我可以阻止Matlab动态调整预分配的数组吗?

Mic*_*l A 9 matlab

例如,在这个简单/愚蠢的例子中:

n = 3;
x = zeros(n, 1);
for ix=1:4
    x(ix) = ix;
end
Run Code Online (Sandbox Code Playgroud)

数组是预先分配的,但在循环中动态调整大小.在这样的动态调整大小时,Matlab中是否存在会引发错误的设置?在这个例子中,我可以轻而易举地重写它:

n = 3;
x = zeros(n, 1);
for ix=1:4
    if ix > n
        error('Size:Dynamic', 'Dynamic resizing will occur.')
    end
    x(ix) = ix;
end
Run Code Online (Sandbox Code Playgroud)

但我希望用这个作为检查,以确保我已经预先分配了我的矩阵.

Moh*_*nia 8

您可以doublesubsasgn方法中创建子类并限制赋值:

classdef dbl < double
    methods
        function obj = dbl(d)
            obj = obj@double(d);
        end

        function obj = subsasgn(obj,s,val)
            if strcmp(s.type, '()')
                mx = cellfun(@max, s.subs).*~strcmp(s.subs, ':');
                sz = size(obj);
                nx = numel(mx);
                if nx < numel(sz)
                    sz = [sz(1:nx-1) prod(sz(nx:end))];
                end
                assert(all( mx <= sz), ...
                    'Index exceeds matrix dimensions.');
            end
            obj = subsasgn@double(obj, s, val);
        end

    end
end
Run Code Online (Sandbox Code Playgroud)

所以现在当你预先分配使用时 dbl

>> z = dbl(zeros(3))
z = 
  dbl

  double data:
     0     0     0
     0     0     0
     0     0     0
  Methods, Superclasses
Run Code Online (Sandbox Code Playgroud)

double现在所有方法都是继承的dbl,您可以照常使用它,直到您分配内容为止z

>> z(1:2,2:3) = 6
z = 
  dbl

  double data:
     0     6     6
     0     6     6
     0     0     0
  Methods, Superclasses

>> z(1:2,2:5) = 6
Error using dbl/subsasgn (line 9)
Index exceeds matrix dimensions.
Run Code Online (Sandbox Code Playgroud)

我没有对它进行基准测试,但我预计这会对性能产生微不足道的影响.

如果您希望值的显示看起来正常,您也可以重载该display方法:

function display(obj)
    display(double(obj));
end
Run Code Online (Sandbox Code Playgroud)

然后

>> z = dbl(zeros(3))
ans =
     0     0     0
     0     0     0
     0     0     0
>> z(1:2,2:3) = 6
ans =
     0     6     6
     0     6     6
     0     0     0
>> z(1:2,2:5) = 6
Error using dbl/subsasgn (line 9)
Index exceeds matrix dimensions.
>> class(z)
ans =
dbl
Run Code Online (Sandbox Code Playgroud)

  • @ DanielE.Shub没有你的解决方案不起作用,并且在[subsasgn的文档]的描述部分的第三段中明确提到它(http://www.mathworks.se/help/matlab/ref/subsasgn的.html) (3认同)
  • 注意冒号操作符 - 您的代码将其转换为ASCII值.简单修复:`mx(cellfun(@(x)strcmp(x,':'),s.subs))= 1;`赋值后.在一些非常快速和粗略的测试中,这比让Matlab动态分配数组慢约2倍,或者比预先分配的双重性能慢约3倍. (2认同)
  • 您不需要子类化“double”,而是可以通过创建“@double”目录并将“subsasgn”函数添加到其中来重载“subsasgn”。它仍然会给您带来相同的性能影响。 (2认同)

Mat*_* B. 5

我能想到的最简单,最直接和最健壮的方法就是在分配索引之前访问索引.不幸的是,你不能为基本类型重载subasgn(在任何情况下都是正确的头痛).

for ix=1:4
    x(ix); x(ix) = ix;
end
% Error: 'Attempted to access x(4); index out of bounds because numel(x)=3.'
Run Code Online (Sandbox Code Playgroud)

或者,您可以尝试聪明并使用end关键字执行某些操作...但无论您做什么,您最终都会得到某种无意义的错误消息(上面提供的很好).

for ix=1:4
    x(ix*(ix<=end)) = ix;
end
% Error: 'Attempted to access x(0); index must be a positive integer or logical.'
Run Code Online (Sandbox Code Playgroud)

或者你可以检查一个函数,它可以获得你很好的错误信息,但仍然非常冗长和混淆:

for ix=1:4
    x(idxchk(ix,end)) = ix;
end
function idx = idxchk(idx,e)
    assert(idx <= e, 'Size:Dynamic', 'Dynamic resizing will occur.')
end
Run Code Online (Sandbox Code Playgroud)

  • @EMS我的声明"你不能超载subasgn的基本类型"是一个非常严格和真正的限制.请参阅[subsasgn]上的文档(http://www.mathworks.com/help/matlab/ref/subsasgn.html).然后,替代方法是使用自定义subsasgn行为定义您自己的类(但自定义matlab OOP为*slow*)或使用某种变通方法.我只是集思广益.不,该函数可以重用于任何数据结构,因为它会检查end关键字. (3认同)
  • @EMS,原始问题只是要求"检查以确保我已正确预先分配了我的矩阵." 我读这是为了寻找一种快速方法来仔细检查索引,而不必知道每个数据结构的长度,而不是一些持久的解决方案.我的第一个建议是简单地获取LHS的副本:快速,简单和简单.我不是在提倡在生产代码中使用这种解决方案.但作为一个快速检查?当然. (2认同)