python function making unrequested changes - python

I have a function (crout) defined in a file called LU.py and another function defined in a different file (invert.py). The contents of the files are:
LU.py
def crout(A,L,U):
N = len(A)
add = 0
#print(L,U)
for i in range(N):
print('b',L[i][i])
U[i][i] = 1
print('a',L[i][i])
#print(L,U)
and invert.py
import LU
def inverse(A):
n = len(A)
B = []
L = []
U = []
for i in range(n):
row = [0 for j in range(n)]
B.append(row)
L.append(row)
U.append(row)
LU.crout(A,L,U)
return B
M = [[1,2,3],[1,0,1],[2,2,0]]
Mi = inverse(M)
A = [[1,2,3],[1,0,1],[2,2,0]]
L = [[0,0,0],[0,0,0],[0,0,0]]
U = [[0,0,0],[0,0,0],[0,0,0]]
print('bla')
LU.crout(A,L,U)
Notice that I run the function crout two times from the invert file, once from the inverse function and once from outside the function.
Next, I run the invert.py file using python 2.7.6 on an ubuntu linux machine and I get the following output:
('b',0)
('a',1)
('b',0)
('a',1)
('b',0)
('a',1)
bla
('b',0)
('a',0)
('b',0)
('a',0)
('b',0)
('a',0)
The numbers before the 'bla' which is the call of crout from within inverse, represent the elements of the diagonal in array L. Notice that these values change from 0 ('b') to 1 ('a') as I change the values in U (which off course should not happen!). On the other hand, when I call crout from outside the function inverse the values in L remain unchanged after changing U, which off course is what should happen.
Any ideas about why this is happening would be very much appreciated!
Carlos

In inverse, you append the row variable to each of B, L, and U.
for i in range(n):
row = [0 for j in range(n)]
B.append(row)
L.append(row)
U.append(row)
Now each list contains a reference to the same row value. changing a value in one of the lists will change the accompanying value in each other one. If this is not the desired behavior, create a new row for each list.
for i in range(n):
B.append([0 for j in range(n)])
L.append([0 for j in range(n)])
U.append([0 for j in range(n)])
If this looks a bit inelegant to you, it may be useful to make an independent function for matrix creation logic.
def make_square_matrix(size):
return [[0]*size for b in range(size)]
def inverse(A):
n = len(A)
B = make_square_matrix(n)
L = make_square_matrix(n)
U = make_square_matrix(n)
LU.crout(A,L,U)
return B

Related

Using output of a function as an input in a different function

I'm trying to create a function in python (without numpy) that would imitate matrix multiplication in numpy. The program contains 2 functions. First function takes in 2 lists (l1 and l2) as input and creates a dummy list (dummy). The second function does the matrix multiplication of the lists l1 and l2 and inputs the values in the dummy list (dummy). The issue is that in the final output, the column values are being added and repeated in each row. However, if I hard code the dummy list in the program, it is giving correct output. If I run the first function to create dummy list separately, I'm getting correct output. Not sure where I'm going wrong. Providing both the codes below. Please help.
#Following code is giving me erroneous result:
l1 = [[1,2],[3,4],[5,6]]
l2 = [[7,8,0],[9,10,5]]
def dummy_matrix(l1,l2):
g = len(l1)
h = len(l2[0])
m = []
p = []
for j in range(h):
p.append(0)
for i in range(g):
m.append(p)
dummy = m
return(dummy)
def mat_mul(l1,l2):
f = dummy_matrix(l1,l2)
for a in range(len(l1)):
for b in range(len(l2[0])):
for c in range(len(l2)):
f[a][b] += l1[a][c]*l2[c][b]
return(f)
mat_mul(l1,l2)
#Following code has hard coded dummy list and is giving correct output
l1 = [[1,2],[3,4],[5,6]]
l2 = [[7,8,0],[9,10,5]]
def dummy_matrix(l1,l2):
g = len(l1)
h = len(l2[0])
m = []
p = []
for j in range(h):
p.append(0)
for i in range(g):
m.append(p)
dummy = m
return(dummy)
def matrix_multi(l1,l2):
f = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
for a in range(len(l1)):
for b in range(len(l2[0])):
for c in range(len(l2)):
f[a][b] += l1[a][c]*l2[c][b]
return(f)
matrix_multi(l1,l2)
You create your dummy_matrix wrong. You first create a row called p, append some zeros to it and then you append the same row multiple times.
dm = dummy_matrix(l1, l2)
dm[1][2] = 1
print(dm)
You can notice that this will modify multiple rows, showing that they are in fact the same reference.
You need to create fresh list for each row:
m = []
for i in range(g):
p = []
for j in range(h):
p.append(0)
m.append(p)

python inverse matrix without numpy

I can't figure it out what's wrong with my code, it's rly frustrating.
I have to make inverse matrix function, what I thought I've done. I don't know why it doesn't work. The problem is probably in line with stars, after this step my matrix named mat is changed to identity matrix, but why? Before stars it prints my mat matrix normaly which I gave to function, but after stars it's a identity matrix, I don't understand why it happend. Here's what I have:
def identity_matrix_convertion(m):
x = m[:]
for i in range(len(x)):
for j in range(len(x[0])):
if i == j:
x[i][j] = 1
else:
x[i][j] = 0
return x
def inverse_matrix(mat):
n = len(mat)
am = mat[:]
show_matrix(mat)
**i = identity_matrix_convertion(am)**
show_matrix(mat)
im = i[:]
ind = list(range(n))
print(len(mat))
if determinant(mat) == 0:
print("This matrix doesn't have an inverse.")
if len(mat) == len(mat[0]):
for i in range(n):
scal = 1.0 / am[i][i]
for j in range(n):
am[i][j] *= scal
im[i][j] *= scal
for k in ind[0:i] + ind[i + 1:]:
current_scal = am[k][i]
for l in range(n):
am[k][l] = am[k][l] - current_scal * am[i][j]
im[k][l] = im[k][l] - current_scal * im[i][j]
return im
so after line **i = identity_matrix_convertion(am)** my mat matrix is changed into identity matrix, but why?
The result is:
1.0 2.0 3.0
2.0 1.0 3.0
4.0 3.0 2.0
The result is:
1 0 0
0 1 0
0 0 1
Instead of saying x = m[:] in the identity_matrix_convertion() function, you should add the following snippet:
x = []
for i in m:
arr = [a for a in i]
x.append(arr)
x = m[:] is still referencing m instead of just making a copy.
Following up on #NumberC's answer, the x = m[:] does make a copy, but only a shallow copy. The copied list will contain references to internal lists of the other list, and so manipulating those lists within x cause change in m too. This is because we represent the 2D matrix as list of lists. If someone would reorder the lists in m (so not the items within the lists but just the pure order of the lists within m) the order would stay the same in the x copy. However any change within the list of the lists is mutating the other too. I hope this is not confusing, List changes unexpectedly after assignment. Why is this and how can I prevent it? has some figures.
Since we don't have to scare away from [:] we can still say:
x = new_list = [y[:] for y in m]
Or even better: we can use the built-in copy module (available everywhere):
import copy
x = copy.deepcopy(m)
See also: Copying nested lists in Python

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

Transposing a list of lists in python

Why does this code doesn't transpose the list of list
import sys
t = input()
for k in range(t):
n,m = [int(i) for i in raw_input().strip().split()]
A = [[None]*m]*n
B = [[None]*n]*m
for l in range(n):
A[l] = raw_input().strip().split()
for j in range(m):
for i in range(n):
B[j][i] = A[i][j]
print B
I know there are better methods to transpose a matrix but why does this doesn't work?
Replace
A = [[None]*m]*n
B = [[None]*n]*m
with
A = [[None for x in range(m)] for x in range(n)]
B = [[None for x in range(n)] for x in range(m)]
Why?
>>> l = [2]*5
>>> l
[2,2,2,2,2]
>>> [id(value) for value in l]
[26089400, 26089400, 26089400, 26089400, 26089400]
Can you see what happened there?
There's just one copy in memory holding a value '2'. All list elements are pointing to that same memory location holding the value '2'.
So, when you do:
A = [[None]*m]*n
you are creating a 2d array with elements pointing to the same memory location. Changing one of them, changes the value stored at that common memory location, hence changes value stored by all the elements!
That is why the program didn't work.
Read more about how all this works in Python, in detail, here:
http://foobarnbaz.com/2012/07/08/understanding-python-variables/

Knapsack algorithm dynamic programming .(incorrect output) here is what I have so far

I wrote this code for dynamic programming implementation of the knapsack problem.
#B = maximum weight
#n = number of items
#p = list of weights
#a = list of values
#p[i] = weight with value a[i]
def maximum_attractiveness(n, B, p, a):
f = [i for i in range(n+1)]
m = [f for i in range(B+1)]
m[0] = [0 for i in range(len(m[0]))]
for i in m:
i[0] = 0
print(m)
for j in range(n):
for w in range(B):
if (p[j]) > (w):
m[w][j] = m[w][j-1]
else:
m[w][j] = max(m[w][j-1],m[w-p[j]][j-1]+a[j])
return m[B][n]
I get an incorrect output for this algorithm. where did I go wrong?
f = [i for i in range(n+1)]
m = [f for i in range(B+1)]
This uses the same array f for every position m, so for example if you change m[1][k], you also change m[i][k] for every i. You probably meant to do
m = [[i for i in range(n+1)] for i in range(B+1)]
There might be some other bugs I think, so maybe you should print out the intermediate arrays at some points to check out where the results are not what you'd expect them to be.
UPDATE:
Your initialization seems strange to me. I think it should be just m = [[0]*n for i in range(B+1)] because you need a matrix of zeroes.
it should be for w in range(B+1)
you should not return m[B][n], but max(m[j][n] for j in range(B+1)).
My attempt, which avoids the the matrix altogether and only uses a single array:
m = [0]*(B+1)
for j in range(n):
for w in range(B,p[j]-1,-1):
m[w] = max(m[w], m[w-p[j]] + a[j])
return max(m)

Categories