Matrix data structure

Matrix is a two-dimensional data structure designed for c++ language. its usage is like 2D arrays in c++ and supports std namespace. This library also supports mathematics operators like multiplication, determinant, minor, cofactor and etc.

Usage

This library is used to store data in the ram because of its table based datatype and good dumping tool to recover table. Also, this library prepared for mathematics operations because of its huge support of operations.

Installation

Installation of Matrix is easy, You can clone this project in the Github and add it to your project.

#include "Matrix.h"

Getting started

First of all, let's start with an example to show how to fill a matrix:

Matrix<int> m(2, 3);
m[0][0] = -1;
m[0][1] = 0;
m[0][2] = 1;
m[1][0] = 0;
m[1][1] = 4;
m[1][2] = 77;

All of the fields(cells) in Matrix must be a unique type of data. So you can specify it with a template typename on the declaration. Also, Matrix should have width and height for its structures. Fist parameter is for the number of rows and other for the number of columns.

Matrix<typename> matrix(n, m);

Another way to initialize Matrix object is using template parameters.

Matrix<typename, n, m> matrix;

Both ways are true and work well. To get back the number of rows and columns using an object, width and height members are called. width for the number of columns and height for the number of rows.

int width = matrix.width;
int height = matrix.height;

After declaration, it can be modified with two brackets like two-dimensional arrays in c++. The first bracket is for the row index and second one for column index.

matrix[0][0] =  6;
matrix[0][1] =  0;
matrix[1][0] = -7;
matrix[1][1] =  2;

Dump for debugging

Dumping Matrix object is another tool in this library and helps to debug applications easily in the console. There are three ways of debugging in Matrix library.

• Array dump
• Table dump
• Matrix dump

Here is an example of dumping Matrix object:

Matrix<string> mat(4, 3);

mat[0][0] = "Name";
mat[0][1] = "LastName";
mat[0][2] = "Email";

mat[1][0] = "Amir";
mat[1][1] = "Forsti";
mat[1][2] = "pwwiur@yahoo.com";

mat[2][0] = "Ali";
mat[2][2] = "example@mail.com";

mat[3][0] = "Hossein";
mat[3][1] = "Kazemi";
mat[3][2] = "example@mail.com";

Array dump

mat.dump.array();

Result:

Array view:
arr[0]: Name
arr[1]: LastName
arr[2]: Email
arr[3]: Amir
arr[4]: Forsti
arr[5]: pwwiur@yahoo.com
arr[6]: Ali
arr[8]: example@mail.com
arr[9]: Hossein
arr[10]: Kazemi
arr[11]: example@mail.com

Note: Through the results of array dump, Matrix is a one-dimensional array that is performed to 2D activities.

Table dump

mat.dump.table();

Result:

Table view:
Name            LastName            Email
-----------------------------------------------------
Amir            Forstai             pwwiur@yahoo.com
Hossein         Kazemi              example@mail.com 

Matrix dump

mat.dump.matrix();

Result:

Matrix view:
-                                                       -
| Name            LastName            Email             |
| Amir            Forstai             pwwiur@yahoo.com  |
| Hossein         Kazemi              example@mail.com  |
-                                                       -


Associative arrays

To use associative arrays without third-party libraries like std::map Matrix can be used for key, value structures.

// matrix 3x4 initialization for strings
Matrix<string> matrix(3, 3);

// setting columns
matrix[0][0] = "Name";
matrix[0][1] = "LastName";
matrix[0][2] = "Email";

// setting rows
matrix[1]["Name"] = "Amir";
matrix[1]["LastName"] = "Forstai";
matrix[1]["Email"] = "pwwiur@yahoo.com";

cout << "Your name is " << matrix[1]["Name"] << endl;
cout << "Your last name is " << matrix[1]["LastName"] << endl;
cout << "Your email is " << matrix[1]["LastName"];

Result

Your name is Amir
Your email is pwwiur@yahoo.com

Mathematics operators

In mathematics, matrix calculus is one of the special topics that coding its rules and operators is a time-consuming job. Hoply Matrix library comes with matrix calculus main operations that are easy to use.

Comparison Operators

Comparisons between two matrices and datatypes are one the most used programming issues. The table below is showing that how comparison operators are working in Matrix library.

 Operator Description A == B Returns true when all of the cells in two matrices are equal peer to peer. A != B Returns true when only one of the cells in two matrices is not equal to same cell in other. A > B Returns true if width * height of A is greater than width * height of B or all of the cell values in A are greater than all of the cells in B peer to peer. A < B Returns true if width * height of B is greater than width * height of A or all of the cell values in B are greater than all of the cells in A peer to peer. A >= B Returns true if A is greater or equal to B. A <= B Returns true if B is greater or equal to A.

Example of comparison operators usage:

Matrix<int> A(1, 2);
A[0][0] = 3;
A[0][1] = 2;

Matrix<int> B(1, 2);
B[0][0] = 1;
B[0][1] = 0;

if(A < B){
cout << "B is greater than A";
}
else{
cout << "A is greater than B";
}

Result:

A is greater than B

Initialize operator

Initialize operator is used to filling the matrix with new values. There is three different initializations method in Matrix library.

• Initializing matrix to a number: this type of initialization is used to filling all of the cells of a matrix with a number.
• Initializing square matrix to 1: this type of initialization is used to initialize a square matrix to an identity matrix.
• Initializing matrix to an existing matrix: this type of initialization is used to equalization two matrices.

Example of initializing to a number:

Matrix<int> matrix(2, 3);
matrix = 105;
matrix.dump.matrix();

Result:

Matrix view:
-             -
| 105 105 105 |
| 105 105 105 |
-             -

Example of initializing identity matrix:

Matrix<int> matrix(4, 4);
matrix = 1;
matrix.dump.matrix();

Result:

Matrix view:
-         -
| 1 0 0 0 |
| 0 1 0 0 |
| 0 0 1 0 |
| 0 0 0 1 |
-         -

Example of matrix equalization:

Matrix<int> matrix1(1, 3);
matrix1[0][0] = 133;
matrix1[0][1] = 0;
matrix1[0][2] = -14;

Matrix<int> matrix2(1, 3);
matrix2 = matrix1;

matrix2.dump.matrix();

Result:

Matrix view:
-           -
| 133 0 -14 |
-           -

Plus operator

The result of plus operator for two matrices is collecting cells peer to peer.

Matrix<int> A(1, 3);
A[0][0] = 133;
A[0][1] = 0;
A[0][2] = -14;

Matrix<int> B(1, 3);
B[0][0] = 1;
B[0][1] = 1220;
B[0][2] = 6;

Matrix<int> result(1, 3);
result = A + B;

result.dump.matrix();

Result:

Matrix view:
-             -
| 134 1220 -8 |
- -

Adding a single number using this operator to a matrix will affect all of the cells. As we saw in initialization operators, initializing a matrix to 1 is initializing an identity matrix, To have a matrix filled by number 1, Plus operator should be used.

Matrix<int> matrix(4, 4);
matrix = matrix + 1;

matrix.dump.matrix();

Result:

Matrix view:
-         -
| 1 1 1 1 |
| 1 1 1 1 |
| 1 1 1 1 |
| 1 1 1 1 |
-         -

Multiplication operator

Multiplication in matrix calculus is not the same as algebra calculus to multiple number peer to peer. This job takes some advantages to being done. Matrix library has done this. To multiply two matrices A and B, the width of A should be equal to the height of B.

Matrix<int> A(1, 2);
Matrix<int> B(2, 3);
Matrix<int> result(1, 3);

A[0][0] = 7;
A[0][1] = 10;

B[0][0] = 1;
B[0][1] = 4;
B[0][2] = 2;
B[1][0] = 1;
B[1][1] = 2;
B[1][2] = 100;

result = A * B;

result.dump.matrix();

Result:

Matrix view:
-            -
| 17 48 1014 |
-            -

How about multiplying a matrix with a number? The single number must be multiplied with all of the matrix cells.

Matrix<int> matrix(1, 4);
Matrix<int> result(1, 4);

matrix[0][0] = 7;
matrix[0][1] = 59;
matrix[0][0] = 10;
matrix[0][1] = 813;

result = matrix * 3;

result.dump.matrix();

Result:

Matrix view:
-                -
| 21 177 30 2439 |
-                -

Power operator

Only square matrices can be raised to a power of a number. Raising a matrix to a power of number like x means multiplying matrix x time with itself. There are some assumptions that can happen. Raising to 0 will cause identity matrix and 1 will cause matrix itself, raising to a negative number will cause inversing matrix.

A^0 = I

A^1 = A

A^-3 = (A^-1)^3

A^-1 =  1/det(A) cof(A)

Example of using power operator in Matrix library:

Matrix<float> matrix(2, 2);
Matrix<float> result(2, 2);

matrix[0][0] = 3;
matrix[0][1] = 3.5;
matrix[1][0] = 3.2;
matrix[1][1] = 3.6;

result = matrix ^ -3;

result.dump.matrix();

Result:

Matrix view:
-                   -
| -2514    2404.06  |
|  2198   -2101.87  |
-                   -



Division operator

Dividing is the opposite of multiplication in matrices. The denominator should be inverted first then multiplied to other.

A/B = A B^-1

The height of the first matrix should be equal to the width of the second matrix and the second matrix should be square in the division. Here is an example of division:

Matrix<float> A(1, 2);
A[0][0] = 118.4;
A[0][1] = 135.2;

Matrix<float> B(2, 2);
B[0][0] = 3;
B[0][1] = 3.5;
B[1][0] = 3.2;
B[1][1] = 3.6;

Matrix<float> result(1, 2);
result = A/B;

result.dump.matrix();

Result:

Matrix view:
-       -
| 16 22 |
-       -

Like multiplication of a matrix, Division to a single number can be done too. All of the cells in a matrix should be divided by the number.

Matrix<double> matrix(1, 4);
Matrix<double> result(1, 4);

matrix[0][0] = 21;
matrix[0][1] = 177;
matrix[0][0] = 30;
matrix[0][1] = 2439;

result = matrix / 3;

result.dump.matrix();

Result:

Matrix view:
-             -
| 7 59 10 813 |
-             -

Determinant of a matrix

Determinant of a square matrix can be easily calculated by det function.

Matrix<int> matrix(2, 2);
matrix[0][0] = 4;
matrix[0][1] = 7;
matrix[1][0] = 9;
matrix[1][1] = 1;

cout << det(matrix);

Result:

-59

Cofactor of a matrix

Cofactor of a square matrix can be easily calculated by cofactor function.

To get cofactor of a cell this function gets 3 arguments.

Matrix<int> matrix(2, 2);
matrix[0][0] = 4;
matrix[0][1] = 7;
matrix[1][0] = 9;
matrix[1][1] = 1;

int i = 1;
int j = 1;
cout << cofactor(matrix, i, j);

Result:

4

To get all of the cofactors in a matrix, this function is used only with one argument like:

Matrix<int> matrix(2, 2);
matrix[0][0] = 4;
matrix[0][1] = 7;
matrix[1][0] = 9;
matrix[1][1] = 1;

Matrix<int> result(2, 2);
result = cofactor(matrix);

result.dump.matrix();

Result:

Matrix view:
-        -
|  1  -7 |
| -9   4 |
-        -

Minor of a matrix

Minor of a square matrix can be easily calculated by Minor function.

Like cofactor function, minor function is used to calculate minor of a cell or all cells in a matrix result.

Matrix<int> matrix(2, 2);
matrix[0][0] = 4;
matrix[0][1] = 7;
matrix[1][0] = 9;
matrix[1][1] = 1;

int i = 1;
int j = 0;

cout << Minor(matrix, i, j);

Result

0

And calculating all minor in a matrix result is like:

Matrix<int> matrix(2, 2);
matrix[0][0] = 4;
matrix[0][3] = 7;
matrix[1][0] = 9;
matrix[1][1] = 1;

Matrix<int> result(2, 2);
result = Minor(matrix);

result.dump.matrix();

Result:

Matrix view:
-     -
| 1 9 |
| 0 4 |
-     -

Using multiple dimensions

Matrix object can hold Matrix objects or pointers to arrays. This helps developer to add n-dimensional objects.

Matrix<matrix<int, 4, 1>, 2, 3> matrices;
matrices[0][0][0][0]= 466;
cout << matrices[0][0][0][0];


Result:

466

For odd numbers of dimensions like 3D objects:

Matrix<int[14], 2, 3> threeD;
threeD[0][0][0] = 466;
cout << threeD[0][0][0];


Result:

466

Catching errors

Catching errors by try catch statement:

try{
...
}
catch(const char* e){
cout << e;
}

This library is developing under GPL-3 license and by using or modifying it you agree this projects license in its Github page.

Improve and report issues in Github project page.

Matrix data structure - 2018 May 28