N 次元インデックスを使用するコードの生成
既定では、コード ジェネレーターは配列に 1 次元インデックスを使用します。コード ジェネレーターは、MATLAB® コードでの N 次元配列に対して C/C++ コードで 1 次元配列を作成します。N 次元インデックスを使用して可読性を向上させ、インターフェイスを生成されたコードに適用することができます。
以下の表は、N 次元インデックスが有効の場合と無効の場合に生成されるコードの違いの例を示しています。
MATLAB コード | 生成される C コード (既定) | N 次元インデックス有効時に生成される C コード |
---|---|---|
A = zeros(2,4,6) | A[48] |
|
MATLAB は、既定で列優先の配列レイアウトを使用するコードを生成するため、N 次元インデックスのインデックスの次元は逆になります。インデックスの次元を切り替えるために、行優先の配列レイアウトを有効にできます。
N 次元配列の 1 次元への変換は、配列の "フラット化" とも呼ばれます。コンピューター メモリでは、すべてのデータは 1 次元の配列に格納されます。インデックスの選択により計算結果が変わることはありません。ただし、コードに配列の入力または出力がある場合、生成されたコードに対するインターフェイスが変更される可能性があります。
N 次元インデックスを有効にするには、次の手順に従います。
-preservearraydims
オプションを使用します。codegen foo -preservearraydims
コード生成構成オブジェクトの
PreserveArrayDimensions
プロパティをtrue
に設定します、次に例を示します。cfg = coder.config('lib'); cfg.PreserveArrayDimensions = true; codegen foo -config cfg
MATLAB Coder™ アプリから N 次元インデックスを有効にするには、次の手順に従います。
コード生成ワークフローにおいて [コード生成] ページに移動します。
[生成] 矢印 をクリックして [生成] ダイアログ ボックスを開きます。
[詳細設定] をクリックします。
[メモリ] タブで、[配列の次元を保持] チェック ボックスをオンにします。
N 次元インデックスおよび行優先のレイアウトによる可読性の向上
N 次元インデックスにより、生成された C/C++ コードの MATLAB コードへのトレースが容易になります。コード ジェネレーターは、配列を 1 次元に変換せず、元の配列の次元を保持します。さらに、行優先のレイアウトを指定して、コード外観をさらに直感的にすることができます。
2 つの行列を 1 要素ずつ追加する、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
2 行 4 列の配列を操作するように、addMatrices
のコードを生成します。N 次元インデックスおよび行優先の配列レイアウトを有効にします。
cfg = coder.config('lib'); cfg.PreserveArrayDimensions = true; cfg.RowMajor = true; codegen addMatrices -args {ones(2,4),ones(2,4)} -config cfg -launchreport
コード生成により、明示的な 2 次元配列インデックスを使用するコードが生成されます。
/* 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 コードと同じ 2 次元インデックスを使用します。生成されたコードを元のアルゴリズムと比較して容易に解析できます。行優先のレイアウトの使用方法を理解するには、行優先の配列レイアウトを使用するコードの生成を参照してください。
列優先のレイアウトおよび 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]; } } }
C コードでの入力および出力行列は、元の 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
C コードでは、元のデータを転置しなければなりませんが、この例では AA
と呼びます。
AA = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
データ要素のリストを取得するために、同じ内部ストレージの順序を使用します。言い換えれば、C 配列は 4 行 2 列でなければなりません(AA = {{1, 2, 3, 4}, {5, 6, 7, 8}}
を使用して配列を 2 行 4 列として定義することで、同様のストレージの順序を取得できます。ただし、この順序を取得するには、手動でのデータの形状の変更または並べ替えが必要です)。
配列レイアウトの選択は内部データ表現のみに影響し、計算結果やアルゴリズムの結果は変わりません。生成されたコードで MATLAB 配列の直感的な外観を維持するには、N 次元インデックスを行優先の配列レイアウトと共に使用します。行優先のレイアウトが生成されたコードの効率性に影響する可能性があることに注意してください。詳細については、行優先のレイアウトのコード設計を参照してください。
コード生成のその他の考慮事項
N 次元インデックスのその他の側面について考えます。N 次元インデックスを指定する場合でも、コード ジェネレーターは、N 次元ベクトルに対して常に 1 次元配列を生成します。たとえば、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 次元配列を 1 次元配列にキャストしなければなりません。キャスティング演算により、コードの解析はコード ジェネレーターにとってさらに複雑になります。複雑であることによって、コード ジェネレーターのパフォーマンスの最適化機能が低下する可能性があります。
最後に、次の点に注意してください。
任意のデータ型の配列に N 次元インデックスを使用できます。
可変サイズ配列ではなく、固定サイズ配列のみが N 次元インデックスを使用できます。
参考
codegen
| reshape
| coder.cstructname