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

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)))

Related

how to call a method from a matrix that takes the "bool" type?

I have a problem with matrix initialization, namely with the "bool" parameter, how can I e.g. initialize a matrix and add it?
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 __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
m1 = Matrix(3,5,**? bool type)**
You can either pass the third argument as such:
m1 = Matrix(3,5,False)
Or using named parameters:
m1 = Matrix(3,5,init = False)
Notice how in Python it's False with a capital F and not false like in some other languages.

python, matrix object calling

maybe a bit trivial question but i'm having trouble calling the object.
How can I call an object from this class and possibly call the add method correctly?
sample code:
class MyMatrix:
height = 0
width = 0
data = tuple()
def __init__(self, data):
self.height = len(data)
self.width = len(data[0])
self.data = data
def add(mat1, mat2):
if mat1.height != mat2.height or mat1.width != mat2.width:
print("The matrices are not the same size!")
return
rows = []
for i in range(len(mat1.data)):
row = []
for j in range(len(mat1.data[0])):
row.append(mat1[i][j] + mat2[i][j])
rows.append(tuple(row))
return MyMatrix(tuple(rows))
Thank you in advance for every answer.
You can call the methods like follows; for your code to work, however, you need to implement getitem (so that you can do matrix[1][2] e.g.).
class MyMatrix:
height = 0
width = 0
data = tuple()
def __init__(self, data):
self.height = len(data)
self.width = len(data[0])
self.data = data
def __getitem__(self, item):
return self.data.__getitem__(item)
def add(mat1, mat2):
if mat1.height != mat2.height or mat1.width != mat2.width:
print("The matrices are not the same size!")
return
rows = []
for i in range(len(mat1.data)):
row = []
for j in range(len(mat1.data[0])):
row.append(mat1[i][j] + mat2[i][j])
rows.append(tuple(row))
return MyMatrix(tuple(rows))
m1 = MyMatrix([[1,2,3]])
m2 = MyMatrix([[3,2,1]])
m12 = m1.add(m2)
print(m12.data)

Computing determinant of matrix recursively

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

Multivariable Cumulants and Moments in python

In Mathematica I can convert multivariable moments in cumulants and back using MomentConvert:
MomentConvert[Cumulant[{2, 2,1}], "Moment"] // TraditionalForm
as one can try in wolframcloud.
I would like to do exactly the same in python. Is there any library in python capable of this?
At least the one direction I now programmed by myself:
# from http://code.activestate.com/recipes/577211-generate-the-partitions-of-a-set-by-index/
from collections import defaultdict
class Partition:
def __init__(self, S):
self.data = list(S)
self.m = len(S)
self.table = self.rgf_table()
def __getitem__(self, i):
#generates set partitions by index
if i > len(self) - 1:
raise IndexError
L = self.unrank_rgf(i)
result = self.as_set_partition(L)
return result
def __len__(self):
return self.table[self.m,0]
def as_set_partition(self, L):
# Transform a restricted growth function into a partition
n = max(L[1:]+[1])
m = self.m
data = self.data
P = [[] for _ in range(n)]
for i in range(m):
P[L[i+1]-1].append(data[i])
return P
def rgf_table(self):
# Compute the table values
m = self.m
D = defaultdict(lambda:1)
for i in range(1,m+1):
for j in range(0,m-i+1):
D[i,j] = j * D[i-1,j] + D[i-1,j+1]
return D
def unrank_rgf(self, r):
# Unrank a restricted growth function
m = self.m
L = [1 for _ in range(m+1)]
j = 1
D = self.table
for i in range(2,m+1):
v = D[m-i,j]
cr = j*v
if cr <= r:
L[i] = j + 1
r -= cr
j += 1
else:
L[i] = r // v + 1
r %= v
return L
# S = set(range(4))
# P = Partition(S)
# for x in P:
# print (x)
# using https://en.wikipedia.org/wiki/Cumulant#Joint_cumulants
import math
def Cum2Mom(arr, state):
def E(op):
return qu.expect(op, state)
def Arr2str(arr,sep):
r = ''
for i,x in enumerate(arr):
r += str(x)
if i<len(arr)-1:
r += sep
return r
if isinstance( arr[0],str):
myprod = lambda x: Arr2str(x,'*')
mysum = lambda x: Arr2str(x,'+')
E=lambda x: 'E('+str(x)+')'
myfloat = str
else:
myfloat = lambda x: x
myprod = np.prod
mysum = sum
S = set(range(len(arr)))
P = Partition(S)
return mysum([
myprod([myfloat(math.factorial(len(pi)-1) * (-1)**(len(pi)-1))
,myprod([
E(myprod([
arr[i]
for i in B
]))
for B in pi])])
for pi in P])
print(Cum2Mom(['a','b','c','d'],1) )
import qutip as qu
print(Cum2Mom([qu.qeye(3) for i in range(3)],qu.qeye(3)) )
It's designed to work with qutip opjects and it also works with strings to verify the correct separation and prefactors.
Exponents of the variables can be represented by repeating the variable.

Which data structure to use when implementing graph representation using adjacency list

I have a graph that is very big about 1,000,000 nodes and many edges. This is what i wanted to know which is the best suited data structure when implementing an adjacency list. Here are the objects that i keep track of
Edge list
Node to node connection list
I am coding with python so I used a set(because according to this it has a o(1) average insertion time) for edge list and a dictionary to node to node connection list(by making it completely hashable according to How to make an object properly hashable?). Here is my code
class node:
def __init__(self, name = ""):
self.__name = name
def getName(self):
return self.__name
def __str__(self):
return self.__name
def __hash__(self):
return hash(self.__name)
def __lt__(self, other):
if(type(self) != type(other)):
return NotImplemented
return self.__name.__lt__(other.__name)
def __eq__(self, other):
if(type(self)) != type(other):
return NotImplemented
return self.__name == other.__name
class Edge:
def __init__(self, name = "", node1 = None, node2 = None, weight = 0):
self.__name = name
self.__firstNode = node1
self.__secondNode = node2
self.__weight = weight
def getName(self):
return self.__name
def getFirstNode(self):
return self.__firstNode
def getSecondNode(self):
return self.__secondNode
def getWeight(self):
return self.__weight
def __lt__(self, other):
if(type(self) != type(other)):
return NotImplemented
return self.__name.__lt__(other.__name) and self.__firstNode.__lt__(other.__firstNode) and self.__secondNode.__lt__(other.__secondNode) and self.__weight.__lt__(other.__weight)
def __eq__(self, other):
if(type(self) != type(other)):
return NotImplemented
return self.__name == other.__name and self.__firstNode == other.__firstNode and self.__secondNode == other.__secondNode and self.__weight == other.__weight
def __str__(self):
return self.__name + " " + str(self.__firstNode) + " " + str(self.__secondNode) + " " + str(self.__weight)
def __hash__(self):
return hash(hash(self.__name) + hash(self.__firstNode) + hash(self.__secondNode) + hash(self.__weight))
class graph:
def __init__(self):
self.__nodeToNode = {}
self.__edgeList = set()
def addEdge(self, edge):
if(type(edge) != type(Edge())):
return False
self.__edgeList.add(edge)
if(not edge.getFirstNode() in self.__nodeToNode):
self.__nodeToNode[edge.getFirstNode()] = set()
self.__nodeToNode[edge.getFirstNode()].add(edge.getSecondNode())
if(not edge.getSecondNode() in self.__nodeToNode):
self.__nodeToNode[edge.getSecondNode()] = set()
self.__nodeToNode[edge.getSecondNode()].add(edge.getSecondNode())
return True
def getNodes(self):
return dict(self.__nodeToNode)
def getEdges(self):
return set(self.__edgeList)
import string
import random
import time
grp = graph()
nodes = [None] * 20000
for i in range(20000):
st = ''.join(random.SystemRandom().choice(string.ascii_letters) for i in range(10))
node1 = node(st)
nodes[i] = node1
current = time.time()
for i in range(3000000):
rdm = random.randint(0, 199)
rdm2 = random.randint(0, 199)
st = ''.join(random.SystemRandom().choice(string.ascii_letters) for i in range(10))
eg = Edge(st, nodes[rdm], nodes[rdm2])
grp.addEdge(eg)
last = time.time()
print((last - current))
nodes = grp.getNodes()
edges = grp.getEdges()
but this code runs very slowly can i make it faster? If so by using what data structure?
Let me introduce you a way to create an adjacency list:
Suppose you have the input like this:
4 4
1 2
3 2
4 3
1 4
The first line contains 2 numbers V and E, the next E lines defines an edge between two vertices.
You can either create a .txt file and read the input or directly type in via sys.stdin.read():
input = sys.stdin.read()
data = list(map(int, input.split()))
n, m = data[0:2]
data = data[2:]
edges = list(zip(data[0:(2 * m):2], data[1:(2 * m):2]))
x, y = data[2 * m:]
adj = [[] for _ in range(n)]
x, y = x - 1, y - 1
for (a, b) in edges:
adj[a - 1].append(b - 1)
adj[b - 1].append(a - 1)
Let's output the adjacency list adj:
>>> print(adj)
[[1, 3], [0, 2], [1, 3], [2, 0]]
adj[0] have two adj nodes: 1 and 3. Meaning the node 1 have two adj nodes: 2 and 4.
And now, if you want a directed, weighted graph, you just need to modify the input like this:
4 4
1 2 3 # edge(1, 2) has the weight of 3
3 2 1
4 3 1
1 4 2
input = sys.stdin.read()
data = list(map(int, input.split()))
n, m = data[0:2]
data = data[2:]
edges = list(zip(zip(data[0:(3 * m):3], data[1:(3 * m):3]), data[2:(3 * m):3]))
data = data[3 * m:]
adj = [[] for _ in range(n)]
cost = [[] for _ in range(n)]
for ((a, b), w) in edges:
adj[a - 1].append(b - 1)
cost[a - 1].append(w)
You store the weight in cost, and for example, cost[0][1] = 3, cost[0][3] = 2.
Hope this helped!

Categories