このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。
コード生成時の可変サイズのサポートに関する 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
が可変サイズの行列の場合、コード ジェネレーターは一般的な MATLAB インデックス付けルールに従い、size(A(B))
が size(B)
と等しいと仮定します。実行時に、A
と B
が異なる方向をもつベクトルである場合、この仮定は正しくありません。したがって、実行時エラー チェックが有効な場合、エラーが発生する可能性があります。
このランタイム エラーを回避するには、次のいずれかの解決法を試してください。
A
またはB
が実行時に固定サイズの行列である場合は、コード生成時にこの行列を固定サイズとして定義します。実行時に
A
とB
が両方ともベクトルである場合は、方向が一致していることを確認します。コードが実行時に異なる方向のベクトルと行列を意図的に受け入れる場合は、ベクトル - ベクトル インデックス付けの明示的なチェックを含め、ベクトルを同じ方向に強制します。たとえば、関数
isvector
を使用して、A
とB
の両方がベクトルであるかどうかを判断し、ベクトルである場合はcolon
演算子を使用して両方のベクトルを強制的に列ベクトルにします。... if isvector(A) && isvector(B) Acol = A(:); Bcol = B(:); out = Acol(Bcol); else out = A(B); end ...
ベクトル - ベクトル インデックス付けにおける MATLAB との非互換性
ベクトル - ベクトル インデックス付けでは、1 つのベクトル (インデックス ベクトル) を使用して別のベクトル (データ ベクトル) にインデックスを付けます。MATLAB で、ベクトル - ベクトル インデックス付けのルールは、結果のベクトルの方向がデータ ベクトルの方向と同じであるということです。たとえば、A
が 1 行 5 列で、B
が 3 行 1 列である場合、A(B)
は 1 行 3 列になります。ただし、このルールは A
がスカラーである場合には適用されません。A
がスカラーの場合、A(B)
の方向はインデックス ベクトル B
の方向と同じになります。
コード ジェネレーターは、MATLAB と同じベクトル - ベクトル インデックス付けルールを適用しようとします。コード生成時に A
が可変サイズのベクトルである場合、コード ジェネレーターは A(B)
の方向が A
の方向と同じであると仮定します。ただし、次の両方の条件が true の場合は、この仮定は誤りであり、ランタイム エラーが発生します。
コード生成時に、
A
の方向がB
の方向と一致しない。実行時に
A
がスカラーで、B
がベクトルである。
このランタイム エラーを回避するには、次のいずれかの解決法を試してください。
A
が実行時にスカラーである場合は、コード生成時にA
をスカラーとして定義します。A
とB
がコード生成時にベクトルとして定義されている場合は、それらの方向が同じであることを確認します。A
とB
がコード生成時に方向が異なる可変サイズのベクトルである場合は、A
が実行時にスカラーでないことを確認します。A
とB
がコード生成時に方向が異なる可変サイズのベクトルである場合は、B
が実行時にベクトルでないことを確認します。
論理インデックス付けでの MATLAB との非互換性
論理インデックス付けでは、論理値の配列 (インデックス配列) を使用して、別の配列 (データ配列) にインデックスを付けます。MATLAB 実行では、結果として得られる配列の形状は、インデックス配列とデータ配列が行列、ベクトル、スカラーのいずれであるかによって異なります。可変サイズの配列を使用して論理インデックス付けを行う MATLAB コードの C/C++ コードを生成する場合、コード ジェネレーターは、インデックス付け結果の形状について、一部の実行時入力に対して、誤った仮定を行うことがあり、ランタイム エラーの原因となります。
インデックス配列とデータ配列が実行時に固定サイズである場合は、コード生成時にこれらの配列の両方を固定サイズとして定義することで、このランタイム エラーを回避できます。
配列のいずれかまたは両方をコード生成時に可変サイズとして定義する必要がある場合は、次の表で、特定の入力で発生する可能性のあるランタイム エラーに対して考えられる解決策を参照してください。この表では、A
がデータ配列で、B
が論理インデックス配列です。
コード生成時の定義 | 実行時の入力 | 考えられる解決策 |
---|---|---|
A は固定サイズの行列で、B は可変サイズの行列である。 | B は行ベクトルである。 | colon 演算子を使用して、実行時に B を強制的に列ベクトルにします。 |
A は可変サイズの行列で、B は固定サイズの行列である。 | A は行ベクトルである。 | colon 演算子を使用して、実行時に A を強制的に列ベクトルにします。 |
A は可変サイズの行列で、B は可変サイズの行列である。 | A は行ベクトルである。 | colon 演算子を使用して、実行時に A を強制的に列ベクトルにします。 |
A は可変サイズの行列で、B は可変サイズの行列である。 | A は行列で、B は行ベクトルである。 | colon 演算子を使用して、実行時に B を強制的に列ベクトルにします。 |
A は可変サイズの行列で、B はベクトルである。 | A と B はベクトルで、A と B の方向が異なる。 | 実行時に A と B の方向を強制的に同じにします。 |
コード生成における行列のインデックス操作に関する 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}]
のサイズが決定されます。