Обновите файлы 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-функция работает с API -R2017b. Как минимум создайте список из ожидаемых вводов и выводов или создайте полный тестовый набор. Используйте эти тесты, чтобы сравнить результаты с обновленным исходным кодом. Результаты должны быть идентичными.

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

  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 и с API -R2018a. Ищите свой код следующие шаблоны.

Замена 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 и с API -R2018a, добавьте макрос 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
        /* add interleaved complex API code here */
    #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

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

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

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

Можно заменить вызовы 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

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

Похожие темы