Apply a function to all column pairs between two matrices in Matlab - matlab

I have a Matlab function z = foo(x, y) that takes two column vector as inputs and output a scalar. Now I would like to apply this function to two matrices A(dimension n * d1) and B (dimension n * d2) and generate a d1 * d2 matrix, such that output(i, j) = foo( A(:, i), B(:, j) ). It should basically resemble the behavior of applying the corr function to two matrices.
I tried the solutions in this link, but the encounter the same problem in the first answer, and the meshgrid step in second solution is way too slow.
Any suggestions? Thanks very much in advance!

If foo accepts a matrix then:
%Find dimensions
dA = size(A,2);
dB = size(B,2);
%Generate a list of all possible column pairs for the two matrices
indA = ceil((1:dA*dB)/dA);
indB = mod(0:dA*dB, dB)+1;
X = A(:, indA);
Y = B(:, indB);
z = foo(X,Y)
then you'll probably be able to reshape z to what you want

Related

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))

Perform element wise multiplication of vectors efficiently?

I have to perform matrix updating by M = M + c*a*a' large number of times, where c is a constant and a is a column vector. If the size of matrix is larger than 1000, this simple updating will cost most of the time of my function, typically more than 1 min counted by profile.
Main codes are:
for i = 1:N
_do something..._
for k = 1:n
a(1:k) = M(1:k,1:k)*p(1:k);
M(1:k,1:k) = M(1:k,1:k)+c*a(1:k)*a(1:k)';
M(1:k, k+1) = b(1:k);
M(k+1, 1:k) = b(1:k)';
M(k+1, k+1) = x;
......
end
end
I have preallocated all variables, column vectors p and b are known, and x is another constant.
As I have large number of data to process by this function, does there exist more efficient alternative to this matrix updating?
You can concatenate a vectors to create a matrix A then apply multiplication just one time.
A =[a1 a2 a3];
M = c * A * A.';
consider the example
A = rand(5,5);
M = 0;
c=4;
for n = 1:5
M = M + c * A(:,n) * A(:,n).';
end
and this one
M1 = c * A * A.'
both M and M1 are equal
Have you tried using bsxfun?
In any case, bsxfun is much faster than regular multiplication, but the vectors/matrices have to be of equal length (which they are for you, aren't they?), and it's operating elementwise (i.e. a Nx1 vector bsx-multiplied with itself yields a Nx1 vector, multiplied with the transpose however yields a NxN matrix).
see https://mathworks.com/help/matlab/ref/bsxfun.html
use as
bsxfun(#times, a, a')

Vectorize weighted sum matlab

I was trying to vectorize a certain weighted sum but couldn't figure out how to do it. I have created a simple minimal working example below. I guess the solution involves either bsxfun or reshape and kronecker products but I still have not managed to get it working.
rng(1);
N = 200;
T1 = 5;
T2 = 7;
A = rand(N,T1,T2);
w1 = rand(T1,1);
w2 = rand(T2,1);
B = zeros(N,1);
for i = 1:N
for j1=1:T1
for j2=1:T2
B(i) = B(i) + w1(j1) * w2(j2) * A(i,j1,j2);
end
end
end
A = B;
You could use a combination of bsxfun, reshape and permute to accomplish this.
We first use permute to move the N dimension to the 3rd dimension of A. We then multiply w1 and the transpose of w2 to create a grid of weights. We can then use bsxfun to perform element-wise multiplication (#times) between this grid and each "slice" of A. We can then reshape the 3D result into M x N and sum across the first dimension.
B = sum(reshape(bsxfun(#times, w1 * w2.', permute(A, [2 3 1])), [], N)).';
Update
There's actually a simpler approach which would use matrix multiplication to perform the summation for you. It unfortunately has to be broken into
% Create the grid of weights
W = w1 * w2.';
% Perform matrix multiplication between a 2D version of A and the weights
B = reshape(A, N, []) * W(:);
Or you could use kron to create the flattened grid of weights:
B = reshape(A, N, []) * kron(w2, w1);

How to efficiently get all elements along 3rd direction at specified locations in a matrix?

A is an M*N*S matrix of values and B is a P*1 vector of indices of locations in an M*N matrix. I want to get the P*S matrix, C, that is all values along 3rd direction form A, at locations specified by B (on the A(:, :, 1)).
This is my current code:
%% sample inputs
M = 2; N = 3; S = 3;
A = reshape(1:M*N*S, M, N, S)
B = (1:3:M*N)'
P = numel(B);
%% solution
B2 = repmat(B, 1, S)+repmat((0:S-1)*M*N, P, 1);
C = A(B2)
But it calls repmat twice, and I need this in a for loop that P changes in every iteration. So how can I make it more efficient?
First of all, I would strongly discourage the use of O as a variable name. It looks like a zero. Similarly, avoid a lower-case l as it looks like a 1. Below I will use S in place of your O.
You can simply reshape your initial matrix into an [M*N, S] matrix and then user the indices on the first column.
% Collapse the first two dimensions into rows
data = reshape(A, [], size(A, 3));
% Grab the rows that correspond to the indices in B
C = data(B, :);
The use of reshape is very efficient here because MATLAB doesn't need to make a copy of the underlying data, just alter how it is accessed.

Vectorizing a weighted sum of matrices in MATLAB

I'm trying to vectorize the following operation in MATLAB, but it's got me stumped. I've learned from experience that there usually is a way, so I'm not giving up just yet. Any help would be appreciated.
I have a collection of m row-vectors each of size n, arranged in an m x n matrix; call it X.
I also have an m-sized vector of weights, w.
I want to compute a weighted sum of the matrices formed by the self outer products of the vectors in X.
Here is a MWE using a for loop:
m = 100;
n = 5;
X = rand(m, n);
w = rand(1, m);
S = zeros(n, n);
for i = 1 : m
S = S + (w(i) * X(i, :)' * X(i, :));
end
S
This is probably the fastest approach:
S = X' * bsxfun(#times, X, w(:));
You could also do
S = squeeze(sum(bsxfun(#times, ...
bsxfun(#times, conj(X), permute(X, [1 3 2])), w(:)), 1));
(or remove the complex conjugate if not needed).
You can employ two approaches here that use one bsxfun call and few permutes and reshapes. The reshaping trick basically allows us to use the efficient matrix multiplication and thus avoid any extra bsxfun call we might have required otherwise.
Approach #1
[m1,n1] = size(X);
XXmult = bsxfun(#times,X,permute(X,[1 3 2])); %// For X(i, :)' * X(i, :) step
S = reshape(reshape(permute(XXmult,[2 3 1]),[],m1)*w(:),n1,[]) %// multiply weights w
Approach #2
[m1,n1] = size(X);
XXmult = bsxfun(#times,permute(X,[2 3 1]),permute(X,[3 2 1]));
S = reshape(reshape(XXmult,[],m1)*w(:),n1,[])
Shortest answer, and probably fastest:
S = X'*diag(W)*X
Been using it for an unscented Kalman filter, works great.