System Architecture
The two main classes
freneticlib features two primary classes: FreneticCore
and Frenetic
.
FreneticCore
is responsible for generation of road representations and the genetic algorithm methodology.It applies the correct mutation and crossover operators and iteratively yields new roads.
Frenetic
is the orchestrator of the execution flow.It asks
FreneticCore
for new roads and triggers the indivudal roads’ simulation. Furthermore, it monitors the stop criterion.
Other classes
Both Frenetic
and FreneticCore
have several other dependencies.
Note, however, that all these dependencies are abstract,
meaning that users may freely choose one of the pre-defined concrete implementations
of those abstract classes, or, alternatively, provide their own.
The respective dependencies are shown in the following class diagram:
Note
This is a reduced class diagram, exemplifying the (abstract) dependencies. freneticlib provides (several) ready-for-use implementations for every abstract class, including representations, mutation and crossover operators.
Please refer to the Usage Examples and the API Reference for details on the available classes.
What happens after you .start()
When calling the Frenetic
class’s start()
method,
the class will trigger the random search phase.
The phase lasts as long as the stop criterion’s
is_random_phase()
returns True
.
In this phase, Frenetic
uses FreneticCore.ask_random()
to obtain random roads,
generated according to the chosen RoadRepresentation
. Thus, internally, FreneticCore.ask_random()
calls RoadRepresentation.generate()
.
Subsequently, the road (a.k.a. test) is handed over to the defined Executor
’s execute_test(test)()
,
which is responsible for:
transformation from the road representation to cartesian coordinates,
creating the simulation artefacts (e.g. required map & configuration files),
execution of the simulation, and
extraction of the simulation data.
Afterwards, Frenetic
informs the core about the simulation result via FreneticCore.tell(exec_data)()
,
and launches the next iteration.
Note
In the figure below, the methods run_simulation()
and extract_data()
are mere indicators
for what is happening. In fact, an executor has only one required method, namely Executor._execute()
,
which is automatically called by Executor.execute_test()
.
After the random search, Frenetic
will proceed to the genetic phase,
where a genetic algorithm methodology is applied.
The execution flow is very similar to the random phase, with the difference that now, Frenetic
calls
FreneticCore.ask()
to obtain a new road. This road is yielded after applying mutation or crossover operators on
the previously simulated roads.
Depending on the outcome, different mutation operaters may be applied (referred to as mutators and exploiters),
to enable small (exploitation) or major (exploration) modification.
The rest of the loop (Executor.execute_test()
, FreneticCore.tell()
) is equivalent to the random phase.