主要内容

在函数和类中指定数组布局

通过在函数体中插入 coder.rowMajorcoder.columnMajor 调用,可以针对行优先布局或列优先布局特化单个 MATLAB® 函数。使用这些函数特化,您可以在生成的代码中组合行优先数据和列优先数据。您还可以针对一个特定数组布局特化类。函数和类特化允许您:

  • 以增量方式修改行优先布局或列优先布局的代码。

  • 为在不同组件中需要不同布局的应用程序定义数组布局边界。

  • 在许多不同函数和类之间构造数组布局的继承。

对于 MATLAB Coder™ 入口(顶层)函数,所有输入和输出必须使用相同的数组布局。在生成的 C/C++ 代码中,入口函数接口使用与函数数组布局设定相同的数组布局接受并返回数据。

注意

默认情况下,代码生成使用列优先数组布局。

在函数中指定数组布局

以特化函数 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

对于 MATLAB Coder,您可以使用 codegen 命令为 addMatrixRM 生成代码。

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

由于 coder.rowMajor 调用,代码生成器会生成使用以行优先布局存储的数据的代码。

从行优先函数或列优先函数调用的其他函数继承相同的数组布局。如果被调函数有自己独特的 coder.rowMajorcoder.columnMajor 调用,则局部调用优先。

您可以在同一代码中混合使用列优先函数和行优先函数。当在行优先函数和列优先函数之间传递数据时,代码生成器会插入转置或转换运算。这些转换运算确保数组元素按照具有不同数组布局设定的函数的要求进行存储。例如,从行优先函数调用的列优先函数的输入在传递给列优先函数之前会转换为列优先布局。

查询函数的数组布局

要在编译时查询函数的数组布局,请使用 coder.isRowMajorcoder.isColumnMajor。当涉及到行优先函数和列优先函数时,此查询对于特化您生成的代码很有用。以如下函数为例:

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

根据此函数是行优先函数还是列优先函数,其行为会有所不同。当 addMatrixRouted 是行优先时,它调用 addMatrixRM 函数,该函数对行优先数据具有高效的内存访问。当该函数是列优先时,它调用针对列优先数据优化的 addMatrixRM 函数版本。

以如下函数定义为例。与 addMatrixRM 函数不同,该算法在外层循环中循环访问列,在内层循环中循环访问行。

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

此函数的代码生成结果如下:

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

生成的代码的步幅长度为仅一个元素。由于特化查询,为 addMatrixRouted 生成的代码为数组布局的任一选择项提供高效的内存访问。

指定类中的数组布局

您可以为类指定数组布局,以便对象属性变量以特定数组布局存储。要指定数组布局,请在类构造函数中放置 coder.rowMajorcoder.columnMajor 调用。如果将具有指定数组布局的对象分配给另一个对象的属性,则所分配对象的数组布局优先。

以行优先类 rowMats 为例。此类包含矩阵属性和一个由按元素相加算法组成的方法。该方法中的算法对于以行优先布局存储的数据的执行效率更高。通过在类构造函数中指定 coder.rowMajor,生成的代码对属性数据使用行优先布局。

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

在简单函数 doMath 中使用该类。入口函数的输入和输出必须都使用相同的数组布局。

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

对于 MATLAB Coder,您可以通过输入以下内容来生成代码:

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

使用默认设置时,代码生成器假定入口函数的输入和输出使用列优先布局,因为您没有为函数 doMath 指定行优先布局。因此,在调用类构造函数之前,生成的代码将 in1in2 转换为行优先布局。同样,它将 doMath 函数输出转换回列优先布局。

为特定数组布局设计类时,请考虑:

  • 如果不在类构造函数中指定数组布局,对象将从调用类构造函数的函数或代码生成配置设置中继承其数组布局。

  • 无法使用 coder.rowMajorcoder.columnMajor 在非静态方法中指定数组布局。方法使用与接收对象相同的数组布局。方法不继承调用它们的函数的数组布局。对于静态方法,其用法类似于普通函数,您可以在方法中指定数组布局。

  • 如果您指定超类的数组布局,子类将继承此数组布局设定。无法在超类和子类之间指定冲突的数组布局。

另请参阅

| | |

主题