Incompatibilities with MATLAB in Variable-Size Support for Code Generation
Incompatibility with MATLAB for Scalar Expansion
Scalar expansion is a method of converting scalar data to match the dimensions of vector or matrix data. If one operand is a scalar and the other is not, scalar expansion applies the scalar to every element of the other operand.
During code generation, scalar expansion rules apply except when operating on two variable-size expressions. In this case, both operands must be the same size. The generated code does not perform scalar expansion even if one of the variable-size expressions turns out to be scalar at run time. Therefore, when run-time error checks are enabled, a run-time error can occur.
Consider this function:
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;
When you generate code for this function, the code generator determines that
z
is variable size with an upper bound of 3
.
If you run the MEX function with u
equal to 0 or 1, the generated code does
not perform scalar expansion, even though z
is scalar at run time.
Therefore, when run-time error checks are enabled, a run-time error can
occur.
scalar_exp_test_err1_mex(0) Subscripted assignment dimension mismatch: [9] ~= [1]. Error in scalar_exp_test_err1 (line 11) y(:) = z;
To avoid this issue, use indexing to force z
to
be a scalar value.
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);
Incompatibility with MATLAB in Determining Size of Variable-Size N-D Arrays
For variable-size N-D arrays, the size
function can return a
different result in generated code than in MATLAB®. In generated code, size(A)
returns a
fixed-length output because it does not drop trailing singleton dimensions of
variable-size N-D arrays. By contrast, size(A)
in MATLAB returns a variable-length output because it drops trailing
singleton dimensions.
For example, if the shape of array A
is
:?x:?x:?
and size(A,3)==1
,
size(A)
returns:
Three-element vector in generated code
Two-element vector in MATLAB code
Workarounds
If your application requires generated code to return the same size of variable-size N-D arrays as MATLAB code, consider one of these workarounds:
Use the two-argument form of
size
.For example,
size(A,n)
returns the same answer in generated code and MATLAB code.Rewrite
size(A)
:B = size(A); X = B(1:ndims(A));
This version returns
X
with a variable-length output. However, you cannot pass a variable-sizeX
to matrix constructors such aszeros
that require a fixed-size argument.
Incompatibility with MATLAB in Determining Size of Empty Arrays
The size of an empty array in generated code might be different from its size
in MATLAB source code. The size might be 1x0
or
0x1
in generated code, but 0x0
in
MATLAB. Therefore, you should not write code that relies on the specific
size of empty matrices.
For example, consider the following code:
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
Concatenation requires its operands to match on the size of the dimension that
is not being concatenated. In the preceding concatenation, the scalar value has
size 1x1
and x
has size
0x0
. To support this use case, the code generator
determines the size for x
as [1 x :?]
.
Because there is another assignment x = []
after the
concatenation, the size of x
in the generated code is
1x0
instead of 0x0
.
This behavior persists while determining the size of empty character vectors
which are denoted as ''
. For example, consider the following
code:
function out = string_size out = size(''); end
Here, the value of out
might be 1x0
or
0x1
in generated code, but 0x0
in
MATLAB.
For incompatibilities with MATLAB in determining the size of an empty array that results from deleting elements of an array, see Size of Empty Array That Results from Deleting Elements of an Array.
Workaround
If your application checks whether a matrix is empty, use one of these workarounds:
Rewrite your code to use the
isempty
function instead of thesize
function.Instead of using
x=[]
to create empty arrays, create empty arrays of a specific size usingzeros
. For example: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
Incompatibility with MATLAB in Determining Class of Empty Arrays
The class of an empty array in generated code can be different from its class in MATLAB source code. Therefore, do not write code that relies on the class of empty matrices.
For example, consider the following code:
function y = fun(n) x = []; if n > 1 x = ['a' x]; end y=class(x); end
fun(0)
returns double
in MATLAB, but char
in the generated code. When the statement
n > 1
is false, MATLAB does not execute x = ['a' x]
. The class of
x
is double
, the class of the empty array.
However, the code generator considers all
execution paths. It determines that based on the
statement x = ['a' x]
, the class of x
is
char
.Workaround
Instead of using x=[]
to create an empty array, create an
empty array of a specific class. For example, use blanks(0)
to create an empty array of characters.
function y = fun(n) x = blanks(0); if n > 1 x = ['a' x]; end y=class(x); end
Incompatibility with MATLAB Due to Resizing of Empty Arrays by MEX, SIL, and PIL Functions
If you generate a MEX, SIL, or PIL function that can accept an empty array, the
generated function accepts empty arrays of any
size. Empty arrays are arrays with at least one dimension equal to
0
. At run time, the generated function resizes empty input
arrays to be compatible with the size of the array that was specified at code
generation time. Therefore, the size of an empty array in a generated MEX, SIL, or
PIL function can differ from the size of the empty array in the corresponding
MATLAB function.
For example, consider the simple function testResize
, which
returns the size of the input array
x
.
function out = testResize(x) out = size(x); end
Generate a MEX function from this MATLAB function and specify the input as a matrix of doubles with size
4x:inf
.
codegen testResize -args {coder.typeof(0,[4 inf])}
In addition to accepting non-empty arrays of size 4x:inf
, the
generated function testResize_mex
also accepts empty arrays of
any size. Because
testResize_mex
resizes empty run-time inputs to be compatible
with the size of the input array specified at code generation time, the size of
x
is 4x0
for
all empty run-time
inputs.
>> testResize(zeros(3,0,6)) ans = 3 0 6 >> testResize_mex(zeros(3,0,6)) ans = 4 0
Incompatibility with MATLAB in Matrix-Matrix Indexing
In matrix-matrix indexing, you use one matrix (the index matrix) to index into another matrix
(the data matrix). In MATLAB, the general rule for matrix-matrix indexing is that the dimensions of the
result are the same as the dimensions of the index matrix. For example, if
A
and B
are matrices,
size(A(B))
equals size(B)
. However, when
A
and B
are vectors, MATLAB applies a different rule. When performing vector-vector indexing, the
orientation of the result is the same as the orientation of the data matrix. For example, if
A
is 1-by-5 and B
is 3-by-1, then
A(B)
is 1-by-3.
The code generator attempts to apply the same matrix-matrix indexing rules as MATLAB. If A
and B
are variable-size matrices
at code generation time, the code generator follows the general MATLAB indexing rule and assumes that size(A(B))
equals
size(B)
. At run time, if A
and
B
are vectors with different orientations, then this assumption is
incorrect. Therefore, when run-time error checks are enabled, an error can occur.
To avoid this run-time error, try one of these solutions:
If
A
orB
is a fixed-size matrix at run time, define this matrix as fixed-size at code generation time.If
A
andB
are both vectors at run time, make sure that their orientations match.If your code intentionally accepts matrices as well as vectors of different orientations at run time, include an explicit check for vector-vector indexing and force vectors into the same orientation. For example, use the
isvector
function to determine whether bothA
andB
are vectors and, if so, use thecolon
operator to force both vectors to be column vectors.... if isvector(A) && isvector(B) Acol = A(:); Bcol = B(:); out = Acol(Bcol); else out = A(B); end ...
Incompatibility with MATLAB in Vector-Vector Indexing
In vector-vector indexing, you use one vector (the index vector) to index into another vector
(the data vector). In MATLAB, the rule for vector-vector indexing is that the orientation of the result vector
is the same as the orientation of the data vector. For example, if A
is
1-by-5 and B
is 3-by-1, then A(B)
is 1-by-3. However, this
rule does not apply if A
is a scalar. If A
is scalar, then
the orientation of A(B)
is the same as the orientation of the index vector
B
.
The code generator attempts to apply the same vector-vector indexing rules as MATLAB. If A
is a variable-size vector at code generation time, the
code generator assumes that the orientation of A(B)
is the same as the
orientation of A
. However, this assumption is false and a run time error occurs
if both of these conditions are true:
At code generation time, the orientation of
A
does not match that ofB
.At run time,
A
is a scalar andB
is a vector.
To avoid this run-time error, try one of these solutions:
If
A
is a scalar at run time, defineA
as a scalar at code generation time.If
A
andB
are defined as vectors at code generation time, make sure that their orientations are the same.If
A
andB
are variable-size vectors with different orientations at code generation time, make sure thatA
is not a scalar at run time.If
A
andB
are variable-size vectors with different orientations at code generation time, make sure thatB
is not a vector at run time.
Incompatibility with MATLAB in Logical Indexing
In logical indexing, you use an array of logical values (the index array) to index into another array (the data array). In MATLAB execution, the shape of the resulting array depends on whether the index and data arrays are matrices, vectors, or scalars. When you generate C/C++ code for MATLAB code that performs logical indexing using variable-size arrays, the code generator can make assumptions about the shape of the indexing result that are false for some run-time inputs, causing a run-time error.
If the index and data arrays are fixed-size at run time, you can avoid this run-time error by defining both of these arrays as fixed-size at code generation time.
If either or both arrays must be defined as variable-size at code generation time,
this table shows some possible solutions for the run-time errors that can occur for
certain inputs. In this table, A
is the data array and
B
is the logical index array.
Definition at Code Generation Time | Input at Run Time | Possible Solution |
---|---|---|
A is a fixed-size matrix and
B is a variable-size matrix. | B is a row vector. | Force B to be a column vector at run time
using the colon
operator. |
A is a variable-size matrix and
B is a fixed-size matrix. | A is a row vector. | Force A to be a column vector at run time
using the colon
operator. |
A is a variable-size matrix and
B is a variable-size matrix. | A is a row vector. | Force A to be a column vector at run time
using the colon
operator. |
A is a variable-size matrix and
B is a variable-size matrix. | A is a matrix and B is
a row vector. | Force B to be a column vector at run time
using the colon
operator. |
A is a variable-size matrix and
B is a vector. | A and B are vectors,
and the orientations of A and
B are different. | Force A and B to have
the same orientation at run time. |
Incompatibility with MATLAB in Matrix Indexing Operations for Code Generation
The following limitation applies to matrix indexing operations for code generation:
Initialization of the following style:
for i = 1:10 M(i) = 5; end
In this case, the size of
M
changes as the loop is executed. Code generation does not support increasing the size of an array over time.For code generation, preallocate
M
.M = zeros(1,10); for i = 1:10 M(i) = 5; end
The following limitation applies to matrix indexing operations for code generation when dynamic memory allocation is disabled:
M(i:j)
wherei
andj
change in a loopDuring code generation, memory is not dynamically allocated for the size of the expressions that change as the program executes. To implement this behavior, use
for-
loops as shown:... M = ones(10,10); for i=1:10 for j = i:10 M(i,j) = 2*M(i,j); end end ...
Note
The matrix
M
must be defined before entering the loop.
Incompatibility with MATLAB in Concatenating Variable-Size Matrices
For code generation, when you concatenate variable-size arrays, the dimensions that are not being concatenated must match exactly.
Differences When Curly-Brace Indexing of Variable-Size Cell Array Inside Concatenation Returns No Elements
Suppose that:
c
is a variable-size cell array.You access the contents of
c
by using curly braces. For example,c{2:4}
.You include the results in concatenation. For example,
[a c{2:4} b]
.c{I}
returns no elements. Eitherc
is empty or the indexing inside the curly braces produces an empty result.
For these conditions, MATLAB omits c{I}
from the concatenation. For example,
[a c{I} b]
becomes [a b]
. The code
generator treats c{I}
as the empty array
[c{I}]
. The concatenation becomes
[...[c{i}]...]
. This concatenation then omits the array
[c{I}]
. So that the properties of [c{I}]
are compatible with the concatenation [...[c{i}]...]
, the code
generator assigns the class, size, and complexity of [c{I}]
according to these rules:
The class and complexity are the same as the base type of the cell array.
The size of the second dimension is always 0.
For the rest of the dimensions, the size of
Ni
depends on whether the corresponding dimension in the base type is fixed or variable size.If the corresponding dimension in the base type is variable size, the dimension has size 0 in the result.
If the corresponding dimension in the base type is fixed size, the dimension has that size in the result.
Suppose that c
has a base type with class
int8
and size:10x7x8x:?
. In the generated
code, the class of [c{I}]
is int8
. The size of
[c{I}]
is 0x0x8x0
. The second dimension is
0. The first and last dimensions are 0 because those dimensions are variable size in
the base type. The third dimension is 8 because the size of the third dimension of
the base type is a fixed size 8.
Inside concatenation, if curly-brace indexing of a variable-size cell array returns no elements, the generated code can have the following differences from MATLAB:
The class of
[...c{i}...]
in the generated code can differ from the class in MATLAB.When
c{I}
returns no elements, MATLAB removesc{I}
from the concatenation. Therefore,c{I}
does not affect the class of the result. MATLAB determines the class of the result based on the classes of the remaining arrays, according to a precedence of classes. See Valid Combinations of Unlike Classes. In the generated code, the class of[c{I}]
affects the class of the result of the overall concatenation[...[c{I}]...]
because the code generator treatsc{I}
as[c{I}]
. The previously described rules determine the class of[c{I}]
.In the generated code, the size of
[c{I}]
can differ from the size in MATLAB.In MATLAB, the concatenation
[c{I}]
is a 0x0 double. In the generated code, the previously described rules determine the size of[c{I}]
.