remove elements with corresponding zeros in another matrix matlab - matlab

I have two matrices A & B in Matlab, for example
A=[0,0,1,2,3,0,4,2,0]
B=[2,3,1,2,2,3,4,4,1]
What I want to do is to set elements in B to zero where they have the same position as zero elements in A. So in my example:
A=[0,0,1,2,3,0,4,2,0]
B=[2,3,1,2,2,3,4,4,1]
I want B to be like this:
B=[0,0,1,2,2,0,4,4,0]
Any idea?

You can do it using logical indexing like so: B(A==0) = 0
EDIT:
You can also do it like this: B.*(A~=0) which will be easier to generalise to higher dimensions using bsxfun as per your comment below.

The only problem with doing something that Dan suggests is if A and B are not the same size. You can still however do this with a little bit of extra work.
indices = find(A==0);
indices = indices(indices <= length(B));
B(indices) = 0;

Related

How do I reshape a non-quadratic matrix?

I have a column vector A with dimensions (35064x1) that I want to reshape into a matrix with 720 lines and as many columns as it needs.
In MATLAB, it'd be something like this:
B = reshape(A,720,[])
in which B is my new matrix.
However, if I divide 35604 by 720, there'll be a remainder.
Ideally, MATLAB would go about filling every column with 720 values until the last column, which wouldn't have 720 values; rather, 504 values (48x720+504 = 35064).
Is there any function, as reshape, that would perform this task?
Since I am not good at coding, I'd resort to built-in functions first before going into programming.
reshape preserves the number of elements but you achieve the same in two steps
b=zeros(720*ceil(35604/720),1); b(1:35604)=a;
reshape(b,720,[])
A = rand(35064,1);
NoCols = 720;
tmp = mod(numel(A),NoCols ); % get the remainder
tmp2 = NoCols -tmp;
B = reshape([A; nan(tmp2,1)],720,[]); % reshape the extended column
This first gets the remainder after division, and then subtract that from the number of columns to find the amount of missing values. Then create an array with nan (or zeros, whichever suits your purpose best) to pad the original and then reshape. One liner:
A = rand(35064,1);
NoCols = 720;
B = reshape([A; nan(NoCols-mod(numel(A),NoCols);,1)],720,[]);
karakfa got the right idea, but some error in his code.
Fixing the errors and slightly simplifying it, you end up with:
B=nan(720,ceil(numel(a)/720));
B(1:numel(A))=A;
Create a matrix where A fits in and assingn the elemnent of A to the first numel(A) elements of the matrix.
An alternative implementation which is probably a bit faster but manipulates your variable b
%pads zeros at the end
A(720*ceil(numel(A)/720))=0;
%reshape
B=reshape(A,720,[]);

logical operation within vector range expression in MATLAB

can I have something like
A=1:10;
A(1:2 && 5:6)=0;
meaning I want to zero out specific ranges within my vector index expression in one line
Is that possible?
And what if I wanted to zero out all the rest like
A(~[1:2]) = 0
What's the way of logical NOT within vector indexing?
Thanks
The following should work:
idx = [1:2,5:6];
A(idx) = 0
If you want to zero the complement of the vector of indices:
idx = [1:2,5:6];
A(~ismembc(1:length(A),idx)) = 0
Where ismembc is a faster, lightweight version of ismember that assumes the array is sorted and non-sparse with no NaN elements. (Credit goes to this question.)
Just do A([1:2 5:6]). I.e., just create a vector of the indices you want to zero out.

Replacing the colon operator with an equivalent vectorizable solution

My current code does something like this:
for offset = 0:0.9:max_offset :
x = offset:step_size:max_value;
[...]
end
I would like to vectorize and remove the for loop to make it faster, but if I try making offset a vector, the colon operator on the second line is equivalent to doing
x = offset(1):step_size:max_value;
What is the most efficient way to achieve the desired result, i.e. get
x = [ 0:step_size:max_value;
0.9:step_size:max_value;
1.8:step_size:max_value; ... ]
assuming I don't know max_offset, and therefore the length of number of rows I want in x?
Since each vector will be a different size, they wont fit in a matrix easily. You will have to put them in a cell array, like so:
offset=0:.9:max_offset;
x=arrayfun(#(k) k:step_size:max_value,offset,'UniformOutput',false)
and rather than referring to rows of x by x(i,:) for a matrix, you would do x{i} to get the right vector out.

Vectorize matrix multiplication

I have a school project about running a SOR algorithm on Octave, but mine is very inefficient. So I have this snippet of code:
for ii=1:n
r = 1/A(ii,ii);
for jj=1:n
if (ii!=jj)
A(ii,jj) = A(ii,jj)*r;
end;
end;
b(ii,1) = b(ii,1)*r;
x(ii,1) = b(ii,1);
end;
How can I vectorize this? My first attempt was this:
for ii=1:n
r = 1/A(ii,ii);
A(find(eye(length(A))!=1)) = A(find(eye(length(A))!=1))*r;
b(ii,1) = b(ii,1)*r;
x(ii,1) = b(ii,1);
end;
But I'm not sure it helped much. Is there a better and/or more efficient way to do it?
Thanks!
You can totally avoid loops I believe. You have to see that you are taking as the reciprocal of diagonal elements of A, then why do you want to use a loop. Do it directly. That's the first step. Remove Inf and now you want to multiply r to corresponding non-diagonal elements of corresponding rows, right?
Therefore, use repmat to construct such a matrix which will have replicated elements along columns, since you are multiplying same r to (1,2), (1,3), ... , (1,n). But R has non-zero diagonal elements. Therefore make them zero. Now you will get your A except that the diagonal elements will be zero. Therefore, you just have to add them back from original A. That can be done by A=A.*R+A.*eye(size(A,1)).
Vectorization comes from experience and most importantly analyzing your code. Think at each step whether you want to use the loop, if not replace that step with the equivalent command, other code will follow (for example, I constructed a matrix R, whereas you were constructing individual elements r. So I only thought about converting r -> R and then the rest of the code will just fall into place).
The code is as follows:
R=1./(A.*eye(size(A,1))); %assuming matrix A is square and it does not contain 0 on the main diagonal
R=R(~isinf(R));
R=R(:);
R1=R;
R=repmat(R,[1,size(A,2)]);
R=R.*(true(size(A,1))-eye(size(A,1)));
A=A.*R+A.*eye(size(A,1)); %code verified till here since A comes out to be the same
b = b.*R1;
x=b;
I suppose there are matrices:
A (NxN)
b (Nx1)
The code:
d = diag(A);
A = diag(1 ./ d) * A + diag(d - 1);
b = b ./ d;
x = b;
Randomly bumped onto this problem and at first glance looked interesting given the fact that the problem was tagged as a vectorization problem.
I was able to come up with a bsxfun based vectorized solution that also uses diagonal indexing. This solution seems to give me a 3-4x speedup over the loop code with decent sized inputs.
Assuming that you are still somewhat interested in seeing speedup improvement on this problem, I would be eager to know the kind of speedups you would be getting with it. Here's the code -
diag_ind = 1:size(A,1)+1:numel(A);
diag_A = A(diag_ind(:));
A = bsxfun(#rdivide,A,diag_A);
A(diag_ind) = diag_A;
b(:,1) = b(:,1)./diag_A;
x(:,1) = b(:,1);
Let me know!

How do I create a matrix whose elements are the sum of the row and column numbers?

I need to create a 95x95 matrix in MATLAB in which each element is a sum of its row and column number.
I'm new at this so I can't really think of a way to tell MATLAB to just create a matrix without putting the elements in.
From what I understand I'll have to initiate a loop for the sum part.
No math needed if you use HANKEL:
A = hankel(2:96, 96:190);
I propose another strategy, as simple as EitanT's one:
v = 1:95;
A = bsxfun(#plus,v,v');
There is no need "reinventing the wheel" with loops. Try this:
[X, Y] = meshgrid(1:95, 1:95);
A = X + Y
The desired output is stored in matrix A.