I have this matrix:
A = [1 3
5 7
9 10];
And this vector:
B = zeros(1,10);
Now I want to change the elements in the ranges of [1:3],[5:7] and [9:10] to 1 .
So, to get this:
C = [1 1 1 0 1 1 1 0 1 1];
I tried:
B(A(:,1):A(:,2)) = 1;
but it just changes the zeros in the first range.
Can it be done without a for loop?
Thanks.
The first column of A are starting positions and the second one are ending positions of each sequence of 1s. To denote a beginning use 1 and for the end -1, then cumsum().
% Preallocate
N = 10;
B = zeros(1,N);
B(A(:,1)) = 1
B =
1 0 0 0 1 0 0 0 1 0
B(A(:,2)+1) = -1
B =
1 0 0 -1 1 0 0 -1 1 0 -1
B = cumsum(B)
B =
1 1 1 0 1 1 1 0 1 1 0
B(1:N)
ans =
1 1 1 0 1 1 1 0 1 1
Would something like this be appropriate?
>> f = #(x)(any(A(:,1)<=x & x<=A(:,2)));
>> i = 1:length(B)
i =
1 2 3 4 5 6 7 8 9 10
>> arrayfun(f,i)
ans =
1 1 1 0 1 1 1 0 1 1
Hello you can try this:
B([A(1,1):A(1,2) A(2,1):A(2,2) A(3,1):A(3,2)]) = 1;
Related
I'm attempting to find a critical point in a matrix. The value at index (i,j) should be greater than or equal to all elements in its row, and less than or equal to all elements in its column.
Here is what I have (it's off but I'm close):
function C = critical(A)
[nrow ncol] = size(A);
C = [];
for i = 1:nrow
for j = 1:ncol
if (A(i,j) >= A(i,1:end)) && (A(i,j) <= A(1:end,j))
C = [C ; A(i,j)]
end
end
end
You can use logical indexing.
minI = min(A,[],1);
maxI = max(A,[],2);
[row,col] = find(((A.'==maxI.').' & A==minI) ==1)
Details
Remember that Matlab is column major. We therefore transpose A and maxI.
A = [
3 4 1 1 2
2 4 2 1 4
4 3 2 1 2
3 3 1 1 1
2 3 0 2 1];
A.'==maxI.'
ans =
0 0 1 1 0
1 1 0 1 1
0 0 0 0 0
0 0 0 0 0
0 1 0 0 0
Then do the minimum
A==minI
ans =
0 0 0 1 0
1 0 0 1 0
0 1 0 1 0
0 1 0 1 1
1 1 1 0 1
And then multiply the two
((A.'==maxI.').' & A==minI)
ans =
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 1 0 0 0
0 1 0 0 0
Then find the rows and cols
[row,col] = find(((A.'==maxI.').' & A==minI) ==1)
row =
4
5
col =
2
2
Try this vectorised solution using bsxfun
function [ r,c,criP ] = critical( A )
%// finding the min and max values of each col & row resptly
minI = min(A,[],1);
maxI = max(A,[],2);
%// matching all the values of min & max for each col and row resptly
%// getting the indexes of the elements satisfying both the conditions
idx = find(bsxfun(#eq,A,maxI) & bsxfun(#eq,A,minI));
%// getting the corresponding values from the indexes
criP = A(idx);
%// Also getting corresponding row and col sub
[r,c] = ind2sub(size(A),idx);
end
Sample Run:
r,c should be a vector of equal length which represents the row and column subs of each Critical point. While val is a vector of same length giving the value of the critical point itself
>> A
A =
3 4 1 1 2
2 4 2 1 4
4 3 2 1 2
3 3 1 1 1
2 3 0 2 1
>> [r,c,val] = critical(A)
r =
4
5
c =
2
2
val =
3
3
I think there is a simpler way with intersect:
>> [~, row, col] = intersect(max(A,[],2), min(A));
row =
4
col =
2
UPDATE:
With intersect, in case you have multiple critical points, it will only give you the first one. To have all the indicies, there is also another simple way:
>> B
B =
3 4 1 4 2 5
2 5 2 4 4 4
4 4 2 4 2 4
3 4 1 4 1 4
2 5 4 4 4 5
>> row = find(ismember(max(B,[],2),min(B)))
row =
3
4
>> col = find(ismember(min(B),max(B,[],2)))
col =
2 4 6
Note that the set of critical points now should be the combination of row and col, means you have total 6 critical points in this example: (3,2),(4,2),(3,4),(4,4),(3,6),(4,6).
Here you can find how to export such combination.
I want to create a matrix from all combinations of elements of one vector that fulfill a condition
For example, I have this vector
a = [1 2 3 4 5]
and want to create a matrix like
a = [1 0 0 0 0;
1 2 0 0 0;
1 2 3 0 0;
1 2 3 4 0;
1 2 3 4 5;
0 2 0 0 0;
0 2 3 0 0;
........;]
and then get the rows that fulfill the condition I can use the command:
b = sum(a')' > value
but I don't know how to generate the matrix
You can generate all possible binary combinations to determine the matrix you want:
a = [1 2 3];
n = size(a,2);
% generate bit combinations
c =(dec2bin(0:(2^n)-1)=='1');
% remove first line
c = c(2:end,:)
n_c = size(c,1);
a_rep = repmat(a,n_c,1);
result = c .* a_rep
Output:
c =
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1
result =
0 0 3
0 2 0
0 2 3
1 0 0
1 0 3
1 2 0
1 2 3
I am trying to split an nx3 matrix into submatrices in matlab. So my matrix C is of this shape
C =
1 1 1
0 0 0
0 0 0
1 1 1
1 1 1
1 1 1
0 0 0
1 1 1
1 1 1
It either has rows of zeros or rows of ones. I want to split this matrix to only keep matrices of ones. So here for instance there's three 'groups' of ones. so I want to get
C1 =
1 1 1
C2 =
1 1 1
1 1 1
1 1 1
C3 =
1 1 1
1 1 1
However my real matrix is an n by 3, so i don't know where the ones are.
Edit 1:
Now, i need to split x1 and y1 (individual row vectors with same length as C) to x(1), x(2),.. (similarly for y vector) based on how the matrix C was split
Sample Input:
x1 = (1:9)';
y1 = (2:2:18)';
Desired Output:
x(1)=[1], x(2)=[4 5 6]' and x(3)=[8 9]'
y(1)=[2], y(2) =[8 10 12]' and y(3)=[16 18]'
Use find function to the first column to find the indices of 1-elements. Then, calculate the relative distance between any two consecutive elements of the obtained vector to determine the boundary. After that, use matrix indexing to get the blocks of 1-element-matrices. Let me know if you have a better idea.
c=[1 1 1;
0 0 0;
0 0 0;
1 1 1;
1 1 1;
1 1 1;
0 0 0;
1 1 1;
1 1 1;]
b=c(:, 1);
find(b);
I will leave the rest to yourself.
Input:
c = [1 1 1;
0 0 0;
0 0 0;
1 1 1;
1 1 1;
1 1 1;
0 0 0;
1 1 1;
1 1 1;]
x1 = (1:9)';
y1 = (2:2:18)';
Code:
elementalLengthA = cellfun('length',regexp(sprintf('%i',all(C,2)),'1+','match'));
elementalStartA = regexp(sprintf('%i',all(C,2)),'1+','start');
result = cell(length(elementalLengthA),1);
x = cell(length(elementalLengthA),1);
y = cell(length(elementalLengthA),1);
for i = 1:length(elementalLengthA)
result(i) = {C(elementalStartA(i):elementalStartA(i)+elementalLengthA(i)-1,:)};
x(i) = {x1(elementalStartA(i):elementalStartA(i)+elementalLengthA(i)-1,:)};
y(i) = {y1(elementalStartA(i):elementalStartA(i)+elementalLengthA(i)-1,:)};
end
Output:
>> cell2mat(result(1))
ans =
1 1 1
>> cell2mat(result(2))
ans =
1 1 1
1 1 1
1 1 1
>> cell2mat(result(3))
ans =
1 1 1
1 1 1
>> cell2mat(x(3)) %similarly do it for other cells to get results
ans =
8
9
Consider an index vector consisting of ones and zeros:
I=[0 0 1 0 1 1 0 0 0];
How can I easily generate the following matrix in matlab:
J=[0 2;
1 1;
0 1;
1 2;
0 3];
Use diff:
I = [0 0 1 0 1 1 0 0 0];
d = diff(I);
ind = [1 find(d~=0)+1]; %// starting index of each new value
rep = diff([ind numel(I)+1]); %// number of repetitions of each new value
J = [ I(ind).' rep.' ];
Using strfind for a slightly bigger example -
I =[1 1 0 0 1 0 1 1 0 0 0 1 1 1 1 0 0]
zero_pos = ['0' num2str(bsxfun(#eq,I,0),'%1d') '0']
ind3 = [ strfind(zero_pos,'01') ; strfind(zero_pos,'10')]
counts = diff(ind3(:))
var = zeros(numel(counts),1);
var(2:2:end)=1;
J = [var counts];
if ind3(1,1)-1>0
J = [1 ind3(1,1)-1;J];
end
Output
J =
1 2
0 2
1 1
0 1
1 2
0 3
1 4
0 2
How can I expand a matrix with zeroes around the edge and then crop it back to the same size, after some manipulations?
You can do this:
octave:1> x = ones(3, 4)
x =
1 1 1 1
1 1 1 1
1 1 1 1
octave:2> y = zeros(rows(x)+2, columns(x)+2);
octave:3> y(2:rows(x)+1, 2:columns(x)+1) = x
y =
0 0 0 0 0 0
0 1 1 1 1 0
0 1 1 1 1 0
0 1 1 1 1 0
0 0 0 0 0 0
octave:4> y = y.*2 (manipulation)
y =
0 0 0 0 0 0
0 2 2 2 2 0
0 2 2 2 2 0
0 2 2 2 2 0
0 0 0 0 0 0
octave:5> x = y(2:rows(x)+1, 2:columns(x)+1)
x =
2 2 2 2
2 2 2 2
2 2 2 2
To pad an array, you can use PADARRAY, if you have the image processing toolbox.
Otherwise, you can pad and shrink the following way:
smallArray = rand(10); %# make up some random data
border = [2 3]; %# add 2 rows, 3 cols on either side
smallSize = size(smallArray);
%# create big array and fill in small one
bigArray = zeros(smallSize + 2*border);
bigArray(border(1)+1:end-border(1),border(2)+1:end-border(2)) = smallArray;
%# perform calculation here
%# crop the array
newSmallArray = bigArray(border(1)+1:end-border(1),border(2)+1:end-border(2));