Custom matrix class (using only 1 list), multiplying to matrices - python

Im trying to create a python class for my assignment. We have to design a custom class handling matrices.
Now Im very new to programming but the main problem I get with this assignment is to multiply two matrices. I can't get my class to actually multiply the rows with more than one column, because I am trying to solve this assignment using only 1 list instead of an array.
I have searched and looked but cant seem to find an answer. I cant use numpy and would like to see if it is doable using just 1 list to describe the matrix.
class simplematrix(object):
def __init__(self,n=0,m=0,values=list()):
self.matrix = []
for x in values:
self.matrix.append(x)
if self.matrix == []:
while len(self.matrix)<n*m:
self.matrix.append(0)
if n*m != len(self.matrix):
raise ValueError('Length of values is different from length of matrix')
self.n = n
self.m = m
def __str__(self):
a = ''
if self.matrix == []:
for x in range(self.n):
a += '\n'
for y in range(self.m):
a += ' '+str(0)
else:
for x in range(self.n):
a += '\n'
for y in range(self.m):
a += ' '+str(self.matrix[y+x*self.m])
return a
def __add__(self,other):
if self.n != other.n or self.m != other.m:
raise ValueError('Matrices have different sizes.')
ans_val = []
for x in range(len(self.matrix)):
ans_val.append(self.matrix[x]+other.matrix[x])
ans = simplematrix(self.n,self.m,ans_val)
return ans
def __mul__(self,other):
if self.m != other.n:
raise ValueError('Matrices have incorrect sizes.')
ans = simplematrix(other.n,self.m)#WTF WTF WTF WTF
for y in range(self.m):
a = self.get_row(y)
b = other.get_col(y)
c = 0
for z in range(len(a)):
c += a[z]*b[z]
ans.matrix[y*self.m] = c
I cant seem to figure out how to get any further. This only calculates the first column of the product matrix. I'm not sure how I can get to change the b to mean another column but still maintain a as being the same column, since i still need to use it :S?
Hope its not to awful to look at.
Any ideas on how to solve this?

Related

Error: 'Matrix' object is not subscriptable

I have created a class in python for matrices and want to have different functions that when applied to a matrix object accomplishes a specific goal. The specific function which have an error is a function to add one matrix to another.
class Matrix:
def __init__(self, rows):
self.rows = rows
self.m = len(rows)
self.n = len(rows[0])
def add(self,other):
output = [[0 for x in range(self.m)] for y in range(self.m)]
for i in range(self.m):
for j in range(self.n):
output[i][j] = self[i][j] + other[i][j]
returnmatrix = Matrix(output)
return returnmatrix
B = Matrix([[1,2,3], [4,5,6], [7,8,9]])
F = Matrix([[1,2,3], [4,5,6], [7,8,9]])
B.add(F)
I expect the output to be a 3x3 matrix that is the addition of matrices B and F. Error recieved is: TypeError: 'Matrix' object is not subscriptable.
The error comes from this line;
for j in range(self.n):
output[i][j] = self[i][j] + other[i][j]
You are subscripting the object but presumably need to be subscripting the rows attribute:
for j in range(self.n):
output.rows[i][j] = self.rows[i][j] + other.rows[i][j]
Also for this to work you need to create output as an instance of Matrix before this, so the full function would be:
def add(self,other):
output = Matrix([[0 for x in range(self.m)] for y in range(self.m)])
for i in range(self.m):
for j in range(self.n):
output.rows[i][j] = self.rows[i][j] + other.rows[i][j]
return output
Also as an aside if you are creating methods like add you should look into dunder methods (e.g. __add__); which will give you the nice functionality of being able to use the plus symbol to add instances of your object together.

backtracking not trying all possibilities

so I've got a list of questions as a dictionary, e.g
{"Question1": 3, "Question2": 5 ... }
That means the "Question1" has 3 points, the second one has 5, etc.
I'm trying to create all subset of question that have between a certain number of questions and points.
I've tried something like
questions = {"Q1":1, "Q2":2, "Q3": 1, "Q4" : 3, "Q5" : 1, "Q6" : 2}
u = 3 #
v = 5 # between u and v questions
x = 5 #
y = 10 #between x and y points
solution = []
n = 0
def main(n_):
global n
n = n_
global solution
solution = []
finalSolution = []
for x in questions.keys():
solution.append("_")
finalSolution.extend(Backtracking(0))
return finalSolution
def Backtracking(k):
finalSolution = []
for c in questions.keys():
solution[k] = c
print ("candidate: ", solution)
if not reject(k):
print ("not rejected: ", solution)
if accept(k):
finalSolution.append(list(solution))
else:
finalSolution.extend(Backtracking(k+1))
return finalSolution
def reject(k):
if solution[k] in solution: #if the question already exists
return True
if k > v: #too many questions
return True
points = 0
for x in solution:
if x in questions.keys():
points = points + questions[x]
if points > y: #too many points
return True
return False
def accept(k):
points = 0
for x in solution:
if x in questions.keys():
points = points + questions[x]
if points in range (x, y+1) and k in range (u, v+1):
return True
return False
print(main(len(questions.keys())))
but it's not trying all possibilities, only putting all the questions on the first index..
I have no idea what I'm doing wrong.
There are three problems with your code.
The first issue is that the first check in your reject function is always True. You can fix that in a variety of ways (you commented that you're now using solution.count(solution[k]) != 1).
The second issue is that your accept function uses the variable name x for what it intends to be two different things (a question from solution in the for loop and the global x that is the minimum number of points). That doesn't work, and you'll get a TypeError when trying to pass it to range. A simple fix is to rename the loop variable (I suggest q since it's a key into questions). Checking if a value is in a range is also a bit awkward. It's usually much nicer to use chained comparisons: if x <= points <= y and u <= k <= v
The third issue is that you're not backtracking at all. The backtracking step needs to reset the global solution list to the same state it had before Backtracking was called. You can do this at the end of the function, just before you return, using solution[k] = "_" (you commented that you've added this line, but I think you put it in the wrong place).
Anyway, here's a fixed version of your functions:
def Backtracking(k):
finalSolution = []
for c in questions.keys():
solution[k] = c
print ("candidate: ", solution)
if not reject(k):
print ("not rejected: ", solution)
if accept(k):
finalSolution.append(list(solution))
else:
finalSolution.extend(Backtracking(k+1))
solution[k] = "_" # backtracking step here!
return finalSolution
def reject(k):
if solution.count(solution[k]) != 1: # fix this condition
return True
if k > v:
return True
points = 0
for q in solution:
if q in questions:
points = points + questions[q]
if points > y: #too many points
return True
return False
def accept(k):
points = 0
for q in solution: # change this loop variable (also done above, for symmetry)
if q in questions:
points = points + questions[q]
if x <= points <= y and u <= k <= v: # chained comparisons are much nicer than range
return True
return False
There are still things that could probably be improved in there. I think having solution be a fixed-size global list with dummy values is especially unpythonic (a dynamically growing list that you pass as an argument would be much more natural). I'd also suggest using sum to add up the points rather than using an explicit loop of your own.

Python 3 - IndexError: list index out of range when trying to find determinant of a matrix

I am trying to find determinant with a nested list representing a two-dimensional matrix. But it is infinitely calling the getMinor() function and continuously deleting from the same list, which should not happend because I am creating new list every time. Below is the code. Also all the functions are defined in a class named 'Matrix()'.
def __init__(self):
self.matrix_list = []
self.no_of_row = 0
self.no_of_col = 0
def getMinor(self, matrix, j):
del matrix[0]
for i in range(len(matrix)):
del matrix[i][j]
m = Matrix()
m.matrix_list = matrix[:]
m.no_of_row = len(m.matrix_list)
#print(m.no_of_row)
print(m.matrix_list)
m.no_of_col = len(m.matrix_list[0])
return m.detMatrix()
def detMatrix(self):
if self.no_of_row == 2 and self.no_of_col == 2:
return self.matrix_list[0][0] * self.matrix_list[1][1] - self.matrix_list[0][1] * self.matrix_list[1][0]
else:
matrix = self.matrix_list[:]
det = 0
for i in range(self.no_of_col):
det += ((-1)**i) * self.matrix_list[0][i] * self.getMinor(matrix, i)
return det
You have two problems. One is alluded to by user2357112 who unfortunately didn't bother to explain. When you use the expression x[:] you get a shallow copy of the list x. Often there is no practical difference between deep and shallow copies; for example if x contains numbers or strings. But in your case the elements of x are lists. Each element of the new list, x[:], will be the same sub-list that was in the original x - not a copy. When you delete one element of those nested lists (del matrix[i][j]), you are therefore deleting some of your original data.
The second problem is that you aren't handling the recursion properly. You create a new variable, matrix, in the function detMatrix. Even if you make a deep copy here, that won't fix the problem. You pass matrix to getMinor, which deletes some data from it. Now in the next step through your for loop, you have messed up the data. You need to make a deep copy inside the function getMinor.
Here is a program that runs, at least. I didn't check your algebra :-)
I will also add that it's very inefficient. The idea of making a copy and then deleting pieces from the copy doesn't make much sense. I didn't address this.
import copy
class Matrix:
def __init__(self):
self.matrix_list = []
self.no_of_row = 0
self.no_of_col = 0
def getMinor(self, matrix_list, j):
print("Entry:", matrix_list)
matrix = copy.deepcopy(matrix_list)
del matrix[0]
for i in range(len(matrix)):
del matrix[i][j]
print("After deletions", matrix_list)
m = Matrix()
m.matrix_list = matrix[:]
m.no_of_row = len(m.matrix_list)
m.no_of_col = len(m.matrix_list[0])
x = m.detMatrix()
print(m.matrix_list, m.no_of_row, m.no_of_col)
return x
def detMatrix(self):
if self.no_of_row == 2 and self.no_of_col == 2:
return self.matrix_list[0][0] * self.matrix_list[1][1] - self.matrix_list[0][1] * self.matrix_list[1][0]
else:
det = 0
for i in range(self.no_of_col):
det += ((-1)**i) * self.matrix_list[0][i] * self.getMinor(self.matrix_list, i)
return det
m = Matrix()
m.matrix_list.append([0.0,1.0,2.0,3.0])
m.matrix_list.append([1.0,2.0,3.0,4.0])
m.matrix_list.append([2.0,3.0,4.0,5.0])
m.matrix_list.append([3.0,5.0,7.0,9.0])
m.no_of_row = 4
m.no_of_col = 4
print(m.detMatrix())

How to Memoize the solution to Unique Paths in Python

I've been trying to solve this problem for a while. A M x N grid is given and we've to find number to paths from top left corner to bottom right corner.
Simple problem though; there are many solutions as well. Here're the details.
http://www.interviewbit.com/courses/programming/topics/math/problems/paths/
http://articles.leetcode.com/2010/11/unique-paths.html
I solved this problem in Java, and wrote one more solution in Python. Now I want to modify the previous solution with Memoized table so that the final answer gets collected at the bottom right cell. Value of a cell is the sum of its right and left adjacent cells.
Here's the code I can't debug:-
class Solution:
#Actual Recursive function
def paths(self,row,col):
if row == 0 or col == 0:
self.Mat[row][col] = 1
return 1
self.Mat[row][col-1] = self.paths(row, col-1)
self.Mat[row-1][col] = self.paths(row-1, col)
self.Mat[row][col] = self.Mat[row][col-1] + self.Mat[row-1][col]
return self.Mat[row][col]
# Driver Function. This will be called
def uniquePaths(self, A, B):
self.Mat = [[-1]*B]*A
ans = self.paths(A-1, B-1)
return self.Mat[A-1][B-1]
And here is my previous solution that works - But doesn't use memoized table.
class OldSolution:
def paths(self,row,col):
if row==0 or col==0:
return 1
elif row<0 or col<0:
return 0
elif row >0 and col > 0:
return self.paths(row-1,col) + self.paths(row,col-1)
def uniquePaths(self, A, B):
Mat = [ [-1] * B ] *A
return self.paths(A-1, B-1)
sol = OldSolution()
print sol.uniquePaths(3,3) # Prints 6
Test Cases:-
3, 3 = 6
15, 9 = 319770
The issue is with the initialization of the matrix. You essentially create the same row duplicated in every column so when you update a cell, all corresponding cells in all columns get updated.
Instead of:
self.Mat = [[-1]*B]*A
Use:
self.Mat = [[-1 for i in range(B)] for j in range(A)]

Matrices Class Calculator Python

In making the function to multiply the matrices my code only prints the first value of the first matrix and fills in all other position with zero. Below is the class with different functions and the multiply matrices function below it. The exception handling works and the printing function works as well. The only problem arises with
class Matrix(object):
"""Input the dimensions of your matrix"""
def __init__(self, rows = 3, cols = 3):
self.rows = rows
self.cols = cols
self.rowList = [ [0 * x for x in range(cols)] for count in range(rows)]
def setRow(self, index = 0, RowData = [0]*2):
"""Enter the index of the row you are defining followed by a string with the values seperated by commas"""
i = 0
if index >= self.cols:
print("Index is out of the bounds that you defined earlier")
return None
if len(RowData) != self.cols:
print("The Row length exceeds the column size of this matrix")
return None
else:
self.rowList[index] = RowData
def rowCount(self):
return self.rows
def columnCount(self):
return self.cols
def get(self, row, col):
return self.rowList[row][col]
def set(self, value = 0, row = 0, col = 0):
self.rowList[row][col] = value
return None
def MultiplyMatrices(A = Matrix(), B = Matrix()):
ARows = A.rowCount()
ACols = A.columnCount()
BRows = B.rowCount()
BCols = B.columnCount()
if ACols != BRows:
print("Matrices are incompatible, therefore cannot be multiplied")
return None
Result = Matrix(ARows, BCols)
for A_row in range(ARows):
for B_col in range(BCols):
Res = 0
for B_row in range(BRows):
Res = Res + A.get(A_row, B_row) * B.get(B_row, B_col)
Result.set(Res, A_row, B_col)
return Result
I think your problem is in your "for" loop.
You have
for B_row in range(BRows):
Res = Res + A.get(A_row, B_row) * B.get(B_row, B_col)
Result.set(Res, A_row, B_col)
return Result
but it should be
for A_row in range(ARows):
for B_col in range(BCols):
Res = 0
for B_row in range(BRows):
Res = Res + A.get(A_row, B_row) * B.get(B_row, B_col)
Result.set(Res, A_row, B_col)
return Result
The way you have things written, your code will return the Result matrix after only calculating the first entry value. I assume you have the other values defaulting to 0, which would explain why the rest of the entries in your Result matrix print as 0.
By the way, one thing you might want to consider is including this Multiply Matrix function in your Matrix class. If you define a class function using this signature
def __mul__(self):
"Your code here"
then when you create two instances of your matrix class, call them A and B, then you can multiply them within your program simply by typing A*B.
You seem to have a two indentation errors so that your MultiplyMatrices won't work correctly. Here's the corrected code:
for A_row in range(ARows):
for B_col in range(BCols):
Res = 0
for B_row in range(BRows):
Res = Res + A.get(A_row, B_row) * B.get(B_row, B_col)
Result.set(Res, A_row, B_col) # this edited so it's the sum over B_row
return Result # this set so it's after all three loops have completed
As a side note, I don't see how your default values (A = Matrix(), B = Matrix()) are ever going to work out well for you. It would almost always be better to just raise an exception if you don't get the needed in input rather than silently returning a matrix of all zeros.
Also, in case you're not already aware, you should know that there's an advanced set of tools for working with matrices in Python called Numpy.

Categories

Resources