Why is assignment with RedefinesParen so slow

5 views (last 30 days)
I want to make a class that wraps around an array, so I tried matlab.mixin.indexing.RedefinesParen to allow interfacing with the object as if it were an array. I'm finding that assigning to the wrapped array is typically 40-80x slower than regular assignment to an array. Here is a simple test class:
classdef TestCustomParen < matlab.mixin.indexing.RedefinesParen
properties
X
end
methods
function obj = cat(dim,varargin)
obj.X = cat(dim,varargin{:});
end
function sz = size(obj)
sz = size(obj.X);
end
end
methods(Static)
function obj = empty
obj = TestCustomParen;
end
end
methods(Access=protected)
function x = parenReference(obj, indexOp)
x = obj.X(indexOp.Indices{1});
end
function obj = parenAssign(obj,indexOp,varargin)
obj.X(indexOp.Indices{1}) = varargin{1};
end
function n = parenListLength(obj,indexOp,ctx)
n = listLength(obj.X,indexOp(3:end),ctx);
end
function obj = parenDelete(obj,indexOp)
obj.X.(indexOp) = [];
end
end
end
I'm not too concerned with what all the implementations are doing, just focsuing on parenAssign here.
And the timing script:
x = TestCustomParen;
tic
for ind = 1:1e4
x(ind) = rand;
end
toc
y = [];
tic
for ind = 1:1e4
y(ind) = rand;
end
toc
And the result:
Elapsed time is 0.085126 seconds.
Elapsed time is 0.001309 seconds.
(It seems I can't actually run this code in the post)
I also tried a version of this where the arrays are both pre-allocated, and in that case the difference becomes even more dramatic (more than 100x slowdown).
Is this slowdown just due to the overhead of accessing indexOp and opening cells? Is is possible to get this sort of behavior in a performant way? The documentation says overriding subsref is no longer recommended, but would that be faster?

Accepted Answer

Matt J
Matt J on 2 Oct 2023
Edited: Matt J on 2 Oct 2023
Here is the proper way to time the operations. The difference isn't that big.
x = TestCustomParen;
x.X=rand(500);
y=x.X;
a=rand;
timeit(@()assig(x,a))\timeit(@()assig(y,a)),
ans = 0.8566
timeit(@()Assig(x,a))\timeit(@()Assig(y,a)),
ans = 0.9793
function assig(z,a)
z(1)=a;
end
function Assig(z,a)
z(:)=a;
end
  12 Comments
LR
LR on 2 Oct 2023
Edited: LR on 2 Oct 2023
Cool, I'll hit accept on the answer. Thanks both for the info. @James Lebak I'd be grateful if you could indicate if there's been any significant performance improvements to this stuff in 23b. The above tests seem to indicate that going from 23a to 23b and modifying my code from
obj.X(indexOp(1).Indices{1}) = varargin{1};
to
obj.X.(indexOp(1)) = varargin{1};
results in a more than 20x speedup.
James Lebak
James Lebak on 3 Oct 2023
In 23b we made significant improvements to dot-indexing performance. On my machine I see your original code running about 2x faster in 23b versus 23a, and my suspicion is that those improvements are probably the cause.

Sign in to comment.

More Answers (0)

Products


Release

R2023a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!