How to manipulate matrix addition and multiplication for Euclidean distance computation? - matlab

I have the following:
A = [1 2 3; 4 5 6; 7 8 9];
B = [10 11 12; 13 14 15];
[N1, D1] = size(A);
[N2, D2] = size(B);
A_sq = sum(A.^2, 2);
B_sq = sum(B.^2, 2)';
D = A_sq(:,ones(1,N2)) + B_sq(ones(1,N1),:) - 2.*(A*B');
where D is N1 x D1 matrix.
I want to write expression for D in one single step, i.e., something like this (this is for illustration purpose, but it should compute the same Euclidean distance as the code above):
D = sum(A - B).^2;
I will appreciate any advise.

If you have the Statistics Toolbox you can use pdist2, which does just that:
D = pdist2(A,B).^2
Or you can do it manually with bsxfun and permute:
D = permute((sum(bsxfun(#minus, A, permute(B, [3 2 1])).^2,2)), [1 3 2]);
For your example matrices
A = [1 2 3; 4 5 6; 7 8 9];
B = [10 11 12; 13 14 15];
either of the above gives
D =
243 432
108 243
27 108

Related

How do I program a function that takes two matrices A and B as input and outputs the product matrix A*B?

How do I program a function that takes two matrices A and B as input and outputs the product matrix A*B? Using MATLAB, with loops and conditionals.
My attempt:
function prodAB=MultiplicoMatrices(A,B)
prod=0;
prodAB=[];
for i=1:length(A)
for j=1:length(B)
prod=prod+A(i,j)*B(j,i);
end
prodAB(i,j)=prod;
prod=0;
end
A =
1 2
3 4
B=[5 6 ; 7 8]
B =
5 6
7 8
>> prodAB=MultiplicoMatrices([1 2; 3 4],[5 6; 7 8])
prodAB =
0 19
0 50
You mean the triple-loop algorithm? You could write the function as follows.
function prodAB = MultiplicoMatrices(A,B)
prodAB = zeros(size(A,1),size(B,2));
for i = 1:size(A,1)
for j = 1:size(B,2)
prod = 0;
for k = 1:size(A,2)
prod = prod + A(i,k) * B(k,j);
end
prodAB(i,j) = prod;
end
end
end
Now test it,
A = [1 2; 3 4];
B = [5 6; 7 8];
MultiplicoMatrices(A,B)
ans =
19 22
43 50
A * B
ans =
19 22
43 50
so, it works.

How to assemble 2x2x1000 array from four 1000x1 arrays

We have four 771x1 arrays that we want to form a 2x2x771 array.
How to make R from H L N and P?
H = [1 2 3 4 5]';
L = [6 7 8 9 10]';
N = [11 12 13 14 15]';
P = [16 17 18 19 20]';
R = [1 6; 11 16];
R(:,:,2) = [2 7; 12 17];
R(:,:,3) = [3 8; 13 18];
R(:,:,4) = [4 9; 14 19];
R(:,:,5) = [5 10; 15 20];
R
Simple:
R=permute(reshape([H,L,N,P]',2,2,[]),[2 1 3])

Combine index-based and logical addressing in Matlab

Consider a matrix X. I have to update a submatrix of X, X(row1:row2, col1:col2), with a matrix Z (of size row2-row1+1, col2-col1+1) but only on those positions where a logical matrix L (of size row2-row1+1, col2-col1+1) is true.
E.g. if
X=[ 1 2 3 4 5 6
11 12 13 14 15 16
21 22 23 24 25 26
31 32 33 34 34 36]
Z=[31 41
32 42]
L=[ 1 0
0 1]
row1 = 2; row2 = 3; col1 = 3; col2 = 4
then after the update I should get:
X=[ 1 2 3 4 5 6
11 12 31 14 15 16
21 22 23 42 25 26
31 32 33 34 34 36]
Currently I do the following:
Y = X(row1:row2, col1:col2);
Y(L) = Z(L);
X(row1:row2, col1:col2) = Y;
This code is in a tight loop and according to Matlab's (v2019a) profiler is the main bottleneck of my program. In the real code X is a 2000x1500x3 cube; row1, row2, col1, col2, Z and L change in the loop.
The question is whether it can be rewritten into a single / faster assignment.
Thanks.
Honestly, without seeing your actual code, I get the sense that your solution may be as fast as you can get. The reason I say that is because I tested a few different solutions by creating some random sample data closer to your actual problem. I assumed X is an image of type uint8 with size 2000-by-1500-by-3, Z is size N-by-N (i.e. we will only be modifying the first page of X), L is an N-by-N logical array, and the row and column indices are randomly chosen:
X = randi([0 255], 2000, 1500, 3, 'uint8');
N = 20; % Submatrix size
Z = randi([0 255], N, N, 'uint8');
L = (rand(N, N) > 0.5);
row1 = randi([1 2000-N]);
row2 = row1+N-1
col1 = randi([1 1500-N]);
col2 = col1+N-1;
I then tested 3 different solutions: your original solution, a solution using find and sub2ind to create a linear index for X, and a solution that creates a logical index for X:
% Original solution:
Y = X(row1:row2, col1:col2, 1);
Y(L) = Z(L);
X(row1:row2, col1:col2, 1) = Y;
% Linear index solution:
[rIndex, cIndex] = find(L);
X(sub2ind(size(X), rIndex+row1-1, cIndex+col1-1)) = Z(L);
% Logical index solution
[R, C, ~] = size(X);
fullL = false(R, C);
fullL(row1:row2, col1:col2) = L;
X(fullL) = Z(L);
I tested these repeatedly with randomly-generated sample data using timeit and found that your original solution is consistently the fastest. The linear index solution is very close, but slightly slower. The logical index solution takes more than twice as long.
Let's define some example data:
X = randi(9,5,6);
Y = 10+X;
row1 = 2;
row2 = 4;
col1 = 3;
col2 = 4;
L = logical([0 1; 0 0; 1 1]);
Then:
ind_subm = bsxfun(#plus, (row1:row2).',size(X,1)*((col1:col2)-1));
% linear index for submatrix
ind_subm_masked = ind_subm(L);
% linear index for masked submatrix
X(ind_subm_masked) = Y(ind_subm_masked);
Example results:
X before:
X =
6 2 1 7 9 6
3 3 3 5 5 7
6 3 8 6 5 4
7 4 1 3 3 4
2 5 9 5 5 9
L:
L =
3×2 logical array
0 1
0 0
1 1
X after:
X =
6 2 1 7 9 6
3 3 3 15 5 7
6 3 8 6 5 4
7 4 11 13 3 4
2 5 9 5 5 9

Sort the row of one matrix with respect to another matrix

I have two different matrices A and B:
A =
[7 8 9;
4 5 6]
B =
[22 32 12;
9 8 10]
sortB =
[12 22 32;
8 9 10]
sortindex_B=[3 1 2;2 1 3];, i.e., 12 is in the third position of matrix B, 22 in first, and 32 in second position; similarly for the second row.
Now I want to sort A depending on Sortindex_B (i.e., in matrix A I want 7 as the third element, 8 as the first, and 9 as the second element of the first row; and similarly for the second row: 4 at the second, 5 at the first, and 6 as the third element). Hence the result should look like:
A_final =
[8 9 7;
5 4 6]
How can I achieve this?
You can ask for the sorting index matrix from sort command, when sorting B, and thereafter operate on A as a cell, in so making cellfun available:
A = [7 8 9; 4 5 6];
B = [22 32 12; 9 8 10];
[sortB, I] = sort(B,2);
Icell = mat2cell(I,ones(1, size(I,1)),size(I,2));
Acell = mat2cell(A,ones(1, size(I,1)),size(I,2));
sortA = cell2mat(...
cellfun(#(x,y) y(x), Icell, Acell, 'UniformOutput', false))
Output (you state first row output as 8 9 7, but did you really mean 9 7 8?)
sortA =
9 7 8
5 4 6
For sorting as specifically specified in your question; re-map index matrix I:
A = [7 8 9; 4 5 6];
B = [22 32 12; 9 8 10];
[sortB, I] = sort(B,2);
%// re-map I
for i = 1:size(I,1)
Itmp = I(i,:);
for j = 1:size(I,2)
I(i,Itmp(j)) = j;
end
end
Icell = mat2cell(I,ones(1, size(I,1)),size(I,2));
ImapCell = mat2cell(Imap,ones(1, size(I,1)),size(I,2));
Acell = mat2cell(A,ones(1, size(I,1)),size(I,2));
sortA = cell2mat(...
cellfun(#(x,y) y(x), Icell, Acell, 'UniformOutput', false))
Output
sortA =
8 9 7
5 4 6
Use a combination of sort as in dfri's answer and sub2ind:
A = [7 8 9;
4 5 6];
B = [22 32 12;
9 8 10];
[sortB, sortindex_B] = sort(B,2);
[~, colIdx] = sort(sortindex_B,2);
rowIdx = ndgrid(1:size(B,1),1:size(B,2));
idx = sub2ind(size(B),rowIdx,colIdx);
sortA = A(idx)
ans =
8 9 7
5 4 6
you will have to do this row by row using the index values that the sort function returns.
Something like this should do the trick and is expandable to any number of rows that your matrix A and B may have. This does also validate that A and B are the same size before it continues.
B= [22 32 12; 9 8 10]
A = [7 8 9; 4 5 6];
assert(all(size(A) == size(B)));
sortB = zeros(size(B));
finalA= zeros(size(A));
for i = 1:size(B,1)
[sorted,idx] = sort(B(i,:));
sortB(i,:) = sorted;
tempA = A(i,:);
tempA = tempA(idx);
finalA(i,:) = tempA;
end
There are many clever ways to do this, including this for loop. I hope the comments will explain the logic.
clear; %// input the sample data
A = [7 8 9; 4 5 6];
B = [22 32 12; 9 8 10];
sortB = [12 22 32; 8 9 10];
%// loop through every element in B
[R C]=size(B);
for i=1:C
for j=1:R
%// Where does A(j,i) need to go in Afinal?
%// It needs to go in the j-th row, and in
%// whatever column of B(j,:) equals sortB(j,i).
Afinal( j , find( B(j,:) ==sortB(j,i)) ) = A(j,i);
end
end
And the result:
>> Afinal
Afinal =
8 9 7
5 4 6

MATLAB plot with sorted order

I have two vectors in MATLAB, say:
x = [1 20 3 7 10]
and
y = [2 51 1 9 18]
How can I plot y vs K where x has sorted value order (1 3 7 10 20) with their respective y values like the following?
x = [1 3 7 10 20]
y = [2 1 9 18 51]
Call sort with a second output argument.
x = [1 20 3 7 10]
y = [2 51 1 9 18]
[xsorted, I] = sort(x)
ysorted = y(I)
XY = sortrows([x ; y]');
plot(XY(:,1), XY(:,2));
Concatenate the matrices, transpose them and then you can use sortrows to order by X