Find if 2 vectors have 4 consecutive identical elements - matlab

I am trying to compare 2 vectors to discover if they share 4 consecutive values.
For example
w = [6 7 8 9 10 11 12 13 14]
v = [5 6 7 8 9]
Has 4 consecutive values 6 7 8 9
But
x = [6 7 8 9 10 11 12 13 14]
y = [6 7 1 2 3 4 5 6 13 14]
has four identical values (6 7 13 14) but they aren't consecutive.
The code I am currently using is:
if length(intersect(v, w)) >= 4
condition = true;
but this doesn't test for consecutive elements, so it would return true for both cases listed above whereas I want it to only return true for the first case.
Can somebody please help me find a way to test for identical consecutive elements rather than just identical elements.

Building on Marcos' answer:
Create all possible search vectors from your initial search (i.e. [5 6 7 8] [6 7 8 9]) - however we will make it a 3D matrix which will be m-by-1-by-n
n = 4;
m = numel(v)-n+1;
V = permute(v(bsxfun(#plus,(0:m-1)',1:n)),[1,3,2])
Check if any of these sub-vectors are a subset of the vector being searched
check = sum(any(bsxfun(#eq, V, w),3),2) >= n;
match = squeeze(V(check,:,:))' %'// The ' is debatable here, it depends on how many matches you get

you can compare
bsxfun(#eq, w,v')
Resulting with
ans =
0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0
As you can see four consecutive matching elements form a diagonal of length 4.
To find the location of this diagonal you can conv2 with a 4 diagonal filter (eye(4)):
[rr cc] = find( conv2( single(bsxfun(#eq, [1 2 3 w],v')), eye(4), 'same' ) == 4 )
compensating for the center of the filter
loc_in_w = cc - 1
loc_in_v = rr - 1
yielding
loc_in_w =
1
loc_in_v =
2
which are the first index of the sequence in w and v respectively.
This method can work with more than one occurrence of a 4-substring of v in w...

I haven't meddled in matlab for ages, but my "general" approach to this in computing terms would be splitting the problem into a needle-and-haystack solution with two parts:
Create all possible search vectors from your initial search (i.e. [5 6 7 8] [6 7 8 9])
Check if any of these sub-vectors are a subset of the vector being searched.
Basically just two set-operations in a row.

You could convert your vectors to strings, and use strfind.
If x and y are your vectors:
x_str = mat2str(x);
y_str = mat2str(y);
n = strfind(x_str(2:end-1), y_str(2:end-1))
Note that you have to remove the first and last characters of the string version, as they correspond to the square brackets of the vectors.

Related

Matlab how to distribute a matrix elements randomly

hi everyone how to make a matrix randomly distributed to another matrix n,
m = [ 1 1 3 3 3 4 4 6 6 7 7 7];
n = zeros(3,10);
the same value must in the sequence, ex : 4 4 4, 7 7 7.result reqiured can be something like {or other combinations):
distributed_matrix =
0 1 1 0 7 7 7 0 0 0
0 0 3 3 3 4 4 0 0 0
6 6 6 0 0 0 0 0 0 0
thank you...
If you do not impose any constraint on the order at which the elements of m are distributed, then randsample might help:
ridx = randsample( numel(n), numel(m) ); %// sample new idices for elelemtns
n(ridx) = m;
Looking into the additional constraints, things get a bit more messy.
For identifying the sequences and their extent in m, you can:
idx = [1 find(diff(m)~=0)+1];
extent = diff([idx numel(m)+1]); %// length of each sequence
vals = m(idx); %// value of each sequence
Once you have the sequqnces and their length you can randomly shuffle them and then distribute along the lines...
If I understand your question correctly, the possible solution is
m = [ 1 1 3 3 3 4 4 6 6 7 7 7];
n = zeros(3,10);
p= randperm(numel(n)); % generate the random permutation
n(p(1:length(m)))= m % assign the elments of m to the elements with indices taken
% from the first length(m) numbers of random permutation

Matlab: Using a matrix as a mask to perform elementwise operations

In Matlab, I have two matrices: one with integers,x, and one with booleans, y:
x =
2 4 2
3 3 1
4 1 5
y =
0 0 1
1 1 0
1 0 1
What I now want to do is to assign some elements of x to 5, and I want to use y as a mask to determine which elements should be set to 5. So elements with a corresponding value of 0 in y should remain as they are in x, but those with a corresponding value of 1 in y should be set to 5. Therefore, the output should be:
2 4 5
5 5 1
5 1 5
I have tried the following:
x(y) = 5
Which gives me the error:
Subscript indices must either be real positive integers or logicals.
And I have also tried:
y(x) = 5
Which gives me the following:
5 5 1
5 1 0
5 0 1
Can somebody please explain what is going on here, and what I need to do to get my desired result?
The error you've got is due to the fact that, apparently, y is of type double while, in this case, it should be of type logical
You could try:
x(logical(y))=5
Hope this helps
Its not a fancy solution but will solve your problem
>> x = [ 2 4 2;3 3 1;4 1 5];
y = logical([ 0 0 1;1 1 0;1 0 1]);
f = x(:);
f(y(:)) = 5;
x = reshape(f,size(x))
x =
2 4 5
5 5 1
5 1 5
>>
x(find(y)) = 5; should work fine.

Dividing a vector to form different matrices

I have a two long vector. Vector one contains values of 0,1,2,3,4's, 0 represent no action, 1 represent action 1 and 2 represent the second action and so on. Each action is 720 sample point which means that you could find 720 consecutive twos then 720 consecutive 4s for example. Vector two contains raw data corresponding to each action. I need to create a matrix for each action ( 1, 2, 3 and 4) which contains the corresponding data of the second vector. For example matrix 1 should has all the data (vector 2 data) which occurred at the same indices of action 1. Any Help??
Example on small amount of data:
Vector 1: 0 0 1 1 1 0 0 2 2 2 0 0 1 1 1 0 0 2 2 2
Vector 2: 6 7 5 6 4 6 5 9 8 7 9 7 0 5 6 4 1 5 8 0
Result:
Matrix 1:
5 6 4
0 5 6
Matrix 2:
9 8 7
5 8 0
Here is one approach. I used a cell array to store the output matrices, hard-coding names for such variables isn't a good plan.
V1=[0 0 1 1 1 0 0 2 2 2 0 0 1 1 1 0 0 2 2 2]
V2=[6 7 5 6 4 6 5 9 8 7 9 7 0 5 6 4 1 5 8 0]
%// Find length of sequences of 1's/2's
len=find(diff(V1(find(diff(V1)~=0,1)+1:end))~=0,1)
I=unique(V1(V1>0)); %// This just finds how many matrices to make, 1 and 2 in this case
C=bsxfun(#eq,V1,I.'); %// The i-th row of C contains 1's where there are i's in V1
%// Now pick out the elements of V2 based on C, and store them in cell arrays
Matrix=arrayfun(#(m) reshape(V2(C(m,:)),len,[]).',I,'uni',0);
%// Note, the reshape converts from a vector to a matrix
%// Display results
Matrix{1}
Matrix{2}
Since, there is a regular pattern in the lengths of groups within Vector 1, that could be exploited to vectorize many things while proposing a solution. Here's one such implementation -
%// Form new vectors out of input vectors for non-zero elements in vec1
vec1n = vec1(vec1~=0)
vec2n = vec2(vec1~=0)
%// Find positions of group shifts and length of groups
df1 = diff(vec1n)~=0
grp_change = [true df1]
grplen = find(df1,1)
%// Reshape vec2n, so that we end up with N x grplen sized array
vec2nr = reshape(vec2n,grplen,[]).' %//'
%// ID/tag each group change based on their unique vector 2 values
[R,C] = sort(vec1n(grp_change))
%// Re-arrange rows of reshaped vector2, s.t. same ID rows are grouped succesively
vec2nrs = vec2nr(C,:)
%// Find extents of each group & use those extents to have final cell array output
grp_extent = diff(find([1 diff(R) 1]))
out = mat2cell(vec2nrs,grp_extent,grplen)
Sample run for the given inputs -
>> vec1
vec1 =
0 0 1 1 1 0 0 2 2 2 ...
0 0 1 1 1 0 0 2 2 2
>> vec2
vec2 =
6 7 5 6 4 6 5 9 8 7 ...
9 7 0 5 6 4 1 5 8 0
>> celldisp(out)
out{1} =
5 6 4
0 5 6
out{2} =
9 8 7
5 8 0
Here is another solution:
v1 = [0 0 1 1 1 0 0 2 2 2 0 0 1 1 1 0 0 2 2 2];
v2 = [6 7 5 6 4 6 5 9 8 7 9 7 0 5 6 4 1 5 8 0];
m1 = reshape(v2(v1 == 1), 3, [])'
m2 = reshape(v2(v1 == 2), 3, [])'
EDIT: David's solution is more flexible and probably more efficient.

Greatest values in a matrix, row by row - matlab

I have an m-by-n matrix. For each row, I want to find the position of the k greatest values, and set the others to 0.
Example, for k=2
I WANT
[1 2 3 5 [0 0 3 5
4 5 9 3 0 5 9 0
2 6 7 1] 0 6 7 0 ]
You can achieve it easily using the second output of sort:
data = [ 1 2 3 5
4 5 9 3
2 6 7 1 ];
k = 2;
[M N] = size(data);
[~, ind] = sort(data,2);
data(repmat((1:M).',1,N-k) + (ind(:,1:N-k)-1)*M) = 0;
In the example, this gives
>> data
data =
0 0 3 5
0 5 9 0
0 6 7 0
You can use prctile command to find the threshold per-line.
prctile returns percentiles of the values in the rows of data and thus can be easily tweaked to return the threshold value above which the k-th largest elements at each row exist:
T = prctile( data, 100*(1 - k/size(data,2)), 2 ); % find the threshold
out = bsxfun(#gt, data, T) .* data; % set lower than T to zero
For the data matrix posted in the question we get
>> out
out =
0 0 3 5
0 5 9 0
0 6 7 0

matlab adjacency list to adjacency matrix

How to convert adjacency list to adjacency matrix via matab
For example: Here is the adjacency list(undirected), the third column is the weight.
1 2 3
1 3 4
1 4 5
2 3 4
2 5 8
2 4 7
++++++++++++++++++++++
that should be converted to:
1 2 3 4 5
1 0 4 5 0
2 3 4 7 8
3 4 7 0 0
4 0 7 0 0
5 0 8 0 0
You can use sparse matrix. Let rows be the first column, cols the second, and s the weight.
A = sparse([rows; cols],[cols; rows],[s; s]);
If you want to see the matrix. use full().
UPDATE:
I made the answer a bit simpler (everything in one line, instead of adding the transposed, and included explanations, as requested:
list = [1 2 3
1 3 4
1 4 5
2 3 4
2 5 8
2 4 7];
rows = list(:,1)
cols = list(:,2)
s = list(:,3)
Now, rows, cols and s contains the needed information. Sparse matrices need three vectors. Each row of the two first vectors, rows and cols is the index of the value given in the same row of s (which is the weight).
The sparse command assigns the value s(k) to the matrix element adj_mat(rows(k),cols(k)).
Since an adjacency matrix is symmetric, A(row,col) = A(col,row). Instead of doing [rows; cols], it is possible to first create the upper triangular matrix, and then add the transposed matrix to complete the symmetric matrix.
A = sparse([rows; cols],[cols; rows],[s; s]);
full(A)
A =
0 3 4 5 0
3 0 4 7 8
4 4 0 0 0
5 7 0 0 0
0 8 0 0 0
It's really hard to tell what your'e asking. Is this right?
list = [1 2 3
1 3 4
1 4 5
2 3 4
2 5 8
2 4 7];
matrix = zeros(max(max(list(:, 1:2)))); %// Or just zeros(5) if you know you want a 5x5 result
matrix(sub2ind(size(matrix), list(:,1), list(:,2))) = list(:,3); %// Populate the upper half
matrix = matrix + matrix' %'// Find the lower half via symmetry
matrix =
0 3 4 5 0
3 0 4 7 8
4 4 0 0 0
5 7 0 0 0
0 8 0 0 0