Documentation |
Scalar expansion is a method of converting scalar data to match the dimensions of vector or matrix data. Except for some matrix operators, MATLAB^{®} arithmetic operators work on corresponding elements of arrays with equal dimensions. For vectors and rectangular arrays, both operands must be the same size unless one is a scalar. If one operand is a scalar and the other is not, MATLAB applies the scalar to every element of the other operand—this property is known as scalar expansion.
During code generation, the standard MATLAB 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. Instead, it generates a size mismatch error at run time for MEX functions. Run-time error checking does not occur for non-MEX builds; the generated code will have unspecified behavior.
For example, in the following function, z is scalar for the switch statement case 0 and case 1. MATLAB applies scalar expansion when evaluating y(:) = z; for these two cases.
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 generation software determines that z is variable size with an upper bound of 3.
If you run the MEX function with u equal to zero or one, even though z is scalar at run time, the generated code does not perform scalar expansion and a run-time error occurs.
scalar_exp_test_err1_mex(0) Sizes mismatch: 9 ~= 1. Error in scalar_exp_test_err1 (line 11) y(:) = z;
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 generation software 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.
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 generation software 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 vector-vector indexing, you use one vector as an index into another vector. When either vector is variable sized, you might get a run-time error during code generation. Consider the index expression A(B). The general rule for indexing is that size(A(B)) == size(B). However, when both A and B are vectors, MATLAB applies a special rule: use the orientation of A as the orientation of the output. For example, if size(A) == [1 5] and size(B) == [3 1], then size(A(B)) == [1 3].
In this situation, if the code generation software detects that both A and B are vectors at compile time, it applies the special rule and gives the same result as MATLAB. However, if either A or B is a variable-size matrix (has shape ?x?) at compile time, the code generation software applies only the general indexing rule. Then, if both A and B become vectors at run time, the code generation software reports a run-time error when you run the MEX function. Run-time error checking does not occur for non-MEX builds; the generated code will have unspecified behavior. It is best practice to generate and test a MEX function before generating C code.
Force your data to be a vector by using the colon operator for indexing: A(B(:)). For example, suppose 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. As a result, the code generation software applies the standard vector-vector indexing rule.
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 as highlighted in the following code.
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 in the following example:
... M = ones(10,10); for i=1:10 for j = i:10 M(i,j) = 2 * M(i,j); end end ...