How to compare array to a number for if statement? - matlab

H0 is an array ([1:10]), and H is a single number (5).
How to compare every element in H0 with the single number H?
For example in
if H0>H
do something
else
do another thing
end
MATLAB always does the other thing.

if requires the following statement to evaluate to a scalar true/false. If the statement is an array, the behaviour is equivalent to wrapping it in all(..).
If your comparison results in a logical array, such as
H0 = 1:10;
H = 5;
test = H0>H;
you have two options to pass test through the if-statement:
(1) You can aggregate the output of test, for example you want the if-clause to be executed when any or all of the elements in test are true, e.g.
if any(test)
do something
end
(2) You iterate through the elements of test, and react accordingly
for ii = 1:length(test)
if test(ii)
do something
end
end
Note that it may be possible to vectorize this operation by using the logical vector test as index.
edit
If, as indicated in a comment, you want P(i)=H0(i)^3 if H0(i)<H, and otherwise P(i)=H0(i)^2, you simply write
P = H0 .^ (H0<H + 2)

#Jonas's nice answer at his last line motivated me to come up with a version using logical indexing.
Instead of
for i=1:N
if H0(i)>H
H0(i)=H0(i)^2;
else
H0(i)=H0(i)^3;
end
end
you can do this
P = zeros(size(H0)); % preallocate output
test = H0>H;
P(test) = H0(test).^2; % element-wise operations
% on the elements for which the test is true
P(~test) = H0(~test).^3; % element-wise operations
% on the elements for which the test is false
Note that this is a general solution.

Anyway take a look at this: using ismemeber() function. Frankly not sure how do you expect to compare. Either greater than, smaller , equal or within as a member. So my answer might not be yet satisfying to you. But just giving you an idea anyway.
H0 = [0 2 4 6 8 10 12 14 16 18 20];
H = [10];
ismember(H,H0)
IF (ans = 1) then
// true
else
//false
end
Update Answer
This is super bruteforce method - just use it explain. You are better off with any other answers given here than what I present. Ideally what you need is to rip off greater/lower values into two different vectors with ^3 processing - I assume... :)
H0 = [0 2 4 6 8 10 12 14 16 18 20];
H = [10];
H0(:)
ans =
0
2
4
6
8
10
12
14
16
18
20
Function find returns indices of all values in H0 greater than 10 values in a linear index.
X = find(H0>H)
X =
7
8
9
10
11
Function find returns indices of all values in H0 lower than 10 in a linear index.
Y = find(H0<H)
Y =
1
2
3
4
5
6
If you want you can access each element of H0 to check greater/lower values or you can use the above matrices with indices to rip the values off H0 into two different arrays with the arithmetic operations.
G = zeros(size(X)); // matrix with the size = number of values greater than H
J = zeros(size(Y)); // matrix with the size = number of values lower than H
for i = 1:numel(X)
G(i) = H0(X(i)).^3
end
G(:)
ans =
1728
2744
4096
5832
8000
for i = 1:numel(Y)
J(i) = H0(Y(i)).^2
end
J(:)
ans =
0
4
16
36
64
100

Related

How to get all the possible combinations of elements in a matrix, but don't allow exchange of elements inbetween columns?

Lets say I have this matrice A: [3 x 4]
1 4 7 10
2 5 8 11
3 6 9 12
I want to permute the element of in each column, but they can't change to a different column, so 1 2 3 need to always be part of the first column. So for exemple I want:
3 4 8 10
1 5 7 11
2 6 9 12
3 4 8 11
1 6 7 10
2 5 9 12
1 6 9 11
. . . .
So in one matrix I would like to have all the possible permutation, in this case, there are 3 different choices 3x3x3x3=81possibilities.So my result matrixe should be 81x4, because I only need each time one [1x4]line vector answer, and that 81 time.
An other way to as the question would be (for the same end for me), would be, if I have 4 column vector:
a=[1;2;3]
b=[4;5;6]
c=[7;8;9]
d=[10;11;12;13]
Compare to my previous exemple, each column vector can have a different number of row. Then is like I have 4 boxes, A, B C, D and I can only put one element of a in A, b in B and so on; so I would like to get all the permutation possible with the answer [A B C D] beeing a [1x4] row, and in this case, I would have 3x3x3x4=108 different row. So where I have been missunderstood (my fault), is that I don't want all the different [3x4] matrix answers but just [1x4]lines.
so in this case the answer would be:
1 4 7 10
and 1 4 7 11
and 1 4 7 12
and 1 4 7 13
and 2 4 8 10
and ...
until there are the 108 combinations
The fonction perms in Matlab can't do that since I don't want to permute all the matrix (and btw, this is already a too big matrix to do so).
So do you have any idea how I could do this or is there is a fonction which can do that? I, off course, also could have matrix which have different size. Thank you
Basically you want to get all combinations of 4x the permutations of 1:3.
You could generate these with combvec from the Neural Networks Toolbox (like #brainkz did), or with permn from the File Exchange.
After that it's a matter of managing indices, applying sub2ind (with the correct column index) and rearranging until everything is in the order you want.
a = [1 4 7 10
2 5 8 11
3 6 9 12];
siz = size(a);
perm1 = perms(1:siz(1));
Nperm1 = size(perm1,1); % = factorial(siz(1))
perm2 = permn(1:Nperm1, siz(2) );
Nperm2 = size(perm2,1);
permidx = reshape(perm1(perm2,:)', [Nperm2 siz(1), siz(2)]); % reshape unnecessary, easier for debugging
col_base_idx = 1:siz(2);
col_idx = col_base_idx(ones(Nperm2*siz(1) ,1),:);
lin_idx = reshape(sub2ind(size(a), permidx(:), col_idx(:)), [Nperm2*siz(1) siz(2)]);
result = a(lin_idx);
This avoids any loops or cell concatenation and uses straigh indexing instead.
Permutations per column, unique rows
Same method:
siz = size(a);
permidx = permn(1:siz(1), siz(2) );
Npermidx = size(permidx, 1);
col_base_idx = 1:siz(2);
col_idx = col_base_idx(ones(Npermidx, 1),:);
lin_idx = reshape(sub2ind(size(a), permidx(:), col_idx(:)), [Npermidx siz(2)]);
result = a(lin_idx);
Your question appeared to be a very interesting brain-teaser. I suggest the following:
in = [1,2,3;4,5,6;7,8,9;10,11,12]';
b = perms(1:3);
a = 1:size(b,1);
c = combvec(a,a,a,a);
for k = 1:length(c(1,:))
out{k} = [in(b(c(1,k),:),1),in(b(c(2,k),:),2),in(b(c(3,k),:),3),in(b(c(4,k),:),4)];
end
%and if you want your result as an ordinary array:
out = vertcat(out{:});
b is a 6x3 array that contains all possible permutations of [1,2,3]. c is 4x1296 array that contains all possible combinations of elements in a = 1:6. In the for loop we use number from 1 to 6 to get the permutation in b, and that permutation is used as indices to the column.
Hope that helps
this is another octave friendly solution:
function result = Tuples(A)
[P,n]= size(A);
M = reshape(repmat(1:P, 1, P ^(n-1)), repmat(P, 1, n));
result = zeros(P^ n, n);
for i = 1:n
result(:, i) = A(reshape(permute(M, circshift((1:n)', i)), P ^ n, 1), i);
end
end
%%%example
A = [...
1 4 7 10;...
2 5 8 11;...
3 6 9 12];
result = Tuples(A)
Update:
Question updated that: given n vectors of different length generates a list of all possible tuples whose ith element is from vector i:
function result = Tuples( A)
if exist('repelem') ==0
repelem = #(v,n) repelems(v,[1:numel(v);n]);
end
n = numel(A);
siz = [ cell2mat(cellfun(#numel, A , 'UniformOutput', false))];
tot_prd = prod(siz);
cum_prd=cumprod(siz);
tot_cum = tot_prd ./ cum_prd;
cum_siz = cum_prd ./ siz;
result = zeros(tot_prd, n);
for i = 1: n
result(:, i) = repmat(repelem(A{i},repmat(tot_cum(i),1,siz(i))) ,1,cum_siz(i));
end
end
%%%%example
a = {...
[1;2;3],...
[4;5;6],...
[7;8;9],...
[10;11;12;13]...
};
result =Tuples(a)
This is a little complicated but it works without the need for any additional toolboxes:
You basically want a b element 'truth table' which you can generate like this (adapted from here) if you were applying it to each element:
[b, n] = size(A)
truthtable = dec2base(0:power(b,n)-1, b) - '0'
Now you need to convert the truth table to linear indexes by adding the column number times the total number of rows:
idx = bsxfun(#plus, b*(0:n-1)+1, truthtable)
now you instead of applying this truth table to each element you actually want to apply it to each permutation. There are 6 permutations so b becomes 6. The trick is to then create a 6-by-1 cell array where each element has a distinct permutation of [1,2,3] and then apply the truth table idea to that:
[m,n] = size(A);
b = factorial(m);
permutations = reshape(perms(1:m)',[],1);
permCell = mat2cell(permutations,ones(b,1)*m,1);
truthtable = dec2base(0:power(b,n)-1, b) - '0';
expandedTT = cell2mat(permCell(truthtable + 1));
idx = bsxfun(#plus, m*(0:n-1), expandedTT);
A(idx)
Another answer. Rather specific just to demonstrate the concept, but can easily be adapted.
A = [1,4,7,10;2,5,8,11;3,6,9,12];
P = perms(1:3)'
[X,Y,Z,W] = ndgrid(1:6,1:6,1:6,1:6);
You now have 1296 permutations. If you wanted to access, say, the 400th one:
Permutation_within_column = [P(:,X(400)), P(:,Y(400)), P(:,Z(400)), P(:,W(400))];
ColumnOffset = repmat([0:3]*3,[3,1])
My_permutation = Permutation_within_column + ColumnOffset; % results in valid linear indices
A(My_permutation)
This approach allows you to obtain the 400th permutation on demand; if you prefer to have all possible permutations concatenated in the 3rd dimension, (i.e. a 3x4x1296 matrix), you can either do this with a for loop, or simply adapt the above and vectorise; for example, if you wanted to create a 3x4x2 matrix holding the first two permutations along the 3rd dimension:
Permutations_within_columns = reshape(P(:,X(1:2)),3,1,[]);
Permutations_within_columns = cat(2, Permutations_within_columns, reshape(P(:,Y(1:2)),3,1,[]));
Permutations_within_columns = cat(2, Permutations_within_columns, reshape(P(:,Z(1:2)),3,1,[]));
Permutations_within_columns = cat(2, Permutations_within_columns, reshape(P(:,W(1:2)),3,1,[]));
ColumnOffsets = repmat([0:3]*3,[3,1,2]);
My_permutations = Permutations_within_columns + ColumnOffsets;
A(My_permutations)
This approach enables you to collect a specific subrange, which may be useful if available memory is a concern (i.e. for larger matrices) and you'd prefer to perform your operations by blocks. If memory isn't a concern you can get all 1296 permutations at once in one giant matrix if you wish; just adapt as appropriate (e.g. replicate ColumnOffsets the right number of times in the 3rd dimension)

Count number of elements in a specific range in an array [duplicate]

I have a huge vector. I have to count values falling within certain ranges.
the ranges are like 0-10, 10-20 etc. I have to count the number of values which fall in certain range.
I did something like this :
for i=1:numel(m1)
if (0<m1(i)<=10)==1
k=k+1;
end
end
Also:
if not(isnan(m1))==1
x=(0<m1<=10);
end
But both the times it gives array which contains all 1s. What wrong am I doing?
You can do something like this (also works for non integers)
k = sum(m1>0 & m1<=10)
You can use logical indexing. Observe:
>> x = randi(40, 1, 10) - 20
x =
-2 17 -12 -9 -14 -14 15 4 2 -14
>> x2 = x(0 < x & x < 10)
x2 =
4 2
>> length(x2)
ans =
2
and the same done in one step:
>> length(x(0 < x & x < 10))
ans =
2
to count the values in a specific range you can use ismember,
if m1 is vector use,
k = sum(ismember(m1,0:10));
If m1 is matrix use k = sum(sum(ismember(m1,0:10)));
for example,
m1=randi(20,[5 5])
9 10 6 10 16
8 9 14 20 6
16 13 14 7 11
16 15 4 12 14
4 16 3 5 18
sum(sum(ismember(m1,1:10)))
12
Why not simply do something like this?
% Random data
m1 = 100*rand(1000,1);
%Count elements between 10 and 20
m2 = m1(m1>10 & m1<=20);
length(m2) %number of elements of m1 between 10 and 20
You can then put things in a loop
% Random data
m1 = 100*rand(1000,1);
nb_elements = zeros(10,1);
for k=1:length(nb_elements)
temp = m1(m1>(10*k-10) & m1<=(10*k));
nb_elements(k) = length(temp);
end
Then nb_elements contains your data with nb_elements(1) for the 0-10 range, nb_elements(2) for the 10-20 range, etc...
Matlab does not know how to evaluate the combined logical expression
(0<m1(i)<=10)
Insted you should use:
for i=1:numel(m1)
if (0<m1(i)) && (m1(i)<=10)
k=k+1;
end
end
And to fasten it up probably something like this:
sum((0<m1) .* (m1<=10))
Or you can create logical arrays and then use element-wise multiplication. Don't know how fast this is though and it might use a lot of memory for large arrays.
Something like this
A(find((A>0.2 .* (A<0.8)) ==1))
Generate values
A= rand(5)
A =
0.414906 0.350930 0.057642 0.650775 0.525488
0.573207 0.763477 0.120935 0.041357 0.900946
0.333857 0.241653 0.421551 0.737704 0.162307
0.517501 0.491623 0.016663 0.016396 0.254099
0.158867 0.098630 0.198298 0.223716 0.136054
Find the intersection where the values > 0.8 and < 0.2. This will give you two logical arrays and the values where A>0.2 and A<0.8 will be =1 after element-wise multiplication.
find((A>0.2 .* (A<0.8)) ==1)
Then apply those indices to A
A(find((A>0.2 .* (A<0.8)) ==1))
ans =
0.41491
0.57321
0.33386
0.51750
0.35093
0.76348
0.24165
0.49162
0.42155
0.65077
0.73770
0.22372
0.52549
0.90095
0.25410

How to reshape vector into sqare matrix?

I have a vector of certain size and I want to reshape it into a square matrix. Here is an example: Let's say the vector is of size 784. Then I would create a matrix of size 28x28. In Matlab I would do it with the following command:
reshape(x,28,28)
Of course it can be possible that it is not possible to have an exact square matrix. In this case the matrix should as squarish as possible.
How can I do this calculation? That means how can I calculate the values a and b in reshape(x,a,b)?
Start with a equal to the square root of numel(x) rounded down. If that number doesn't divide numel(x), subtract 1 and try again. That way you end with a equal to the closest integer to sqrt(x) (from below) that divides numel(x). b would then be numel(x)/a, but you can simply use [] as the third argument to reshape:
a = floor(sqrt(numel(x)));
while mod(x,a)
a = a-1;
end
result = reshape(x,a,[]);
Example:
x = 1:20;
gives
result =
1 5 9 13 17
2 6 10 14 18
3 7 11 15 19
4 8 12 16 20
One possible approach:
x = rand(1, 784);
divisors = find(rem(numel(x), 1:numel(x)) == 0);
[~, idx] = min(abs(divisors - sqrt(numel(x))));
x = reshape(x, divisors(idx), numel(x) / divisors(idx));
Let me explain:
Suppose you have a vector named x:
x = rand(1, 784);
First, you find the divisors of the size of x:
divisors = find(rem(numel(x), 1:numel(x)) == 0);
Then, you proceed to choose the divisor which is closest to the square root of x's size:
[~, idx] = min(abs(divisors - sqrt(numel(x))));
Finally, you reshape x using that divisor (and the corresponding multiple):
x = reshape(x, divisors(idx), numel(x) / divisors(idx));
It is not a simple problem to find closest factors of an integer. You need to use the MATLAB answers to the question Input an integer, find the two closest integers which, when multiplied, equal the input. From that question if you use the answer that provides the function findIntegerFactorsCloseToSquarRoot, you can use the following code to reshape.
[a, b] = findIntegerFactorsCloseToSquarRoot(numel(x));
reshape(x, a, b);
I suggest you to first check whether the number is prime or not by isprime(784).
Then you can use prime_factors = factor(784) to get the integer factorization of the number. (Depending on the MATLAB version you may use ifactor(784))
The rest needs just a little more work on prime_factors.

Recurring Function with Matrix Input

I believe most functions in MATLAB should be able to receive matrix input and return the output in the form of matrix.
For example sqrt([1 4 9]) would return [1 2 3].
However, when I tried this recurring factorial function:
function k = fact(z)
if z ~= 0
k = z * fact(z-1);
else
k = 1;
end
end
It works perfectly when a number is input into fact. However, when a matrix is input into fact, it returns the matrix itself, without performing the factorial function.
E.g.
fact(3) returns 6
fact([1 2 3]) returns [1 2 3] instead of [1 2 6].
Any help is appreciated. Thank you very much!
Since MATLAB is not known to be good with recursive functions, how about a vectorized approach? Try this for a vector input -
mat1 = repmat([1:max(z)],[numel(z) 1])
mat1(bsxfun(#gt,1:max(z),z'))=1
output1 = prod(mat1,2)
Sample run -
z =
1 2 7
output1 =
1
2
5040
For the sake of answering your original question, here's the annoying loopy code for a vector or 2D matrix as input -
function k1 = fact1(z1)
k1 = zeros(size(z1));
for ii = 1:size(z1,1)
for jj = 1:size(z1,2)
z = z1(ii,jj);
if z ~= 0
k1(ii,jj) = z .* fact1(z-1);
else
k1(ii,jj) = 1;
end
end
end
return
Sample run -
>> fact1([1 2 7;3 2 1])
ans =
1 2 5040
6 2 1
You can use the gamma function to compute the factorial without recursion:
function k = fact(z)
k = gamma(z+1);
Example:
>> fact([1 2 3 4])
ans =
1 2 6 24
Not sure if all of you know, but there is an actual factorial function defined in MATLAB that can take in arrays / matrices of any size, and computes the factorial element-wise. For example:
k = factorial([1 2 3 4; 5 6 7 8])
k =
1 2 6 24
120 720 5040 40320
Even though this post is looking for a recursive implementation, and Divakar has provided a solution, I'd still like to put my two cents in and suggest an alternative. Also, let's say that we don't have access to factorial, and we want to compute this from first principles. What I would personally do is create a cell array that's the same size as the input matrix, but each element in this cell array would be a linear index array from 1 up to the number defined for each location in the original matrix. You would then apply prod to each cell element to compute the factorial. A precondition is that no number is less than 1, and that all elements are integers. As such:
z1 = ... ; %// Define input matrix here
z1_matr = arrayfun(#(x) 1:x, z1, 'uni', 0);
out = cellfun(#prod, z1_matr);
If z1 = [1 2 3 4; 5 6 7 8];, from my previous example, we get the same output with the above code:
out =
1 2 6 24
120 720 5040 40320
This will obviously be slower as there is an arrayfun then cellfun call immediately after, but I figured I'd add another method for the sake of just adding in another method :) Not sure how constructive this is, but I figured I'd add my own method and join Divakar and Luis Mendo :)

vectorized array creation from a list of start/end indices

I have a two-column matrix M that contains the start/end indices of a bunch of intervals:
startInd EndInd
1 3
6 10
12 12
15 16
How can I generate a vector of all the interval indices:
v = [1 2 3 6 7 8 9 10 12 15 16];
I'm doing the above using loops, but I'm wondering if there's a more elegant vectorized solution?
v = [];
for i=1:size(M,1)
v = [v M(i,1):M(i,2)];
end
Here's a vectorized solution I like to use for this particular problem, using the function cumsum:
v = zeros(1, max(endInd)+1); % An array of zeroes
v(startInd) = 1; % Place 1 at the starts of the intervals
v(endInd+1) = v(endInd+1)-1; % Add -1 one index after the ends of the intervals
v = find(cumsum(v)); % Perform a cumulative sum and find the nonzero entries
cell2mat(arrayfun(#colon,M(:,1)',M(:,2)','UniformOutput',false))
I don't have IMFILL, but on my machine this method is faster than the other suggestions and I think would beat the IMFILL method due to the use of find.
It can be made even faster if M is set up transposed (and we adjust the third and fourth arguments of arrayfun).
There's probably an even better solution I'm somehow not seeing, but here's a version using IMFILL
startInd = [1,6,12,15];
endInd = [3,10,12,16];
%# create a logical vector with starts and ends set to true to prepare for imfill
tf = false(endInd(end),1);
tf([startInd,endInd]) = true;
%# fill at startInd+1 wherever startInd is not equal endInd
tf = imfill(tf,startInd(startInd~=endInd)'+1); %' SO formatting
%# use find to get the indices
v = find(tf)' %' SO formatting
v =
1 2 3 6 7 8 9 10 12 15 16
Very weird solution IMHO creating temporary strings and using EVAL. Can be also one-liner.
tmp = cellstr(strcat(num2str(M(:,1)),{':'},num2str(M(:,2)),{' '}));
v = eval(['[' cell2mat(tmp') ']']);
I know it will probably not work on large matrix. Just for fun.