/*========================================================================= * * Copyright NumFOCUS * * 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 * * https://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: ITK_DISALLOW_COPY_AND_MOVE(ParticleSwarmOptimizerBase); /** Standard "Self" type alias. */ using Self = ParticleSwarmOptimizerBase; using Superclass = SingleValuedNonLinearOptimizer; using Pointer = SmartPointer; using ConstPointer = SmartPointer; /** \see LightObject::GetNameOfClass() */ itkOverrideGetNameOfClassMacro(ParticleSwarmOptimizerBase); using ParameterBoundsType = std::vector>; struct ParticleData { ParametersType m_CurrentParameters; ParametersType m_CurrentVelocity; CostFunctionType::MeasureType m_CurrentValue; ParametersType m_BestParameters; CostFunctionType::MeasureType m_BestValue; }; using SwarmType = std::vector; using NumberOfIterationsType = unsigned int; using NumberOfParticlesType = unsigned int; using NumberOfGenerationsType = unsigned int; using MeasureType = CostFunctionType::MeasureType; using ValueType = ParametersType::ValueType; using RandomVariateGeneratorType = Statistics::MersenneTwisterRandomVariateGenerator; /** 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. */ void StartOptimization() 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 repeatable 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 */ const std::string GetStopConditionDescription() const 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(); ~ParticleSwarmOptimizerBase() override; void PrintSelf(std::ostream & os, Indent indent) const override; void PrintParamtersType(const ParametersType & x, std::ostream & os) const; /** * Implement your update rule in this function.*/ virtual void UpdateSwarm() = 0; 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{ 0 }; std::vector m_FunctionBestValueMemory{}; ParametersType m_ParametersBestValue{}; NumberOfIterationsType m_IterationIndex{ 0 }; RandomVariateGeneratorType::IntegerType m_Seed{}; bool m_UseSeed{}; }; } // end namespace itk #endif