Matrix multiplication with numpy.einsum - python

I have the following two arrays with shape:
A = (d,w,l)
B = (d,q)
And I want to combine these into a 3d array with shape:
C = (q,w,l)
To be a bit more specific, in my case d (depth of the 3d array) is 2, and i'd first like to multiply all positions out of w * l in the upper layer of A (so d = 0) with the first value of B in the highest row (so d=0, q=0). For d=1 I do the same, and then sum the two so:
C_{q=0,w,l} = A_{d=0,w,l}*B_{d=0,q=0} + A_{d=1,w,l}*B_{d=1,q=0}
I wanted to calculate C by making use of numpy.einsum. I thought of the following code:
A = np.arange(100).reshape(2,10,5)
B = np.arange(18).reshape(2,9)
C = np.einsum('ijk,i -> mjk',A,B)
Where ijk refers to 2,10,5 and mjk refers to 9,10,5. However I get an error. Is there some way to perform this multiplication with numpy einsum?
Thanks

Your shapes A = (d,w,l), B = (d,q), C = (q,w,l) practically write the einsum expression
C=np.einsum('dwl,dq->qwl',A,B)
which I can test with
In [457]: np.allclose(A[0,:,:]*B[0,0]+A[1,:,:]*B[1,0],C[0,:,:])
Out[457]: True

Related

Fastest way to find locations from other numpy array(same shape) and calculate horizontal sum

Hi let's say there are two numpy 2D arrays A, B with same shape.
I am trying to get elements from A where B element equals to x, and get horizontal sum of these elements at A.
I tried two following ways but they were both slow,,(it is big array)
Can somebody advice me faster way? Thank you.
First
farr = np.stack([np.where(rarr == d, varr, 0).sum(axis=1) for d in digits])
Second
#njit
def final_array(varr, rarr, digits):
farr = np.zeros((len(varr), len(digits)))
for i, d in enumerate(digits):
farr[:,i] = np.where(rarr == d, varr, 0).sum(axis=1)
return farr
farr = final_array(varr, rarr, digits)

Numpy function operating on two ndarrays

Given two ndarrays a = np.asarray([[0,1,2],[3,4,5]]) and b = np.asarray([[6,7,8],[9,10,11]])I want to write a function that iterates over a and b, such that
[0,1,2] and [6,7,8] are considered
[3,4,5] and [9,10,11] are considered
An example would be a functionn that takes
[0,1,2] and [6,7,8] as an input and outputs 0*6+1*7+2*8 = 23
[3,4,5] and [9,10,11] as an input and outputs 3*9+4*10+5*11 = 122
-> (23,122)
Is there any way to do this efficiently in numpy?
My idea was to zip both arrays, however, this is not efficient.
Edit: I am looking for a way to apply a customizable function myfunc(x,y). In the previous example myfunc(x,y) corresponded to the multipication.
c = a * b
sum1 = c[0].sum()
sum2 = c[1].sum()
if you want the algorithmic way ( custom function )
a = np.asarray([[0,1,2],[3,4,5]])
b = np.asarray([[6,7,8],[9,10,11]])
for i in range(a.shape[0]) :
s = 0
for j in range(a.shape[1]) :
s = s + a[i][j]*b[i][j]
print(s)
import numpy as np
a = np.asarray([[0,1,2],[3,4,5]])
b = np.asarray([[6,7,8],[9,10,11]])
c = a*b
print(sum(c[0]),sum(c1))
ans->23,122
Don't need to use zip both array, you need to understand numpy package help you work well with matrix. So you need the basic knowledge about matrix, i recommend you learn from this link http://cs231n.github.io/python-numpy-tutorial/ , from cs231n of Stanford university.
This is a function can solve your problem:
import numpy as np
def interates(matrix_a, matrix_b):
product = matrix_a*matrix_b
return (np.sum(product,1))
The value product contain a new matrix with same shape of matrix_a and matrix_b, each element in there is the result of matrix_a[i][j] * matrix_b[i][j]with i and j run from 0 to matrix_a.shape[0]and matrix_a.shape[1].
Now check with your example
a = np.asarray([[0,1,2],[3,4,5]])
b = np.asarray([[6,7,8],[9,10,11]])
result = interates(a,b)
Print result
>> print(result)
>> [23 122]
If you want a tuple
>> result = tuple(result)
>> print(result)
>> (23, 122)

Numpy where conditional statement along axis 0

I have a 1D vector Zc containing n elements that are 2D arrays. I want to find the index of each 2D array that equals np.ones(Zc[i].shape).
a = np.zeros((5,5))
b = np.ones((5,5))*4
c = np.ones((5,5))
d = np.ones((5,5))*2
Zc = np.stack((a,b,c,d))
for i in range(len(Zc)):
a = np.ones(Zc[i].shape)
b = Zc[i]
if np.array_equal(a,b):
print(i)
else:
pass
Which returns 2. The code above works and returns the correct answer, but I want to know if there a vectorized way to achieve the same result?
Going off of hpaulj's comment:
>>> allones = (Zc == np.array(np.ones(Zc[i].shape))).all(axis=(1,2))
>>> np.where(allones)[0][0]
2

Too many indices for array

I am trying to create a 3D image mat1 from the data given to me by an object. But I am getting the error for the last line: mat1[x,y,z] = mat[x,y,z] + (R**2/U**2)**pf1[l,m,beta]:
IndexError: too many indices for array
What could possible be the problem here?
Following is my code :
mat1 = np.zeros((1024,1024,360),dtype=np.int32)
k = 498
gamma = 0.00774267
R = 0.37
g = np.zeros(1024)
g[0:512] = np.linspace(0,1,512)
g[513:] = np.linspace(1,0,511)
pf = np.zeros((1024,1024,360))
pf1 = np.zeros((1024,1024,360))
for b in range(0,1023) :
for beta in range(0,359) :
for a in range(0,1023) :
pf[a,b,beta] = (R/(((R**2)+(a**2)+(b**2))**0.5))*mat[a,b,beta]
pf1[:,b,beta] = np.convolve(pf[:,b,beta],g,'same')
for x in range(0,1023) :
for y in range(0,1023) :
for z in range(0,359) :
for beta in range(0,359) :
a = R*((-x*0.005)*(sin(beta)) + (y*0.005)*(cos(beta)))/(R+ (x*0.005)*(cos(beta))+(y*0.005)*(sin(beta)))
b = z*R/(R+(x*0.005)*(cos(beta))+(y*0.005)*(sin(beta)))
U = R+(x*0.005)*(cos(beta))+(y*0.005)*(sin(beta))
l = math.trunc(a)
m = math.trunc(b)
if (0<=l<1024 and 0<=m<1024) :
mat1[x,y,z] = mat[x,y,z] + (R**2/U**2)**pf1[l,m,beta]
The line where you do the convolution:
pf1 = np.convolve(pf[:,b,beta],g)
generates a 1-dimensional array, and not 3-dimensional as your call in the last line: pf1[l,m,beta]
To solve this you can use:
pf1[:,b,beta] = np.convolve(pf[:,b,beta],g,'same')
and you also need to predefine pf1:
pf1 = np.zeros((1024,1024,360))
Note that the convolution of f*g (np.convole(f,g)) returns normally a length of |f|+|g|-1. If you however use np.convolve with the parameter 'same' it returns an array which has the maximum length of f or g (i.e. max(|f|,|g|)).
Edit:
Furthermore you have to be sure that the dimensions of the matrices and the indices you use are correct, for example:
You define mat1 = np.zeros((100,100,100),dtype=np.int32), thus a 100x100x100 matrix, but in the last line you do mat1[x,y,z] where the variables x, y and z clearly get out of these dimensions. In this case they get to the range of the mat matrix. Probably you have to change the dimensions of mat1 also to those:
mat1 = np.zeros((1024,1024,360),dtype=np.int32)
Also be sure that the last variable indices you calculate (l and m) are within the dimensions of pf1.
Edit 2: The range(a,b) function returns an array from a to b, but not including b. So instead of range(0,1023) for example, you should write range(0,1024) (or shorter: range(1024)).
Edit 3: To check if l or m exceed the dimensions you could add an error as soon as they do:
l = math.trunc(a)
if l>=1024:
print 'l exceeded bounds: ',l
m = math.trunc(b)
if m>=1024:
print 'm exceeded bounds: ',m
Edit 4: note that your your code, especially your last for will take a long time! Your last nested for results in 1024*1024*360*360=135895449600 iterations. With a small time estimation I did (calculating the running time of the code in your for loop) your code might take about 5 days to run.
A small easy optimization you could do is instead of calculating the sin and cos several times, create a variable storing the value:
sinbeta = sin(beta)
cosbeta = cos(beta)
but it will probably still take several days. You might want to check how to optimize your calculations or calculate it with a C program for example.

Cumulative integration of elements of numpy arrays

I would like to to the following type of integration:
Say I have 2 arrays
a = np.array[1,2,3,4]
b = np.array[2,4,6,8]
I know how to integrate these using something like:
c = scipy.integrate.simps(b, a)
where c = 15 for above data set.
What I would like to do is multiply the first elements of each array and add to new array called d, i.e. a[0]*b[0] then integrate the first 2 elements the arrays then the first 3 elements, etc. So eventually for this data set, I would get
d = [2 3 8 15]
I have tried a few things but no luck; I am pretty new to writing code.
If I have understood correctly what you need you could do the following:
import numpy as np
from scipy import integrate
a = np.array([2,4,6,8])
b = np.array([1,2,3,4])
d = np.empty_like(b)
d[0] = a[0] * b[0]
for i in range(2, len(a) + 1):
d[i-1] = integrate.simps(b[0:i], a[0:i])
print(d)

Categories