exponenta event banner

Обновление файлов 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
}
Заменить исходный код Fortran:С:
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

Предположим, что имеется следующий комплекс: 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 функция.

Заменить исходный код Fortran:С:
      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

Этот фрагмент кода C показывает, как преобразовать вещественный, двойной, входной массив 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]);
Заменить исходный код Fortran:С:
      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

См. также

Связанные темы