/*=========================================================================
*
* Copyright Insight Software Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*=========================================================================*/
#ifndef itkParticleSwarmOptimizerBase_h
#define itkParticleSwarmOptimizerBase_h
#include "itkSingleValuedNonLinearOptimizer.h"
#include "itkMersenneTwisterRandomVariateGenerator.h"
#include "ITKOptimizersExport.h"
namespace itk
{
/** \class ParticleSwarmOptimizerBase
* \brief Abstract implementation of a Particle Swarm Optimization (PSO) algorithm.
*
* The PSO algorithm was originally presented in:
* J. Kennedy, R. Eberhart, "Particle Swarm Optimization",
* Proc. IEEE Int. Neural Networks, 1995.
*
* The algorithm is a stochastic global search optimization approach.
* Optimization is performed by maintaining a swarm of particles that traverse
* the parameter space, searching for the optimal function value. Associated
* with each particle are its location and speed, in parameter space.
*
* Swarm initialization is performed within the user supplied parameter bounds
* using either a uniform distribution or a normal distribution centered on
* the initial parameter values supplied by the user. The search terminates when
* the maximal number of iterations has been reached or when the change in the
* best value in the past \f$g\f$ generations is below a threshold and the swarm
* has collapsed (i.e. best personal particle locations are close to the
* swarm's best location in parameter space).
*
* The actual optimization procedure, updating the swarm, is performed in the
* subclasses, required to implement the UpdateSwarm() method.
*
* NOTE: This implementation only performs minimization.
*
* \ingroup Numerics Optimizers
* \ingroup ITKOptimizers
*/
class ITKOptimizers_EXPORT ParticleSwarmOptimizerBase :
public SingleValuedNonLinearOptimizer
{
public:
/** Standard "Self" typedef. */
typedef ParticleSwarmOptimizerBase Self;
typedef SingleValuedNonLinearOptimizer Superclass;
typedef SmartPointer Pointer;
typedef SmartPointer ConstPointer;
/** Run-time type information (and related methods). */
itkTypeMacro( ParticleSwarmOptimizerBase, SingleValuedNonLinearOptimizer )
typedef std::vector< std::pair > ParameterBoundsType;
struct ParticleData
{
ParametersType m_CurrentParameters;
ParametersType m_CurrentVelocity;
CostFunctionType::MeasureType m_CurrentValue;
ParametersType m_BestParameters;
CostFunctionType::MeasureType m_BestValue;
};
typedef std::vector SwarmType;
typedef unsigned int NumberOfIterationsType;
typedef unsigned int NumberOfParticlesType;
typedef unsigned int NumberOfGenerationsType;
typedef CostFunctionType::MeasureType MeasureType;
typedef ParametersType::ValueType ValueType;
typedef Statistics::MersenneTwisterRandomVariateGenerator
RandomVariateGeneratorType;
/** Specify whether to initialize the particles using a normal distribution
* centered on the user supplied initial value or a uniform distribution.
* If the optimum is expected to be near the initial value it is likely
* that initializing with a normal distribution will result in faster
* convergence.*/
itkSetMacro( InitializeNormalDistribution, bool )
itkGetMacro( InitializeNormalDistribution, bool )
itkBooleanMacro( InitializeNormalDistribution )
/**
* Specify the initial swarm. Useful for evaluating PSO variants. If the
* initial swarm is set it will be used. To revert to random initialization
* (uniform or normal particle distributions) set using an empty swarm.
*/
void SetInitialSwarm( const SwarmType &initialSwarm );
void ClearSwarm();
/**
* Indicate whether or not to output the swarm information when printing an
* object. By default this option is turned off as it generates too much
* information.
*/
itkSetMacro( PrintSwarm, bool )
itkGetMacro( PrintSwarm, bool )
itkBooleanMacro( PrintSwarm )
/** Start optimization. */
virtual void StartOptimization( void ) ITK_OVERRIDE;
/** Set/Get number of particles in the swarm - the maximal number of function
evaluations is m_MaximalNumberOfIterations*m_NumberOfParticles */
void SetNumberOfParticles( NumberOfParticlesType n );
itkGetMacro( NumberOfParticles, NumberOfParticlesType )
/** Set/Get maximal number of iterations - the maximal number of function
evaluations is m_MaximalNumberOfIterations*m_NumberOfParticles */
itkSetMacro( MaximalNumberOfIterations, NumberOfIterationsType )
itkGetMacro( MaximalNumberOfIterations, NumberOfIterationsType )
/** Set/Get the number of generations to continue with minimal improvement in
* the function value, |f_best(g_i) - f_best(g_k)| &bounds,
unsigned int n );
ParameterBoundsType GetParameterBounds() const;
/** The optimization algorithm will terminate when the function improvement
* in the last m_NumberOfGenerationsWithMinimalImprovement generations
* is less than m_FunctionConvergenceTolerance and the maximal distance
* between particles and the best particle in each dimension is less than
* m_ParametersConvergenceTolerance[i] for the specified percentage of the
* particles.
* That is, we haven't improved the best function value for a while and in
* the parameter space most (m%) of our particles attained their best value
* close to the swarm's best value.
* NOTE: The use of different tolerances for each dimension is desired when
* optimizing over non-commensurate parameters (e.g. rotation and
* translation). Alternatively, we could use ITK's parameter scaling
* approach. The current approach seems more intuitive.
*/
itkSetMacro( FunctionConvergenceTolerance, MeasureType )
itkGetMacro( FunctionConvergenceTolerance, MeasureType )
/**Set parameters convergence tolerance using the same value for all, sz,
parameters*/
void SetParametersConvergenceTolerance( ValueType convergenceTolerance,
unsigned int sz );
itkSetMacro( ParametersConvergenceTolerance, ParametersType )
itkGetMacro( ParametersConvergenceTolerance, ParametersType )
itkGetMacro( PercentageParticlesConverged, double )
itkSetMacro( PercentageParticlesConverged, double )
/**Set the random number seed for the swarm. Use this method to
* produce reaptible results, typically, for testing.
*/
itkSetMacro( Seed, RandomVariateGeneratorType::IntegerType)
itkGetMacro( Seed, RandomVariateGeneratorType::IntegerType)
/** Use a specific seed to initialize the random number
* generator. If On, use m_Seed to seed the random number
* generator. Default is Off. */
itkSetMacro( UseSeed, bool )
itkGetMacro( UseSeed, bool )
itkBooleanMacro( UseSeed)
/** Get the function value for the current position.
* NOTE: This value is only valid during and after the execution of the
* StartOptimization() method.*/
MeasureType GetValue() const;
/** Get the reason for termination */
virtual const std::string GetStopConditionDescription() const ITK_OVERRIDE;
/** Print the swarm information to the given output stream. Each line
* (particle data) is of the form:
* current_parameters current_velocity current_value best_parameters best_value
*/
void PrintSwarm( std::ostream& os, Indent indent ) const;
protected:
ParticleSwarmOptimizerBase();
virtual ~ParticleSwarmOptimizerBase() ITK_OVERRIDE;
virtual void PrintSelf( std::ostream& os, Indent indent ) const ITK_OVERRIDE;
void PrintParamtersType( const ParametersType& x, std::ostream& os ) const;
/**
* Implement your update rule in this function.*/
virtual void UpdateSwarm() = 0;
ITK_DISALLOW_COPY_AND_ASSIGN(ParticleSwarmOptimizerBase);
virtual void ValidateSettings();
/**
* Initialize the particle swarm, and seed the random number generator.
*/
virtual void Initialize();
void RandomInitialization();
void FileInitialization();
bool m_PrintSwarm;
std::ostringstream m_StopConditionDescription;
bool m_InitializeNormalDistribution;
NumberOfParticlesType m_NumberOfParticles;
NumberOfIterationsType m_MaximalNumberOfIterations;
NumberOfGenerationsType m_NumberOfGenerationsWithMinimalImprovement;
ParameterBoundsType m_ParameterBounds;
ParametersType m_ParametersConvergenceTolerance;
double m_PercentageParticlesConverged;
CostFunctionType::MeasureType m_FunctionConvergenceTolerance;
std::vector m_Particles;
CostFunctionType::MeasureType m_FunctionBestValue;
std::vector m_FunctionBestValueMemory;
ParametersType m_ParametersBestValue;
NumberOfIterationsType m_IterationIndex;
RandomVariateGeneratorType::IntegerType m_Seed;
bool m_UseSeed;
};
} // end namespace itk
#endif