メインコンテンツ

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

可変サイズ配列のコード生成

MATLAB® では、スカラー、ベクトル、および多次元行列を配列として表現します。スカラーは 1 行 1 列の配列、ベクトルは 1 行 n 列または n 行 1 列の配列、多次元行列は m×n×... の配列です。コード生成時、コード ジェネレーターは次のプロセスに従って配列の各次元のサイズを特定しようと試みます。

  • 配列の次元のサイズをコード ジェネレーターで特定できない場合や次元のサイズが変わる場合、コード ジェネレーターは次元を可変サイズとして指定します。

    • 可変サイズの次元に固定の最大サイズがある場合、コード ジェネレーターは次元を制限付き可変サイズとして指定します。

    • 可変サイズの次元に固定の最大サイズがない場合、コード ジェネレーターは次元を制限なしとして指定します。

  • 配列の次元のサイズが変わらないことをコード ジェネレーターで特定できる場合、コード ジェネレーターは次元を固定サイズとして指定します。

場合によっては、コード ジェネレーターにより、サイズが変わる変数が固定サイズとして誤って識別されることがあります。そのような状況では、コード生成時にサイズ非互換性エラーが表示される可能性があります。これらのエラーの診断と解決に関するヘルプについては、エラーの解決: 配列のサイズに互換性がないを参照してください。

コード生成レポートを検証することで、コード ジェネレーターが可変サイズの次元を固定サイズ、制限付き可変サイズ、または制限なしとして識別したかを確認できます。このレポートにおいて、コロン (:) は次元が可変サイズであることを示し、疑問符 (?) はサイズに制限がないことを示します。たとえば、サイズが 1x:? の変数は、1 番目の次元が固定サイズの 1、2 番目の次元が制限なしの可変サイズです。コード生成レポートの詳細については、コード生成レポートを参照してください。

可変サイズの配列の定義

次のいずれかの方法を使用して、生成コードに含める可変サイズの配列を定義できます。

  • zerosones などの関数を使用して、少なくとも 1 つの次元が不定次元である配列を作成する。

  • 使用前に同じ変数に複数のサイズを割り当てる。

  • end+1 のインデックス付けを使用して配列を拡張する。

  • coder.varsize を使用して可変サイズの配列を明示的に宣言する。

詳細については、コード生成のための可変サイズ データの定義を参照してください。

coder.Type オブジェクトを使用して可変サイズの入力の型を指定することもできます。coder.Type オブジェクトは、コマンド ラインまたはコード生成の型エディターを使用して作成および編集できます。コード生成の型エディターを使用した入力の型の作成と編集を参照してください。

たとえば、以下の関数を考えます。

function out = demoVarsize(n) %#codegen
x = ones(n,n);
coder.varsize("y",[10,1],[true,false])
y = (1:n)';
z = 5;
z(end+1) = 3;
out = n;
end

n を固定サイズのスカラーとして指定して、この関数のコードを生成し、コード生成レポートを検証します。

  • x のサイズは :?x:? です。どちらの次元も制限のない可変サイズです。

  • y のサイズは :10x1 です。1 番目の次元は上限が 10 の可変サイズ、2 番目の次元は固定サイズの 1 です。

  • z のサイズは 1x:2 です。1 番目の次元は固定サイズの 1、2 番目の次元は可変サイズで上限が 2 です。

  • n のサイズは 1x1 です。どちらの次元も固定サイズの 1 です。

この関数のコードを生成する場合、n を可変サイズのスカラーとして指定 (:1x:1) すると、ones 関数はスカラー値しか受け入れないためコード生成に失敗します。

メモ

コード ジェネレーターでは、:1 を 1 と等価として扱いません。関数でスカラーが必要な場合、固定サイズ 1x1 の変数を渡す必要があります。サイズが :1x11x:1、または :1x:1 の変数を渡すと、コード生成に失敗したり、生成コードの実行時にエラーが発生したりすることがあります。同様に、関数でベクトルが必要な場合は、いずれかの次元が固定サイズの 1 でなければなりません。

C コードと C++ コードにおける可変サイズ配列の実装の違い

動的に割り当てられるデータをコード ジェネレーターが生成コードに実装する方法は、ターゲット言語によって異なります。C を生成する場合、コード ジェネレーターは emxArray という構造体を使用します。C++ を生成する場合、コード ジェネレーターは coder::array というクラス テンプレートを使用します。生成される C コードまたは C++ コードでこれらのデータ構造体を使用する方法については、生成される関数インターフェイスでの動的に割り当てられる C 配列の使用または生成された関数インターフェイスでの動的に割り当てられた C++ 配列の使用をそれぞれ参照してください。

可変サイズ配列のメモリ割り当て

既定では、可変サイズ配列に対するコード生成のサポートは有効で、構成可能なしきい値以上のサイズをもつ可変サイズ配列に対して動的メモリ割り当てが有効になっています。既定では以下のようになります。

  • 固定サイズ配列の場合、コード ジェネレーターはメモリをコード生成時に事前に割り当てます。

  • サイズが構成されたしきい値未満の可変サイズ配列の場合、コード ジェネレーターはメモリをコード生成時に事前に割り当てます。

  • 制限のない可変サイズ配列、サイズが実行時に決まる可変サイズ配列、サイズが構成されたしきい値以上の可変サイズ配列の場合、コード ジェネレーターはメモリを実行時に動的に割り当てます。

アプリケーションのニーズに応じて、可変サイズのサポートとメモリ割り当ての設定を制御できます。

可変サイズ配列のサポートの無効化

アプリケーションで可変サイズのデータを使用しない場合は、可変サイズ配列のサポートを無効にして生成コードのパフォーマンスを改善できます。可変サイズ配列のサポートを無効にするには、次のいずれかの方法を使用します。

  • コード構成オブジェクトで、EnableVariableSizing パラメーターを false に設定する。

  • MATLAB Coder™ アプリで、[メモリ] 設定の [可変サイズを有効化] チェック ボックスをオフにする。

動的メモリ割り当ての制御

動的メモリ割り当ての制御は、生成コードのパフォーマンスを微調整するのに役立ちます。動的メモリ割り当てによってスタックのストレージ要件を減らすことができます。ただし、メモリを実行時に動的に割り当てるため、生成コードの速度が低下する可能性があります。可変サイズ配列に対する動的メモリ割り当ての制御の詳細については、可変サイズの配列に対するメモリ割り当ての制御を参照してください。可変サイズ配列に対する動的メモリ割り当ての制御については、固定サイズの配列に対する動的メモリ割り当ての制御を参照してください。

ループ内でベクトルを拡張する MATLAB 関数のコードの生成

この例では、制限付きと制限なしの可変サイズ配列を使用する MATLAB® 関数の C コードと C++ コードを生成する方法を示します。

MATLAB 関数とサンプル データの作成

MATLAB 関数 myuniquetol を作成します。この関数は、指定された許容誤差 tol に関して一意である入力ベクトル A の要素を識別します。A を並べ替えた後、関数は A の要素を反復します。要素 A(i) と最後に B に追加された要素との差の絶対値が tol より大きい場合にのみ、A(i)B に追加します。その後、関数は B を返します。

type myuniquetol.m
function B = myuniquetol(A,tol)
A = sort(A);
B = A(1);
k = 1;
for i = 2:length(A)
   if abs(A(k)-A(i)) > tol
      B = [B A(i)];
      k = i;
   end
end

ノイズを含む値の 10 要素ベクトルを生成し、このベクトルの一意の要素を myuniquetol を使用して識別します。許容誤差は 0.05 とします。

noisyData = 0.01*sin(1:10)+[1.01, 1.02, 1.03, 2.05, 2.10, 3.00, 3.01, 4.50, 5.00, 5.05];
cleanData = myuniquetol(noisyData,0.05)
cleanData = 1×5

    1.0184    2.0424    2.9972    4.5099    5.0041

コード生成用の MATLAB コードの準備

myuniquetol 関数の名前を myuniquetolCG に変更します。myuniquetolCG%#codegen 命令を追加して、コード生成に固有の警告とエラーを特定するように MATLAB コード アナライザーに指示します。この関数を MATLAB エディターで調べます。コード アナライザーは、変数 B のサイズが for ループで変わる可能性があることを検出し、警告を発行します。ベクトル B はベクトル A から値が追加されるとサイズが拡張されるため、この警告は無視してかまいません。

type myuniquetolCG.m
function B = myuniquetolCG(A,tol) %#codegen
A = sort(A);
B = A(1);
k = 1;
for i = 2:length(A)
   if abs(A(k)-A(i)) > tol
      B = [B A(i)];
      k = i;
   end
end

MEX 関数の生成とテスト

C/C++ コードを生成する前に、MEX 関数を生成してテストすることが重要です。C/C++ コードを生成する前に MATLAB で MEX 関数を実行することにより、実行時エラーを検出して修正できます。さらに、MEX 関数を使用して、生成されたコードが元の MATLAB コードと同様に機能することを確認できます。

codegenコマンドを使用して myuniquetolCG から MEX 関数を生成します。-report オプションを使用してレポートを生成し、-args オプションを使用して以下の入力引数の型を指定します。

  • 1 番目の入力引数について、coder.typeofを使用して最大長が 100 の可変長の行ベクトルとして定義する。

  • 2 番目の入力引数について、固定サイズのスカラーとして例で定義する。

codegen myuniquetolCG -args {coder.typeof(0,[1,100],[false,true]),0} -report
Code generation successful: View report

レポートを開き、[変数] タブで定義を調べます。B は制限のない行ベクトル、A は長さの上限が 100 の可変長のベクトルです。

元の MATLAB 関数に渡したのと同じ入力を使用して MEX 関数をテストし、結果を比較します。MEX 関数は同じ出力を生成します。

cleanData_mex = myuniquetolCG_mex(noisyData,0.05)
cleanData_mex = 1×5

    1.0184    2.0424    2.9972    4.5099    5.0041

C コードの生成

myuniquetolCG の静的な C ライブラリを生成し、MEX 関数を生成するときに使用したものと同じ入力引数を指定します。既定では、codegen は、動的メモリ割り当てしきい値の 64 キロバイトより小さいサイズのデータに対してメモリを静的に割り当てます。配列のサイズがしきい値以上の場合や配列が制限なしの場合、codegen はメモリをヒープで動的に割り当てます。

codegen myuniquetolCG -config:lib -args {coder.typeof(0,[1,100],[false,true]),0} -report
Warning: Code generation is using a coder.EmbeddedCodeConfig object. Because
Embedded Coder is not installed, this might cause some Embedded Coder features
to fail.


Code generation successful (with warnings): View report

ファイル myuniquetolCG.h で関数宣言を調べます。

myfile = fullfile("codegen","lib","myuniquetolCG","myuniquetolCG.h");
coder.example.extractLines(myfile,"/* Function Declarations */",");",0,1)
extern void myuniquetolCG(const double A_data[], const int A_size[2],
                          double tol, emxArray_real_T *B);

コード ジェネレーターは A のサイズを計算し、A の最大サイズが既定の動的メモリ割り当てしきい値の 64 キロバイトより小さいため、このメモリを静的に割り当てます。生成される関数宣言には以下が含まれます。

  • double A_data[]A の定義です。

  • const int A_size[2]。入力の実際のサイズです。

  • double toltol の定義です。

  • emxArray_real_T *BB の定義です。

コード ジェネレーターは、B は上限が不明な可変サイズであると判定し、BemxArray という可変サイズの配列型として表します。MATLAB Coder™ には、それらの型の配列を生成コードで作成して操作するためのユーティリティ関数が用意されています。詳細については、生成される関数インターフェイスでの動的に割り当てられる C 配列の使用を参照してください。

C++ コードの生成

myuniquetolCG の静的な C++ ライブラリを生成し、MEX 関数を生成するときに使用したものと同じ入力引数を指定します。-lang オプションを使用して C++ をターゲット言語として指定します。前に生成した C コードがコード ジェネレーターによって上書きされないように、-d オプションを使用して別の出力フォルダーを指定します。

codegen myuniquetolCG -config:lib -lang:c++ -d myuniquetolCG_cpp -args {coder.typeof(0,[1,100],[false,true]),0} -report
Warning: Code generation is using a coder.EmbeddedCodeConfig object. Because
Embedded Coder is not installed, this might cause some Embedded Coder features
to fail.


Code generation successful (with warnings): View report

ファイル myuniquetolCG.h で関数宣言を調べます。

myfile = fullfile("myuniquetolCG_cpp","myuniquetolCG.h");
coder.example.extractLines(myfile,"// Function Declarations",");",0,1)
extern void myuniquetolCG(const double A_data[], const int A_size[2],
                          double tol, coder::array<double, 2U> &B);

生成される C++ 関数宣言は C 関数宣言と似ていますが、動的に割り当てられる配列が emxArray ではなく coder::array クラス テンプレートである点が異なります。カスタム C++ コードで coder::array クラス テンプレートを使用する方法については、生成された関数インターフェイスでの動的に割り当てられた C++ 配列の使用を参照してください。

固定サイズの入力配列に動的メモリ割り当てを使用する C コードの生成

動的メモリ割り当ては生成されたコードの速度を低下させる可能性があります。ただし、大きな配列では、動的メモリ割り当てによってストレージ要件を減らすことができます。A を非常に大きな可変サイズ配列として指定すると、コード ジェネレーターは A のメモリをヒープで動的に割り当てます。可変サイズ配列に対する動的メモリ割り当ての制御の詳細については、可変サイズの配列に対するメモリ割り当ての制御を参照してください。

codegen myuniquetolCG -config:lib -args {coder.typeof(0,[1,10000],[false,true]),0} -report
Warning: Code generation is using a coder.EmbeddedCodeConfig object. Because
Embedded Coder is not installed, this might cause some Embedded Coder features
to fail.


Code generation successful (with warnings): View report
myfile = fullfile("codegen","lib","myuniquetolCG","myuniquetolCG.h");
coder.example.extractLines(myfile,"/* Function Declarations */",");",0,1)
extern void myuniquetolCG(const emxArray_real_T *A, double tol,
                          emxArray_real_T *B);

制限のある出力ベクトルの C コードの生成

入力 A は可変サイズであり、上限が 100 であるため、出力ベクトル B には最大で 100 個の要素が格納されます。coder.varsizeを使用して、B の長さの上限を 100 要素に設定します。

type myuniquetolCG_bounded.m
function B = myuniquetolCG_bounded(A,tol) %#codegen
coder.varsize("B",[1,100],[false,true]);
A = sort(A);
B = A(1);
k = 1;
for i = 2:length(A)
   if abs(A(k)-A(i)) > tol
      B = [B A(i)];
      k = i;
   end
end

この関数のコードを生成し、MEX 関数を生成するときに使用したものと同じ入力の型を指定します。関数宣言を調べます。コード ジェネレーターは、B のメモリを静的に割り当て、B のサイズを int B_size[2] に格納します。

codegen myuniquetolCG_bounded -config:lib -args {coder.typeof(0,[1,100],[false,true]),0} -report
Warning: Code generation is using a coder.EmbeddedCodeConfig object. Because
Embedded Coder is not installed, this might cause some Embedded Coder features
to fail.


Code generation successful (with warnings): View report
myfile = fullfile("codegen","lib","myuniquetolCG_bounded","myuniquetolCG_bounded.h");
coder.example.extractLines(myfile,"/* Function Declarations */",");",0,1)
extern void myuniquetolCG_bounded(const double A_data[], const int A_size[2],
                                  double tol, double B_data[], int B_size[2]);

参考

トピック