Defining a quadratic function with numpy.meshgrid - python

Let's consider a function of two variables f(x1, x2) , where x1 spans over a vector v1 and x2 spans over a vector v2.
If f(x1, x2) = np.exp(x1 + x2), we can represent this function in Python as a matrix by means of the command numpy.meshgrid like this:
xx, yy = numpy.meshgrid(v1, v2)
M = numpy.exp(xx + yy)
This way, M is a representation of the function f over the cartesian product "v1 x v2", since M[i,j] = f(v1[i],v2[j]).
But this works because both sums and exponential work in parallel componentwise. My question is:
if my variable is x = numpy.array([x1, x2]) and f is a quadratic function f(x) = x.T # np.dot(Q, x), where Q is a 2x2 matrix, how can I do the same thing with the meshgrid function (i.e. calculating all the values of the function f on "v1 x v2" at once)?
Please let me know if I should include more details!

def quad(x, y, q):
"""Return an array A of a shape (len(x), len(y)) with
values A[i,j] = [x[i],y[j]] # q # [x[i],y[j]]
x, y: 1d arrays,
q: an array of shape (2,2)"""
from numpy import array, meshgrid, einsum
a = array(meshgrid(x, y)).transpose()
return einsum('ijk,kn,ijn->ij', a, q, a)
Notes
meshgrid produces 2 arrays of a shape (len(y), len(x)), where first one is with x values along the second dimension. If we apply to this pair np.array then a 3d array of shape (2, len(y), len(x)) will be produced. With transpose we obtain an array, where an element indexed by [i,j,k] is x[i] if k==0 else y[j], where k is 0 or 1, i.e. first or second array from meshgrid.
With 'ijk,kn,ijn->ij' we tell einsum to return the sum written bellow for each i, j:
sum(a[i,j,k]*q[k,n]*a[i,j,n] for k in range(2) for n in range(2))
Note, that a[i,j] == [x[i], y[j]].

Related

Function that takes in a meshgrid of values

I want a function that takes in 2 numbers and a matrix and does a multiplication operation using them and then sums every element of the matrix after multiplication (see code below).
I am trying to do this operation for all possible combinations of x and y. What is the best way to do this without using loops, since I know I could loop over the function with different values of x and y but this doesn't seem like an efficient way to do it.
I tried using a meshgrid as input but that didnt work due to the way the input is broadcasted.
import numpy as np
def my_func(num1, num2, matrix2):
return np.sum(matrix*num1*num2)
x = np.linspace(0,5)
y = np.linspace(0,1)
X, Y = np.meshgrid(x, y)
matrix = np.array([[1],[2],[3]])
a = my_func(X,Y,matrix)
I get the following error:
ValueError: operands could not be broadcast together with shapes (50,50) (3,1)
I would like a to equal a meshgrid of values where each value in the array corresponds to the output of my_func for every possible combination of x and y.
The result of x * y * M when x and y are scalar is just M.shape. If you want this result for each value of x and y, you will want a result of shape x.shape + y.shape + M.shape. You can do this with broadcasting for the totally general case. The idea is that you need to reshape x to have trailing ones too fill in y.ndim + M.ndim dimensions and y to have M.ndim trailing dimensions.
For the sake of the summation, it's actually easier to ravel M, even though np.sum allows for multiple axes since version 1.7.0.
def my_func(x, y, matrix):
x = np.reshape(x, x.shape + (1,) * (y.ndim + 1))
y = np.reshape(y, y.shape + (1,))
return (x * y * matrix.ravel()).sum(axis=-1)
If you want to input x and y that are already broadcasted together, you can adjust the calculation slightly:
def my_func(x, y, matrix):
return ((x * y)[:, None] * matrix.ravel()).sum(-1)
The conceptual difference is that the first version accepts the linspaces you created directly, while the second version requires you to construct the meshgrid, or at least transpose one of the arrays.
It looks like you have to adjust the dimensions of your x and y array:
import numpy as np
def my_func(num1, num2, matrix2):
return matrix*num1*num2
x = np.linspace(0,5, num=3)
y = np.linspace(0,1, num=3)
X, Y = np.meshgrid(x, y)
matrix = np.array([[1],[2],[3]])
a = my_func(X,Y,matrix)
print(a)
# [[ 0. 0. 0. ]
# [ 0. 2.5 5. ]
# [ 0. 7.5 15. ]]

how to create a matrix from combinations of elements from two vectors in tensorflow

I have two vectors X = [a,b,c,d] and Y = [m,n,o]. I'd like to construct a matrix M where each element is an operation on each pair from X and Y. i.e.
M[j,i] = f(X[i], Y[j])
# e.g. where f(x,y) = x-y:
M :=
a-m b-m c-m d-m
a-n b-n c-n d-n
a-o b-o c-o d-o
I imagine I could do this with two tf.while_loop(), but that seems inefficient, I was wondering if there is a more compact and parallel way of doing this.
P.S. There is a slight complication that X and Y are in fact not vectors, but R2. i.e. each element in X and Y is itself a fixed length vector, and f(X, Y) performs f() element wise. Plus there is a batch component too.
I.e.
X.shape => [BATCH, I, K]
Y.shape => [BATCH, J, K]
M[batch, j, i, k] = f( X[batch, i, k], Y[batch, j, k] )
# e.g.:
= X[batch, i, k] - Y[batch, j, k]
this is using the python API btw
I found a way of doing this by increasing rank and using broadcasting. I still don't know if this is the most efficient way of doing it, but it's a heck of a lot better than using tf.while_loop I guess! I'm still open to suggestions / improvements.
X_expand = tf.expand_dims(X, 1)
Y_expand = tf.expand_dims(Y, 2)
# now I think M = f(X,Y) will broadcast each tensor to the higher dimension on each axis duplicating the data e.g.:
M = X-Y

dot product with diagonal matrix, without creating it full matrix

I'd like to calculate a dot product of two matrices, where one of them is a diagonal matrix. However, I don't want to use np.diag or np.diagflat in order to create the full matrix, but instead use the 1D array directly filled with the diagonal values. Is there any way or numpy operation which I can use for this kind of problem?
x = np.arange(9).reshape(3,3)
y = np.arange(3) # diagonal elements
z = np.dot(x, np.diag(y))
and the solution I'm looking for should be without np.diag
z = x ??? y
Directly multiplying the ndarray by your vector will work. Numpy conveniently assumes that you want to multiply the nth column of x by the nth element of your y.
x = np.random.random((5, 5)
y = np.random.random(5)
diagonal_y = np.diag(y)
z = np.dot(x, diagonal_y)
np.allclose(z, x * y) # Will return True
The Einstein summation is an elegant solution to these kind of problems:
import numpy as np
x = np.random.uniform(0,1, size=5)
w = np.random.uniform(0,1, size=(5, 3))
diagonal_x = np.diagflat(x)
z = np.dot(diagonal_x, w)
zz = np.einsum('i,ij->ij',x , w)
np.allclose(z, zz) # Will return True
See: https://docs.scipy.org/doc/numpy/reference/generated/numpy.einsum.html#numpy.einsum

Advanced numpy array multiplication

Consider three numpy arrays. Each numpy array is three dimensional. We have array X, array Y, and array Z. All these arrays are the same shape. Combining the three matching elements of X, Y, and Z at the same places gives a coordinate. I have a function (not python function, mathematical) which has to run on one of these position vectors and place an output into another three dimensional array called s. So if the arrays were defined as shown below:
X = [[[1,2],[3,4]] Y = [[[1,2],[3,4]] Z = [[[1,2],[3,4]]
[[5,6],[7,8]]] [[5,6],[7,8]]] [[5,6],[7,8]]]
Then the points to be tested would be:
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),(6,6,6),(7,7,7),(8,8,8)
If the function s was simply a+b+c then the results matrix would be:
s=[[[ 3, 6],[ 9,12]]
[[15,18],[21,24]]]
But this is not the case instead we have a two dimensional numpy array called sv. In the actual problem, sv is a list of vectors of dimension three, like our position vectors. Each position vector must be subtracted from each support vector and the magnitude found of the resulting vector to give the classification of each vector. What numpy operations can be used to do this?
We start with the 3 arrays of components x, y, and z. I will change the values from your example so that they have unique values:
x = np.array([[[1,2],[3,4]],
[[5,6],[7,8]]])
y = x + 10
z = y + 10
Each of the above have shape (2,2,2), but they could be any (n, m, l). This shape will have little impact on our process.
We next combine the three component arrays into a new array p, the "position vector", creating a new dimension i will iterate over the three physical dimensions x, y, z,
p = np.array([x, y, z])
so p[0] is x and so on, and p has shape (d, n, m, l) (where d=3 is the physical dimensionality of the vectors).
Now we look at your list of vectors sv which presumably has shape (N, d). Let us use a small number for N:
N = 4
d = 3
sv = np.arange(d*N).reshape(N,d) # a list of N vectors in 3d
OK the above was a little repetive but I want to be clear (and please correct any misunderstandings I may have had from your question).
You want to make some difference, diff in which you take each of the n*m*l vectors buried in p and subtract from it each of the N vectors in sv. This will give you N*n*m*l vectors, which each have d components. We need to align each of these dimensions before we do subtractions.
Basically we want to take p - sv but we must make sure that their shapes match so that the d axis is aligned, and the n, m, l and N axes basically just add up. The way numpy broadcasts is to take the shapes of the array, and aligns them from the end, so the last axis of each is aligned, and so on. To broadcast, each size must match exactly, or must be empty (on the left) or 1. That is, if your shapes were (a, b, c) and (b, c), you would be fine, and the second array would be repeated ("broadcasted") a times to match the a different subarrays of shape (b, c) in the first array. You can use dimensions length 1 which will force the position, so normally two arrays of shape (a, b, c) and (a, b) will not align because the last axis does not match, but you can add a new placeholder axis at the end of the second to give it shape (a, b, 1) which will match to (a, b, c) no matter what the value of c is.
We give shape (N, d, 1, 1, 1) to sv which matches the shape (d, n, m, l) of p. This can be done several ways:
sv = sv.reshape(sv.shape + (1,1,1)])
#or
sv.shape += (1, 1, 1)
#or
sv = sv[..., None, None, None]
Then, we can do the difference:
diff = p - sv[..., None, None, None]
where we have that diff.shape is (N, d, n, m, l). Now we can square it and sum over the second (d) dimension to get the norm/magnitude of each vector:
m = (diff*diff).sum(1)
which of course will have shape (N, n, m, l), or in the example case (4, 2, 2, 2)
So, all together:
import numpy as np
x = np.array([[[1,2],[3,4]],
[[5,6],[7,8]]])
y = x + 10
z = y + 10
p = np.array([x, y, z])
print p.shape
N = 4
d = 3
sv = np.arange(d*N).reshape(N,d) # a list of N vectors in 3d
print sv.shape
diff = p - sv[..., None, None, None]
print diff.shape
m = (diff*diff).sum(1)
print m.shape

find the dot product of sub-arrays in numpy

In numpy, the numpy.dot() function can be used to calculate the matrix product of two 2D arrays. I have two 3D arrays X and Y (say), and I'd like to calculate the matrix Z where Z[i] == numpy.dot(X[i], Y[i]) for all i. Is this possible to do non-iteratively?
How about:
from numpy.core.umath_tests import inner1d
Z = inner1d(X,Y)
For example:
X = np.random.normal(size=(10,5))
Y = np.random.normal(size=(10,5))
Z1 = inner1d(X,Y)
Z2 = [np.dot(X[k],Y[k]) for k in range(10)]
print np.allclose(Z1,Z2)
returns True
Edit Correction since I didn't see the 3D part of the question
from numpy.core.umath_tests import matrix_multiply
X = np.random.normal(size=(10,5,3))
Y = np.random.normal(size=(10,3,5))
Z1 = matrix_multiply(X,Y)
Z2 = np.array([np.dot(X[k],Y[k]) for k in range(10)])
np.allclose(Z1,Z2) # <== returns True
This works because (as the docstring states), matrix_multiplyprovides
matrix_multiply(x1, x2[, out]) matrix
multiplication on last two dimensions

Categories