// Strategie evolutiva de tip mu+lambda
// Parametri:
//   mu:  numarul de parinti
//   lambda: numarul de urmasi 
//   n: dimensiunea fiecarui element
//   gen:  numar de generatii
//   [a,b]: domeniul de definitie al functiei de optimizat (minimizat)
//   sigma: parametrul care controleaza marimea perturbatiei
//   rho: numarul de parinti utilizati in recombinare
//   selectie: numele functiei de selectie
//   functie: numele functiei de minimizat
// Exemplu de apel: SE(10,20,1,100,-50,50,0.1,5,@SE_trunchiere,@SE_f1)

function [pop,f]=SE(mu,lambda,n,gen,a,b,sigma,rho,selectie,functie)
    pop1=SE_initpop(mu,n,a,b); //initializarea populatiei
    pop2=zeros(lambda,n); //alocare spatiu pentru populatia de copii obtinuta dupa recombinare si  mutatie
    m=mu+lambda;
    f=zeros(1,m);      //alocare spatiu pentru valorile elementelor populatiei reunite
    for k=1:gen
        // generare populatie de urmasi prin recombinare si mutatie  
        for i=1:lambda
            pop2(i,:)=SE_recombinare(pop1,rho);
            pop2(i,:)=SE_mutatie(pop2(i,:),sigma);
        end
        pop=[pop1;pop2];  // concatenarea populatiei curente si a populatiei de copii
        // evaluarea tuturor elementelor
        for i=1:m
            f(1,i)=functie(pop(i,:));     
        end   
        // selectie urmasi
        pop1=selectie(pop,f,mu); 
        disp(min(f));  // afisarea valorii celui mai bun element din populatie
     end 
     disp(min(f)); 
     f=[];
     for i=1:mu
         f(i)=functie(pop1(i,:));     
     end
     // reprezentarea grafica a functiei si a elementelor populatiei
     x=a:0.1:b; y=zeros(1,size(x,2));
     for j=1:size(x,2)
         y(j)=functie(x(j));
     end   
     plot(x,y,"b",pop1',f,"r*");
endfunction

// Strategie evolutiva:  initializarea populatiei (m vectori avand cate n componente)
// fiecare componenta se genereaza uniform aleator in intervalul [a,b]
function pop = SE_initpop(m,n,a,b)
    pop=zeros(m,n);
    for i=1:m
        for j=1:n
            pop(i,j)=grand(1,1,'unf',a,b);
        end   
    end   
endfunction

// Strategie evolutiva: recombinare
// pornind de la rho parinti selectati aleator se genereaza un fiu: media aritmetica a parintilor
function copil=SE_recombinare(p, rho)
    m=size(p,1); 
    n=size(p,2);
    copil=zeros(1,n);
    for k=1:rho
        ind=grand(1,1,"uin",1,m);  // selectare indice parinte
        copil=copil+p(ind,:); 
    end
    copil=copil/rho;
endfunction

// Strategie evolutiva: mutatie
// genereaza un nou element prin aplicarea unei perturbatii normale de medie 0 si abatere standard sigma
function copil=SE_mutatie(parinte,sigma)
    n=size(parinte,2);
    copil=parinte;
    for i=1:n
        copil(i)=copil(i)+grand(1,1,"nor",0,sigma);
    end   
endfunction

// Strategie evolutiva:  selectie de tip turneu
// din populatia primita ca parametru se selecteaza aleator perechi de 
// elemente care se compara intre ele
function p2=SE_turneu(p1,f1,mu)
m=size(p1,1);
p2=[];
sel=zeros(1,m);
for i=1:mu
   j1=grand(1,1,'uin',1,m);
   j2=grand(1,1,'uin',1,m);
   if f1(j1)<f1(j2)
      p2(i,:)=p1(j1,:);
   else   
      p2(i,:)=p1(j2,:);  
   end   
end   
endfunction

// Strategie evolutiva:  selectie prin trunchiere
// din populatia primita ca parametru se selecteaza cele mai bune mu elemente
function p2=SE_trunchiere(p1,f1,mu)
m=size(p1,1); 
n=size(p1,2);
p2=zeros(mu,n);
sel=zeros(1,m); 
for i=1:mu
   jmin=1;
   for j=2:m
      if sel(j)==0 
         if f1(j)<f1(jmin)
            jmin=j;
         end   
      end
   end   
   sel(jmin)=1;
   p2(i,:)=p1(jmin,:);
end  
endfunction

// Strategie evolutiva:  functie test (functia patratica)
function y=SE_f1(x)
    n=size(x,2);
    y=0;
    for j=1:n
        y=y+x(j)^2;
    end
endfunction

// Strategie evolutiva: functie test multi-modala (multe minime locale)
function y=SE_f2(x)
    n=size(x,2);
    s=0;p=1;
    for j=1:n
        s=s+x(j)^2;
        p=p*cos(x(j)/sqrt(j));   
    end   
    y=s/4000-p+1;
endfunction

SE(20,50,1,500,-50,50,0.1,4,SE_turneu,SE_f2)
