为代码生成定义可变大小数据
对于代码生成,在运算中使用变量或以输出形式返回变量之前,必须为它们分配特定的类、大小和复/实性。通常,在初始分配后,您便无法再重新分配变量属性。因此,在为变量或结构体字段分配固定大小后,尝试增大变量或结构体字段可能会导致编译错误。在这些情况下,您必须使用以下方法之一将数据显式定义为可变大小。
方法 | 参阅 |
---|---|
从可变大小矩阵构造函数中分配数据,例如: | 使用具有非常量维度的矩阵构造函数 |
在使用(读取)变量之前为同一变量分配多个常量大小。 | 为同一个变量分配多个大小 |
使用 (end + 1) 索引增大数组。 | 使用 (end + 1) 索引增大数组 |
将变量的所有实例定义为可变大小。 | 使用 coder.varsize 显式定义可变大小数据 |
使用具有非常量维度的矩阵构造函数
您可以通过使用具有非常量维度的构造函数来定义可变大小矩阵。例如:
function s = var_by_assign(u) %#codegen y = ones(3,u); s = numel(y);
如果不使用动态内存分配,还必须添加 assert
语句来提供维度的上界。例如:
function s = var_by_assign(u) %#codegen assert (u < 20); y = ones(3,u); s = numel(y);
为同一个变量分配多个大小
在代码中使用(读取)变量之前,可以通过为其分配多个恒定大小来使其大小可变。当代码生成器在堆栈上使用静态分配时,它会根据为每个维度指定的最大大小来推断上界。当您在所有分配中为给定的维度分配相同的大小时,代码生成器假定该维度固定为该大小。通过这些分配可以指定不同的形状和大小。
当代码生成器使用动态内存分配时,它不检查上界。它假设可变大小数据是无界的。
从多个不同形状的定义推断上界
function s = var_by_multiassign(u) %#codegen if (u > 0) y = ones(3,4,5); else y = zeros(3,1); end s = numel(y);
当代码生成器使用静态分配时,它推断 y
是三维矩阵:
第一个维度的大小固定为 3
第二个维度为可变大小,上界为 4
第三个维度为可变大小,上界为 5
当代码生成器使用动态分配时,它会以不同方式分析 y
的维度:
第一个维度的大小固定为 3。
第二个和第三个维度是无界的。
使用 (end + 1)
索引增大数组
在 MATLAB® 执行中,您可以使用 end
增大数组的任何维度。例如,您可以通过为每个维度的 (end + 1)
元素赋值来增大二维矩阵的两个维度。
A = magic(5)
A = 17 24 1 8 15 23 5 7 14 16 4 6 13 20 22 10 12 19 21 3 11 18 25 2 9
A(end + 1,end + 1) = 1
A = 17 24 1 8 15 0 23 5 7 14 16 0 4 6 13 20 22 0 10 12 19 21 3 0 11 18 25 2 9 0 0 0 0 0 0 1
要使用 MATLAB 代码中的 end
增大数组以生成代码,您必须遵守以下限制:
您只能使用
end
来增大向量。例如,以下函数的代码生成失败,因为X
是矩阵,而不是向量。function X = foo X = [1 2; 3 4]; X(end + 1,:) = 5; end
您只能通过为
(end + 1)
元素赋值来增大向量。不支持为后续元素赋值,如(end + 2)
。您可以使用
(end + 1)
来增大空 1×0 数组。不支持使用(end + 1)
增大 0×1 数组。仅在使用[]
创建数组时,才能使用(end + 1)
增大 0×0 数组。不支持使用
(end + 1)
来增大已使用圆点表示法定义的结构体数组。例如,以下 MATLAB 函数的代码生成失败。要使用function growStruct s.field1 = 5; s.field2 = 2; s(end + 1) = s; end
(end + 1)
增大结构体数组,请使用struct
构造函数定义结构体的字段。要了解有关使用function growStruct s = struct("field1",5,"field2",2); s(end + 1) = s; end
(end + 1)
增大数组的更多信息,请参阅Generate Code for Growing Arrays and Cell Arrays with end + 1 Indexing。
使用 coder.varsize 显式定义可变大小数据
要显式定义可变大小数据,请使用函数 coder.varsize
。您也可以指定哪些维度大小可变及其上界。例如:
将
B
定义为可变大小的二维数组,其中每个维度的上界为 64。coder.varsize('B', [64 64]);
将
B
定义为可变大小数组:coder.varsize('B');
如果您仅提供第一个参量,
coder.varsize
将假设B
的所有维度都是可变的,并且上界为size(B)
。
指定哪些维度可变
您可以使用函数 coder.varsize
来指定哪些维度是可变的。例如,以下语句将 B
定义为数组,其第一个维度固定为 2,但其第二个维度可以增长到 16:
coder.varsize('B',[2, 16],[0 1])
第三个参量指定哪些维度是可变的。此参量必须为逻辑向量或只包含 0 和 1 的双精度向量。对应于零或 false
的维度具有固定大小。对应于 1 或 true
的维度的大小是可变的。coder.varsize
通常将大小为 1 的维度视为固定大小。请参阅用单一维度定义可变大小矩阵。
定义固定维度后允许增大变量大小
函数 var_by_if
定义矩阵 Y
,在第一次使用前具有固定的 2×2 维度(其中语句 Y = Y + u
从 Y
读取)。但是,coder.varsize
将 Y
定义为可变大小矩阵,允许它根据 else
子句中的决策逻辑来更改大小:
function Y = var_by_if(u) %#codegen if (u > 0) Y = zeros(2,2); coder.varsize('Y'); if (u < 10) Y = Y + u; end else Y = zeros(5,5); end
如果没有 coder.varsize
,代码生成器会推断 Y
是固定大小的 2×2 矩阵。它会生成大小不匹配的错误。
用单一维度定义可变大小矩阵
单一维度是 size(A,dim)
= 1 的维度。在下列情况下,单一维度的大小是固定的:
您在
coder.varsize
表达式中指定上界为 1 的维度。例如,在此函数中,
Y
的行为类似于具有一个可变大小维度的向量:function Y = dim_singleton(u) %#codegen Y = [1 2]; coder.varsize('Y', [1 10]); if (u > 0) Y = [Y 3]; else Y = [Y u]; end
您使用矩阵构造函数表达式或矩阵函数初始化具有单一维度的可变大小数据。
例如,在此函数中,
X
和Y
的行为类似于向量,其中只有其第二个维度的大小是可变的。function [X,Y] = dim_singleton_vects(u) %#codegen Y = ones(1,3); X = [1 4]; coder.varsize('Y','X'); if (u > 0) Y = [Y u]; else X = [X u]; end
您可以通过使用 coder.varsize
显式指定单一维度可变来覆盖此行为。例如:
function Y = dim_singleton_vary(u) %#codegen Y = [1 2]; coder.varsize('Y', [1 10], [1 1]); if (u > 0) Y = [Y Y+u]; else Y = [Y Y*u]; end
在此示例中,coder.varsize
的第三个参量是由 1 组成的向量,表示 Y
的每个维度的大小可变。
定义可变大小结构体字段
要将结构体字段定义为可变大小数组,请使用冒号 (:
) 作为索引表达式。冒号 (:
) 表示数组的所有元素的大小都是可变的。例如:
function y=struct_example() %#codegen d = struct('values', zeros(1,0), 'color', 0); data = repmat(d, [3 3]); coder.varsize('data(:).values'); for i = 1:numel(data) data(i).color = rand-0.5; data(i).values = 1:i; end y = 0; for i = 1:numel(data) if data(i).color > 0 y = y + sum(data(i).values); end end
表达式 coder.varsize('data(:).values')
将矩阵 data
的每个元素中的字段 values
定义为可变大小。
以下是其他示例:
coder.varsize('data.A(:).B')
在此示例中,
data
是包含矩阵A
的标量变量。矩阵A
的每个元素都包含大小可变的字段B
。coder.varsize('data(:).A(:).B')
此表达式将矩阵
A
和data
的每个元素内的字段B
定义为可变大小。