メインコンテンツ

コード生成における cell 配列の制限事項

コード生成用の MATLAB® コードで cell 配列を使用するときは、以下の制限に従わなければなりません。

一貫性のある要素型の代入

cell 配列の要素に代入する値の型は、すべての実行パスで同じでなければなりません。たとえば、関数 inconsistentTypeError について考えます。ca{2} がある実行パスでは double、別の実行パスでは char であるため、次の関数のコード生成は失敗します。

function out = inconsistentTypeError(n) %#codegen
ca = cell(1,3);
if n > 1
    ca{1} = 1;
    ca{2} = 2;
    ca{3} = 3;
else
    ca{1} = 10;
    ca{2} = 'a';
    ca{3} = 30;
end
out = ca{1};
end

可変サイズの cell 配列は同種でなければならない

cell 配列を含む MATLAB 関数のコードを生成すると、コード ジェネレーターは各 cell 配列を "同種" または "異種混合" として分類します。一般に、コード ジェネレーターは同じ型の要素を含む cell 配列を同種として、異なる型の要素を含む cell 配列を異種混合として分類します。コード ジェネレーターが同種および異種混合の cell 配列を処理する方法の詳細については、cell 配列のコード生成を参照してください。

coder.varsize (MATLAB Coder) を使用して同種の cell 配列を可変サイズとして定義し、可変サイズの cell 配列の上限を設定できます。たとえば、次のコードは caXcaY を固定サイズ 1x3 の cell 配列から、2 番目の次元が最大でサイズ 5 (1x:5) まで変化できる可変サイズの cell 配列に変更します。

...
caX = {1 2 3};
caY = cell(1,3);
coder.varsize('caX',[1 5])
coder.varsize('caY',[1 5])
...

すべての cell 配列要素への値の代入

cell 配列を使用する前に、すべての実行パスですべての cell 配列要素に値を代入しなければなりません。関数 cell を使用して可変サイズの cell 配列を作成する場合、生成されるコードでは cell 配列の要素のサイズと型は未定義になります。そのため、コード生成用の MATLAB コードでは、関数 cell を使用して作成した可変サイズのすべての cell 配列の全要素に必ず初期値を代入しなければなりません。たとえば、関数 incompleteAssignmentError について考えます。この関数のコード生成は失敗します。これは、関数が返す要素 ca{2} が、n5 未満の実行パス上で未定義であるとコード ジェネレーターによって検出されるためです。

function out = incompleteAssignmentError(n) %#codegen
ca = cell(1,2);
if n < 5
    ca{1} = 0;    
else
    ca{2} = 3;
end
out = ca{2};
end

MATLAB コードで cell 配列のすべての要素に値が代入されていても、cell 配列のすべての要素が代入されていることをコード ジェネレーターが認識できないため、コード生成が失敗することがあります。一般に、cellArrayPatternExample で示されているコーディング パターンを使用して、cell によって作成した可変サイズの cell 配列の要素に値を代入します。

function out = cellArrayPatternExample(n) %#codegen
ca = cell(1,n);   
for i = 1:n
    ca{i} = i;
end
out = ca{n};
end

すべての cell 配列要素を確実に定義するために使用できるその他のパターンについては、問題の解決: cell 配列の要素は使用前に完全に定義する必要があるを参照してください。

関数 cell と同じ実行パスでの初期値の代入

関数 cell を使用して cell 配列を作成する場合、cell 配列を作成する関数 cell と同じ一意の実行パスで cell 配列要素に初期値を代入するループを含めなければなりません。たとえば、関数 cellLoopError のコード生成は失敗します。これは、cell 配列 ca の要素に初期値を代入する for ループが、cell 配列を作成する関数 cell と共に一意の実行パス上にないためです。

function out = cellLoopError(n) %#codegen
if n < 5
    ca = cell(1,n);
else
    ca = cell(n,1);
end
for i = 1:n
    ca{i} = i;
end
out = ca;
end

この問題を解決するには、各 cell 配列を作成する関数 cell を含むコード ブロック内で cell 配列要素に初期値を代入します。

function out = cellLoopExample(n) %#codegen
if n < 5
    ca = cell(1,n);
    for i = 1:n
        ca{i} = 0;
    end
else
    ca = cell(n,1);
    for i = 1:n
        ca{i} = 0;
    end
end
for i = 1:n
    ca{i} = i;
end
out = ca{n};
end

オブジェクト プロパティまたは構造体フィールドで可変サイズの cell 配列に初期値を代入するには、一時変数を使用する

関数 cell を使用して可変サイズの cell 配列を作成する場合、オブジェクト プロパティまたは構造体フィールドで使用する前に、cell 配列のすべての要素に初期値を代入しなければなりません。たとえば、関数 fieldAssignmentError のコード生成は失敗します。これは、構造体フィールドの cell 配列要素に直接初期値を代入しているためです。

function out = fieldAssignmentError(n) %#codegen
s.field = cell(1,n);
for i = 1:n
    s.field{i} = i+1;
end
out = s.field{n};
end
このエラーを回避するには、一時変数を使用して cell 配列を初期化します。次に、初期化した cell 配列を構造体フィールドまたはオブジェクト プロパティに代入します。その後、構造体フィールドまたはオブジェクト プロパティに直接アクセスすることで、cell 配列の要素を変更することができます。
function out = fieldAssignmentExample(n) %#codegen
ca = cell(1,n);
for i = 1:n
   ca{i} = 0;
end
s.field = ca;
for i = 1:n
   s.field{i} = i+1;
end
out = s.field{n};
end

異種混合配列にインデックスを付けるには、定数のインデックスまたは定数境界をもつ for ループを使用する

cell 配列を含む MATLAB 関数のコードを生成すると、コード ジェネレーターは各 cell 配列を "同種" または "異種混合" として分類します。一般に、コード ジェネレーターは同じ型の要素を含む cell 配列を同種として、異なる型の要素を含む cell 配列を異種混合として分類します。コード ジェネレーターが同種および異種混合の cell 配列を処理する方法の詳細については、cell 配列のコード生成を参照してください。

定数のインデックスまたは定数境界をもつ for ループを使用して、異種混合 cell 配列にインデックスを付けなければなりません。たとえば、インデックスが定数ではないため、関数 cellIndexingError のコード生成は失敗します。

function cellIndexingError(n) %#codegen
ca = {1 "a" 2 5:7 3 "c"};
disp(ca{n});
end

コード ジェネレーターはループを展開するため、つまりループの反復ごとにループ本体の個別のコピーを作成するため、定数境界をもつ for ループを使用して異種混合 cell 配列にインデックスを付けることができます。

function cellIndexingExample(n) %#codegen
ca = {1 "a" 2 5:7 3 "c"};
for i = 1:6
    if i == n
        disp(ca{i});
    end
end
end

メモ

for ループ本体が大きい場合や、反復数が多い場合、展開によってコンパイル時間が増加し、非効率的なコードが生成される可能性があります。

{end + 1} を使用して cell 配列を拡張するには、特定のコーディング パターンを使用する

コード生成は、コード生成用の MATLAB コードで {end + 1} を使用した cell 配列の拡張をサポートしています。たとえば、{end + 1} を使用して配列 ca を拡張する関数 growCellArray のコードを生成できます。

function out = growCellArrayExample(n) %#codegen
ca = {1  2};
for i = 1:n
    ca{end+1} = 3+i;
end
out = ca{n};
end

コード生成用の MATLAB コードで cell 配列を拡張するために {end + 1} を使用するときは、以下の制限に従わなければなりません。

  • {end + 1} 要素に値を代入することによってのみ cell 配列を拡張できます。{end + 2} などの後続の要素への値の代入はサポートされていません。

  • cell 配列ベクトルを拡張するには、{end + 1} のみ使用できます。たとえば、ca はベクトルではなく行列であるため、関数 growMatrixError のコード生成は失敗します。

    function ca = growMatrixError %#codegen
    ca = {1 2; 3 4};
    ca{1,end+1} = 5;
    end
  • {end + 1} は変数の直後になければなりません。たとえば、growArraySubscriptError のコード生成は失敗します。これは、{end + 1}ca の隣ではなく ca{2} の隣にあるためです。

    function out = growArraySubscriptError(x) %#codegen
    ca = {'a' { 1 2 3 }};
    ca{2}{end+1} = x;
    out = ca{2}{4};
    end
    この問題を解決するには、変更する cell 配列の要素を一時変数に等しく設定します。その後、{end + 1} を使用して、一時変数を拡張します。coder.varsize を使用して、変更した cell 配列の要素のサイズを変更できるようにします。
    function out = growArrayExampleA(x) %#codegen
    ca = {'a' {1 2 3}};
    coder.varsize('ca{2}')
    temp = ca{2};
    temp{end+1} = x;
    ca{2} = temp;
    out = ca{2}{4};
    end

    または、{end + 1} の代わりに配列連結を使用して新しい要素を追加します。

    function out = growArrayExampleB(x) %#codegen
    ca = {'a' {1 2 3}};
    coder.varsize('ca{2}')
    ca{2} = [ca{2} {x}];
    out = ca{2}{4};
    end

  • {end + 1} を使用してループ内の cell 配列を拡張する場合、cell 配列は同種である必要があります。つまり、すべての cell 配列要素は同じ型でなければなりません。たとえば、関数 growHeterogeneousError のコード生成は失敗します。これは、cell 配列 castring 型と double 型の要素が含まれているためです。

    function out = growHeterogeneousError(n) %#codegen
    ca = {1  2 "a"};
    for i = 1:n
        ca{end+1} = 3+i;
    end
    out = ca;
    end
    コード ジェネレーターが同種および異種混合の cell 配列を処理する方法の詳細については、cell 配列のコード生成を参照してください。

cell 配列を直接反復処理するには、cell 配列の最初の次元が 1 でなければならない

MATLAB では、任意の次元数の cell 配列を直接反復処理することができます。たとえば、3 行 4 列の cell 配列を反復処理し、各列の内容を表示する関数 directIterationError ついて考えます。配列 ca の最初の次元が 1 ではないため、この関数のコード生成は失敗します。

function directIterationError
ca = {1 2 3 4; "five" "six" "seven" "eight"; 9 10 11 12};
for i = ca
    disp(i);
end
end

コード生成用の MATLAB コードで、最初の次元が 1 でない cell 配列を反復処理するには、cell 配列自体ではなく、cell 配列の各次元のサイズをループ処理します。

function iterationExample %#codegen
ca = {1 2 3 4; "five" "six" "seven" "eight"; 9 10 11 12};
for i = 1:size(ca,1)
    for j = 1:size(ca,2)
        disp(ca{i,j});
    end
end
end

cell 配列へのインデックス付けに小かっこ () を使用しない

コード生成用の MATLAB コードでは、小かっこ () を使用して cell 配列にインデックスを付けることはできません。中かっこ {} を使用して cell の内容にアクセスします。

cell 配列コンストラクター {} 内から関数 cell を呼び出さない

コード生成は cell 配列コンストラクター {} 内での関数 cell の使用をサポートしていません。このため、関数 cellCellError のコード生成は失敗します。

function out = cellCellError(n) %#codegen
ca = {cell(1,n) cell(1,n)};
for i = 1:n
    ca{1}{i} = i+1;
    ca{2}{i} = i+2;
end
out = ca;
end

他の cell 配列を含む cell 配列を作成するには、外側配列を作成する前に各内側 cell 配列のすべての要素を初期化します。その後、内側配列の要素に直接アクセスできます。

function out = cellCellExample(n) %#codegen
x = cell(1,n);
y = cell(1,n);
for i = 1:n
    x{i} = 0;
    y{i} = 0;
end
ca = {x y};
for i = 1:n
    ca{1}{i} = i+1;
    ca{2}{i} = i+2;
end
out = ca{1}{n}+ca{2}{n};
end

cell 配列に mxArray データを格納しない

コード生成用の MATLAB コードでは、mxArray とも呼ばれる MATLAB 配列を cell 配列に格納することはできません。coder.extrinsic を使用して外部関数を呼び出すと、呼び出された関数の実行時の出力は mxArray になります。そのため、最初に外部関数の出力を既知の型に変換せずに出力を cell 配列に格納することはできません。mxArrays の利用を参照してください。

coder.ceval を使用して外部 C/C++ 関数に cell 配列を渡さない

コード生成は、coder.ceval (MATLAB Coder) を使用して外部 C/C++ 関数に cell 配列を渡すことをサポートしていません。cell 配列が coder.ceval への入力引数である場合、cell 配列を通常の配列または構造体として再定義します。

参考

トピック