Matlab: interpolation operator for multigrid methods - matlab

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.

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.

From vector to heatmap in matlab

My data looks like this:
A = [1 1 0;
1 2 1;
2 2 0;
2 1 1]
The first two columns represent interactions. The third one represents the presents or absence of the interaction. How can I transform this into a heat map like this:
1 2
1 0 1
2 1 0
I used find, but is there a faster and more elegant way to do it?
Is it simple enough?
n = max(A(:, 1));
m = max(A(:, 2));
b = nan(n, m);
for i = 1:length(A)
b(A(i, 1), A(i, 2)) = A(i, 3);
end
I've tried some other code, but it failed. Thus the above might be the simpliest:
n = max(A(:, 1));
m = max(A(:, 2));
b = nan(n, m);
b(A(:, 1), A(:, 2)) = A(:, 3);
Anyway, I'd like to how you implement using find

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,:);

Matlab Combine Row Vectors into one row

Is there a vectorized, automated way to fill a row vector l times with repeating numbers x such that x is increased by y after a certain number k of elements? k, l, x, and y are given.
Two examples:
(k = 4, l = 4, x = 0, y = 1): $A = [0 0 0 0; 1 1 1 1; 2 2 2 2; 3 3 3 3];$
(k = 2, l = 3, x = 0, y = 0.1): $B = [0 0; 0.1 0.1; 0.2 0.2]$
You can use repmat together with a:b
This way your fist example would look like this:
repmat((0:3)', 1,4)
The second one:
repmat((0:0.1:0.2)', 1,2)
You can also try linspace or similar functions to be as close to what you want as possible