% SOMA - Self-Organizing Migration Algorithm
close all; clear all; clc;
global dim bounds;
backup=false;
if (backup)
    clear all; close all; clc;
    try
        %Absolutni cesta k backup souboru
        % Nacteni adresare
        addpath('c:/optimalizace/SOMA_CST/files/');
        run('files/backup.m');
    catch
        disp('Nebylo mozno nacist skript backup.m...');
        disp('Bud neexistuje nebo je zadana spatna cesta...');
        return;
    end
else
    optimizedFunctionName = 'AntenaCST';     %bounds -20 -> +20
    additionalParameters = 0;   % nothing to pass

    dim = 4; %pocet parametru

    %nastaveni vsech peti natavenych predmetu
    bounds(1,:) = [30 35]; %hranice parametru 1 30,70
    bounds(2,:) = [25 30]; %hranice parametru 2 25,55
    DL = [1 4 6 8 9 10 11 12];
    TL = [0.1 0.2 0.5 1 1.5 1.6 2 2.5];

    %zadany parametr
    findValue=1.6e+009;

    step = 0.21;
    pathLength = 2.1;
    prt = 0.1;
    minDiv = 0;
    migrations = 5;
    popSize = 2; %15;%dim*2;
    vypocet = 0;
    
    %findValue=0;
    dim = length(bounds);

    % create "instance" of optimized function
    costFunctionHandle = str2func(optimizedFunctionName);

    % generating of population within borders
    individuals = zeros(popSize,4);
    costValues = zeros(popSize,1);

    for i=1:popSize

        %vygenerovani nahodnych parametru ze zadanych nastavenych hranic
        individuals(i,1)=bounds(1,1)+(bounds(1,2)-bounds(1,1))*rand;
        individuals(i,2)=bounds(2,1)+(bounds(2,2)-bounds(2,1))*rand;
        individuals(i,3)=DL(:,1+bi2de((round(rand(1,3))),'left-msb'))';
        individuals(i,4)=TL(:,1+bi2de((round(rand(1,3))),'left-msb'))';

        %ma pouze informativni charakter  a je zobrazen v command window
        vypocet = vypocet + 1;
        disp(sprintf('vypocet cislo = %i of %i',vypocet,popSize+popSize*(pathLength/step)*(migrations)+popSize*migrations));
        
        % vycisleni kriterialni hodnoty ze zadanych vygenerovanych parametru
        costValues(i) = feval(costFunctionHandle,individuals(i,:), additionalParameters);   % find the cost value of each individual
    end
    % kriterialni funkce
    for i = 1:popSize
        costValues(i)=sqrt(((findValue-costValues(i))^2)+((findValue-costValues(i))^2));
    end

    indexOfLeader = 1;
    % find the leader ( individual with the lowest cost value )
    min = 9999999;
    for i = 1:popSize
        if costValues(i)<min
            min = costValues(i);
            indexOfLeader = i;
        end
    end

    globalErrorHistory = zeros(migrations,1);
    mig = 0;
go = true;
end
while(mig<migrations&&go==true) 

    % migrate individuals to the leader ( except leader to himself, of course :)
    for i = 1:popSize
        
        % Check if this individual is not leader. If true, skip it.
        if i==indexOfLeader
            if indexOfLeader~=popSize
                i=i+1;
            else
                break;  % current leader is the last in the population, all migrations has been done
            end
        end
            
        % store the individual's start position
        startPositionOfIndividual = individuals(i,:)';
        
        leaderPosition = individuals(indexOfLeader,:)';
        tmpIndividual = individuals(i,:)';
        
        % Let's migrate!
        for t=0:step:pathLength
            
            % Generate new PRTVector for each step of this individual:
            prtVectorContainOnlyZeros = true;
            while(prtVectorContainOnlyZeros)
                for j=1:dim
                    if rand<prt
                        PRTVector(j) = 1;
                        prtVectorContainOnlyZeros = false;
                    else
                        PRTVector(j) = 0;
                    end
                end
            end
            
            %new position for all dimensions:
            for j=1:dim
                tmpIndividual(j) = startPositionOfIndividual(j) + ( leaderPosition(j) - startPositionOfIndividual(j) ) * t * PRTVector(j);
            end
            
            %check boundaries
            for j=1:dim
                if tmpIndividual(j)<bounds(j,1)||tmpIndividual(j)>bounds(j,2)
                    tmpIndividual(j) = bounds(j,1)+(bounds(j,2)-bounds(j,1))*rand; 
                end
            end
            
            %ma pouze informativni charakter  a je zobrazen v command window
            vypocet = vypocet + 1;
            disp(sprintf('vypocet cislo = %i of %i',vypocet,popSize+popSize*(pathLength/step)*(migrations)+popSize*migrations));
        
            tmpCostValue = feval(costFunctionHandle, tmpIndividual, additionalParameters);
            tmpCostValue = sqrt(((findValue-tmpCostValue)^2)+((findValue-tmpCostValue)^2));
            
            if tmpCostValue<costValues(i)
                costValues(i) = tmpCostValue;   % store better CV and position
                individuals(i,:) = tmpIndividual';
            end
        end % for t
    end % for i

    % find the leader ( individual with the lowest cost value )
    min = 9999999;
    for i = 1:popSize
        if costValues(i)<min
            min = costValues(i);
            indexOfLeader = i;
        end
    end
    
    globalErrorHistory(mig+1) = costValues(indexOfLeader);
    
    % check end conditions
    migCheck = 20;
    if mig>(migCheck+1)
        decrease = 0;
        for i=1:migCheck
            decrease = decrease + abs(globalErrorHistory(mig-i-1)-globalErrorHistory(mig-i));
        end
        if decrease < minDiv
            go = false;
        end
    end

    mig=mig+1;
    
    % Ukladani zaloznich informaci
    val = 0;
    while val ~= 1
        % Nacteni adresare
        addpath('c:/optimalizace/SOMA_CST/files/');
        % Otevreni souboru
        fid = fopen('files/backup.m', 'wt'); 
        val=SOMABACKUPFILE(fid,DL,PRTVector,TL,additionalParameters,bounds,func2str(costFunctionHandle),costValues,dim,findValue,globalErrorHistory,go,i,indexOfLeader,individuals,j,leaderPosition,mig,migCheck,migrations,min,minDiv,optimizedFunctionName,pathLength,popSize,prt,prtVectorContainOnlyZeros,startPositionOfIndividual,step,t,tmpCostValue,tmpIndividual,vypocet);
        fclose(fid);
    end
    
    %pause;

    if round(mig/10) == mig/10
        disp(sprintf('mig = %i of %i',mig, migrations));
    end
%     disp(sprintf('mig = %i of %i',mig, migrations));
end

globalErrorHistory4Saving = zeros(mig,1);
for i=1:mig
    globalErrorHistory4Saving(i) = globalErrorHistory(i);
end

try
%     save c:/wqz/prog/matlab/soma_history.txt globalErrorHistory4Saving -ASCII -TABS
    save c:/tmp_moravec/matlabea/VYSLEDKY/soma_history.txt globalErrorHistory4Saving -ASCII -TABS

    temp = costValues(indexOfLeader); %/dim;
%     save c:/wqz/prog/matlab/soma_leader_cv.txt temp -ASCII -TABS
    save c:/tmp_moravec/matlabea/VYSLEDKY/soma_leader_cv.txt temp -ASCII -TABS

    temp = individuals(indexOfLeader,:);
%     save c:/wqz/prog/matlab/soma_leader.txt temp -ASCII -TABS
    save c:/tmp_moravec/matlabea/VYSLEDKY/soma_leader.txt temp -ASCII -TABS
catch
    disp('Varovani! Nastavena cesta k ulozeni soma.m je spatne nastavena.');
end
%tmpValue = feval(costFunctionHandle, individuals(indexOfLeader,:), additionalParameters);
% return values:
retVal.bestPosition = individuals(indexOfLeader,:);
%retVal.findValue=tmpValue;
retVal.costValue = costValues(indexOfLeader); %/dim;
retVal.history = globalErrorHistory4Saving;

plot(1:length(retVal.history), retVal.history,'b:');
retVal