Edwardo
Edwardo

Reputation: 643

vectorization in matlab class

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

Upvotes: 1

Views: 697

Answers (2)

Amro
Amro

Reputation: 124563

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{:};

Upvotes: 2

Phonon
Phonon

Reputation: 12737

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.

Upvotes: 0

Related Questions