Python returning two identical matrices - python

I am trying to write a small program for Markov Decision Process (inventory problem) using Python. I cannot figure out why the program outputs two identical matrices (for profit and decision matrices). The programming itself has some problems too because the last two columns are all zeros, which should not happen. Any help on the program itself would also be super helpful!
import math
import numpy as np
def salvageCost(b):
return 5 * b
def orderingCost(b):
if b == 0:
return 0
else:
return 4 + 2 * b
def holdingCost(b):
return 1.5 * b
def revenue(b):
return 8 * b
M = 10
N = 4
u = np.zeros((M+1,N))
T = np.array([4,3,2,1])
S = np.array(range(M+1))
A = np.array(range(M+1))
u[:,0] = S*5
d = np.zeros((11,4))
probs = np.array([0.05, 0.1, 0.15, 0.2, 0.2, 0.15, 0.1, 0.05, 0, 0, 0])
demands = np.array(range(11))
candidate = [0]*11
d = u
for i in T[1:N]:
for j in S:
for a in range(M-j+1):
candidate[a] = -holdingCost(j) - orderingCost(a) \
+ np.array([probs[k]for k in range(j+a)]).dot(8*np.array([demands[k]for k in range(j+a)])) \
+ np.array([probs[p] for p in range(min(j+a+1,M+1),M+1)]).dot(np.array(range(min(j+a+1,M+1),M+1)))*80\
+ probs.dot(u[:,i-1])
u[j,i] = max(candidate)
d[j,i] = candidate.index(max(candidate))
print(d)
print(u)
This is the output
[[ 0. 0. 0. 0.]
[ 5. 0. 0. 0.]
[10. 0. 0. 0.]
[15. 0. 0. 0.]
[20. 0. 0. 0.]
[25. 0. 0. 0.]
[30. 0. 0. 0.]
[35. 0. 0. 0.]
[40. 0. 0. 0.]
[45. 0. 0. 0.]
[50. 0. 0. 0.]]
[[ 0. 0. 0. 0.]
[ 5. 0. 0. 0.]
[10. 0. 0. 0.]
[15. 0. 0. 0.]
[20. 0. 0. 0.]
[25. 0. 0. 0.]
[30. 0. 0. 0.]
[35. 0. 0. 0.]
[40. 0. 0. 0.]
[45. 0. 0. 0.]
[50. 0. 0. 0.]]

This line:
d = u
points d and u to the same location in memory. As a result, any changes to d are reflected in u, and vice versa.
You are probably looking to create a copy of the contents of u, in which case you can use d = u.copy().

Because numpy.ndarrays are mutable, when you write
d = u
d and u point to the same matrix, so any change to d or to u affects both:
>>> import numpy as np
>>> x = np.array([1, 2])
>>> y = x
>>> y[0] = 10
>>> x
array([10, 2])

Related

How to insert the entered numbers into the diagonal

As usual, was practicing python and got this exercise:
Create a 4 * 4 matrix with values of 1,2,3,4 on the main diagonal of the
array.
Input and output legend:
Enter your value: 4
[[1. 0. 0. 0.]
[0. 2. 0. 0.]
[0. 0. 3. 0.]
[0. 0. 0. 4.]]
Did this so far, not much yeah but can't get how to approach to this task
import numpy as ar
x = ar.zeros((4, 4))
x[::2, 1::2] = 0
x[1::2, ::2] = 0
print(x)
You could use np.fill_diagonal() documentation
import numpy as np
x = np.zeros((4, 4))
np.fill_diagonal(x, [1,2,3,4])
print(x)
Output:
[[1. 0. 0. 0.]
[0. 2. 0. 0.]
[0. 0. 3. 0.]
[0. 0. 0. 4.]]
Automatically using the number from your input:
import numpy as np
input_val = int(input('Enter your value:'))
x = np.zeros((input_val, input_val))
np.fill_diagonal(x, range(1,input_val+1))
print(x)
Output:

Create 4-dimensional NxNxMxM array using 2-dimension NxM array as diagonal

I am looking to perform the following operation: A[i,j,a,b] = δ ij δ ab B[i,a]. Where A is a NxNxMxM array and B is a NxM array and the δ symbols corresponds to the Kronecker delta.
This can be easily done using explicit looping.
A = np.zeros((N,N,M,M))
for i in range(N):
for j in range(N):
for a in range(M):
for b in range(M):
if i == j and a == b:
A[i,j,a,b] = B[i,a]
However, there must be easier and faster ways to perform such operations.
A much shorter way (but still maybe not the most optimal) is to do the following:
Try it online!
import numpy as np
np.random.seed(4)
N, M = 2, 3
B = np.random.randint(0, 100, (N, M))
print(B)
A = np.zeros((N, N, M, M))
arange_m = np.arange(M)
for i in range(N):
A[(i, i, arange_m, arange_m)] = B[i, arange_m]
print(A)
Output:
[[46 55 69]
[ 1 87 72]]
[[[[46. 0. 0.]
[ 0. 55. 0.]
[ 0. 0. 69.]]
[[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]]]
[[[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]]
[[ 1. 0. 0.]
[ 0. 87. 0.]
[ 0. 0. 72.]]]]
I just found even shorter way doing same thing using mesh-grid:
Try it online!
import numpy as np
np.random.seed(4)
N, M = 2, 3
B = np.random.randint(0, 100, (N, M))
print(B)
A = np.zeros((N, N, M, M))
mg = np.meshgrid(np.r_[:N], np.r_[:M], sparse = True)
A[(mg[0], mg[0], mg[1], mg[1])] = B[(mg[0], mg[1])]
print(A)
Output:
[[46 55 69]
[ 1 87 72]]
[[[[46. 0. 0.]
[ 0. 55. 0.]
[ 0. 0. 69.]]
[[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]]]
[[[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]]
[[ 1. 0. 0.]
[ 0. 87. 0.]
[ 0. 0. 72.]]]]

In a 10 by 10 matrix, why does this array notation not work?

I would like to know why doesn't my following code output a 1. on the left and right side of the matrix:
import numpy as np
import matplotlib.pyplot as plt
N = 10
def dungeon(N):
dungeon = np.zeros((N, N))
# Top and bottom
dungeon[0] = 1
dungeon[-1] = 1
# Right side
#dungeon[1][0] = 1
#dungeon[2][0] = 1
# etc...
dungeon[0:3][0]
print(dungeon)
Why doesn't dungeon[0:3][0] output 1.'s on the left column? How can I fix this without individually writing dungeon[1][0], dungeon[2][0], etc...?
You are generating a 10x10 Matrix.
dungeon[0] = 1 sets all the elements in the 1st row to 1.
dungeon[-1] = 1 sets all the elements in the last row to 1.
You didn't set the right and left sides.
There are two ways to generate a 10x10 matrix which contains 0s in the center and 1s at the sides:
dungeon = np.ones((10, 10))
dungeon [1:-1, 1:-1] = 0
OR
dungeon = np.zeros((10, 10))
dungeon[0:N,0:1] = 1
dungeon[0:N,-1:N] = 1
dungeon[0:1,0:N] = 1
dungeon[-1:N,0:N] = 1
OUTPUT:
[[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]]
Just take the transpose!
import numpy as np
N = 10
def dungeon(N):
dungeon = np.zeros((N, N))
# Top and bottom
dungeon[0] = 1
dungeon[-1] = 1
# Right and left side
dungeon = dungeon.T
dungeon[0] = 1
dungeon[-1] = 1
print(dungeon)

How to scatter a smaller array in to a larger array using a list as index?

I need help to obtain the following type of result in Python (that I was used to in Matlab):
M = numpy.zeros((5,5))
m = numpy.array([[1,2,3],[4,5,6],[7,8,9]])
indx = [0, 2, 3]
# in Matlab: M(indx,indx) = M(indx,indx) + m
so that the output is:
[[ 1. 0. 2. 3. 0.]
[ 0. 0. 0. 0. 0.]
[ 4. 0. 5. 6. 0.]
[ 7. 0. 8. 9. 0.]
[ 0. 0. 0. 0. 0.]]

Python: Appending dimensions to a bidimensional array

Suppose you have an array (m, m) and want to make it (n, n). For example, transforming a 2x2 matrix to a 6x6. So:
[[ 1. 2.]
[ 3. 4.]]
To:
[[ 1. 2. 0. 0. 0. 0.]
[ 3. 4. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 0.]]
This is what I'm doing:
def array_append(old_array, new_shape):
old_shape = old_array.shape
dif = np.array(new_shape) - np.array(old_array.shape)
rows = []
for i in xrange(dif[0]):
rows.append(np.zeros((old_array.shape[0])).tolist())
new_array = np.append(old_array, rows, axis=0)
columns = []
for i in xrange(len(new_array)):
columns.append(np.zeros(dif[1]).tolist())
return np.append(new_array, columns, axis=1)
Example use:
test1 = np.ones((2,2))
test2 = np.zeros((6,6))
print array_append(test1, test2.shape)
Output:
[[ 1. 1. 0. 0. 0. 0.]
[ 1. 1. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 0.]]
Based on this answer. But that's a lot of code for an (imho) simple operation. Is there a more concise/pythonic way to do it?
Why not use array = numpy.zeros((6,6)), see the numpy docs...
EDIT, woops, question has been edited... I guess you are trying to put ones in a section of an array filled with zeros? Then:
array = numpy.zeros((6,6))
array[0:2,0:2] = 1
If the small matrix does not all have the value of 1:
array[ystart:yend,xstart:xend] = smallermatrix
That would be then:
# test1= np.ones((2, 2))
test1= np.random.randn((2, 2))
test2= np.zeros((6, 6))
test2[0: 2, 0: 2]= test1

Categories