vectorization in matlab class - matlab

I have a class in MATLAB that represents an imaginary number. I have a constructor and two data members: real and imag. I am playing with overloading operator in a class and I want to make it work with matrices:
function obj = plus(o1, o2)
if (any(size(o1) ~= size(o2)))
error('dimensions must match');
end
[n,m] = size(o1);
obj(n,m) = mycomplex();
for i=1:n
for j=1:m
obj(i,j).real = o1(i,j).real + o2(i,j).real;
obj(i,j).imag = o1(i,j).imag + o2(i,j).imag;
end
end
end
But I don't want to use for loops. I want to do something like:
[obj.real] = [o1.real] + [o2.real]
But I don't understand why it does not work... the error says:
"Error in + Too many output arguments".
I know that in MATLAB it is good to avoid for loops for speed up... Can someone explain me why this does not work, and the right way to think about vectorization in MATLAB with an example for my function?
Thanks in advance.
EDIT: definition of my complex class:
classdef mycomplex < handle & matlab.mixin.CustomDisplay
properties (Access = public)
real;
imag;
end
methods (Access = public)
function this = mycomplex(varargin)
switch (nargin)
case 0
this.real = 0;
this.imag = 0;
case 1
this.real = varargin{1};
this.imag = 0;
case 2
this.real = varargin{1};
this.imag = varargin{2};
otherwise
error('Can''t have more than two arguments');
end
obj = this;
end
end
end

Consider the implementation below. First some notes:
the constructor can be called with no parameters. This is important to allow preallocating object arrays: obj(m,n) = MyComplex()
for convenience, the constructor accepts either scalar of array arguments. So we can call: c_scalar = MyComplex(1,1) or c_array = MyComplex(rand(3,1), rand(3,1))
the plus operator uses a for-loop for now (we will later change this).
(Note that I skipped some validations in the code, like checking that o1 and o2 are of the same size, similarly for a and b in the constructor).
classdef MyComplex < handle
properties
real
imag
end
methods
function obj = MyComplex(a,b)
% default values
if nargin < 2, b = 0; end
if nargin < 1, a = 0; end
% accepts scalar/array inputs
if isscalar(a) && isscalar(b)
obj.real = a;
obj.imag = b;
else
[m,n] = size(a);
obj(m,n) = MyComplex();
for i=1:m*n
obj(i).real = a(i);
obj(i).imag = b(i);
end
end
end
function obj = plus(o1, o2)
[m,n] = size(o1);
obj(m,n) = MyComplex(); % preallocate object array
for i=1:m*n % linear indexing
obj(i).real = o1(i).real + o2(i).real;
obj(i).imag = o1(i).imag + o2(i).imag;
end
end
end
end
An example of using the class:
% scalar objects
>> c1 = MyComplex(1,2);
>> c2 = MyComplex(3,4);
>> c3 = c1 + c2
c3 =
MyComplex with properties:
real: 4
imag: 6
% array of objects
>> c4 = [c1;c1] + [c2;c2]
c4 =
2x1 MyComplex array with properties:
real
imag
Now here is a vectorized version of the plus method:
function obj = plus(o1, o2)
[m,n] = size(o1);
obj(m,n) = MyComplex();
x = num2cell([o1.real] + [o2.real]);
[obj.real] = deal(x{:});
x = num2cell([o1.imag] + [o2.imag]);
[obj.imag] = deal(x{:});
end
I'm using the syntax: [objarray.propName] to reference a property in object arrays, this return the values as a vector.
For the opposite of assigning a property in an object array, I use comma-separated lists, thus I had to convert to a cell array to get the x{:} convenient syntax.
Note that the deal call is not strictly needed, we could write the assignment without it:
[obj.real] = x{:};

The line obj(n,m) = mycomplex() looks very suspicious. I think what you want to do there is obj = mycomplex(n,m) instead.
I can't see the rest of your code, but it's miraculous to me that this line even works. I suspect that you have an obj variable stored somewhere already, and this code simply overwrites one entry of that variable. I predict that if you clear all variables, it's going to fail on that line.
Again, it's very difficult to understand what happens without knowing what mycomplex() actually does.

Related

A Matlab class for Commutative Hypercomplex number: How to overload the basic Matlab function?

I am programming commutative hypercomplex number class.
First of all: If that already exist, please tell. I have not found.
PS: Quaternion exists but are not commutative.
I am trying to reproduce all that Matlab can do with real and complex, but with hypercomplex. The solution that I am working on is to define a class. If a more smart method may be used, please tell.
Many codes with complex numbers exist, the idea is to overload smartly to make working all existing program with Hypercomplex. This work might be used by many users.
please see at the end of the post the main maths principle found in Ablamowicz1996 _ Clifford Algebras with Numeric and Symbolic Computations
My Hypercomplex class works for basic operation: I have overloaded the mtimes(a,b) = a*b operation.
For instance, I can do:
A = MyClass(1);
B = MyClass(2);
A*B; % ->that works
As a main problem, for instance in 2D, I would like to be able to use
[A B C].*[D ; E]
while using the element-wise behavior of Matlab, and for any dimension , and with my definition of *. For instance, while dealing with matrices of compatible size but not identical:
A = [1 2 3]; B = [1;2]
Matlab gives
A.*B
ans =
1 2 3
2 4 6
That works also for N dimension when compatible.
How can I overload times(a,b) = a.*b , power, rdivide.. in order to have the element-wise behavior of Matlab?
Here is my Class
classdef Hypercomplex < handle
properties (SetAccess = public, GetAccess = public)
A
end
properties (SetAccess = private, GetAccess = private)
eps,nu,e1,e2
end
methods
function s = Hypercomplex(Z) %% Conctruc
% Z might be real, complex or hypercomplex
if isa(Z,'Hypercomplex') % is HyperComplex
s = Z;
elseif ~isreal(Z) && length(Z) == 1 % is Complex
s = Hypercomplex([real(Z) imag(Z) 0 0]);
elseif isreal(Z) && length(Z) < 5
s.A = zeros(1,4);
for ii = 1:length(Z) % is vecteur
s.A(ii) = Z(ii);
end
end
end
function s = epsnu(s)
s.eps = (s.A(1) - s.A(4)) + 1i*(s.A(2)+s.A(3));
s.nu = (s.A(1) + s.A(4)) + 1i*(s.A(2)-s.A(3));
end
function s = e1e2(s)
s.e1 = Hypercomplex([0.5 0 0 -0.5]);
s.e2 = Hypercomplex([0.5 0 0 0.5]);
end
%% Overload
function out = cos(a)
a.epsnu.e1e2;
out = cos(a.eps)*a.e1 + cos(a.nu)*a.e2;
% I might also do for sin exp sqrt ...
end
function out = mtimes(a,b) % '*'
a = Hypercomplex(a).epsnu;
b = Hypercomplex(b).epsnu;
eps12 = 0.5*(a.eps * b.eps);% produit complex
nu12 = 0.5*(a.nu * b.nu );% produit complex
h1 = Hypercomplex([real(eps12) imag(eps12) imag(eps12) -real(eps12)]);
h2 = Hypercomplex([real(nu12) imag(nu12) -imag(nu12) real(nu12) ]);
out = h1+h2;
end
function out = mrdivide(a,b)
a = Hypercomplex(a);
b = Hypercomplex(b);
out = a * b.inverse;
end
function s = inverse(s)
s = Hypercomplex(s).epsnu.e1e2;
s = 1/(s.eps)*s.e1 + 1/(s.nu)*s.e2;
end
function out = plus(a,b)
a = Hypercomplex(a);
b = Hypercomplex(b);
out = Hypercomplex(a.A + b.A);
end
function out = minus(a,b)
a = Hypercomplex(a);
b = Hypercomplex(b);
out = Hypercomplex(a.A - b.A);
end
end
end
Example i^2 = -1 :
>> Ni = Hypercomplex([0 1 0 0]) ;
>> Ni*Ni
Hypercomplex with properties:
A: [-1 0 0 0]
I would think you need to loop over your arrays, and have a special case where, if for one dimension one of the inputs has size 1 and the other doesn't, then the same element for that array is used. A simple way to accomplish this is to index with (i-1)*step + 1, where step is 0 if the array has size 1, and 1 otherwise.
One thing to note is that, in your overloaded method, indexing doesn't use your custom indexing definition (subsref and subsasgn), but the built-in one.
For example, assuming you only allow 2D arrays of your class:
function C = times(A, B)
szA = size(A);
szB = size(B);
if numel(szA)~=2 || numel(szB)~=2
error('Only 2D arrays are supported')
end
szC = max(szA, szB);
stepA = [matchSizes(szA(1), szC(1)), matchSizes(szA(2), szC(2))];
stepB = [matchSizes(szB(1), szC(1)), matchSizes(szB(2), szC(2))];
C = MyClass.empty(szC);
for jj = 1:szC(2)
for ii = 1:szC(1)
C(ii,jj) = A((ii-1)*stepA(1)+1,(jj-1)*stepA(2)+1) * B((ii-1)*stepB(1)+1,(jj-1)*stepB(2)+1);
end
end
% private helper function, keep in the same file
function step = matchSizes(szIn, szOut)
step = 1;
if szIn ~= szOut
if szIn == 1
step = 0;
else
error('Sizes not compatible')
end
end
NOTE: Code not tested.
NOTE2: This is one of the cases where 0-based indexing is more convenient!
If MyClass has a property val to store numeric values I think (hope) that this should be possible (not tested):
function obj = times(A, B)
r = reshape([A.val], size(A)) .* reshape([B.val], size(B));
obj = arrayfun(#MyClass, r);
end
EDIT (because question is edited):
You can follow two ways to implement array of those numbers:
Array of objects
In this method each object just contains a hypercomplex number. It is the way that you have tried. As #CrisLuengo pointed out you can use loops to create the desired result or you can use a combination of vectorization and use of functions like arrayfun and cellfun. You need to know how to work with cell arrays and comma separated list and be familiar with verctorization operations like implicit expansion. Here I implemented plus and epsnu using vectorization and cellfun. They can work with both scalar and object arrays:
function out = plus(a,b)
a = Hypercomplex(a);
b = Hypercomplex(b);
AA = reshape([a.A], [4, size(a)]);
BB = reshape([b.A], [4, size(b)]])
CC = AA + BB;
A1 = reshape()
out = cellfun(#Hypercomplex, num2cell(reshape(CC, 4, []).', 2));
end
function s = epsnu(s)
AA = reshape([s.A], 4, []);
eps = num2cell(AA(1, :) - AA(4, :) + 1i.*(AA(2, :) + AA(3, :)));
nu = num2cell(AA(1, :) + AA(4, :) + 1i.*(AA(2, :) - AA(3, :)));
[s.eps] = eps{:};
[s.nu] = nu{:};
end
Object containing array of numbers
Instead of defining A as a [4 x 1] array you can define each coordinate (x,y,z,et) as a separate property of class each can contain array of numbers. you need to overload the cat operator to concatenate objects. As a result no object array is created but the underlying verctors are concatenated. You need tooverload subsref and subsasgn if you want to simulate element access. I think this method is simpler to implement than the first method.

matlab how to call a class method that changes prop from another class method

If I call a method (receiving and returning obj) it changes my property.
But if I call that method from another method it fails. I tried all kinds of ways but still failing.
classdef AClass
properties
A;
end
methods
function obj = ChangeA(obj, v)
obj.A = v;
end
function obj = CallChangeA(obj)
obj.ChangeA(4);
%obj = obj.ChangeA(4);
%ChangeA(obj, 4);
%obj = ChangeA(obj, 4);
% none of these works
end
end
end
% ------ script:
a1 = AClass;
a1.A = 1;
a1.ChangeA(2); % a1.A = 2
a2 = AClass;
a2.A = 3;
a2.CallChangeA(); % a2.A = 3 !!! not four
How do I write the code so calling from 1 method to the other updates the property?
Other than the obvious typos in your example code, as I commented above, I would highly suggest taking a look at the difference between MATLAB's Handle and Value classes. By default, MATLAB classes are value classes, so each time the object is passed to a function an independent copy is created. If you're making changes to this object then you need to return it as an output:
classdef AClass
properties
A;
end
methods
function obj = ChangeA(obj, a)
obj.A = a;
end
function obj = CallChangeA(obj)
obj = obj.ChangeA(4);
end
end
end
Which functions as expected:
>> a1 = AClass;
>> a1.A = 1
a1 =
AClass with properties:
A: 1
>> a1 = a1.CallChangeA()
a1 =
AClass with properties:
A: 4
Handle classes, on the other hand, are references to a single underlying object, allowing for (among other things) in place modification of the object:
classdef AClass < handle
properties
A;
end
methods
function ChangeA(obj, a)
obj.A = a;
end
function CallChangeA(obj)
obj.ChangeA(4);
end
end
end
Which also functions as expected:
>> a1 = AClass;
>> a1.A = 1;
>> a1.A
ans =
1
>> a1.CallChangeA()
>> a1.A
ans =
4

How to time each line of a MatLab script?

Suppose we have a loop:
for i = 1:1000
A
B
C
end
... and I wish to find out the CPU usage spread.
A, B, C are MatLab statements not functions, so (IIUC) I can't use the profiler.
Also in reality I have a dozen lines to cover.
The obvious long-winded way would be:
s = zeros(50, 1);
t = cputime;
for ...
A
s(1) = s(1) + (cputime-t); t = cputime;
B
s(2) = s(2) + (cputime-t); t = cputime;
:
... which isn't too bad, I suppose.
But can it be improved upon?
I thought of doing:
t = zeros(50, 1);
e(t,0); % reset
for i = 1:1000
A
e(1);
B
e(2);
C
e(3);
end
... with:
function e(t, k)
if k==0
last_cputime = cputime;
return
end
t(k) = t(k) + (cputime-last_cputime);
last_cputime = cputime;
end
But it doesn't see t, so I have to pass that.
Also it doesn't remember last_cputime between invocations, so I need to pass that as well.
So e(last_cputime,t,1)
It's rather ugly. I experimented with using an in-line function:
e = #(k) eval( 't(k) = t(k) + (cputime-last_cputime); cputime = last_cputime;' );
But I couldn't get this working either:
K>> t = zeros(3,1)
t =
0
0
0
K>> eval( 't(1) = 3' )
t =
3
0
0
K>> e = #(k) eval( 't(k) = 3;' )
e =
function_handle with value:
#(k)eval('t(k) = 3;')
K>> e(1)
Attempt to add "t" to a static workspace.
See Variables in Nested and Anonymous Functions.
Error in pi_test>#(k)eval('t(k) = 3;')
I wonder if another option might be:
for i = 1:1000
e('A');
e('B');
e('C');
end
But then how to code up e?
Is there any way to do avoid horrible ugliness-through-duplication?
How about a classdef that handles this?
You can save this as mtime.m
classdef mtime < handle
properties
times
end
properties (Access = private)
t
end
methods
function obj = mtime() %initialize
obj.t=cputime;
obj.times=[];
end
function time(obj)
obj.times(end+1) = cputime-obj.t;
obj.t = cputime;
end
end
end
You can then intialize with T=mtime(); and time your code by calling time(T); After the code is finished the timings can be found in T.times.

Stopping the output of a for cycle in matlab

I'm facing an issue with this simple Fibonacci number generator program:
function f = fibonr(n)
f(1) = 1;
f(2) = 1;
for i = 3:n
f(i) = f(i-1) + f(i-2);
end
end
If I want to display only the n-th number of the sequence, what adjustments should I make?
function f = fibonr(n)
f = zeros(n,1); %//initialise the output array
f(1,1) = 1;
f(2,1) = 1;
for ii = 3:n
f(ii,1) = f(ii-1,1) + f(ii-2,1);
end
%//create a string with text and variables
str = sprintf('The %d th number in the Fibonacci sequence is %d',n,f(ii,1));
disp(str) %//display your output.
end
first up: don't use i as a variable. Secondly, I switched to using column vectors, since MATLAB processes them faster, as well as I initialised the array, which is way faster (hence the shiny orange wiggles below your f(i)= line).
Call your function:
output = fibonr(10);
The 10 th number in the Fibonacci sequence is 55
If you use e.g. n=20 and still want the 10th argument just call output(10)
if you want the specified output right away you can use nargin. This code will give you all of the sequence if you call fibonr(n), or you can specify a vector to get the fibonacy numbers at said positions. If you are interested in both, your specified output and all the numbers, you can call the function with:
[output, fibnumbers] = fibonr(n,v);
function [output,f] = fibonr(n,v)
f(1) = 1;
f(2) = 1;
for i = 3:n
f(i) = f(i-1) + f(i-2);
end
if nargin() > 1
output = f(v);
else
output = f;
end

How to find the command by which certain struct done in Matlab?

Suppose a is defined as the struct below. I tried to find equivalent command to R's dput but errs here. For example, I know that the below must be of the form struct('const',1,'terms',{{struct(),struct()}}) but I don't know what is stored inside the structure without going to check it with commands like here, time-consuming.
So by which command I can see the original command to generate a struct in Matlab?
>> a
a =
const: 1
terms: {[1x1 struct] [1x1 struct]}
Comment
Is it possible for you to switch from using a structure to a class? If so you could make one that mimics the struct, and each time it is modified call stack = dbstack to get the stack - then store the stack along with the change. The command that made the change could then be retrieved automatically later from the line numbers in the stack.
As a follow-up request to this in the comment, here is an example of a class that provides struct functionality and also keeps a record of its assignments:
classdef utstruct
properties (SetAccess = private)
modifications
end
properties (Dependent, SetAccess = private)
myStruct
end
properties (Access = private)
m_struct
end
methods
function self = utstruct(varargin)
if nargin > 0
self.m_struct = builtin('struct', varargin{:});
else
self.m_struct = builtin('struct');
end
% Should update self.modifications here
end
function B = subsref(self, s)
if any(strcmp(s(1).subs, properties(self)))
B = builtin('subsref', self, s);
else
B = subsref(self.m_struct, s);
end
end
function A = subsasgn(self, s, b)
self.m_struct = subsasgn(self.m_struct, s, b);
newMod = builtin('struct');
newMod.type = 'subsasgn';
newMod.modData = {s b};
newMod.stack = dbstack;
self.modifications = [self.modifications; newMod];
A = self;
end
function disp(self)
disp(self.m_struct);
end
function names = fieldnames(self, varargin)
names = fieldnames(self.m_struct, varargin{:});
end
function C = cat(self, dim, varargin)
uts = cellfun(#(x)isa(x, 'utstruct'), varargin);
varargin{uts} = cellfun(#(x)x.m_struct, varargin(uts));
varargin = [{self.m_struct} varargin];
self.m_struct = cat(dim, varargin{:});
% Should update self.modifications here
C = self;
end
function C = horzcat(self, varargin)
C = self.cat(1, varargin{:});
end
function C = vertcat(self, varargin)
C = self.cat(2, varargin{:});
end
function value = get.myStruct(self)
value = self.m_struct;
end
end
end
You should add some code to update the modifications array when initialisation / concatenation operations occur.
The subsref and subsasgn overrides are the key points here that make it behave like a struct (by deferring all their activity to an actual struct), but other overrides like fieldnames and disp do the same thing. In subsasgn a record of all the assignments to the struct is kept, along with the stack that generated the assignment.
Note: for this to be fully compatible with the built-in struct you probably should override a few more methods, but this should be enough to get you started. See Subclassing MATLAB Built-In Types.
Edit: I made the example a bit more robust. It's now a value class - as it should be - and works with concatenation.
Edit: You can avoid using a find-and-replace to refactor existing struct(...) calls by redefining the function struct:
function s = struct(varargin)
% STRUCT Overrides default struct function to provide unit-testable structs
%
% Set global variable unitTestStructEnabled to true to enable this
% function.
%
global unitTestStructEnabled;
if isempty(unitTestStructEnabled)
unitTestStructEnabled = false;
end
if unitTestStructEnabled
s = utstruct(varargin{:});
else
s = builtin('struct', varargin{:});
end
You probably don't want that hanging around on your path the whole time, as you will get a warning when you first create a struct (you could turn it off, but that might hide other problems), so you should probably put it in a folder that's not normally in the path, and temporarily add it to the path for unit testing (addpath / rmpath).
Here's the skeleton of a dumpvar function, i.e. something along the idea of tashuhka
function str = dumpvar(a)
switch class(a)
case 'double'
if isempty(a)
str = '[]'; % bug when "a" is multidimensional and empty
elseif isscalar(a)
str = num2str(a);
elseif isrow(a)
str = strcat('[', dumpvar(a(1)));
for k = 2:size(a,2)
str = strcat(str,',',dumpvar(a(k)));
end;
str = strcat(str, ']');
elseif numel(size(a)) == 2
str = strcat('[', dumpvar(a(1,:)));
for k = 2:size(a,1)
str = strcat(str,';',dumpvar(a(k,:)));
end;
str = strcat(str, ']');
else
do_what_i_mean();
end;
case 'struct'
fn = fieldnames(a);
if isempty(fn)
str = 'struct()';
elseif isscalar(a)
str = strcat('struct(''', fn{1},''',', dumpvar(a.(fn{1})));
for k=2:numel(fn)
str = strcat(str,',''',fn{k},''',', dumpvar(a.(fn{k})));
end;
str = strcat(str, ')');
else
do_what_i_mean();
end;
otherwise
do_what_i_mean();
end;
function do_what_i_mean()
throwAsCaller(MException(...
'beingLazy:onSaturday:Fault', ...
'Storage of class "%s" and arity %d is not implemented yet. Would you?', ...
class(a), numel(size(a))...
));
end;
end
Save it in a dumpvar.m file somewhere in Matlab's path, then test it with this code snippet:
a = struct(...
'field1', 1,...
'field2', [],...
'field10', struct(...
'field3', [1 2;2 3;3 4],...
'field4', struct()...
)...
);
disp(dumpvar(a));
eval(sprintf('b=%s;', dumpvar(a)));
Please note that this function is still in a toy stage: it's anywhere near exhaustive (lacks treatment of struct arrays, cells, char, logical and other fundamental types, not to mention user-defined classes --- hehe, those would be a pickle) and it is meant to be completed by you with whatever functionality you need.
Although it does not answer completely your question, vsize() by Urs can help you:
% Create some complicated variable
v(1).a{1}=sparse(magic(3)+2i*magic(3));
v(2).a{2}={struct('FA',{'a','bb'},'FB',{magic(5),{}})};
v(2).b{2}=#(x) sind(x);
% Dissect
P = vsize(v);
% -------------------------
% 1998 1998 B * v = 2:1x2:struct.(2)
% CELL ----- 360 B v[].a = 2:1x1:cell
% 1750 248 B - v[].a{} = 2:3x3:double.sparse.complex
% CELL ----- 1014 B v[].a = 2:1x2:cell
% 1750 0 B - v[].a{} = 2:0x0:double
% CELL ----- 894 B v[].a{} = 2:1x1:cell
% STRUCT --- 782 B v[].a{}{} = 2:1x2:struct.(2)
% 1748 2 B - v[].a{}{}[].FA = 2:1x1:char
% 1744 4 B - v[].a{}{}[].FA = 2:1x2:char
% 1544 200 B - v[].a{}{}[].FB = 2:5x5:double
% CELL ----- 0 B v[].a{}{}[].FB = 2:0x0:cell
% 1544 0 B - v[].b = 2:0x0:double
% CELL ----- 152 B v[].b = 2:1x2:cell
% 1544 0 B - v[].b{} = 2:0x0:double
% 1512 32 B - v[].b{} = 2:1x1:function_handle