I made a recursive function to compute the determinant of a matrix, based on the cofactors:
# determinant of a 2x2 matrix
def det2(matrix):
return matrix[0][0]*matrix[1][1]-matrix[1][0]*matrix[0][1]
# recursive part
def recursion(matrix,somme=None,prod=1):
if(somme==None):
somme=[]
if(len(matrix)==1):
somme.append(matrix[0][0])
elif(len(matrix)==2):
somme.append(det2(matrix)*prod)
else:
for index, elmt in enumerate(matrix[0]):
transposee = [list(a) for a in zip(*matrix[1:])]
transposee.remove(transposee[index])
mineur = [list(a) for a in zip(*transposee)]
somme = recursion(mineur,somme,prod*matrix[0][index]*(-1)**(index+2))
return somme
def main(matrix):
return sum(recursion(matrix))
Nothing complicated, except I don't understand why it doesn't work. It does give the right answer in some cases, but not all.
I suspect the result is wrong when there are 0s in the matrix, but I'm not sure.
If you have any idea,
Thanks
I think your problem is probably here:
transposee.remove(transposee[index])
The remove removes the first occurence of the value passed to it from the list. Your test matrix has several duplicate values and so the one removed may not be the one you want removed to create your mineur array.
Your algorithm works for random arrays because such duplicates are unlikely to occur in this case.
To make your program work, replace the line with
del transposee[index]
which will remove specifically the value at index.
Related
I'm writing a code (using Python) to simultaneously diagonalize two commuting matrices A and B, and hoping to create a dictionary to do this. Here, 'keys' are the eigenvalues, and 'values' are eigenvectors (may or may not be degenerate). Here's the program I've written. However, it cannot give me all the eigenvectors with shared eigenvalue. I guess I need to change something in my code to accommodate degeneracy, but how can I do this? Thanks!
def simultaneous_eig(A, B):
epsilon = 10**-10
vals, vecs = la.eig(A)
degen = {}
for n in range(0,len(vals)):
for m in range(0,n):
#equality up to certain precision
if np.abs(vals[m]-vals[n]) < epsilon:
degen.get(vals[m], vecs[:,n])
degen[vals[n]] = np.array([vecs[:,n]])
return degen
I found a few issues in your function. First, to achieve the recursive comparison you are trying to make, the outer loop should go from 0 to len(vals)-1, and the inner loop should be from “n” to len(vals), as seen in my corrected snippet below.
Also, the “.get()” method for dictionaries does not modify in place. In other words, you must assign the output to a variable within the “if” clause (again, see corrected code below).
Finally, to avoid extra singleton dimensions, avoid putting “[]” around the variable you wish to convert to a numpy array.
The revised function below should solve your problems. I wasn’t able to test it completely, so let me know if there are still issues.
Happy coding!
def simultaneous_eig(A, B):
epsilon = 10**-10
vals, vecs = la.eig(A)
degen = {}
for n in range(0,len(vals)-1):
for m in range(n+1,len(vals)):
#equality up to certain precision
if np.abs(vals[m]-vals[n]) < epsilon:
vecs[:,n] = degen.get(vals[m])
degen[vals[n]] = np.array([vecs[:,n]])
return degen
Depending on the size of the values in your matrices, you may be using the wrong criterion for "almost equal". For example, when comparing scalars, 1E-20 and 1.1E-20 would be "almost equal" according to your criterion, but 1E20 and 1.1E20 would not be, even though the relative error is the same.
Why not just use math.isclose?
I am trying to make an algorithm that propagates from point to point in a distance matrix using the smallest distance in the proximity. The code has two conditions: the minimum distance must be no less than 0 and each point must be visited once and return to the starting position.
This is my code in its entirety:
def totalDistance(aList):
path = []
for j in range(0,len(aList)):
k=j
order = []
for l in range(0,len(aList)):
order.append(k)
initval= min(x for x in aList[k] if x > 0 )
k = aList[k].index(initval)
for s in range(0,len(aList)):
for t in range(0,len(aList[s])):
aList[s][k] = 0
path.append(order)
return path
The code is meant to return the indexes of the points in within the closes proximity of the evaluated point.
aList = [[0,3,4,6],[3,0,7,3],[4,7,0,9],[6,3,9,0]] and represents the distance matrix.
When running the code, I get the following error:
initval= min(x for x in aList[k] if x > 0 )
ValueError: min() arg is an empty sequence
I presume that when I make the columns in my distance matrix zero with the following function:
for s in range(0,len(aList)):
for t in range(0,len(aList[s])):
aList[s][k] = 0
the min() function is unable to find a value with the given conditions. Is there a better way to format my code such that this does not occur or a better approach to this problem all together?
One technique and a pointer on the rest that you say is working...
For preventing re-visiting / backtracking. One of the common design patterns for this is to keep a separate data structure to "mark" the places you've been. Because your points are numerically indexed, you could use a list of booleans, but I think it is much easier to just keep a set of the places you've been. Something like this...
visited = set() # places already seen
# If I decide to visit point/index "3"...
visited.add(3)
Not really a great practice to modify your input data as you are doing, and especially so if you are looping over it, which you are...leads to headaches.
So then... Your current error is occurring because when you screen the rows for x>0 you eventually get an empty list because you are changing values and then min() chokes. So part of above can fix that, and you don't need to zero-ize, just mark them.
Then, the obvious question...how to use the marks? You can just use it as a part of your search. And it can work well with the enumerate command which can return index values and the value by enumeration.
Try something like this, which will make a list of "eligible" tuples with the distance and index location.
pts_to_consider = [(dist, idx) for idx, dist in enumerate(aList[k])
if dist > 0
and idx not in visited]
There are other ways to do this with numpy and other things, but this is a reasonable approach and close to what you have in code now. Comment back if stuck. I don't want to give away the whole farm because this is probably H/W. Perhaps you can use some of the hints here.
Is there any neat way to check is numpy array surrounded by zeros.
Example:
[[0,0,0,0],
[0,1,2,0],
[0,0,0,0]]
I know I can iterate it element wise to find out but I wonder is there any nice trick we can use here. The numpy array is of floats, n x m of arbitrary size.
Any ideas are welcome.
You can use numpy.any() to test if there is any non-zero element in numpy array.
Now, to test if a 2D array is surrounded by zeroes, you can get first and last columns as well as first and last rows and test if any of those contains a non-zero number.
def zero_surrounded(array):
return not (array[0,:].any() or array[-1,:].any() or array[:,0].any() or array[:,-1].any())
We can check this by constructing two submatrices:
A[[0,-1]] the first and the last row, including the first and last column; and
A[1:-1,[0,-1]] the first and last column, excluding the first and last row.
All the values of these matrices should be equal to zero, so we can use:
if np.all(A[[0,-1]] == 0) and np.all(A[1:-1,[0,-1]] == 0):
# ...
pass
This works for an arbitrary 2d-array, but not for arrays with arbitrary depth. We can however use a trick for that as well.
For an arbitrary matrix, we can use:
def surrounded_zero_dim(a):
n = a.ndim
sel = ([0,-1],)
sli = (slice(1,-1),)
return all(np.all(a[sli*i+sel] == 0) for i in range(n))
Using the slice is strictly speaking not necessary, but it prevents checking certain values twice.
Not the fastest, but perhaps the shortest (and hence a "neat") way of doing it:
surrounded = np.sum(a[1:-1, 1:-1]**2) == np.sum(a**2)
print(surrounded) # True
Here, a is the array.
This compares the sum of all squared elements to the sum of all squared elements except for those on the boundary. If we left out the squaring, cases where positive and negative boundary values add up to zero would produce the wrong answer.
so as homework for a programming class on python we're supposed to multiply to integers (n,m) with each other WITHOUT using the * sign (or another multiplication form). We're supposed to use recursion to solve this problem, so i tried just adding n with itself, m number of times. I think my problem is with using recursion itself. I have searched on the internet for recursion usage, no results. Here is my code. Could someone point me in the right direction?
def mult(n,m):
""" mult outputs the product of two integers n and m
input: any numbers
"""
if m > 0:
return n + n
return m - 1
else:
return 1
I don't want to give you the answer to your homework here so instead hopefully I can provide an example of recursion that may help you along :-).
# Here we define a normal function in python
def count_down(val):
# Next we do some logic, in this case print the value
print(val)
# Now we check for some kind of "exit" condition. In our
# case we want the value to be greater than 1. If our value
# is less than one we do nothing, otherwise we call ourself
# with a new, different value.
if val > 1:
count_down(val-1)
count_down(5)
How can you apply this to what you're currently working on? Maybe, instead of printing something you could have it return something instead...
Thanks guys, i figured it out!!!
i had to return 0 instead of 1, otherwise the answer would always be one higher than what we wanted.
and i understand how you have to call upon the function, which is the main thing i missed.
Here's what i did:
def mult(n,m):
""" mult outputs the product of two integers n and m
input: any numbers
"""
if m == 0:
return 0
else:
return n + mult(n, m - 1)
You have the right mechanics, but you haven't internalized the basics you found in your searches. A recursive function usually breaks down to two cases:
Base Case --
How do you know when you're done? What do you want to do at that point?
Here, you've figured out that your base case is when the multiplier is 0. What do you want to return at this point? Remember, you're doing this as an additive process: I believe you want the additive identity element 0, not the multiplicative 1.
Recursion Case --
Do something trivial to simplify the problem, then recur with this simplified version.
Here, you've figured out that you want to enhance the running sum and reduce the multiplier by 1. However, you haven't called your function again. You haven't properly enhanced any sort of accumulative sum; you've doubled the multiplicand. Also, you're getting confused about recursion: return is to go back to whatever called this function. For recursion, you'll want something like
mult(n, m-1)
Now remember that this is a function: it returns a value. Now, what do you need to do with this value? For instance, if you're trying to compute 4*3, the statement above will give you the value of 4*2, What do you do with that, so that you can return the correct value of 4*3 to whatever called this instance? You'll want something like
result = mult(n, m-1)
return [...] result
... where you have to fill in that [...] spot. If you want, you can combine these into a single line of code; I'm just trying to make it easier for you.
I am using Python to solve Project Euler problems. Many require caching the results of past calculations to improve performance, leading to code like this:
pastResults = [None] * 1000000
def someCalculation(integerArgument):
# return result of a calculation performed on numberArgument
# for example, summing the factorial or square of its digits
for eachNumber in range(1, 1000001)
if pastResults[eachNumber - 1] is None:
pastResults[eachNumber - 1] = someCalculation(eachNumber)
# perform additional actions with pastResults[eachNumber - 1]
Would the repeated decrementing have an adverse impact on program performance? Would having an empty or dummy zeroth element (so the zero-based array emulates a one-based array) improve performance by eliminating the repeated decrementing?
pastResults = [None] * 1000001
def someCalculation(integerArgument):
# return result of a calculation performed on numberArgument
# for example, summing the factorial or square of its digits
for eachNumber in range(1, 1000001)
if pastResults[eachNumber] is None:
pastResults[eachNumber] = someCalculation(eachNumber)
# perform additional actions with pastResults[eachNumber]
I also feel that emulating a one-based array would make the code easier to follow. That is why I do not make the range zero-based with for eachNumber in range(1000000) as someCalculation(eachNumber + 1) would not be logical.
How significant is the additional memory from the empty zeroth element? What other factors should I consider? I would prefer answers that are not confined to Python and Project Euler.
EDIT: Should be is None instead of is not None.
Not really an answer to the question regarding the performance, rather a general tip about caching previously calculated values. The usual way to do this is to use a map (Python dict) for this, as this allows to use more complex keys instead of just integer numbers, like floating point numbers, strings, or even tuples. Also, you won't run into problems in case your keys are rather sparse.
pastResults = {}
def someCalculation(integerArgument):
if integerArgument not in pastResults:
pastResults[integerArgument] = # calculation performed on numberArg.
return pastResults[integerArgument]
Also, there is no need to perform the calculations "in order" using a loop. Just call the function for the value you are interested in, and the if statement will take care that, when invoked recursively, the function is called only once for each argument.
Ultimately, if you are using this a lot (as clearly the case for Project Euler) you can define yourself a function decorator, like this one:
def memo(f):
f.cache = {}
def _f(*args, **kwargs):
if args not in f.cache:
f.cache[args] = f(*args, **kwargs)
return f.cache[args]
return _f
What this does is: It takes a function and defines another function that first checks whether the given parameters can be found in the cache, and otherwise calculates the result of the original function and puts it into the cache. Just add the #memo annotation to your function definitions and this will take care of caching for you.
#memo
def someCalculation(integerArgument):
# function body
This is syntactic sugar for someCalculation = memo(someCalculation). Note however, that this will not always work out well. First, the paremters have to be hashable (no lists or other mutable types); second, in case you are passing parameters that are not relevant for the result (e.g., debugging stuff etc.) your cache can grow unnecessarily large, as all the parameters are used as the key.