C and C++ library of functions and procedures for matrix (bidimensional arrays) – Mathematical functions

No comments - This post in romanian

Other posts on this topic:

The mathematical functions uses the matrices as operands in different math operations. The operations with matrices described in this chapter are adding, multiplying, transposing, subtracting and inverting. Also here are some arithmetical operations with linear matrices like adding, subtracting, multiplying and transposing. For example, two linear matrices sum is obtained after transforming the matrices in one-dimensional arrays and adding them. In the same way are done the others operations.

In this post are described the functions that are doing those computations. Both variants of defining a matrix, the static method and the dynamic one, are used.

The multiplying operation is implemented in two ways:

  • by the function multiplying( n1, m1, x, n2, m2, y, z,*n3, *m3), from the library matrix.h.
  • by overloading the operator “*”, inside the matrix class.

The function void multiplying(int n1,int m1,int x[30][30],int n2,int m2,int y[30][30],int z[30][30],int *n3,int *m3) creates a new matrix by multiplying two known matrices. This function’ parameters are:

  • int n1,m1- entry parameters representing the matrix x dimensions, which are the lines and the columns numbers;
  • int n2,m2- entry parameters representing the matrix y dimensions, which are the lines and the columns numbers;
  • int x[30][30],y[30][30]- entry parameters representing the two matrices that will be multiplied;
  • int z[30][30]- exit parameter representing the result of the two above matrices multiplying;
  • int n3,m3- exit parameters representing the lines number and the columns number of the result matrix z.

These parameters are transferred by their value. The code sequence, that multiplies the two matrices, is:

error=1;
if(m1! =n2) error=0;
else
{
for(i=0;i for(j=0;j {
z[i][j]=0;
for(k=0;k z[i][j]+=x[i][k]*y[k][j];
}
}
if (error==0) printf("\n Multiplying is not possible!");
else {
*n3=n1;
*m3=m2;
}

 

As everybody knows, two matrices multiplying is possible only if the first matrix lines number is equal with the second one columns number. In the previous function, when this condition is not respected a message is displayed: Multiplying is not possible!

In the class matrix the multiplying operation is done by overloading the operator “*”. The code sequence is:

matrix matrix::operator*(matrix b)
{
matrix c(n,b.m);
if (m==b.n) {
	     for(i=0;i<n;i++)
		      for(j=0;j<b.m;j++)
		      			{
					c.a[i][j]=0;
					for(int k=0;k<m;k++)
					     c.a[i][j]+=a[i][k]*b.a[k][j];
					}
	       }
return c;
}

Overloading procedure returns a matrix object, named c, created by multiplying two matrices. The memory allocation for this resulted matrix is realized by calling the class constructor, matrix c(n,b.m).

This function parameter is an object of type matrix, named b. It represents the right operand of this mathematical operation. The left operand is represented by the pointer this. As in the function from the library, the validation test is also done here.

Two matrices sum is calculated by a library matrix.h member function named adding(n1,m1,x,n2,m2,y,*n3,*m3,z). Its parameters are:

  • int n1,m1- entry parameters representing the matrix x dimensions, which are the lines and the columns numbers;
  • int n2,m2- entry parameters representing the matrix y dimensions, which are the lines and the columns numbers;
  • int x[30][30],y[30][30]- entry parameters representing the two matrices that will be multiplied;
  • int z[30][30]- exit parameter representing the result of adding the two above matrices;
  • int n3,m3- exit parameters representing the lines number and the columns number of the result matrix z.

The code sequence, that realizes the adding of two matrices, is:

error=1;
if((n1!=n2)|(m1!=m2)) error=0;
  	else
   {
	   for(i=0;i<n1;i++)
	          for(j=0;j<m1;j++)
    	               z[i][j]=x[i][j]+y[i][j];
	   }
if (error==0) printf("\n Adding is not possible!");
          else { 
               *n3=n1;
	    *m3=m2;
	 	}

Here, as in the multiplying case, must be verified if those matrices dimensions are equal. If this is not true the following message will be display: Adding is not possible!

Using only the class matrix member functions, the operation of adding two matrices is made with the “+” operator, which has been overloaded. Its code sequence is:

  matrix matrix::operator +(matrix b)
{
matrix c(n,m);
 
if ((n==b.n)&&(m==b.m)){
		      for(i=0;i<n;i++)
			     for(j=0;j<m;j++)
				  c.a[i][j]=a[i][j]+b.a[i][j];
			}
return c;
}

This function parameters are the pointer this and a matrix object named b. The c object represents this operation result. Same as the multiplication operation, the left operand is the pointer this and the right one is the matrix object, named b.

Two matrices subtraction is done by a function named subtracting (n1,m1,x,n2,m2,y,*n3,*m3,z), from the library matrix.h. It has the following parameters:

int n1,m1- entry parameters representing the matrix x dimensions, which are the lines and the columns numbers;

int n2,m2- entry parameters representing the matrix y dimensions, which are the lines and the columns numbers;

int x[30][30],y[30][30]- entry parameters representing the two matrices that will be multiplied;

int z[30][30]- exit parameter representing the result of the two above matrices subtraction;

int n3,m3- exit parameters representing the lines number and the columns number of the result matrix z. These parameters transfer is made by their value.

This function’ body is:

error=1;
if((n1!=n2)|(m1!=m2)) error=0;
  	else
   {
	   for(i=0;i<n1;i++)
	          for(j=0;j<m1;j++)
    	               z[i][j]=x[i][j]-y[i][j];
	   }
if (error==0) printf("\n Subtraction is not possible!");
          else { 
               *n3=n1;
	    *m3=m2;
	 	}

The function contains a validation test. It verifies that the two matrices have their dimension equal. Otherwise the message Subtracting is not possible! is displayed.

Inside the class matrix the mathematical operation described above is realized by overloading the “-” operator.

  matrix matrix::operator -(matrix b)
{
matrix c(n,m);
 
if ((n==b.n)&&(m==b.m)){
		      for(i=0;i<n;i++)
			     for(j=0;j<m;j++)
				  c.a[i][j]=a[i][j]-b.a[i][j];
			}
return c;
}

This function parameter is an object of type matrix, named b. It represents the right operand of this mathematical operation. The left operand is represented by the pointer this. As in the function from the library, the validation test is also done here.

The operation of transposing a matrix is done in two ways:

  • by the function transpose( n, m, x, *n1, *m1, y) from the library matrix.h
  • by overloading the operator “!” inside the matrix class.

The function void transpose(int n,int m,int x[30][30],int *n1,int *m1,int y[30][30]) transpose a matrix being obtained in this way a new matrix. The parameters fo this function are:

  • int n,m- entry parameters representing the matrix x dimensions, which are the lines and the columns numbers;
  • int x[30][30] – entry parameter representing the matrix that will be transpose;
  • int *n1,*m1- exit parameters representing the lines number and the columns number of the result matrix y. These parameters transfer is made by their value.
  • int y[30][30]- exit parameter representing the resulted matrix;

This function code sequence is:

for(i=0;i<n;i++)
                        for(j=0;j<m;j++)
	   			y[j][i]=x[i][j];
*n1=m;
*m1=n;

The second way of transposing a matrix is by using the overloaded operator “!” from the class matrix.

matrix matrix::operator!()
{
matrix b(n,m);
int i,j;
for(i=0;i<n;i++)
                         for(j=0;j<m;j++)  b.a[j][i]=a[i][j];
return b;
}

Overloaded function returns a type matrix object named b, which is a new matrix obtained by transposing the initial one. The function gets the address of an object represented by the pointer this. The new matrix memory is allocated during the call of the class constructor matrix b(n,m).

The power function for a matrix is the next described mathematical operation. For getting the right result besides the power function two more additional functions are needed: the function that copies a matrix into another and the function that multiplies two matrices. The last one has already been presented in this chapter so it is only reminded.

The function from the library matrix.h, which copies a matrix into another one, is void copy(int n,int m, int x[30][30], int *n1,int *m1, int y[30][30]). Its parameters are:

  • int n,m- entry parameters representing the matrix x dimensions, which are the lines and the columns numbers;
  • int x[30][30] – entry parameter representing the matrix that will be copied into the matrix Y;
  • int *n1,*m1- exit parameters representing the lines number and the columns number of the result matrix y. These parameters transfer is made by their value.
  • int y[30][30]- exit parameter representing the resulted matrix;

The function is:

void copy(int n,int m, int x[30][30], int *n1,int *m1, int y[30][30])
{
int i,j;
 
for (i=0;i<n;i++)
   for (j=0;j<m;j++) y[i][j]=x[i][j];
 
*n1=n;
*m1=m;
}

Using the class matrix, the copying operation is realized by overloading the operator “=”. Its code sequence is:

matrix&  matrix ::operator =(matrix b)
{
 
for (i=0;i<b.n;i++)
   for (j=0;j<b.m;j++) a[i][j]=b.a[i][j];
 
n=b.n;
m=b.m;
 
return *this;
}

The function returns a matrix object, by using its address (in the above example it is used the pointer this). The entry parameter is represented by the object b, and the exit parameter by the pointer this.

The power function from the library matrix.h is void power(int n,int m,int x[30][30],int power,int *n2,int *m2, int y[30][30]).

This function’ parameters are:

  • int n, int m- entry parameters representing the matrix x dimensions, which are the lines and the columns numbers;
  • int x[30][30] – entry parameter representing the matrix that is powered;
  • int power – entry parameter representing the grade of this mathematical operation
  • int *n1,*m1- exit parameters representing the lines number and the columns number of the result matrix y. These parameters transfer is made by their value.
  • int y[30][30]- exit parameter representing the resulted matrix;

The algorithm of the function is:

copy(n,m,x,&n1,&m1,temp);
 
if((power!=0)&&(power!=1))
		    {
		    for (i=1;i<power;i++)
				     {
				      multiplying(n1,m1,temp,n,m,x,y,n2,m2);
				      copy(*n2,*m2,y,&n1,&m1,temp);
					 }
		    }
      else  if (power==0)
                           {
			  *n2=n;
			  *m2=m;
			  creating_unit_1(*n2,*m2,y);
			    }
		     else copy(n,m,x,n2,m2,y);

If it is calculated the power 0 of a matrix, the result is the unit matrix. And if it is calculated the power 1 of the matrix X, the result is exactly the matrix X.

In the class matrix the power of a matrix is done by the function void matrix::power(int p, matrix b). The matrix, used to calculate its power, is represented by the pointer this. Another entry parameter for this function is the variable int p, which is representing the power. The exit parameter is the class matrix object named b and it is the resulted matrix.

The function is:

void matrix::power(int p, matrix b)
{
matrix temp(n,m);
 
temp=*this;
 
if((p!=0)&&(p!=1))
		    {
		     for (i=1;i<p;i++)
				     {
				     b=temp*(*this);
				     temp=b;
					}
		     }
	else if (p==0) b.creating_unit();
		     else b=*this;
}

The function from the library matrix.h, named void e(int n,int m,float x[30][30],int p,int *line,int *column,float e[30][30]) calculates the power XP
of the mathematical constant e. This is done, using the formula:

Formula ridicare la putere matrice

Formula ridicare la putere matrice

, where E represents the unit matrix.

The parameters of this function are:

  • int n, int m- entry parameters representing the matrix x dimensions, which are the lines and the columns numbers;
  • float x[30][30] – entry parameter representing the matrix from the power of e;
  • int p – entry parameter representing the grade of the matrix X power;
  • int *line,*column- exit parameters representing the lines number and the columns number of the result matrix y. These parameters transfer is made by their value.
  • float e[30][30]- exit parameter representing the resulted matrix;

This function algorithm is:

multiplying_no_matrix_float(n,m,x,1/fact(1),&n1,&m1,y);
for (i=2;i<=p;i++)
		      {
		      power_float(n,m,x,i,&n2,&m2,z);
		      multiplying_no_matrix_float(n2,m2,z,1/fact(i),&n3,&m3,temp);
		      adding_float(n1,m1,y,n3,m3,temp,&n4,&m4,temp1);
		      copy_float(n4,m4,temp1,&n1,&m1,y);
		       }
 
creating_unit_1_float(n,m,unit);
adding_float(n,m,unit,n1,m1,y,line,column,e);

As it can be seen the function multiplying_no_matrix_float is called. It is doing the multiplication of a matrix with a number. Because the multiplication operation of a matrix with the number 1/(i!) is present, it is necessary that the resulted matrix to have elements of type float. The functions power_float, adding_float and copy_float are described at the end of this chapter. Their particularity is that they use matrices with components of type float. The function creating_unit_1_float is present in the second chapter.

The function from the class matrix is:

void matrix::e(int p,matrix &er)
{
matrix b(n,m),c(n,m),temp(n,m),temp1(n,m),unit(n,m);
int l;
 
multiplying_no_matrix(1/fact(1),temp);
     for (l=2;l<=p;l++)
		      {
		      power(l,b);
		      b.multiplying_no_matrix(1/fact(l),c);
		      temp1=temp+c;
		      temp=temp1;
		       }
 
unit.creating_unit();
er=unit+temp;
}

This function gets the following parameters: the pointer this representing the matrixi object and the variable p representing the power. Matrix &e is the exit parameter and is representing the resulted matrix.

A wide range of use has also the operation of transforming a matrix into an one-dimensional array, into a vector. This has been materialized by creating in the library matrix.h the function void matrix_line(int n,int m, int a[30][30],int x[],int *k).

This function gets a matrix with n lines and m columns and transforms it into a vector with n*m+2 components. The matrix is read following its lines, so putting those lines one after one creates the vector. As it can be seen the vector has two more elements than the initial matrix. That is, because the last two elements of the array are the matrix dimensions and they are needed for the opposite operation (from an one-dimensional array to a matrix) or for the operations of addition, subtraction, transposing and multiplication in which the operands are vectored matrices.

The function has the parameters:

  • int n,m- entry parameters representing the matrix a dimensions, which are the lines and the columns numbers;
  • int a[30][30] – entry parameter representing the matrix that will be transformed into a one-dimensional array;
  • int x[]- exit parameter representing the new created array
  • int *k-exit parameter representing the dimension of the vector x

Its sequence is:

void matrix_line(int a[30][30], int n, int m, int x[], int *k)
{
int i,j;
(*k)=0;
for (i=0;i<n;i++)
     			for(j=0;j<m;j++)
	  			 {
	    			 x[*k]=a[i][j];
	    			 (*k)++;
	     			}
x[*k]=n;
(*k)++;
x[*k]=m;
(*k)=(n*m)+2;
                }

The class matrix member function that is doing the same thing is int*
matrix_line(int &k). This function type is int*, so it returns the start address of an array. Different than the library function is the fact that both the matrix and the vector are declared dynamic. That’s why inside the function is allocated memory for the new created array.

The function is:

int*matrix:: matrix_line( int *k)
{
int i,j,*x;
x=aloc_vec(n,m);
(*k)=0;
for (i=0;i<n;i++)
     			for(j=0;j<m;j++)
	  			 {
	    			 x[*k]=a[i][j];
	    			 (*k)++;
	     			}
x[*k]=n;
(*k)++;
x[*k]=m;
(*k)=(n*m)+2;
            	 return x;   
 }

For a better understanding of the algorithm, we take a matrix and we transform it into an one-dimensional array.

The matrix used in this example has 3 lines and 3 columns and it is:

1 2 3

4 5 6

7 8 9

After calling the function matrix_line from the library matrix.h or from the class matrix a the following array is obtained:

1 2 3 4 5 6 7 8 9 3 3

As it can be seen the array has 3*3+2 components. Two elements are different from the matrix ones and they are memorized on the last two positions. They represent the initial matrix dimensions.

Two linear matrices sum is also created in two ways:

  • using linear matrices defined static
  • using linear matrices defined dynamic

The first method is implemented by the a library matrix.h member function, named void add_line_matr(int x[],int l1,int y[],int l2,int z[],int *k).

It has the next parameters:

  • int x[],y[]- entry parameters representing the two linear matrices to be add;
  • int l1,l2- entry parameters representing the dimensions of the linear matrices; l1 for the first one and l2 for the second one;
  • int z[]- exit parameter representing the resulted array, obtained by adding the two linear matrices;
  • int *k- exit parameter representing the array z components number.

This function structure is:

void add_line_matr(int x[],int l1,int y[],int l2,int z[],int *k)
{
int i,j;
*k=0;
if ((x[l1-2]==y[l2-2])&&(x[l1-1]==y[l2-1]))
 {
					 for(i=0;i<l1-2;i++) z[i]=x[i]+y[i];
					 z[i]=x[l1-2];
					 i++;
					 z[i]=x[l1-1];
					*k=l1;
					    }
}

The function, member of the class matrix, which is adding two linear matrices, is row_matrix_elem_sum. Its heading is int* row_matrix_elem_sum( matrix ,int *,int *,int *). Being of type int* it returns the starting address of an array. Because it implements the second method, the dynamic one, both the array and the matrix are declared dynamic and the function allocates memory for that new created array.

This function’ parameters are:

  • Entry parameters – this, matrix b, int *x, int *y; representing the initial matrices and the arrays in which they have been transformed;
  • Exit parameter – int *k; representing the new array dimension.

The function is:

int * matrix::row_matrix_elem_sum( matrix b,int *x,int *y,int *k)
{
int *z;
z=aloc_vec(n,m);
*k=0;
if ((n==b.n)&&(m==b.m))
 {
			for(i=0;i<n*m;i++) z[i]=x[i]+y[i];
					     z[i]=n;
					     i++;
					     z[i]=m;
					     *k=(n*m+2);
					    }
return z;
   }

Here it is an example:

The initial matrices are: A= 2     12

3    1

B= 56    4

43    5

The linear matrices obtained by transforming the first ones are:

X=2 12 3 1 2 2

Y= 56 4 43 5 2 2

Using the function described above for these matrices, add_line_matr(x,6,y,6,z,&k) a new linear matrix is created: Z=58 16 46 6 2 2

The mathematical operation of subtracting a linear matrix from another one is done by the functions: void substr_line_matr (int x[],int l1,int y[],int l2,int z[],int k) from matrix.h, and int*matrix::row_matrix_elem_substr( matrix b,int *x,int *y,int *k) from the class matrix. The conditions are the same as the addition ones. The functions’ code sequences are described in the project’ annex.

Two static defined matrices multiplication is realized by the function void multiply_line_matr(int x[],int l1,int y[],int l2,int z[],int *k). The function gets the following parameters:

  • int x[],y[]- entry parameters representing the two linear matrices to be multiplied;
  • int l1,l2- entry parameters representing the dimension of the linear matrix x and of the matrix y ;
  • int z[]- exit parameter representing the resulted array;
  • int *k- exit parameter representing the number of components of the array z.

The code sequence of the function previously described is:

void multiply_line_matr(int x[],int l1,int y[],int l2,int z[],int *k)
{
int q,r,i,j,lineA,columnA,lineB,columnB;
int *v,*w,l,vb,vb1,matrix[30][30];
 
lineA=x[l1-2];
columnA=x[l1-1];
 
lineB=y[l2-2];
columnB=y[l2-1];
 
if ((columnA==lineB))
	{
	line_matrix(y,l2,matrix,&q,&r);
	matrix_line_top(q,r,matrix,v,&l);
	vb=0;*k=0;
 
	while(vb*columnA!=(columnA*lineA))
		{
		j=0;
		for (i=(vb*columnA);i<((vb+1)*columnA);i++) {w[j]=x[i];j++;}
		vb1=0;
		while ((vb1*lineB)!=(lineB*columnB))
			{
			j=0;z[*k]=0;
			for(i=(vb1*lineB);i<((vb1+1)*lineB);i++)
				{
				z[*k]+=w[j]*v[i];
				j++;
				}
			vb1++;
			(*k)++;
			}
		vb++;
		}
	z[*k]=lineA;
	(*k)++;
	z[*k]=columnB;
	*k=columnB*lineA+2;
	}
    else *k=0;
}

It is necessary to transform the array y into a matrix. This is done by the function:

void line_matrix(int x[],int l,int a[30][30],int *n,int *m)
{
int i,j,p;
 
(*n)=x[l-2];
(*m)=x[l-1];
 
p=0;
for(i=0;i<*n;i++)
    			for(j=0;j<*m;j++) {
		  				 a[i][j]=x[p];
		    				 p++;
		  				   }
}

After that transformation, realized by the function line_matrix(y,l2,matrix,&q,&r), the resulted matrix is changed back into an array, but in a special way. Using the function void matrix_line_top(int a[30][30],int n,int m,int x[],int *k) the new obtained array is in fact the transpose of the first linear matrix. All these supplementary operations are helping in multiplying two linear matrices.

Using the two variables vb and vb1 to count the matrix components, the algorithm is very simple. In this way the risk of multiplying the last two elements of each array is eliminated.

Also, with the help of these variables, the lines and the columns of the matrices changed into the one-dimensional arrays x and y, are distinguished from the great number of elements. This is necessary for getting a good result.

Inside the function, the variables lineA, and columnA are used to memorize the lines number and the columns number of linear matrix x. In the same way are used also the variables lineB and columnB.

The multiplication of two define dynamic linear matrices is done by the class function int * row_matrix_elem_multpl(matrix b,int *x,int *y,int k). For not to use many variables, this function has as parameters the two matrices (defined by the pointer this and by the object matrix b) and the two linear matrices (defined by int*x and int*y). The algorithm is same as the function multiply_line_matr one, but the objects are declared dynamic.

The class function is:

int * matrix::row_matrix_elem_multpl(matrix b,int *x,int *y,int *k)
{
int vb,vb1,**matrix,*v,*w,*z;
 
z=aloc_vec(m,b.n);
if ((m==b.n))
		{
		matrix=b.row_to_matrix(y);
		v=b.row_matrix2(matrix);
		vb=0;*k=0;
 
		while(vb*m!=(n*m))
		     {
		     j=0;
		     w=(int *)malloc(m*sizeof(int));
		     for (i=(vb*m);i<((vb+1)*m);i++)
		     			{
					w[j]=x[i];j++;
					}
		     vb1=0;
		     while ((vb1*b.n)!=(b.n*b.m))
		     	{
			j=0;z[*k]=0;
			for(i=(vb1*b.n);i<((vb1+1)*b.n);i++)
					{
					z[*k]+=w[j]*v[i];
					j++;
					}
			vb1++;
			(*k)++;
			}
		     vb++;
		      }
		z[*k]=n;
		(*k)++;
		z[*k]=b.m;
		*k=b.m*n+2;
		}
	   else *k=0;
return z;
}

The function that transposes a linear matrix is used by the previous described function. This makes the algorithm easier. Its code sequence is the following:

void transpose_line_matrix(int x[],int k,int z[],int *l1)
{
int *v,a[30][30],q,r,l,i;
 
line_matrix(x,k,a,&q,&r);
matrix_line(a,q,r,v,&l);
 
for (i=0;i<l-2;i++) z[i]=v[i];
 
z[i]=r;
i++;
z[i]=q;
(*l1)=q*r+2;
}

The equivalent function from the class matrix is of type int*. It returns the starting address of the new array. Its parameters are the linear matrix and the number of elements of the array. The function is:

int * matrix::row_matrix_elem_transpose(int *x,int  *k)
{
int **matrix,*v,*z;
 
z=aloc_vec(m,n);
*k=0;
matrix=row_to_matrix(x);
v=row_matrix2(matrix);
 
for (i=0;i<n*m;i++) z[i]=v[i];
 
z[i]=m;
i++;
z[i]=n;
(*k)=n*m+2;
return z;
}

Because some of the variables are declared dynamic, a function is needed to allocate memory for the resulted array. This function belongs to the class matrix and it has a private access inside the class. Its code sequence is:

int* matrix::aloc_vec(int n,int m)
{
int *pvec;
 
pvec=(int *)malloc((n*m+2)*sizeof(int));
 
return pvec;
}

It allocates memory for an array with n*m+2 elements.

Other posts on this topic:

,


  1. No comments yet.
(will not be published)

  1. No trackbacks yet.