// pSMPSO.java
//
// Author:
// Antonio J. Nebro <antonio@lcc.uma.es>
//
// Copyright (c) 2013 Antonio J. Nebro
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package jmetal.metaheuristics.smpso;
import jmetal.core.*;
import jmetal.qualityIndicator.Hypervolume;
import jmetal.qualityIndicator.QualityIndicator;
import jmetal.util.Distance;
import jmetal.util.JMException;
import jmetal.util.PseudoRandom;
import jmetal.util.archive.CrowdingArchive;
import jmetal.util.comparators.CrowdingDistanceComparator;
import jmetal.util.comparators.DominanceComparator;
import jmetal.util.parallel.IParallelEvaluator;
import jmetal.util.wrapper.XReal;
import java.io.IOException;
import java.util.Comparator;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* This class implements the SMPSO algorithm described in:
* A.J. Nebro, J.J. Durillo, J. Garcia-Nieto, C.A. Coello Coello, F. Luna and E. Alba
* "SMPSO: A New PSO-based Metaheuristic for Multi-objective Optimization".
* IEEE Symposium on Computational Intelligence in Multicriteria Decision-Making
* (MCDM 2009), pp: 66-73. March 2009
*/
public class pSMPSO extends Algorithm {
/**
* Stores the number of particles_ used
*/
private int swarmSize_;
/**
* Stores the maximum size for the archive
*/
private int archiveSize_;
/**
* Stores the maximum number of iteration_
*/
private int maxIterations_;
/**
* Stores the current number of iteration_
*/
private int iteration_;
/**
* Stores the particles
*/
private SolutionSet particles_;
/**
* Stores the best_ solutions founds so far for each particles
*/
private Solution[] best_;
/**
* Stores the leaders_
*/
private CrowdingArchive leaders_;
/**
* Stores the speed_ of each particle
*/
private double[][] speed_;
/**
* Stores a comparator for checking dominance
*/
private Comparator dominance_;
/**
* Stores a comparator for crowding checking
*/
private Comparator crowdingDistanceComparator_;
/**
* Stores a <code>Distance</code> object
*/
private Distance distance_;
/**
* Stores a operator for non uniform mutations
*/
private Operator polynomialMutation_;
QualityIndicator indicators_; // QualityIndicator object
/**
* ParallelEvaluator object
*/
IParallelEvaluator parallelEvaluator_ ;
/**
* Number of threads to be executed in parallel
*/
private int numberOfThreads_;
double r1Max_;
double r1Min_;
double r2Max_;
double r2Min_;
double C1Max_;
double C1Min_;
double C2Max_;
double C2Min_;
double WMax_;
double WMin_;
double ChVel1_;
double ChVel2_;
private double trueHypervolume_;
private Hypervolume hy_;
private SolutionSet trueFront_;
private double deltaMax_[];
private double deltaMin_[];
boolean success_;
/**
* Constructor
* @param problem Problem to solve
*/
public pSMPSO(Problem problem, IParallelEvaluator evaluator) {
super(problem) ;
r1Max_ = 1.0;
r1Min_ = 0.0;
r2Max_ = 1.0;
r2Min_ = 0.0;
C1Max_ = 2.5;
C1Min_ = 1.5;
C2Max_ = 2.5;
C2Min_ = 1.5;
WMax_ = 0.1;
WMin_ = 0.1;
ChVel1_ = -1;
ChVel2_ = -1;
parallelEvaluator_ = evaluator ;
} // Constructor
/**
* Initialize all parameter of the algorithm
*/
public void initParams() {
swarmSize_ = ((Integer) getInputParameter("swarmSize")).intValue();
archiveSize_ = ((Integer) getInputParameter("archiveSize")).intValue();
maxIterations_ = ((Integer) getInputParameter("maxIterations")).intValue();
indicators_ = (QualityIndicator) getInputParameter("indicators");
polynomialMutation_ = operators_.get("mutation") ;
parallelEvaluator_.startEvaluator(problem_) ;
iteration_ = 1 ;
success_ = false;
particles_ = new SolutionSet(swarmSize_);
best_ = new Solution[swarmSize_];
leaders_ = new CrowdingArchive(archiveSize_, problem_.getNumberOfObjectives());
// Create comparators for dominance and crowding distance
dominance_ = new DominanceComparator();
crowdingDistanceComparator_ = new CrowdingDistanceComparator();
distance_ = new Distance();
// Create the speed_ vector
speed_ = new double[swarmSize_][problem_.getNumberOfVariables()];
deltaMax_ = new double[problem_.getNumberOfVariables()];
deltaMin_ = new double[problem_.getNumberOfVariables()];
for (int i = 0; i < problem_.getNumberOfVariables(); i++) {
deltaMax_[i] = (problem_.getUpperLimit(i) -
problem_.getLowerLimit(i)) / 2.0;
deltaMin_[i] = -deltaMax_[i];
} // for
} // initParams
// Adaptive inertia
private double inertiaWeight(int iter, int miter, double wma, double wmin) {
return wma; // - (((wma-wmin)*(double)iter)/(double)miter);
} // inertiaWeight
// constriction coefficient (M. Clerc)
private double constrictionCoefficient(double c1, double c2) {
double rho = c1 + c2;
//rho = 1.0 ;
if (rho <= 4) {
return 1.0;
} else {
return 2 / (2 - rho - Math.sqrt(Math.pow(rho, 2.0) - 4.0 * rho));
}
} // constrictionCoefficient
// velocity bounds
private double velocityConstriction(double v, double[] deltaMax,
double[] deltaMin, int variableIndex,
int particleIndex) throws IOException {
double result;
double dmax = deltaMax[variableIndex];
double dmin = deltaMin[variableIndex];
result = v;
if (v > dmax) {
result = dmax;
}
if (v < dmin) {
result = dmin;
}
return result;
} // velocityConstriction
/**
* Update the speed of each particle
* @throws JMException
*/
private void computeSpeed(int iter, int miter) throws JMException, IOException {
double r1, r2, W, C1, C2;
double wmax, wmin, deltaMax, deltaMin;
XReal bestGlobal;
for (int i = 0; i < swarmSize_; i++) {
XReal particle = new XReal(particles_.get(i)) ;
XReal bestParticle = new XReal(best_[i]) ;
//Select a global best_ for calculate the speed of particle i, bestGlobal
Solution one, two;
int pos1 = PseudoRandom.randInt(0, leaders_.size() - 1);
int pos2 = PseudoRandom.randInt(0, leaders_.size() - 1);
one = leaders_.get(pos1);
two = leaders_.get(pos2);
if (crowdingDistanceComparator_.compare(one, two) < 1) {
bestGlobal = new XReal(one);
} else {
bestGlobal = new XReal(two);
//Params for velocity equation
}
r1 = PseudoRandom.randDouble(r1Min_, r1Max_);
r2 = PseudoRandom.randDouble(r2Min_, r2Max_);
C1 = PseudoRandom.randDouble(C1Min_, C1Max_);
C2 = PseudoRandom.randDouble(C2Min_, C2Max_);
W = PseudoRandom.randDouble(WMin_, WMax_);
//
wmax = WMax_;
wmin = WMin_;
for (int var = 0; var < particle.getNumberOfDecisionVariables(); var++) {
//Computing the velocity of this particle
speed_[i][var] = velocityConstriction(constrictionCoefficient(C1, C2) *
(inertiaWeight(iter, miter, wmax, wmin) *
speed_[i][var] +
C1 * r1 * (bestParticle.getValue(var) -
particle.getValue(var)) +
C2 * r2 * (bestGlobal.getValue(var) -
particle.getValue(var))), deltaMax_, //[var],
deltaMin_, //[var],
var,
i);
}
}
} // computeSpeed
/**
* Update the position of each particle
* @throws JMException
*/
private void computeNewPositions() throws JMException {
for (int i = 0; i < swarmSize_; i++) {
XReal particle = new XReal(particles_.get(i)) ;
for (int var = 0; var < particle.getNumberOfDecisionVariables(); var++) {
particle.setValue(var, particle.getValue(var) + speed_[i][var]) ;
if (particle.getValue(var) < problem_.getLowerLimit(var)) {
particle.setValue(var, problem_.getLowerLimit(var));
speed_[i][var] = speed_[i][var] * ChVel1_; //
}
if (particle.getValue(var) > problem_.getUpperLimit(var)) {
particle.setValue(var, problem_.getUpperLimit(var));
speed_[i][var] = speed_[i][var] * ChVel2_; //
}
}
}
} // computeNewPositions
/**
* Apply a mutation operator to some particles in the swarm
* @throws JMException
*/
private void mopsoMutation(int actualIteration, int totalIterations) throws JMException {
for (int i = 0; i < particles_.size(); i++) {
if ( (i % 6) == 0)
polynomialMutation_.execute(particles_.get(i)) ;
//if (i % 3 == 0) { //particles_ mutated with a non-uniform mutation %3
// nonUniformMutation_.execute(particles_.get(i));
//} else if (i % 3 == 1) { //particles_ mutated with a uniform mutation operator
// uniformMutation_.execute(particles_.get(i));
//} else //particles_ without mutation
//;
}
} // mopsoMutation
/**
* Runs of the SMPSO algorithm.
* @return a <code>SolutionSet</code> that is a set of non dominated solutions
* as a result of the algorithm execution
* @throws JMException
*/
public SolutionSet execute() throws JMException, ClassNotFoundException {
initParams();
success_ = false;
//->Step 1 (and 3) Create the initial population and evaluate
for (int i = 0; i < swarmSize_; i++) {
Solution particle = new Solution(problem_);
particles_.add(particle);
parallelEvaluator_.addSolutionForEvaluation(particle) ;
}
parallelEvaluator_.parallelEvaluation() ;
//-> Step2. Initialize the speed_ of each particle to 0
for (int i = 0; i < swarmSize_; i++) {
for (int j = 0; j < problem_.getNumberOfVariables(); j++) {
speed_[i][j] = 0.0;
}
}
// Step4 and 5
for (int i = 0; i < particles_.size(); i++) {
Solution particle = new Solution(particles_.get(i));
leaders_.add(particle);
}
//-> Step 6. Initialize the memory of each particle
for (int i = 0; i < particles_.size(); i++) {
Solution particle = new Solution(particles_.get(i));
best_[i] = particle;
}
//Crowding the leaders_
distance_.crowdingDistanceAssignment(leaders_, problem_.getNumberOfObjectives());
//-> Step 7. Iterations ..
while (iteration_ < maxIterations_) {
try {
//Compute the speed_
computeSpeed(iteration_, maxIterations_);
} catch (IOException ex) {
Logger.getLogger(pSMPSO.class.getName()).log(Level.SEVERE, null, ex);
}
//Compute the new positions for the particles_
computeNewPositions();
//Mutate the particles_
mopsoMutation(iteration_, maxIterations_);
for (int i = 0; i < particles_.size(); i++) {
Solution particle = particles_.get(i);
parallelEvaluator_.addSolutionForEvaluation(particle) ;
}
parallelEvaluator_.parallelEvaluation() ;
//Actualize the archive
for (int i = 0; i < particles_.size(); i++) {
Solution particle = new Solution(particles_.get(i));
leaders_.add(particle);
}
//Actualize the memory of this particle
for (int i = 0; i < particles_.size(); i++) {
int flag = dominance_.compare(particles_.get(i), best_[i]);
if (flag != 1) { // the new particle is best_ than the older remeber
Solution particle = new Solution(particles_.get(i));
best_[i] = particle;
}
}
//Assign crowding distance to the leaders_
distance_.crowdingDistanceAssignment(leaders_,
problem_.getNumberOfObjectives());
iteration_++;
if ((iteration_ % 1) == 0) {
leaders_.printObjectivesToFile("FUN"+iteration_) ;
leaders_.printVariablesToFile("VAR"+iteration_) ;
}
}
parallelEvaluator_.stopEvaluator() ;
return this.leaders_;
} // execute
/**
* Gets the leaders of the SMPSO algorithm
*/
public SolutionSet getLeader() {
return leaders_;
} // getLeader
} // SMPSO