Main Content

可変サイズ データのためのコード生成

可変サイズ データは実行時にサイズが変化する可能性のあるデータです。MATLAB® Coder™ を使用して、可変サイズ データを使用している MATLAB コードから C/C++ コードを生成できます。MATLAB では、コード生成に対して制限付きと制限なしの可変サイズ データがサポートされています。"制限付き可変サイズ データ" には固定の上限が設定されています。このデータはスタックで静的に割り当てることも、ヒープで動的に割り当てることもできます。"制限なしの可変サイズ データ" には上限が設定されていません。このデータはヒープで割り当てなければなりません。既定では、MEX コードおよび C/C++ コードの生成において可変サイズ データのサポートは有効で、構成可能なしきい値以上のサイズをもつ可変サイズ配列に対し動的なメモリの割り当てが有効になっています。

可変サイズ データのサポートの無効化

既定では、MEX および C/C++ コードの生成において、可変サイズ データのサポートは有効になっています。[プロジェクトの設定] ダイアログ ボックス、コマンド ラインから、またはダイアログ ボックスを使用して可変サイズの設定を変更します。

MATLAB Coder アプリの使用

  1. [生成] ダイアログ ボックスを開くために、[コード生成] ページの [生成] 矢印 をクリックします。

  2. [詳細設定] をクリックします。

  3. [メモリ] タブで、[可変サイズを有効化] をオンまたはオフにします。

コマンド ラインの入力

  1. コード生成の構成オブジェクトを作成します。たとえば、ライブラリの場合は以下のとおりです。

    cfg = coder.config('lib');

  2. EnableVariableSizing オプションを次のように設定します。

    cfg.EnableVariableSizing = false;

  3. -config オプションを使用して、構成オブジェクトを codegen に渡します。

    codegen -config cfg foo
    

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

既定では、設定可能なしきい値以上のサイズをもつ可変サイズ配列に対して、動的メモリ割り当てが有効になっています。[プロジェクトの設定] ダイアログ ボックスまたはコマンド ラインから、動的メモリ割り当ての設定を変更できます。

MATLAB Coder アプリの使用

  1. [生成] ダイアログ ボックスを開くために、[コード生成] ページの [生成] 矢印 をクリックします。

  2. [詳細設定] をクリックします。

  3. [メモリ] タブで、[動的メモリ割り当てを有効化] を次のいずれかのオプションに設定します。

    設定アクション
    false動的メモリ割り当てが無効になります。可変サイズ データはスタックで静的に割り当てられます。
    true[動的メモリ割り当てしきい値] 以上のサイズをもつ可変サイズ配列に対して、動的メモリ割り当てが有効になります。このしきい値より小さいサイズの可変サイズ配列は、スタックで割り当てられます。

  4. 必要に応じて、[動的メモリ割り当てしきい値] を構成してメモリ割り当てを微調整できます。[動的メモリ割り当てしきい値] の値を 0 に設定すると、可変サイズ データがヒープで動的に割り当てられます。

コマンド ラインの入力

  1. コード生成の構成オブジェクトを作成します。たとえば、MEX 関数の場合は、以下のようになります。

    mexcfg = coder.config('mex');

  2. EnableDynamicMemoryAllocation オプションを次のように設定します。

    設定アクション
    mexcfg.EnableDynamicMemoryAllocation=false;
    動的メモリ割り当てが無効になります。可変サイズ データはスタックで静的に割り当てられます。
    mexcfg.EnableDynamicMemoryAllocation=true;
    DynamicMemoryAllocationThreshold パラメーターを使用して指定された値以上のサイズ (バイト単位) の可変サイズ配列に対して動的メモリ割り当てが有効になります。このしきい値より小さいサイズの可変サイズ配列は、スタックで割り当てられます。

  3. DynamicMemoryAllocationThreshold オプションを構成してメモリ割り当てを微調整できます。DynamicMemoryAllocationThreshold0 に設定すると、可変サイズ データがヒープで動的に割り当てられます。

  4. -config オプションを使用して、構成オブジェクトを codegen に渡します。

    codegen -config mexcfg foo
    

可変サイズ データによる MATLAB 関数のコードの生成

はじめに MEX コードを生成して生成コードを検証し、次にプロトタイプの結果に満足できたらスタンドアロン コードを生成する基本ワークフローを以下に示します。

簡単な例を使用してこれらの手順を実行するには、ループ内でベクトルを拡張する MATLAB 関数のコードの生成を参照してください。

  1. MATLAB エディターで、コンパイル命令 %#codegen を関数の最上部に追加します。

    この命令は、以下を実行します。

    • MATLAB アルゴリズムのコードを生成することを示す。

    • コード生成中に潜在的なエラーを検出するために MATLAB コード アナライザーでのチェックをオンにする。

  2. コード アナライザーで検出された問題を解決します。

    場合によっては、コードでデータに固定サイズが割り当てられているときに、ループでの割り当てや連結によって後からデータが大きくなると、MATLAB コード アナライザーが警告を表示することがあります。実行時にデータのサイズが変化することが想定されている場合は、これらの警告を無視できます。

  3. codegen を使用して MEX 関数を生成し、生成されたコードを検証します。以下のコマンド ライン オプションを使用します。

    • -args {coder.typeof...}: 可変サイズ入力がある場合

    • -report: コード生成レポートを生成する場合

    以下に例を示します。

    codegen -report foo -args {coder.typeof(0,[2 4],1)}
    
    このコマンドは coder.typeof を使用して関数 foo への可変サイズ入力を 1 つ指定します。最初の引数 0 は、入力データ型 (double) と実数/複素数 (real) を示します。2 番目の引数 [2 4] は、サイズを示す 2 次元の行列です。3 番目の引数 1 は、入力が可変サイズであることを示します。最初の次元の上限は 2 で、2 番目の次元の上限は 4 です。

    メモ

    コンパイル中に codegen は定義後にサイズが変化した変数と構造体フィールドを検出し、これらが発生した場合はエラーとして報告します。さらに、codegen は実行時チェックを実行し、データが上限を超えた場合はエラーを生成します。

  4. サイズ不一致エラーを解決します。

    原因解決方法詳細
    データのサイズがロックされた後にサイズを変更しようとした。データを可変サイズとして宣言します。サイズ不一致エラーの診断と修正を参照してください。
  5. 上限エラーを解決します。

    原因解決方法詳細
    MATLAB が上限を判断または計算できない。上限を指定します。可変サイズ配列の上限の指定およびサイズ不一致エラーの診断と修正を参照してください。
    MATLAB が制限なしの可変サイズ データの上限を計算しようとした。制限なしのデータの場合は、動的メモリ割り当てを有効にします。 動的メモリ割り当ての制御を参照してください。
  6. 関数 codegen を使用して C/C++ コードを生成します。

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

MATLAB 関数 myuniquetol について

この例は、関数 myuniquetol を使用します。この関数は、入力ベクトル A のバージョンであるベクトル B で返されます。ここで、各要素はそれぞれの許容誤差 tol 内で一意であるとします。ベクトル B では、すべての ij に対して abs(B(i) - B(j)) > tol となります。まず、入力ベクトル A は最大 100 までの要素を格納できると想定します。

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

手順 1: コード生成のコンパイル命令の追加

コンパイル命令 %#codegen を関数の最上部に追加します。

function B = myuniquetol(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

手順 2: コード アナライザーで検出された問題の解決

コード アナライザーは変数 B のサイズが for- ループ内で変化する可能性を検出します。これにより、次の警告が表示されます。

The variable 'B' appears to change size on every loop iteration.
Consider preallocating for speed.

この関数では、ベクトル B はベクトル A から値を追加するためサイズを拡大することが想定されます。したがって、この警告は無視できます。

手順 3: MEX コードの生成

C/C++ コードを生成する前に MEX コードを生成することをお勧めします。MEX コードを生成することによって、実行時には検出が難しくなるコード生成上の問題を特定できます。

  1. myuniquetol の MEX 関数を生成します。

    codegen -report myuniquetol -args {coder.typeof(0,[1 100],1),coder.typeof(0)}

     これらのコマンド ライン オプションの意味

    コード生成は正常に実行されます。codegen で問題は検出されません。現在のフォルダーで、codegenmyuniquetol の MEX 関数を生成し、コード生成レポートへのリンクを提供します。

  2. [レポートの表示] リンクをクリックします。

  3. コード生成レポートで [変数] タブを選択します。

    Contents of the Variables tab, showing definitions for variables B, A, tol, i, and k

    A は上限が 100 の可変サイズであることを指定したため、A のサイズは 1 行 :100 列です。変数 B のサイズは 1x:? で、上限のない可変サイズであることが示されます。

手順 4: C コードの生成

可変サイズ入力の C コードを生成します。既定では、codegen は、動的メモリ割り当てしきい値の 64 キロバイトより小さいサイズのデータに対してメモリを静的に割り当てます。データのサイズがしきい値以上の場合や制限なしの場合、codegen はヒープでメモリを動的に割り当てます。

  1. C ライブラリ生成の構成オプションを作成します。

    cfg=coder.config('lib');
    
  2. 次のコマンドを実行します。

    codegen -config cfg -report myuniquetol -args {coder.typeof(0,[1 100],1),coder.typeof(0)}

    codegen は、既定の場所 codegen\lib\myuniquetol にスタティック ライブラリを生成し、コード生成レポートへのリンクを提供します。

  3. [レポートの表示] リンクをクリックします。

  4. 生成ファイルのリストで、myuniquetol.h をクリックします。

    関数宣言は以下のとおりです。

    extern void myuniquetol(const double A_data[], const int A_size[2], double tol,
      emxArray_real_T *B);

    codegenA のサイズを計算し、その最大サイズが既定の動的メモリ割り当てしきい値の 64k バイトより小さいため、このメモリを静的に割り当てます。生成されたコードには次が含まれます。

    • double A_data[]: A の定義。

    • int A_size[2]: 入力の実際のサイズ。

    コード ジェネレーターは、B が、上限が不明な可変サイズであると判断します。これは BemxArray_real_T として表します。MATLAB は、生成されたコード内で emxArrays を作成して相互作用のためのユーティリティ関数を提供します。詳細は、生成された関数インターフェイスでの C 配列の使用を参照してください。

手順 5: 出力ベクトルに対する上限の指定

入力 A は上限が 100 の可変サイズであることを指定しました。このため、出力 B100 要素よりも大きくすることはできません。

  • coder.varsize を使用して、B は上限が 100 の可変サイズであることを示します。

    function B = myuniquetol(A, tol) %#codegen
    A = sort(A);
    coder.varsize('B', [1 100], [0 1]);
    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

  • コードを生成します。

    codegen -config cfg -report myuniquetol -args {coder.typeof(0,[1 100],1),coder.typeof(0)}  

    関数宣言は以下のとおりです。

    extern void myuniquetol(const double A_data[], const int A_size[2], double tol,
      double B_data[], int B_size[2]);

    コード ジェネレーターは、メモリを B に静的に割り当てます。B のサイズを int B_size[2] に格納します。

手順 6: 動的メモリ割り当てしきい値の変更

この手順では、動的メモリ割り当てしきい値を減らして、このしきい値を超える入力のコードを生成します。この手順では、A の 2 番目の次元に上限 10000 があることを指定します。

  1. B の上限を A の上限と一致するように変更します。

    function B = myuniquetol(A, tol) %#codegen
    A = sort(A);
    coder.varsize('B', [1 10000], [0 1]);
    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

  2. 動的メモリ割り当てしきい値を 4 キロバイトに設定し、入力 A のサイズがこのしきい値を超える場合のコードを生成します。

    cfg.DynamicMemoryAllocationThreshold=4096;
    codegen -config cfg -report myuniquetol -args {coder.typeof(0,[1 10000],1),coder.typeof(0)} 

  3. レポートで生成コードを表示します。現在、AB の最大サイズが動的メモリ割り当てしきい値を超えているため、codegenAB をヒープで動的に割り当てます。生成されたコードでは、AB は型 emxArray_real_T をもちます。

    extern void myuniquetol(const emxArray_real_T *A, double tol, emxArray_real_T *B);

関連するトピック