Make matrix from shifted vector matlab vectorization - matlab

Geetings, here's the little problem.
I have a vector v (size(v) = T), a positive number P, P < T nad positive number N, N < T. And want to make matrix M with size PxN, so that:
M = [v(T), v(T-1), ....., v(T-N+2), v(T-N+1);
v(T-1), v(T-2), ....., v(T-N+1), v(T-N) ;
v(T-2), v(T-3), ....., v(T-N), v(T-N-1);
. . . . . ;
. . . . . ;
v(T-P+1), v(T-P), ....., v(T-P-N+3), v(T-P-N+2)]
It holds that T > P + N.
Let given an example.
v = [1, 2, 3, 4, 5]';
P = 3;
N = 3;
M = [5, 4, 3;
4, 3, 2;
3, 2, 1]
I know how to do this using for loop, but I also think that it is possible do by vectorizations - here the problem is - I am not so skilled in vectorizations.
Thx for hints and so on :))

Use the Hankel matrix:
v = [1 2 3 4 5];
T = length(v);
P = 3;
N = 3;
out = hankel(v(T:-1:T-P+1),v(T-P+1:-1:T-P-N+2));

You can make use of bsxfun
v = [1, 2, 3, 4, 5]';
P = 3;
N = 3;
idx = bsxfun(#minus, length(v):-1:length(v)-N+1, (0:P-1)');
result = v(idx);
this will result in
result =
5 4 3
4 3 2
3 2 1

Related

How to permutate over columns for each row in a matrix in MATLAB?

I have a matrix
A = [1,2;3,4];
I would like to generate a new matrix B, which contains all permutations over the columns for each row.
B = [1,2;2,1;3,4;4,3]
Is there a one-liner solution?
I could only think of a solution incorporating cell arrays, thus I'm not sure, if that is "efficient" at all. Also, have a look at the limitations of perms.
% Input.
A = [1, 2; 3, 4]
% Expected output.
B = [1, 2; 2, 1; 3, 4; 4, 3]
% Calculate output.
C = sortrows(cell2mat(cellfun(#(x) perms(x), mat2cell(A, ones(1, size(A, 1)), 2), 'UniformOutput', false)))
A =
1 2
3 4
B =
1 2
2 1
3 4
4 3
C =
1 2
2 1
3 4
4 3
I found a solution to my own question.
n = 2; % size of permutations
perm_index = perms(1:n); % index of the matrix to perm
perm_length = size(perm_index,1);
data = [3,4;5,6];
data_length = size(data,1);
output_length = perm_length* data_length;
output = reshape(data(:,perm_index), output_length,n);
%Final output
output = [4,3;6,5;3,4;5,6]
I couldn't find any one-liner solution. Hope this one is simpler enough:
A = [1, 2, 3; 4, 5, 6];
B = [];
for i=1:size(A,1)
B = [B ; perms(A(i, :))];
end
Read about the function nchoosek
A = [1 2 3 4] ;
B = nchoosek(A,2)

Using Matlab to write a sequence

I'm struggling to write this question into Matlab Code. I know that I should use a 'for' loop, but I don't know how to use this to do it.
Consider the following sequence of row vectors v(n) for n ≥ 1:
v(1) = (1)
v(2) = (1, 1)
v(3) = (2, 1)
v(4) = (1, 2, 1, 1)
v(5) = (1, 1, 1, 2, 2, 1)
v(6) = (3, 1, 2, 2, 1, 1)
Each row is given by reading out the contents of the row above, so for example v(6) contains “three ones, two twos, one one” and this gives v6. Write a script to print v(n) for n = 1 up to n = 12.
One possible version:
N = 6;
v = cell(N,1);
v{1} = 1;
for ii = 2:N
v1 = v{ii-1};
stop_point = find(diff(v1));
if isempty(stop_point)
n = length(v1);
m = v1(1);
v{ii} = [n,m];
else
n = diff([0,stop_point,length(v1)]);
m = v1([stop_point,end]);
v2 = [n;m];
v{ii} = v2(:).';
end
end
Example output:
>> v{:}
ans =
1
ans =
1 1
ans =
2 1
ans =
1 2 1 1
ans =
1 1 1 2 2 1
ans =
3 1 2 2 1 1
>>
Note: Row vectors of unequal lengths cannot be contained in a matrix. An easy way to store them is using a cell array.

Matlab: interpolation operator for multigrid methods

I have to build the following matrix:
1 2 1
1 2 1
1 2 1
I tried the following:
N = 8;
full( ( spdiags(repmat([1/4,1/2,1/4], N/2-1, 1), 0:2, N/2-1, N-1) ) )
but the output is not what I want.
It is not clean but it should work anyway:
N = 10;
w(1, :) = [1, 2, 1, zeros(1, (N-1)-3)];
for i = 1:(N/2-2)
w(i+1, :) = [zeros(1, i*2), 1, 2, 1, zeros(1, (N-1)-(3+i*2))];
end
I'm sure this could be condensed a bit, but here's a solution without loops. Assuming h is the grid spacing and N=1/h-1 is odd:
wdiag = 2*ones(N,1);
wsubsuperdiag = ones(N,1);
w = spdiags([wsubsuperdiag wdiag wsubsuperdiag],[-2 -1 0],N,(N+1)/2-1);
w = 1/2*cell2mat(arrayfun(#(k) circshift(w(:,k),k-1),1:(N+1)/2-1,'uni',0));
Some credit to Jon.

How to update the length of a vector in matlab if statement

I'm using MATLAB to write a function, which can find all elements in vector v that are equal to scalar a, and change each one of them to [b c], finally return the new vector w. If v = [1 2 5], a = 2, b = 4, c = 3, then the result is w = [1 4 3 5].
Below is my code
function w = change(v, a , b ,c )
for ii = 1:length(v)
if v(ii) == a
v_1 = v(1:ii-1);
v_2 = v(ii+1:length(v));
v_3 = [b c];
v = [v_1 v_3 v_2];
end
end
w = v;
end
However, the problem is: for statement will only read the length of the v before the first run of the loop, in this way, if the size of vector is increased, then length(v) in if statement will not be updated thus ii can not cover all the element indices. For example, if my input is ([1 2 2 2 3 2 4 5 6 2], 2, 4, 4), then with my code, for will stop at ii = 10, which is length of the old v, and give a wrong result [1 4 4 4 4 4 4 3 4 4 4 5 6 2], which does not change the last element (because ii doesn't cover 15).
My question is: how to update length(v) in if statement? or is there any other better way to finish this task?
Thank you very much.
I think this will be easier if you do it with cell arrays.
function w = change(v, a , b ,c )
cellV = num2cell(v);
cellW = cellfun(#(x)(subFunction(x,a,b,c)),cellV,'uni',0);
w = [cellW{:}];
end
function out = subFunction(val,a,b,c)
if (val == a)
out = [b c];
else
out = x;
end
end
A simpler method than checking each element in a loop is to find where the new elements will go, by using find(v==a) and just loop on those cases (taking care with the indexing!):
s = find(v==a);
v(end+1:end+numel(s))=0;
for ii=1:numel(s)
ind=s(ii)+ii;
v(ind-1:end)=[b c v(ind:end-1)];
end

Filter matrix rows depending on values in a second matrix

Given a 2x3 matrix x and a 4x2 matrix y, I'd like to use each row of y to index into x. If the value in x is not equal to -1 I'd like to remove that row from y. Here's an example that does what I'd like, except I'd like to do it in a fast, simple way without a loop.
x = [1, 2, 3; -1, 2, -1];
y = [1, 1; 1, 3; 2, 1; 2, 3];
for i=size(y,1):-1:1
if x(y(i,1), y(i,2)) ~= -1
y(i,:) = [];
end
end
This results in:
y =
2 1
2 3
A raw approach to what sub2ind follows (as used by this pretty nice-looking solution posted by Luis) inherently would be this -
y = y(x((y(:,2)-1)*size(x,1)+y(:,1))==-1,:)
Benchmarking
Benchmarking Code
N = 5000;
num_runs = 10000;
x = round(rand(N,N).*2)-1;
y = zeros(N,2);
y(:,1) = randi(size(x,1),N,1);
y(:,2) = randi(size(x,2),N,1);
disp('----------------- With sub2ind ')
tic
for k = 1:num_runs
y1 = y(x(sub2ind(size(x), y(:,1), y(:,2)))==-1,:);
end
toc,clear y1
disp('----------- With raw version of sub2ind ')
tic
for k = 1:num_runs
y2 = y(x((y(:,2)-1)*size(x,1)+y(:,1))==-1,:);
end
toc
Results
----------------- With sub2ind
Elapsed time is 4.095730 seconds.
----------- With raw version of sub2ind
Elapsed time is 2.405532 seconds.
This can be easily vectorized as follows (see sub2ind):
y = y(x(sub2ind(size(x), y(:,1), y(:,2)))==-1,:);
>> x = [1, 2, 3; -1, 2, -1];
>>y = [1, 1;
1, 2;
1, 3;
2, 1;
2, 2;
2, 3];
>>row_idx = reshape((x == -1)',1,6);
>>y = y(row_idx,:);
I think you didn't include all the index of x in y. I included all of them in y. Have a look..
Generalized version:
>> x = [1, 2, 3; -1, 2, -1];
>>y = [1, 1;
1, 2;
1, 3;
2, 1;
2, 2;
2, 3];
>>row_idx = reshape((x == -1)',1,size(x,1)*size(x,2));
>>y = y(row_idx,:);