How to check for identical Vectors concurrently? - matlab

Trying to check for identical vectors. Currently using the isequal function to check for identical ones.
It runs like this.
if isequal (vectorA, vectorB) == 0
It will then run an instruction.
end
if isequal (vectorA, vectorB) == 1
It will run another instruction.
end
I now have a set of vectors more from A to F. Is there anyway to check all of them (B,C,D,F) against Vector A and do the same thing as mentioned?
Meaning
if vectorA matches any of B,C,D,F == 0
The same with the second case where
if vectorA matches any of B,C,D,F == 1
The vectors are constantly changing and this is running in a loop to check for identical vectors. Seems like the isequal function only works between 2 Vectors.
all the vectors are 1xi where i can be a number up to 50
ANY help in this would be greatly apreciated!

I suggest you keep your other vectors in a matrix rather so something like:
a = vectorA;
B = [vectorB, vectorC, vectorD, vectorE];
Then just use a simple for loop:
flag = false;
for k = 1:size(B,2)
flag = flag || isequal(a,B(:,k));
if flag
break
end;
end
or if you prefer a completely vecotrized one-liner over the loop (but in this case, I suspect the early exit clause in the loop might actually provide a performance benefit, depends on your data though):
flag = any(all(bsxfun(#eq,a,B)))
then
if flag
%// do stuff if any was equal
else
%// Do stuff if none were equal to a
BTW if you wanted to check if they ALL match instead of if ANY match then change to:
flag = all(all(bsxfun(#eq,a,B)))
or in the loop change to
flag = true;
for k = 1:size(B,2)
flag = flag && isequal(a,B(:,k));
if ~flag
break
end;
end

This can be done very easily with ismember:
To check whether it a vector matches any of the rows:
v = 1:3
M = [1:3;2:4;3:5]
ismember(v,M,'rows')
To check whether it matches all of the rows, you can extend it by also checking something like:
size(unique(M,'rows'),1)==1
This assumes that the vectors are stacked below each other, but of course it is easily adjusted to match the situation when they are next to each other.

To check if A equals any of B, C, D, F (with possibly different sizes), use cellfun on a cell array containing your vectors:
if any(cellfun(#(x) isequal(A,x), {B,C,D,F}))
If all vectors are row vectors with an equal number columns, it may be faster to use bsxfun on a matrix containing your vectors:
if any(all(bsxfun(#eq, A, [B; C; D; F]).'))

Related

MATLAB - Check matrix to see if two consecutive numbers = 0

I have a matrix being created in MATLAB but need to check if any two consecutive numbers (by row) = 0 and if it does output with a yes or no without showing the answers. Ive put my code below my final loop is returning errors and im not too sure how to go about this.
%%Input positive integer
n=input('Give a positive integer greater than 1: ');
%%Error for below 1
if n<=1
error('The value given is less than or equal to 1')
end
%%loop for vector v
for i=1:n
v(i)=2^i*3;
end
%display vector
v
A=randi([-5,5],n,n);
A
x = 1;
consecutive = false;
for i = 1:25
if (A(x) + A(x+1) = 0);
consecutive = true;
end
end
There's a lot wrong with the code of your final loop:
You set x to 1 and use it as an index into A, but never change it from 1.
As Amit points out, you are using = (used for assignment) when you should be using == (the equality operator).
As Gondrian points out, you are testing if a sum is equal to zero, but from your description it sounds like you should be testing if each value is zero.
Your loop iterates 25 times (i = 1:25), but it's not clear why, since your matrix A is of size n-by-n.
Instead of using a for loop, it's possible to do this with indexing instead. Since you are checking for consecutive zeroes by row, this is what it would look like:
zeroPairs = (A(:, 1:(n-1)) == 0) & (A(:, 2:n) == 0);
consecutive = any(zeroPairs(:));
The term A(:, 1:(n-1)) gets all of the "left" values in each pairwise comparison and the term A(:, 2:n) gets all of the "right" value. These are compared to 0, then combined. This creates an n-by-(n-1) matrix zeroPairs where a value of true indicates where a pair of consecutive zeroes occurs. This matrix is reshaped into a column vector and any is used to check if a value of true is present anywhere.
You will need to change your if block as follows.
if (A(x) + A(x+1) == 0);
consecutive = true;
end
Notice the == instead of just =. The first one is for comparison and the second one is for assignment. This will get rid of the error that you are currently getting. There may be other issues in the algorithm of your code but I did not examine or try to fix that.
btw:
'if any two consecutive numbers (by row) = 0'
If I understand you right, you should try 'if A(x) == 0 && A(x+1) == 0';
because '(A(x) + A(x+1) == 0)' would be true for -5 and 5, as it equals to 0. But -5 and 5 are not two consecutive zeros.
(or even look at the 'diff' function. It will return a 0 if two following numbers are the same)
To show a vectorized, more Matlab-like approach:
v = 0; % sought value
C = 2; % desired number of consecutive values in a row
consecutive = nnz(conv2(double(A==v), ones(1,C))==C)>0;
This compares each entry of A with the value v, and then applies 2D convolution with a row vector of C ones. Any C horizontally-consecutive entries of A with value v will produce an entry equal to C in the convolution result. So we check if the number of such entries is positive.

find returns empty matrix

I have two vectors which are of length 200,000 approximately. They consist of dates in the datenum format.
%datenums
date_exp = datenum(data_exp(:,1:6));
date_sim = datenum(data_sim(:,1:6));
I want to find the dates in date_exp that exists in date_sim.
Then remove the values from date_exp
I have used the the ismember tool but ending up at i=38 find retunrs: Improper assignment with rectangular empty matrix.
Error in filter (line 18)
c(i)= find(ismember(date_sim(:),date_exp(i)),1);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
c = zeros(length(date_sim),1);
for i=1:length(date_sim)
c(i)= find(ismember(date_sim(:),date_exp(i)),1);
if isempty(c(i)) == 1
c(i) = 0;
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
I would be really helpful if anyone could help me out here.
The issue is because date_exp(38) must not be within date_sim. When there are no 1's in the input, find returns an empty array ([]).
Your code does not handle this as you would expect though because of this line.
c(i) = find(...)
In this case, if there are no matches (find() == []), then you are essentially calling
c(i) = [];
This deletes the ith element of c element
Therefore the following line is never true!
if isempty(c(i)) == 1
Instead, you should probably do something to handle the empty value.
index = find(ismember(date_sim(:), date_exp(i)), 1);
%// Only assign the index if it isn't an empty array
if ~isempty(index)
c(i) = index;
end
You don't have to worry about assigning zeros because your initial matrix is already full of zeros.
A Better Option
All of that aside, it would likely be a much better approach to not loop at all and to instead use the second output of ismember (on the arrays before you pass them to datenum) to give you the same result in a much more efficient way.
[~, c] = ismember(date_exp(:,1:6), date_sim(:,1:6), 'rows');

Is there a way to make this more efficient (Matlab)?

I've figured out a method that works for my purposes, however I would like to make the solution generalizable to more numbers of trials without having to hard-code a new if-statement for every increase in trials. Right now trials=4 and if I wanted to make trials=5 I would need to write a new if-statement.
if new_A == 1:trials;
outer_matrices{:,1} = A;
end
if new_A == trials+1:trials*2;
outer_matrices{:,2} = A;
end
if new_A == (trials*2)+1:trials*3;
outer_matrices{:,3} = A;
end
if new_A == (trials*3)+1:trials*4;
outer_matrices{:,4} = A;
end
You see the pattern (with trials=5 I would need to multiply by 4 and 5 respectively and then change to outer_matrices{:,5})
I'm sure there's a fairly simple solution/structure that I'm just not thinking of. Thanks in advance!
Try this (no loops or conditionals approach) -
N = 5;%%// Number of cases
ind = find(all(bsxfun(#eq,reshape(1:trials*N,trials,[]),new_A'),1))
outer_matrices{:,ind} = A;
I take it new_A is a vector with trials number of elements. As (trials*n)+1:trials*(n+1) is a vector of the form [trials*n+1, trials*n+2, ... ] you can do:
if ~mod(new_A(1)-1,trials) && all(diff(new_A) == 1)
outerMatrices{(trials+new_A(1)-1)/trials} = A;
end
What it does is:
~mod(new_A(1)-1,trials) uses the modulus operation, to check if the first element in new_A is divisible by trials. If it is, the mod will return 0. The ~ in front of mod means "not", thus if mod returns zero, this will evaluate to "~0 == 1".
all(diff(new_A)==1) checks if all the elements in new_A is a exactly one element apart.
A basic for-loop approach to mirror the code in the question would be:
N=5;
for ii=1:N
if new_A == trials*(ii-1)+1:trials*ii
outer_matrices{:,ii} = A;
end
end

MATLAB: I want to threshold a matrix, based on thresholds in a vector, without a for loop. Possible?

Let us say I have the following:
M = randn(10,20);
T = randn(1,20);
I would like to threshold each column of M, by each entry of T. For example, find all indicies of all elements of M(:,1) that are greater than T(1). Find all indicies of all elements in M(:,2) that are greater than T(2), etc etc.
Of course, I would like to do this without a for-loop. Is this possible?
You can use bsxfun like this:
I = bsxfun(#gt, M, T);
Then I will be a logcial matrix of size(M) with ones where M(:,i) > T(i).
You can use bsxfun to do things like this, but it may not be faster than a for loop (more below on this).
result = bsxfun(#gt,M,T)
This will do an element wise comparison and return you a logical matrix indicating the relationship governed by the first argument. I have posted code below to show the direct comparison, indicating that it does return what you are looking for.
%var declaration
M = randn(10,20);
T = randn(1,20);
% quick method
fastres = bsxfun(#gt,M,T);
% looping method
res = false(size(M));
for i = 1:length(T)
res(:,i) = M(:,i) > T(i);
end
% check to see if the two matrices are identical
isMatch = all(all(fastres == res))
This function is very powerful and can be used to help speed up processes, but keep in mind that it will only speed things up if there is a lot of data. There is a bit of background work that bsxfun must do, which can actually cause it to be slower.
I would only recommend using it if you have several thousand data points. Otherwise, the traditional for-loop will actually be faster. Try it out for yourself by changing the size of the M and T variables.
You can replicate the threshold vector and use matrix comparison:
s=size(M);
T2=repmat(T, s(1), 1);
M(M<T2)=0;
Indexes=find(M);

How to make random matrix whose rows must all sum <=11 and which cannot contain consecutive triplets of 0-0-0 in any row

I want to make an array called result, which has dimensions (14,12,10) and has values random[0 2], but it should not contain 0 more than three consecutive times in each row (dimension 2), and the sum of all values in each row must be <= 11.
This is my current approach:
jum_kel = 14;
jum_bag = 12;
uk_pop = 10;
for ii = 1:uk_pop,
libur(:,:,ii) = randint(jum_kel,jum_bag,[0 2]); %#initialis
sum_libur(1,:,ii) = sum(libur(:,:,ii),2); %#sum each row
end
for jj = 1:jum_kel
while sum_libur(1,jj,ii) > 11, %# first constraint : sum each row should be <=11,
libur(jj,:,ii) = randint(1,jum_bag,[0 2])
sum_libur(1,:,ii)= sum(libur(:,:,ii),2);
for kk = 1:jum_bag
if kk>2
o = libur(jj,kk,ii)+libur(jj,kk-1,ii)+libur(jj,kk-2)
while kk>2 && o==0 %# constraint 2: to make matrix will not contain consecutive triplets (0-0-0) in any row.
libur(jj,:,ii) = randint(1,jum_bag,[0 2]);
sum_libur(1,:,ii)= sum(libur(:,:,ii),2);
end
end
end
end
end
but this is extremely slow...Does anyone see a faster method?
(sidenote: A matrix does not have 3 dimensions: that would be a tensor, in which case the concept of "row" is not well-defined.)
The easiest way is to use Rejection Sampling. Normally this might be slow, and even though you don't mention it, I'd worry this code might occur in a performance-critical section of your program. Nevertheless, everything is okay, since the chance of a 14 3-sided coinflips in a row containing the substring 0-0-0 is fairly small. Even it's an issue, since the matrix is (supposedly) uniformly distributed, its elements must also be independently distributed, so you can sample each row separately, rejecting and recreating any row with 0-0-0 in a row or which has a sum <= 11.
As indicated by #ninjagecko, rejecting and recreating is the most obvious (if not the only) way to go here. In that light, I think this'll do nicely:
R = 14;
C = 12;
T = 10;
result = zeros(C,R*T);
for ii = 1:(R*T)
done = false;
while ~done
newRow = randi([0 2],C,1);
done = ...
(sum(newRow)<12) && ...
(~any(diff([0;find(newRow);C+1])>3));
end
result(:,ii) = newRow;
end
result = permute(reshape(result,C,R,T), [2 1 3]);
Note that <12 equals <=11 for integer math (and >3 equals >=4), but requires one less check and is thus faster. The variable newRow is created as a column vector, since such things are better organized in memory and can be checked faster. 3D arrays are generally slower to assign to than 2D matrices, therefore everything is kept 2D until after all operations. The most computationally intense check (~any(diff(find(newRow))>3)) is done last, so that short-circuiting (&&) may render its evaluation unnecessary. Both loops are small and fulfil all conditions to be compiled to machine code by Matlab's JIT.
So this is pretty close to optimized, and will be pretty fast. Unless someone comes up with an entirely different algorithm for this, I believe this is pretty close to the theoretical maximum speed in Matlab. If you need to go faster, you'll have to switch to C (which will allow optimization of the constraint checks).
For simply finding a series of numbers in an array, you can (ab)use strfind. When indexing into a multidimensional array, you can also combine subindices and linear indexing to the remaining dimensions (used in the assignment result(:,ii) = newRow):
result = NaN(12,14,10);
for ii = 1:14*10
while 1
newRow = randi([0 2],12,1);
if isempty(strfind(newRow',[0 0 0])) && sum(newRow)<=11
result(:,ii) = newRow;
break;
end
end
end
result = permute(result, [2 1 3]);