Operations on adjacent elements in a vector - matlab

I have a binary vector, if I find a 0 in the vector I want to make the adjacent elements 0 if they are not already.
For example if input = [1 1 0 1 1] I want to get output = [1 0 0 0 1]
I tried the following but it's messy and surely there is a neater way:
output=input;
for i = 1:length(input)
if(input(i) == 0)
output(i-1)=0;
output(i+1)=0;
end
end

In = [1, 1, 0, 1, 1]; % note that input is a MATLAB function already and thus a bad choice for a variable name
Find the zeros:
ind_zeros = ~In; % or In == 0 if you want to be more explicit
now find the indicies before and after
ind_zeros_dilated = ind_zeros | [ind_zeros(2:end), false] | [false, ind_zeros(1:end-1)]
Finally set the neighbours to zero:
Out = In;
Out(ind_zeros_dilated) = 0
For fun, an alternative way to calculate ind_zeros_dilated is to use convolution:
ind_zeros_dilated = conv(ind_zeros*1, [1,1,1],'same') > 0 %// the `*1` is just a lazy way to cast the logical vector ind_zeros to be of type float

Related

Perform a successive XOR along rows

I'm trying to figure out how to perform a successive XOR on a row in matlab, where each element is the result of XORing itself and the previous element, for example:
If the row is
x = [1 0 1 1]
I would want the result to be:
x[0] = 1
x[1] = x[0]^x[1] = 1
x[2] = x[1]^x[2] = 0
x[3] = x[2]^x[3] = 1
x = [1 1 0 1]
I have tried using xor(A,B) but this only seems to work on multiple arrays at once. I also have tried this loop:
for k = 10000:1
for i = 1:64
allchallenge_full(k,i+1) = xor(allchallenge_full(k,i).^allchallenge_full(k,i+1))
end
end
But this simply results in all 1s.
Any suggestions are appreciated! Thank you!
If the input x is just zeros and ones:
result = mod(cumsum(x), 2);
To apply it on each row of a matrix x:
result = mod(cumsum(x,2), 2);
If you want to keep things simple, a for loop, together with the xor function (^ in Matlab represents the raising to a power), should work fine:
x = [1 0 1 1];
for i = 2:numel(x)
x(i) = xor(x(i-1),x(i));
end
The final output is the expected one:
x =
1 1 0 1
Remember that, in Matlab, indexing is one-based and not zero-based as in many other programming languages. The first element of x is, therefore, x(1) and not x(0).

Constructing vectors of different lengths

I want to find out row and column number of zeros in 3 dimensional space. Problem is I get output vectors(e.g row) of different length each time, hence dimension error occurs.
My attempt:
a (:,:,1)= [1 2 0; 2 0 1; 0 0 2]
a (:,:,2) = [0 2 8; 2 1 0; 0 0 0]
for i = 1 : 2
[row(:,i) colum(:,i)] = find(a(:,:,i)==0);
end
You can use linear indexing:
a (:,:,1) = [1 2 0; 2 0 1; 0 0 2];
a (:,:,2) = [0 2 8; 2 1 0; 0 0 0];
% Answer in linear indexing
idx = find(a == 0);
% Transforms linear indexing in rows-columns-3rd dimension
[rows , cols , third] = ind2sub(size(a) ,idx)
More on the topic can be found in Matlab's help
Lets assume your Matrix has the format N-by-M-by-P.
In your case
N = 3;
M = 3;
P = 2;
This would mean that the maximum length of rows and coloms from your search (if all entries are zero) is N*M=9
So one possible solution would be
%alloc output
row=zeros(size(a,1)*size(a,2),size(a,3));
colum=row;
%loop over third dimension
n=size(a,3);
for i = 1 : n
[row_t colum_t] = find(a(:,:,i)==0);
%copy your current result depending on it's length
row(1:length(row_t),i)=row_t;
colum(1:length(colum_t),i)=colum_t;
end
However, when you past the result to the next function / script you have to keep in mind to operate on the non-zero elements.
I would go for the vectorized solution of Zep. As for bigger matrices a it is more memory efficient and I am sure it must be way faster.

Combination and Multiplying Rows of array in matlab

I have a matrix (89x42) of 0's and 1's that I'd like to multiply combinations of rows together.
For example, for matrix
input = [1 0 1
0 0 0
1 1 0];
and with 2 combinations, I want an output of
output = [0 0 0; % (row1*row2)
1 0 0; % (row1*row3)
0 0 0] % (row2*row3)
Which rows to multiply is dictated by "n Choose 2" (nCk), or all possible combinations of the rows n taken k at a time. In this case k=2.
Currently I am using a loop and it works fine for the 89C2 combinations of rows, but when I run it with 89C3 it takes far too long too run.
What would be the most efficient way to do this program so I can do more than 2 combinations?
You can do it using nchoosek and element-wise multiplication.
inp = [1 0 1; 0 0 0; 1 1 0]; %Input matrix
C = nchoosek(1:size(inp,1),2); %Number of rows taken 2 at a time
out = inp(C(:,1),:) .* inp(C(:,2),:); %Multiplying those rows to get the desired output
Several things you can do:
Use logical ("binary") arrays (or even sparse logical arrays) instead of double arrays.
Use optimized combinatorical functions.
bitand or and instead of times (where applicable).
Vectorize:
function out = q44417404(I,k)
if nargin == 0
rng(44417404);
I = randi(2,89,42)-1 == 1;
k = 3;
end
out = permute(prod(reshape(I(nchoosek(1:size(I,1),k).',:).',size(I,2),k,[]),2),[3,1,2]);

How to convert a vector into a matrix where values on columns are 1 where the column number is the vector element, else 0?

I'm unsure how to phrase the question, but I think an example will help. Suppose I have a vector y = [3;1;4;1;6]. I want to create the matrix Y =
[0 0 1 0 0 0;
1 0 0 0 0 0;
0 0 0 1 0 0;
1 0 0 0 0 0;
0 0 0 0 0 1]
↑ ↑ ↑ ↑ ↑ ↑
1 2 3 4 5 6
where the element on each column is one or zero corresponding to the value in the vector.
I found that I could do it using
Y = []; for k = 1:max(y); Y = [Y (y==k)]; end
Can I do it without a for loop (and is this method more efficient if y has thousands of elements)?
Thanks!
Your method is not efficient because you're growing the size of Y in the loop which is not a good programming practice. Here is how your code can be fixed:
Ele = numel(y);
Y= zeros(Ele, max(y));
for k = 1:Ele
Y (k,y(k))= 1;
end
And here is an alternative approach without a loop:
Ele = numel(y); %Finding no. of elements in y
Y= zeros(Ele, max(y)); % Initiailizing the matrix of the required size with all zeros
lin_idx = sub2ind(size(Y), 1:Ele, y.'); % Finding linear indexes
Y(lin_idx)=1 % Storing 1 in those indexes
You can use bsxfun:
result = double(bsxfun(#eq, y(:), 1:max(y)));
If you are running the code on Matlab version R2016b or later, you can simplify the syntax to
result = double(y(:)==(1:max(y)));
Another approach, possibly more efficient, is to fill in the values directly using accumarray:
result = accumarray([(1:numel(y)).' y(:)], 1);
I found another solution:
E = eye(max(y));
Y = E(y,:);
Another solution:
Y = repmat(1:max(y), size(y)) == repmat(y, 1, max(y))

fill gaps specified as "0" in 2D matrix not taking into account NaN

I'm working with a 2D matrix (global soiltype grid) that I want to fill up to fit a new mask. For that, my idea is to fill the blanks using an interpolation by nearest neighbor. I don't see how can I apply that interpolation just to the zeros, and not considering NaNs (which represent the sea). I was thinking about filling those blanks by hand as there aren't too many of them, but I thought that it's interesting to know how to do this anyway. I'd like grid cells representing islands in the middle of the ocean to consider the closest coast as nearest neighbor, if that makes sense. I know that's not realistic, but for my purposes is good enough.
Thank you in advance for any ideas. I don't play with Matlab very often and this kind of things are too much of a challenge timewise.
I advice you to use the function isnan() of matlab.
Here's un example:
A = [1 0 4, 0 3 NaN, NaN 4 5, 0 0 0, NaN 1 NaN]
A =
1 0 4
0 3 NaN
NaN 4 5
0 0 0
NaN 1 NaN
By using isnan(A) will return you a matrix with 1's where there are NaN's and 0 elsewhere.
isnan(A)
ans =
0 0 0
0 0 1
1 0 0
0 0 0
1 0 1
Then you can use the returned matrix (same size as A) as a mask for something else and/or replace the NaN's with whatever you want.
Hope this helps!
This is what I came up with.
function result = nonNanNearestNeighbor(A)
[gridX, gridY] = meshgrid(1:size(A,2), 1:size(A,1));
%if you don't want periodic BCs change function below
t = PeriodicBC(gridY - 1, size(A,1));
b = PeriodicBC(gridY + 1, size(A,1));
l = PeriodicBC(gridX - 1, size(A,2));
r = PeriodicBC(gridX + 1, size(A,2));
%Convert from rc notation to index notation
T = sub2ind(size(A), t, gridX);
B = sub2ind(size(A), b, gridX);
L = sub2ind(size(A), gridY, l);
R = sub2ind(size(A), gridY, r);
%Shift the stencils until they're not nans
while any(isnan(A(T(:))))
[tNaN, gX] = ind2sub(size(A), T(isnan(A(T))));
T(isnan(A(T))) = sub2ind(size(A), PeriodicBC(tNaN - 1, size(A,1)), gX);
end
while any(isnan(A(B(:))))
[bNaN, gX] = ind2sub(size(A), B(isnan(A(B))));
B(isnan(A(B))) = sub2ind(size(A), PeriodicBC(bNaN + 1, size(A,1)), gX);
end
while any(isnan(A(L(:))))
[gY, lNaN] = ind2sub(size(A), L(isnan(A(L))));
L(isnan(A(L))) = sub2ind(size(A), gY, PeriodicBC(lNaN - 1, size(A,2)));
end
while any(isnan(A(R(:))))
[gY, rNaN] = ind2sub(size(A), R(isnan(A(R))));
R(isnan(A(R))) = sub2ind(size(A), gY, PeriodicBC(rNaN + 1, size(A,2)));
end
result = (A(T) + A(B) + A(L) + A(R)) / 4;
end
function shifted = PeriodicBC(shifted, value)
shifted(shifted <= 0) = value - shifted(shifted <= 0);
shifted(shifted > value) = shifted(shifted > value) - value;
if any((shifted(:) <= 0) | (shifted(:) > value))
shifted = PeriodicBC(shifted, value);
end
end