On the division and multiplication of matrices in python - python

Here the question with details and I think it's clearer,
suppose I have a matrix h of size 4 x 4 , and a vector of x of size 4 x 1, if we have y is the output of multiplication between h and x which means y = h * x; whose size is 1 x 4. So when I multiply again the inverse of every column in h by vector y, I should be able to get a vector equivalent of vector x which means $x = h^{-1} * y $. But unfortunately, I can't get that in python.
for example, let's first do that in MATLAB:
clear all
clc
h = (randn(4,4) + 1j*randn(4,4)); %any matrix of 4 x 4
x = [1 + 1j ; 0; 0 ; 0]; % a vector of 4 x 1
y = h * x ; % y is the output of multiplication
x2 = [];
for ii = 1 : 4
x1 = pinv(h(:,ii))*y; %multiply every column of h^(-1) with y
x2 = [x2 x1]; % the output
end
in that case, the output x2 is as expected, a vector 1 x 4 as below:
x2 =
1.0000 + 1.0000i 0.7249 + 0.5054i -0.0202 + 0.0104i 0.2429 + 0.0482i
In MATLAB, that's ok.
Now let's do that in python:
import numpy as np
h = np.random.randn(4,4) + 1j*np.random.randn(4,4)
x = [[1+1j],[0+0j],[0+0j],[0+0j]]
y = h.dot(x)
x2 = []
for ii in range(4):
x1 = np.divide(y, h[:,ii])
x2.append(x1)
print(x2)
Although x2 is supposed to be a vector of dimension 1 x 4 similar as in output of above MATLAB code, but in that case, I get x2 a matrix of size 4 x 4 !!
please any help.

There are two issues here:
np.divide() is for element-wise division, you may be looking for np.linalg.pinv() instead.
MATLAB is col major (FORTRAN-style), while NumPy is row major (C-style) so getting a list as a NumPy array will get you to a shape (n,) with n the length of the list and not an object of size (1, n) as MATLAB would.
The Python code equivalent (sort of, I'll do preallocation) to your MATLAB one, would be:
import numpy as np
h = np.random.randn(4, 4) + 1j * np.random.randn(4, 4)
x = np.array([[1 + 1j], [0 + 0j], [0 + 0j], [0 + 0j]])
# y = h.dot(x) <-- now NumPy supports also `#` in place of `np.dot()`
y = h # x
x2 = np.zeros((1, 4), dtype=np.complex)
for i in range(4):
x2[0, i] = np.linalg.pinv(h[:, i:i + 1]) # y
as you can see, the shape of the output is enforced right away.

Related

I need to concatenate two vectors same dimension but different shape

I have a vector y of size 4 x 1 , and another vector y2 of size 4 x 1 too, I concatenated the vectors y and real and imaginary parts of y2 and got two different vectors with same dimension but different shape ! . . I don't know what's the difference between both them.
For example, here is the first code:
import numpy as np
h = np.random.randn(4, 4) + 1j * np.random.randn(4, 4)
x = np.array([[1 + 1j], [0 + 0j], [0 + 0j], [0 + 0j]])
y = h # x
n = 3
y2 = np.zeros((1, 4), dtype=np.complex)
for ii in range(n):
y2[: , ii] = np.linalg.pinv(h[: , ii].reshape(-1,1)).dot(y)
y_con = np.concatenate((np.real(y2),np.imag(y2)))
y_m = np.absolute(y)
Y3 = np.concatenate([y_con.reshape(-1,1), y_m])
So, in this case, the output Y3 is a vector of dimension 12 x 1 when I check its shape, it's (12,1)
now, let's run the code in another way:
import numpy as np
h = np.random.randn(4, 4) + 1j * np.random.randn(4, 4)
x = np.array([[1 + 1j], [0 + 0j], [0 + 0j], [0 + 0j]])
y = h # x
y2 = np.linalg.pinv(h).dot(y)
y_con = np.concatenate((np.real(y2),np.imag(y2)))
y_m = np.absolute(y)
Y3 = np.concatenate([y_con, y_m])
In this case, Y3 is a vector of dimension 12, when I check its shape, it's (12,)
First I don't know what's the difference between the two vectors in their shape? .. and what I want is to use the first code to get a code of dimension of (12,) instead of (12,1)? how can I do that ?
You created a "column" vector which is 2-dimensional. Just add .flatten() to the end of the last line in your first code to make a 1-dimensional "row" vector.

I keep getting the error "index 2 is out of bounds for axis 0 with size 2" in my loop

I'm basically trying to sum a gradient here, see the screenshots I have attached for a better idea. Rho is an nx1 input vector, the screenshot I have attached shows the idea for a 3x1 rho vector but it really has an undefined length.
enter image description here
enter image description here
# JACOBIAN
def derivative(rho, a, A, tilde_k, x, y, vecinc, chi):
n = rho.shape[0]
result1 = np.array([n,1],complex)
result2 = np.array([n,1],complex)
result = np.array([n,1],complex)
u = np.zeros((n, 3))
W_tilde = np.array([3,3],complex)
loop1 = 0
loop2 = 0
for i in range(n):
for j in range(n):
u[i] = x[i] - y[j] # n x 3
W_tilde = A_matrix * chi.imag * A_matrix * G(u[i],k) * A_matrix # 3 x 3
ei_block = np.exp(1j * np.vdot(x[i], tilde_k)) * vecinc # 3 x 1
ej_block = np.exp(1j * np.vdot(x[j], tilde_k)) * vecinc # 3 x 1
eiT_block = np.matrix.getH(ei_block) # 1 x 3
mm = np.matmul(W_tilde, ej_block) # (3 x 3)(3 x 1) = 3 x 1
alpha_tilde = np.dot(eiT_block, mm) # (1 x 3)(3 x 1) = 1 x 1 = scalar
loop1 = loop1 + (2 * rho[i] * alpha_tilde * rho[j]) # scalar
if (i != j):
loop2 = loop2 + ((rho[j]**2) * alpha_tilde) # scalar
result1[i] = loop1
result2[i] = loop2
result = result1 + result2 # (n x 1) + (n x 1) = n x 1 vector
return result
I am getting "IndexError: index 2 is out of bounds for axis 0 with size 2" for the line, result1[i] = loop1. Pls help :(
That error means that you are attempting to access the third element (index 2) of an array with only two elements (size 2).
It looks like you're defining your arrays in a funny way; np.array([n,1],complex) creates an array of length 2, not n. What you want is probably np.zeros(n,complex), which will create an n-length array filled with 0s.

A system of two multivariable coupled ODEs

I'm trying to solve the following problem of coupled ODEs using odeint() from scipy. The system looks like this:
X'_k = mean(Y_k) + F
Y'_{k,j} = X_k - Y_{k,j}
This is a system with 3 X variables, and for each X variable, there are other 3 Y variables.
From what I read from the documentation, and the examples here and here, I can pass the system of equations as a list. And that is what I tried in the following example:
import numpy as np
from scipy.integrate import odeint
def dZdt(Z, t):
X = Z[0]
Y = Z[1]
F = 4
d_x = np.zeros(3)
d_y = np.zeros(3*3).reshape(3,3)
# Compute the Y values
for k in range(3):
for j in range(3):
d_y[k][j] = X[k] - Y[k][j]
# X values
d_x[k] = Y[k].mean() + F
d = [d_x, d_y]
return d
# Initial conditions
X0 = np.random.uniform(size=3)
Y0 = np.random.uniform(size = 3*3).reshape(3,3)
Z0 = [X0, Y0]
t = range(20)
Z = odeint(dZdt, Z0, t)
Where k, j = (1,2,3) and Z = [X,Y]
But I'm afraid I'm getting the following error:
ValueError: could not broadcast input array from shape (3,3) into shape (3)
My real problem is more complex, because j, and k, can be bigger than 3 (they go from 1 to j_max, and K_max, respectively) so I cannot write the 12 variables one by one.
My guessing is that somewhere in the code, Y variables are tried to fill in X shape... but no clue about where.
Any idea of what I'm doing wrong?
You are trying to represent an unknown function by two arrays inside of a list. It must be a one-dimensional array. So, instead of 3 X-variables and 9 Y-variables it must be a flat list of 12 variables. Like this:
def dZdt(Z, t):
X = Z[:3]
Y = Z[3:].reshape(3, 3)
F = 4
d_x = np.zeros(3)
d_y = np.zeros((3, 3))
# Compute the Y values
for k in range(3):
for j in range(3):
d_y[k, j] = X[k] - Y[k, j]
# X values
d_x[k] = Y[k].mean() + F
d = np.concatenate((d_x.ravel(), d_y.ravel()))
return d
# Initial conditions
X0 = np.random.uniform(size=3)
Y0 = np.random.uniform(size=(3, 3))
Z0 = np.concatenate((X0.ravel(), Y0.ravel()))
t = range(20)
Z = odeint(dZdt, Z0, t)
NumPy arrays are indexed as Y[k, j], not Y[k][j]. And there are ample vectorization opportunities that would eliminate the loops in the computation of dZdt. Like this:
def dZdt(Z, t):
X = Z[:3]
Y = Z[3:].reshape(3, 3)
F = 4
d_y = X[:, None] - Y
d_x = Y.mean(axis=1) + F
d = np.concatenate((d_x.ravel(), d_y.ravel()))
return d

How to put an "arbitrary" operation into a sliding window using Theano?

I want to define some function on a matrix X. For example mean(pow(X - X0, 2)), where X0 is another matrix (X0 is fixed / constant). To make it more specific, let's assume that both X and X0 are 10 x 10 matrices. The result of the operation is a real number.
Now I have a big matrix (let's say 500 x 500). I want to apply the operation defined above to all 10 x 10 sub-matrices of the "big" matrix. In other words, I want to slide the 10 x 10 window over the "big" matrix. For each location of the window, I should get a real number. So, as a final result, I need to get a real-valued matrix (or 2D tensor) (its shape should be 491 x 491).
What I want to have is close to a convolutional layer but not exactly the same because I want to use a mean squared deviation instead of a linear function represented by a neuron.
This is only a Numpy solution, hope it suffices.
I assume that your function is made up of an operation on the matrix elements and of a mean, i.e. a scaled sum. Hence, it is sufficient to look at Y as in
Y = np.power(X-X0, 2)
So we only need to deal with determining a windowed mean. Note that for the 1D case the matrix product with an appropriate vector of ones can be determined for calculating the mean, e.g.
h = np.array([0, 1, 1, 0]) # same dimension as y
m1 = np.dot(h, y) / 2
m2 = (y[1] + y[2]) / 2
print(m1 == m2) # True
The 2D case is analogous, but with two matrix multiplications, one for the rows and one for the columns. E.g.
m_2 = np.dot(np.dot(h, Y), h) / 2**2
To construct a sliding window, we need to build a matrix of shifted windows, e.g.
H = [[1, 1, 1, 0, 0, ..., 0],
[0, 1, 1, 1, 0, ..., 0],
.
.
.
[0, ..., 0, 0, 1, 1, 1]]
to calculate all the sums
S = np.dot(np.dot(H, Y), H.T)
A full example for a (n, n) matrix with a (m, m) window would be
import numpy as np
n, m = 500, 10
X0 = np.ones((n, n))
X = np.random.rand(n, n)
Y = np.power(X-X0, 2)
h = np.concatenate((np.ones(m), np.zeros(n-m))) # window at position 0
H = np.vstack((np.roll(h, k) for k in range(n+1-m))) # slide the window
M = np.dot(np.dot(H,Y), H.T) / m**2 # calculate the mean
print(M.shape) # (491, 491)
An alternative but probably slightly less efficient way for building H is
H = np.sum(np.diag(np.ones(n-k), k)[:-m+1, :] for k in range(m))
Update
Calculating the mean squared deviation is also possible with that approach. For that, we generalize the vector identity |x-x0|^2 = (x-x0).T (x-x0) = x.T x - 2 x0.T x + x0.T x0 (a space denotes a scalar or matrix multiplication and .T a transposed vector) to the matrix case:
We assume W is a (m,n) matrix containing a block (m.m) identity matrix, which is able to extract the (k0,k1)-th (m,m) sub-matrix by Y = W Z W.T, where Z is the (n,n) matrix containing the data. Calculating the difference
D = Y - X0 = Y = W Z W.T - X0
is straightforward, where X0 and D is a (m,m) matrix. The square-root of the squared sum of the elements is called Frobenius norm. Based on those identities, we can write the squared sum as
s = sum_{i,j} D_{i,j}^2 = trace(D.T D) = trace((W Z W.T - X0).T (H Z H.T - X0))
= trace(W Z.T W.T W Z W.T) - 2 trace(X0.T W Z W.T) + trace(X0.T X0)
=: Y0 + Y1 + Y2
The term Y0 can be interpreted as H Z H.T from the method from above.The term Y1 can be interpreted as a weighted mean on Z and Y2 is a constant, which only needs to be determined once.
Thus, a possible implementation would be:
import numpy as np
n, m = 500, 10
x0 = np.ones(m)
Z = np.random.rand(n, n)
Y0 = Z**2
h0 = np.concatenate((np.ones(m), np.zeros(n-m)))
H0 = np.vstack((np.roll(h0, k) for k in range(n+1-m)))
M0 = np.dot(np.dot(H0, Y0), H0.T)
h1 = np.concatenate((-2*x0, np.zeros(n-m)))
H1 = np.vstack((np.roll(h1, k) for k in range(n+1-m)))
M1 = np.dot(np.dot(H1, Z), H0.T)
Y2 = np.dot(x0, x0)
M = (M0 + M1) / m**2 + Y2

Fast math operations on an array in python

I have a fairly simple math operation I'd like to perform on a array. Let me write out the example:
A = numpy.ndarray((255, 255, 3), dtype=numpy.single)
# ..
for i in range(A.shape[0]):
for j in range(A.shape[1]):
x = simple_func1(i)
y = simple_func2(j)
A[i, j] = (alpha * x * y + beta * x**2 + gamma * y**2, 1, 0)
So basically, there's a mapping between (i, j) and the 3 values of that value (this is for visualization).
I'd like to roll this up and somehow vectorize this, but I'm not sure how to or if I can. Thanks.
Here is the vectorized version:
i = arange(255)
j = arange(255)
x = simple_func1(i)
y = simple_func2(j)
y = y.reshape(-1,1)
A = alpha * x * y + beta * x**2 + gamma * y**2 # broadcasting is your friend here
If you want to fill the last coordinates with 1 and 0:
B = empty(A.shape+(3,))
B[:,:,0] = A
B[:,:,1] = 1 # broadcasting again
B[:,:,2] = 0
You have to change simple_funcN so that they take arrays as input, and create arrays as output. After that, you could look into the numpy.meshgrid() or the cartesian() function here to build coordinate arrays. After that, you should be able to use the coordinate array(s) to fill A with a one-liner.

Categories

Resources