Scalar-Vector multiplication with meshgrid (Matlab) - matlab

I have an expression such as s=aU+bV, where a and b are scalars and U and V 3-component vectors. The output s is clearly a 3-component vector. Let's assume I want to plot the first component of s find out how this varies when I change a and b.
In order to plot I have to use surf, which takes matrices for the variables a b. So I attempt to create matrices with meshgrid:
A=0:10;
B=1:10;
[a,b]=meshgrid(A,B);
U=[1,1,0];
V=[1,0,1];
s = a*U + b*V;
This clearly doesn't work, because nor the matrix product nor the element-wise product are well defined in this case. How do I actually make the matrices which represent the grid a b multiply element-by-element the vectors U and V?

You want to use element-wise multiplication (.*) because you still want to treat a and b as scalars (i.e. use each element individually).
You can make a 3D output, where each 2D slice corresponds to your meshgrid output, with one slice per component of U and V. Therefore in this example getting a 10*11*3 matrix.
To do this, just reshape the U and V vectors to be 1*1*3 in size
U = reshape( [1,1,0], 1, 1, [] ); % Or equivalently U(1,1,:) = [1,1,0]
V = reshape( [1,0,1], 1, 1, [] ); % Or equivalently U(1,1,:) = [1,0,1]
Then do element-wise multiplication
s = a.*U + b.*V;
Note: before MATLAB R2016b (when implicit expansion was introduced) you'll have to use bsxfun to get the equivalent:
s = bsxfun( #times, a, U ) + bsxfun( #times, b, V );
You can then plot the ith element of S changing with A and B by plotting s(:,:,i).

You could do it using a 3D matrix:
[A,B] = meshgrid(0:10,1:10);
U(1,1,:) = [1,1,0];
V(1,1,:) = [1,0,1];
s = A.*U + B.*V;
% s is now a NxMx3 matrix, where N = length(A) and M = length(B)
% We can plot how s varies with a and b as follows
surf(A,B,s(:,:,1)); % first component
surf(A,B,s(:,:,2)); % second component
surf(A,B,s(:,:,3)); % third component

Related

Best way to perform a convolution with a new vector for each image?

I try to figure out the best way to perform a kind of convolution.
I have a 3D matrix I = [N x M x P] and a 2D matrix S = [1 x 1 x K x P]. For each pth frame (third dimension) of my 3D matrix I want to return the valid convolution between I(:, :, p-K/2:p+K/2) and S(1, 1, :, p). Do you see a way to do this ?
In fact, in terms of computation the numbers of operation in very close to a standard convolution, the difference is that I need to change the second matrix for each frame...
This is the method I currently use:
% I = 3D matrix [N x M x P]
% S = Filter [1 x 1 x K x P] (K is an odd number)
% OUT = Result
[N, M, P] = size(I); % Data size
K = size(S, 3); % Filter length
win = (K-1)/2 ; % Window
OUT = zeros(size(I)); % Pre-allocation
for p = win+1:P-win
OUT(:, :, p) = convn(I(:, :, p-win:p+win), S(1, 1, :, p), 'valid'); % Perform convolution
end
At the end we have the same number of operations than the standard convolution, the only difference is that the filter is different for each frame...
Any idea ?
Thanks ;)
So you want to convolve a NxMxK sub-image with a 1x1xKx1 kernel, and then only take the valid part, which is an NxM image.
Let's look at this operation for a single (x,y) location. This 1D convolution, of which you only keep 1 value, is equivalent to the dot product of the sub-image and your kernel:
OUT(x,y,p) = squeeze(I(x,y,p-win:p+win))' * squeeze(S(1,1,:,p))
This you can vectorize across all (x,y) by reshaping the sub-image of I to a (N*M)xK matrix (the K is horizontal, S is a column vector).
Repeating this across all p is easiest to implement with a loop, as you do now. The alternative is to create a larger S where each column is shifted by one, so you can do a single dot product between tge two matrices. But that S is also espensive to create, presumably requires a loop too. I don't think that avoiding loops is that pressing any more in MATLAB (it's gotten a lot faster over the years) and the product itself is probably the most expensive part of the algorithm anyway.

Linear combination of the Slices in a 3D

I have a 3D matrix sized (x,y,N) and a 2D matrix sized (N,N).
I would like to manipulate the two in a way that each column in the 2D matrix has the coefficients for a linear combination of the 2D sized- (x, y) slices in the 3D matrix. And I would like to do this for all N columns in the 2D matrix.
Schematically,
Currently the code looks like:
A = zeros(numel(x_axis), numel(y_axis), N);
B = zeros(numel(x_axis), numel(y_axis), N);
C = zeros(N, N)
for i = 1 : N
for j = 1 : N
A(:,:,i) = A(:,:,i) + B(:,:,j) * C(j,i);
end
end
But it is quite slow. Is there any way to speed up the MATLAB code by vectorizing?
If I understand your problem well, then this should work:
[p,q,N] = size(B);
A = reshape( reshape(B, [p*q, N]) * C, [p, q, N]);
edit: Cleaner version suggested by Suever:
A = reshape(reshape(B, [], size(B, 3)) * C, size(B))
Generalization to the R-D case:
A = reshape(reshape(B, [], size(B, ndims(B))) * C, size(B))
You can use bsxfun which will calculate this very quickly for you. We have to use permute to re-arrange C a little bit to ensure that it has conformant dimensions for using bsxfun and then we perform the summation along the third dimension of the resulting output and apply squeeze to remove the singleton third dimension.
A = squeeze(sum(bsxfun(#times, B, permute(C, [3 4 1 2])), 3))

Finding rotation between vectors in Matlab, from matrices of x and y components [duplicate]

This question already has answers here:
Angle between two vectors matlab
(6 answers)
Closed 7 years ago.
I am trying to find the angle of rotation between two sets of vectors, each plotted using the quiver() command. I would like the smaller angle between the vectors.
For each set of vectors, I am passing four 654x470 matrices to quiver(), where the first two matrices are simply x and y map positions, and the second two matrices are the x-component and y-component magnitudes, respectively.
So all I have to work with is the x-component and y-component matrices for each set of vectors. Ultimately, I would like a resulting 654x470 matrix that is the angle of rotation between the two vectors at each point.
I believe I need to solve for theta in the following:
cosθ = (u⃗ · v⃗) / (||u⃗|| ||v ⃗ ||)
But I am unsure how to implement the dot product, only using the 654x470 matrices of the x and y components for u and v.
This question is unique in that the vectors are 2D, and need to be computed from x and y components.
If you simply want the angle between the points, you can implement the angle formula in vectorized form.
% Toy Example Data
A = rand(654,470);
B = rand(654,470);
C = rand(654,470);
D = rand(654,470);
% Create a Vector of Vectors
u = [A(:); B(:)];
v = [C(:); D(:)];
% Declare euclidian norm function
n = #(x) sum( sqrt( x .* x ) );
G = acos( dot( u, v ) ./ n( u ) ./ n( v ) );
% Reshape into original dimensions
G = reshape( G, 654, [] );
First, vectorize A,B,C,D using the (:) operator. The function n performs the norm calculation, the first G will use the angle formula. The second G calculation reshapes it into it's original dimensions.

Plot first element of vector in A^x * v in Matlab (matrix powers)

I want to plot A^x * v, where A is a square matrix represent an adjacency matrix in a graph, x is the number of steps, and v is the initial vector.
My goal is to plot the first element of each resulting vector; that is, I want A*v[1], A^2*v[1], A^2*v[1]
I tried
x = 1:1:50
y = A^x*v
plot(y(1),x)
But got
Error using ^
Inputs must be a scalar and a square matrix.
To compute elementwise POWER, use POWER (.^) instead.
I understand the error, but don't understand how else to approach this problem, just going off Matlab's plot examples.
Thanks in advance for the help!
If you want an almost one liner:
x = 1:1:50;
f = #(z) z(1);
plot(x, arrayfun(#(n) f(A^n*v), x))
The error in what you tried comes from A^x: x cannot be a vector, it must be a scalar because A is a square matrix. See the help of mpower for more info.
How about saving some of the computations?
To get the first element you don't need to compute the entire product A*v.
x = 1:1:50;
f = (n) A(1,:) * ( A^(n-1) ) * v; % returns a scalar - no redundant computation
plot( x, arrayfun( f, x ) );
A modification to #Simon's answer, using subsref rather than anonymous function.
x = 1:1:50;
s.type = '()';
s.subs = {1};
plot( x, arrayfun( #(n) subsref( (A^n)*v, s ), x ) );
See also this answer about subsref.

How to compute cosine similarity using two matrices

I have two matrices, A (dimensions M x N) and B (N x P). In fact, they are collections of vectors - row vectors in A, column vectors in B. I want to get cosine similarity scores for every pair a and b, where a is a vector (row) from matrix A and b is a vector (column) from matrix B.
I have started by multiplying the matrices, which results in matrix C (dimensions M x P).
C = A*B
However, to obtain cosine similarity scores, I need to divide each value C(i,j) by the norm of the two corresponding vectors. Could you suggest the easiest way to do this in Matlab?
The simplest solution would be computing the norms first using element-wise multiplication and summation along the desired dimensions:
normA = sqrt(sum(A .^ 2, 2));
normB = sqrt(sum(B .^ 2, 1));
normA and normB are now a column vector and row vector, respectively. To divide corresponding elements in A * B by normA and normB, use bsxfun like so:
C = bsxfun(#rdivide, bsxfun(#rdivide, A * B, normA), normB);
You can use scipy to compute it very easily.
from scipy.spatial import distance
cosine_sim = 1 - sp.distance.cdist(A, B, 'cosine')
All you need to do is pass your 2D matrices in above formula and spicy will return you numpy array.
Refer doc here: https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.cdist.html