evolved-ge is a modular Java framework for experimenting with Grammatica Evolution (GE), an Evolutionary Algorith (EA) often considered a form of Genetic Programming (GP). evolved-ge can be used to:
- apply existing GE variants to user-provided problems;
- investigate about specific aspects of existing variants (e.g., diversity, locality, redundancy, evolvability);
- design and assess new variants or extensions.
It currently contains the implementations of several mappers:
- standard GE mapper [1];
- breath-first mapper (used in [2]);
- piGE mapper [3];
- SGE mapper [4] (and a variant);
- WHGE/HGE mapper [5].
Moreover, beyond the mapper, it can operate with different EA-related settings:
- diversity promotion [6];
- different replacement strategies, different selection criteria, different genetic operators.
Finally, it can be easily configured and instrumented to output several metrics describing ongoing evolutions. Among them, there is the visualization tool called DU Map [7].
The user is expected to provide the problem as a Problem
object including:
- the
Grammar
defining the language for the solutions (can be loaded from a text file withUtils.parseFromFile()
) - the
FintessComputer
to be used for learning - the
Ranker
for individuals (usually one amongComparableRanker
andParetoRanker
)
The FintessComputer
allows evolved-ge to associate each candidate solution with an indication of its ability to solve the problem.
FintessComputer
operates on individuals as trees (Node<T>
): in an individual tree, each leaf node is a terminal symbol of the grammar.
FintessComputer
returns a Fintess
object: currently supported types of fitnesses include NumericFintess
and MultiObjectiveFintess
.
A simple problem example follows.
The goal is to generate a target string: each solution (individual) represents a string and its fitness is given by its distance from the target string (class LeafContentsDistanceFitness
).
public class LeafContentsDistance<T> implements FitnessComputer<T, NumericFitness> {
private final List<T> target;
private final Distance<List<T>> distance;
public LeafContentsDistance(List<T> target, Distance<List<T>> distance) {
this.target = target;
this.distance = distance;
}
@Override
public NumericFitness compute(Node<T> phenotype) {
double d = distance.d(Utils.contents(phenotype.leaves()), target);
return new NumericFitness(d);
}
@Override
public NumericFitness worstValue() {
return new NumericFitness(Double.POSITIVE_INFINITY);
}
}
The BNF grammar of the corresponding problem is:
<text> ::= <sentence> <text> | <sentence>
<sentence> ::= <Word> _ <sentence> | <word> _ <sentence> | <word> <punct>
<word> ::= <letter> <word> | <letter>
<Word> ::= <Letter> <word>
<letter> ::= <vowel> | <consonant>
<vowel> ::= a | o | u | e | i
<consonant> ::= q | w | r | t | y | p | s | d | f | g | h | j | k | l | z | x | c | v | b | n | m
<Letter> ::= <Vowel> | <Consonant>
<Vowel> ::= A | O | U | E | I
<Consonant> ::= Q | W | R | T | Y | P | S | D | F | G | H | J | K | L | Z | X | C | V | B | N | M
<punct> ::= ! | ? | .
Performing an evolutionary run with evolved-ge consists in three steps:
- building a
Configuration
object (suitable for the chosen evolver) - setting zero or more
EvolverListener
- starting the proper
Evolver
A simple code could be (see ExampleMain
):
public final static void main(String[] args) throws IOException, InterruptedException, ExecutionException {
Random random = new Random(1l);
Problem<String, NumericFitness> problem = new HarmonicCurve();
StandardConfiguration<BitsGenotype, String, NumericFitness> configuration = new StandardConfiguration<>(
500,
50,
new RandomInitializer<>(random, new BitsGenotypeFactory(256)),
new Any<BitsGenotype>(),
new StandardGEMapper<>(8, 5, problem.getGrammar()),
new Utils.MapBuilder<GeneticOperator<BitsGenotype>, Double>()
.put(new LengthPreservingTwoPointsCrossover(random), 0.8d)
.put(new ProbabilisticMutation(random, 0.01), 0.2d).build(),
new ComparableRanker<>(new IndividualComparator<BitsGenotype, String, NumericFitness>(IndividualComparator.Attribute.FITNESS)),
new Tournament<Individual<BitsGenotype, String, NumericFitness>>(3, random),
new LastWorst<Individual<BitsGenotype, String, NumericFitness>>(),
500,
true,
problem);
List<EvolverListener<BitsGenotype, String, NumericFitness>> listeners = new ArrayList<>();
listeners.add(new CollectorGenerationLogger<>(
Collections.EMPTY_MAP, System.out, true, 10, " ", " | ",
new Population<BitsGenotype, String, NumericFitness>("%7.2f"),
new NumericFirstBest<BitsGenotype, String>("%6.2f", false),
new Diversity<BitsGenotype, String, NumericFitness>()
));
Evolver<BitsGenotype, String, NumericFitness> evolver = new StandardEvolver<>(
1, configuration, random, false);
List<Node<String>> bests = evolver.solve(listeners);
System.out.printf("Found %d solutions.%n", bests.size());
}
The available evolvers for GE variants include:
- the
StandardEvolver
, which implements the generic m+n replacement strategy with or without overlapping (depending on the values forpopulationSize
(for m),offspringSize
(for n), andoverlapping
fields in theStandardConfiguration
); - the
PartitionEvolver
, which implements the modular diversity promotion mechanism sketched in [6].
The available listeners include:
- a modular
CollectorGenerationLogger
, which at each generation collects ad logs to aPrintStream
(optionally with a customizable format) a set of specified metrics (through some collectors) concerning the current population (e.g., best individual, stats, diversity measure); it can be used to log both on the standard output or on a file (possibly in a csv format); - a
ConfigurationSaverListener
, useful for saving the configuration of each run in an automated execution of several runs.
- Ryan, Conor, J. J. Collins, and Michael O. Neill. "Grammatical evolution: Evolving programs for an arbitrary language." European Conference on Genetic Programming. Springer Berlin Heidelberg, 1998.
- Fagan, David, et al. "An analysis of genotype-phenotype maps in grammatical evolution." European Conference on Genetic Programming. Springer Berlin Heidelberg, 2010.
- O’Neill, Michael, et al. "πgrammatical evolution." Genetic and Evolutionary Computation Conference. Springer Berlin Heidelberg, 2004.
- Lourenço, Nuno, Francisco B. Pereira, and Ernesto Costa. "SGE: a structured representation for grammatical evolution." International Conference on Artificial Evolution (Evolution Artificielle). Springer International Publishing, 2015.
- Medvet, Eric. "Hierarchical Grammatical Evolution." ACM Genetic and Evolutionary Computation Conference (GECCO), 2017
- Medvet, Eric, Alberto Bartoli, and Giovanni Squillero. "An Effective Diversity Promotion Mechanism in Grammatical Evolution" ACM Genetic and Evolutionary Computation Conference (GECCO), 2017
- Medvet, Tušar. "The DU Map: A Visualization to Gain Insights into Genotype-Phenotype Mapping and Diversity." 8th annual workshop on Visualisation in Genetic and Evolutionary Computation (VizGEC), 2017