About np.einsum - python

I don't understand how the following code realizes the transformation of dimensions? The shape of C is [2, 3, 3, 4]. How to realize the following matrix operation without einsum function?
import numpy as np
a = np.random.randint(0, 10, (2,3,4))
b = np.random.randint(0, 10, (3, 6, 4))
c = np.einsum('bld,hid-> blhd', a,b)

You can find more details in about einstein notation wikipedia
This means that you have indices b,l,h,i,d
this will iterate the indices to cover all the inputs and build the input
I will use capital letters for the arrays here to distinguish from the indices.
C[b,l,h,d] += A[b,l,d] * B[h,i,d]
The shape of the output can be determined as follows.
You take the index of each output axis and look for the same index in the input. For instance the first axis of C is indexed with b that is also used to index the first axis of A, thus assert C.shape[0] == A.shape[0]. Repeating for the other axes we have assert C.shape[1] == A.shape[1], assert C.shape[2] == B.shape[0], and assert C.shape[3] == A.shape[2], also assert C.shape[3] == B.shape[2].
Notice that the index i does not affect where the term will be added, each element of the output can be written as
C[b,l,h,d] = sum(A[b,l,d] * B[h,i,d] for i in range(B.shape[1]))
Notice also that i is not used to index A. So this could be also written as
C[b,l,h,d] = A[b,l,d] * B[h,:,d].sum();
Or if you want to use vectorized operation
first expanding then reducing
C = A[:,:,None,:] * B[None,None,:,:,:].sum(-2)
expanding reducing then expandin, possible because A does not use i
C = A[:,:,None,:] * B.sum(-2)[None,None,:,:]

To answer your first question
c = np.einsum('bld,hid->blhd', a,b)
implements the formula
which, if you don't want to use einsum, you can achieve using
c = a[:, :, None, :] * b.sum(-2)[None, None, :, :]
# b l (h) d i (b) (l) h d

Related

Vectoring for loop in Python [duplicate]

This question already has answers here:
NumPy selecting specific column index per row by using a list of indexes
(7 answers)
Closed 4 days ago.
I am having a difficulty vectorizing the following for loops in Python.
out = np.zeros((N, d))
dir_int = []
for i in range(N):
dir_int.append(np.random.randint(low=0, high = d))
out[i,dir_int[i]] = 1
#where:
# direct_int has shape (N, )
# u has shape (N, d)
# x has the same shape as u
# A has shape (2d, d) = [I,-I]^T, I the dxd identity
# b has shape (2d, )
bmAx = b - np.concatenate((x,-x), axis=1) #This is b-Ax has shape N x 2d
upper = np.copy(x)
lower = np.copy(x)
temp = np.zeros(2)
for i in range(len(dir_int)):
temp[0] = bmAx[i, dir_int[i]]
temp[1] = -bmAx[i, d + dir_int[i]]
upper[i, dir_int[i]] += np.amax(temp)
lower[i, dir_int[i]] += np.amin(temp)
For the first loop, dir_int can be created as dir_int = np.random.randint(low=0, high = d, size = N). Then for each "row" of out one of its columns should be 1; this column is dir_int[row]. Not sure how to do that in one line.
The second loop is even harder than the first. Any help is much appreaciated.
The first loop comes out as
out = np.zeros((N, d))
dir_int = np.random.randint(0, d, N)
out[np.arange(N), dir_int] = 1
and it it's a bit harder to help with the second one, since b and x are undefined and I'm not sure I'm visualizing the desired output. But you should be able to use dir_int to index into bMax to update an entire N-length column at a time.

Matlab to Python

I have a simple code in MATLAB which I am trying to translate to python, but I am stuck in a simple for loop:
Here is the situation:
Matlab
f0 = constant
fn = (nx1) matrix
b = (nx1) matrix
d and x are constant
mthd = 1 or 2
s = 1:-0.1:0.1;
for i = 1:10
f = fn * s(i)
switch mthd
case 1
v(:,i) = d *(1 + 1./b.*(f0./f)).^x
case 2
v(:,i) = log(f0./f)./b;
v(:,i) = v./(1+v)
end
v(1,:) = min(vp(2,:));
The output in Matlab results v with nx1 matrix
Assuming it is a simple equation with element wise operation in matlab,
I went ahead and wrote a code in python like this:
s = np.linspace(1,0.1,num=10)
for i in range(1,11)
f = fn * s[i]
if mthd ==1:
v = d *(1 + 1/b*(f0/f))^x
elif mthd ==2:
v = log(f0/f)/b;
v = v/(1+v)
Clearly, this is not the right one and I get stuck right from f = fn* s[i]
Any suggestion in this conversion will be of great help.
Thank you
Clearly this is not the right one and I get stuck right from f = fn* s[i]
What error message are you getting here? Make sure your vectors fn and b are numpy arrays and not lists.
for i in range(1,11)
Python uses zero indexing, whereas Matlab uses 1-indexing. Therefore your for loop should use for i in range(10), which iterates from 0 to 9 instead of 1 to 10.
v = d *(1 + 1/b*(f0/f))^x
Assuming fn and b are numpy arrays in your Python implementation, if you really want this to mirror the Matlab code you can still use indexing such as v[:,i]. However you need to initialize v as a numpy array with the correct size first.
v = log(f0/f)/b;
You probably want np.log here.
Hopefully this is helpful, let me know if you still have questions. You may also find this website helpful.
The code block below should be closer to what you want. Here are a few things to look out for:
Phyton arrays are indexed from 0. In base Python you handle powers with ** e.g. 2 ** 2 equals 4
When performing scalar multiplication and divide of arrays, better to use np.multiply and np.divide
Use np.log for logarithm and np.power for exponentiation with numpy matrices.
Use np.add to add a scalar to a numpy array.
import numpy as np
f0 = 5 # constant
fn = np.matrix([[5], [4], [3], [2], [1]]) # 5 x 1 matrix
b = np.matrix([[9], [8], [7], [6], [5]]) # 5 x 1 matrix
# d and x are constant
d = 4
x = 8
# mthd = 1 or 2
mthd = 1
s = np.linspace(1,0.1,num=10)
# python arrays are indexed from 0
for i in range(0,len(s)):
f = fn * s[i]
if mthd == 1:
v = np.power(np.multiply(d, (1 + np.divide(1., np.multiply
(b, np.divide(f0, f) ) ) ) ), x)
elif mthd ==2:
v = np.divide(np.log(np.divide(f0,f)), b);
v = np.divide(v, (np.add(1, v)) )

Efficient matrix multiplication in Matlab

I have two matrices, A (N by K) and B (N by M) and I would like to concentrate A and B into a tensor C (N by K by M) where C(n,k,m) = A(n,k) * B(n,m). I know how to do it in python like
C = B[:,numpy.newaxis,:] * A[:,:,numpy.newaxis]
Can anyone please tell me the matlab code that does the same thing efficiently?
Take advantage of the implicit expansion feature of bsxfun. Use permute to have your B as an Nx1xM matrix:
C = bsxfun(#times, A, permute(B, [1, 3, 2]));
And from MATLAB R2016b onward, you can get the same result in this way:
C = A * permute(B, [1, 3, 2]);

Nested for Loop optimization in python

i want to optimize 2 for loops into single for loop, is there any way as length of array is very large.
A = [1,4,2 6,9,10,80] #length of list is very large
B = []
for x in A:
for y in A:
if x != y:
B.append(abs(x-y))
print(B)
not any better but more pythonic:
B = [abs(x-y) for x in A for y in A if x!=y]
unless you absolutely need duplicates (abs(a-b) == abs(b-a)), you can half your list (and thus computation):
B = [abs(A[i]-A[j]) for i in range(len(A)) for j in range(i+1, len(A))]
finaly you can use the power of numpy to get C++ speedup:
import numpy as np
A = np.array(A)
A.shape = -1,1 # make it a column vector
diff = np.abs(A - A.T) # diff is the matrix of abs differences
# grab upper triangle of order 1 (i.e. less the diagonal)
B = diff[np.triu_indices(len(A), k=1)]
But this will always be O(n^2) no matter what...

np.tile to repeat an 1D array

I have an ndarray, A,
and I want to multiply this ndarray element wise by another 1D array b where I assume that A.shape[i] = len(b) for some i. I need this generality in my application.
I can do this using np.tile as follows:
A = np.random.rand(2,3,5,9)
b = np.random.rand(5)
i = 2
b_shape = np.ones(len(A.shape), dtype=np.int)
b_shape[i] = len(b)
b_reps = list(A.shape)
b_reps[i] = 1
B = np.tile(b.reshape(b_shape), b_reps)
# Here B.shape = A.shape and
# B[i,j,:,k] = b for all i,j,k
This strikes me as ugly. Is there a better way to do this?
For this particular example, the following code would do the trick:
result = A*b[:, np.newaxis]
For any value of i, try this:
A2, B = np.broadcast_arrays(A, b)
result = A2*B

Categories