# Genetic Algorithms in OpenMOLE

OpenMOLE make an intensive use of genetic algorithms (GA) in its various methods : whereas it deals with model calibration (which is an optimization problem) or a diversity of outputs research like in PSE (which boils down to Genetic algorithms with a novelty incentive).

GAs can be smartly distributed on grid environments using islands scheme, and and be able to deal with model stochasticity .

OpenMOLE provides advanced methods to help you calibrate your model. These methods automatically generate workflows to explore your model's parameter space towards the best parameter set according to a previously defined goal (or objective or criterion) . This is commonly addressed in literature as a calibration/optimization methods.

Calibration methods of OpenMOLE use Genetic Algorithms to explore the parameter space of a simulation model, looking for parameter sets that will produce outputs that reach one or several given objectives. Objectives functions,also called fitness functions, compute quantities from model outputs that have to be minimized or maximized ; they're a quantification of the characteristics of what is the optimal model output according to what you're looking for.

One common use case is optimization to fit some data. Objective function could be a distance function between simulation results and data ; a classical example is the Squared Error function.
If you want your model to reproduce several characteristics (sometimes called stylised facts), you need several objectives, each of them quantifying the similarity between your model outputs and the characteristics you want to reproduce.

To calibrate your model, you need to define:
• the genome of your model, i.e. the parameters to be calibrated. They are the dimensions of the parameter space that will be explored by the genetic algorithm. GA will try different genomes, and keep the best discovered ever since.
• the objectives you want to reach, expressed as variables to be minimized.
• a termination criterion, to stop the method eventually

# Dummy Model Optimization Example

This workflow optimises a dummy model using the generational NSGA II multi-objective algorithm. You can replace the instances of model by your own model and adapt the variation range of its input variables. If you're not familiar with parameter tuning using Genetic Algorithms (GA), you should first consult the tutorial explaining how to calibrate a NetLogo model with a GA.
``````//model inputs
val x = Val[Double]
val y = Val[Double]
//model outputs
val o1 = Val[Double]
val o2 = Val[Double]

val model =
ScalaTask("val o1 = x; val o2 = y") set (
inputs += (x, y),
outputs += (o1, o2)
)

// Construction of the workflow orchestrating the genetic algorithm
// termination is the termination criterion, here it runs for 100 generations. A time limit could be set as an
// alternative by replacing 100 by 1 hour (hour is a duration type understood by OpenMOLE).
// the parallelism specifies how many evaluation are concurrently submitted to the execution environment
val evolution =
// Definition of the optimisation algorithm
// mu is the size of the population
// genome is the inputs prototype and their variation ranges
// objectives are the objectives to minimise
algorithm =
NSGA2(
mu = 100,
genome = Seq(x in (0.0, 1.0), y in (0.0, 1.0)),
objectives = Seq(o1, o2)
),
evaluation = model,
parallelism = 10,
termination = 100
)

// Definition of a hook to save the population of solutions to /tmp/evolution on the local machine running OpenMOLE
val savePopulation = SavePopulationHook(evolution, workDirectory / "evolution/")

// Construction of the complete workflow with the execution environment, and the hook.
// Here the generated workflow will run using 4 threads of the local machine.
(evolution hook savePopulation on LocalEnvironment(4))``````

Notice that the objectives are given as a sequence of model outputs variables to minimize.
So if you want to reach specific target values, like Pi and 42 you can use the DeltaTask an plug it after your model:
``````//model inputs
val x = Val[Double]
val y = Val[Double]
//model outputs
val o1 = Val[Double]
val o2 = Val[Double]

val model =
ScalaTask("val o1 = x; val o2 = y") set (
inputs += (x, y),
outputs += (o1, o2)
)

val evolution =
// Definition of the optimisation algorithm
// mu is the size of the population
// genome is the inputs prototype and their variation ranges
// objectives are the objectives to minimise
algorithm =
NSGA2(
mu = 100,
genome = Seq(x in (0.0, 1.0), y in (0.0, 1.0)),
objectives = Seq(o1, o2)
),
evaluation = model -- DeltaTask(o1 -> math.Pi, o2 -> 42),
parallelism = 10,
termination = 100
)``````

NB: in this case the results in the saved file in will be the difference between the outputs of the model and your objectives.

Obviously, maximization problem are performed by taking the opposite of variables as objectives. You may use a ScalaTask in place of the DeltaTask to perform such a small computations in the workflow.

``````//model inputs
val x = Val[Double]
val y = Val[Double]
//model outputs
val o1 = Val[Double]
val o2 = Val[Double]

val model =
ScalaTask("val o1 = x; val o2 = y") set (
inputs += (x, y),
outputs += (o1, o2)
)

val maximize = ScalaTask("o1 = -o1") set ((inputs, outputs) += (o1, o2))

val evolution =
// Definition of the optimisation algorithm
// mu is the size of the population
// genome is the inputs prototype and their variation ranges
// objectives are the objectives to minimise
algorithm =
NSGA2(
mu = 100,
genome = Seq(x in (0.0, 1.0), y in (0.0, 1.0)),
objectives = Seq(o1, o2)
),
evaluation = model -- maximize,
parallelism = 10,
termination = 100
)``````

# Real world Example

This tutorial exposes how to use Genetic Algorithms to perform optimization on a NetlogModel.