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 fromAbstractOptimizertypeindividual, 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) -> BoolReturn 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
endThe 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 metricat 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.