/* * RapidMiner * * Copyright (C) 2001-2008 by Rapid-I and the contributors * * Complete list of developers available at our web site: * * http://rapid-i.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.tools.math.optimization.ec.pso; import com.rapidminer.operator.OperatorException; import com.rapidminer.operator.performance.PerformanceVector; import com.rapidminer.tools.RandomGenerator; import com.rapidminer.tools.math.optimization.Optimization; /** * This class performs the optimization of a value vector with a particle swarm * approach. * * @author Ingo Mierswa * @version $Id: PSOOptimization.java,v 1.3 2008/05/09 19:23:19 ingomierswa Exp $ */ public abstract class PSOOptimization implements Optimization { private int maxGen; private int maxWithoutImprovement; private double inertiaWeight; private double localWeight; private double globalWeight; private double minValue; private double maxValue; private double inertiaWeightDelta; private RandomGenerator random; private Population population; /** Creates a new PSO optimization with the given parameters. */ public PSOOptimization(int popSize, int individualSize, int maxGen, int maxWithoutImprovement, double inertiaWeight, double localWeight, double globalWeight, double minValue, double maxValue, boolean dynamicInertiaWeight, RandomGenerator random) { this.maxGen = maxGen; this.maxWithoutImprovement = maxWithoutImprovement; if (this.maxWithoutImprovement < 1) this.maxWithoutImprovement = this.maxGen; this.inertiaWeight = inertiaWeight; this.localWeight = localWeight; this.globalWeight = globalWeight; this.minValue = minValue; this.maxValue = maxValue; this.inertiaWeightDelta = 0.0d; if (dynamicInertiaWeight) { inertiaWeightDelta = inertiaWeight / maxGen; } this.random = random; this.population = createInitialPopulation(popSize, individualSize); } /** * Subclasses must implement this method to calculate the fitness of the * given individual. Please note that null might be returned for non-valid * individuals. */ public abstract PerformanceVector evaluateIndividual(double[] individual) throws OperatorException; /** * This method is invoked after each evaluation. The default implementation * does nothing but subclasses might implement this method to support online * plotting or logging. */ public void nextIteration() throws OperatorException {} public void setMinValue(double minValue) { this.minValue = minValue; } public void setMaxValue(double maxValue) { this.maxValue = maxValue; } /** Creates the initial population. */ protected Population createInitialPopulation(int popSize, int individualSize) { Population initPop = new Population(popSize, individualSize); for (int i = 0; i < popSize; i++) { double[] values = new double[individualSize]; for (int j = 0; j < values.length; j++) { values[j] = random.nextDoubleInRange(minValue, maxValue); } initPop.setValues(i, values); } return initPop; } /** Invoke this method for optimization. */ public void optimize() throws OperatorException { // velocities double[][] velocities = new double[population.getNumberOfIndividuals()][population.getIndividualSize()]; for (int p = 0; p < velocities.length; p++) { for (int a = 0; a < velocities[p].length; a++) { velocities[p][a] = 0.0d; } } evaluate(population); population.nextGeneration(); nextIteration(); while (!((population.getGeneration() >= maxGen) || (population.getGenerationsWithoutImprovement() >= maxWithoutImprovement) || (population.getBestFitnessEver() >= population.getBestPerformanceEver().getMainCriterion().getMaxFitness()))) { // update velocities double[] globalBest = population.getGlobalBestValues(); for (int i = 0; i < velocities.length; i++) { double[] localBest = population.getLocalBestValues(i); double[] current = population.getValues(i); for (int d = 0; d < velocities[i].length; d++) { velocities[i][d] = inertiaWeight * velocities[i][d] + localWeight * (random.nextGaussian() + 1.0d) * (localBest[d] - current[d]) + globalWeight * (random.nextGaussian() + 1.0d) * (globalBest[d] - current[d]); } } // update positions for (int i = 0; i < velocities.length; i++) { double[] current = population.getValues(i); double[] newValues = new double[current.length]; for (int d = 0; d < velocities[i].length; d++) { newValues[d] = current[d] + velocities[i][d]; if (newValues[d] < minValue) newValues[d] = minValue; if (newValues[d] > maxValue) newValues[d] = maxValue; } population.setValues(i, newValues); } inertiaWeight -= inertiaWeightDelta; evaluate(population); population.nextGeneration(); nextIteration(); } } /** * Calculates the fitness for all individuals and gives the fitness values * to the population. */ private void evaluate(Population population) throws OperatorException { PerformanceVector[] fitnessValues = new PerformanceVector[population.getNumberOfIndividuals()]; for (int i = 0; i < fitnessValues.length; i++) { double[] individual = population.getValues(i); fitnessValues[i] = evaluateIndividual(individual); } population.setFitnessVector(fitnessValues); } /** Returns the current generation. */ public int getGeneration() { return population.getGeneration(); } /** Returns the best fitness in the current generation. */ public double getBestFitnessInGeneration() { return population.getBestFitnessInGeneration(); } /** Returns the best fitness ever. */ public double getBestFitnessEver() { return population.getBestFitnessEver(); } /** Returns the best performance vector ever. */ public PerformanceVector getBestPerformanceEver() { return population.getBestPerformanceEver(); } /** * Returns the best values ever. Use this method after optimization to get * the best result. */ public double[] getBestValuesEver() { return population.getGlobalBestValues(); } }