Sum parts of a column separated by 0 - matlab

Suppose that you have a matrix with:
0 0 0 .... 0
A 0 0 .... 0
B 0 0 .... 0
C 0 0 .... 0
0 0 0 .... 0
D 0 0 .... 0
E 0 0 .... 0
If I want to get a new array with the output:
[A+B+C D+E]
how would you do it? Of course I can always do loops and check for 0 but I'd like to know if there is any other alternative.

Use cumsum to generate a vector of grouping values, and then accumarray to do the sums:
x = [0; 1; 2; 4; 0; 7; 3];
result = accumarray(cumsum(x==0) + (x(1)~=0), x);
gives
result =
7
10
The + (x(1)~=0) part is necessary if x may not start with a zero. This part ensures that for
x = [1; 2; 4; 0; 7; 3];
the result is the desired
result =
7
10
With the above approach, each zero starts a new group. So, for
x = [0; 1; 2; 4; 0; 7; 3; 0; 0; 5; 0];
the result is
result =
7
10
0
5
0
If you want each run of one or more zeros to start a new group: first collapse consecutive zeros in x, then apply the above:
x = [0; 1; 2; 4; 0; 7; 3; 0; 0; 5; 0];
ind = [true; x(2:end)~=0 | x(1:end-1)~=0]; % index to remove a zero if preceded by zero
t = x(ind);
result = accumarray(cumsum(t==0) + (x(1)~=0), t);
gives
result =
7
10
5
0

Related

Writing a loop that works for any value of N

I have a code for a 1D heat equation. Im trying to format a for loop so that the A matrix will follow a certain pattern of 1 -2 1 down the entire diagonal of a matrix that could be infinite. The pattern starts to take shape when I mess around with the initialized count at the beginning of the for loop but this changes the size of the matrix which fails the rest of the code.
My current code is below. The commented A matrix edits are what it should be.
N = 5;
%A(2,1:3) = [1 -2 1];
%A(3,2:4) = [1 -2 1];
%A(4,3:5) = [1 -2 1];
%A(5,4:6) = [1 -2 1];
A = zeros(N+1,N+1);
A(1,1) = 1;
for count=N:N+1
A(count+1,count:count+2) = [1 -2 1];
end
A(N+1,N+1) = 1;
In Matlab you can often avoid loops. In this case you can get the desired result with 2D convolution:
>> N = 6;
>> A = [1 zeros(1,N-1); conv2(eye(N-2), [1 -2 1]); zeros(1,N-1) 1]
A =
1 0 0 0 0 0
1 -2 1 0 0 0
0 1 -2 1 0 0
0 0 1 -2 1 0
0 0 0 1 -2 1
0 0 0 0 0 1
Or, depending on what you want,
>> A = conv2(eye(N), [1 -2 1], 'same')
A =
-2 1 0 0 0 0
1 -2 1 0 0 0
0 1 -2 1 0 0
0 0 1 -2 1 0
0 0 0 1 -2 1
0 0 0 0 1 -2
There are many simple ways of creating this matrix.
Your loop can be amended as follows:
N = 5;
A = zeros(N+1,N+1);
A(1,1) = 1;
for row = 2:N
A(row, row-1:row+1) = [1 -2 1];
end
A(N+1,N+1) = 1;
I've renamed count to row, we're indexing each row (from 2 to N, skipping the first and last rows), then finding with row-1:row+1 the three indices for that row that you want to address.
Directly indexing the diagonal and off-diagonal elements. Diagonal elements for an NxN matrix are 1:N+1:end. This is obviously more complex, I'd prefer the loop:
N = 6;
A = zeros(N,N);
A(1:N+1:end) = -2;
A(2:N+1:end-2*N) = 1; % skip last row
A(2*N+2:N+1:end) = 1; % skip first row
A(1,1) = 1;
A(N,N) = 1;
Using diag. We need to special-case the first and last rows:
N = 6;
A = diag(-2*ones(N,1),0) + diag(ones(N-1,1),1) + diag(ones(N-1,1),-1);
A(1,1:2) = [1,0];
A(end,end-1:end) = [0,1];

Make a one simple code from several similar code

Hello everybody I have a very simple problem, I have too many data y, p and r. So I want to calculate it in a single code.
This an example of my code if I breakdown into separate code
y1=45
y2=56
y3=67
p1=34
p2=45
p3=56
r1=23
r2=34
r3=45
Ryaw1=[cosd(y1) -sind(y1) 0;
sind(y1) cosd(y1) 0;
0 0 1]
Rpitch1=[cosd(p1) 0 sind(p1);
0 1 0;
-sind(p1) 0 cos(p1)]
Rroll1=[1 0 0;
0 cosd(r1) -sind(r1);
0 sind(r1) cosd(r1)]
R1=Ryaw1*Rpitch1*Rroll1
Coordinate1=R1*X0
Ryaw2=[cosd(y2) -sind(y2) 0;
sind(y2) cosd(y2) 0;
0 0 1]
Rpitch2=[cosd(p2) 0 sind(p2);
0 1 0;
-sind(p2) 0 cos(p2)]
Rroll2=[1 0 0;
0 cosd(r2) -sind(r2);
0 sind(r2) cosd(r2)]
R2=Ryaw2*Rpitch2*Rroll2
Coordinate2=R2*X0
Ryaw3=[cosd(y3) -sind(y3) 0;
sind(y3) cosd(y3) 0;
0 0 1]
Rpitch3=[cosd(p3) 0 sind(p3);
0 1 0;
-sind(p3) 0 cos(p3)]
Rroll3=[1 0 0;
0 cosd(r3) -sind(r3);
0 sind(r3) cosd(r3)]
R3=Ryaw3*Rpitch3*Rroll3
Coordinate3=R3*X0
Coordinate=[Cooedinate1 Coordinate2 Coordinate3]
The goals is to find "Coordinate" (in matrix - combined from Coordinate1, Coordinate2, Coordinate3, .... ,Coordinate..) from every y, p and r data with the same "X0" as a single primary data for calculation.
Sorry for my bad english,
Thanks :)
Use vectors and matrices instead of individual scalars. These are indexed in almost the same way as you had before, i.e. y1 becomes y(1).
Then you can easily loop over the code 3 times and save the repetition.
See my commented code below.
% Define some X0. This should be a column vector.
X0 = [1; 2; 3];
% Make y,p,r into 3 element vectors
y = [45 56 67];
p = [34 45 56];
r = [23 34 45];
% Make R, Ryaw, Rpitch and Rroll 3x3x3 matrices
R = zeros(3,3,3);
Ryaw = zeros(3,3,3);
Rpitch = zeros(3,3,3);
Rroll = zeros(3,3,3);
% Make Coordinate a 3x3 matrix
Coordinate = zeros(3,3);
% Loop k from 1 to 3
% For each 3x3x3 matrix, the kth 3x3 matrix is equivalent to your Ryawk, Rpitchk, Rrollk, Rk
for k = 1:3
Ryaw(:,:,k) = [cosd(y(k)) -sind(y(k)) 0
sind(y(k)) cosd(y(k)) 0
0 0 1];
Rpitch(:,:,k)= [cosd(p(k)) 0 sind(p(k))
0 1 0
-sind(p(k)) 0 cos(p(k))];
Rroll(:,:,k) = [1 0 0
0 cosd(r(k)) -sind(r(k))
0 sind(r(k)) cosd(r(k))];
R(:,:,k) = Ryaw(:,:,k)*Rpitch(:,:,k)*Rroll(:,:,k);
Coordinate(:,k) = R(:,:,k)*X0;
end
disp(Coordinate)

Convert an array of bounded integers to matrix of bit arrays

Suppose I have an array a of bounded integers (in this case bounded by 5):
a = [3 4 4 2 1 5 5];
I want to convert this array of integers to a length(a) x 5 matrix A where each row is a bit array with a 1 in the column indexed by the integer from a:
A = [0 0 1 0 0;
0 0 0 1 0;
0 0 0 1 0;
0 1 0 0 0;
1 0 0 0 0;
0 0 0 0 1;
0 0 0 0 1];
This is easily accomplished with a for loop:
n = length(a)
A = zeros(n, max(a(:)));
for k = 1 : n
A(k, a(k)) = 1;
end
I am looking for a vectorized implementation that does not use a for loop.
Two possible methods:
use sparse:
A = sparse( 1:n, a, 1, n, max(a(:)) );
if you want a non-sparse result
full(A);
Using sun2ind:
A = zeros( n, max(a(:)) );
A( sub2ind(size(A), 1:n, a ) ) = 1;

Randomly permute matrix rows keeping same-valued rows adjacent

How can I randomly permute row keeping those with the same value adjacent to each other? I know that I can use randperm on the rows to randomly permute all rows, but I do not know how to keep the same-valued rows adjacent. Thanks.
A = [0 0 0;
0 0 0;
1 1 1;
1 1 1;
1 1 1;
2 2 2;
2 2 2];
permute_A = [0 0 0;
0 0 0;
2 2 2;
2 2 2;
1 1 1;
1 1 1;
1 1 1];
You have to identify the clusters and then permute them:
Finding the clusters can be done by finding the changes in their differences:
diffA = diff(A);
clusters_start = [1 ; find(any(diffA,2)~=0)+1];
Then the cluster ends are easily found by:
clusters_end = [clusters_start(2:end)-1 ;size(A,1)];
clusters_length = clusters_end-clusters_start+1;
now you know the number of clusters and you can permute them:
Nclusters = numel(clusters_start);
perm_idx = randperm(Nclusters );
clusters_start = clusters_start(perm_idx);
clusters_end = clusters_end(perm_idx);
clusters_length = clusters_length(perm_idx);
and put them in a new matrix:
newA = NaN(size(A));
for ii=1:Nclusters
newA(sum(clusters_length(1:ii-1))+(1:clusters_length(ii)),:) = A(clusters_start(ii):clusters_end(ii),:);
end

Converting a matrix in MATLAB

Let's say I've got a vector a = [1 2 4]. I want it converted into a vector which looks like this b = [1 2 0 4], i.e. each number is placed into a correct position and since 3 is not included into the vector a, it is replaced by 0 in vector b. This can be done the following way:
a = [1 2 4]
b = zeros(1, size(a, 2));
b(1, a) = a;
I can't figure out a way to do the same for a matrix. For example,
c = [1 4 2 0; 3 1 0 0; 4 0 0 0; 1 3 4 0];
I need to convert into a matrix that looks like this:
d = [1 2 0 4; 1 0 3 0; 0 0 0 4; 1 0 3 4];
Any tips? How can this be done? How can I do this without using loops?
Here's a vectorized solution:
a = [1 4 2 0; 3 1 0 0; 4 0 0 0; 1 3 4 0];
b = zeros(size(a,1),max(a(:)));
[rowIdx,~] = find(a);
vals = a(a>0);
b( sub2ind(size(b),rowIdx,vals) ) = vals;
Does this work? (Edited: fixed mistake.)
[m,n] = size(c)
d = zeros(m,n)
for i=1:m
d(i,c(i,c(i,:)>0)) = c(i,c(i,:)>0)
end