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

В этом разделе описывается, как обновить файлы MEX для использования чередующегося комплексного API. Вы можете продолжать использовать отдельный комплексный API, вызывая mex команда со -R2017b опция. Однако для получения дополнительной информации об использовании этой опции см. Раздел «Нужно ли обновлять файлы MEX для использования комплексного API с чередованием»?

Примечание

Если вы создаете свои файлы MEX с помощью mex команда со -compatibleArrayDims Опция сначала необходимо обновить исходный код, чтобы использовать 64-битный API. Для получения дополнительной информации смотрите Обновление файлов MEX для использования 64-Bit 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 */
        }
    }
}

Handle Complex 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

См. также

Похожие темы