関数とクラスにおける配列レイアウトの指定
関数本体に coder.rowMajor
または coder.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.rowMajor
または coder.columnMajor
呼び出しを含む場合、ローカルな呼び出しが優先されます。
同じコードの中で、列優先の関数と行優先の関数を混在させることができます。列優先の関数と行優先の関数間でデータを受け渡すとき、コード ジェネレーターが転置または変換演算を挿入します。これらの変換演算により、配列要素が、異なる配列レイアウト仕様をもつ関数によって要求される形式で格納されるようになります。たとえば、行優先の関数から列優先の関数を呼び出す場合、その入力は、列優先の関数に受け渡される前に列優先のレイアウトに変換されます。
関数の配列レイアウトのクエリ
コンパイル時に関数の配列レイアウトをクエリするには、coder.isRowMajor
または coder.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]; } } ...
生成されたコードのストライド長は、わずか 1 要素です。特殊化のクエリにより、addMatrixRouted
の生成されたコードは、どちらの配列レイアウトが選択された場合でも効率的なメモリ アクセスを提供します。
クラスにおける配列レイアウトの指定
クラスに配列レイアウトを指定して、オブジェクト プロパティ変数が特定の配列レイアウトで格納されるようにできます。配列レイアウトを指定するには、クラス コンストラクターに coder.rowMajor
または coder.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
に行優先のレイアウトを指定していないため、コード ジェネレーターは、エントリポイント関数の入力と出力が列優先のレイアウトであるものと想定します。そのため、クラス コンストラクターを呼び出す前に、生成されたコードでは in1
と in2
を行優先のレイアウトに変換します。同様に、関数 doMath
の出力は、列優先のレイアウトに再変換されます。
特定の配列レイアウトについてクラスを設計する場合、以下を考慮します。
クラス コンストラクターに配列レイアウトを指定しない場合、オブジェクトの配列レイアウトは、クラス コンストラクターの呼び出し元の関数から、またはコード生成構成設定から継承されます。
静的でないメソッドでは、
coder.rowMajor
またはcoder.columnMajor
を使用して配列レイアウトを指定することはできません。メソッドは、受け取りオブジェクトと同じ配列レイアウトを使用します。メソッドは、呼び出し元関数の配列レイアウトを継承しません。通常の関数と同じように利用される静的なメソッドでは、メソッドに配列レイアウトを指定できます。スーパークラスに配列レイアウトを指定すると、サブクラスはその配列レイアウト指定を継承します。スーパークラスとサブクラスとで競合する配列レイアウトを指定することはできません。
参考
coder.columnMajor
| coder.rowMajor
| coder.isRowMajor
| coder.isColumnMajor
| codegen