I am translating some MATLAB code and am having some problems understanding the syntaxical difference between MATLAB and numpy for Python.
In MATLAB I have a 6 by 6 matrix, A, as well as 6 float values, a, b, c, d, e, f.
The MATLAB code
B = A*[a;b;c;d;e;f];
produces a 6 by 1 matrix, B.
So I figured that the MATLAB operator '*' must correspond to the numpy operator numpy.dot().
So in my Python code I have the same matrix, A, and the same values for a, b, c, d, e and f.
B = numpy.dot(A, [[a],[b],[c],[d],[e],[f]])
does not produce the same matrix, B, and neither does
B = numpy.dot(A, [a,b,c,d,e,f])
I have also tried building the Python matrix and array with numpy's array function with the same result.
It feels like I am mixing something fundamental up here. Any help is greatly appreciated.
It's difficult to answer fully without knowing the values in A, and a,b,c,d,e,f. However, you're code seems to work:
MATLAB:
A = [1,2,3,4,5,6;
1,2,3,4,5,6;
1,2,3,4,5,6;
1,2,3,4,5,6;
1,2,3,4,5,6;
1,2,3,4,5,6];
b = [7;8;9;10;11;12];
A*b
ans =
217
217
217
217
217
217
A'*b
ans =
57
114
171
228
285
342
Python:
import numpy as np
A = np.array([[1,2,3,4,5,6],
[1,2,3,4,5,6],
[1,2,3,4,5,6],
[1,2,3,4,5,6],
[1,2,3,4,5,6],
[1,2,3,4,5,6]])
b = np.array([7,8,9,10,11,12]).reshape(6, 1)
B = np.dot(A, b)
B
array([[217],
[217],
[217],
[217],
[217],
[217]])
B = np.dot(A.transpose(), b)
B
array([[57],
[114],
[171],
[228],
[285],
[342]])
The numpy dot operator does perform matrix multiplication, so it is likely that something is going wrong with your initialisation of A which you don't show.
Note that the reshape operation is not necessary (the same results are seen regardless). However, this makes a column vector rather than a 1D array and so can be transposed etc. in the same fashion as the MATLAB array [7;8;9;10;11;12].
The vector you are multiplying is a column, so use it as a column to have a final 6x1 vector and not a 1x6 vector, as you are doing a dot product of 6x6 by 6x1 in MATLAB.
This example is for a 3x3 dimension (just to reduce the code and be understandable):
import numpy as np
A = np.array([[8,1,6],[3,5,7],[4,9,2]]) # This is the matrix
b = np.array([1,2,3]) # These are the float numbers
c = np.dot(A,b.reshape(-1,1)) # This is a 3x1 vector
This is equivalent on MATLAB to:
magic(3)*[1;2;3]
Related
Given a matrix A in matlab with:
3 1
4 5
7 8
and another matrix B which could be referred to as some reference points (each row is reference point that is to be compared to each row of A),
1 1
1 2
I need to compute a matrix C, such that
4 5
25 18
85 72
Where each row of C is the difference (squared L2 norm) between each row of A and the rows of B. One possible way to do this in MATLAB is to first create a zero matrix C, C = zeros(5,2), and then use double for-loops to fill in the appropriate value. Is there any other efficient/simpler way in MATLAB?
Find the code snippet below
C = zeros(5,2)
for i = 1:rows
for j = 1:rows2
C(i,j) = (norm(A(i,:)-B(j,:)))^2
end
end
A solution similar to ThomasIsCoding's, but generalized to any number of dimensions (=columns). Thomas' answer requires A and B to have exactly 2 columns to use the complex representation. Here, we use a 3rd array dimension instead of complex values:
n = 3; % number of spatial dimensions for computing the L2 norm
A = 10*rand(20,n);
B = 10*rand(4,n);
C = sum((reshape(A,[],1,n) - reshape(B,1,[],n)).^2,3)
First we reshape A, such that its rows remain rows, but its columns are arranged along the 3rd array dimension. We reshape B similarly, but its rows become columns, and its columns are moved to the 3rd dimension. This arrangement of the first two dimensions match that of the output C.
Next we take the difference (using implicit singleton expansion, for older versions of MATLAB you'd need to use bsxfun), square, and sum along the 3rd dimension.
Maybe you can try bsxfun like below
A = [3,1; 4,5;7,8];
B = [1,1;1,2];
% you can first rewrite A and B in complex coordinates to simplify the computation, and then compute difference of two complex values
C = abs(bsxfun(#minus,A*[1;1j],transpose(B*[1;1j]))).^2;
and you will get
C =
4.0000 5.0000
25.0000 18.0000
85.0000 72.0000
Say I have the following matrix
B = [1 2 3;4 5 6;7 8 9;10 11 12]
and another matrix
A = [a b c;d e f;g h i]
How do I multiply each row of matrix B by the matrix A (without using a for loop), i.e.
for i = 1:4
c(i) = B(i,:)*A*B(i,:)'
end
many thanks in advance.
You can use:
c = diag(B*A*B.');
However, this computes a whole 4×4 matrix only to extract its diagonal, so it's not very efficient.
A more efficient way that only computes the desired values is:
c = sum(bsxfun(#times, permute(sum(bsxfun(#times, B, permute(A, [3 1 2])), 2), [1 3 2]), B), 2);
Here is a breakdown of the above code:
c1 = sum(bsxfun(#times, B, permute(A, [3 1 2])), 2); % B(i,:)*A
c = sum(bsxfun(#times, permute(c1, [1 3 2]), B), 2); % (B(i,:)*A)*B(i,:)'
The first permute is used so that the number of columns in B matches the number of columns in A. Following the element-wise multiplication in bsxfun() each row is summed up (remember, permute shifted the rows into the 2nd-dimension), reproducing the effect of the vector-matrix multiplication B(i,:) * A occurring in the for loop.
Following the first sum, the 2nd-dimension is a singleton dimension. So, we use the second permute to move the 2nd-dimension into the 3rd-dimension and produce a 2-D matrix. Now, both c1 and B are the same size. Following element-wise multiplication in the second bsxfun() each column is summed up (remember, permute shifted columns back into the 2nd-dimension), reproducing the effect of B(i,:) * A * B(i,:)'.
Take note of a hidden advantage in this approach. Since we are using element-wise multiplication to replicate the results of matrix multiplication, order of the arguments doesn't matter in the bsxfun() calls. One less thing to worry about!
Or, from Matlab R2016b onwards, you can replace bsxfun(#times,...) by .*, thanks to implicit expansion:
c = sum(permute(sum(B.*permute(A, [3 1 2]), 2), [1 3 2]).*B, 2);
I need to make an array of matrices in numpy. This is so I can treat them as scalars and dot this with another array, like so:
a = [1,2,3]
b = [A,B,C] #A, B, and C are matrices
result = a.dot(b) #1A + 2B + 3C
Or similarly with a matrix M such that:
M.dot(b) -> another array of matrices
Is there a way of doing this? Currently, every array-like thing gets subsumed into the numpy array outside that allows .dot() in the first place. So, if A, B, and C were 3x3 matrices, a would be:
a.shape -> (3,3,3) #matrices absorbed into array
Thanks.
Solution:
import numpy as np
a = np.array([1,2,3])
X= np.ones((3,3))
Y= np.ones((3,3))
Z= np.ones((3,3))
b = np.array([X,Y,Z], dtype=object)
print a.dot(b)
results in:
[[6.0 6.0 6.0]
[6.0 6.0 6.0]
[6.0 6.0 6.0]]
Remember that the length of array of scalars must be of the same size of matrices (in this case matrices 3x3, so you need an array of length 3)
I have a three dimensional domain in MATLAB. For each point in the domain I have defined three arrays of size (NX,NY,NZ) at each point of the domain:
A1; % size(A1) = [NX NY NZ]
A2; % size(A2) = [NX NY NZ]
A3; % size(A3) = [NX NY NZ]
For each element, I am trying to construct an array which holds the value of A1, A2, and A3. Would the following be a good candidate for having a 1×3 vector at each point?
B = [A1(:) A2(:) A3(:)];
B = reshape(B, [size(A1) 1 3]);
If the 1×3 array is named C, I am trying to find C'*C at each point.
C = [A1(i,j,k) A2(i,j,k) A3(i,j,k)]; % size(C) = [1 3]
D = C'*C; % size(D) = [3 3]
My ultimate goal is to find the array D with size 3×3 for all the points in the domain in a vectorize fashion? In fact, the output which consists of array D for each point will have the size [NX NY NZ 3 3]. Could someone help me?
Basically we concatenate A1, A2 and A3 along the 4th and 5th dimensions separately that leaves singleton dimensions in the 5th and 4th dimensions respectively, which are then used by bsxfun [Apply element-by-element binary operation to two arrays with singleton expansion enable] to expand as 3x3 matrices along the 4th-5th dimensions for matrix multiplication result from each triplet of [A1(i,j,k),A2(i,j,k),A3(i,j,k)].
D = bsxfun(#times,cat(4,A1,A2,A3),cat(5,A1,A2,A3));
I have 2 matrices A (nxm) and B (nxd) and want to multiply element-wise each column of A with a row of B. There are m columns in A and n 1xd vectors in B so the results are m nxd matrices. Then I want to sum(result_i, 1) to get m 1xd vectors, which I want to apply vertcat to get a mxd matrix. I'm doing this operations using for loop and it is slow because n and d are big. How can I vectorize this in matlab to make it faster? Thank you.
EDIT:
You're all right: I was confused by my own question. What I meant by "multiply element-wise each column of A with a row of B" is to multiply n elements of a column in A with the corresponding n rows of B. What I want to do with one column of A is as followed (and I repeat this for m columns of A, then vertcat the C's vector together to get an mxd matrix):
column_of_A =
3
3
1
B =
3 1 3 3
2 2 1 2
1 3 3 3
C = sum(diag(column_of_A)*B, 1)
16 12 15 18
You can vectorize your operation the following way. Note, however, that vectorizing comes at the cost of higher memory usage, so the solution may end up not working for you.
%# multiply nxm A with nx1xd B to create a nxmxd array
tmp = bsxfun(#times,A,permute(B,[1 3 2]));
%# sum and turn into mxd
out = squeeze(sum(tmp,1));
You may want to do everything in one line, which may help the Matlab JIT compiler to save on memory.
EDIT
Here's a way to replace the first line if you don't have bsxfun
[n,m] = size(A);
[n,d] = size(B);
tmp = repmat(A,[1 1 d]) .* repmat(permute(B,[1 3 2]),[1,m,1]);
It's ugly, but as far as I can see, it works. I'm not sure it will be faster than your loop though, plus, it has a large memory overhead. Anyway, here goes:
A_3D = repmat(reshape(A, size(A, 1), 1, size(A, 2)), 1, size(B, 2));
B_3D = repmat(B, [ 1 1 size(A, 2)]);
result_3D = sum(A_3D .* B_3D, 1);
result = reshape(result_3D, size(A, 2), size(B, 2))
What it does is: make A into a 3D matrix of size n x 1 x m, so one column in each index of the 3rd dimension. Then we repeat the matrix so we get an n x d x m matrix. We repeat B in the 3rd dimension as well. We then do a piecewise multiplication of all the elements and sum them. The resulting matrix is a 1 x d x m matrix. We reshape this into a m x d matrix.
I'm pretty sure I switched around the size of the dimensions a few times in my explanation, but I hope you get the general gist.
Multiplying with a diagonal matrix seems at least twice as fast, but I couldn't find a way to use diag, since it wants a vector or 2D matrix as input. I might try again later tonight, I feel there must be a faster way :).
[Edit] Split up the command in parts to at least make it a little bit readable.
This is the way I would do this:
sum(repmat(A,1,4).*B)
If you don't know the number of columns of B:
sum(repmat(A,1,size(B,2)).*B)