Computing determinant of matrix recursively - python

I'm trying to compute the determinant of matrix using recursive function.
I got a Matrix class that have getitem, setitem,... The .eliminated(i,j) method will return a new matrix that is removed row i, column j.
Here is the Matrix class, I also created Array, Array_2D class before and they are all fine:
class Matrix:
def __init__(self, numRows, numCols):
self.grid = Array_2D(numRows,numCols)
self.grid.clear(0)
def __getitem__(self, tuple):
return self.grid[tuple[0],tuple[1]]
def numRows(self):
return self.grid.numRows()
def numCols(self):
return self.grid.numCols()
def __add__(self, other):
assert other.numRows() == self.numRows() and\
other.numCols == self.numCols() , "Matrix sizes not compatible"
newMatrix = Matrix(self.numRows(),self.numCols())
for r in range(self.numRows()):
for c in range(self.numCols()):
newMatrix[r,c]=self[r,c]+other[r,c]
return newMatrix
def __setitem__(self, tuple, value):
self.grid[tuple[0],tuple[1]]=value
def scaleBy(self,scalar):
for r in range(self.numRows()):
for c in range(self.numCols()):
self[r,c]=self[r,c]*scalar
def tranpose(self):
newMatrix = Matrix(self.numCols(),self.numRows())
for r in range(newMatrix.numRows()):
for c in range(newMatrix.numCols()):
newMatrix[r,c]=self[c,r]
return newMatrix
def __sub__(self, other):
assert other.numRows() == self.numRows() and \
other.numCols == self.numCols(), "Matrix sizes not compatible"
newMatrix = Matrix(self.numRows(), self.numCols())
for r in range(self.numRows()):
for c in range(self.numCols()):
newMatrix[r, c] = self[r, c] - other[r, c]
return newMatrix
def __mul__(self, other):
assert other.numRows() == self.numCols(), "Matrix sizes not compatible"
newMatrix = Matrix(self.numRows(),other.numCols())
for r in range(newMatrix.numRows()):
for c in range(newMatrix.numCols()):
newMatrix[r,c] = 0
for i in range(self.numCols()):
newMatrix[r,c]+=self[r,i]*other[i,c]
return newMatrix
def determinant(self):
assert self.numCols()==self.numRows(), "Must be a square matrix"
assert self.numCols() > 0
if self.numCols() == 1:
return self[0,0]
if self.numCols() == 2:
return self[0,0]*self[1,1]-self[0,1]*self[1,0]
det = 0
if self.numCols() >=2:
for c in range(self.numCols()):
det+=((-1) ** c) * self[0, c] * self.eliminated(0, c).determinant()
return det
def eliminated(self,row,col):
assert row >=0 and row < self.numRows(), "Invalid row"
assert col >=0 and col < self.numCols(), "Invalid column"
assert self.numCols() >1 and self.numRows()>1
entry_list = []
for r in range(self.numRows()):
for c in range(self.numCols()):
self[r, col] = None
self[row,c]=None
if self[r,c] != None:
entry_list.append(self[r,c])
new_matrix = Matrix(self.numRows()-1, self.numCols()-1)
for r in range(new_matrix.numRows()):
for c in range(new_matrix.numCols()):
new_matrix[r,c] = entry_list[c + r*new_matrix.numCols()]
return new_matrix
I kept getting this error for 3x3 Matrix, 2x2 and 1x1 are fine:
Traceback (most recent call last):
File "E:/DataStructures/matrix.py", line 100, in <module>
print(ma4.determinant())
File "E:/DataStructures/matrix.py", line 67, in determinant
det+=((-1) ** c) * self[0, c] * self.eliminated(0, c).determinant()
TypeError: unsupported operand type(s) for *: 'int' and 'NoneType'
I know that my recursive function keeps removing row and column until it gets to NoneType, but no idea how to fix it

Hello there check out this:
matrix=[]
def det(IC,i):
global matrix,row
determinent=0
m=1
for j in range(len(matrix)):
if j not in IC:
m+=1
if i == row-1:
determinent = matrix[i][j]
else:
determinent+=(-1)**(m)*matrix[i][j]*det(IC+[j],i+1)
return determinent
row=int(input("enter order:"))
for i in range(row):
rowEntry=[int(x) for x in input().split(' ')]
matrix.append(rowEntry)
print(matrix)
print(det([],0))
please give input carefully e.g:
enter order:3
2 3 4
1 2 3
3 4 5

Related

adding two matrices together (using methods, without using numpy)

how can i add a matrix using the implemented methods?
my problem is that I don't know very much how I can get an operation to add the matrix correctly.
for example, such an operation:
A = 1 2 3 1 2 1
4 5 6 + 0 1 0
7 8 9 3 2 1
I would like to use the methods from the Matrix class:
class Matrix:
def __init__(self, m, n, init=True):
if init:
self.rows = [[0] * n for x in range(m)]
else:
self.rows = []
self.m = m
self.n = n
def __getitem__(self, idx):
return self.rows[idx]
def __setitem__(self, idx, item):
self.rows[idx] = item
def __add__(self, mat):
ret = Matrix(self.m, self.n)
for x in range(self.m):
row = [sum(item) for item in zip(self.rows[x], mat[x])]
ret[x] = row
return ret
Updated to the below runs for me, even though there is room for improvement (checking matrix sizes,...)
def getitem(self, idx):
return self.rows[idx]
def setitem(self, idx, item):
self.rows[idx] = item
def add(self, mat):
ret = Matrix(self.m, self.n)
for x in range(self.m):
row = [sum(item) for item in zip(self.rows[x], mat.getitem(x))]
ret.setitem(x,row)
return ret
mat_a = Matrix(5,5)
mat_b = Matrix(5,5)
mat_b.setitem(slice(0,3),[[1,2,3,4,5],[4,5,6,7,8],[9,10,4,3,1]])
mat_c = mat_a.add(mat_b)
print(mat_c.getitem(slice(0,3)))

How to sum two matrix in a class

I'm trying to define some methods to a class Matrix that receives the number of rows and the number of columns, a list or a code as arguments.
I have to do:
import numpy as np
class Matrix:
def __init__(self, rows = 0, columns =0, data=None, code =''):
if data is None:
data = []
self.code = ''
self.rows = rows
self.columns = columns
self.data = data
self.code = code
self.matrix = [[]]
assert self.columns != 0 and self.rows != 0
if code == 'z':
self.matrix = np.zeros([self.rows, self.columns], int)
elif code == 'u':
self.matrix = np.ones([self.rows, self.columns], int)
elif code == 'i':
self.matrix = np.identity(self.rows, int)
else:
if code == '' and len(self.data) != 0:
self.matrix = np.reshape(self.data, (-1, self.columns))
def __str__(self):
return f'Matrix: {self.matrix}'
def get_matrix(self):
return self.matrix
def sumM(self,m1):
k = self.get_matrix()
m1.get_matrix()
print(k)
print(m1.get_matrix())
assert (self.rows == m1.rows)
m3 = np.zeros([self.rows, self.rows])
print(m3.shape)
for i in range(m3.shape[0]):
for j in range(m3.shape[1]):
output = m1[i, j] + k[i, j]
print(output)
return m3
Although, when I'm call the sumM method, python retrieves the error:
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "C:/Users/sandr/PycharmProjects/Trabalho 2/teste2.py", line 41, in sumM
output = m1[i, j] + k[i, j]
TypeError: 'Matrix' object is not subscriptable
What I'm doing wrong?
This should do it:
def sumM(self,m1):
k = self.get_matrix()
k1 = m1.get_matrix()
assert (self.rows == m1.rows)
m3 = np.zeros([self.rows, self.rows])
for i in range(m3.shape[0]):
for j in range(m3.shape[1]):
m3[i][j] = k1[i][j] + k[i][j]
return m3

Assigning variable = self creating a copy. Need it to be a reference (pointer)

I am working on creating a matrix class for an assignment I have and usually if I assign a variable as x = self, x is a reference to self and thus all operations are in place. I have a function that reduces the matrix, and as an optional parameter I've added inplace=False such that:
if inplace:
self = A
else:
A = self.copy()
Now normally when I do this, if I were to do an operation such as A += B, self would be modified. However, when I run A.reduce(inplace=True), A is not modified. I've included the full class below and am hoping that someone can tell my why the operations are not happening in place. Thanks in advance.
import numpy as np
class matrix:
def __init__(self, A):
self.value = np.array(A, dtype=np.float)
self.indices = np.arange(self.value.shape[0])
self.shape = self.value.shape
def swap_rows(self, r1, r2):
ind = np.arange(self.value.shape[0])
swap = (r1, r2)
ind[swap[0]] = swap[1]
ind[swap[1]] = swap[0]
temp_ind = self.indices[swap[0]]
self.indices[swap[0]] = self.indices[swap[1]]
self.indices[swap[1]] = temp_ind
self.value = self.value[ind]
def add_rows(self, operations):
# operations = [(c, row1, row2)]
# where operation will be:
# c * row1 + row2 -> row2
for c, row1, row2 in operations:
self.value[row2] += c * self.value[row1]
# ... #
def reduce(self, b_ = None, swap=True, normalize=True, return_steps=False, inplace=False, debug=False):
if inplace:
A = self
else:
A = self.copy()
if b_:
b = b_.copy()
if len(b.shape) == 1:
b.reshape((-1, 1), inplace=True)
if return_steps:
steps = []
# Normalize
if normalize:
A_max = A.row_max()
A /= A_max
if debug:
print("A after normalization:")
print(A)
print("")
if return_steps:
steps.append([('normalize', A_max)])
if b_:
b /= A_max
m, n = A.shape
for col in range(n-1):
# Swap
if swap:
# Check for max value
max_ind = np.argmax(np.abs(A[:, col]))
# Check if max is zero
if np.abs(A[max_ind, col]) < 1e-30:
print('Matrix is singular')
if b_:
return A, b
else:
return A
# Swap if necessary
if max_ind > col:
A.swap_rows(col, max_ind)
if return_steps:
steps.append([('swap', col, max_ind)])
if b_:
b.swap_rows(col, max_ind)
# Get constants
cs = -A[col+1:, col] / A[col, col]
operations = [(c, col, i+col+1) for i, c in enumerate(cs)]
if return_steps:
steps.append(operations)
A.add_rows(operations)
if b_:
b.add_rows(operations)
if debug:
print("A after row operations:")
print(A)
print("")
return_vals = np.array([A, None, None])
if b_:
return_vals[1] = b
if return_steps:
return_vals[2] = steps
if inplace:
return_vals = return_vals[1:]
if return_vals.any():
return tuple(return_vals[return_vals != None])
# ... #
def row_max(self):
return np.array([self[row, i] for row, i in enumerate(np.argmax(np.abs(self.value), axis=1))]).reshape(-1, 1)
# ... #
def copy(self):
return matrix(np.copy(self.value))
def T(self):
return matrix(self.value.T)
def inverse(self):
return matrix(np.linalg.inv(self.value))
def flip(self, axis=None, inplace=False):
if inplace:
self.value = np.flip(self.value, axis=axis)
else:
return matrix(np.flip(self.value, axis=axis))
def reshape(self, shape, inplace=False):
if inplace:
self.value = self.value.reshape(*shape)
else:
return matrix(self.value.reshape(*shape))
def __add__(self, x):
if isinstance(x, matrix):
return matrix(self.value + x.value)
else:
return matrix(self.value + x)
def __sub__(self, x):
if isinstance(x, matrix):
return matrix(self.value - x.value)
else:
return matrix(self.value - x)
def __mul__(self, x):
if isinstance(x, matrix):
return matrix(self.value * x.value)
else:
return matrix(self.value * x)
def __truediv__(self, x):
if isinstance(x, matrix):
return matrix(self.value / x.value)
else:
return matrix(self.value / x)
# ... #
def __matmul__(self, A):
if isinstance(A, matrix):
return matrix(self.value # A.value)
else:
return matrix(self.value # A)
def __repr__(self):
return str(self.value)
def __getitem__(self, item):
return self.value[item]
def __setitem__(self, i, v):
self.value[i] = v
A = matrix([ [ 5, 6, 7, 5, -1],
[ 8, -4, -1, 0, -3],
[ 2, 1, -1, 3, 6],
[-9, 10, 1, -4, 6],
[ 9, 5, -5, -8, 4] ])
print("Original A:")
print(A)
print("")
A.reduce(inplace=True, debug=True)
print("A after inplace reduce function:")
print(A)
print("")
EDIT
Here is what I am trying to recreate in a simplistic way:
class obj:
def __init__(self, value):
self.value = value
def copy(self):
return obj(self.value)
def op(self, y, inplace=False):
if inplace:
x = self
else:
x = self.copy()
x.value += y
x.value /= y
if not inplace:
return x
def __repr__(self):
return str(self.value)
x = obj(5)
x.op(3)
print("Copy:", x)
x.op(3, inplace=True)
print("Inplace:", x)
You say that operators like += modify objects in place, but that's not always true. It only happens if the type of the object on the left side of the operator has an __iadd__ method. If it only has an __add__ method, then the Python interpreter translates X += Y to X = X + Y which is generally not an in-place operation.
So the reason your code doesn't do what you expect is because you don't have an __itruediv__ operator, and when you call A /= A_max (if normalize is True), you make a copy, despite your intention to be operating in place.

AttributeError: 'tuple' object has no attribute 'times_scalar'

This is my Linear System code. The times_scalar function is defined in the Vector object. When executing the multiply_coefficient_and_row function, I get AttributeError: 'tuple' object has no attribute 'times_scalar'. I tried different things including converting the tuple into a list and back to a tuple but had no success.
from decimal import Decimal, getcontext
from copy import deepcopy
from Vector import Vector
from Plane import Plane
getcontext().prec = 30
class LinearSystem(object):
ALL_PLANES_MUST_BE_IN_SAME_DIM_MSG = 'All planes in the system should live in the same dimension'
NO_SOLUTIONS_MSG = 'No solutions'
INF_SOLUTIONS_MSG = 'Infinitely many solutions'
def __init__(self, planes):
try:
d = planes[0].dimension
for p in planes:
assert p.dimension == d
self.planes = planes
self.dimension = d
except AssertionError:
raise Exception(self.ALL_PLANES_MUST_BE_IN_SAME_DIM_MSG)
def swap_rows(self, row1, row2):
self[row1], self[row2] = self[row2], self[row1]
def multiply_coefficient_and_row(self, coefficient, row):
n = self[row].normal_vector.coordinates
k = self[row].constant_term
new_normal_vector = n.times_scalar(coefficient)
new_constant_term = k * coefficient
self[row] = Plane(normal_vector = new_normal_vector, constant_term = new_constant_term)
def add_multiple_times_row_to_row(self, coefficient, row_to_add, row_to_be_added_to):
n1 = self[row_to_add].normal_vector.coordinates
n2 = self[row_to_be_added_to].normal_vector.coordinates
k1 = self[row_to_add].constant_term
k2 = self[row_to_be_added_to].constant_term
new_normal_vector = n1.times_scalar(coefficient).plus(n2)
new_constant_term = (k1 * coefficient) + k2
self[row_to_be_added_to] = Plane(normal_vector = new_normal_vector, constant_term = new_constant_term)
def indices_of_first_nonzero_terms_in_each_row(self):
num_equations = len(self)
num_variables = self.dimension
indices = [-1] * num_equations
for i,p in enumerate(self.planes):
try:
indices[i] = p.first_nonzero_index(p.normal_vector.coordinates)
except Exception as e:
if str(e) == Plane.NO_NONZERO_ELTS_FOUND_MSG:
continue
else:
raise e
return indices
def __len__(self):
return len(self.planes)
def __getitem__(self, i):
return self.planes[i]
def __setitem__(self, i, x):
try:
assert x.dimension == self.dimension
self.planes[i] = x
except AssertionError:
raise Exception(self.ALL_PLANES_MUST_BE_IN_SAME_DIM_MSG)
def __str__(self):
ret = 'Linear System:\n'
temp = ['Equation {}: {}'.format(i+1,p) for i,p in enumerate(self.planes)]
ret += '\n'.join(temp)
return ret
class MyDecimal(Decimal):
def is_near_zero(self, eps=1e-10):
return abs(self) < eps
and from the Vector class this times_scalar function:
def times_scalar(self, c):
new_coordinates = [Decimal(c) * x for x in self.coordinates]
return Vector(new_coordinates)

Matrix Multiplication in pure Python?

I'm trying to multiply two matrices together using pure Python. Input (X1 is a 3x3 and Xt is a 3x2):
X1 = [[1.0016, 0.0, -16.0514],
[0.0, 10000.0, -40000.0],
[-16.0514, -40000.0, 160513.6437]]
Xt = [(1.0, 1.0),
(0.0, 0.25),
(0.0, 0.0625)]
where Xt is the zip transpose of another matrix. Now here is the code:
def matrixmult (A, B):
C = [[0 for row in range(len(A))] for col in range(len(B[0]))]
for i in range(len(A)):
for j in range(len(B[0])):
for k in range(len(B)):
C[i][j] += A[i][k]*B[k][j]
return C
The error that python gives me is this:
IndexError: list index out of range.
Now I'm not sure if Xt is recognised as an matrix and is still a list object, but technically this should work.
If you really don't want to use numpy you can do something like this:
def matmult(a,b):
zip_b = zip(*b)
# uncomment next line if python 3 :
# zip_b = list(zip_b)
return [[sum(ele_a*ele_b for ele_a, ele_b in zip(row_a, col_b))
for col_b in zip_b] for row_a in a]
x = [[1,2,3],[4,5,6],[7,8,9],[10,11,12]]
y = [[1,2],[1,2],[3,4]]
import numpy as np # I want to check my solution with numpy
mx = np.matrix(x)
my = np.matrix(y)
Result:
>>> matmult(x,y)
[[12, 18], [27, 42], [42, 66], [57, 90]]
>>> mx * my
matrix([[12, 18],
[27, 42],
[42, 66],
[57, 90]])
This is incorrect initialization. You interchanged row with col!
C = [[0 for row in range(len(A))] for col in range(len(B[0]))]
Correct initialization would be
C = [[0 for col in range(len(B[0]))] for row in range(len(A))]
Also I would suggest using better naming conventions. Will help you a lot in debugging. For example:
def matrixmult (A, B):
rows_A = len(A)
cols_A = len(A[0])
rows_B = len(B)
cols_B = len(B[0])
if cols_A != rows_B:
print "Cannot multiply the two matrices. Incorrect dimensions."
return
# Create the result matrix
# Dimensions would be rows_A x cols_B
C = [[0 for row in range(cols_B)] for col in range(rows_A)]
print C
for i in range(rows_A):
for j in range(cols_B):
for k in range(cols_A):
C[i][j] += A[i][k] * B[k][j]
return C
You can do a lot more, but you get the idea...
One liner:
def dot(m1, m2):
return [
[sum(x * y for x, y in zip(m1_r, m2_c)) for m2_c in zip(*m2)] for m1_r in m1
]
Explanation:
zip(*m2) - gets a column from the second matrix
zip(m1_r, m2_c) - creates tuple from m1 row and m2 column
sum(...) - sums multiplication row * col
Test:
m1 = [[1, 2, 3], [4, 5, 6]]
m2 = [[7, 8], [9, 10], [11, 12]]
result = dot(m1, m2)
assert result == [[58, 64], [139, 154]]
Here's some short and simple code for matrix/vector routines in pure Python that I wrote many years ago:
'''Basic Table, Matrix and Vector functions for Python 2.2
Author: Raymond Hettinger
'''
Version = 'File MATFUNC.PY, Ver 183, Date 12-Dec-2002,14:33:42'
import operator, math, random
NPRE, NPOST = 0, 0 # Disables pre and post condition checks
def iszero(z): return abs(z) < .000001
def getreal(z):
try:
return z.real
except AttributeError:
return z
def getimag(z):
try:
return z.imag
except AttributeError:
return 0
def getconj(z):
try:
return z.conjugate()
except AttributeError:
return z
separator = [ '', '\t', '\n', '\n----------\n', '\n===========\n' ]
class Table(list):
dim = 1
concat = list.__add__ # A substitute for the overridden __add__ method
def __getslice__( self, i, j ):
return self.__class__( list.__getslice__(self,i,j) )
def __init__( self, elems ):
list.__init__( self, elems )
if len(elems) and hasattr(elems[0], 'dim'): self.dim = elems[0].dim + 1
def __str__( self ):
return separator[self.dim].join( map(str, self) )
def map( self, op, rhs=None ):
'''Apply a unary operator to every element in the matrix or a binary operator to corresponding
elements in two arrays. If the dimensions are different, broadcast the smaller dimension over
the larger (i.e. match a scalar to every element in a vector or a vector to a matrix).'''
if rhs is None: # Unary case
return self.dim==1 and self.__class__( map(op, self) ) or self.__class__( [elem.map(op) for elem in self] )
elif not hasattr(rhs,'dim'): # List / Scalar op
return self.__class__( [op(e,rhs) for e in self] )
elif self.dim == rhs.dim: # Same level Vec / Vec or Matrix / Matrix
assert NPRE or len(self) == len(rhs), 'Table operation requires len sizes to agree'
return self.__class__( map(op, self, rhs) )
elif self.dim < rhs.dim: # Vec / Matrix
return self.__class__( [op(self,e) for e in rhs] )
return self.__class__( [op(e,rhs) for e in self] ) # Matrix / Vec
def __mul__( self, rhs ): return self.map( operator.mul, rhs )
def __div__( self, rhs ): return self.map( operator.div, rhs )
def __sub__( self, rhs ): return self.map( operator.sub, rhs )
def __add__( self, rhs ): return self.map( operator.add, rhs )
def __rmul__( self, lhs ): return self*lhs
def __rdiv__( self, lhs ): return self*(1.0/lhs)
def __rsub__( self, lhs ): return -(self-lhs)
def __radd__( self, lhs ): return self+lhs
def __abs__( self ): return self.map( abs )
def __neg__( self ): return self.map( operator.neg )
def conjugate( self ): return self.map( getconj )
def real( self ): return self.map( getreal )
def imag( self ): return self.map( getimag )
def flatten( self ):
if self.dim == 1: return self
return reduce( lambda cum, e: e.flatten().concat(cum), self, [] )
def prod( self ): return reduce(operator.mul, self.flatten(), 1.0)
def sum( self ): return reduce(operator.add, self.flatten(), 0.0)
def exists( self, predicate ):
for elem in self.flatten():
if predicate(elem):
return 1
return 0
def forall( self, predicate ):
for elem in self.flatten():
if not predicate(elem):
return 0
return 1
def __eq__( self, rhs ): return (self - rhs).forall( iszero )
class Vec(Table):
def dot( self, otherVec ): return reduce(operator.add, map(operator.mul, self, otherVec), 0.0)
def norm( self ): return math.sqrt(abs( self.dot(self.conjugate()) ))
def normalize( self ): return self / self.norm()
def outer( self, otherVec ): return Mat([otherVec*x for x in self])
def cross( self, otherVec ):
'Compute a Vector or Cross Product with another vector'
assert len(self) == len(otherVec) == 3, 'Cross product only defined for 3-D vectors'
u, v = self, otherVec
return Vec([ u[1]*v[2]-u[2]*v[1], u[2]*v[0]-u[0]*v[2], u[0]*v[1]-u[1]*v[0] ])
def house( self, index ):
'Compute a Householder vector which zeroes all but the index element after a reflection'
v = Vec( Table([0]*index).concat(self[index:]) ).normalize()
t = v[index]
sigma = 1.0 - t**2
if sigma != 0.0:
t = v[index] = t<=0 and t-1.0 or -sigma / (t + 1.0)
v /= t
return v, 2.0 * t**2 / (sigma + t**2)
def polyval( self, x ):
'Vec([6,3,4]).polyval(5) evaluates to 6*x**2 + 3*x + 4 at x=5'
return reduce( lambda cum,c: cum*x+c, self, 0.0 )
def ratval( self, x ):
'Vec([10,20,30,40,50]).ratfit(5) evaluates to (10*x**2 + 20*x + 30) / (40*x**2 + 50*x + 1) at x=5.'
degree = len(self) / 2
num, den = self[:degree+1], self[degree+1:] + [1]
return num.polyval(x) / den.polyval(x)
class Matrix(Table):
__slots__ = ['size', 'rows', 'cols']
def __init__( self, elems ):
'Form a matrix from a list of lists or a list of Vecs'
Table.__init__( self, hasattr(elems[0], 'dot') and elems or map(Vec,map(tuple,elems)) )
self.size = self.rows, self.cols = len(elems), len(elems[0])
def tr( self ):
'Tranpose elements so that Transposed[i][j] = Original[j][i]'
return Mat(zip(*self))
def star( self ):
'Return the Hermetian adjoint so that Star[i][j] = Original[j][i].conjugate()'
return self.tr().conjugate()
def diag( self ):
'Return a vector composed of elements on the matrix diagonal'
return Vec( [self[i][i] for i in range(min(self.size))] )
def trace( self ): return self.diag().sum()
def mmul( self, other ):
'Matrix multiply by another matrix or a column vector '
if other.dim==2: return Mat( map(self.mmul, other.tr()) ).tr()
assert NPRE or self.cols == len(other)
return Vec( map(other.dot, self) )
def augment( self, otherMat ):
'Make a new matrix with the two original matrices laid side by side'
assert self.rows == otherMat.rows, 'Size mismatch: %s * %s' % (`self.size`, `otherMat.size`)
return Mat( map(Table.concat, self, otherMat) )
def qr( self, ROnly=0 ):
'QR decomposition using Householder reflections: Q*R==self, Q.tr()*Q==I(n), R upper triangular'
R = self
m, n = R.size
for i in range(min(m,n)):
v, beta = R.tr()[i].house(i)
R -= v.outer( R.tr().mmul(v)*beta )
for i in range(1,min(n,m)): R[i][:i] = [0] * i
R = Mat(R[:n])
if ROnly: return R
Q = R.tr().solve(self.tr()).tr() # Rt Qt = At nn nm = nm
self.qr = lambda r=0, c=`self`: not r and c==`self` and (Q,R) or Matrix.qr(self,r) #Cache result
assert NPOST or m>=n and Q.size==(m,n) and isinstance(R,UpperTri) or m<n and Q.size==(m,m) and R.size==(m,n)
assert NPOST or Q.mmul(R)==self and Q.tr().mmul(Q)==eye(min(m,n))
return Q, R
def _solve( self, b ):
'''General matrices (incuding) are solved using the QR composition.
For inconsistent cases, returns the least squares solution'''
Q, R = self.qr()
return R.solve( Q.tr().mmul(b) )
def solve( self, b ):
'Divide matrix into a column vector or matrix and iterate to improve the solution'
if b.dim==2: return Mat( map(self.solve, b.tr()) ).tr()
assert NPRE or self.rows == len(b), 'Matrix row count %d must match vector length %d' % (self.rows, len(b))
x = self._solve( b )
diff = b - self.mmul(x)
maxdiff = diff.dot(diff)
for i in range(10):
xnew = x + self._solve( diff )
diffnew = b - self.mmul(xnew)
maxdiffnew = diffnew.dot(diffnew)
if maxdiffnew >= maxdiff: break
x, diff, maxdiff = xnew, diffnew, maxdiffnew
#print >> sys.stderr, i+1, maxdiff
assert NPOST or self.rows!=self.cols or self.mmul(x) == b
return x
def rank( self ): return Vec([ not row.forall(iszero) for row in self.qr(ROnly=1) ]).sum()
class Square(Matrix):
def lu( self ):
'Factor a square matrix into lower and upper triangular form such that L.mmul(U)==A'
n = self.rows
L, U = eye(n), Mat(self[:])
for i in range(n):
for j in range(i+1,U.rows):
assert U[i][i] != 0.0, 'LU requires non-zero elements on the diagonal'
L[j][i] = m = 1.0 * U[j][i] / U[i][i]
U[j] -= U[i] * m
assert NPOST or isinstance(L,LowerTri) and isinstance(U,UpperTri) and L*U==self
return L, U
def __pow__( self, exp ):
'Raise a square matrix to an integer power (i.e. A**3 is the same as A.mmul(A.mmul(A))'
assert NPRE or exp==int(exp) and exp>0, 'Matrix powers only defined for positive integers not %s' % exp
if exp == 1: return self
if exp&1: return self.mmul(self ** (exp-1))
sqrme = self ** (exp/2)
return sqrme.mmul(sqrme)
def det( self ): return self.qr( ROnly=1 ).det()
def inverse( self ): return self.solve( eye(self.rows) )
def hessenberg( self ):
'''Householder reduction to Hessenberg Form (zeroes below the diagonal)
while keeping the same eigenvalues as self.'''
for i in range(self.cols-2):
v, beta = self.tr()[i].house(i+1)
self -= v.outer( self.tr().mmul(v)*beta )
self -= self.mmul(v).outer(v*beta)
return self
def eigs( self ):
'Estimate principal eigenvalues using the QR with shifts method'
origTrace, origDet = self.trace(), self.det()
self = self.hessenberg()
eigvals = Vec([])
for i in range(self.rows-1,0,-1):
while not self[i][:i].forall(iszero):
shift = eye(i+1) * self[i][i]
q, r = (self - shift).qr()
self = r.mmul(q) + shift
eigvals.append( self[i][i] )
self = Mat( [self[r][:i] for r in range(i)] )
eigvals.append( self[0][0] )
assert NPOST or iszero( (abs(origDet) - abs(eigvals.prod())) / 1000.0 )
assert NPOST or iszero( origTrace - eigvals.sum() )
return Vec(eigvals)
class Triangular(Square):
def eigs( self ): return self.diag()
def det( self ): return self.diag().prod()
class UpperTri(Triangular):
def _solve( self, b ):
'Solve an upper triangular matrix using backward substitution'
x = Vec([])
for i in range(self.rows-1, -1, -1):
assert NPRE or self[i][i], 'Backsub requires non-zero elements on the diagonal'
x.insert(0, (b[i] - x.dot(self[i][i+1:])) / self[i][i] )
return x
class LowerTri(Triangular):
def _solve( self, b ):
'Solve a lower triangular matrix using forward substitution'
x = Vec([])
for i in range(self.rows):
assert NPRE or self[i][i], 'Forward sub requires non-zero elements on the diagonal'
x.append( (b[i] - x.dot(self[i][:i])) / self[i][i] )
return x
def Mat( elems ):
'Factory function to create a new matrix.'
m, n = len(elems), len(elems[0])
if m != n: return Matrix(elems)
if n <= 1: return Square(elems)
for i in range(1, len(elems)):
if not iszero( max(map(abs, elems[i][:i])) ):
break
else: return UpperTri(elems)
for i in range(0, len(elems)-1):
if not iszero( max(map(abs, elems[i][i+1:])) ):
return Square(elems)
return LowerTri(elems)
def funToVec( tgtfun, low=-1, high=1, steps=40, EqualSpacing=0 ):
'''Compute x,y points from evaluating a target function over an interval (low to high)
at evenly spaces points or with Chebyshev abscissa spacing (default) '''
if EqualSpacing:
h = (0.0+high-low)/steps
xvec = [low+h/2.0+h*i for i in range(steps)]
else:
scale, base = (0.0+high-low)/2.0, (0.0+high+low)/2.0
xvec = [base+scale*math.cos(((2*steps-1-2*i)*math.pi)/(2*steps)) for i in range(steps)]
yvec = map(tgtfun, xvec)
return Mat( [xvec, yvec] )
def funfit( (xvec, yvec), basisfuns ):
'Solves design matrix for approximating to basis functions'
return Mat([ map(form,xvec) for form in basisfuns ]).tr().solve(Vec(yvec))
def polyfit( (xvec, yvec), degree=2 ):
'Solves Vandermonde design matrix for approximating polynomial coefficients'
return Mat([ [x**n for n in range(degree,-1,-1)] for x in xvec ]).solve(Vec(yvec))
def ratfit( (xvec, yvec), degree=2 ):
'Solves design matrix for approximating rational polynomial coefficients (a*x**2 + b*x + c)/(d*x**2 + e*x + 1)'
return Mat([[x**n for n in range(degree,-1,-1)]+[-y*x**n for n in range(degree,0,-1)] for x,y in zip(xvec,yvec)]).solve(Vec(yvec))
def genmat(m, n, func):
if not n: n=m
return Mat([ [func(i,j) for i in range(n)] for j in range(m) ])
def zeroes(m=1, n=None):
'Zero matrix with side length m-by-m or m-by-n.'
return genmat(m,n, lambda i,j: 0)
def eye(m=1, n=None):
'Identity matrix with side length m-by-m or m-by-n'
return genmat(m,n, lambda i,j: i==j)
def hilb(m=1, n=None):
'Hilbert matrix with side length m-by-m or m-by-n. Elem[i][j]=1/(i+j+1)'
return genmat(m,n, lambda i,j: 1.0/(i+j+1.0))
def rand(m=1, n=None):
'Random matrix with side length m-by-m or m-by-n'
return genmat(m,n, lambda i,j: random.random())
if __name__ == '__main__':
import cmath
a = Table([1+2j,2,3,4])
b = Table([5,6,7,8])
C = Table([a,b])
print 'a+b', a+b
print '2+a', 2+a
print 'a/5.0', a/5.0
print '2*a+3*b', 2*a+3*b
print 'a+C', a+C
print '3+C', 3+C
print 'C+b', C+b
print 'C.sum()', C.sum()
print 'C.map(math.cos)', C.map(cmath.cos)
print 'C.conjugate()', C.conjugate()
print 'C.real()', C.real()
print zeroes(3)
print eye(4)
print hilb(3,5)
C = Mat( [[1,2,3], [4,5,1,], [7,8,9]] )
print C.mmul( C.tr()), '\n'
print C ** 5, '\n'
print C + C.tr(), '\n'
A = C.tr().augment( Mat([[10,11,13]]).tr() ).tr()
q, r = A.qr()
assert q.mmul(r) == A
assert q.tr().mmul(q)==eye(3)
print 'q:\n', q, '\nr:\n', r, '\nQ.tr()&Q:\n', q.tr().mmul(q), '\nQ*R\n', q.mmul(r), '\n'
b = Vec([50, 100, 220, 321])
x = A.solve(b)
print 'x: ', x
print 'b: ', b
print 'Ax: ', A.mmul(x)
inv = C.inverse()
print '\ninverse C:\n', inv, '\nC * inv(C):\n', C.mmul(inv)
assert C.mmul(inv) == eye(3)
points = (xvec,yvec) = funToVec(lambda x: math.sin(x)+2*math.cos(.7*x+.1), low=0, high=3, EqualSpacing=1)
basis = [lambda x: math.sin(x), lambda x: math.exp(x), lambda x: x**2]
print 'Func coeffs:', funfit( points, basis )
print 'Poly coeffs:', polyfit( points, degree=5 )
points = (xvec,yvec) = funToVec(lambda x: math.sin(x)+2*math.cos(.7*x+.1), low=0, high=3)
print 'Rational coeffs:', ratfit( points )
print polyfit(([1,2,3,4], [1,4,9,16]), 2)
mtable = Vec([1,2,3]).outer(Vec([1,2]))
print mtable, mtable.size
A = Mat([ [2,0,3], [1,5,1], [18,0,6] ])
print 'A:'
print A
print 'eigs:'
print A.eigs()
print 'Should be:', Vec([11.6158, 5.0000, -3.6158])
print 'det(A)'
print A.det()
c = Mat( [[1,2,30],[4,5,10],[10,80,9]] ) # Failed example from Konrad Hinsen
print 'C:\n', c
print c.eigs()
print 'Should be:', Vec([-8.9554, 43.2497, -19.2943])
A = Mat([ [1,2,3,4], [4,5,6,7], [2,1,5,0], [4,2,1,0] ] ) # Kincaid and Cheney p.326
print 'A:\n', A
print A.eigs()
print 'Should be:', Vec([3.5736, 0.1765, 11.1055, -3.8556])
A = rand(3)
q,r = A.qr()
s,t = A.qr()
print q is s # Test caching
print r is t
A[1][1] = 1.1 # Invalidate the cache
u,v = A.qr()
print q is u # Verify old result not used
print r is v
print u.mmul(v) == A # Verify new result
print 'Test qr on 3x5 matrix'
a = rand(3,5)
q,r = a.qr()
print q.mmul(r) == a
print q.tr().mmul(q) == eye(3)
When I had to do some matrix arithmetic I defined a new class to help. Within such a class you can define magic methods like __add__, or, in your use-case, __matmul__, allowing you to define x = a # b or a #= b rather than matrixMult(a,b). __matmul__ was added in Python 3.5 per PEP 465.
I have included some code which implements this below (I excluded the prohibitively long __init__ method, which essentially creates a two-dimensional list self.mat and a tuple self.order according to what is passed to it)
class Matrix:
def __matmul__(self, multiplier):
if self.order[1] != multiplier.order[0]:
raise ValueError("The multiplier was non-conformable under multiplication.")
return [[sum(a*b for a,b in zip(srow,mcol)) for mcol in zip(*multiplier.mat)] for srow in self.mat]
def __imatmul__(self, multiplier):
self.mat = self # multiplier
return self.mat
def __rmatmul__(self, multiplicand):
if multiplicand.order[1] != self.order[0]:
raise ValueError("The multiplier was non-conformable under multiplication.")
return [[sum(a*b for a,b in zip(mrow,scol)) for scol in zip(*self.mat)] for mrow in multiplicand.mat]
Note:
__rmatmul__ is used if b # a is called and b does not implement __matmul__ (e.g. if I wanted to implement premultiplying by a 2D list)
__imatmul__ is required for a #= b to work correctly;
If a matrix is non-conformable under multiplication it means that it cannot be multiplied, usually because it has more or less rows than there are columns in the multiplicand
Matrix Multiplication in pure python.
def matmult(m1,m2):
r=[]
m=[]
for i in range(len(m1)):
for j in range(len(m2[0])):
sums=0
for k in range(len(m2)):
sums=sums+(m1[i][k]*m2[k][j])
r.append(sums)
m.append(r)
r=[]
return m
The fault occurs here:
C[i][j]+=A[i][k]*B[k][j]
It crashes when k=2. This is because the tuple A[i] has only 2 values, and therefore you can only call it up to A[i][1] before it errors.
EDIT: Listen to Gerard's answer too, your C is wrong. It should be C=[[0 for row in range(len(A))] for col in range(len(A[0]))].
Just a tip: you could replace the first loop with a multiplication, so it would be C=[[0]*len(A) for col in range(len(A[0]))]
The shape of your matrix C is wrong; it's the transpose of what you actually want it to be. (But I agree with ulmangt: the Right Thing is almost certainly to use numpy, really.)
All the below answers would return you the list.Your need to convert it to matrix
def MATMUL(X, Y):
rows_A = len(X)
cols_A = len(X[0])
rows_B = len(Y)
cols_B = len(Y[0])
if cols_A != rows_B:
print "Matrices are not compatible to Multiply. Check condition C1==R2"
return
# Create the result matrix
# Dimensions would be rows_A x cols_B
C = [[0 for row in range(cols_B)] for col in range(rows_A)]
print C
for i in range(rows_A):
for j in range(cols_B):
for k in range(cols_A):
C[i][j] += A[i][k] * B[k][j]
C = numpy.matrix(C).reshape(len(A),len(B[0]))
return C
def matrixmult (A, B):
C = [[0 for row in range(len(A))] for col in range(len(B[0]))]
for i in range(len(A)):
for j in range(len(B[0])):
for k in range(len(B)):
C[i][j] += A[i][k]*B[k][j]
return C
at second line you should change
C = [[0 for row in range(len(B[0]))] for col in range(len(A))]
m=input("row")
n=input("col")
X=[]
for i in range (m):
m1=[]
for j in range (n):
m1.append(input("num"))
X.append(m1)
Y=[]
for i in range (m):
n1=[]
for j in range (n):
n1.append(input("num"))
Y.append(n1)
# result is 3x3
result = [[0,0,0],
[0,0,0],
[0,0,0]]
# iterate through rows of X
for i in range(len(X)):
# iterate through columns of Y
for j in range(len(Y[0])):
# iterate through rows of Y
for k in range(len(Y)):
result[i][j] += X[i][k] * Y[k][j]
for r in result:
print(r)
Had to delete the first post because I noticed an error but this should work fine for multiplying two matrixes.
from numpy import*
A = matrix([[1.0016, 0.0, -16.0514],[0.0, 10000.0, -40000.0],[-16.0514, -40000.0, 160513.6437]])
B = matrix([(1.0, 1.0),(0.0, 0.25),(0.0, 0.0625)])
n,m = shape(B)
C = ones((n,m*n))
index=0
matrixA=ones(shape(A))
for i in range(n):
if (i==1):
for y in range(n):
for z in range(n):
matrixA[y,z]=matrixA[y,z]*A[y,z]
elif(i>1):
matrixA=matrixA*A
if (i==0):
result=B
else:
result = matrixA * B
for x in range (n):
for y in range(m):
C[x,index] = result[x,y]
index+=1
index=index-m
index=index+m
print(C)

Categories