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

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.]]]]

Related

Python returning two identical matrices

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

Why does reshape work differently for Transpose and return a new nd array?

Why does reshape return a new array when transposed and return view when not transposed? When does it return views and when a new array?
a = np.zeros((3,2))
b = a.T.reshape(3*2)
c = a.reshape(3*2)
print(a)
c[2] = 10000
b[0] = 10000
print(a)
print(b)
Result
[[0. 0.]
[0. 0.]
[0. 0.]]
[[ 0. 0.]
[10000. 0.]
[ 0. 0.]]
[10000. 0. 0. 0. 0. 0.]

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.]]

Tridiagonal Matrix with Matrix Blocks

I read this, but I wasn't able to create a (N^2 x N^2) - matrix A with (N x N) - matrices I on the lower and upper side-diagonal and T on the diagonal. I tried this
def prep_matrix(N):
I_N = np.identity(N)
NV = zeros(N*N - 1)
# now I want NV[0]=NV[1]=...=NV[N-1]:=I_N
but I have no idea how to fill NV with my matrices. What can I do? I found a lot on how to create tridiagonal matrices with scalars, but not with matrix blocks.
You could initialize like this:
n = 3
I, T, A = np.identity(n), np.ones(n), np.zeros([n * n, n * n])
for i in range(n):
a, b, c = i * n, (i + 1) * n, (i + 2) * n
A[a:b, a:b] = T
if i < n - 1: A[b:c, a:b] = A[a:b, b:c] = I
The above example has the following output:
[[ 1. 1. 1. 1. 0. 0. 0. 0. 0.]
[ 1. 1. 1. 0. 1. 0. 0. 0. 0.]
[ 1. 1. 1. 0. 0. 1. 0. 0. 0.]
[ 1. 0. 0. 1. 1. 1. 1. 0. 0.]
[ 0. 1. 0. 1. 1. 1. 0. 1. 0.]
[ 0. 0. 1. 1. 1. 1. 0. 0. 1.]
[ 0. 0. 0. 1. 0. 0. 1. 1. 1.]
[ 0. 0. 0. 0. 1. 0. 1. 1. 1.]
[ 0. 0. 0. 0. 0. 1. 1. 1. 1.]]
For the sake of art, another approach based on bmat():
Z = np.zeros((n, n))
I = np.eye(n)
T = np.ones((n, n))*2
B = np.diag([1]*n) + np.diag([2]*np.ones(n-1), 1) + np.diag(2*np.ones(n-1), -1)
# B = array([[ 1., 2., 0.],
# [ 2., 1., 2.],
# [ 0., 2., 1.]])
# build 2d list `Bm` replacing 0->Z, 1->T, 2->I:
bdict = {0.:Z, 1.:T, 2.:I}
Bm = [[bdict[i] for i in rw] for rw in B]
# Use the power of bmat to construct matrix:
A = np.asarray(np.bmat(Bm))

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