Development
If you are contributing a new algorithm to this package, you need to know an internal API which allows to add a new algorithm without considerable changes to overall structure of the package.
Adding an algorithm
If you're contributing a new algorithm, you shouldn't need to touch any of the code in src/api/optimize.jl. You should rather add a file named (solver is the name of the solver) algo.jl
in src, and make sure that you define an optimizer parameters and state types, initial_population
that initializes a population of individual
objects, a state type that holds all variables that are (re)used throughout the iterative procedure, an initial_state
that initializes such a state, and an update_state!
method that does the actual work.
Algorithm
Every optimization algorithm have to implement an algorithm parameters type derived from AbstractOptimizer
type, e.g. struct Algo <: AbstractOptimizer end
, with appropriate fields, a default constructor with a keyword for each field.
Function initial_state
returns an initial state for the algorithm, see State section. Function update_state!
returns a Bool
value. If the state update is successfully completed then the function returns false
, otherwise true
.
Evolutionary.AbstractOptimizer
— TypeAbstract evolutionary optimizer algorithm
Evolutionary.initial_state
— FunctionInitialization of ES algorithm state
Initialization of CMA-ES algorithm state
Initialization of GA algorithm state
Initialization of NSGA2 algorithm state
Initialization of DE algorithm state
Initialization of GP algorithm state
State
Every optimization algorithm have to implement a state type derived from AbstractOptimizerState
type, e.g. struct AlgoState <: AbstractOptimizerState end
. All derived types should implement value
and minimizer
functions
Evolutionary.AbstractOptimizerState
— TypeAbstract type for defining an optimizer state
Every algorithm have to implement a state type derived from this abstract type.
NLSolversBase.value
— Methodvalue(state)
Returns a minimum value of the current state
.
Evolutionary.minimizer
— Methodminimizer(state)
Returns a minimizer object in the current state
.
Evolutionary.terminate
— Methodterminate(state)
Returns true
if the state
requires early termination.
Population
The evolutionary algorithms require a collection of individuals, population, which the algorithm constantly modifies. The population collection type must be derived from the AbstractVector
type. Function initial_population
is used for implementing a strategy of population collection initialization.
The initial_population
must accept two parameters:
method
, an algorithm object derived fromAbstractOptimizer
typeindividual
, a description of an individual template used to create the population
Following population initialization strategies are available:
Evolutionary.initial_population
— Functioninitial_population(method, individual::AbstractVector)
Initialize population by replicating the individual
vector.
initial_population(method, individuals::AbstractVector{<:AbstractVector})
Initialize population from the collection of individuals
vectors.
initial_population(method, individual::Function)
Initialize population from the individual
function which returns an individual object.
initial_population(method, individual::AbstractMatrix)
Initialize population by replicating the individual
matrix.
initial_population(method, bounds::ConstraintBounds)
Initialize a random population within the individual bounds
.
initial_population(m::TreeGP, expr::{Expr,Nothing}=nothing)
Initialize a random population of expressions derived from expr
.
Constraints
All constraints derived from the AbstractConstraints
abstract type. For the derived type, the constraints interface functions
have to be implemented. If the derived type wraps a ConstraintBounds
object, the bounds
method should be implemented.
Following auxiliary functions are available for every derived type of AbstractConstraints
.
Evolutionary.isfeasible
— Methodisfeasible(c::AbstractConstraints, x) -> Bool
Return true
if point x
is feasible, given the constraints object c
.
Package provides following additional constrains implementations.
Evolutionary.NoConstraints
— TypeType for an empty set of constratins
Evolutionary.MixedTypePenaltyConstraints
— TypeThis type provides an additional type constraints on the varaibles required for mixed integer optimization problmes.
Objective
Internally, the objective function is wrapped into EvolutionaryObjective
type object.
Evolutionary.EvolutionaryObjective
— TypeWrapper around an objective function (compatible with NLSolversBase).
Evolutionary.EvolutionaryObjective
— MethodEvolutionaryObjective(f, x[, F])
Constructor for an objective function object around the function f
with initial parameter x
, and objective value F
.
Evolutionary.EvolutionaryObjective
— MethodEvolutionaryObjective(f, x::Expr[, F])
Constructor for an objective object for a Julia evaluatable expression.
Evolutionary.ismultiobjective
— Functionismultiobjective(objfun)
Return true
if the function is multi-objective objective.
Parallelization
For additional modes of parallelization of the objective function evaluation, add overrides of the value!
function. By default, the fitness of the population is calculated by the following function:
function value!(obj::EvolutionaryObjective{TC,TF,TX,Val{:serial}}, fitness, population::AbstractVector{IT}) where {IT}
n = length(xs)
for i in 1:n
F[i] = value(obj, xs[i])
end
F
end
The first symbolic value type parameter, :serial
, corresponds to the default value of the parallelization
of the Options
object. Any additional overrides with different value type parameters will be triggered by specifying a corresponded value type symbol in the Options.parallelization
field. A multi-threaded override of the above evaluation is provided.
Convergence Metrics
In order to add a new convergence metric, create a new type derived from ConvergenceMetric
abstract type. In addition, every convergence metric class should implement following interface:
Evolutionary.ConvergenceMetric
— TypeInterface for the convergence metrics
Evolutionary.description
— Functiondescription(metric)
Return a string with a description of the metric
.
Evolutionary.converged
— Functionconverged(metric)
Return true
if the convergence is archived for the metric
.
converged(result)
Returns true
if the optimization successfully converged to a minimum value.
Evolutionary.assess!
— Functionassess!(metric, state)
Asses the convergence of an algorithm using the metric
at the state
.
Evolutionary.diff
— Functiondiff(metric)
Return the value difference for the metric
.
Evolutionary.tolerance
— Functiontolerance(metric)
Return a tolerance value for the metric
.
Note: If the class contains the field Δ
, which holds the current difference between last consecutive convergence function evaluations, then the provided Evolutinary.diff
function will work correctly. Similarly, if the class has the field tol
, which holds a tolerance value, the Evolutionary.tolerance
method will work correctly.