matlab the index of the next smallest element in a matrix - matlab

I could get the minimum value and its index like in here matlab how to get min value and its index in a matrix.
From a matrix A
A=[1 3 6 2 0 4
6 8 9 5 1 3
7 2 7 8 9 2]
To get the minimal value MinVal(where the row is given (r) and the column is in an interval ([c.. c+x]) and the index ind (number of column of it)). I have to do
[MinVal,I]=min(A(r,c:c+x))
ind= c-1+I;
Example
[MinVal, ind]=min(A(2,3:3+2))
will give me
% MinVal= 1
% ind =5
Then I have
B.state=[ 0
0
1
0
1]
So here I can't take ind=5 because B(5).state==1, I need to move to the next MinVal= 5 and ind = 4. Here, it is ok, I can stop but if B(4).state ==1, then I need to move the next smallest and so on
But then the problem is that I have another structure B where I am going to check if B(ind).state== 1 then I have to move to the next smallest element and get its index and so on until I find the first empty one.
If I try like this
MinD = A(r,c:c+x);
[MinVal,Ind]=min(MinD);
ind= nbrT+Ind;
MinD2 = sort(MinD(:));
p=2;
while (B(ind).state == 1)
MinVal= MinD2(p);
%need to get the new index
%something like this
ind=find (A == MinVal) ;
p=p+1;
end
The problem is that I can get the next minimum value but the index I will get can be of more than one value if MinVal appears more than once so how can I get the one with state == 0
I don't want to use unique either because even if I have two different elements with the same minimum, they refer to two different places and I have to keep both (I can use the second one if the first one is full).
Modified code to
MinD = A(r,c:c+x);
[MinVal,Ind]=min(MinD);
ind= nbrT+Ind;
[MinD2, IndMinD2] = sort(MinD(:));
p=2;
while (B(ind).state == 1)
MinVal=MinD2(p);
Ind=IndMind2(p);
p=p+1;
end
Ind= c-1+Ind;
So how can I do it?

I think this should work:
MinD2 = MinD(:));
for ii=1:numel(MinD2)
[MinVal,Ind]=min(MinD2);
%do you stuff with the index
%and at the end do this:
MinD2(Ind)=Inf;
end

Related

Build the matrix of all the combinations of given numbers using recursion [matlab]

Let say we have the vector v=[1,2,3] and we want to build the matrix of all the combinations of the numbers contained in v, i.e.
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
Since I'm not good in recursion, firstly I tried to write the code to build such a matrix by using for loops
makeLoop([1,2,3])
function A = makeLoop(v)
loops=length(v);
for i = 1:loops
dummy=v;
m=factorial(loops)/loops;
A((1+m*(i-1)):m*i,1)=v(i);
v(i)=[];
loops2=length(v);
for j = 1:loops2
dummy2=v;
m2=factorial(loops2)/loops2;
A(((1+m2*(j-1))+m*(i-1)):(m2*j+m*(i-1)),2)=v(j);
v(j)=[];
loops3=length(v);
for k = 1:loops3
m3=factorial(loops3)/loops3;
A(((1+m2*(j-1))+m*(i-1)):(m2*j+m*(i-1)),3)=v(k);
end
v=dummy2;
end
v=dummy;
end
end
it seems like it work, but obviously write it all for a bigger v would be like hell. Anyway I don't understand how to properly write the recursion, I think the recursive structure will be something like this
function A = makeLoop(v)
if length(v)==1
"do the last for loop"
else
"do a regular loop and call makeLoop(v) (v shrink at each loop)"
end
but I don't get which parts should I remove from the original code, and which to keep.
You were very close! The overall structure that you proposed is sound and your loopy-code can be inserted into it with practically no changes:
function A = makeLoop(v)
% number of (remaining) elements in the vector
loops = length(v);
if loops==1 %"do the last for loop"
A = v; %Obviously, if you input only a single number, the output has to be that number
else %"do a regular loop and call makeLoop(v) (v shrink at each loop)"
%preallocate matrix to store results
A = zeros(factorial(loops),loops);
%number of results per vector element
m = factorial(loops)/loops;
for i = 1:loops
%For each element of the vector, call the function again with that element missing.
dummy = v;
dummy(i) = [];
AOut = makeLoop(dummy);
%Then add that element back to the beginning of the output and store it.
A((1+m*(i-1)):m*i,:) = [bsxfun(#times,v(i),ones(m,1)) AOut];
end
end
Explanation bsxfun() line:
First, read the bsxfun documentation, it explains how it works way better than I could. But long story short, with bsxfun() we can replicate a scalar easily by multiplying it with a column vector of ones. E.g. bsxfun(#times,5,[1;1;1]) will result in the vector [5;5;5]. Note that since Matlab 2016b, bsxfun(#times,5,[1;1;1]) can written shorter as 5.*[1;1;1]
To the task at hand, we want to add v(i) in front (as the first column) of all permutations that may occur after it. Therefore we need to replicate the v(i) into the 1. dimension to match the number of rows of AOut, which is done with bsxfun(#times,v(i),ones(m,1)). Then we just horizontally concatenate this with AOut.
You can simply use the perms function to achieve this:
v = [1 2 3];
perms(v)
ans =
3 2 1
3 1 2
2 3 1
2 1 3
1 3 2
1 2 3
If you want them sorted using the same criterion you applied in the desired output, use the following code (refer to this page for an official documentation of the sortrows functon):
v = [1 2 3];
p = perms(v);
p = sortrows(p)
p =
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

What does it mean to use logical indexing/masking to extract data from a matrix? (MATLAB)

I am new to matlab and I was wondering what it meant to use logical indexing/masking to extract data from a matrix.
I am trying to write a function that accepts a matrix and a user-inputted value to compute and display the total number of values in column 2 of the matrix that match with the user input.
The function itself should have no return value and will be called on later in another loop.
But besides all that hubbub, someone suggested that I use logical indexing/masking in this situation but never told me exactly what it was or how I could use it in my particular situation.
EDIT: since you updated the question, I am updating this answer a little.
Logical indexing is explained really well in this and this. In general, I doubt, if I can do a better job, given available time. However, I would try to connect your problem and logical indexing.
Lets declare an array A which has 2 columns. First column is index (as 1,2,3,...) and second column is its corresponding value, a random number.
A(:,1)=1:10;
A(:,2)=randi(5,[10 1]); //declares a 10x1 array and puts it into second column of A
userInputtedValue=3; //self-explanatory
You want to check what values in second column of A are equal to 3. Imagine as if you are making a query and MATLAB is giving you binary response, YES (1) or NO (0).
q=A(:,2)==3 //the query, what values in second column of A equal 3?
Now, for the indices where answer is YES, you want to extract the numbers in the first column of A. Then do some processing.
values=A(q,2); //only those elements will be extracted: 1. which lie in the
//second column of A AND where q takes value 1.
Now, if you want to count total number of values, just do:
numValues=length(values);
I hope now logical indexing is clear to you. However, do read the Mathworks posts which I have mentioned earlier.
I over simplified the code, and wrote more code than required in order to explain things. It can be achieved in a single-liner:
sum(mat(:,2)==userInputtedValue)
I'll give you an example that may illustrate what logical indexing is about:
array = [1 2 3 0 4 2];
array > 2
ans: [0 0 1 0 1 0]
using logical indexing you could filter elements that fullfil a certain condition
array(array>2) will give: [3 4]
you could also perform alterations to only those elements:
array(array>2) = 100;
array(array<=2) = 0;
will result in "array" equal to
[0 0 100 0 100 0]
Logical indexing means to have a logical / Boolean matrix that is the same size as the matrix that you are considering. You would use this as input into the matrix you're considering, and any locations that are true would be part of the output. Any locations that are false are not part of the output. To perform logical indexing, you would need to use logical / Boolean operators or conditions to facilitate the selection of elements in your matrix.
Let's concentrate on vectors as it's the easiest to deal with. Let's say we had the following vector:
>> A = 1:9
A =
1 2 3 4 5 6 7 8 9
Let's say I wanted to retrieve all values that are 5 or more. The logical condition for this would be A >= 5. We want to retrieve all values in A that are greater than or equal to 5. Therefore, if we did A >= 5, we get a logical vector which tells us which values in A satisfy the above condition:
>> A >= 5
ans =
0 0 0 0 1 1 1 1 1
This certainly tells us where in A the condition is satisfied. The last step would be to use this as input into A:
>> B = A(A >= 5)
B =
5 6 7 8 9
Cool! As you can see, there isn't a need for a for loop to help us select out elements that satisfy a condition. Let's go a step further. What if I want to find all even values of A? This would mean that if we divide by 2, the remainder would be zero, or mod(A,2) == 0. Let's extract out those elements:
>> C = A(mod(A,2) == 0)
C =
2 4 6 8
Nice! So let's go back to your question. Given your matrix A, let's extract out column 2.
>> col = A(:,2)
Now, we want to check to see if any of column #2 is equal to a certain value. Well we can generate a logical indexing array for that. Let's try with the value of 3:
>> ind = col == 3;
Now you'll have a logical vector that tells you which locations are equal to 3. If you want to determine how many are equal to 3, you just have to sum up the values:
>> s = sum(ind);
That's it! s contains how many values were equal to 3. Now, if you wanted to write a function that only displayed how many values were equal to some user defined input and displayed this event, you can do something like this:
function checkVal(A, val)
disp(sum(A(:,2) == val));
end
Quite simply, we extract the second column of A and see how many values are equal to val. This produces a logical array, and we simply sum up how many 1s there are. This would give you the total number of elements that are equal to val.
Troy Haskin pointed you to a very nice link that talks about logical indexing in more detail: http://www.mathworks.com/help/matlab/math/matrix-indexing.html?refresh=true#bq7eg38. Read that for more details on how to master logical indexing.
Good luck!
%% M is your Matrix
M = randi(10,4)
%% Val is the value that you are seeking to find
Val = 6
%% Col is the value of the matrix column that you wish to find it in
Col = 2
%% r is a vector that has zeros in all positions except when the Matrix value equals the user input it equals 1
r = M(:,Col)==Val
%% We can now sum all the non-zero values in r to get the number of matches
n = sum(r)
M =
4 2 2 5
3 6 7 1
4 4 1 6
5 8 7 8
Val =
6
Col =
2
r =
0
1
0
0
n =
1

Changing the elements of a matrix using a for loop in matlab

I'm having a few issues getting MATLAB to do what I want.
say I have a matrix x = [1 2 3 4; 1 4 4 5; 6 4 1 4]
I'm trying to write code that will go through the matrix and change each 4 to a 5, so it modifies the input matrix
I've tried a few things:
while index <= numel(x)
if index == 4
index = 5;
end
index = index + 1;
end
for item = x
if item == 4
item = 5;
end
end
the simplest thing i tried was
for item = x
if item == 4
item = 5;
end
end
i noticed by looking at the workspace that the value of item did indeed change but the value of x (the matrix) stayed the same.
How do I get the output that i'm looking for?
If you just want to change all the 4s to 5s then:
x(x==4)=5
basically x==4 will result in a logical matrix with 1s everywhere there was a 4 in x:
[0 0 0 1
0 1 1 0
0 1 0 1]
We then use logical index to only affect the values of x where those 1s are and change them all to 5s.
If you wanted to do this using a loop (which I highly recommend against) then you can do this:
for index = 1:numel(x)
if x(index) == 4
x(index) = 5;
end
end
Short answer to achieve what you want:
x(x==4) = 5
Answer to why your code doesn't do what you expected:
You are changing the item to a 5. But that item is a new variable, it does not point to the same item in your matrix x. Hence the original matrix x remains unchanged.

comparing multiple columns of matrix together

I have a 50x50 matrix named nghlist(i,j) containing 0 and 1 values. 1 means there is a relation between (i,j).
There is another 5x50 matrix named chlist.
I need to check the nghlist matrix and if there is any connection between i and j (nghlist(i,j)==1) then I need to go to the chlist matrix and compare the values on column i and column j. For example compare columns (1,3,8,21,52) and get how many similar values they share together. i.e. I find all those columns have 3 similar values.
I tried using following code. But the problem is I need to compare the unknown number of columns (depend on the node connection (nghlist) for example 4 or 5 columns) together.
for i=1:1:n
for j=1:1:n
if (i~=j & nghlist(i,j)==1)
sum(ismember(chlist(:,i),chlist(:,j)));
end
end
end
Any help is highly appreciated.
++++ simplified example ++++++
take a look at the example http://i.imgur.com/mQjDqzz.jpg
nghlist matrix:
1 1 1 0 0
1 1 1 0 0
1 1 1 1 1
0 0 1 1 1
0 0 1 1 1
chlist matrix:
3 1 4 5 4
4 3 5 6 5
5 4 6 7 6
In this example since node 1 is connected to nodes 2 and 3, I need to compare column 1,2 and 3 from chlist. The output would be 1 (because they only share value '4').
And this value for node 5 would be 2 (because columns 3,4 and 5 only share value '5' and '6'). I hope now it is clear.
If the result of your simplified example is [1,2,0,3,2] then the following code worked for me.
(Matrix a stands for nghlist and matrix b for chlist, result is stored in s )
for i = 1:size(a,1)
s(i)=0;
row = a(i,:);
idx = find(row==1);
idx = idx(idx~=i);
tempb = b(:,idx);
for j=1:size(tempb,1)
if sum(sum(tempb==tempb(j,1)))==size(tempb,2)
s(i)=s(i)+1;
end
end
end
For every node you find all the ones in its row, then discard the one referring to the node itself. Pick the appropriate columns of chlist (line 6) and create a new matrix. For every element of the 1st column of this matrix check if it exists in all other columns.If it does, update the s value
Let's say, the indices of the columns that are to be compared is called idxList:
idxList = [1,3,8,21,50];
You may compare all with the first one and use "AND" to find the minimum number of shared values:
shared = ones(size(chlist(:,i)))
for ii = 2:length(idxList)
shared = (shared == (chlist(:,idxList(1)) == chlist(:,idxList(ii))))
end
Finally, sum as before
sum(shared)
I haven't checked the exact code, but the concept should become clear.
I manage to solve it this way. I compare the first and second column of tempb and put the result in tem. then compare tem with third column of tempb and so on. Anyway thank you finmor and also pyStarter, your codes has inspired me. However I knew its not the best way, but at least it works.
for i=1:size(nghlist,1)
s(i)=0;
j=2;
row=nghlist(i,:);
idx=find(row==1);
tempb=chlist(:,idx);
if (size(tempb,2)>1)
tem=intersect(tempb(:,1),tempb(:,2));
if (size(tempb,2)<=2)
s(i)=size(tem,1);
end
while (size(tempb,2)>j & size(tem)~=0)
j=j+1;
tem= intersect(tem(:,1),tempb(:,j));
s(i)=size(tem,1);
end
end
end

addition of one column with certain condition in another colum, like sumifs of excel in matlab [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
addition of one column with certain condition in another colum, like sumifs of excel
here i want to count the no of 2nd column, with the same conditions in column 1,
i m dictating here again,
A=[1 2;2 3;3 4;3 2;4 3;5 4;5 2;6 3;7 2;8 3]
now i want to count no of 2, 3 and 4 in column2, condition is that when column 1 ranges from 0 to 3, 3 to 6, 6 to 9, 9 to 12 like that.
answer is like that
ranges no2, no3, no4
0 to 3-- 2-----1-------1
3 to 6---1------2-------1
6 to 9-- --1-----1------0
help me,,,, waiting for your reply..
With MATLAB you can use logical indexing meaning that you can filter a variable with any number of conditions. For example, if vec is any vector and you wish to know how many elements of vec are negative you can do the following,
% save the elements of vec which are negative
ind = vec < 0
% vec is a logical variable. Each element of vec lower that 0 is store as 1.
% to know how many elements of vec are smaller than 0
sum(ind)
% will tell you how many ones are there in ind, meaning the number of elements in vec which
% are smaller than 0
% Of course you can do the same all at once,
sum(vec < 0)
% and you can directly access the elements in the same way
vec(vec < 0)
So returning to your problem, you can use something like,
for i = 1:3:length(A)
%print how many 2s,3s and 4s
fprintf('%d to %d: %d, %d, %d\n',i,i+2,sum(A(i:i+2,2)==2),sum(A(i:i+2,2)==3),sum(A(i:i+2,2)==4))
end
You could potentially do something like this:
for(n=1:size(A,1))
if(A(n,1) >= 0 && A(n,1) < 3)
% Do something
elseif( ) % next test condition
% Do something there.
end
end
Another option would be to use the for loop to go through your first column and using a switch statement to pull the appropriate action based on that input.
Update below:
for(n = 1:size(A,1))
switch(mod(A(n,1),3))
case 0 % this will be 0, 1, 2 in your column
% code
case 1
etc...
end
end
Info on modulus in matlab
Info on switch in matlab