# 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`

— Method`value(state)`

Returns a minimum value of the current `state`

.

`Evolutionary.minimizer`

— Method`minimizer(state)`

Returns a minimizer object in the current `state`

.

`Evolutionary.terminate`

— Method`terminate(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 from`AbstractOptimizer`

type`individual`

, a description of an individual template used to create the population

Following population initialization strategies are available:

`Evolutionary.initial_population`

— Function`initial_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`

— Method`isfeasible(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`

— Method`EvolutionaryObjective(f, x[, F])`

Constructor for an objective function object around the function `f`

with initial parameter `x`

, and objective value `F`

.

`Evolutionary.EvolutionaryObjective`

— Method`EvolutionaryObjective(f, x::Expr[, F])`

Constructor for an objective object for a Julia evaluatable expression.

`Evolutionary.ismultiobjective`

— Function`ismultiobjective(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`

— Function`description(metric)`

Return a string with a description of the `metric`

.

`Evolutionary.converged`

— Function`converged(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!`

— Function`assess!(metric, state)`

Asses the convergence of an algorithm using the `metric`

at the `state`

.

`Evolutionary.diff`

— Function`diff(metric)`

Return the value difference for the `metric`

.

`Evolutionary.tolerance`

— Function`tolerance(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.