Symmetrically extending a matrix - matlab

How can I extend a matrix in MATLAB by symmetrically replicating the boundary values? For example, if X is my matrix, extended matrix Xextsym should look like the following:
X =
1 2 3
4 5 6
Xextsym =
5 4 4 5 6 6 5
2 1 1 2 3 3 2
2 1 1 2 3 3 2
5 4 4 5 6 6 5
5 4 4 5 6 6 5
2 1 1 2 3 3 2
I'm aware that a function called wextend exists in the Wavelet Toolbox for this task exactly, but I don't have it.

Here is a function that extends a given matrix A by symmetric reflection, adding w element in each of four directions. Usage example:
symextend([1 2 3; 4 5 6], 2)
returns the extended matrix in your question.
function R = symextend(A, w)
[m, n] = size(A);
B = [A A(:, n:-1:1); A(m:-1:1, :) A(m:-1:1, n:-1:1)];
repm = 2*ceil(0.5+0.5*w/m);
repn = 2*ceil(0.5+0.5*w/n);
C = repmat(B, repm, repn);
R = C(m*repm + 1 - w : m*repm + m + w, n*repn + 1 - w : n*repn + n + w)
end
Idea: first reflect A once in each direction (this produces B), then repeat B with repmat, obtaining C. Finally, a suitable piece is carved out of C. The tricky parts are counting how many times to repeat, and which part to carve out.

Related

Creating a matrix according to some rules

How can I generate the following matrix having m rows and n columns?
1st row 1 2 3 L n-1 n
2nd 2 3 4 L n 1
3rd 3 4 5 n-1 1 2
Nth M M M ....
N-1 m-1 m m+1 L m-3 m-2
last m m+1 m+2 l m-2 m-1
It's difficult to tell from your description, but it appears you want to create a matrix where the first row is 1:n and each successive row is a circular shift to the left of the previous row. If so, you can still use hankel for this (as Dev-iL mentions in their answer), but incorporate a remainder operation like so:
n = 5;
m = 8;
mat = rem(hankel(0:(m-1), (m-1):(m+n-2)), n)+1
mat =
1 2 3 4 5
2 3 4 5 1
3 4 5 1 2
4 5 1 2 3
5 1 2 3 4
1 2 3 4 5
2 3 4 5 1
3 4 5 1 2
This looks like a Hankel matrix. You should use the 2-input syntax for it,
H = hankel(c,r)
So for example, with m = 4 and n = 5 we get:
m = 4; n = 5;
X = hankel( 1:m, m:m+n-1 )
X =
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8

How to align vectors with asynchronous time stamp in matlab?

I would like to align and count vectors with different time stamps to count the corresponding bins.
Let's assume I have 3 matrix from [N,edges] = histcounts in the following structure. The first row represents the edges, so the bins. The second row represents the values. I would like to sum all values with the same bin.
A = [0 1 2 3 4 5;
5 5 6 7 8 5]
B = [1 2 3 4 5 6;
2 5 7 8 5 4]
C = [2 3 4 5 6 7 8;
1 2 6 7 4 3 2]
Now I want to sum all the same bins. My final result should be:
result = [0 1 2 3 4 5 6 7 8;
5 7 12 16 ...]
I could loop over all numbers, but I would like to have it fast.
You can use accumarray:
H = [A B C].'; %//' Concatenate the histograms and make them column vectors
V = [unique(H(:,1)) accumarray(H(:,1)+1, H(:,2))].'; %//' Find unique values and accumulate
V =
0 1 2 3 4 5 6 7 8
5 7 12 16 22 17 8 3 2
Note: The H(:,1)+1 is to force the bin values to be positive, otherwise MATLAB will complain. We still use the actual bins in the output V. To avoid this, as #Daniel says in the comments, use the third output of unique (See: https://stackoverflow.com/a/27783568/2732801):
H = [A B C].'; %//' stupid syntax highlighting :/
[U, ~, IU] = unique(H(:,1));
V = [U accumarray(IU, H(:,2))].';
If you're only doing it with 3 variables as you've shown then there likely aren't going to be any performance hits with looping it.
But if you are really averse to the looping idea, then you can do it using arrayfun.
rng = 0:8;
output = arrayfun(#(x)sum([A(2,A(1,:) == x), B(2,B(1,:) == x), C(2,C(1,:) == x)]), rng);
output = cat(1, rng, output);
output =
0 1 2 3 4 5 6 7 8
5 7 12 16 22 17 8 3 2
This can be beneficial for particularly large A, B, and C variables as there is no copying of data.

using Mean Square Error to create an index matrix matlab

The Mean Square Error(MSE), is a method used to define the difference in between two blocks, and can be calculated as follow:
a and b two blocks equal size
MSE = sqrt(sum(sum((a-b).^2)))/size(a or b)
If the MSE is less than a given threshold, than the two blocks are not diffrent.
Given two matrix A and B, the purpose is to divide the two matrix to blocks of a given size, then extract the first block from A and let it be a, then search for a block b from B where the Mean Square Error between a and b is less then a given threshold, then return the position of the block b from the matrix B. and so on. and here is an example:
Given two matrix A and B where:
A= [1 1 4 4 2 2
1 1 4 4 2 2
2 2 9 9 5 5
2 2 9 9 5 5
3 3 4 4 9 9
3 3 4 4 9 9];
B = [ 2 2 4 4 9 9
2 2 4 4 9 9];
the threshold is 2
The first block a obtained from the matrix A is:
1 1
1 1
The block b obtained from the matrix B that MSR between a and b is less than the threshold is:
2 2
2 2
Therefore we return the position of the block b in the matrix B which is 1
The second block a obtained from the matrix A is:
4 4
4 4
The block b obtained from the matrix B where MSR between a and b is less than threshold is:
4 4
4 4
Therefore we return the position of the block b in the matrix B which is 2. and so on.
The final result should be as follow
RES= [1 2 1
1 3 2
1 2 3];
Is there a faster way?
Here's a vectorized approach with bsxfun.
First define data:
A = [1 1 4 4 2 2
1 1 4 4 2 2
2 2 9 9 5 5
2 2 9 9 5 5
3 3 4 4 9 9
3 3 4 4 9 9]; %// data: A
B = [2 2 4 4 9 9
2 2 4 4 9 9]; %// data: B
m = 2; %// number of rows per block
n = 2; %// number of cols per block
Then apply the following steps:
Reshape matrices so that each block is a row (inspired by this great answer).
Compute the MSE for all pairs of blocks.
Find the argmin of the MSE with respect to blocks of B (for each block of A). Note that if there are several minimizing blocks in B this finds the first.
Reshape result into a matrix.
Code:
A2 = reshape(permute(reshape(A, size(A, 1), n, []), [2 1 3]), n*m, []); %// step 1
B2 = reshape(permute(reshape(B, size(B, 1), n, []), [2 1 3]), n*m, []);
mse = squeeze(sum(bsxfun(#minus, A2, permute(B2,[1 3 2])).^2, 1)); %// step 2
[~, result] = min(mse, [], 2); %// step 3
result = reshape(result, size(A,1)/m, size(A,2)/n); %// step 4

Build a huge matrix with vector components in MATLAB

How can I avoid using a double for loop in order to build a matrix pos like this code does:
pos=[0 0];
for i=1:m;
for j=1:n;
pos=[pos; i j];
end
end
m and n are numbers such as 500 and 900.
I have to find a better solution in order improve computation time.
Thank you so much.
You can easily do this by meshgrid.
[X,Y] = meshgrid(1:m, 1:n);
pos = [0 0; X(:) Y(:)];
How the above code works is the following. meshgrid (in this case) creates a 2D grid of (X,Y) co-ordinates. X progresses horizontally while Y progresses vertically. As we can see in your for loops, m defines the horizontal boundaries while n denotes the vertical boundaries. By calling meshgrid(1:m, 1:n), I am creating a n x m grid for both X and Y, where each row of X progresses from 1 to m, while each column of Y progresses from 1 to n. Therefore, these will both be n x m matrices. Calling the above with m = 4 and n = 5 computes:
m = 4;
n = 5;
[X,Y] = meshgrid(1:m, 1:n)
X =
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
Y =
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
5 5 5 5
This almost follows the format you wish. You'll notice that by looking at the columns individually, this achieves what you want, but you want to stack all of the X and Y to be in a (n x m) + 1 x 2 matrix (1 to account for [0 0]). All we have to do now is take every column of X and Y and stack them on top of each other to create a single column for both. We can stack all of these together by doing X(:) and Y(:). X(:) will take every column of X and create a single column that stacks all of the columns together. The same is done for Y(:). As such, we first create pos by attaching [0 0] as the first row, and we then attach X(:) and Y(:) as columns to pos after, thus completing the construction of pos.
Let's do an example as a proof-of-concept. Suppose that we use the same values like we did before:
m = 4;
n = 5;
Using your for loop, we get:
pos =
0 0
1 1
1 2
1 3
1 4
1 5
2 1
2 2
2 3
2 4
2 5
3 1
3 2
3 3
3 4
3 5
4 1
4 2
4 3
4 4
4 5
Using the code I have written, we also get:
pos =
0 0
1 1
1 2
1 3
1 4
1 5
2 1
2 2
2 3
2 4
2 5
3 1
3 2
3 3
3 4
3 5
4 1
4 2
4 3
4 4
4 5
Minor Note
As you stated that m and n are going to be relatively large, I would recommend you clear X and Y from your workspace before you proceed. X and Y were only created to help you create pos. As you don't need them anymore, after you calculate pos, do:
clear X;
clear Y;

Construct columns from submatrices in Matlab

In Matlab, I'm trying to transform a matrix A to another matrix B such that B's columns are made up of square submatrices of A. For example, if A is:
A = [1 1 2 2
1 1 2 2
3 3 4 4
3 3 4 4];
I'd like B to be:
B = [1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4]
A could be, say 16-by-16, and constructing B from 4-by-4 squares would result in B being 4-by-64.
Is there an efficient way to do this using reshape in combination with some other commands? Or some other approach? I am currently iterating in a loop, which is very slow with a large number of large source matrices.
Assume your matrix is a bit more general, and made of 3x2 blocks:
A = [1 1 2 2
1 1 2 2
1 1 2 2
3 3 4 4
3 3 4 4
3 3 4 4
5 5 6 6
5 5 6 6
5 5 6 6];
b = [3 2];
szA = size(A);
Transpose, reshape, permute, reshape.
nb = prod(szA./b); % Number of blocks
nelb = prod(b); % Number of elements per block
out1 = reshape(permute(reshape(A',szA(2),b(1),szA(1)/b(1)),[2,1,3]),nelb,nb)
Alternatively, slower and memory intensive but more readable:
d1 = repmat(b(1),1,szA(1)/b(1));
d2 = repmat(b(2),1,szA(2)/b(2));
out = reshape(mat2cell(A,d1,d2)',1,nelb);
out = reshape([out{:}],nelb,nb)
Now, if the blocks are square, simply set b = [2,2] or b = [3,3], etc..., or simplify the general formulation removing indexing of b and prod.