I have a 3D MATLAB function.
I want to multiply each slice of the matrix by a different number.
I tried to implement this by bsxfun in the following example code:
a=randi(10,4,3,2);
b=[2 3];
c=bsxfun(#times,a,b)
I intended that the first 4*3 slice of 'a' would be multiplied by 2, and the second 4*3 slice of 'a' would be multiplied by 3.
However, I only got the following error:
??? Error using ==> bsxfun
Non-singleton dimensions of the two
input arrays must match each other.
How to solve the problem without using a loop?
As the error says, you need to make the dimensions of the vector and the matrix match. Since b is a row vector, you can make the slices of the matrix into columns. You can do this with permute:
a = randi(10, 4, 3, 2);
b = [2 3];
ap = permute(a, [1 3 2]);
c = bsxfun(#times, ap, b)
Then, to get the result matrix back into the correct shape, you need to permute again. You can either figure out the correct permutation order (it happens to be the same in this case, i.e. [1 3 2]) or you can use ipermute (inverse permute) and let it figure it out for you. Just give it the same permutation order you gave permute earlier.
c = ipermute(c, [1 3 2]);
Alternatively, you can permute the vector b to be the right shape to multiply the slices by making it extend in the 3rd dimension:
a = randi(10, 4, 3, 2);
b = [2 3];
bp = permute(b, [1 3 2]);
c = bsxfun(#times, a, bp)
In this case, since we didn't change a, we don't have to permute c again to get the correct shape.
Related
I have a 3D-matrix A, with size lets say 3x12x100. The first two dimensions define 3×12 matrices, the latter one is simply the linear index. I want a very simple operation on these 100 matrices. For all these matrices, i want them multiplied with its conjugate transpose. With a very simple for loop, i can create this:
data = data;
A = zeros(100, 12, 12);
for i=1:100
A(i, :, :) = data(:, :, i)'*data(:, :, i);
end
But i like clean code, so i dont really prefer this for-loop. I have done some searching and sometimes find something like mtimesx (which is a custom made MATLAB function from 2010). I think i am missing something very obvious (as usual), because this seems a fairly easy operation (its just an "element-wise" matrix multiplication).
The size of my actual matrix is 3x12x862400. My original script takes about 10 minutes or longer, a variant on what #FangQ posts fixes it in a matter of seconds. My new code is as following, note that it still is under construction and i still need to validate it:
data = rand(3, 12, 862400) + i*rand(3, 12, 862400)
data2 = conj(permute(data, [2 1 3])); % conjugate transpose each matrix
% my data matrix contains 862400 3x12 matrices with complex numbers
Ap = permute(data2, [2 1 4 3]);
Bp = permute(data, [1 4 2 3]);
M = Ap.*Bp;
M = sum(M, 1);
M = permute(M, [2 3 4 1]);
#Cris was right, you can find an example from this MatlabCentral post
https://www.mathworks.com/matlabcentral/answers/10161-3d-matrix-multiplication#answer_413531
Suppose I have a matrix
A=[1 2 3]
which is row matrix. Not I want to do it "page" matrix, i.e. align elements along 3rd dimension.
I noticed, that the following
A=permute(A,[3 1 2])
works, while the following
A=permute(A,[3 2 1])
does not.
Why?
Your question is not really clear. If I'm right you'd like your matrix to become B = [0,0,1;0,0,2; 0,0,3].
This can be done easily with the transpose function by typing:
B(:,:,3)=A'
Instead of using the permute function which is a generalization of transpose. Also, your operation might not "work" because permute is an operation that affects the dimension of the array, and not of its elements
Note that the size of A is [1 3], not [3 1]. As CST-Link points out, this is equivalent with [1 3 1 1] etc., since the singleton dimensions are removed.
size(A,1) = 1
size(A,2) = 3 <-- You want this to be the third dimension
size(A,3) = 1
Now, what you want to do is align the second dimension (the one telling you how many columns you have) to the third dimension (the one telling you how many slices you have).
When you use permute, you specify the order you want the original dimensions to occur. I.e. if you do permute(A, [2 1]) for a vector, you will transpose it. The second dimension is now the first and vice versa. You want the second dimemsion to be the third, and keep the first dimension constant, so:
permute(A, [1 3 2])
If you do:
permute(A, [3 2 1])
you will take the third dimension to be the first (size(A,1) = 1), the second dimension (size(A,2) = 3) will be the second (i.e. it is not changed), and the first dimension is the third. Thus, the only dimensions that change are the first and third. These are both 1 to begin with, so nothing has changed.
Note that you can also use shiftdim in this particular case:
shiftdim(A,-1)
I have a Matrix called A. For example the following:
A = [1 2 3; 3 4 1; 2 4 4]
Now I have the following equation:
A(x,y) = (j^x)*(i^y)
j and i are normal values (dimension 1x1), not indices of a matrix. ^
Lets make an example:
A(1,1) = 1 (First value of the Matrix)
1 = (j^1)*(i^1)
And a second one:
A(1,2) = 3
3 = (j^1)*(i^2)
Is there a possibility to receive one solution for the two parameters using Matlab?
Here is some code that can find the best solution to your problem, if there is one. In this case, there is no reasonable solution, but defining A by M([4 2]) (for example) does work reasonably well.
A = [1 2 3; 3 4 1; 2 4 4] %// the A matrix
[C,R]=meshgrid(1:3) %// create matrices of row/column indices
M=#(xy) xy(2).^C.*xy(1).^R %// calculates matrix of elements j^x*i^y
d=#(xy) A-M(xy) %// calculates difference between A and the calculated i^x*y^j matrix
r=fsolve(#(xy) norm(d(xy)),[1 1]) %// use fsolve to attempt to find a solution
d(r) %// show resulting difference between target matrix and solution matrix
norm(d(r)) %// norm of that matrix
M(r) %// show the solution matrix
Let's say I have two vectors:
A = [1 2 3];
B = [1 2];
And that I need a function similar to multiplication of A*B to produce the following output:
[
1 2 3
2 4 6
]
It seems that things like A*B, A*B' or A.*B are not allowed as the number of elements is not the same.
The only way I managed to do this (I am quite new at MATLAB) is using ndgrid to make two matrices with the same number of elements like this:
[B1,A1] = ndgrid(B, A);
B1.*A1
ans =
1 2 3
2 4 6
Would this have good performance if number of elements was large?
Is there a better way to do this in MATLAB?
Actually I am trying to solve the following problem with MATLAB:
t = [1 2 3]
y(t) = sigma(i=1;n=2;expression=pi*t*i)
Nevertheless, even if there is a better way to solve the actual problem in place, it would be interesting to know the answer to my first question.
You are talking about an outer product. If A and B are both row vectors, then you can use:
A'*B
If they are both column vectors, then you can use
A*B'
The * operator in matlab represents matrix multiplication. The most basic rule of matrix multiplication is that the number of columns of the first matrix must match the number of rows of the second. Let's say that I have two matrices, A and B, with dimensions MxN and UxV respectively. Then I can only perform matrix multiplication under the following conditions:
A = rand(M,N);
B = rand(U,V);
A*B % Only valid if N==U (result is a MxV matrix)
A'*B % Only valid if M==U (result is a NxV matrix)
A*B' % Only valid if N==V (result is a MxU matrix)
A'*B' % Only valid if V==M (result is a UxN matrix)
There are four more possible cases, but they are just the transpose of the cases shown. Now, since vectors are just a matrix with only one non-singleton dimension, the same rules apply
A = [1 2 3]; % (A is a 1x3 matrix)
B = [1 2]; % (B is a 1x2 matrix)
A*B % Not valid!
A'*B % Valid. (result is a 3x2 matrix)
A*B' % Not valid!
A'*B' % Not valid!
Again, there are four other possible cases, but the only one that is valid is B'*A which is the transpose of A'*B and results in a 2x3 matrix.
Say I have three 3D arrays of size 2x2x2
u =[[3 4][9 8];[1 2][3 4]]
v =[[5 4][8 5];[3 2][-1 4]]
w =[[1 4][9 0];[4 5][3 1]]
I want to create a single 3d array of size 2x2x2 that stores these as a 3D vector where the elements are derived from the arrays u,v,w
V = [[(3,5,1)(4,4,4)][(9,8,9)(8,5,0)];[(1,3,4)(2,2,5)][(3,-1,3)(4,4,1)]]
Is there a way to specify and do this in matlab?
EDIT: I changed the representation to avoid any confusion about cell arrays. They are all numeric arrays.
P.S: I would also like this representation to have the capability of calculations like gradient and such ? Is that possible ?
Did you mean cell arrays like this?
u ={[3 4],[9 8];[1 2],[3 4]}
v ={[5 4],[8 5];[3 2],[-1 4]}
w ={[1 4],[9 0];[4 5],[3 1]} % (note the commas)
It would be very cumbersome to do it like this and it is much more straight-forward to use normal matlab 3D matrices like this:
u = cat(3,[3 4; 9 8],[1 2; 3 4])
v = cat(3,[5 4; 8 5],[3 2; -1 4])
w = cat(3,[1 4; 9 0],[4 5; 3 1])
You can simply concatenate those along the fourth dimension using the cat command like this:
V = cat(4, u, v, w)
The 3D vectors you are interested in are then in the last dimension of V, for example you can obtain the vector at (1,2,1) with
V(1,2,1,:)
or
>> squeeze(V(1,2,1,:))
ans =
4
4
4
if you want to get a 3x1 vector.
If you must you can get matrices from the cell arrays using cell2mat, and get them in the right dimensions using reshape. Check the matlab documentation for these:
doc cell2mat
doc reshape