Finding a vector within a vector - matlab

I have an (7,6) logical array, such as the following:
validY2_A =
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 1 0 0
1 0 0 1 1 0
1 1 1 0 0 1
1 1 1 0 1 1
0 1 1 1 1 1
I want to create a (1,6) logical vector 'contig' that shows whether the above matrix has 3 contiguous ones in each column. For example, the outcome of this would be:
contig =
[1, 1, 1, 0, 0 ,1];
I've tried strfind but there are two issues with this, the first being that it is an array of columns (transposing either didn't help at all. or would require lots of extra code to use temporarily. The second issue is that because it is a logical array, if I change it to a string, the values all become true or false, and trying to get that to work has also been fruitless. Is there a method to search a column vector to find if another, specific column vector exists anywhere within it? I want to search each column for [1; 1; 1];
Thanks

How about
t = imfilter( validY2_A, ones(3,1) );
contig = any( t >= 3, 1 );
Alternatively (as suggested by #Dan):
t = conv2( validY2_A, ones(3,1), 'same');
contig = any( t >= 3, 1 );
As suggested by #GeorgeAprilis, one might need to convert the logical matrix validY2_A to double first:
validY2_A = double( validY2_A );

Here is a way that should be easy to understand:
idx1=1:end-2
idx2=2:end-1
idx3=3:end
Basically these indexes shift your matrix three times.
Now you just apply them:
any(validY2_A(idx1,:) & validY2_A(idx2,:) & validY2_A(idx3,:))
This is not too hard to generalize using a loop and shift function for example.

Related

Generate truth table in MatLab

I want to create a truth table in MatLab with i columns and i2 rows. For example, if i=2, then
T =
[0 0]
[1 0]
[0 1]
[1 1]
Code to do this has already been created here
This is part of a larger project, which requires i large. Efficiency is a concern. Is there more efficient code to create a truth table? Does MatLab have a built in function to do this?
Edit: Sorry about the formatting!
Something like this?
n=2;
d=[0:2^n-1].';
T=dec2bin(d,n)
T =
00
01
10
11
dec2bin will give you a character array, which you can convert to logical, if needed. There's also de2bi that gives you a numeric array directly, but you need a newer version of Matlab and the ordering of the bits is reversed.
Here's Luis Mendo's speedup, which replicates dec2bin (n and d are as above):
T=rem(floor(d*pow2(1-n:0)),2);
ndgrid is very much your friend here:
function t = truthTable(n)
dims = repmat({[false, true]}, 1, n);
[grids{1:n}] = ndgrid(dims{:});
grids = cellfun(#(g)g(:), grids, 'UniformOutput',false);
t = [grids{:}];
First you need to create grids for the number of dimensions in your truth table. Once you have those you can columnize them to get the column vectors you need and you can horizontally concatenate those column vectors to get your truth table.
I imagine the performance of this will be quite competitive.
>> truthTable(2)
ans =
0 0
1 0
0 1
1 1
>> truthTable(4)
ans =
0 0 0 0
1 0 0 0
0 1 0 0
1 1 0 0
0 0 1 0
1 0 1 0
0 1 1 0
1 1 1 0
0 0 0 1
1 0 0 1
0 1 0 1
1 1 0 1
0 0 1 1
1 0 1 1
0 1 1 1
1 1 1 1
>>
>> timeit(#() truthTable(20))
ans =
0.030922626777
EDIT: Use reshape instead of column dereferencing for further performance improvement
function t = truthTable(n)
dims = repmat({[false, true]}, 1, n);
[grids{1:n}] = ndgrid(dims{:});
grids = cellfun(#(g) reshape(g,[],1), grids, 'UniformOutput',false);
t = [grids{:}];
>> timeit(#() truthTable(20))
ans =
0.016237298777
I know this question has been dead a while, but I was wondering the same thing and found a solution I like a lot. Thought I'd share it here:
fullfact(ones(1, i) + 1) - 1

Count the number of the first zero elements

I would line to find the number of the first consecutive zero elements. For example in [0 0 1 -5 3 0] we have two zero consecutive elements that appear first in the vector.
could you please suggest a way without using for loops?
V=[0 0 1 -5 3 0] ;
k=find(V);
Number_of_first_zeros=k(1)-1;
Or,
Number_of_first_zeros=find(V,1,'first')-1;
To solve #The minion comment (if that was the purpose):
Number_of_first_zeros=find(V(find(~V,1,'first'):end),1,'first')-find(~V,1,'first');
Use a logical array to find the zeros and then look at where the zeros and ones are alternating.
V=[1 2 0 0 0 3 5123];
diff(V==0)
ans =
0 1 0 0 -1 0
Create sample data
V=[1 2 0 0 0 3 5123];
Find the zeros. The result will be a logical array where 1 represents the location of the zeros
D=V==0
D =
0 0 1 1 1 0 0
Take the difference of that array. 1 would then represent the start and -1 would represent the end.
T= diff(D)
ans =
0 1 0 0 -1 0
find(T==1) would give you the start and find(T==-1) would give you the end. The first index+1 of T==1 would be the start of the first set of zeros and the first index of T==-1 would be the end of the first set of zeros.
You could find position the first nonzero element using find.
I=find(A, 1);
The number of leading zeros is then I-1.
My solution is quite complex yet it doesn't use the loops and it does the trick. I am pretty sure, that there is a more direct approach.
Just in case no one else posts a working solution here my idea.
x=[1 2 4 0 20 0 10 1 23 45];
x1=find(x==0);
if numel(x1)>1
x2=[x1(2:end), 0];
x3=x2-x1;
y=find(x3~=1);
y(1)
elseif numel(x1)==1
display(1)
else
display('No zero found')
end
x is the dataset. x1 contains the index of all zero elements. x2 contains all those indices except the first one (because matrix dimensions must agree, one zero is added. x3 is the difference between the index and the previous index of zeros in your dataset. Now I find all those differences which are not 1 (do not correspond to sequences of zeros) and the first index (of this data is the required result. The if case is needed in case you have only one or no zero at all.
I'm assuming your question is the following: for the following vector [0 0 1 -5 3 0], I would like to find the index of the first element of a pair of 0 values. Is this correct? Therefore, the desired output for your vector would be '1'?
To extend the other answers to find any such pairs, not just 0 0 (eg. 0 1, 0 2, 3 4 etc), then this might help.
% define the pattern
ptrn = [ 0 0 ];
difference = ptrn(2) - ptrn(1)
V = [0 0 1 -5 3 0 0 2 3 4 0 0 1 0 0 0]
x = diff(V) == difference
indices = find(x)
indices =
1 6 11 14 15

Convert digit to vector octave/matlab [duplicate]

This question already has answers here:
Construct this matrix based on two vectors MATLAB
(3 answers)
Closed 8 years ago.
I have a vector y = [0; 2; 4]
I want to convert each element of it into vector, where all elements are zero but element with index equal to digit is 1.
I'd like to do it without loops.
For example [0; 2; 4] should be converted to
[1 0 0 0 0 0 0 0 0 0;
0 0 1 0 0 0 0 0 0 0;
0 0 0 0 1 0 0 0 0 0]
(in this example vector first index is 0)
The usual trick with sparse can be used to simplify the process. Let n denote the desired number of columns. Then
result = full(sparse(1:numel(y), y+1, 1, numel(y), n));
For example, y = [0;2;4] and 10 produce
result =
1 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
First you need to decide how many digits you want to represent each number. In your case, you have 10 digits per number, so let's keep that in mind.
Once you do this, it's just a matter of indexing each element in your matrix. In your case, you have 10 digits per number. As such, do something like this:
y = [0; 2; 4]; %// Your digits array
out = zeros(numel(y), 10); %// 10 digits per number
ind = sub2ind(size(out), [1:numel(y)].', y+1);
out(ind) = 1;
The output should look like this:
out =
1 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
Let's go through this code slowly. y defines the digits you want per row of the output matrix. out allocates a matrix of zeroes where the number of rows is defined by how many digits you want in y. out will thus store your resulting matrix that you have shown us in your post.
The number of columns is 10, but you change this to be whatever you want. ind uses a command called sub2ind. This allows to completely vectorize the assignment of values in your out matrix and avoids a for loop. The first parameter is an array of values that defines how many rows and columns are in your matrix that you are trying to assign things to. In this case, it's just the size of out. The second and third parameters are the rows and columns you want to access in your matrix. In this case, the rows vary from 1 to as many elements as there are in y. In our case, this is 3. We want to generate one number per row, which is why it goes from 1 to 3. The columns denote where we want to set the digit to one for each row. As MATLAB indexes starting at 1, we have to make sure that we take y and add by 1. ind thus creates the column-major indices in order to access our matrix. The last statement finally accesses these locations and assigns a 1 to each location, thus producing our matrix.
Hope this helps!

specific column [Remove elements up to last zero element, then remove elements from first zero element to the end]

This is a very specific question. I have an M*3 matrix. The first column contains M set of elements. It may follow this.
0
0
0
0
1
1
1
1
1
1
1
1
1
0
0
0
0
0
My interest is only 1s and corresponding other column values. I can remove zeros get a new set of matrix with only 1s, but sometimes it may follow this:
1
1
1
0
0
0
0
0
1
1
1
1
1
1
1
1
1
1
1
1
1
0
0
1
1
When the situation is like above I want to disregard 1s in the beginning and remove all the elements in M*3 matrix up to the first 1, then when it reaches second start of zeros in the column it can remove all the values to the end of the column. (so it will be 13*3 matrix).
I'm doing this in matlab.
Thank you :)
Let's call your matrix A:
firstCol = A(:, 1);
indices = find(firstCol);
check = find(diff(indices) ~= 1);
if (isempty(check) )
Afinal = A(indices, :);
else
indices2 = indices(check(1)+1:1:check(2));
Afinal = A(indices2, :);
end
Afinal should be the output you're looking for.

Effiicient ways to count a streak of consecutive integers in MATLAB

Say I have a vector containing only logical values, such as
V = [1 0 1 0 1 1 1 1 0 0]
I would like to write a function in MATLAB which returns a 'streak' vector S for V, where S(i) represents the number of consecutive 1s in V up to but not including V(i). For the example above, the streak vector would be
S = [0 1 0 1 0 1 2 3 4 0]
Given that I have to do this for a very large matrix, I would very much appreciate any solution that is vectorized / efficient.
This should do the trick:
S = zeros(size(V));
for i=2:length(V)
if(V(i-1)==1)
S(i) = 1 + S(i-1);
end
end
The complexity is only O(n), which I guess should be good enough.
For your sample input:
V = [1 0 1 0 1 1 1 1 0 0];
S = zeros(size(V));
for i=2:length(V)
if(V(i-1)==1)
S(i) = 1 + S(i-1);
end
end
display(V);
display(S);
The result would be:
V =
1 0 1 0 1 1 1 1 0 0
S =
0 1 0 1 0 1 2 3 4 0
You could also do it completely vectorized with a couple intermediate steps:
V = [1 0 1 0 1 1 1 1 0 0];
Sall = cumsum(V);
stopidx = find(diff(V)==-1)+1;
V2=V;
V2(stopidx) = -Sall(stopidx)+[0 Sall(stopidx(1:end-1))];
S2 = cumsum(V2);
S = [0 S2(1:end-1)];
Afaik the only thing that can take a while is the find call; you can't use logical indexing everywhere and bypass the find call, because you need the absolute indices.
It's outside the box - but have you considered using text functions? Since strings are just vectors for Matlab it should be easy to use them.
Regexp contains some nice functions for finding repeated values.