Сгенерируйте код, который использует N-размерную индексацию

По умолчанию генератор кода использует одномерную индексацию для массивов. Генератор кода создает одномерные массивы в коде C/C + + для N-мерных массивов в MATLAB® код. Вы можете использовать N-мерную индексацию, чтобы улучшить читаемость и адаптировать интерфейс к своему сгенерированному коду.

В этой таблице показан пример различий в сгенерированном коде с N-мерной индексацией и без нее.

Код MATLAB

Сгенерированный код C (по умолчанию)

Сгенерированный код C с включенной индексацией N-D

A = zeros(2,4,6)
A[48]
  • С размещением массива основного столбца (по умолчанию):

    A[6][4][2]
    
  • С включённым размещением массива основной строки:

    A[2][4][6]
    

Порядок индексов сторнируется для N-мерного индексирования, потому что MATLAB генерирует код, который по умолчанию использует размещение массива с основным столбцом. Чтобы переключить порядок индексов, можно включить размещение массива с основной строкой.

Преобразование N-мерного массива в одну размерность также называется уплощением массива. В памяти компьютера все данные хранятся в терминах одномерных массивов. Выбор индексации не меняет результаты расчетов. Однако, если ваш код имеет входы или выходы, которые являются массивами, интерфейс с вашим сгенерированным кодом может измениться.

Чтобы включить N-мерную индексацию:

  • Используйте -preservearraydims опция:

    codegen foo -preservearraydims
  • Установите PreserveArrayDimensions свойство для объекта строения генерации кода, чтобы true. Для примера:

    cfg = coder.config('lib');
    cfg.PreserveArrayDimensions = true;
    codegen foo -config cfg

Чтобы включить N-мерную индексацию из приложения MATLAB Coder™:

  • Перейдите на страницу Generate Code в рабочем процессе генерации кода.

  • Откройте диалоговое окно Generate, щелкнув стрелу Generate.

  • Нажмите More Settings.

  • На вкладке Memory установите флажок Preserve array dimensions.

Улучшите читаемость с N-мерным индексированием и основным размещением строки

N-мерная индексация может упростить для вас отслеживание вашего сгенерированного кода C/C + + назад к коду MATLAB. Генератор кода сохраняет размерности исходных массивов, а не преобразует массивы в одно измерение. Кроме того, можно задать основную строку размещения, чтобы сделать внешний вид кода еще более интуитивно понятным.

Рассмотрим функцию MATLAB addMatrices, который добавляет две матрицы, элемент за элементом:

function sum = addMatrices(A,B) 
%#codegen
sum = coder.nullcopy(A);
for row = 1:size(A,1) 
   for col = 1:size(A,2)  
       sum(row,col) = A(row,col) + B(row,col);
   end
end

Сгенерируйте код для addMatrices так, что он работает с массивами 2 на 4. Включите N-мерную индексацию и размещение массива с основной строкой:

cfg = coder.config('lib');
cfg.PreserveArrayDimensions = true; 
cfg.RowMajor = true; 
codegen addMatrices -args {ones(2,4),ones(2,4)} -config cfg -launchreport

Генерация кода создает код с явной двумерной индексацией массива:

/* N-d indexing on, row-major on */
void addMatrices(double A[2][4], double B[2][4], double sum[2][4])
{
  int row;
  int col;
  for (row = 0; row < 2; row++) {
    for (col = 0; col < 4; col++) {
      sum[row][col] = A[row][col] + B[row][col];
    }
  }
}

Сгенерированный код для addMatrices использует ту же двумерную индексацию, что и оригинальный код MATLAB. Можно легко проанализировать сгенерированный код по сравнению с исходным алгоритмом. Чтобы понять, как использовать размещение основной строки, см. Раздел «Генерация кода, который использует размещение массива основной строки».

Основной столбец Размещения и N-размерная индексация

Выбор размещения массива влияет на внешний вид N-мерного индексирования. Для примера сгенерируйте код для addMatrices функция с использованием размещения массива основного столбца:

cfg.RowMajor = false;
codegen addMatrices -args {ones(2,4),ones(2,4)} -config cfg -launchreport

Генерация кода создает этот код C:

/* N-d indexing on, row-major off */
void addMatrices(double A[4][2], double B[4][2], double sum[4][2])
{
  int row;
  int col;
  for (row = 0; row < 2; row++) {
    for (col = 0; col < 4; col++) {
      sum[col][row] = A[col][row] + B[col][row];
    }
  }
}

Входная и выходные матрицы в коде С являются транспонированием исходных матриц MATLAB. Чтобы понять, почему, рассмотрим, как массивы представлены в памяти компьютера. Язык MATLAB по умолчанию использует размещение с основным столбцом, где элементы первого (крайнего левого) размерности или индекса смежны в памяти. По умолчанию C использует размещение массива с основной строкой, где элементы последнего (крайнего правого) размерности или индекса смежны. Чтобы сохранить смежность исходного элемента, генератор кода должен изменить порядок измерений массива.

Например, в этом случае, если вы задаете матрицу MATLAB A как:

A=reshape(1:8,2,4)

или

A =
     1     3     5     7
     2     4     6     8

затем, поскольку MATLAB использует размещение основного столбца, данные внутренне хранятся в следующем порядке:

A(:)' = 
     1     2     3     4     5     6     7     8

В коде С необходимо транспонировать исходные данные, в данном примере вызвать его AA:

AA = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};

для получения списка элементов данных с тем же внутренним порядком на хранение. Другими словами, массив C должен быть 4 на 2. (Можно получить эквивалентный порядок на хранение, определив массив как 2 на 4, с AA = {{1, 2, 3, 4}, {5, 6, 7, 8}}. Однако получение этого порядка требует ручного изменения формы или перестройки данных.)

Выбор размещения массива влияет только на представление внутренних данных и не изменяет вычислительные или алгоритмические результаты. Чтобы сохранить интуитивно понятный внешний вид массивов MATLAB в сгенерированном коде, используйте N-мерную индексацию с размещением массива с основной строкой. Обратите внимание, что основные размещения могут повлиять на эффективность вашего сгенерированного кода. Для получения дополнительной информации смотрите Проект для Row-Major Array Layout.

Другие факторы генерации кода

Рассмотрим другие аспекты N-мерного индексирования. Генератор кода всегда производит одномерные массивы для N-мерных векторов, даже когда вы задаете N-мерную индексацию. Для примера, если вы генерируете код для вектора MATLAB:

A = zeros(1,10)

или

A = zeros(1,10,1)

получившиеся массивы C/C + + сохраняются как:

A[10]

N-мерная индексация также применяется к массивам и структурам. Для примера, если вы декларируете структуры в своем коде как:

x = struct('f1', ones(2,3));
coder.cstructname(x,'myStruct1');
y = struct('f2', ones(1,6,1));
coder.cstructname(y,'myStruct2');

затем сгенерированный код содержит определения структур:

typedef struct {
  double f1[2][3];
} myStruct1;
typedef struct {
  double f2[6];
} myStruct2;

Избегайте линейной индексации на N-мерных массивах. Линейная индексация происходит, например, когда вы используете оператор двоеточия:

A(:)

Чтобы применить линейную индексацию, генератор кода должен привести N-мерный массив в одномерный массив. Операции кастинга делают ваш код более комплексным для генератора кода, чтобы анализировать. Эта повышенная сложность может затруднить способность генератора кода оптимизировать для эффективности.

Наконец, обратите внимание на следующее:

  • Вы можете использовать N-мерную индексацию для массивов любого типа данных.

  • N-размерную индексацию могут использовать только массивы фиксированного размера, а не массивы переменного размера.

См. также

| |

Похожие темы