How to count the number of iterations - matlab

I'm working with k-means on MATLAB. To process the valid cluster, it needs to do a looping until the cluster position doesn't change any more. The looping will show the iterations process.
I want to count how many looping/iteration happens on that clustering process. Here is the snippet of looping/iteration processing part:
while 1,
d=DistMatrix3(data,c); %// calculate the distance
[z,g]=min(d,[],2); %// set the matrix g group
if g==temp, %// if the iteration does not change anymore
break; %// stop the iteration
else
temp=g; %// copy the matrix to the temporary variable
end
for i=1:k
f=find(g==i);
if f %// calculate the new centroid
c(i,:)=mean(data(find(g==i),:),1);
end
end
end
All I know that I have to do is define the iteration variable, and then write the calculation part. But, where do I have to define the variable? And how?
All the answers will be so much appreciated.
Thank you.

A Matlab while-loop is executed until the expression is false. The general setup is like this:
while <expression>
<statement>
end
If you want to count the number of times the while loop was entered, the easiest way is to declare a variable outside the loop and incrementing it inside:
LoopCounter = 0;
while <expression>
<statement>
LoopCounter = LoopCounter + 1;
end
The question whether to increment the LoopCounter before or after the <statement> depends on whether you need it to access vector entries. In that case, it should be incremented before the <statement> because 0 is not a valid index in Matlab.

Define before your loop, update in your loop.
iterations=0;
while 1,
d=DistMatrix3(data,c); % calculate the distance
[z,g]=min(d,[],2); % set the matrix g group
if g==temp, % if the iteration doesn't change anymore
break; % stop the iteration
else
temp=g; % copy the matrix to the temporary variable
end
for i=1:k
f=find(g==i);
if f % calculate the new centroid
c(i,:)=mean(data(find(g==i),:),1);
end
end
iterations=iterations+1;
end
fprintf('Did %d iterations.\n',iterations);

Related

How do I adjust this code so that I can enter how many runs I want and it will store each run in a matrix?

I have created this code to generate a 1 set of lottery numbers, but I am trying to make it so that the user can enter how many sets they want (input n), and it will print out as one long matrix of size nX6? I was messing around with a few options from online suggestions, but to no avail. I put the initial for i=1:1:n at the beginning, but I do not know how to store each run into a growing matrix. Right now it still generates just 1 set.
function lottery(n)
for i=1:1:n
xlow=1;
xhigh=69;
m=5;
i=1;
while (i<=m)
lottonum(i)=floor(xlow+rand*(xhigh-xlow+1));
flag=0;
for j=1:i-1
if (lottonum(i)==lottonum(j))
flag=1;
end
end
if flag==0
i=i+1;
end
end
ylow=1;
yhigh=26;
m=1;
lottonum1=floor(ylow+rand*(yhigh-ylow+1));
z = horzcat(lottonum, lottonum1);
end
disp('The lotto numbers picked are')
fprintf('%g ',z)
disp (' ')
The problem is that you are not storing or displaying the newly generated numbers, only the last set. To solve this, initialize z with NaNs or zeros, and later index z to store each set in a row of z, by using z(i,:) = lottonum.
However, you are using i as iterator in the while loop already, so you should use another variable, e.g. k.
You can also set z as an output of the function, so you can use this matrix in some other part of a program.
function z = lottery(n)
% init z
z = NaN(n,6);
for k = 1:n
xlow=1;
xhigh=69;
m=5;
i=1;
while (i<=m)
lottonum(i)=floor(xlow+rand*(xhigh-xlow+1));
flag=0;
for j=1:i-1
if (lottonum(i)==lottonum(j))
flag=1;
end
end
if flag==0
i=i+1;
end
end
ylow=1;
yhigh=26;
lottonum1 = floor(ylow+rand*(yhigh-ylow+1));
z(k,:) = horzcat(lottonum, lottonum1); % put the numbers in a row of z
end
disp('The lotto numbers picked are')
disp(z) % prettier display than fprintf in this case.
disp (' ')
end
The nice answer from rinkert corrected your basic mistakes (like trying to modify your loop iterator i from within the loop => does not work), and answered your question on how to store all your results.
This left you with a working code, however, I'd like to propose to you a different way to look at it.
The porposed architecture is to divide the tasks into separate functions:
One function draw_numbers which can draw N numbers randomly (and does only that)
One function draw_lottery which call the previous function as many times as it needs (your n), collect the results and display them.
draw_lottery
This architecture has the benefit to greatly simplify your main function. It can now be as simple as:
function Draws = draw_lottery(n)
% define your draw parameters
xmin = 1 ; % minimum number drawn
xmax = 69 ; % maximum number drawn
nballs = 5 ; % number of number to draw
% pre allocate results
Draws = zeros( n , nballs) ;
for iDraw=1:1:n
% draw "nballs" numbers
thisDraw = draw_numbers(xmin,xmax,nballs) ;
% add them to the result matrix
Draws(iDraw,:) = thisDraw ;
end
disp('The lotto numbers picked are:')
disp (Draws)
disp (' ')
end
draw_numbers
Instead of using a intricated set of if conditions and several iterators (i/m/k) to branch the program flow, I made the function recursive. It means the function may have to call itself a number of time until a condition is satisfied. In our case the condition is to have a set of nballs unique numbers.
The function:
(1) draws N integer numbers randomly, using randi.
(2) remove duplicate numbers (if any). Using unique.
(3) count how many unique numbers are left Nu
(4a) if Nu = N => exit function
(4b) if Nu < N => Call itself again, sending the existing Nu numbers and asking to draw an additional N-Nu numbers to add to the collection. Then back to step (2).
in code, it looks like that:
function draw = draw_numbers(xmin,xmax,nballs,drawn_set)
% check if we received a partial set
if nargin == 4
% if yes, adjust the number of balls to draw
n2draw = nballs - numel(drawn_set) ;
else
% if not, make a full draw
drawn_set = [] ;
n2draw = nballs ;
end
% draw "nballs" numbers between "xmin" and "xmax"
% and concatenate these new numbers with the partial set
d = [drawn_set , randi([xmin xmax],1,n2draw)] ;
% Remove duplicate
drawn_set = unique(d) ;
% check if we have some more balls to draw
if numel(drawn_set) < nballs
% draw some more balls
draw = draw_numbers(xmin,xmax,nballs,drawn_set) ;
else
% we're good to go, assign output and exit funtion
draw = drawn_set ;
end
end
You can have both functions into the same file if you want.
I encourage you to look at the documentation of a couple of Matlab built-in functions used:
randi
unique

Matlab. I got some errors

l_0=1.5;
l_1=1.6;
Lambda_min=2*(1+1)*l_0;
Lambda_max=2*(1+1)*l_1;
n_0=linspace(2,2.11,10);
n_1=linspace(2.30,2.50,10);
for i=1:10
for j=1:10
for k=1:10
l(i) = Lambda_min * ( Lambda_max/Lambda_min)^(i/10)
sum=sum(l)
d_0(:,j)= l(i)/((n_0(i)/n_1(i)+1))
d_1(:,k)= (n_0(i)/n_1(i))*d_0(:,j)
end
end
end
First of all; I want to find values of l(i) which is a vector, then take the sum of that vector. second, for d_0(:,j) I want to create a matrix so I can plot it later, that takes different values from l(i),n_0,n_1 each time. If I take the values for n_0 and n_1 and put in the for loop I will get index error because it should be logic or integer number.
My matrix is overwritten and do not know how to avoid it. Note, I want in d_0 and d_1 n_0 and n_1 to take values from linspace. for example in the first iteration n_0= 2 n_1= 2.30 then second iteration take the next value in linspace.
I tried to see the value of n_0(i) and does it give me 10 iterations. It gives me more that that overwritten.
Try:
l_0=1.5;
l_1=1.6;
Lambda_min = 4*l_0;
Lambda_max = 4*l_1;
n_0 = linspace(2,2.11,10) % don't add semicolon so you can check this is giving 10 values
n_1 = linspace(2.30,2.50,10) %
for i=1:10
l(i) = Lambda_min * ( Lambda_max/Lambda_min)^(i/10) % should give you 10 values
end
d_0= l./((n_0./n_1+1)); % This will only give you a vector, not a matrix.
d_1= (n_0./n_1).*d_0;
Lsum = sum(l); % should give you one value

Matlab Iteratively remove a row of matrix, except for first iteration

I have a matrix that I use to solve a system of equation using ode45. I am iteratively removing one row in a while loop. However, I want the first iteration to 'continue' and not remove any arrow, so that I can compare all my results where one array is removed with the result using initial matrix.
It would look like:
while smtg
A(pos,:)=0 % Do not compute this line the first iteration
pop=ode45(involving A)
end
My real code:
countrow=0;
A=randi([0 1], 5, 5);
distrib=sum(A,1);
while sum(distrib)>5
countrow=countrow+1;
A(pos,:)=0; % remove one row
options = odeset('RelTol', 1e-4);
[t, pop]=ode45(#Diff,[0 MaxTime],[E I],options,n,m, A);
nbtot =sum(pop(:,n+1:2*n),2);
end
I tried to use
if countrow==1 % (the first iteration),
continue;
end
but it skips until the second end and not compute nbtot so I'm out of ideas... Any help?
If you don't want A(pos,:)=0; % remove one row to occur on the first iteration then put it inside an if statement like
countrow = countrow + 1;
if countrow ~= 1
A(pos,:)=0; % remove one row
end
The ~= symbol in MATLAB is "not equal to". The line A(pos,:)=0; % remove one row will now only execute when countrow is not equal to 1 but all of the other statements within the loop will execute as normal.
The keyword continue will stop the execution of the current loop iteration and proceed to the next loop iteration. All of the statements after a continue within a loop will not be executed.
Or you can go with :
A(pos,:)=A(pos,:)*(countrow==1);

How to check a matrix is/isn't in an array (Matlab)

I have an array (M) of matrices. I perform an operation on the matrix in the ith position, and it adds three more matrices to my array in the (3i-1), (3i) and (3i+1)th positions. I want to continue this process until I reach the jth position in the array, where j is such that all matrices in the (j+1)th position and onwards have appeared already somewhere between positions 1 and j (inclusive).
EDIT: I've been asked to clarify what I mean. I am unable to write code that makes my algorithm terminate when I want it to as explained above. If I knew a proper way of searching through an array of matrices to check if a given matrix is contained, then I could do it. I tried the following:
done = 0;
ii = 1
while done ~= 1
%operation on matrix in ith position omitted, but this is where it goes
for jj = ii+1:numel(M)
for kk = 1:ii
if M{jj} == M{kk};
done = done + 1/(numel(M) - ii);
break
end
end
end
if done ~= 1
done = 0;
end
ii = ii + 1
end
The problem I have with this (as I'm sure you can see) is that if the process goes on for too long, rounding errors stop ever allowing done = 1, and the algorithm doesn't terminate. I tried getting round this by introducing thresholds, something like
while abs(done - 1) > thresh
and
if abs(done - 1) > thresh
done = 0;
end
This makes the algorithm work more often, but I don't have a 'one size fits all' threshold that I could use (the process could continue for arbitrarily many steps), so it still ends up breaking.
What can I do to fix this?
Thanks
Why don't you initialize done at 0, keep your while done==0 loop, and instead of computing done as a sum of elements, check if your condition (finding if the matrix already exists) is verified for all jj, something like this:
alldone=zeros(numel(M)-ii,1);
for jj = ii+1:numel(M)
for kk = 1:ii
if isequal(M{jj},M{kk})
alldone(jj-ii) = 1
break
end
end
end
done=prod(alldone);
There is probably a more elegant way to code this, though.
For instance, you could add early termination:
while done==0
done=1;
for jj = ii+1:numel(M)
match_success=0;
for kk = 1:ii
if isequal(M{jj},M{kk})
match_success=1;
break
end
end
if match_success==0
done=0;
break;
end
end
end
At the beginning of each loop, the algorithm assumes it is going to succeed and stop there (hence the done=1). Then for each jj, we create a match_success which will be set to 1 only if a match is found for M{jj}. If the match is found, we break and go to the next j. If no match if found for j, match_success is left to 0, done is initialized to 0 and the while loop continues. I haven't checked it, but I think it should work.
This is just a simple tweak, but again, more thought can probably speed up this whole code a lot.

Mark values from loop for each iteration

I want to mark each value that comes out of my loop with a value.
Say I have a variable number of values that come out of each iteration. I want those values to be labeled by which iteration they came out of.
like
1-1,
2-1,
3-1,
1-2,
2-2,
3-2,
4-2,
etc.
where the first number is the value from the loop and the second is counting which iteration it came from.
I feel like there is a way I just cant find it.
ok so here is some code.
for c=1:1:npoints;
for i=1:1:NN;
if ((c-1)*spacepoints)<=PL(i+1) && ((c-1)*spacepoints)>=PL(i);
local(c)=((c)*spacepoints)-PL(i);
end
if ((c-1)*spacepoints)>=PL(NN);
local(c)=((c)*spacepoints)-PL(NN);
element(i)=NN;
end
end
I want to mark each local value with the iteration it came from for the i:NN. PL is a vector and the output is a set of vectors for each iteration.
For this sort of quick problem I like to create a cell array:
for k = 1:12
results{k} = complicated_function(...);
end
If the output is really complicated, then I return a struct with fields relating to the outputs:
for k = 1:12
results{k}.file = get_filename(...);
results{k}.result = ...;
end
Currently as it is right now, in your inner 1:NN loop, your local(c) variable is being updated or overwritten. You never apply the previous value of local, so it is not some iterative optimization algorithm(?)...
Perhaps an easy solution is to change the size/type of local from a vector to a matrix. Let's say that local is of size [npoints 1]. Instead you make it of size [npoints NN]. It is now a 2d-array (a matrix of npoints rows and NN columns). use the second dimension to store each (assumed column) vector from the inner loop:
local = zeros([npoints NN]);
%# ... code in bewteen ...
for c=1:1:npoints;
for i=1:1:NN;
if ((c-1)*spacepoints)<=PL(i+1) && ((c-1)*spacepoints)>=PL(i);
local(c, i)=((c)*spacepoints)-PL(i);
end
if ((c-1)*spacepoints)>=PL(NN);
local(c, i)=((c)*spacepoints)-PL(NN);
element(i)=NN;
end
end
end
The c'th row of your local matrix will then corresponds to the NN values from the inner loop. Please note that I have assumed your vector to be a column vector - if not, just change the order of the sizes.