%=============================================
% Cluster Restarted - Differential Migration
% Implementation for BBOB framework
% Copyright (C) 2017 Ing. Marek Dlapa, Ph.D.
%=============================================

echo off;
warning off;

global noaa;
global lowfe;
global maxfunevals;
global dim;

JR =[0 2];   % jump range
PRT = 0.15;  % perturbation constant
AE = 0;      % accepted error
CD = 0.7;    % cluster distance
CL = 3;      % cluster latency
CM = 4;      % maximum number of clusters for restart
LR = 40;     % minimum number of loops before restart

MNE = eval(maxfunevals);   % maximum number of cost function evaluations
NP = MNE / (4000 * n );    % size of population for dimension n

lowfe = 0;

% PopList for the population in the space [-5,5]^DIM

PopList = [-5 5 1];
for i=2:DIM
    PopList(i,:) = [-5 5 1];
end 

SizePL = size(PopList);
n = SizePL(1,1);
SS = MNE / ( NP - 1 );
%SS = 1;

newpop; % generate new population of individuals

calccv;

NE = fgeneric('evaluations');

mincv = min(cv);
ftarget1 = fgeneric('ftarget');
Err = mincv - ftarget1;
%fprintf('Minimum at %f    Error at %f\n',mincv,Err);
%fprintf('Self organization began\n');
%clock
store = 0;
loop = 0;
NofC = 1;
CH = [];
CHI = 1;
NE1 = fgeneric('evaluations');
while (mincv > ftarget1)
   noaa = 0;
   loop = loop + 1;
   if loop == SS
      fprintf('Loop %d\nSearching clusters...\n',NE);
   end;
   %%%%%%%%%%%%%%%%%%
   % Cluster search %
   %%%%%%%%%%%%%%%%%%
   NofC = 1;
   ps(1) = 1;
   for i = 1 : NP
      IsFar = 1;
      j = 1;
      for j = 1 : NofC
         x = Population(ps(j),:)-Population(i,:);
         for k=1:n
            x(k) = x(k) / (PopList(k,2)-PopList(k,1));
         end
         Dst = sqrt(x*x');
         if Dst < CD
            if cv(i) < cv(ps(j))
               ps(j) = i;
            end
            IsFar = 0;
         end
      end
      if IsFar == 1
         NofC = NofC + 1;
         ps(NofC) = i;
      end
   end
   if NE - NE1 + ( NP - 1 ) * NofC >= MNE
       break;
   end
   if loop==SS
       fprintf('...%d cluster found. Calculating jumps...\n',NofC);
   end;
   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   % Migration to the cluster centres %
   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   for i = 1 : NP
      mincv = cv(i);
      minpop = Population(i,:);
      for j = 1 : NofC
         if ps(j) ~= i
            direct = Population(ps(j),:)-Population(i,:);
            for k = 1 : n
               if rand >= PRT
                  direct(k) = 0;
               end
            end
            k = JR(1) + rand * (JR(2) - JR(1));
            pop = Population(i,:) + direct * k;
            for l = 1:n
               pop(l) = CheckType(pop(l),PopList(l,:));
            end
            tcv = FitFnc(pop');
            if tcv < mincv
               mincv = tcv;
               minpop = pop;
            end
         end
      end
      NewP(i,:) = minpop;
      Newcv(i) = mincv;
   end
   minpop;
   Population = NewP;
   cv = Newcv;
   mincv = min(cv); maxcv = max(cv);
   Err = mincv - ftarget1;
%   HistPop1(NE) = mincv;
%   ClusterHist(NE) = NofC;
%   NE = NE + NP * NofC - NofC;
   NE = fgeneric('evaluations');
   store = store + 1;
   if store == SS
      fprintf('Minimum at %f    Error at %f\n',mincv,Err);
      store = 0;
      loop = 0;
   end
   CH(CHI) = NofC;
   if CHI > LR
       if CH(CHI) < CM
           restart = 1;
           for i = 1 : CL - 1
               if CH(CHI) ~= CH(CHI - i)
                   restart = 0;
               end
           end
           if restart == 1
%               fprintf('i = %f  CL = %f  CHI = %f  CH(CHI - 1) = %f  CH(CHI - 2) = %f  CH(CHI - 3) = %f  CH(CHI - 4) = %f\n',i,CL,CHI,CH(CHI - 1),CH(CHI - 2),CH(CHI - 3),CH(CHI - 4));
               break;
           end
       end
%       if (CH(CHI - 1) == CH(CHI - 2)) && (CH(CHI - 1) == CH(CHI - 3)) && (CH(CHI - 1) < CM)
%           % if the number of clustres is lower than MC
%           % and equal to the number of clusters in GR previous generations then the algorithm is restarted
%           break;
%       end
   end
   CHI = CHI + 1;

end

if ( NE - NE1 + (NP - 1) * NofC >= MNE ) && ( NE - NE1 < NP*2 )
    lowfe = 1;
end
