コード生成時の可変サイズのサポートに関する MATLAB との非互換性
スカラー拡張に関する MATLAB との非互換性
スカラー拡張とは、スカラー データをベクトルや行列のデータの次元に一致するように変換する方法です。一方のオペランドがスカラーで他方がスカラーでない場合、スカラー拡張は、他方のオペランドの各要素にスカラーを適用します。
コード生成中は、スカラー拡張ルールが適用されます。ただし、2 つの可変サイズの式を操作する場合は例外です。この場合、両方のオペランドが同じサイズでなければなりません。生成されたコードでは、実行時にどちらかの可変サイズの式がスカラーだった場合もスカラー拡張を行いません。したがって、実行時エラー チェックが有効な場合、実行時エラーが発生する可能性があります。
次の関数を考えてみます。
function y = scalar_exp_test_err1(u) %#codegen y = ones(3); switch u case 0 z = 0; case 1 z = 1; otherwise z = zeros(3); end y(:) = z;
この関数のコードを生成すると、コード ジェネレーターは z
が上限 3
の可変サイズであると判定します。
u
を 0 または 1 にして MEX 関数を実行すると、実行時には z
がスカラーでも、生成されたコードはスカラー拡張を行いません。したがって、実行時エラー チェックが有効な場合、実行時エラーが発生する可能性があります。
scalar_exp_test_err1_mex(0) Subscripted assignment dimension mismatch: [9] ~= [1]. Error in scalar_exp_test_err1 (line 11) y(:) = z;
この問題を回避するには、インデックス付けを使用して強制的に z
をスカラー値にします。
function y = scalar_exp_test_err1(u) %#codegen y = ones(3); switch u case 0 z = 0; case 1 z = 1; otherwise z = zeros(3); end y(:) = z(1);
可変サイズの N 次元配列のサイズを判定する上での MATLAB との非互換性
可変サイズの N 次元配列については、関数 size
が、生成されたコードで MATLAB® ソース コードと異なる結果を返す場合があります。生成されたコードでは、size(A)
は、可変サイズの n 次元配列の後に続く大きさが 1 の次元を破棄しないため、固定長の出力を返します。それとは対照的に、MATLAB の size(A)
は可変長の出力を返します。これは、後続する大きさが 1 の次元を切り捨てるためです。
たとえば、配列 A
の形状が :?x:?x:?
で size(A,3)==1
の場合、size(A)
は以下を返します。
生成されたコードでは、3 要素のベクトル
MATLAB コードでは、2 要素のベクトル
回避方法
生成されたコードで返される可変サイズ N 次元配列のサイズが、MATLAB コードと同じであることが必要とされるアプリケーションでは、以下のいずれかの回避方法を検討してください。
size
の 2 つの引数をもつ形式を使用する。たとえば、
size(A,n)
は生成されたコードと MATLAB コードで同じ答えを返します。size(A)
を次のように書き換える。B = size(A); X = B(1:ndims(A));
このバージョンは、
X
を可変長の出力で返します。ただし、可変サイズのX
をzeros
のような固定サイズの引数を必要とする行列コンストラクターに渡すことはできません。
空配列のサイズを判定する際の MATLAB との非互換性
空の配列のサイズは、生成コードと MATLAB ソース コードでは異なる場合があります。生成コードでは、サイズが 1x0
または 0x1
で、MATLAB では 0x0
の場合があります。したがって、空行列の特定のサイズに依存するようなコードを書かないようにしてください。
たとえば、以下のコードについて考えます。
function y = foo(n) %#codegen x = []; i = 0; while (i < 10) x = [5 x]; i = i + 1; end if n > 0 x = []; end y = size(x); end
連結を行うには、オペランドが連結されない次元のサイズにおいて一致している必要があります。前述の連結では、スカラー値のサイズが 1x1
で、x
のサイズが 0x0
です。このような用途に対応するため、コード ジェネレーターは x
のサイズを [1 x :?]
と判定します。この連結後に別の代入 x = []
があるため、生成コードの x
のサイズは、0x0
ではなく 1x0
になります。
この動作は、''
で示される空の文字ベクトルのサイズを判定する間維持されます。たとえば、以下のコードについて考えます。
function out = string_size out = size(''); end
ここで、out
の値が生成コードでは 1x0
または 0x1
で、MATLAB では 0x0
の場合があります。
配列の要素を削除したことによる空配列のサイズを決定する際の MATLAB との非互換性については、配列の要素を削除した結果として生じる空配列のサイズを参照してください。
回避方法
アプリケーションで行列が空かどうかをチェックする場合は、以下のいずれかの回避方法を使ってください。
関数
size
の代わりに関数isempty
を使うようにコードを変更する。x=[]
を使って空の配列を作成する代わりに、特定のサイズの空の配列をzeros
を使って作成する。次に例を示します。function y = test_empty(n) %#codegen x = zeros(1,0); i=0; while (i < 10) x = [5 x]; i = i + 1; end if n > 0 x = zeros(1,0); end y=size(x); end
空配列のクラス決定における MATLAB との非互換性
空配列のクラスは、生成コードと MATLAB ソース コードでは異なる場合があります。したがって、空行列のクラスに依存するようなコードを書かないようにしてください。
たとえば、以下のコードについて考えます。
function y = fun(n) x = []; if n > 1 x = ['a' x]; end y=class(x); end
fun(0)
は、MATLAB では double
を返しますが、生成コードでは char
を返します。ステートメント n > 1
が偽の場合、MATLAB は x = ['a' x]
を実行しません。x
のクラスは double
の空配列のクラスです。ただし、コード ジェネレーターではすべての実行パスが考慮されます。ステートメント x = ['a' x]
に基づいて、x
のクラスは char
に決まります。回避方法
x=[]
を使って空の配列を作成する代わりに、特定のクラスの空の配列を作成します。たとえば、blanks(0)
を使って文字の空配列を作成します。
function y = fun(n) x = blanks(0); if n > 1 x = ['a' x]; end y=class(x); end
行列 - 行列インデックス付けでの MATLAB との非互換性
行列 - 行列インデックス付けでは、1 つの行列を使用して別の行列にインデックスを付けます。MATLAB で、行列 - 行列インデックス付けの一般的なルールは、結果のサイズと方向がインデックス行列のサイズと方向に一致するということです。たとえば、A
と B
が行列の場合、size(A(B))
は size(B)
と等しくなります。A
と B
がベクトルの場合、MATLAB では特別なルールが適用されます。特別なベクトル - ベクトル インデックス付けルールは、結果の方向がデータ行列の方向になることです。たとえば、A
が 1 行 5 列で、B
が 3 行 1 列である場合、A(B)
は 1 行 3 列になります。
コード ジェネレーターは、MATLAB と同じ行列 - 行列インデックス付けルールを適用します。A
と B
が可変サイズ行列の場合、行列 - 行列インデックス付けルールを適用するために、コード ジェネレーターは size(A(B))
が size(B)
と等しいと仮定します。実行時に、A
と B
がベクトルになり、異なる方向を持つ場合、この仮定は正しくありません。したがって、実行時エラー チェックが有効な場合、エラーが発生する可能性があります。
この問題を回避するには、インデックスにコロン演算子を使用して、データを強制的にベクトルにします。たとえば、コードが意図的に実行時にベクトルと正則行列を切り替えるものであるとします。ベクトル - ベクトル インデックス付けを明示的に次のようにチェックすることができます。
... if isvector(A) && isvector(B) C = A(:); D = C(B(:)); else D = A(B); end ...
最初の分岐のインデックス付けが、C
と B(:)
をコンパイル時のベクトルとして指定しています。したがって、コード ジェネレーターは、1 つのベクトルを別のベクトルでインデックス付けするインデックス付けルールを適用します。結果の方向はデータ ベクトル C
の方向となります。
ベクトル - ベクトル インデックス付けにおける MATLAB との非互換性
MATLAB で、ベクトル - ベクトル インデックス付けの特別なルールは、結果の方向がデータ ベクトルの方向であるということです。たとえば、A
が 1 行 5 列で、B
が 3 行 1 列である場合、A(B)
は 1 行 3 列になります。ただし、データ ベクトル A
がスカラーの場合、A(B)
の方向はインデックス ベクトル B
の方向になります。
コード ジェネレーターは、MATLAB と同じベクトル - ベクトル インデックス付けルールを適用します。A
と B
が可変サイズ ベクトルである場合、インデックス付けルールを適用するには、コード ジェネレーターは B
の方向が A
の方向と一致すると仮定します。実行時に、A
がスカラーで、A
と B
の方向が一致しない場合、この仮定は正しくありません。したがって、実行時エラー チェックが有効な場合、実行時エラーが発生する可能性があります。
この問題を回避するには、ベクトルの方向を一致させます。または、行と列を指定して単一要素にインデックス付けします。例: A(row, column)
コード生成における行列のインデックス操作に関する MATLAB との非互換性
コード生成の行列インデックス演算には以下の制限が適用されます。
以下のようなスタイルの初期化:
for i = 1:10 M(i) = 5; end
この場合、ループの実行時に
M
のサイズが変化します。コード生成は、時間と共にサイズが増加するような配列をサポートしていません。コード生成の場合、
M
を事前に割り当てます。M = zeros(1,10); for i = 1:10 M(i) = 5; end
動的メモリ割り当てが無効な場合、コード生成の行列インデックス演算には以下の制限が適用されます。
M(i:j)
でi
とj
がループ内で変化する場合プログラム実行時に式のサイズが変化する場合、コード生成中にメモリが動的に割り当てられることはありません。この動作を実装するには、以下の例に示すように、
for
ループを使用します。... M = ones(10,10); for i=1:10 for j = i:10 M(i,j) = 2*M(i,j); end end ...
メモ
行列
M
はループに入る前に定義されていなければなりません。
可変サイズ行列の連結における MATLAB との非互換性
コードを生成するには、可変サイズの配列を連結するときに、連結されない次元が正確に一致しなければなりません。
連結内で中かっこを使用した可変サイズの cell 配列インデックスが要素を返さない場合の違い
以下を仮定します。
c
は可変サイズの cell 配列です。中かっこを使用して
c
の内容にアクセスします。例:c{2:4}
。連結に結果を含めます。例:
[a c{2:4} b]
。c{I}
は要素を返しません。c
が空であるか、中かっこ内のインデックスが空の結果を返します。
このような条件では、MATLAB は連結から c{I}
を除外します。たとえば、[a c{I} b]
は [a b]
になります。コード ジェネレーターは c{I}
を空の配列 [c{I}]
として処理します。連結は [...[c{i}]...]
になります。その後、この連結は配列 [c{I}]
を除外します。[c{I}]
のプロパティは連結 [...[c{i}]...]
と互換性があるため、コード ジェネレーターはこれらのルールに基づいて [c{I}]
のクラス、サイズおよび実数/複素数を割り当てます。
クラスと実数/複素数は cell 配列の基本データ型と同じです。
2 番目の次元のサイズは常に 0 です。
残りの次元については、
Ni
のサイズは、基本データ型において対応する次元のサイズが固定か可変かによって異なります。基本データ型において対応する次元が可変サイズの場合、結果的に次元サイズは 0 になります。
基本データ型において対応する次元が固定サイズの場合、結果的に次元はそのサイズになります。
c
にクラスが int8
でサイズが :10x7x8x:?
の基本データ型があると仮定します。生成されたコードでは、[c{I}]
のクラスは int8
です。[c{I}]
のサイズは 0x0x8x0
です。2 番目の次元は 0 です。最初の次元と最後の次元は、基本データ型において可変サイズであるため、0 になります。3 番目の次元は基本データ型の 3 番目の次元が固定サイズの 8 なので、8 になります。
連結内で中かっこを使用した可変サイズの cell 配列インデックスが要素を返さない場合、生成されたコードと MATLAB の間に次の相違点が発生する可能性もあります。
生成されたコードの
[...c{i}...]
クラスと MATLAB のクラスが異なる場合があります。c{I}
が要素を返さない場合、MATLAB はc{I}
を連結から削除します。したがって、c{I}
は結果のクラスに影響しません。MATLAB は残りの配列のクラスによる優先順位に基づいて結果のクラスを決定します。異なるクラスの有効な組み合わせを参照してください。コード ジェネレーターはc{I}
を[c{I}]
として処理するため、生成されたコード内で[c{I}]
のクラスは連結[...[c{I}]...]
全体の結果のクラスに影響します。前述のルールにより、[c{I}]
のクラスが決定されます。生成されたコードでは、
[c{I}]
のサイズは MATLAB のサイズと異なる場合があります。MATLAB では、連結
[c{I}]
は 0 行 0 列の double です。生成されたコードでは、前述のルールにより[c{I}]
のサイズが決定されます。