How to write an efficient overloaded subsasgn?

2 views (last 30 days)
I want to write a class which defines subsasgn. The class holds a numeric value val and the subsasgn should target val only.
I wrote the following test:
function [] = test()
num = 1000;
a = randi([0 255],[1000 num]);
b = Subsasgntest(randi([0 255],[1000 num]));
c = randi([0 255],[1 num]);
tic;
for i = 1:length(c)
a(2,i) = c(i);
end
toc
tic;
for i = 1:length(c)
b(3,i) = c(i);
end
toc
b = b.setKind(1);
tic;
for i = 1:length(c)
b(4,i) = c(i);
end
toc
end
classdef Subsasgntest
properties
val
kind = 0;
end
methods
function obj = Subsasgntest(in)
obj.val = in;
end
function obj = setKind(obj,kind)
obj.kind = kind;
end
function obj = subsasgn(obj,sub,varargin)
%SUBSASGN Subscripted assignment
if(isequal(sub.type,'()'))
if isequal(obj,[])
error('Not yet implemented!');
end
if(isa(varargin{1},'Subsasgntest'))
switch obj.kind
case 0
obj.val = builtin('subsasgn',obj.val,sub,varargin{1}.val);
case 1
obj.val = subsasgn(obj.val,sub,varargin{1}.val);
end
else
switch obj.kind
case 0
obj.val = builtin('subsasgn',obj.val,sub,varargin{1});
case 1
obj.val = subsasgn(obj.val,sub,varargin{1});
end
end
else
error('This is not supported for this class!');
end
end
end
end
Results are;
Elapsed time is 0.000019 seconds.
Elapsed time is 4.477900 seconds.
Elapsed time is 4.449843 seconds.
I know self-written subsasgn can be slow, but 235680x slower? Is there any way to achieve a similar level of optimization as in matlabs standard subsasgn?
This guide tells how to branch for different input subscripts, but not how to write the subsasgn syntx itself: https://www.mathworks.com/help/matlab/matlab_oop/code-patterns-for-subsref-and-subsasgn-methods.html
  1 Comment
Jan Siegmund
Jan Siegmund on 19 May 2020
Update: I added a third kind of subsasgn:
...
case 2
obj.val(sub.subs{1},sub.subs{2}) = varargin{1}.val;
...
which does not cover all cases, but works for the little example and is much faster:
Elapsed time is 0.028915 seconds.
I think the key here is making matlab realize, that in this call:
obj.val = subsasgn(obj.val,sub,varargin{1}.val);
the rvalue obj.val is equal the lvalue obj.val, so it does not create a temporary obj.val.
Any ideas how I could do this?

Sign in to comment.

Accepted Answer

Jan Siegmund
Jan Siegmund on 19 May 2020
I may have a solution but do not know if this covers all cases:
classdef Subsasgntest
properties
val
end
methods
function obj = Subsasgntest(in)
obj.val = in;
end
function obj = subsasgn(obj,sub,varargin)
%SUBSASGN Subscripted assignment
if(isequal(sub.type,'()'))
if isequal(obj,[])
error('Not yet implemented!');
end
if(isa(varargin{1},'Subsasgntest'))
obj.val(sub.subs{:}) = varargin{1}.val;
else
obj.val(sub.subs{:}) = varargin{1};
end
else
error('This is not supported for this class!');
end
end
end
end
  5 Comments
James Lebak
James Lebak on 13 Oct 2021
In MATLAB R2021b there is a new way to overload subscripting which has two advantages:
1) It allows the class author to overload only a particular type of indexing, that is, paren, dot, or brace, or some combination of types.
2) It improves the performance of indexing into contained objects.
See the section on 'Modular indexing' here to get started.

Sign in to comment.

More Answers (0)

Categories

Find more on Construct and Work with Object Arrays in Help Center and File Exchange

Products


Release

R2019b

Community Treasure Hunt

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

Start Hunting!