/*
 * RankSelection.java
 *
 * Created on 12. unor 2006, 15:01
 *
 * To change this template, choose Tools | Options and locate the template under
 * the Source Creation and Management node. Right-click the template and choose
 * Open. You can then make changes to the template in the Source Editor.
 */

package cz.pcland.ga.selection;
import cz.pcland.ga.BaseIndividual;
import cz.pcland.ga.*;
/**
 *
 * @author petr
 */
public class RankSelection implements SelectionOperator{
    double sumOfRanks;
    
    int getFitnessRank(double fitness, BaseIndividual[] population) {
        int fitnessRank = -1;
        for(int i = 0; i < population.length; i++){
            if(fitness >= population[i].getFitness()){
                fitnessRank++;
            }
        }
        
        //System.out.println("fitnessRank=" + fitnessRank);
        //System.out.println("popSize=" + popSize);
        return fitnessRank;
    }
    
    void setFitnessRanks(BaseIndividual[] population){
        double rank;
        
        for(int i = 0; i < population.length; i++){
            //System.out.println("population[i].getFitness()=" + population[i].getFitness());
            population[i].setFitnessRank(getFitnessRank(population[i].getFitness(),  population));
        }
    }
    
    public String toString(){
        return "Rank roulette";
    }
    
   
    
    public double getSumOfRanks(BaseIndividual[] population){
        double ret = 0;
        for(int i=0;i<population.length;i++){
            ret += population[i].getFitnessRank();
        }
       // System.out.println("getSumOfRanks=" + ret);
        return ret;
    }
    
    public void onStart(BaseIndividual[] population) {
        
    }
    
    public void init(BaseIndividual[] population, double sumOfFitness) {
        setFitnessRanks(population);
        sumOfRanks = getSumOfRanks(population);
    }
    
    public BaseIndividual select(BaseIndividual[] population, int popSize, double sumOfFitness){
        
        //double n = Math.random()*sumOfRanks;
        double n = Math.abs(MyRand.getInt()%sumOfRanks) + Math.random();
        double sum = 0;
        
        for(int i=0;i<popSize;i++){
            sum+=population[i].getFitnessRank();
            if(sum > n){
                return population[i];
            }
        }
        
        return population[popSize-1];
        /*int i;
        System.out.println("sumOfRanks=" + sumOfRanks);
        for (i = 0;  n >= sum + population[i].getFitnessRank(); i++) //todo: outofbones
            if(i < population.length) sum += population[i].getFitnessRank(); else break;
        return population[i];*/
    }
    
    
    
    
    /** Creates a new instance of RankSelection */
    public RankSelection() {
        
    }
    
}
