Java
Creating a new optimisation is straightforward in EvoAl. First, you have to create a new class that implements OptimisationAlgorithm
and annotate it properly:
package com.example;
import lombok.extern.slf4j.Slf4j;
import javax.enterprise.context.Dependent;
import de.evoal.core.api.optimisation.OptimisationAlgorithm;
@Slf4j
@Dependent
@Named("com.example.optimisation.new-algorithm")
public class NewAlgorithm implements OptimisationAlgorithm {
@Override
public OptimisationAlgorithm init(final Instance instance) {
// do initialisation stuff
return this;
}
@Override
public void run() {
// do the actual run
}
}
DSL
For the DSL side, creating a corresponding .dl
file is necessary to declare all possible configuration options. Therefore, you declare a new type that extends de.evoal.core.optimisation.algorithm
. Thus, it inherits different attributes from the base type algorithm
. By declaring additional attributes, you can add any configuration option you need.
import de.evoal.core.math;
import de.evoal.core.optimisation;
module com.example.optimisation {
type 'new-algorithm' extends algorithm {
option : real := 3 * PI;
}
}
Looking up attributes
The example introduces a new attribute named option
with a corresponding default value. There are two options to get the values from an .ol
file. First, you can use CDI and second, programmatically:
public class NewAlgorithm implements OptimisationAlgorithm {
// Option 1) getting value using CDI
@Inject
@ConfigurationValue(entry = CoreBlackboardEntries.OPTIMISATION_CONFIGURATION, access = "algorithm.option")
private double option;
// Option 2) Programmatic
@Inject
private LanguageHelper helper;
@Override
public OptimisationAlgorithm init(final Instance instance) {
// 2) Programmatic lookup
double option = helper.lookup(instance, "option");
return this;
}
// actual run is missing
}
Now, everything is set up for using the newly implemented optimisation algorithm in a .dl
file.
Using pre-implemented options
There are different options for your optimisation algorithm that you can use from the problem definition or the base type algorithm
.
algorithm.initialisation
Helps you to to initialise your population for the optimisation algorithm. You can inject an InitialCandidatesProvider
that you can ask for new candidates. These candidates are generated according to the configuration.
@Inject @Named("initial")
private InitialCandidatesProvider provider;
void do() {
provider.create()
.stream()
// do stuff
;
}
Please be aware that creating a new provider whenever you need an instance may lead to a predictable order of individuals, for instance, when the individuals are read from a file.
algorithm.optimisation-function
Configures the optimisation (aka fitness) function and allows you to inject it via CDI:
@Inject @Named("optimisation-function")
private OptimisationFunction fitness;
void do() {
Properties individual = // get an individual, e.g. from the initial stream
double [] values = fitness.evaluate(individual);
}
algorithm.comparator
Configures the comparator of optimisation values and allows you to inject it via CDI. The comparator may implement different strategies of comparing individuals.
@Inject @Named("comparator")
private OptimisationValueComparator comparator;
void do() {
Properties individual = // get an individual, e.g. from the initial stream
double [] values = fitness.evaluate(individual);
OptimisationValue value = comparator.apply(values);
}
problem.optimisation-space
and problem.search-space
These settings describe the optimisation and the search space. You can get the corresponding PropertiesSpecification
via CDI:
@Inject @Named("search-space-specification")
private PropertiesSpecification searchSpaceSpecification;
@Inject @Named("optimisation-space-specification")
private PropertiesSpecification optimisationSpaceSpecification;
problem.maximise
If the problem is a maximise or minimise problem:
@Inject @Named("problem.maximise")
private boolean maximise;