computing determinant of a matrix (nxn) recursively - python

I'm about to write some code that computes the determinant of a square matrix (nxn), using the Laplace algorithm (Meaning recursive algorithm) as written Wikipedia's Laplace Expansion.
I already have the class Matrix, which includes init, setitem, getitem, repr and all the things I need to compute the determinant (including minor(i,j)).
So I've tried the code below:
def determinant(self,i=0) # i can be any of the matrix's rows
assert isinstance(self,Matrix)
n,m = self.dim() # Q.dim() returns the size of the matrix Q
assert n == m
if (n,m) == (1,1):
return self[0,0]
det = 0
for j in range(n):
det += ((-1)**(i+j))*(self[i,j])*((self.minor(i,j)).determinant())
return det
As expected, in every recursive call, self turns into an appropriate minor. But when coming back from the recursive call, it doesn't change back to it's original matrix.
This causes trouble when in the for loop (when the function arrives at (n,m)==(1,1), this one value of the matrix is returned, but in the for loop, self is still a 1x1 matrix - why?)

Are you sure that your minor returns the a new object and not a reference to your original matrix object? I used your exact determinant method and implemented a minor method for your class, and it works fine for me.
Below is a quick/dirty implementation of your matrix class, since I don't have your implementation. For brevity I have chosen to implement it for square matrices only, which in this case shouldn't matter as we are dealing with determinants. Pay attention to det method, that is the same as yours, and minor method (the rest of the methods are there to facilitate the implementation and testing):
class matrix:
def __init__(self, n):
self.data = [0.0 for i in range(n*n)]
self.dim = n
#classmethod
def rand(self, n):
import random
a = matrix(n)
for i in range(n):
for j in range(n):
a[i,j] = random.random()
return a
#classmethod
def eye(self, n):
a = matrix(n)
for i in range(n):
a[i,i] = 1.0
return a
def __repr__(self):
n = self.dim
for i in range(n):
print str(self.data[i*n: i*n+n])
return ''
def __getitem__(self,(i,j)):
assert i < self.dim and j < self.dim
return self.data[self.dim*i + j]
def __setitem__(self, (i, j), val):
assert i < self.dim and j < self.dim
self.data[self.dim*i + j] = float(val)
#
def minor(self, i,j):
n = self.dim
assert i < n and j < n
a = matrix(self.dim-1)
for k in range(n):
for l in range(n):
if k == i or l == j: continue
if k < i:
K = k
else:
K = k-1
if l < j:
L = l
else:
L = l-1
a[K,L] = self[k,l]
return a
def det(self, i=0):
n = self.dim
if n == 1:
return self[0,0]
d = 0
for j in range(n):
d += ((-1)**(i+j))*(self[i,j])*((self.minor(i,j)).det())
return d
def __mul__(self, v):
n = self.dim
a = matrix(n)
for i in range(n):
for j in range(n):
a[i,j] = v * self[i,j]
return a
__rmul__ = __mul__
Now for testing
import numpy as np
a = matrix(3)
# same matrix from the Wikipedia page
a[0,0] = 1
a[0,1] = 2
a[0,2] = 3
a[1,0] = 4
a[1,1] = 5
a[1,2] = 6
a[2,0] = 7
a[2,1] = 8
a[2,2] = 9
a.det() # returns 0.0
# trying with numpy the same matrix
A = np.array(a.data).reshape([3,3])
print np.linalg.det(A) # returns -9.51619735393e-16
The residual in case of numpy is because it calculates the determinant through (Gaussian) elimination method rather than the Laplace expansion. You can also compare the results on random matrices to see that the difference between your determinant function and numpy's doesn't grow beyond float precision:
import numpy as np
a = 10*matrix.rand(4)
A = np.array( a.data ).reshape([4,4])
print (np.linalg.det(A) - a.det())/a.det() # varies between zero and 1e-14

use Sarrus' Rule (non recursive method)
example on below link is in Javascript, but easily can be written in python
https://github.com/apanasara/Faster_nxn_Determinant

import numpy as np
def smaller_matrix(original_matrix,row, column):
for ii in range(len(original_matrix)):
new_matrix=np.delete(original_matrix,ii,0)
new_matrix=np.delete(new_matrix,column,1)
return new_matrix
def determinant(matrix):
"""Returns a determinant of a matrix by recursive method."""
(r,c) = matrix.shape
if r != c:
print("Error!Not a square matrix!")
return None
elif r==2:
simple_determinant = matrix[0][0]*matrix[1][1]-matrix[0][1]*matrix[1][0]
return simple_determinant
else:
answer=0
for j in range(r):
cofactor = (-1)**(0+j) * matrix[0][j] * determinant(smaller_matrix(matrix, 0, j))
answer+= cofactor
return answer
#test the function
#Only works for numpy.array input
np.random.seed(1)
matrix=np.random.rand(5,5)
determinant(matrix)

Here's the function in python 3.
Note: I used a one-dimensional list to house the matrix and the size array is the amount of rows or columns in the square array. It uses a recursive algorithm to find the determinant.
def solve(matrix,size):
c = []
d = 0
print_matrix(matrix,size)
if size == 0:
for i in range(len(matrix)):
d = d + matrix[i]
return d
elif len(matrix) == 4:
c = (matrix[0] * matrix[3]) - (matrix[1] * matrix[2])
print(c)
return c
else:
for j in range(size):
new_matrix = []
for i in range(size*size):
if i % size != j and i > = size:
new_matrix.append(matrix[i])
c.append(solve(new_matrix,size-1) * matrix[j] * ((-1)**(j+2)))
d = solve(c,0)
return d

i posted this code because i couldn't fine it on the internet, how to solve n*n determinant using only standard library.
the purpose is to share it with those who will find it useful.
i started by calculating the submatrix Ai related to a(0,i).
and i used recursive determinant to make it short.
def submatrix(M, c):
B = [[1] * len(M) for i in range(len(M))]
for l in range(len(M)):
for k in range(len(M)):
B[l][k] = M[l][k]
B.pop(0)
for i in range(len(B)):
B[i].pop(c)
return B
def det(M):
X = 0
if len(M) != len(M[0]):
print('matrice non carrée')
else:
if len(M) <= 2:
return M[0][0] * M[1][1] - M[0][1] * M[1][0]
else:
for i in range(len(M)):
X = X + ((-1) ** (i)) * M[0][i] * det(submatrix(M, i))
return X
sorry for not commenting before guys :)
if you need any further explanation don't hesitate to ask .

Related

How can I avoid exceeding maximum recursion depth when generating a Hadamard Matrix?

I am trying to recursively generate Hadamard matrices by Sylvester construction, following this recurrence formula:
H(2) = (1 1)
(1 -1)
H(2**k) = ( H(2**(k-1)) H(2**(k-1)) )
( H(2**(k-1)) -H(2**(k-1)) )
this formula as an image of LaTeX
Or using the notation (x) for Kronecker product:
H(2**k) = H(2) (x) H(2**(k-1))
My code to generate a Hadamard matrix by Sylvester construction is as follows:
def deepMap(f,seq):
if seq == []:
return seq
elif type(seq) != list:
return f(seq)
else:
return [deepMap(f,seq[0])] + deepMap(f,seq[1:])
def Hadamard(n): #n is a power of 2
if n == 1:
return [1]
elif n == 2:
return [[1,1],[1,-1]]
else:
k = 2
array = [Hadamard(k)]
while k < n:
k *= 2
matrix,prev = [],array.pop(0)
for i in range(k):
if i < k//2:
matrix.append(prev[i]+prev[i])
else:
matrix.append(prev[i%(k//2)]+deepMap(lambda x: -x,prev[i%(k//2)]))
array.append(matrix)
#print(f'matrix {k} = {matrix}')
return array[0]
The code works, but is pretty slow, and exceeds maximum depth recursion when n > 1024.
How could I make the code handle larger values of n?
Context: This code was written for a Kattis question https://open.kattis.com/problems/sylvester
Fixing your code: recursion in deepMap
With just a small modification to your deepMap function, it becomes faster and avoids stacking up thousands of recursive calls: replace return [deepMap(f,seq[0])] + deepMap(f,seq[1:]) with return [deepMap(f, x) for x in seq].
def deepMap(f,seq):
if seq == []:
return seq
elif type(seq) != list:
return f(seq)
else:
return [deepMap(f, x) for x in seq]
def Hadamard(n): #n is a power of 2
if n == 1:
return [1]
elif n == 2:
return [[1,1],[1,-1]]
else:
k = 2
array = [Hadamard(k)]
while k < n:
k *= 2
matrix,prev = [],array.pop(0)
for i in range(k):
if i < k//2:
matrix.append(prev[i]+prev[i])
else:
matrix.append(prev[i%(k//2)]+deepMap(lambda x: -x,prev[i%(k//2)]))
array.append(matrix)
#print(f'matrix {k} = {matrix}')
return array[0]
print( Hadamard(2048) ) # should take less than a second
A different version: avoiding .append
Since we already know the size of the matrix, I suggest creating a matrix that already has the correct size, then filling it recursively or iteratively. To fill the matrix, I made a function dup that duplicates a quadrant of the matrix to another quadrant.
def dup(h, k, i0,j0, s=1):
for i in range(k):
for j in range(k):
h[i0+i][j0+j] = s * h[i][j]
def had(n):
'''assume n >= 2 is a power of 2'''
h = [[0 for _ in range(n)] for _ in range(n)]
h[0][0]=1
h[0][1]=1
h[1][0]=1
h[1][1]=-1
k = 2
while k < n:
dup(h, k, 0,k)
dup(h, k, k,0)
dup(h, k, k,k, -1)
k *= 2
return h
print( had(2048) )
Using numpy: everything is easy with concatenate
Using numpy.concatenate, the code becomes much shorter, much much faster, and easier to read:
from numpy import array, concatenate
def hadamard(n):
'''assume n is a power of 2'''
if n == 1:
return array([1])
elif n == 2:
return array([[1,1],[1,-1]])
else:
a = hadamard(n // 2)
return concatenate(
(concatenate((a, a), axis=1),
concatenate((a, -a), axis=1)),
axis=0
)
print( hadamard(2048) )

Lower Triangle Matrix

I am trying to create a lower triangle matrix, without imports (though I use a math import in the beginning). The function I have written takes a list of DNA sequences, and compares them and inputs a float in a list of lists. The problem, however is that I accidentally created the upper triangle. Here is my code (I'll include the other functions so it might make sense):
def sequence_difference(seq1, seq2):
counter = 0
if len(seq1) == len(seq2):
for i in range(len(seq1)):
if seq1[i] != seq2[i]:
counter += 1
return counter / len(seq1)
else:
return ''
def jukes_cantor(diff):
K = -(3/4) * log(1 - (4/3) * diff)
return K
def lower_trian_matrix(list_of_seq):
matrix = []
for i in range(len(list_of_seq)):
matrix.append([])
for j in range(i + 1, len(list_of_seq)):
matrix[i].append(jukes_cantor(sequence_difference(list_of_seq[j], list_of_seq[i])))
return matrix
sequences = ['TAAAAAAAAAAA',
'TTAAAAAAAAAA',
'AAAAAAAAAAGG',
'AAAAAAAAGGGG']
print(lower_trian_matrix(sequences))
It outputs:
[[0.08833727674228764, 0.30409883108112323, 0.6081976621622466],
[0.4408399986765892, 0.8239592165010822],
[0.18848582121067953],
[]]
But I want it to output:
[[],
[0.08833727674228764],
[0.30409883108112323, 0.4408399986765892],
[0.6081976621622466, 0.8239592165010822, 0.18848582121067953]]
The sequence_difference returns how different two sequences are in frequencies. The jukes_cantor returns a corrected estimate of how much the sequences actually have changed over the course of evolution.
Just reverse the indexing for i and j:
from math import log
def sequence_difference(seq1, seq2):
counter = 0
if len(seq1) == len(seq2):
for i in range(len(seq1)):
if seq1[i] != seq2[i]:
counter += 1
return counter / len(seq1)
else:
return ''
def jukes_cantor(diff):
K = -(3/4) * log(1 - (4/3) * diff)
return K
def lower_trian_matrix(list_of_seq):
matrix = [[]]
for i in range(1, len(list_of_seq)):
matrix.append([])
for j in range(i):
matrix[i].append(jukes_cantor(sequence_difference(list_of_seq[j], list_of_seq[i])))
return matrix
sequences = ['TAAAAAAAAAAA',
'TTAAAAAAAAAA',
'AAAAAAAAAAGG',
'AAAAAAAAGGGG']
print(lower_trian_matrix(sequences))
Alternatively, rename it to def upper_trian_matrix(list_of_seq): and tell your teacher, you always wanted to create the upper triangle.
Print this line matrix.append([]) below this for loop for j in range(i + 1, len(list_of_seq)): matrix[i].append(jukes_cantor(sequence_difference(list_of_seq[j], list_of_seq[i])))
Currently, it is above, hence it is executing first.

Access a class's method within the class

Let's say i have this class called grid for 2D arrays:
class grid:
def __init__(self, N, S, F, p):
## Make sure start and end are within the grid
assert N > 2
assert S[0] < N
assert S[1] < N
assert F[0] < N
assert F[1] < N
assert S[0] > 0
assert S[1] > 0
assert F[0] > 0
assert F[1] > 0
self.N = N
self.grid = np.zeros((N, N), dtype=np.int32)
## Surround the grid with obstacles
self.grid[0, :] = 1
self.grid[N - 1, :] = 1
self.grid[:, 0] = 1
self.grid[:, N - 1] = 1
obstacle_free_points = {S, F}
### Fill the grid with obstacles.
### An obstacle at position (x,y) -> grid[x,y]=1
### Ensure there is a path from S to F
### Your code here ###
def isReachable(self):
visited= np.zeros((N, N), dtype=np.int32)
queue=[]
queue.append(S)
visited[S] = True
def adjacent(self, S):
adjacent_nodes = []
for n in (node[0] - 1, node[1]), (node[0] + 1, node[1]), (node[0], node[1] - 1), (node[0], node[1] + 1):
if self.grid[n] == 0:
adjacent_nodes.append(n)
return adjacent_node
What i would like to do is use adjacent inside isReachable.More specificaly given a pair of numbers (x,y) find all the adjacent array cells using method adjacent.Adjacent works just fine if i use it outside of the class but calling it from another method produces errors.How could this be done?
You need to use the self keyword.
self.adjacent(...)

Optimal Search Tree Using Python - Code Analysis

First of all, sorry about the naive question. But I couldn't find help elsewhere
I'm trying to create an Optimal Search Tree using Dynamic Programing in Python that receives two lists (a set of keys and a set of frequencies) and returns two answers:
1 - The smallest path cost.
2 - The generated tree for that smallest cost.
I basically need to create a tree organized by the most accessed items on top (most accessed item it's the root), and return the smallest path cost from that tree, by using the Dynamic Programming solution.
I've the following implemented code using Python:
def optimalSearchTree(keys, freq, n):
#Create an auxiliary 2D matrix to store results of subproblems
cost = [[0 for x in xrange(n)] for y in xrange(n)]
#For a single key, cost is equal to frequency of the key
#for i in xrange (0,n):
# cost[i][i] = freq[i]
# Now we need to consider chains of length 2, 3, ... .
# L is chain length.
for L in xrange (2,n):
for i in xrange(0,n-L+1):
j = i+L-1
cost[i][j] = sys.maxint
for r in xrange (i,j):
if (r > i):
c = cost[i][r-1] + sum(freq, i, j)
elif (r < j):
c = cost[r+1][j] + sum(freq, i, j)
elif (c < cost[i][j]):
cost[i][j] = c
return cost[0][n-1]
def sum(freq, i, j):
s = 0
k = i
for k in xrange (k,j):
s += freq[k]
return s
keys = [10,12,20]
freq = [34,8,50]
n=sys.getsizeof(keys)/sys.getsizeof(keys[0])
print(optimalSearchTree(keys, freq, n))
I'm trying to output the answer 1. The smallest cost for that tree should be 142 (the value stored on the Matrix Position [0][n-1], according to the Dynamic Programming solution). But unfortunately it's returning 0. I couldn't find any issues in that code. What's going wrong?
You have several very questionable statements in your code, definitely inspired by C/Java programming practices. For instance,
keys = [10,12,20]
freq = [34,8,50]
n=sys.getsizeof(keys)/sys.getsizeof(keys[0])
I think you think you calculate the number of items in the list. However, n is not 3:
sys.getsizeof(keys)/sys.getsizeof(keys[0])
3.142857142857143
What you need is this:
n = len(keys)
One more find: elif (r < j) is always True, because r is in the range between i (inclusive) and j (exclusive). The elif (c < cost[i][j]) condition is never checked. The matrix c is never updated in the loop - that's why you always end up with a 0.
Another suggestion: do not overwrite the built-in function sum(). Your namesake function calculates the sum of all items in a slice of a list:
sum(freq[i:j])
import sys
def optimalSearchTree(keys, freq):
#Create an auxiliary 2D matrix to store results of subproblems
n = len(keys)
cost = [[0 for x in range(n)] for y in range(n)]
storeRoot = [[0 for i in range(n)] for i in range(n)]
#For a single key, cost is equal to frequency of the key
for i in range (0,n):
cost[i][i] = freq[i]
# Now we need to consider chains of length 2, 3, ... .
# L is chain length.
for L in range (2,n+1):
for i in range(0,n-L+1):
j = i + L - 1
cost[i][j] = sys.maxsize
for r in range (i,j+1):
c = (cost[i][r-1] if r > i else 0)
c += (cost[r+1][j] if r < j else 0)
c += sum(freq[i:j+1])
if (c < cost[i][j]):
cost[i][j] = c
storeRoot[i][j] = r
return cost[0][n-1], storeRoot
if __name__ == "__main__" :
keys = [10,12,20]
freq = [34,8,50]
print(optimalSearchTree(keys, freq))

Matrix multiplication in Python

Hello (excuse my English), I have a big doubt in python with matrix multiplication, I create a list of lists and multiplied by a scaling matrix, this is what I've done and I can not alparecer perform a multiplication operation problem with indexes, I check with paper and pencil and it works, I'm doing something bad to accommodate indexes or am I wrong accommodating matrices from the beginning?
def main():
if len(sys.argv) > 1:
v = int(sys.argv[1])
else:
print "error python exe:"
print "\tpython <programa.py> <num_vertices>"
A = []
for i in range(v):
A.append([0]*2)
for i in range(v):
for j in range(2):
A[i][j] = input("v: ")
print A
Escala(A)
def Escala(A):
print "Escala"
sx = input("Sx: ")
sy = input("Sy: ")
S = [(sx,0),(0,sy)]
print S
M = mult(S,A)
print M
def mult(m1,m2):
M = zero(len(m1),len(m2[0]))
for i in range(len(m2)):
for j in range(len(m2[0])):
for k in range(len(m1)):
M[i][j] += m1[k][j]*m2[k][j]
print M
return M
def zero(m,n):
# Create zero matrix
new_matrix = [[0 for row in range(n)] for col in range(m)]
return new_matrix
This seems wrong to me:
M[i][j] += m1[k][j]*m2[k][j]
shouldn't it be:
M[i][j] += m1[i][k]*m2[k][j]

Categories