System Architecture¶
The two main classes¶
freneticlib features two primary classes: FreneticCore and Frenetic.
FreneticCoreis responsible for generation of road representations and the genetic algorithm methodology.It applies the correct mutation and crossover operators and iteratively yields new roads.
Freneticis the orchestrator of the execution flow.It asks
FreneticCorefor 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.