Main Content

Generate Code That Uses N-Dimensional Indexing

By default, the code generator uses one-dimensional indexing for arrays. The code generator creates one-dimensional arrays in C/C++ code for N-dimensional arrays in MATLAB® code. You can use N-dimensional indexing to improve readability and adapt the interface to your generated code.

This table shows an example of the differences in the generated code with and without N-dimensional indexing.

MATLAB Code

Generated C Code (default)

Generated C Code with N-D Indexing Enabled

A = zeros(2,4,6)
A[48]
  • With column-major array layout (default):

    A[6][4][2]
    
  • With row-major array layout enabled:

    A[2][4][6]
    

The order of the indices is reversed for N-dimensional indexing because MATLAB generates code that uses column-major array layout by default. To switch the order of the indices, you can enable row-major array layout.

Conversion of an N-dimensional array to one dimension is also called array flattening. In computer memory, all data is stored in terms of one-dimensional arrays. The choice of indexing does not change computation results. However, if your code has inputs or outputs that are arrays, the interface to your generated code can change.

To enable N-dimensional indexing:

  • Use the -preservearraydims option:

    codegen foo -preservearraydims
  • Set the PreserveArrayDimensions property for your code generation configuration object to true. For example:

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

To enable N-dimensional indexing from the MATLAB Coder™ App:

  • Navigate to the Generate Code page in the code generation workflow.

  • Open the Generate dialog box by clicking the Generate arrow .

  • Click More Settings.

  • On the Memory tab, select the Preserve array dimensions check box.

Improve Readability with N-Dimensional Indexing and Row-Major Layout

N-dimensional indexing can make it easier for you to trace your generated C/C++ code back to your MATLAB code. The code generator preserves the dimensions of the original arrays, rather than converting arrays to one dimension. Furthermore, you can specify row-major layout to make the code appearance even more intuitive.

Consider the MATLAB function addMatrices, which adds two matrices, element by element:

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

Generate code for addMatrices so that it operates on 2-by-4 arrays. Enable N-dimensional indexing and row-major array layout:

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

Code generation produces code with explicit two-dimensional array indexing:

/* 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];
    }
  }
}

The generated code for addMatrices uses the same two-dimensional indexing as the original MATLAB code. You can easily analyze the generated code in comparison with the original algorithm. To understand how to use row-major layout, see Generate Code That Uses Row-Major Array Layout.

Column-Major Layout and N-Dimensional Indexing

The choice of array layout affects the appearance of N-dimensional indexing. For example, generate code for the addMatrices function using column-major array layout:

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

Code generation produces this C code:

/* 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];
    }
  }
}

The input and output matrices in the C code are transposes of the original MATLAB matrices. To understand why, consider how arrays are represented in computer memory. The MATLAB language uses column-major layout by default, where the elements from the first (leftmost) dimension or index are contiguous in memory. C uses row-major array layout by default, where elements from the last (rightmost) dimension or index are contiguous. To preserve the original element adjacency, the code generator must reverse the order of the array dimensions.

For example, in this case, if you define the MATLAB matrix A as:

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

or

A =
     1     3     5     7
     2     4     6     8

then, because MATLAB uses column-major layout, the data is internally stored in the order:

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

In C code, you must transpose the original data, for this example, call it AA:

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

to attain the list of data elements with the same internal storage order. In other words, the C array must be 4-by-2. (You can obtain an equivalent storage order by defining the array as a 2-by-4, with AA = {{1, 2, 3, 4}, {5, 6, 7, 8}}. However, obtaining this order requires a manual reshape or rearrangement of the data.)

The choice of array layout affects only internal data representation and does not change computational or algorithmic results. To preserve the intuitive appearance of MATLAB arrays in generated code, use N-dimensional indexing with row-major array layout. Note that row-major layout can affect the efficiency of your generated code. For more information, see Code Design for Row-Major Array Layout.

Other Code Generation Considerations

Consider other aspects of N-dimensional indexing. The code generator always produces one-dimensional arrays for N-dimensional vectors, even when you specify N-dimensional indexing. For example, if you generate code for a MATLAB vector:

A = zeros(1,10)

or

A = zeros(1,10,1)

the resulting C/C++ arrays are stored as:

A[10]

N-dimensional indexing also applies to arrays and structures. For example, if you declare structures in your code as:

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

then the generated code contains the structure definitions:

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

Avoid linear indexing on N-dimensional arrays. Linear indexing occurs, for example, when you use the colon operator:

A(:)

To apply linear indexing, the code generator must cast an N-dimensional array into a one-dimensional array. Casting operations make your code more complex for the code generator to analyze. This increased complexity can hinder the ability of the code generator to optimize for performance.

Last, note the following:

  • You can use N-dimensional indexing for arrays of any data type.

  • Only fixed-size arrays, and not variable-size arrays, can use N-dimensional indexing.

See Also

| |

Related Topics