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);
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
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-size X
to
matrix constructors such as zeros
that
require a fixed-size argument.
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.
If your application checks whether a matrix is empty, use one of these workarounds:
Rewrite your code to use the isempty
function
instead of the size
function.
Instead of using x=[]
to create
empty arrays, create empty arrays of a specific size using zeros
.
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
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
.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
In matrix-matrix indexing, you use one matrix to index into
another matrix. In MATLAB, the general rule for matrix-matrix
indexing is that the size and orientation of the result match the
size and orientation of the index matrix. For example, if A
and B
are
matrices, size(A(B))
equals size(B)
.
When A
and B
are vectors, MATLAB applies
a special rule. The special vector-vector indexing rule is that the
orientation of the result is the orientation of the data matrix. For
example, iA
is 1-by-5 and B
is
3-by-1, then A(B)
is 1-by-3.
The code generator applies the same matrix-matrix indexing rules
as MATLAB. If A
and B
are
variable-size matrices, to apply the matrix-matrix indexing rules,
the code generator assumes that the size(A(B))
equals size(B)
.
If, at run time, A
and B
become
vectors and have different orientations, then the assumption is incorrect.
Therefore, when run-time error checks are enabled, an error can occur.
To avoid this issue, force your data to be a vector by using the colon operator for indexing. For example, suppose that your code intentionally toggles between vectors and regular matrices at run time. You can do an explicit check for vector-vector indexing.
... if isvector(A) && isvector(B) C = A(:); D = C(B(:)); else D = A(B); end ...
The indexing in the first branch specifies that C
and B(:)
are
compile-time vectors. Therefore, the code generator applies the indexing
rule for indexing one vector with another vector. The orientation
of the result is the orientation of the data vector, C
.
In MATLAB, the special rule for vector-vector indexing
is that the orientation of the result is 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. If, however, the data
vector A
is a scalar, then the orientation of A(B)
is
the orientation of the index vector B
.
The code generator applies the same vector-vector indexing
rules as MATLAB. If A
and B
are
variable-size vectors, to apply the indexing rules, the code generator
assumes that the orientation of B
matches the
orientation of A
. At run time, if A
is
scalar and the orientation of A
and B
do
not match, then the assumption is incorrect. Therefore, when run-time
error checks are enabled, a run-time error can occur.
To avoid this issue, make the orientations of the vectors match.
Alternatively, index single elements by specifying the row and column.
For example, A(row, column)
.
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)
where i
and j
change
in a loop
During 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.
For code generation, when you concatenate variable-size arrays, the dimensions that are not being concatenated must match exactly.
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. Either c
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 removes c{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 treats c{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}]
.