Обновите файлы MEX, чтобы использовать чередованный комплексный API

Эта тема описывает, как обновить ваши файлы MEX, чтобы использовать чередованный комплексный API. Можно продолжить использовать отдельный комплексный API путем вызова mex команда с -R2017b опция. Однако для получения дополнительной информации об использовании этой опции, смотрите, что я должен Обновить Свои файлы MEX, чтобы Использовать Чередованный Комплексный API?

Примечание

Если вы создаете свои файлы MEX с помощью mex команда с -compatibleArrayDims опция, затем сначала необходимо обновить исходный код, чтобы использовать 64-битный API. Для получения информации смотрите файлы MEX Обновления, чтобы Использовать 64-битный API.

Чтобы обновить ваш исходный код MEX, используйте следующий контрольный список.

  1. Рассмотрите свой код для использования pr и pi указатели, указатели, возвращенные mxGetPr/mxGetPi и mxGetData/mxGetImagData функции. В чередованном комплексном API существует один указатель, pa, значение возвращено mxGetDoubles и другие введенные функции данных. Важно проверять входной массив на сложность прежде, чем попытаться считать данные. Вызовы mxGetPr и mxGetData на комплексных массивах возвращают различные результаты в чередованный комплексный API, чем в отдельном комплексном API.

  2. Подготовьте свой код перед редактированием.

    Прежде, чем изменить ваш код, проверьте, что MEX-функция работает с -R2017b API. Как минимум создайте список из ожидаемых вводов и выводов или создайте полный тестовый набор. Используйте эти тесты, чтобы сравнить результаты с обновленным исходным кодом. Результаты должны быть идентичными.

    Поддержите весь источник, двоичный файл и тестовые файлы.

  3. Итеративно осуществите рефакторинг свой существующий код путем проверки на следующие условия.

  4. После каждого изменения, компиляция с помощью чередованного комплексного API. Создавать myMexFile.cВвод:

    mex -R2018a myMexFile.c
    Создавать myMexFile.FВвод:

    mex -R2018a myMexFile.F
  5. Разрешите отказы и предупреждения.

  6. Протестируйте после каждого рефакторинга.

    Сравните результаты выполнения вашей MEX-функции, скомпилированной с чередованным комплексным API с результатами вашего исходного двоичного файла. Если существуют какие-либо различия или отказы, используйте отладчик, чтобы исследовать причину. Для получения информации о возможностях вашего отладчика обратитесь к своей документации компилятора.

  7. Добавьте информацию о сборке в справочный файл MEX

Проверяйте сложность массивов Используя mxIsComplex

Если ваш код вызывает mxGetPi функция, чтобы определить, имеет ли массив комплексные элементы, используйте mxIsComplex функцию вместо этого. Эта функция создает с обоими -R2017b и -R2018a API. Ищите свой код следующие шаблоны.

Замена C исходный код:С:
mxArray *pa;
...
if (mxGetPi(pa)) { 
    /* process complex array */
}
mxArray *pa;
...
if (mxIsComplex(pa)) { 
    /* process complex array */
}
double *ptr;
ptr = mxGetPi(pa);
if (ptr != NULL) { 
    /* process complex array */
}

Добавьте MX_HAS_INTERLEAVED_COMPLEX поддерживать оба представления комплексного числа

Записать код, который создает с обоими -R2017b и -R2018a API, добавляет MX_HAS_INTERLEAVED_COMPLEX макрос. Этот макрос возвращает true если вы создаете файл MEX с -R2018a опция.

Перенос следующего кода в #if MX_HAS_INTERLEAVED_COMPLEX оператор гарантирует, что этот код создаст с любым -R2017b или -R2018a mex опция. Однако в этом примере, нет никакого кода, чтобы выполниться, когда создано с -R2018a.

Замена C исходный код:С:
static void
analyze_double(const mxArray *array_ptr)
{
    mwSize total_num_of_elements, index;
    double *pr, *pi;
    total_num_of_elements = mxGetNumberOfElements(array_ptr);
    pr = mxGetPr(array_ptr);
    pi = mxGetPi(array_ptr);
    for (index=0; index<total_num_of_elements; index++)  {
        if (mxIsComplex(array_ptr)) {
            mexPrintf("%g + %gi\n", *pr++, *pi++);
        }
        else {
            mexPrintf("%g\n", *pr++);
        }
    }
}
static void
analyze_double(const mxArray *array_ptr)
{
    mwSize total_num_of_elements, index;
    total_num_of_elements = mxGetNumberOfElements(array_ptr);

    #if MX_HAS_INTERLEAVED_COMPLEX
        /* interleaved complex API processing */
        mxComplexDouble *pc;
        mxDouble *p;
        if (mxIsComplex(array_ptr)) {
            pc = mxGetComplexDoubles(array_ptr);
            for (index=0; index<total_num_of_elements; index++)  {
                mexPrintf(" = %g + %gi\n",(*pc).real,(*pc).imag);
                pc++;
            }
        }
        else {
            p = mxGetDoubles(array_ptr);
            for (index=0; index<total_num_of_elements; index++)  {
                mexPrintf(" = %g\n", *p++);
            }
        }
    #else
        /* separate complex API processing */
        double *pr, *pi;
        pr = mxGetPr(array_ptr);
        pi = mxGetPi(array_ptr);
        for (index=0; index<total_num_of_elements; index++)  {
            if (mxIsComplex(array_ptr)) {
                mexPrintf("%g + %gi\n", *pr++, *pi++);
            }
            else {
                mexPrintf("%g\n", *pr++);
            }
        }
    #endif
}
Замена исходный код Фортрана:С:
mwPointer prhs(*), pr
pr = mxGetPr(prhs(1))
mwPointer prhs(*), pr
#if MX_HAS_INTERLEAVED_COMPLEX
      pr = mxGetDoubles(prhs(1))
#else
      pr = mxGetPr(prhs(1))
#endif

Используйте введенные функции доступа к данным

Использовать mxGetData и mxGetImagData функции, необходимо проверить тип входа mxArray и вручную бросок указатель выход к правильному типу. Введенные функции доступа к данным проверяют тип массива и возвращают правильный тип указателя. Когда вы используете mxGetInt16s и mxGetComplexInt16s функции в следующем коде, чтобы обработать int16 массив, вы не должны помнить соответствующий тип C, short int.

Замена C исходный код:С:
static void
analyze_int16(const mxArray *array_ptr)
{
    short int  *pr, *pi;
    pr = (short int *)mxGetData(array_ptr);
    pi = (short int *)mxGetImagData(array_ptr);
    
    if (mxIsComplex(array_ptr)) {
         /* process complex data *pr,*pi */
    }
    else {
        /* process real data *pr */
    }
}
static void
analyze_int16(const mxArray *array_ptr)
{
    mxComplexInt16 *pc;
    mxInt16 *p;
    if(mxIsComplex(array_ptr)) {
        pc = mxGetComplexInt16s(array_ptr);
        /* process complex data (*pc).real,(*pc).imag */
        }
    }
    else {
        p = mxGetInt16s(array_ptr);
        /* process real data *p */
        }
    }
}

Комплекс указателя mxArrays

Следующие примеры показывают, как MATLAB® использует одну переменную типа массив, чтобы представлять комплексный массив.

Объедините mxArrays C

Предположим, что у вас есть следующий комплексный mxArray переменные и хотят добавить вещественные числа и мнимые числа x и y создать массив z. Массивы x и y одного размера.

mxArray * x, y, z;

Вместо того, чтобы создать два указателя xr и xi для массива x, создайте один указатель xc из типа mxComplexDouble. Получить доступ к действительным и мнимым частям элемента xc[i], используйте xc[i].real и xc[i].imag.

Замена C исходный код:С:
double  *xr, *xi, *yr, *yi, *zr, *zi;
/* get pointers to the real and imaginary parts of the arrays */
xr = mxGetPr(x);
xi = mxGetPi(x);
yr = mxGetPr(y);
yi = mxGetPi(y);
zr = mxGetPr(z);
zi = mxGetPi(z);

...
/* perform addition on element i */
zr[i] = xr[i] + yr[i];
zi[i] = xi[i] + yi[i];
/* get pointers to the complex arrays */
mxComplexDouble * xc = mxGetComplexDoubles(x);
mxComplexDouble * yc = mxGetComplexDoubles(y);
mxComplexDouble * zc = mxGetComplexDoubles(z);

...
/* perform addition on element i */
zc[i].real = xc[i].real + yc[i].real;
zc[i].imag = xc[i].imag + yc[i].imag;

Следующий код копирует mxArray в выходной аргумент. Код показывает, как протестировать на и скопировать комплексные массивы.

Замена C исходный код:С:
mxGetPr(plhs[0])[0] = mxGetPr(prhs[0])[index];
if (mxIsComplex(prhs[0])) {
    mxGetPi(plhs[0])[0] = mxGetPi(prhs[0])[index];
}
if (mxIsComplex(prhs[0])) {
   mxGetComplexDoubles(plhs[0])[0] = mxGetComplexDoubles(prhs[0])[index];
}
else {
   mxGetDoubles(plhs[0])[0] = mxGetDoubles(prhs[0])[index];
}

Объедините Фортран mxArrays

Предположим, что у вас есть два комплекса, двойные mxArrays и хочу передать их функции Фортрана с входными параметрами x и y заданный можно следующим образом.

complex*16 x(*), y(*)

Вместо того, чтобы отдельно преобразовать действительные и мнимые части каждого mxArray, используйте mxGetComplexDoubles функция.

Замена исходный код Фортрана:С:
      mwPointer mxGetPr, mxGetPi

C     Copy the data into native COMPLEX Fortran arrays.
      call mxCopyPtrToComplex16(
     +    mxGetPr(prhs(1)),
     +    mxGetPi(prhs(1)),x,nx)
      call mxCopyPtrToComplex16(
     +    mxGetPr(prhs(2)),
     +    mxGetPi(prhs(2)),y,ny)
      mwPointer mxGetComplexDoubles
      integer*4 status
      integer*4 mxCopyPtrToComplex16, mxCopyComplex16ToPtr

C     Copy the data into native COMPLEX Fortran arrays.
      status = 
     +   mxCopyPtrToComplex16(mxGetComplexDoubles(prhs(1)),x,nx)
C     Test status for error conditions

      status = 
     +   mxCopyPtrToComplex16(mxGetComplexDoubles(prhs(2)),y,ny)
C     Test status for error conditions

Обеспечьте сложность mxArray

Этот отрывок кода С показывает, как преобразовать действительный, дважды, входной массив prhs[0] в комплексный массив. Следующие кодовые наборы переменные раньше заполняли комплексную часть массива с последовательными числами.

// code to check number of arguments and expected types
mwSize rows = mxGetM(prhs[0]);
mwSize cols = mxGetN(prhs[0]);
mwSize sz = mxGetElementSize(prhs[0]);

Следующий код показывает, как использовать mxMakeArrayComplex преобразовывать действительный, дважды, входной массив в чередованный комплексный mxArray. Для большего количества примеров смотрите mxMakeArrayComplex (C).

Замена C исходный код:С:
plhs[0] = mxDuplicateArray(prhs[0]);

mxDouble *dc = (mxDouble*)mxMalloc(rows*cols*sz);
mxSetImagData(plhs[0], dc);
for (int i = 0 ; i < rows*cols ; i++)
{
    dc[i] = i+1;
}
plhs[0] = mxDuplicateArray(prhs[0]);

if (mxMakeArrayComplex(plhs[0])) {
    mxComplexDouble *dt = mxGetComplexDoubles(plhs[0]);
    for (int i = 0 ; i < rows*cols ; i++)
    {
        dt[i].imag = i+1;
    }
}

Замените отдельные комплексные функции

Следующие функции не находятся в чередованном комплексном API. Необходимо заменить их на чередованные комплексные функции при обработке комплексных данных.

  • mxGetPi

  • mxSetPi

  • mxGetImagData

  • mxSetImagData

Можно заменить вызовы mxGetPr и mxGetPi с вызовом mxGetComplexDoubles. Эта функция проверяет, что ваш массив содержит элементы типа mxComplexDouble. Аналогично, mxSetComplexDoubles замены mxSetPr и mxSetPi.

mxGetData и mxGetImagData функции не проверяют тип массива. Вместо этого необходимо бросить возвращаемое значение к типу указателя, который совпадает с типом, заданным входом. Замените вызовы mxGetData и mxGetImagData с одной, соответствующей, введенной функцией доступа к данным, например, mxGetComplexInt64s.

Замена C исходный код:С:
mxArray *pa;
mwSize numElements; 

int64_T  *pr, *pi;
pr = (int64_T *)mxGetData(pa);
pi = (int64_T *)mxGetImagData(pa);
numElements = mxGetNumberOfElements(pa);
mxArray *pa;
mwSize numElements; 

mxComplexInt64 *pc;
pc = mxGetComplexInt64s(pa);
numElements = mxGetNumberOfElements(pa);

Вычислите размер данных массива с mxGetElementSize

В -R2018a API, mxGetElementSize (C) функция возвращает sizeof(std::complex<T>) для комплексного mxArray с типом данных T. Это значение является дважды значением, возвращенным функцией в -R2017b API. Точно так же mxGetElementSize (Fortran) в -R2018a API возвращает дважды значение как функцию в -R2017b API.

Полагайте заменяющий быть поэтапно осуществленными функции

Следующие функции находятся в обоих -R2017b и -R2018a API. В то время как вы не должны заменять их на введенные функции доступа к данным, введенные функции данных обеспечивают проверку типа. Кроме того, если вы используете mxGetPr, вы можете выбрать mxGetPi для любой обработки комплексного массива. Этот шаблон кода вызывает ошибки при записи -R2018a MEX-функции.

Можно заменить вызовы mxGetPr с вызовом mxGetDoubles. Эта функция проверяет, что ваш массив содержит элементы типа mxDouble. Аналогично, mxSetDoubles замены mxSetPr. Заменять вызовы mxGetData и mxSetData функции, выберите соответствующую введенную функцию доступа к данным, например, mxGetInt64s и mxSetInt64s.

Замена C исходный код:С:
double *y;
/*  create a pointer y to input matrix */
y = mxGetPr(prhs[1]);
mxDouble *p;
p = mxGetDoubles(prhs[1]);
Замена исходный код Фортрана:С:
      mwPointer pr
      mwPointer mxGetPr
C     Create a pointer to input matrix
      pr = mxGetPr(prhs(1))
      mwPointer pr
      mwPointer mxGetDoubles

      pr = mxGetDoubles(prhs(1))

Добавьте информацию о сборке в справочный файл MEX

Рассмотрите создание справочного файла, описанного в Использовании справочных файлов с MEX-функциями, который содержит информацию о сборке. Например, создайте файл displayTypesafeNumeric.m содержа следующий текст.

% displayTypesafeNumeric.m Help file for displayTypesafeNumeric C MEX function
% 
% Use the following command to build this MEX file:
% mex -R2018a displayTypesafeNumeric.c

В командной строке MATLAB введите:

help displayTypesafeNumeric
displayTypesafeNumeric.m Help file for displayTypesafeNumeric C MEX function
  
  Use the following command to build this MEX file:
  mex -R2018a displayTypesafeNumeric.c

Смотрите также

Похожие темы