問題の解決: cell 配列の要素は使用前に完全に定義する必要がある
問題
動的に型指定される言語である MATLAB® とは異なり、C と C++ は静的に型指定されます。つまり、コード ジェネレーターは、生成されたコード内の変数を定義できるように、MATLAB コード内のすべての変数の型を判断できる必要があります。関数 cell
を使用して cell 配列を作成した場合、生成されたコードでは cell 配列の要素のサイズと型が未定義になります。そのため、コード生成用の MATLAB コードでは、関数 cell
を使用して作成したすべての cell 配列の全要素に必ず初期値を代入しなければなりません。
コード ジェネレーターが MATLAB コード内のすべての cell 配列の全要素の型を判別できない場合は、次の文を含むエラー メッセージが表示されます。
コード生成では、すべての cell 配列要素を使用前に完全に定義する必要があります。
MATLAB コードで cell 配列のすべての要素に値が代入されていても、特定のコーディング パターンでは、コード ジェネレーターが cell 配列のすべての要素に代入されていることを認識できないためにコード生成が失敗することがあります。該当するコーディング パターンには次のようなものがあります。
異なるループで cell 配列要素に初期値を代入する。たとえば、関数
cellArrayAssignmentError1
について考えます。MATLAB は、n
のすべての値について cell 配列ca
に値を代入します。ただし、すべての cell 配列要素がn
のすべての値に対して定義されていることをコード ジェネレーターが判断できないため、cellArrayAssignmentError1
のコード生成は失敗します。function out = cellArrayAssignmentError1(n) %#codegen ca = cell(1,n); for i = 1:5 ca{i} = 5; end for i = 6:n ca{i} = i; end out = ca{n}; end
cell
を使用して cell 配列を構築するために使用する変数が、cell 配列要素に初期値を代入するfor
ループを制御するために使用する変数と異なっている。たとえば、関数cellArrayAssignmentError2
について考えます。MATLAB は、n
のすべての値について cell 配列ca
に値を代入します。ただし、すべての cell 配列要素がn
のすべての値に対して定義されていることをコード ジェネレーターが判断できないため、cellArrayAssignmentError2
のコード生成は失敗します。function out = cellArrayAssignmentError2(n) %#codegen ca = cell(1,n); counter = n; for i = 1:counter ca{i} = 2*i; end out = ca{n}; end
cell 配列要素に初期値を代入するために使用する
for
ループで、ループ カウンターを1
以外の数値ずつインクリメントまたはデクリメントしている。たとえば、関数cellArrayAssignmentError3
について考えます。MATLAB は、n
のすべての値について cell 配列ca
に値を代入します。ただし、ca
のすべての要素がn
のすべての値に対して定義されていることをコード ジェネレーターが判断できないため、cellArrayAssignmentError3
のコード生成は失敗します。function out = cellArrayAssignmentError3(n) %#codegen ca = cell(1,n*2); for i = 1:2:n*2-1 ca{i} = 1; ca{i+1} = 2; end out = ca{n}; end
添字またはドット インデックス付けを使用して、cell 配列要素に初期値を代入する。たとえば、関数
cellArrayAssignmentError4
について考えます。MATLAB は、cell 配列ca
に値を代入します。ただし、ca
のすべての要素が定義される前に、コード ジェネレーターがca
に添字を付けることができないため、cellArrayAssignmentError4
のコード生成は失敗します。function out = cellArrayAssignmentError4 %#codegen ca = cell(1,3); for j = 1:3 ca{j}(1) = 10; ca{j}(2) = 20; ca{j}(3) = 30; end out = ca{2}; end
考えられる解決策
この問題を解決するには、次のいずれかの解決策を試してください。
認識されるコーディング パターンを使用して cell 配列要素に代入する
コード ジェネレーターが認識できるコーディング パターンを使用して、cell 配列の要素に値を代入します。for
ループを使用して cell 配列の要素に初期値を代入する場合に、cell 配列が可変サイズのときは、必ず次のようにしてください。
同じループ内ですべての要素に初期値を代入します。
cell 配列を作成するために関数
cell
で使用した変数と同じ変数をループ カウンターに使用します。ループ カウンターを
1
ずつインクリメントまたはデクリメントします。
1 行 n
列の cell 配列の各要素にスカラー値を代入するには、次のパターンに従います。
function out = codingPatternExample1(n) %#codegen ca = cell(1,n); for i = 1:n ca{i} = sqrt(i); end out = ca{n}; end
1 行 n
列の cell 配列の各要素に値の配列を代入するには、1 つのステートメントで各要素に値の配列を代入します。添字やドットによる代入は使用しないでください。
function out = codingPatternExample2(n) %#codegen ca = cell(1,n); for i = 1:n ca{i} = [sqrt(i) i i^2]; end out = ca{n}; end
多次元 cell 配列の各要素に値を代入するには、入れ子にしたループを使用します。たとえば、3 次元 (m
×n
×p
) 配列には、このコーディング パターンを使用します。
function out = codingPatternExample3(m,n,p) %#codegen ca = cell(m,n,p); for i = 1:m for j =1:n for k = 1:p ca{i,j,k} = i+j+k; end end end out = ca{m,n,p}; end
関数 repmat
を使用する
関数 repmat
は入力配列を受け取り、それを行次元と列次元で指定された回数複製して出力配列を作成します。cell 配列に繰り返し要素が含まれている場合は、repmat
を使用して cell 配列の要素を定義するようにコードを書き換えることができます。たとえば、関数 cell
を使用して 1 行 (n*2)
列の cell 配列を作成する関数 repmatAssignmentError
について考えます。repmatAssignmentError
は ca
の奇数要素に 1
を代入し、偶数要素に 0
を代入します。異なる for
ループ内で初期値が cell 配列要素に代入されるため、またループ カウンターが 1 以外の値ずつインクリメントされるため、この関数のコード生成は失敗します。
function out = repmatAssignmentError(n) %#codegen ca = cell(1,n*2); for i = 1:2:n*2 ca{i} = 1; end for i = 2:2:n*2 ca{i} = 0; end out = ca{n}; end
この問題を解決するには、まず関数 cell
を使用して、1 番目の要素が 1 で 2 番目の要素が 0 である一時的な 1 行 2 列の cell 配列を作成します。次に、関数 repmat
を使用して、要素の値が 1 と 2 の間で交互に切り替わる 1 行 (n*2)
列の cell 配列を作成します。
function out = repmatAssignmentExample(n) %#codegen tmp = cell(1,2); tmp{1} = 1; tmp{2} = 0; ca = repmat(tmp,1,n); out = ca{n}; end
coder.nullcopy
を使用する
関数 coder.nullcopy
を使用して、cell 配列要素に値を明示的に代入することなく、同種の cell 配列用にメモリを事前に割り当てることができます。一般に、同種の cell 配列には、double
や string
など、すべて同じ型の要素が含まれています。しかし、特定の状況では、コード ジェネレーターは同じ cell 配列を、あるコンテキストでは同種として分類するが、他のコンテキストでは異種混合として分類することがあります。cell 配列のコード生成を参照してください。
coder.nullcopy
を使用して同種の cell 配列を定義する場合、前述の認識されるコーディング パターンに従わなくてもコードを生成できます。たとえば、関数 nullcopyExample
について考えます。この関数は coder.nullcopy
を使用して同種の cell 配列 ca
用にメモリを事前に割り当てるため、2 つの別個のループで cell 配列に値を代入できます。
function out = nullcopyExample(n) %#codegen tmp = cell(1,n); ca = coder.nullcopy(tmp); for i = 1:4 ca{i} = 0; end for i = 5:n ca{i} = i; end out = ca{n}; end
メモ
coder.nullcopy
は注意して使用してください。cell 配列のすべての要素に値が代入されていることを確認する必要があります。初期化されていない cell 配列要素にアクセスした場合、結果は予測できません。
参考
cell
| repmat
| coder.nullcopy