You are on page 1of 8

# Matrix operation and solving linear equations

"""
Some codes were modified from
https://techgoggler.com/computer-engineering/linear-equations-python-gauss-
elimination-method/
https://integratedmlai.com/basic-linear-algebra-tools-in-pure-python-without-
numpy-or-scipy/
"""
import math
import numpy as np

print('Calculate the rank of a matrix:')


#A=[[1.0,2.0,1.0],[-2.0,-3.0,1.0],[3.0,5.0,0.0]]
A=np.array([[1.0,2.0,1.0],[-2.0,-3.0,1.0],[3.0,5.0,0.0]])
A=np.array([[1,2,3],[4,5,6],[7,8,9]])
print('With numpy function linalg.matrix_rank, rank of matrix \n',A,'=\
n',np.linalg.matrix_rank(A))

def MatUpper(a):
n = len(a) # or, a.shape[0] #number of rows
# len(a[0]) is the number of columns
# Elimination phase
for k in range(0,n-1):
for i in range(k+1,n):
if a[i,k] != 0.0: #abs(a[i,k])>1.0e-12: #
#if not null define λ
lam = a[i,k]/a[k,k]
#we calculate the new row of the matrix
a[i,k+1:n] = a[i,k+1:n] - lam*a[k,k+1:n]
#a[i,k:n] = a[i,k:n] - lam*a[k,k:n]
#no need to start from k, because we know it is 0.
a[i,k] = 0.0 #Thus, the matrix becomes upper-triangular
return a

uA=MatUpper(A)
print('Upper triangular form of the matrix is\n',uA)

n_notzero=0 #number of rows with at least one nonzero element


for i in range(len(uA)):
if sum(abs(uA[i]))>0:
n_notzero += 1

print('We can also count the number of rows with at least one nonzero element
to get the rank of the matrix\n',n_notzero)

def MatEucNorm(a):
n=a.shape[0]
m=a.shape[1]
f=0
for i in range(0,n):
for j in range(0,m):
f=f+ (a[j][i])**2
return np.sqrt(f)#Mat

#B=np.array([[5,-4,2],[-1,2,3],[-2,1,0]])
B=np.array([[2,1],[2,1.001]])
Bo=B.copy()
print('Euclidean norm of matrix\n',Bo,'\n=',MatEucNorm(B))
print('Use numpy function linalg.norm, Euclidean norm of matrix\n',Bo,'\
n=',np.linalg.norm(Bo))

def MatDet(a): #determinant of a matrix


n = a.shape[0] #number of rowss
# Elimination phase
for k in range(0,n-1):
for i in range(k+1,n):
if a[i,k] != 0.0:
#if not null define λ
lam = a[i,k]/a[k,k]
#we calculate the new row of the matrix
a[i,k+1:n] = a[i,k+1:n] - lam*a[k,k+1:n]
#a[i,k:n] = a[i,k:n] - lam*a[k,k:n]
a[i,k] = 0.0 #Thus, the matrix becomes upper-triangular
det=1
for j in range(0,n):
det=det*a[j,j]
return det

print('Determinant of matrix\n',Bo,'\n=',MatDet(B))

def MatAdjoint(a):
n=a.shape[0]
m=a.shape[1]
Mat=np.zeros((n,m))
for i in range(0,n):
for j in range(0,m):
MatA=np.delete(a,i,axis=0)
MatB=np.delete(MatA,j,axis=1)
Mat[j,i]=MatDet(MatB)*(-1)**(i+j)#remember to transpose
return Mat

def gaussElim(a,b):
n = len(b)
# Elimination phase
for k in range(0,n-1):
for i in range(k+1,n):
if a[i,k] != 0.0:
#if not null define λ
lam = a[i,k]/a[k,k]
#we calculate the new row of the matrix
a[i,k+1:n] = a[i,k+1:n] - lam*a[k,k+1:n]
#we update vector b
b[i] = b[i] - lam*b[k]
# backward substitution
for k in range(n-1,-1,-1):
b[k] = (b[k] - np.dot(a[k,k+1:n],b[k+1:n]))/a[k,k]

return b
def LUdecomp(a):
n = len(a)
for k in range(0,n-1):
for i in range(k+1,n):
if a[i,k] != 0.0:
lam = a [i,k]/a[k,k]
a[i,k+1:n] = a[i,k+1:n] - lam*a[k,k+1:n]
a[i,k] = lam
return a
def LUsolve(a,b):
n = len(a)
for k in range(1,n):
b[k] = b[k] - np.dot(a[k,0:k],b[0:k])
b[n-1] = b[n-1]/a[n-1,n-1]
for k in range(n-2,-1,-1):
b[k] = (b[k] - np.dot(a[k,k+1:n],b[k+1:n]))/a[k,k]
return b

def myinvMat(a):#the code is modified from https://codepal.ai/code-


generator/query/yrUV5L09/python-gauss-jordan
# Use Gauss-Jordan elimination to invert a matrix
https://www.mathsisfun.com/algebra/matrix-inverse-row-operations-gauss-
jordan.html
m = len(a)
n = len(a[0])
b = np.identity(n) #identity matrix
for i in range(m):
# Finding the pivot element
pivot = a[i][i]
if pivot == 0:
print('The calculation cannot be done (dividing by zero).')
else:
# Dividing the current row by the pivot element
for j in range(n):
a[i][j] /= pivot
b[i][j] /= pivot
# Subtracting multiples of the current row from other rows to
eliminate the elements below and above the pivot
for k in range(m):
if k != i:
factor = a[k][i]
for j in range(n):
a[k][j] -= factor*a[i][j]
b[k][j] -= factor*b[i][j]
#At the end, a becomes an identity matrix.
return b # b is the inverted original a

print('Condition number of the matrix for a linear system.')


A = np.array([[2, 1], [2, 1.001]])
print('Condition number of matrix',A,'obtained by numpy function
linalg.cond():',np.linalg.cond(A))
print('By definition, the condition number is
norm(A)*norm(inv(A)):',np.linalg.norm(A)*np.linalg.norm(np.linalg.inv(A)))
print('By definition and with my functions, the condition number is
norm(A)*norm(inv(A)):',MatEucNorm(A)*MatEucNorm(myinvMat(A)))

#initial coefficients
# a=np.array([[1.0,4.0,1.0],[1.0,6.0,-1.0],[2.0,-1.0,2.0]])
# b=np.array([7.0,13.0,5.0])
a=np.array([[3.0,1.0,-1.0],[1.0,-1.0,1.0],[2.0,1.0,1.0]])
b=np.array([1.0,-3.0,0.0])
# a=np.array([[1.0,1.0,1.0],[1.0,-1.0,-1.0],[1.0,-2.0,3.0]])
# b=np.array([1.0,1.0,-5.0])
# a=np.array([[4.0,-2.0,1.0],[-2.0,4.0,-2.0],[1.0,-2.0,4.0]])
# b=np.array([11.0,-16.0,17.0])
aOrig = a.copy() # save original matrix A
bOrig = b.copy() #save original vector b

print('Matrix A=\n',a)
#print('The determinant, using numpy function:\n',np.linalg.det(a))
print('Adjoint of the matrix:\n',MatAdjoint(a))
print('The determinant, using my function MatDet:\n',MatDet(a))
print('Matrix inversion, using numpy function:\n', np.linalg.inv(a))
print('Matrix inversion, using the definition adjoint/determinant:\
n',MatAdjoint(a)/MatDet(a))
print('Matrix inversion, using Gauss-Jordan:\n',myinvMat(a))
#print('Check whether inverse of matrix A times A becomes I matrix\
n:',np.dot(MatAdjoint(aOrig)/MatDet(aOrig), aOrig))

print('Transform to upper-triangular:\n',MatUpper(a))
a=aOrig.copy()
x = gaussElim(a,b)
print('Use Gauss elimination, x=',x)
print("\nCheck result: [a]{x} - b =\n",np.dot(aOrig,x) - bOrig)

a=aOrig.copy(); b=bOrig.copy()
a=LUdecomp(a); x=LUsolve(a,b) # Solution by LU decomposition

#print A transformed for check


print('The coef matrix after decomposition is\n',a)
print("Use LU decomposition, x=\n",x)
#det = np.prod(np.diagonal(a)) #determinant
#print("\ndet =",det)
#check result and numerical precision
print("\nCheck result: [a]{x} - b =\n",np.dot(aOrig,x) - bOrig)

print('\nSolve a system of linear equations using Gauss-Jordan method.')


def gauss_jordan(matrix):#modified from
https://codepal.ai/code-generator/query/yrUV5L09/python-gauss-jordan
"""
Solves a system of linear equations using the Gauss-Jordan elimination
method.
Parameters:
- matrix: list of lists
The matrix representing the system of linear equations.
Returns:
- list:
The solution to the system of linear equations.
Raises:
- ValueError:
Raises an error if the matrix is not square or if it is not in the
correct format.
"""
# Checking if the matrix is square
rows = len(matrix)
cols = len(matrix[0])
# if rows != cols:
# raise ValueError("Matrix must be square.")

# # Checking if the matrix is in the correct format


# for row in matrix:
# if len(row) != cols:
# raise ValueError("Matrix must be in the correct format.")

# Applying Gauss-Jordan elimination


for i in range(rows):
# Finding the pivot element
pivot = matrix[i][i]

# Dividing the current row by the pivot element


for j in range(cols):
matrix[i][j] /= pivot

# Subtracting multiples of the current row from other rows to


eliminate the elements below and above the pivot
for k in range(rows):
if k != i:
factor = matrix[k][i]
for j in range(cols):
matrix[k][j] -= factor * matrix[i][j]

# Extracting the solution from the matrix


solution = []
for row in matrix:
solution.append(row[-1])

return solution,matrix

matrix = [[2, 1, -1, 8],


[-3, -1, 2, -11],
[-2, 1, 2, -3]]
solution,matnew = gauss_jordan(matrix)
print('To use the function gauss_jordan, the right-hand-side (b) column is
included in the input matrix.')
print("Solution:", solution,'new matrix:',matnew)

# Gauss-Seidel iteration method


# modified from https://www.geeksforgeeks.org/gauss-seidel-method/

# # int(input())input as number of variable to be solved


# n = 3
# a = []
# b = []
# initial solution depending on n(here n=3)

# x = np.array([0.2,1.1,0.8]) #[1, 2, 3]
# a = np.array([[4, 1, 2],[3, 5, 1],[1, 1, 3]]) # [[4, 1, 2],[3, 5, 1],[1, 1,
3]]
# b = np.array([4,7,3]) #[4,7,3]

# a=[[4.0,-2.0,1.0],[-2.0,4.0,-2.0],[1.0,-2.0,4.0]]
# b=[11.0,-16.0,17.0]
# x=[0.5, 0.5, 0.5]
#a=[[2.0,1.0,1.0],[3.0,5.0,2.0],[2.0,1.0,4.0]] #np.array([[1.0,-1.0,1.0],
[3.0,1.0,-1.0],[2.0,1.0,1.0]])
#b=[5.0,15.0,8.0]#np.array([-3.0,1.0,0.0])
x=[-0.60,1.50,-0.50]#[-0.5, 0.5, -0.5]

a=np.array([[2.0,1.0,1.0],[3.0,5.0,2.0],[2.0,1.0,4.0]])
b=np.array([5.0,15.0,8.0])
"""
#this problem can be solved only by relaxation
a=np.array([[3.0,1.0,-1.0],[1.0,-1.0,1.0],[2.0,1.0,1.0]])
b=np.array([1.0,-3.0,0.0])
"""
aOrig = a.copy() # save original matrix A
bOrig = b.copy() #save original vector b
x = gaussElim(a,b)
print('Use Gauss elimination, x=',x)

a=aOrig; b=bOrig;
x=[-0.60,1.50,-0.50]#[-0.5, 0.5, -0.5]
xi=x[:]
print('Use the initial guess for Gauss-Seidel method:',x)
def mySeidel(a,b,x,tol=[],itermax=[]):
if tol==[]:
tol=1.0e-6
if itermax==[]:
itermax=1000 #maximum number of iteration
xo=x[:] #the original one
n = len(b)
xdif=np.ones(n)#x[:] #temp values
k=0
while np.sqrt(np.dot(xdif,xdif))>tol:
if k>itermax:
print('Maximum number of iteration exceeded!')
break
else:
xo=x[:] #the original one
for j in range(0, n):
# temp variable d to store b[j]
d = b[j]
# to calculate respective xi, yi, zi
for i in range(0, n):
if(j != i):
d-=a[j][i] * x[i]
# updating the value of our solution
x[j] = d/a[j][j]
xdif[j] = x[j]-xo[j]
k=k+1
return x,k

def mySeidelW(a,b,x,tol=[],w=[],itermax=[]): #with relaxation coef


if w==[]:
w=0.75
if tol==[]:
tol=1.0e-6
if itermax==[]:
itermax=1000 #maximum number of iteration
xo=x[:] #the original one
n = len(b)
xdif=np.ones(n)#x[:] #temp values
k=0
while np.sqrt(np.dot(xdif,xdif))>tol:
if k>itermax:
print('Maximum number of iteration exceeded!')
break
else:
xo=x[:] #the original one
for j in range(0, n):
# temp variable d to store b[j]
d = b[j]

# to calculate respective xi, yi, zi


for i in range(0, n):
if(j != i):
d-=a[j][i] * x[i]
# updating the value of our solution
x[j] = w*d/a[j][j] + (1-w)*x[j]
xdif[j] = x[j]-xo[j]
k=k+1
return x,k

xsol,iterN=mySeidel(a,b,x)
print('Use mySeidel after',iterN,'iterations, x=',xsol)

print('xi=',xi)
xsol,iterN=mySeidelW(a,b,xi)
print('Use mySeidelW after',iterN,'iterations, x=',xsol)
"""
def seidel(a,b,x):
#Finding length of a(3)
n = len(a)
# for loop for 3 times as to calculate x, y , z
for j in range(0, n):
# temp variable d to store b[j]
d = b[j]
# to calculate respective xi, yi, zi
for i in range(0, n):
if(j != i):
d-=a[j][i] * x[i]
# updating the value of our solution
x[j] = d/a[j][j]
# returning our updated solution
return x

xdif =xdif2= x[:]

for i in range(0, 20):


#print('i=',i)
xold=x[:]
#print('xold=',xold)
x = seidel(a, b, x)
xnew=x[:]
#print('xold=',xold)
#print('xnew=',xnew)
#print each time the updated solution
for j in range(0,len(x)):
#print('j=',j)
xdif[j]=xnew[j]-xold[j]
# xdif2[j]=xdif[j]*xdif[j]
#print('xdif=',xdif)
# if sum(xdif2)<(0.0001)**2:
# break
if math.sqrt(np.dot(xdif,xdif))<0.0000001:
break
# print(x)
"""

You might also like