// Genetic Algoritmi for ONEMAX
// Input parameters:
//  m - population size (ex: 20)
//  n - problem size (ex:10)
//  gen - number of generations (ex: 50)
//  pm - mutation probability (ex: 0.01)
// Call:  onemaxGA(20,10,50,0.01)
function pop=onemaxGA(m,n,gen,pm)
    pop=initpop(m,n);                  // population initialization 
    for k=1:gen      
        copii=zeros(m,n);              
        val=evalpop(pop);              // population evaluation
        prob=calculprob(val);          // selection probabilities
        indici1=ruleta(prob);          // selection of parents
        indici2=ruleta(prob);
        for i=1:m/2                    // crossover
          parinte1=pop(indici1(i),:);  
          parinte2=pop(indici2(i),:);
          [copil1,copil2]=incrucisare(parinte1,parinte2);
          copii(i,:)=copil1;
          copii(m-i+1,:)=copil2;
        end  
        for i=1:m                      // mutation (chromosome based)
          if grand(1,1,"unf",0,1)<pm
             copii(i,:)=mutatie(copii(i,:));
          end
        end   
        pop=copii;               
        disp(pop);               
    end   
    indBest=findBest(val);
    disp(pop(indBest,:),"Best element:");
endfunction

function pop = initpop(m,n)
    for i=1:m
        for j=1:n
            pop(i,j)=grand(1,1,"uin",0,1);
        end
    end    
endfunction

function val=evalpop(pop)
[m,n]=size(pop);
val=[];
for i=1:m
   val(i)=0;
   for j=1:n
      val(i)=val(i)+pop(i,j);
   end
end   
endfunction
 
function indBest=findBest(val)
    indBest=1;
    for i=2:length(val)
        if val(i)>val(indBest)
            indBest=i;
        end
    end
endfunction    

function prob=calculprob(val)
m=length(val);
prob=zeros(m);
s=0;
for i=1:m
   s=s+val(i);
end
for i=1:m
   prob(i)=val(i)/s;
end     
endfunction

// roulette selection
// Input: selection probabilities
// Output: selected elements
function indici=ruleta(prob)
    indici=zeros(length(prob));
    for k=1:length(prob)
        i=1;
        s=prob(1);
        u=grand(1,1,"unf",0,1);
        while u>s
           i=i+1;
           s=s+prob(i);
        end
        indici(k)=i;
    end
endfunction

// one cut point crossover
// Input:  
//      parinte1, parinte2 - current elements
// Output:  two new elements (children)
function [copil1,copil2]=incrucisare(parinte1, parinte2)
    n=size(parinte1,2); 
    copil1=zeros(1,n);copil2=zeros(1,n);
    poz=grand(1,1,"uin",1,n-1); // cut point
    for i=1:poz                 
      copil1(1,i)=parinte1(1,i);
      copil2(1,i)=parinte2(1,i);
   end
   for i=poz+1:n            
      copil1(1,i)=parinte2(1,i);
      copil2(1,i)=parinte1(1,i);
   end
endfunction

// simple mutation:  a random component is complemented
function copil=mutatie(parinte)
    n=size(parinte,2);
    copil=parinte;
    poz=grand(1,1,"uin",1,n);
    copil(poz)=1-copil(poz);
endfunction

// pop=onemaxGA(m,n,gen,pm)
onemaxGA(30,10,50,0.01)

