Main Content

Specify Array Layout in Functions and Classes

You can specialize individual MATLAB® functions for row-major layout or column-major layout by inserting coder.rowMajor or coder.columnMajor calls into the function body. Using these function specializations, you can combine row-major data and column-major data in your generated code. You can also specialize classes for one specific array layout. Function and class specializations allow you to:

  • Incrementally modify your code for row-major layout or column-major layout.

  • Define array layout boundaries for applications that require different layouts in different components.

  • Structure the inheritance of array layout between many different functions and classes.

For MATLAB Coder™ entry-point (top-level) functions, all inputs and outputs must use the same array layout. In the generated C/C++ code, the entry-point function interface accepts and returns data with the same array layout as the function array layout specification.

Note

By default, code generation uses column-major array layout.

Specify Array Layout in a Function

For an example of a specialized function, consider addMatrixRM:

function [S] = addMatrixRM(A,B) 
%#codegen
S = zeros(size(A));
coder.rowMajor; % specify row-major code
for row = 1:size(A,1) 
   for col = 1:size(A,2)  
       S(row,col) = A(row,col) + B(row,col);
   end
end

For MATLAB Coder, you can generate code for addMatrixRM by using the codegen command.

codegen addMatrixRM -args {ones(20,10),ones(20,10)} -config:lib -launchreport

Because of the coder.rowMajor call, the code generator produces code that uses data stored in row-major layout.

Other functions called from a row-major function or column-major function inherit the same array layout. If a called function has its own distinct coder.rowMajor or coder.columnMajor call, the local call takes precedence.

You can mix column-major and row-major functions in the same code. The code generator inserts transpose or conversion operations when passing data between row-major and column-major functions. These conversion operations ensure that array elements are stored as required by functions with different array layout specifications. For example, the inputs to a column-major function, called from a row-major function, are converted to column-major layout before being passed to the column-major function.

Query Array Layout of a Function

To query the array layout of a function at compile time, use coder.isRowMajor or coder.isColumnMajor. This query can be useful for specializing your generated code when it involves row-major and column-major functions. For example, consider this function:

function [S] = addMatrixRouted(A,B)
 if coder.isRowMajor
     %execute this code if row-major
     S = addMatrixRM(A,B); 
 elseif coder.isColumnMajor
     %execute this code if column-major
     S = addMatrix_OptimizedForColumnMajor(A,B);
 end

This function behaves differently depending on whether it is row-major or column-major. When addMatrixRouted is row-major, it calls the addMatrixRM function, which has efficient memory access for row-major data. When the function is column-major, it calls a version of the addMatrixRM function optimized for column-major data.

For example, consider this function definition. The algorithm iterates through the columns in the outer loop and the rows in the inner loop, in contrast to the addMatrixRM function.

function [S] = addMatrix_OptimizedForColumnMajor(A,B) 
%#codegen
S = zeros(size(A));
for col = 1:size(A,2) 
   for row = 1:size(A,1)  
       S(row,col) = A(row,col) + B(row,col);
   end
end

Code generation for this function yields:

... 
/* column-major layout */
for (col = 0; col < 10; col++) {
  for (row = 0; row < 20; row++) {
     S[row + 20 * col] = A[row + 20 * col] + B[row + 20 * col];  
  }
}
...

The generated code has a stride length of only one element. Due to the specializing queries, the generated code for addMatrixRouted provides efficient memory access for either choice of array layout.

Specify Array Layout in a Class

You can specify array layout for a class so that object property variables are stored with a specific array layout. To specify the array layout, place a coder.rowMajor or coder.columnMajor call in the class constructor. If you assign an object with a specified array layout to the property of another object, the array layout of the assigned object takes precedence.

Consider the row-major class rowMats as an example. This class contains matrix properties and a method that consists of an element-wise addition algorithm. The algorithm in the method performs more efficiently for data stored in row-major layout. By specifying coder.rowMajor in the class constructor, the generated code uses row-major layout for the property data.

classdef rowMats
    properties (Access = public)
        A;
        B;
        C;
    end
    methods
        function obj = rowMats(A,B)
            coder.rowMajor;
            if nargin == 0
                obj.A = 0;
                obj.B = 0;
                obj.C = 0;
            else
                obj.A = A;
                obj.B = B;
                obj.C = zeros(size(A));
            end
        end
        function obj = add(obj)
            for row = 1:size(obj.A,1)
                for col = 1:size(obj.A,2)
                    obj.C(row,col) = obj.A(row,col) + obj.B(row,col);
                end
            end
        end
    end
end

Use the class in a simple function doMath. The inputs and outputs of the entry-point function must all use the same array layout.

function [out] = doMath(in1,in2)
%#codegen
out = zeros(size(in1));
myMats = rowMats(in1,in2);
myMats = myMats.add;
out = myMats.C;
end

For MATLAB Coder, you can generate code by entering:

A = rand(20,10);
B = rand(20,10);
cfg = coder.config('lib');
codegen -config cfg doMath -args {A,B} -launchreport

With default settings, the code generator assumes that the entry-point function inputs and outputs use column-major layout, because you do not specify row-major layout for the function doMath. Therefore, before calling the class constructor, the generated code converts in1 and in2 to row-major layout. Similarly, it converts the doMath function output back to column-major layout.

When designing a class for a specific array layout, consider:

  • If you do not specify the array layout in a class constructor, objects inherit their array layout from the function that calls the class constructor, or from code generation configuration settings.

  • You cannot specify the array layout in a nonstatic method by using coder.rowMajor or coder.columnMajor. Methods use the same array layout as the receiving object. Methods do not inherit the array layout of the function that calls them. For static methods, which are used similarly to ordinary functions, you can specify the array layout in the method.

  • If you specify the array layout of a superclass, the subclass inherits this array layout specification. You cannot specify conflicting array layouts between superclasses and subclasses.

See Also

| | |

Related Topics