Iterating through a matrix using a smaller matrix - matlab

I've been struggling with this for a bit now. I have a small matrix s for example and a bigger matrix B as shown below.
B =
0 0 0 0 0 0 1 1
1 1 0 0 1 0 1 1
1 1 0 1 0 0 1 1
1 1 1 0 0 0 1 0
0 0 1 1 1 0 0 1
0 0 0 1 1 1 1 1
1 1 1 0 0 0 1 0
0 1 1 0 1 1 0 0
s =
1 1
1 1
What I want to do is iterate through B with s and compare the values. If all the values in s equal the values in B (the small section of B), then the answer is 1, if not then 0.
The 1's and 0's would be placed in a matrix as well.
This is what I've done so far but unfortunately, it doesn't iterate step by step and doesn't create a matrix either.
s = ones(2,2)
B = randi([0 1],8,8)
f = zeros(size(B))
[M,N]=size(B); % the larger array
[m,n]=size(s); % and the smaller...
for i=1:M/m-(m-1)
for j=1:N/n-(n-1)
if all(s==B(i:i+m-1,j:j+n-1))
disp("1")
else
disp("0")
end
end
end
Any help would be appreciated!

The following code works on the examples you supplied, I haven't tested it on anything else, and it will not work if the dimensions of the smaller matrix are not factors of the dimensions of the larger matrix, but you didn't indicate that it needed to do that in your description.
B =[0 0 0 0 0 0 1 1
1 1 0 0 1 0 1 1
1 1 0 1 0 0 1 1
1 1 1 0 0 0 1 0
0 0 1 1 1 0 0 1
0 0 0 1 1 1 1 1
1 1 1 0 0 0 1 0
0 1 1 0 1 1 0 0];
S =[1 1
1 1];
%check if array meets size requirements
numRowB = size(B,1);
numRowS = size(S,1);
numColB = size(B,2);
numColS = size(S,2);
%get loop multiples
incRows = numRowB/numRowS;
incCols = numColB/numColS;
%create output array
result = zeros(incRows, incCols);
%create rows and colums indices
rowsPull = 1:numRowS:numRowB;
colsPull = 1:numColS:numColB;
%iterate
for i= 1:incRows
for j= 1:incCols
result(i,j) = isequal(B(rowsPull(i):rowsPull(i)+numRowS-1, colsPull(j):colsPull(j)+numColS-1),S);
end
end
%print the resulting array
disp(result)

Related

elimination of consecutive regions

I need to effectively eliminate consecutive regions in vector "a" or better in rows/columns of matrix "A" with length of separate ones regions greater than positive integer N <= length(A):
See following example:
N = 2 % separate consecutive regions with length > 2 are zeroed
a = [0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1]
a_elim = [0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1]
or 2D case:
N = 2
A = [1 0 1 …
1 1 0 …
1 1 0 …
0 0 1 …
1 1 1]
% elimination over columns
A_elim= 0 0 1
0 1 0
0 1 0
0 0 1
1 1 1
% elimination over rows
A_elim= 1 0 1
1 1 0
1 1 0
0 0 1
0 0 0
I am looking for effective vectorized MATLAB function performing this task for size(A) ~ [100000, 1000] (over columns case).
You can use a convolution:
For the 1D case:
N = 2 %tolerance
A = [0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1]
ind = conv(A,ones(N+1,1),'same');
%ind = 1 2 2 1 1 2 3 2 1 1 2 3 3 2 2 1
%A = 0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1
ind = conv(ind>N,ones(N+1,1),'same')>0;
%ind = 0 0 0 0 0 1 1 1 0 0 1 1 1 1 0 0
%A = 0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1
A(ind) = 0
if N is odd you need an extra step:
ind = conv(A,ones(N+1,1),'same');
ind(find(ind==N+1)+1) = N+1 %the extra step
ind = conv(ind>N,ones(N+1,1),'same')>0;
Generalization for nD dimension:
N = 3 %tolerance
A = round(rand(5,5,5));
for ii = 1:ndims(A)
conv_vec = permute(ones(N+1,1),circshift([1:ndims(A)],ii-1,2))
ind = convn(A,conv_vec,'same')
if mod(N,2) == 1
ind(find(ind==N+1)+1) = N+1
end
ind = convn(ind>N,conv_vec,'same')>0
X = A;
X(ind) = 0
end

Matrix row/column manipulation in matlab

I have got the following function for spreading out the number of 1's in a matrix and if there are rows with all 0's or all 1's then that particular row has to be deleted
function ReducedMatrix = ReduceMatrix(result)
D1 = sum(result(:));
NumberOfOnes = floor(D1*0.3);
NewMatrix = zeros(size(result));
NewMatrix(randi(numel(NewMatrix),1,NumberOfOnes)) = 1;
ReducedMatrix = NewMatrix;
while numel(ReducedMatrix)/numel(NewMatrix) > 0.2
IndexOfFullRows = find(all(ReducedMatrix));
if isempty(IndexOfFullRows)
break
end
ReducedMatrix(:,IndexOfFullRows(1)) = [];
end
end
The input of the function and output are as follows
result =
0 1 1 1 1 1 1 1 1 1
1 1 1 1 1 0 1 0 1 1
1 1 0 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 0
1 1 1 1 1 1 0 1 0 1
1 0 1 1 1 1 1 0 1 1
1 1 1 1 0 1 1 1 0 1
1 0 1 1 1 0 1 1 1 1
1 1 1 1 0 1 0 1 1 1
1 1 1 0 1 1 1 1 1 1
ReducedMatrix =
0 1 1 0 0 0 0 0 1 0
0 1 0 0 0 0 0 1 0 0
1 1 1 0 0 0 0 0 0 0
0 0 0 1 0 0 1 0 0 0
0 0 0 0 0 0 1 0 0 0
0 1 0 0 0 0 1 0 1 1
1 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 1
0 0 0 0 0 0 0 0 0 0
1 0 1 0 0 0 0 0 0 1
row_sum =
3
2
3
2
1
4
2
2
0
3
col_sum =
3 4 4 1 0 0 3 2 2 3
Now if there exists a row or column with the row_sum/col_sum equal to either 0 or 1 then then the corresponding row has to be deleted.
For Example. Row-R4,R9 and Col-C4,C5,C6 have row_sum and col_sum as either 1,0. So adding them up R4,R9,C4,C5,C6 = 5 rows have to be eliminated from the matrix so my reduced matrix should be of the size 5x5. Please note column should not be eliminated and instead of removing columns having 0 and 1, the corresponding rows can be removed. Similarly this function has to run for larger matrices with the same constraints. I tried doing the above function however i do not possess enough skills to achieve my desired results, Any help is much appreciated
I see a number of potential problems and possible simplifications to your code.
For one thing, the way you construct the original matrix, NewMatrix(randi(numel(NewMatrix),1,NumberOfOnes)) = 1; may not behave the way you would expect. randi does not guarantee that the same index will not appear multiple times in the output, so your new matrix may have fewer ones than the original. To solve this, shuffle the elements using randperm:
ReducedMatrix = [ones(1, NumberOfOnes), zeros(1, numel(result) - NumberOfOnes)];
ReducedMatrix = ReducedMatrix(randperm(numel(ReducedMatrix)));
ReducedMatrix = reshape(ReducedMatrix, size(result));
Secondly, you do not need to construct the new matrix as NewMatrix and then reassign it with ReducedMatrix = NewMatrix;. Just do ReducedMatrix = zeros(size(result)); and skip the reassignment. For the while loop condition, where NewMatrix appears to be "used", remember that numel(NewMatrix) == numel(result).
If you are not removing homogeneous columns, only rows, you do not need a loop to do the removal:
rowSum = sum(ReducedMatrix, 2);
rowMask = (rowSum == size(ReducedMatrix, 2) | rowSum == 0);
ReducedMatrix(rowMask, :) = [];
Your original code seems to swap the row and column indices when removing the rows. It also did not handle the case of all zeros. If you want to remove not more than 30% of rows, you can do something like this before the removal:
rowMask = find(rowMask); % Convert to indices
rowMask = rowMask(1:min(numel(rowMask), round(0.3 * size(ReducedMatrix, 2))));

How to perform logical AND operation by refering the coordinates in matrix [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
The matrix A contains 1's in different coordinates:
A =
1 0 0 0 1 0 0 0 0 0
0 1 0 0 0 1 0 0 1 0
0 0 1 0 0 0 1 0 0 1
0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0
Step 1:
Finding the coordinates of the 1's. For example, in the first row it is (1,1) and (1,5).
c1 = find(A==1)
Step 2:
Scanning this coordinates in Main M matrix and performing AND operation. If the answer is 1 then place the 1 in corresponding coordinates of A matrix. For example, (1,1) (1,5) in M matrix is ANDed with (2,1)(2,5)==> 1 1 ANDed 0 0 ==>0 0. Likewise (3,1) (3,5) upto (10,1) (10,5) in M matrix. If any place 1 it came place the 1 in respective coordinate place in A matrix.
M =
1 0 0 0 1 1 1 1 1 1
0 1 0 0 0 1 1 1 1 1
0 0 1 0 1 1 1 1 1 1
0 0 0 1 0 0 0 0 1 1
1 0 1 0 1 0 0 0 0 0
1 1 1 0 0 1 0 0 1 1
1 1 1 0 0 0 1 0 1 1
1 1 1 0 0 0 0 1 0 0
1 1 1 1 0 1 1 0 1 0
1 1 1 1 0 1 1 0 0 1
Here in the given matrix in 4th row A matrix has 1 in (4,4) check the remaining coordinates in M matrix. It is ANDed with (1,4) the (2,4), while (9,4) it is 1. Place that 1 in A matrix (4,9). I have tried with the code but it is not working in generic case.
a = 1:size(M)
R1 = 1;
for j = 1:size(A)
A1 = A(j,:)
c = find(A1==1) % finding 1's place
l = length(c)
a1 = a(a~=j)
for k = a1(1):a1(end)
R1 = 1;
for i = 1:l1
temp1 = R1
R1 = and(M(j,c(i)),M(k,c(i))) % performing AND operations
R2 = and(R1,temp1)
end
if (R2==1) % if the condition is satisfied by 1
A(j,k)=1 % place the 1 in the particular coordinate in A matrix
end
end
end
New_A = A
New_A =
1 0 0 0 1 0 0 0 0 0
0 1 0 0 0 1 0 0 1 0
0 0 1 0 0 0 1 0 0 1
0 0 0 1 0 0 0 0 1 0
1 0 0 0 0 0 0 1 0 0
If I understand your question, then for each row r of A you want to extract all M columns where A(r,:)==1, then place 1 in first column c of A(r,:) that all the columns in row c in the extracted M is 1. Using the updated A continue the process on the same row until you reach the end, and move to the next row.
Here is a code for that (assuming size(A,1)==size(M,2)):
new_A = A; % copy the current state
for r = 1:size(new_A,1)
Mc = M(:,new_A(r,:)==1).'; % extract the relevat columns in new_A
c = 1; % column counter
while c<=size(A,2)
next_item = find(all(Mc(:,c:end),1),1)+c-1; % find the next item to change
new_A(r,next_item) = 1; % if all rows in Mc are 1, then place 1
Mc = M(:,new_A(r,:)==1).'; % extract the relevat columns in new_A
c = c+1; % go to the next column
end
end
which result in new_A using your A and M above:
new_A =
1 0 0 0 1 0 0 0 0 0
0 1 0 0 0 1 0 0 1 0
0 0 1 0 0 0 1 0 0 1
0 0 0 1 0 0 0 0 1 0
1 0 0 0 0 0 0 1 0 0
Is this what you looked for?

How to replace duplicate elements as 0 in column matrix in matlab

I need to replace the repeated elements in column of a matrix as 0's and delete the rows which has all 0's. If my matrix is like this means.
Input =
1 0 0 1
0 1 0 1
0 0 1 1
1 1 1 1
My expected output should be like this
Output =
1 0 0 1
0 1 0 0
0 0 1 0
0 0 0 0 ---> this row should be get deleted in this case
This doesn't work for my problem
c = [ 1 1 0 1 0 1 1 1 0 1 1 0];
[c, ic] = unique(a, 'first');
c(~ismember(1:length(a),ic)) = 0;
You can use logical indexing and cumsum:
A = [1 0 0 1;
0 1 0 1;
0 0 1 1;
1 1 1 1];
ind = cumsum(A); %cumulative sum (by column)
A(ind>1) = 0;
A(sum(A')==0,:)=[]

Assign values w/ multiple conditions

Let's have a M = [10 x 4 x 12] matrix. As example I take the M(:,:,4):
val(:,:,4) =
0 0 1 0
0 1 1 1
0 0 0 1
1 1 1 1
1 1 0 1
0 1 1 1
1 1 1 1
1 1 1 1
0 0 1 1
0 0 1 1
How can I obtain this:
val(:,:,4) =
0 0 3 0
0 2 2 2
0 0 0 4
1 1 1 1
1 1 0 1
0 2 2 2
1 1 1 1
1 1 1 1
0 0 3 3
0 0 3 3
If I have 1 in the first column then all the subsequent 1's should be 1.
If I have 0 in the first column but 1 in the second, all the subsequent 1's should be 2.
If I have 0 in the first and second column but 1 in the third then all the subsequent 1's should be 3.
If I have 0 in the first 3 columns but 1 in the forth then this one should be four.
Note: The logical matrix M is constructed:
Tab = [reshape(Avg_1step.',10,1,[]) reshape(Avg_2step.',10,1,[]) ...
reshape(Avg_4step.',10,1,[]) reshape(Avg_6step.',10,1,[])];
M = Tab>=repmat([20 40 60 80],10,1,size(Tab,3));
This is a very simple approach that works for both 2D and 3D matrices.
%// Find the column index of the first element in each "slice".
[~, idx] = max(val,[],2);
%// Multiply the column index with each row of the initial matrix
bsxfun(#times, val, idx);
This could be one approach -
%// Concatenate input array along dim3 to create a 2D array for easy work ahead
M2d = reshape(permute(M,[1 3 2]),size(M,1)*size(M,3),[]);
%// Find matches for each case, index into each matching row and
%// elementwise multiply all elements with the corresponding multiplying
%// factor of 2 or 3 or 4 and thus obtain the desired output but as 2D array
%// NOTE: Case 1 would not change any value, so it was skipped.
case2m = all(bsxfun(#eq,M2d(:,1:2),[0 1]),2);
M2d(case2m,:) = bsxfun(#times,M2d(case2m,:),2);
case3m = all(bsxfun(#eq,M2d(:,1:3),[0 0 1]),2);
M2d(case3m,:) = bsxfun(#times,M2d(case3m,:),3);
case4m = all(bsxfun(#eq,M2d(:,1:4),[0 0 0 1]),2);
M2d(case4m,:) = bsxfun(#times,M2d(case4m,:),4);
%// Cut the 2D array thus obtained at every size(a,1) to give us back a 3D
%// array version of the expected values
Mout = permute(reshape(M2d,size(M,1),size(M,3),[]),[1 3 2])
Code run with a random 6 x 4 x 2 sized input array -
M(:,:,1) =
1 1 0 1
1 0 1 1
1 0 0 1
0 0 1 1
1 0 0 0
1 0 1 1
M(:,:,2) =
0 1 0 1
1 1 0 0
1 1 0 0
0 0 1 1
0 0 0 1
0 0 1 0
Mout(:,:,1) =
1 1 0 1
1 0 1 1
1 0 0 1
0 0 3 3
1 0 0 0
1 0 1 1
Mout(:,:,2) =
0 2 0 2
1 1 0 0
1 1 0 0
0 0 3 3
0 0 0 4
0 0 3 0