How can I do below calculations (finding C) without using "for loop"?
[4, 2, 1, 7;
A = 0, 3, 4, 0;
8, 0, 10, 12;
11, 6, 2, 5];
[1, 0, 0, 4;
B = 0, 3, 2, 0;
5, 0, 8, 10;
7, 2, 1, 2];
C(i,j)= B(i,j-1) - B(i,j+1) + A(i,j+1); %if j is not equal to 4(number of columns) and it is not equal to 1
C(i,j)= B(i,4) - B(i,j+1) + A(i,j+1); %if j is equal to 1
C(i,j)= B(i,j-1) - B(i,1) + A(i,1); %if j is equal to 4(number of columns)
You can specify an array as index to work on multiple element at the same time:
A=[4,2,1,7;0,3,4,0;8,0,10,12;11,6,2,5];
B=[1,0,0,4;0,3,2,0;5,0,8,10;7,2,1,2];
C = zeros(size(A));
C(:,2:end-1) = B(:,1:end-2) - B(:,3:end) + A(:,3:end); %if j is not equal to 4(number of columns) and it is not equal to 1
j = 1;
C(:,j)= B(:,4) - B(:,j+1) + A(:,j+1); %if j is equal to 1
j = 4;
C(:,j)= B(:,j-1) - B(:,1) + A(:,1); %if j is equal to 4(number of columns)
Related
I am trying to find an efficient way of extracting groups of n consecutive columns in a matrix. Example:
A = [0, 1, 2, 3, 4; 0, 1, 2, 3, 4; 0, 1, 2, 3, 4];
n = 3;
should produce an output similar to this:
answer = cat(3, ...
[0, 1, 2; 0, 1, 2; 0, 1, 2], ...
[1, 2, 3; 1, 2, 3; 1, 2, 3], ...
[2, 3, 4; 2, 3, 4; 2, 3, 4]);
I know this is possible using a for loop, such as the following code snippet:
answer = zeros([3, 3, 3]);
for i=1:3
answer(:, :, i) = A(:, i:i+2);
endfor
However, I am trying to avoid using a for loop in this case - is there any possibility to vectorize this operation as well (using indexed expressions)?
Using just indexing
ind = reshape(1:size(A,1)*n, [], n) + reshape((0:size(A,2)-n)*size(A,1), 1, 1, []);
result = A(ind);
The index ind is built using linear indexing and implicit expansion.
Using the Image Package / Image Processing Toolbox
result = reshape(im2col(A, [size(A,1) n], 'sliding'), size(A,1), n, []);
Most of the work here is done by the im2col function with the 'sliding' option.
Just came across this problem might be interesting in many applications, for example,
I have a vector A = [2; 5; 10], the values in vector A is sorted and unique.
I have got a matrix (2D or 3D), for example, B = [2, 8, 10; 2, 5, 5; 9, 1, 10];
Want to get a matrix C = [1, 0, 1; 1, 1, 1; 0, 0, 1].
It means if the element in B is also an element of A, we set it to one; otherwise, set the value to zero.
I did this in a for-loop, but for a large 3D matrix, it takes a long time to finish the loop.
Just wondering if there is a smarter method to do this without 'for' loop.
C = zeros(size(B));
for i = 1:size(A,1)
a = A(i);
C(B==a) = 1;
end
This is exactly what ismember does:
A = [2; 5; 10];
B = [2, 8, 10; 2, 5, 5; 9, 1, 10];
C = ismember(B,A)
C =
1 0 1
1 1 1
0 0 1
From the documentation:
ismember(A,B) returns an array containing 1 (true) where the data in A
is found in B. Elsewhere, it returns 0 (false).
I'm trying to create a random number matrix in matlab. However, I'm struggling a little with the logic of some of it. What I want is this:
I need it to loop through a predefined random matrix (2 rows, n columns) 50% of which are 1's and 50% are 0's (I can already do this part). Everytime it encounters a 1 it should then enter another loop which puts a 1,2,3 or 4 in the corresponding position in the second row. However (and this is the part I'm struggling with) I need it to have an equal number of 1's, 2's, 3's and 4's in the second row. So for example:
The matrix n = [0, 1, 0, 1, 1, 1, 0, 0; 0,0,0,0,0,0,0,0] should run through the script and produce something like: n = [0, 1, 0, 1, 1, 1, 0, 0; 0, 1, 0, 3, 2, 4, 0, 0]
This is what I have so far:
function pureToneTimer
ptpschedule = [0, 1, 0, 1, 1, 1, 0, 0; 0, 0, 0, 0, 0 , 0, 0, 0]
a = 0;
b = 0;
c = 0;
d = 0;
x = length(ptpschedule)/4
for n = 1:length(ptpschedule)
if ptpschedule(1,n) == 1
while a < x && b < x && c < x && d < x
i = randi(4)
ptpschedule(2,n) = i;
switch i
case 1
a = a + 1;
case 2
b = b + 1;
case 3
c = c + 1;
case 4
d = d + 1;
end
end
end
end
assignin('caller', 'ptpschedule', ptpschedule)
end
Sorry if this turns out to be a really trivial question. I'm just struggling to wrap my head around it!
Thanks,
Martin
This does what you want:
V = 4; %// number of values you want. 4 in your example
ind = ptpschedule(1,:)>0; %// logical index of positive values in the first row
n = nnz(ind);
vals = mod(0:n-1, V)+1; %// values to be randomly thrown in.
%// This guarantees the same number of each value if n is a multiple of V
ptpschedule(2,ind) = vals(randperm(n)); %// fill values in second row in random order
If the number of 1's in the first row is a multiple of V, this generates each value 1, 2, ... V the same number of times in the second row.
Otherwise, some values in the second row will appear once more than other values.
Example:
ptpschedule = [0, 1, 0, 1, 1, 1, 0, 0
0, 0, 0, 0, 0, 0, 0, 0];
V = 4;
produces
ptpschedule =
0 1 0 1 1 1 0 0
0 3 0 4 2 1 0 0
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,:);
It is almost the same question as this one Matrices intersection!
The difference is this: If the intersection of the element (i, j) of all matrices is the same number then do not output -1 but output this number. An example is the following:
A1 = [2, 2, 0;
2, 2, 0;
0, 2, 0];
A2 = [2, 0, 4;
4, 3, 0;
0, 0, 1];
A3 = [2, 0, 0;
1, 0, 3;
3, 4, 3];
I want to get the follow matrix:
B = [2, 2, 4;
-1, -1, 3;
3, -1, -1];
Version 1
out1 = -1.*(A1~=A2).*(A1~=A3).*(A2~=A3)
max_mat = max(cat(3,A1,A2,A3),[],3)
out1(~out1) = max_mat(~out1)
Output
out1 =
2 2 4
-1 -1 3
3 -1 -1
Version 2: Maybe a faster version
Assumption - If out of the three elements in the corresponding positions across A1, A2 and A3, only two are same, then take the max of those three elements for the final matrix, B.
Code
%%// Concatenate all three A matrices
A=cat(3,A1,A2,A3,A1);
%%// Logical matrix with ones where all three elements are different from each other
out1 = -1.*all(diff(A,[],3)~=0,3)
%%// Get the max values, to be stored where -1 all three corresponding elements
%%// are not different from each other
max_mat = max(A,[],3)
%%// Get the final output
out1(~out1) = max_mat(~out1)
This produces the same output as the previous version.
Version 3
Assumption - If out of the three elements in the corresponding positions across A1, A2 and A3, only two are same, then take the element that is different from the other two for the final matrix, B.
Code
A=cat(3,A1,A2,A3,A1);
AA = A(:,:,1:3);
t1 = bsxfun(#ne,AA,mode(AA,3));
out1 = max(AA.*t1,[],3) + all(~t1,3).*A1;
out1(all(diff(A,[],3)~=0,3))=-1;
This produces the same output as the previous versions.
I would do this
A = A1+A2+A3;
B = (A1==A2)&(A1==A3);
C = (A1==0)+(A2==0)+(A3==0);
D = ones(3)*-1;
D(B==1) = A1(B==1);
D(C==2) = A(C==2);
B records the position of the elements whose number is same for all the matrices.
C records the position of the elements where two of the matrices have 0.
Then we can modify the elements of D, whose values are set -1 initially, using the information in matrices B and C.
A1 = [2, 2, 0;
2, 2, 0;
0, 2, 0];
A2 = [2, 0, 4;
4, 3, 0;
0, 0, 1];
A3 = [2, 0, 0;
1, 0, 3;
3, 4, 3];
A=cat(3,A1,A2,A3);
%identify all fields with identical values on the 3rd dimension
[X,Y]=find(sum(abs(diff(A,1,3)),3)==0);
%delete all but the first repetition, then use the previous code
A(X,Y,2:end)=0;
L=(sum(A~=0,3)>1);
L*-1+(1-L).*sum(A,3)
/update: Had to fix the code, now it should be correct.