Wichita State University Logo

M451: Computational Mathematics

4.2 A Complex Class in MATLAB


4.2.1 Classes

In MATLAB, and in programming in general, one of the most important tools is a class . Classes are special objects that combine structures (called properties for classes) and functions specifically designed for the class (called methods ). Understanding and using classes is important because it allows us to create objects for specific and specialized purposes beyond just having doubles, matrices, strings, etc.

4.2.2 A Basic Class

Below is ourComplex.m , a very simple class based on complex numbers. We know that a complex number is written as $ x + yi $ where $ i = \sqrt{-1} $, and $ x $ and $ y $ represent the real and imaginary parts of the number, respectively. To represent this sort of object in MATLAB , we want to treat the real and imaginary part as independent double precision values, keeping them separated.

classdef ourComplex
    %OURCOMPLEX Our implementation of complex numbers
    %   We're going to be making a class that has most of the same features as
    %   the complex numbers class in MATLAB. Let's start with basic properties
    %   and implementing a constructor, display, and plus method.

    properties
        value
    end

    methods
        function obj = ourComplex(num1,num2)
            %OURCOMPLEX Construct an instance of the ourComplex class
            %   obj = OURCOMPLEX(num1,num2) takes real values a and b and constructs
            %   a complex number num1 + num2*i, where i is the imaginary unit sqrt(-1)
            obj.value(1) = num1;
            obj.value(2) = num2;
        end
    end
end

4.2.3 The Constructor

Creating the class object starts with a special method called a constructor . The constructor is a function that shares the same name as the class whose job it is to create an instance (distinct object) of the class. Constructors always appear first in the list of methods. The constructor for ourComplex is quite simple and only takes two input values:

a = ourComplex(1,-2)

What happens inside the class definition file is that an instance of the class ( obj ), which behaves like a structure named obj with the field value , is created. Just like with structures, we say

obj.value(1) = a;

to assign the number num1 to the first entry of field value within the class object obj . This is done here by taking a 2-vector named value and using the first entry value(1) as $x$ and the second entry value(2) as $y$. We will add other methods to the class later to make sure it behaves like a typical complex number.

In [1]:
a = ourComplex(1,-2)
a = 

 1.0000 - 2.0000i 

The constructor is called in the command line (or anywhere in MATLAB ) like above. We treat it like a function, giving it inputs $x = 1$ and $y = -2$ for the real and imaginary parts, and assign its output to the variable a . This a is now an instance of the ourComplex class and will have any behaviors we have assigned to it. One of the things that we can do is make it display its values in a "prettier" way, so that it looks like $x + yi$. We're going to add a method called disp to accomplish this.

4.2.4 Disp Method

Any output to the MATLAB console is generated by a function called disp . Each of the normal types of objects that we have used in MATLAB thus far such as floats, matrices, strings, cell arrays, and structures have a disp function that controls how the are displayed in the console. By default, user defined classes look very similar to a structure, but we may write a custom disp method that changes this behavior.

function output = disp(obj)
    %DISP displays ourComplex in "pretty" form
    fprintf('%7.4f ', obj.value(1))
    if obj.value(2) < 0
        fprintf('-')
    else
        fprintf('+')
    end
    fprintf('%7.4fi \n', abs(obj.value(2)) )
end

This function is added below the constructor in the above code block. It has the following effect:

In [2]:
b = ourComplex(5,-pi)
b = 

 5.0000 - 3.1416i 

We made a different ourComplex number and it displays according to the method now in the class definition file. This is an example of something called operator overloading , which we will discuss in more detail later. What matters right now is that we have a function that works only exactly on objects of the ourComplex class. Any other type of object will not behave properly. To demonstrate this more explicitly, let's add a plus method to our class.

4.2.5 Plus Method

We insert the following method below the constructor and display methods in our class definition file.

function output = plus(a,b)
    %PLUS Addition method for ourComplex
    %    For this function, we want to make sure that our output is *also*
    %    a member of the class, so we use the constructor
    output = ourComplex(a.value(1) + b.value(1), a.value(2) + b.value(2));
end

Now, we can add two ourComplex numbers.

In [3]:
a = ourComplex(1,-2);
b = ourComplex(5,-pi);
plus(a,b)
a + b
ans = 

 6.0000 - 5.1416i 

ans = 

 6.0000 - 5.1416i 

It works!

In MATLAB , a+b is just a shorthand for calling the function plus(a,b) , so whenever you type a+b , the plus function is really what's being called.

The plus method is really important here, because is demonstrates how you need to be thinking about coding within a class.
First off, notice that it takes as input a and b , which are both ourComplex members. Inside the function, we type

a.value(1)

to refer to the first element of the property value of structure a . We imagine that $a = x_a + y_a i$ and that $b = x_b + y_b i$, and according to the summation rule for complex numbers, $a+b = (x_a + x_b) + (y_a + y_b)i$. Using this information, we wrote the algorithm for our plus method.

Secondly, we need to make sure that our answer is itself an ourComplex number. To make this happen, we call the constructor function of the class in the plus method to make a new ourComplex number and return that as the output. To verify that something is a member of a particular class, MATLAB has a built in function called isa :

In [4]:
isa(a+b,'ourComplex')
ans =

  logical

   1


The isa function is a simple text comparison, and makes sure that the first argument a+b is a member of the class named ourComplex , which it is, meaning our plus method returned a member of the class.

4.2.6 Uminus Method

Next, we add a method for uminus , which is short for "unary minus." It takes an ourComplex number $a = x + yi$ and returns its additive inverse $-a = -x - yi$. In MATLAB , this can be invoked by using the shorthand -a .

function output = uminus(a)
    %UMINUS Unary minus method for ourComplex
    output = ourComplex(-a.value(1), -a.value(2));
end
In [5]:
a
uminus(a)
-a
a = 

 1.0000 - 2.0000i 

ans = 

-1.0000 + 2.0000i 

ans = 

-1.0000 + 2.0000i 

4.27 Minus Method

Now is where things start to get interesting. We have developed a couple of methods plus and uminus . Using these, we are able to form more complicated methods based on ones that we have previously written. For example, subtraction of two complex numbers $ a - b $ (a minus b) can be thought of as $ a + (-b) $ (a plus the additive inverse of b). Since plus and uminus already exist, we use these to define the minus operation for ourComplex .

function output = minus(a,b)
    %Minus Subtraction method for ourComplex
    %    Combines plus and uminus methods to define subtraction
    output = a + (-b);
end

The following inputs all, by design, produce the same results:

In [6]:
minus(a,b)
a + (-b)
a - b
ans = 

-4.0000 + 1.1416i 

ans = 

-4.0000 + 1.1416i 

ans = 

-4.0000 + 1.1416i 

4.2.8 Multiplication Methods (Mtimes and Times)

We're starting to get somewhere, but something extremely important has been missing up until now: multiplication.

Multiplication for this example takes some special care because we actually have two different kinds of multiplication to deal with when using complex numbers. We have to worry about both multiplying an ourComplex number by a double , say by typing 2*a , and multiplying two ourComplex numbers together a*b . This distinction is required since our method mtimes (the function that powers a*b , short for matrix times) will need to have different behavior if it is given two ourComplex numbers or a mix of a double and an ourComplex .

MATLAB distinguishes between mtimes(a,b) = a*b and times(a,b) = a.*b , which we know from previous discussions are matrix multiplication and element-wise multiplication. If we were going to support matrices for our class, we would need to distinguish between the two of them for our work as well. However, we are going to for simplicity not support matrices so these two operations will do the same thing.

Setting up the method for multiplication requires us to check the inputs to see if one is a double or if both are ourComplex .

If we have a double $k$ and an ourComplex $a = x+yi$, then k*a is equal to $$ka = (ka) + (ky)i.$$

If there are two ourComplex values a*b , then $$(x_a + y_a i)(x_b + y_b i) = (x_a y_a - x_b y_b) + (x_a y_b + x_b y_a)i $$

We'll use the isa command we talked about earlier to help check the inputs.

function output = mtimes(a,b)
    %MTIMES is the multiplication method for ourComplex
    %    output = MTIMES(a,b) multiplies
    if isa(a,'ourComplex') %check if a ourComplex, then do what is necessary based on what b is
        if isa(b,'ourComplex')
            output = ourComplex(a.value(1)*b.value(1) - a.value(2)*b.value(2),...
                     a.value(1)*b.value(2) + a.value(2)*b.value(1));
        else % b is a double
            output = ourComplex(a.value(1)*b, a.value(2)*b);
        end
    else % a is a double, and b is ourComplex
        output = ourComplex(a*b.value(1), a*b.value(2));
    end
end

Let's incorporate this into our function and see if it works.

Current Version of OurComplex Function

classdef ourComplex
    %OURCOMPLEX Our implementation of complex numbers
    %   We're going to be making a class that has most of the same features as
    %   the complex numbers class in MATLAB. Let's start with basic properties
    %   and implementing a constructor, display, and plus method.

    properties
        value
    end

    methods
        function obj = ourComplex(num1,num2)
            %OURCOMPLEX Construct an instance of the ourComplex class
            %   obj = OURCOMPLEX(num1,num2) takes real values a and b and constructs
            %   a complex number num1 + num2*i, where i is the imaginary unit sqrt(-1)
            obj.value(1) = num1;
            obj.value(2) = num2;
        end

        function output = disp(obj)
            %DISP displays ourComplex in "pretty" form
            fprintf('%7.4f ', obj.value(1))
            if obj.value(2) < 0
                fprintf('-')
            else
                fprintf('+')
            end
            fprintf('%7.4fi \n', abs(obj.value(2)) )
        end

        function output = plus(a,b)
            %PLUS Addition method for ourComplex
            %    For this function, we want to make sure that our output is *also*
            %    a member of the class, so we use the constructor
            output = ourComplex(a.value(1) + b.value(1), a.value(2) + b.value(2));
        end

        function output = uminus(a)
            %UMINUS Unary minus method for ourComplex
            output = ourComplex(-a.value(1), -a.value(2));
        end

        function output = minus(a,b)
            %Minus Subtraction method for ourComplex
            %    Combines plus and uminus methods to define subtraction
            output = a + (-b);
        end

        function output = mtimes(a,b)
            %MTIMES is the multiplication method for ourComplex
            %    output = MTIMES(a,b) multiplies
            if isa(a,'ourComplex') %check if a ourComplex, then do what is necessary based on what b is
                if isa(b,'ourComplex')
                    output = ourComplex(a.value(1)*b.value(1) - a.value(2)*b.value(2),...
                             a.value(1)*b.value(2) + a.value(2)*b.value(1));
                else % b is a double
                    output = ourComplex(a.value(1)*b, a.value(2)*b);
                end
            else % a is a double, and b is ourComplex
                output = ourComplex(a*b.value(1), a*b.value(2));
            end
        end
    end
end
In [7]:
3*(1+2i)
3*ourComplex(1,2)
(1 + 2i)*(5 - pi*1i)
ourComplex(1,2)*ourComplex(5,-pi)
ans =

   3.0000 + 6.0000i


ans = 

 3.0000 + 6.0000i 

ans =

  11.2832 + 6.8584i


ans = 

11.2832 + 6.8584i 

Victory!

It looks like this doing what we want. It'll take more testing to make absolutely sure , but we're in a good spot. The other thing we'll add is a simple method that makes times behave the same as mtimes , but I'll add that to the next version to save some space.

4.2.9 Real Part, Imaginary Part, and Conjugate

Here's what I want you to do to test your knowledge: I am going to add a method that computes the real part of an ourComplex number called real (just like the MATLAB function). If $a = x + yi$, then $$ \text{Re}(a) = x.$$ It just returns the double that is a 's real part. This is not an ourComplex number, so we won't use the constructor.

Your job is to add two methods:

  1. imag , which returns the imaginary part (just like the built in MATLAB function)
  2. conj , which returns the complex conjugate of an ourComplex number

If $a = x+yi$, then $$ \overline{a} = x - yi.$$ The conj method will be making an ourComplex object, so use the constructor in that method.

Here's ourComplex.m with the real method added, copy this and submit it with your imag and conj methods added to it.

classdef ourComplex
    %OURCOMPLEX Our implementation of complex numbers
    %   We're going to be making a class that has most of the same features as
    %   the complex numbers class in MATLAB. Let's start with basic properties
    %   and implementing a constructor, display, and plus method.

    properties
        value
    end

    methods
        function obj = ourComplex(num1,num2)
            %OURCOMPLEX Construct an instance of the ourComplex class
            %   obj = OURCOMPLEX(num1,num2) takes real values a and b and constructs
            %   a complex number num1 + num2*i, where i is the imaginary unit sqrt(-1)
            obj.value(1) = num1;
            obj.value(2) = num2;
        end

        function output = disp(obj)
            %DISP displays ourComplex in "pretty" form
            fprintf('%7.4f ', obj.value(1))
            if obj.value(2) < 0
                fprintf('-')
            else
                fprintf('+')
            end
            fprintf('%7.4fi \n', abs(obj.value(2)) )
        end

        function output = plus(a,b)
            %PLUS Addition method for ourComplex
            %    For this function, we want to make sure that our output is *also*
            %    a member of the class, so we use the constructor
            output = ourComplex(a.value(1) + b.value(1), a.value(2) + b.value(2));
        end

        function output = uminus(a)
            %UMINUS Unary minus method for ourComplex
            output = ourComplex(-a.value(1), -a.value(2));
        end

        function output = minus(a,b)
            %Minus Subtraction method for ourComplex
            %    Combines plus and uminus methods to define subtraction
            output = a + (-b);
        end

        function output = mtimes(a,b)
            %MTIMES Multiplication method for ourComplex
            %    output = MTIMES(a,b) multiplies
            if isa(a,'ourComplex') %check if a ourComplex, then do what is necessary based on what b is
                if isa(b,'ourComplex')
                    output = ourComplex(a.value(1)*b.value(1) - a.value(2)*b.value(2),...
                             a.value(1)*b.value(2) + a.value(2)*b.value(1));
                else % b is a double
                    output = ourComplex(a.value(1)*b, a.value(2)*b);
                end
            else % a is a double, and b is ourComplex
                output = ourComplex(a*b.value(1), a*b.value(2));
            end
        end

        function output = times(a,b)
            %TIMES Multiplication method for ourComplex
            %    Just copies mtimes
            output = mtimes(a,b);
        end

        function number = real(a)
            %REAL Returns real part of an ourComplex number
            %    I used number here to drive home that real DOES NOT return an ourComplex
            number = a.value(1);
        end       
    end
end

Testing the real method:

In [8]:
a = ourComplex(1,-2)
real(a)
a = 

 1.0000 - 2.0000i 

ans =

     1


Now it is your turn. After your methods are added, you can invoke them by typing things like

a = ourComplex(1,-2);
real(a)
a.real % we'll discuss this later
real(ourComplex(5,-pi))
imag(a)
a.imag
imag(ourComplex(3,-4.7))
conj(a)
a.conj
conj(ourComplex(-1.8, exp(1)))

Check your results against the MATLAB complex number behavior.

In [9]:
real(1-2i)
real(ourComplex(1,-2))
imag(1-2i)
imag(ourComplex(1,-2))
conj(1-2i)
conj(ourComplex(1,-2))
ans =

     1


ans =

     1


ans =

    -2


ans =

    -2


ans =

   1.0000 + 2.0000i


ans = 

 1.0000 + 2.0000i