multiply many matrices and many vectors pytorch - python-3.x

I am trying to multiply the following:
A batch of matrices N x M x D
A batch of vectors N x D x 1
To get a result: N x M x 1
as if I were doing N dot products on M x D D x 1.
I cant seem to find the correct function in PyTorch.
torch.bmm as far as I can tell only works for a batch of vectors and a single matrix. If I have to use torch.einsum then so be it but id rather not!

It's pretty straightforward and intuitive with einsum:
torch.einsum('ijk, ikl->ijl', mats, vecs)
But your operation is just:
mats # vecs

Related

taking the norm of 3 vectors in python

This is probably a stupid question, but for some reason I can't get the norm of three matrices of vectors.
Each vector in the x matrix represents the x coordinate of a sensor (8 sensors total) for three different experiments. Same for y and z.
ex:
x = [array([ 2.239, 3.981, -8.415, 33.895, 48.237, 52.13 , 60.531, 56.74 ]), array([ 2.372, 6.06 , -3.672, 3.704, -5.926, -2.341, 35.667, 62.097])]
y = [array([ 18.308, -17.83 , -22.278, -99.67 , -121.575, -116.794,-123.132, -127.802]), array([ -3.808, 0.974, -3.14 , 6.645, 2.531, 7.312, -129.236, -112. ])]
z = [array([-1054.728, -1054.928, -1054.928, -1058.128, -1058.928, -1058.928, -1058.928, -1058.928]), array([-1054.559, -1054.559, -1054.559, -1054.559, -1054.559, -1054.559, -1057.959, -1058.059])]
I tried doing:
norm= np.sqrt(np.square(x)+np.square(y)+np.square(z))
x = x/norm
y = y/norm
z = z/norm
However, I'm pretty sure its wrong. When I then try and sum the components of let's say np.sum(x[0]) I don't get anywhere close to 1.
Normalization does not make the sum of the components equal to one. Normalization makes the norm of the vector equal to one. You can check if your code worked by taking the norm (square root of the sum of the squared elements) of the normalized vector. That should equal 1.
From what I can tell, your code is working as intended.
I made a mistake - your code is working as intended, but not for your application. You could define a function to normalize any vector that you pass to it, much as you did in your program as follows:
def normalize(vector):
norm = np.sqrt(np.sum(np.square(vector)))
return vector/norm
However, because x, y, and z each have 8 elements, you can't normalize x with the components from x, y, and z.
What I think you want to do is normalize the vector (x,y,z) for each of your 8 sensors. So, you should pass 8 vectors, (one for each sensor) into the normalize function I defined above. This might look something like this:
normalized_vectors = []
for i in range(8):
vector = np.asarray([x[i], y[i],z[i]])
normalized_vectors.append = normalize(vector)

Multiply every element of matrix with a vector to obtain a matrix whose elements are vectors themselves

I need help in speeding up the following block of code:
import numpy as np
x = 100
pp = np.zeros((x, x))
M = np.ones((x,x))
arrayA = np.random.uniform(0,5,2000)
arrayB = np.random.uniform(0,5,2000)
for i in range(x):
for j in range(x):
y = np.multiply(arrayA, np.exp(-1j*(M[j,i])*arrayB))
p = np.trapz(y, arrayB) # Numerical evaluation/integration y
pp[j,i] = abs(p**2)
Is there a function in numpy or another method to rewrite this piece of code with so that the nested for-loops can be omitted? My idea would be a function that multiplies every element of M with the vector arrayB so we get a 100 x 100 matrix in which each element is a vector itself. And then further each vector gets multiplied by arrayA with the np.multiply() function to then again obtain a 100 x 100 matrix in which each element is a vector itself. Then at the end perform numerical integration for each of those vectors with np.trapz() to obtain a 100 x 100 matrix of which each element is a scalar.
My problem though is that I lack knowledge of such functions which would perform this.
Thanks in advance for your help!
Edit:
Using broadcasting with
M = np.asarray(M)[..., None]
y = 1000*arrayA*np.exp(-1j*M*arrayB)
return np.trapz(y,B)
works and I can ommit the for-loops. However, this is not faster, but instead a little bit slower in my case. This might be a memory issue.
y = np.multiply(arrayA, np.exp(-1j*(M[j,i])*arrayB))
can be written as
y = arrayA * np.exp(-1j*M[:,:,None]*arrayB
producing a (x,x,2000) array.
But the next step may need adjustment. I'm not familiar with np.trapz.
np.trapz(y, arrayB)

Creating a 3-D (or larger) diagonal NumPy array from diagonals

Is there an efficient 'Numpy'-based solution to create a 3 (or higher) dimensional diagonal matrix?
More specifically, I am looking for a shorter (and perhaps more efficient) solution to replace the following:
N = 100
M = 4
d = np.random.randn(N) # calculated in the real use case from other parameters
A = np.zeros(M, M, N, dtype=d.dtype)
for i in range(M):
A[i, i, :] = d
The above-mentioned solution will be slow if M is large, and I think not very memory-efficient as d is copied M times in the memory.
Here's one with np.einsum diag-view -
np.einsum('iij->ij',A)[:] = d
Looking at the string notation, this also translates well from the iterative part : A[i, i, :] = d.
Generalize to ndarray with ellipsis -
np.einsum('ii...->i...',A)[:] = d

How to find the L1-Norm/Manhattan distance between two vectors in Python without libraries

I have two vectors with equal dimensions and need to find the distance between them
I have tried various approaches:
sum([a-b for a, b in zip(u, v)])
c= sum([a-b for a, b in zip(u, v)]
#If x is negative, multiply by negative one to convert x to a positive
if c<=0:
return c*-1
#No changes are made to x if it is positive
else:
return c
I am yet to have success!
You want to use the abs() function, which is available in standard python.
So if you have
a = [1,2,3,4,5,.4]
b = [4,3,4,5,-2,.8]
Than you can get the distance with
sum([abs(i-j) for i,j in zip(a,b)])
We can use the sklearn implementation to check indeed this is the correct answer.
from sklearn.metrics.pairwise import manhattan_distances
manhattan_distances([a], [b])

Rank elements based off two variables

I want to rank all the entities in a list based of two variables (both percentages). One of the variables is 'the bigger the better' (x) and the other is 'smaller the better' (y). What is the best way to give each entity a score in order to rank them?
I tried doing x*(1-y) but as some of the y values are over 1, the negatives it created caused some errors.
Below is the data:
x y
a 0.953882755 0.926422663
b 0.757267676 0.926967001
c 1 1.01607838
d 0.89805254 1.008814817
e 0.672989727 0.932579014
f 0.643306278 0.924523932
g 0.621091809 0.935122957
h 0.56891321 0.918181342
i 0.563662125 0.924102288
j 0.579410248 0.946421415
k 0.781299906 1.040418561
l 0.490013047 0.920900829
m 0.475050754 0.932586282
n 0.505211144 0.972570665
o 0.566582462 1.009732948
p 0.610994363 1.031047605
q 0.686065983 1.060742126
r 0.47642017 0.983301498
s 0.463552006 0.976645044
t 0.551532341 1.025816246
u 0.478092524 1.012675037
v 0.645790431 1.084143812
w 0.390365014 1.189518019
Two ways : averaged ranking OR sort by distance from min&max
average ranking :
use =RANK.AVG() on X & Y separately. Get the average, then rank again base on the average.
sort by distance from min&max :
do '=(B2-MIN(B:B)) + (MAX(C:C)-C2)' and drag downwards. Then use =RANK.AVG() on the results, being the smaller (the distance from min/max) the better.
Hope it solves.

Resources