How to Build a Matrix Module from Scratch | by Khuyen Tran | Towards Data Science

Numpy is a useful library that enables you to create a matrix and perform matrix operations with ease. If you want to know about tricks you could use to create a matrix with Numpy, check out my blog here. But what if you want to create a matrix class with features that are not included in the Numpy library? To be able to do that, we first should start with understanding how to build a matrix class that enables us to create a matrix that has basic functions of a matrix such as print, matrix addition, scalar, element-wise, or matrix multiplication, have access and set entries.
By the end of this tutorial, you should have the building block to create your own matrix module.
Creating a class allows new instances of a type of object to be made. Each class instance can have different attributes and methods. Thus, using a class will enable us to create an instance that has attributes and multiple functions of a matrix. For example, if A = [[2,1],[2,3]], B = [[0,1],[2,1]], A + B should give us a matrix [[2,3],[4,4]].
__method__ is a private method. Even though you cannot call the private method directly, these built-in methods in a class in Python will let the compiler know which one to access when you perform a specific function or operation. You just need to use the right method for your goal.
I will start from what we want to create then find the way to create the class according to our goal. I recommend you to test your class as you add more methods to see if the class acts like what you want.
What we want to achieve with our class is below
        >>> A = Matrix(dims=(3,3), fill=1.0)	>>> print( A )	------------- output -------------	|   1.000,    1.000,    1.000| 	|   1.000,    1.000,    1.000| 	|   1.000,    1.000,    1.000| 	----------------------------------
Thus, we want to create a Matrix object with parameters that are dims and fill.
class Matrix:    def __init__(self, dims, fill):         self.rows = dims[0]       self.cols = dims[1]        self.A = [[fill] * self.cols for i in range(self.rows)]
We use __init__ as a constructor to initialize the attributes of our class (rows, cols, and matrix A). The rows and cols are assigned by the first and second dimensions of the matrix. Matrix A is created with fill as the values and self.cols and self.rows as the shape of the matrix.
We should also create a __str__ method that enables us to print a readable format like above.
def __str__(self):       m = len(self.A) # Get the first dimension       mtxStr = ''  mtxStr += '------------- output -------------\n'            for i in range(m):              mtxStr += ('|' + ', '.join( map(lambda x:'{0:8.3f}'.format(x), self.A[i])) + '| \n')  mtxStr += '----------------------------------'  return mtxStr
Goal:
Standard matrix-matrix addition
        >>> A = Matrix(dims=(3,3), fill=1.0)	>>> B = Matrix(dims=(3,3), fill=2.0)	>>> C = A + B	>>> print( C )	------------- output -------------	|   3.000,    3.000,    3.000| 	|   3.000,    3.000,    3.000| 	|   3.000,    3.000,    3.000| 	----------------------------------
Scaler-matrix addition (pointwise)
        >>>A = Matrix(dims=(3,3), fill=1.0)	>>> C = A + 2.0	>>> print( C )	------------- output -------------	|   3.000,    3.000,    3.000| 	|   3.000,    3.000,    3.000| 	|   3.000,    3.000,    3.000| 	---------------------------------- 
We use __add__ method to perform the right addition.
Since addition is commutative, we also want to be able to add on the right-hand-side of the matrix. This could be easily done by calling the left addition.
def __radd__(self, other):    return self.__add__(other)
Goal:
Matrix-Matrix Pointwise Multiplication
        >>> A = Matrix(dims=(3,3), fill=1.0)	>>> B = Matrix(dims=(3,3), fill=2.0)	>>> C = A * B	>>> print( C )	------------- output -------------	|   2.000,    2.000,    2.000| 	|   2.000,    2.000,    2.000| 	|   2.000,    2.000,    2.000| 	----------------------------------
Scaler-matrix Pointwise Multiplication
        >>> A = Matrix(dims=(3,3), fill=1.0)	>>> C = 2.0 * A	>>> C = A * 2.0	>>> print( C )	------------- output -------------	|   2.000,    2.000,    2.000| 	|   2.000,    2.000,    2.000| 	|   2.000,    2.000,    2.000| 	----------------------------------
Use __mul__ method and __rmul__ method to perform left and right point-wise
Goal:
        >>> A = Matrix(dims=(3,3), fill=1.0)	>>> B = Matrix(dims=(3,3), fill=2.0)	>>> C = A @ B	>>> print( C )	------------- output -------------	|   6.000,    6.000,    6.000| 	|   6.000,    6.000,    6.000| 	|   6.000,    6.000,    6.000| 	----------------------------------
Matrix multiplication could be achieved by __matmul__ method that is specific for matrix multiplication.
Goal:
        >>> A = Matrix(dims=(3,3), fill=1.0)	>>> A[i,j]	>>> A[i,j] = 1.0
Use __setitem__ method to set the value for the matrix indices and use__getitem__ method to get value for the matrix indices.
After creating the class Matrix, it is time to turn it into a module. Rename the text that contains the class to __init__.py. Create a folder called Matrix. Putmain.py and another file calledlinearAlgebra inside this folder. Put__init__.py file inside the linearAlgebra file.
Use main.py to import and use our Matrix class.
Awesome! You have learned how to create a matrix class from scratch. There are other methods in Python class that would enable you to add more features for your matrix. As you have the basic knowledge of creating a class, you could create your own version of Matrix that fits your interest. Feel free to fork and play with the code for this article in this Github repo.
I like to write about basic data science concepts and play with different algorithms and data science tools. You could connect with me on LinkedIn and Twitter.
Star this repo if you want to check out the codes for all of the articles I have written. Follow me on Medium to stay informed with my latest data science articles like these: