es.udc.gii.common.eaf.algorithm.EvolutionaryAlgorithm.java Source code

Java tutorial

Introduction

Here is the source code for es.udc.gii.common.eaf.algorithm.EvolutionaryAlgorithm.java

Source

/*
 * Copyright (C) 2010 Grupo Integrado de Ingeniera
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package es.udc.gii.common.eaf.algorithm;

import es.udc.gii.common.eaf.algorithm.evaluate.EvaluationStrategy;
import es.udc.gii.common.eaf.algorithm.fitness.comparator.FitnessComparator;
import es.udc.gii.common.eaf.algorithm.operator.OperatorChain;
import es.udc.gii.common.eaf.algorithm.operator.evaluate.EvaluationOperator;
import es.udc.gii.common.eaf.algorithm.operator.replace.ReplaceOperator;
import es.udc.gii.common.eaf.algorithm.operator.reproduction.ReproductionOperator;
import es.udc.gii.common.eaf.algorithm.operator.selection.SelectionOperator;
import es.udc.gii.common.eaf.algorithm.population.Individual;
import es.udc.gii.common.eaf.algorithm.population.Population;
import es.udc.gii.common.eaf.algorithm.productTrader.specification.BestIndividualSpecification;
import es.udc.gii.common.eaf.algorithm.productTrader.specification.WorstIndividualSpecification;
import es.udc.gii.common.eaf.algorithm.restart.RestartStrategy;
import es.udc.gii.common.eaf.config.Configurable;
import es.udc.gii.common.eaf.problem.Problem;
import es.udc.gii.common.eaf.stoptest.CompositeStopTest;
import es.udc.gii.common.eaf.stoptest.EvolveGenerationsStopTest;
import es.udc.gii.common.eaf.stoptest.FEsStopTest;
import es.udc.gii.common.eaf.stoptest.StopTest;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import org.apache.commons.configuration.Configuration;

/*
 * This class represents an evolutionary algorithm. This algorithm it will be used to resolve a
 * problem. <p/>
 *
 * @author Grupo Integrado de Ingeniera (<a href="http://www.gii.udc.es">www.gii.udc.es</a>) @since
 * 1.0
 */
public abstract class EvolutionaryAlgorithm extends Observable implements Configurable {
    //Estado inicial: en el que se genera la poblacion inicial.

    public final static int INIT_STATE = 0;
    // Rafa: Cambio los atributos de clase a final para que sean constantes.
    //Evaluacion de la poblacion inicial:
    public final static int INIT_EVALUATE_STATE = 1; //Antes de la seleccion:
    public final static int SELECT_STATE = 2;
    public final static int REPRODUCTION_STATE = 3;
    public final static int EVALUATE_STATE = 4;
    public final static int REPLACE_STATE = 5;
    public final static int FINAL_STATE = 6;
    public final static int CLOSE_LOGS_STATE = 7;
    public final static int PRE_EVALUATION_STATE = 8;
    protected int state;
    private Population population;
    private Population new_population;
    private EvaluationStrategy evaluationStrategy;
    private RestartStrategy restartStrategy;
    private OperatorChain<SelectionOperator> selectionChain;
    private OperatorChain<ReproductionOperator> reproductionChain;
    private OperatorChain<ReplaceOperator> replaceChain;
    private OperatorChain<EvaluationOperator> evalChain;
    private Problem problem;
    protected int generations;
    private int FEs = 1;
    private boolean finish = false;
    private int maxGenerations = 0;
    private int maxEvaluations = 0;
    private FitnessComparator<Individual> comparator = null;
    private StopTest stopTest;
    private StopTest restartTest;
    private String userTag = "";
    // This allows the user to use a custom init population instead of a
    // random one
    private boolean useCustomInitPopulation = false;
    private List<Individual> fitness_history;
    private int fitness_history_capacity = -1;

    //27-02-2010: se implementa el mtodo best_ever para cuando haya 
    //tcnica de reemplazo que se guarde
    //el mejor individuo que se haya encontrado hasta ese momento. 
    //getBestIndividual sigue devolviendo
    //el mejor de la poblacin, pero bestEver devuelve el mejor.
    private Individual best_ever_individual;

    //04-09-2013: "debug" boolean parameter to indicate if debug messages are printed or not.
    //false by default
    private boolean debug = false;

    public EvolutionaryAlgorithm() {
    }

    public String getUserTag() {
        return userTag;
    }

    public void setUserTag(String userTag) {
        this.userTag = userTag;
    }

    public Population getPopulation() {
        return population;
    }

    public void setPopulation(Population population) {
        this.population = population;
    }

    public EvaluationStrategy getEvaluationStrategy() {
        return evaluationStrategy;
    }

    public void setEvaluationStrategy(EvaluationStrategy evaluationStrategy) {
        this.evaluationStrategy = evaluationStrategy;
    }

    public RestartStrategy getRestartStrategy() {
        return restartStrategy;
    }

    public void setRestartStrategy(RestartStrategy restartStrategy) {
        this.restartStrategy = restartStrategy;
    }

    public OperatorChain<SelectionOperator> getSelectionChain() {
        return selectionChain;
    }

    public void setSelectionChain(OperatorChain<SelectionOperator> selectionChain) {
        this.selectionChain = selectionChain;
    }

    public OperatorChain<ReproductionOperator> getReproductionChain() {
        return reproductionChain;
    }

    public void setReproductionChain(OperatorChain<ReproductionOperator> reproductionChain) {
        this.reproductionChain = reproductionChain;
    }

    public OperatorChain<ReplaceOperator> getReplaceChain() {
        return this.replaceChain;
    }

    public void setReplaceChain(OperatorChain<ReplaceOperator> replaceChain) {
        this.replaceChain = replaceChain;
    }

    public OperatorChain<EvaluationOperator> getEvalChain() {
        return evalChain;
    }

    public void setEvalChain(OperatorChain<EvaluationOperator> evalChain) {
        this.evalChain = evalChain;
    }

    public int getGenerations() {
        return generations;
    }

    public int getMaxGenerations() {

        return this.maxGenerations;
    }

    public int getMaxEvaluations() {
        return this.maxEvaluations;
    }

    protected void setMaxEvaluations(int evaluations) {
        this.maxEvaluations = evaluations;
    }

    protected void setMaxGenerations(int generations) {
        this.maxGenerations = (int) generations;
    }

    protected void setMaxEvaluations(StopTest objective) {

        List<StopTest> stopTests;
        this.maxEvaluations = -Integer.MAX_VALUE;

        if (objective instanceof CompositeStopTest) {

            stopTests = ((CompositeStopTest) objective).getStopTests();

        } else {

            stopTests = (new ArrayList<StopTest>());
            stopTests.add(objective);
        }

        for (int i = 0; i < stopTests.size(); i++) {

            if (stopTests.get(i) instanceof FEsStopTest) {

                this.maxEvaluations = Math.max(this.maxEvaluations, ((FEsStopTest) stopTests.get(i)).getFEs(this));

            }

        }

        if (this.maxEvaluations == -Integer.MAX_VALUE) {
            this.maxEvaluations = Math.abs(this.maxEvaluations);
        }

    }

    protected void setMaxGenerations(StopTest objective) {

        List<StopTest> stopTests;
        this.maxGenerations = -Integer.MAX_VALUE;

        if (objective instanceof CompositeStopTest) {

            stopTests = ((CompositeStopTest) objective).getStopTests();

        } else {

            stopTests = (new ArrayList<StopTest>());
            stopTests.add(objective);
        }

        for (int i = 0; i < stopTests.size(); i++) {

            if (stopTests.get(i) instanceof EvolveGenerationsStopTest) {

                this.maxGenerations = Math.max(this.maxGenerations,
                        ((EvolveGenerationsStopTest) stopTests.get(i)).getGenerations());

            }

        }

        if (this.maxGenerations == -Integer.MAX_VALUE) {
            this.maxGenerations = Math.abs(this.maxGenerations);
        }

    }

    public void setProblem(Problem problem) {
        this.problem = problem;
    }

    public Problem getProblem() {
        return this.problem;
    }

    public int getState() {
        return this.state;
    }

    public String getStateString() {

        switch (this.state) {
        case EvolutionaryAlgorithm.INIT_STATE:
            return "INIT_STATE";
        case EvolutionaryAlgorithm.INIT_EVALUATE_STATE:
            return "INIT_EVALUATE_STATE";
        case EvolutionaryAlgorithm.SELECT_STATE:
            return "SELECT_STATE";
        case EvolutionaryAlgorithm.REPRODUCTION_STATE:
            return "REPRODUCTION_STATE";
        case EvolutionaryAlgorithm.PRE_EVALUATION_STATE:
            return "PRE_EVALUATION_STATE";
        case EvolutionaryAlgorithm.EVALUATE_STATE:
            return "EVALUATE_STATE";
        case EvolutionaryAlgorithm.REPLACE_STATE:
            return "REPLACE_STATE";
        case EvolutionaryAlgorithm.FINAL_STATE:
            return "FINAL_STATE";
        case EvolutionaryAlgorithm.CLOSE_LOGS_STATE:
            return "CLOSE_LOGS_STATE";
        default:
            return "";
        }

    }

    public void resolve(StopTest objective, int maxGenerations) {

        this.maxGenerations = maxGenerations;

        this.resolve(objective);

    }

    public void resolve(StopTest objective) {

        this.generations = 0;
        this.FEs = 0;
        this.state = EvolutionaryAlgorithm.INIT_STATE;
        //TODO: Cambiar esto para que se encargue la factoria de establecerlo:
        this.stopTest = objective;

        this.next();

        this.next();

        while (objective == null || !objective.isReach(this) /*&& !this.finish*/) {
            this.step();

        }

        this.next();
        this.next();
        this.finish = true;
    }

    /*
     * This method allow to execute one step of a generation according to the current state of the
     * algorithm. If state == EvolutionaryAlgorithm.INIT_STATE: init() If state
     * ==EvolutionaryAlgorithm.INIT_EVALUATE_STATE: evaluate() If state ==
     * EvolutionaryAlgorithm.SELECT_STATE: select() If state ==
     * EvolutionaryAlgorithm.REPRODUCTION_STATE: reproduce() If state ==
     * EvolutionaryAlgorithm.EVALUATE_STATE: evaluate() If state
     * ==EvolutionaryAlgorithm.REPLACE_STATE: replace() If state ==
     * EvolutionaryAlgorithm.FINAL_STATE: notify to the observers. If state ==
     * EvolutionaryAlgorithm.CLOSE_LOGS_STATE: notify to the observers.
     */
    public void next() {

        switch (this.state) {

        case EvolutionaryAlgorithm.INIT_STATE:
            this.init();
            this.notifyChanges();
            this.state = EvolutionaryAlgorithm.INIT_EVALUATE_STATE;
            this.notifyChanges();
            break;
        case EvolutionaryAlgorithm.INIT_EVALUATE_STATE:
            this.evaluate(this.problem, this.getPopulation());
            this.new_population = new Population();
            this.notifyChanges();
            this.state = EvolutionaryAlgorithm.SELECT_STATE;
            break;
        case EvolutionaryAlgorithm.SELECT_STATE:
            this.select(this.new_population);
            this.notifyChanges();
            this.state = EvolutionaryAlgorithm.REPRODUCTION_STATE;
            break;
        case EvolutionaryAlgorithm.REPRODUCTION_STATE:
            this.reproduce(this.new_population);
            this.notifyChanges();
            this.state = EvolutionaryAlgorithm.PRE_EVALUATION_STATE;
            this.notifyChanges();
            this.state = EvolutionaryAlgorithm.EVALUATE_STATE;
            break;
        case EvolutionaryAlgorithm.EVALUATE_STATE:
            this.evaluate(this.problem, new_population);
            this.notifyChanges();
            this.state = EvolutionaryAlgorithm.REPLACE_STATE;
            break;
        case EvolutionaryAlgorithm.REPLACE_STATE:
            this.replace(this.new_population);
            this.notifyChanges();
            //Despus de replace hay que comprobar el test de parada
            this.generations++;
            this.problem.resetObjectiveFunctions();

            //01 - 07 - 2011 - Aadidas las estrategias de restart, en esta 
            //ltima fase de la generacin se comprueban si se cumple alguna 
            //si se cumple se aplica la estrategia de restart que es la 
            //encargada de poner el nuevo estado del algoritmo.
            if (this.restartStrategy != null && this.restartTest != null && this.restartTest.isReach(this)) {

                this.restartStrategy.restart(this);

            } else if (this.stopTest == null || !this.stopTest.isReach(this)) {
                this.state = EvolutionaryAlgorithm.SELECT_STATE;
            } else {
                this.state = EvolutionaryAlgorithm.FINAL_STATE;
                //this.finish = true;
            }
            break;
        case EvolutionaryAlgorithm.FINAL_STATE:
            this.notifyChanges();
            this.state = EvolutionaryAlgorithm.CLOSE_LOGS_STATE;
            break;
        case EvolutionaryAlgorithm.CLOSE_LOGS_STATE:
            this.notifyChanges();
            break;
        }
    }

    /*
     * This method allows to execute one complete generation.
     */
    public void step() {

        if (this.state == EvolutionaryAlgorithm.INIT_STATE) {
            //One step for the init state and the other one for the init_evaluate:
            this.next();
            this.next();
        }

        do {
            this.next();
        } while (this.state != EvolutionaryAlgorithm.SELECT_STATE
                && this.state != EvolutionaryAlgorithm.FINAL_STATE);

    }

    private void notifyChanges() {
        this.setChanged();
        this.notifyObservers();
        this.clearChanged();
    }

    protected void init() {
        if (this.maxGenerations == 0) {
            this.setMaxGenerations(this.stopTest);
        }
        if (this.maxEvaluations == 0) {
            this.setMaxEvaluations(this.stopTest);
        }
        if (!this.useCustomInitPopulation) {
            this.getPopulation().generate();
        }

    }

    protected void evaluate(Problem problem, Population population) {
        if (getEvalChain() != null && getEvalChain().getOperators() != null
                && !getEvalChain().getOperators().isEmpty()) {
            population.setIndividuals(getEvalChain().execute(this, population));
            this.setFEs(this.getFEs() + population.getSize());
        } else if (this.getEvaluationStrategy() != null) {
            //21 - 06 - 2011 : Se aade la posibilidad de que no exista 
            //evaluacin en el algoritmo.
            this.getEvaluationStrategy().evaluate(this, population.getIndividuals(),
                    problem.getObjectiveFunctions(), problem.getConstraints());

            this.setFEs(this.getFEs() + population.getSize());
        }
        //16 - 02 - 2012: Se aade el histrico de calidad, es una FIFO, 
        //si existe se inserta la calidad del mejor individuo:
        if (this.fitness_history != null) {

            if (this.fitness_history.size() == this.fitness_history_capacity) {
                this.fitness_history.set(this.getGenerations() % this.fitness_history_capacity,
                        this.getBestIndividual());
            } else {
                this.fitness_history.add(this.getBestIndividual());
            }
        }
    }

    protected void select(Population toPopulation) {
        if (this.getSelectionChain() != null) {
            toPopulation.setIndividuals(this.getSelectionChain().execute(this, this.getPopulation()));
        } else {
            toPopulation.setIndividuals(this.getPopulation().getIndividualsCopy());
        }
    }

    protected void reproduce(Population population) {
        population.setIndividuals(this.getReproductionChain().execute(this, population));
    }

    protected void replace(Population toPopulation) {
        if (this.getReplaceChain() != null) {
            this.getPopulation().setIndividuals(this.getReplaceChain().execute(this, toPopulation));
        } else {
            this.getPopulation().setIndividuals(toPopulation.getIndividuals());
        }
        updateBestEver();
    }

    public void evaluate(Individual individual) {

        this.evaluationStrategy.evaluate(this, individual, this.problem.getObjectiveFunctions(),
                this.problem.getConstraints());
        this.setFEs(this.getFEs() + 1);

    }

    public void evaluate(List<Individual> individuals) {
        this.evaluationStrategy.evaluate(this, individuals, this.problem.getObjectiveFunctions(),
                this.problem.getConstraints());
        this.setFEs(this.getFEs() + individuals.size());
    }

    public int getFEs() {
        return FEs;
    }

    public void setFEs(int FEs) {
        this.FEs = FEs;
    }

    public void setFinish(boolean finish) {
        this.finish = finish;
    }

    @Override
    public void configure(Configuration conf) {
        try {
            setComparator((FitnessComparator) Class.forName(conf.getString("Comparator")).newInstance());

            setUseCustomInitPopulation(conf.containsKey("UseCustomRandomInitPopulation"));

            setDebug(conf.containsKey("Debug"));

            if (conf.containsKey("FitnessHistoryCapacity")) {
                this.fitness_history_capacity = conf.getInt("FitnessHistoryCapacity");
                this.fitness_history = new ArrayList<Individual>();

            } else {
                this.fitness_history = null;
            }

        } catch (Exception ex) {

            System.exit(0);
        }
    }

    public boolean isDebug() {
        return debug;
    }

    public void setDebug(boolean debug) {
        this.debug = debug;
    }

    public boolean isUseCustomInitPopulation() {
        return useCustomInitPopulation;
    }

    public void setUseCustomInitPopulation(boolean useCustomInitPopulation) {
        this.useCustomInitPopulation = useCustomInitPopulation;
    }

    public boolean getFinish() {
        return this.finish;
    }

    public void updateParameters() {
    }

    public String getAlgorithmID() {
        return "EA";
    }

    public FitnessComparator<Individual> getComparator() {
        return comparator;
    }

    public void setComparator(FitnessComparator<Individual> comparator) {
        this.comparator = comparator;
    }

    public StopTest getStopTest() {
        return stopTest;
    }

    public void setStopTest(StopTest stopTest) {
        this.stopTest = stopTest;
    }

    public StopTest getRestartTest() {
        return restartTest;
    }

    public void setRestartTest(StopTest restartTest) {
        this.restartTest = restartTest;
    }

    public Individual getBestIndividual() {

        BestIndividualSpecification spec = new BestIndividualSpecification();

        return spec.get(this.population.getIndividuals(), 1, this.comparator).get(0);

    }

    public Individual getWorstIndividual() {
        WorstIndividualSpecification spec = new WorstIndividualSpecification();

        return spec.get(this.population.getIndividuals(), 1, this.comparator).get(0);
    }

    public void setState(int state) {
        this.state = state;
    }

    public List<Individual> getFitnessHistory() {
        return this.fitness_history;
    }

    public void setFitnessHistory(List<Individual> fitness_history) {
        this.fitness_history = fitness_history;
    }

    public void setFitnessHistoryCapacity(int fitnessHistoryCapacity) {
        this.fitness_history_capacity = fitnessHistoryCapacity;
    }

    public void setPopulationSize(int new_pop_size) {
        this.getPopulation().modifyPopulationSize(new_pop_size);
    }

    private void updateBestEver() {
        if (this.best_ever_individual == null) {
            this.best_ever_individual = this.getBestIndividual();
        } else {
            if (this.comparator.compare(this.best_ever_individual, this.getBestIndividual()) >= 1) {
                this.best_ever_individual = (Individual) this.getBestIndividual().clone();
            }
        }
    }

    public Individual getBestEverIndividual() {
        return this.best_ever_individual;
    }

    public Population getNewPopulation() {
        return this.new_population;
    }
}