migrating - morinim/ultra GitHub Wiki
Generally speaking migrating code from Vita isn't too hard: Ultra has a simpler interface but the backbone structure is similar in many respects.
Many of the examples have been ported to Ultra and are a good starting point for understanding the differences.
The majority of class specializations have their own namespace. So instead of vita::de_problem, vita::de_search, vita::de_individual, ultra::src_search you should use ultra:de::problem, ultra:de::search, ultra::de::individual, ultra::src::search.
You usually haven't to specify template arguments since they're automatically deduced:
vita::de_search<decltype(neg_rastrigin)> search(prob, neg_rastrigin);is now the simpler:
de::search search(prob, neg_rastrigin);environment class has been renamed to parameters and parameters have been grouped by category. E.g.
environment env;
env.p_mutation = 0.6;
env.tournament_size = 3;becomes
parameters params;
params.evolution.p_mutation = 0.6;
params.evolution.tournament_size = 3;Return results of a search are contained in a different structure (search_stats defined in kernel/search.h). So, for example, the usual access to the best individual / fitness changes from:
const auto res(search.run());
const auto solution(res.best.solution);
const auto value(res.best.score.fitness);to
const auto res(search.run());
const auto solution(res.best_individual);
const auto value(*res.best_measurements.fitness);Note that scores contained in the search_stats struct are optional values hence the * to get the fitness.
The threshold for identifying successful runs isn't specified anymore in the environment / parameters structure but is passed to the search::run member functions:
environment env;
env.threshold.fitness = -0.5;
// ...
src_search s(prob);
const auto result(s.run(10));should be replaced with
model_measurements<double> threshold;
mm.fitness = -0.5;
// ...
src::search s(prob);
const auto result(s.run(10, threshold));All the search strategies can be used enabling multiple layers / subgroups (prob.params.population.init_subgroups > 1). Evolution happens in parallel for every subgroup. Many algorithms take advantage of this organization to explore different search spaces, possibly using different parameters; anyway the can be executed in single thread mode.
ALPS, otherwise, is conceived to exchange information among subgroups and, even if started with a single layer, will add further layers during the evolution (thus enabling concurrency).
Concurrency is a great performance boost but makes evolution non-repeatable.
There isn't anymore a fixed type for representing fitness. User can employ the type more appropriate for the specific task provided that it satisfies the Fitness concept. However a fitnd class is available for filling the gap.
Serialisation of floating point values now uses hexadecimal format (std::hexfloat) for improved precision and performance:
- no rounding occurs when writing or reading a value formatted in this way;
- operations on such values can be faster with a well tuned I/O library;
- fewer digits are required to represent values exactly.
Existing serialisation files have to accommodate this change.
As before, the data are written in a CSV-like fashion and are partitioned into blocks separated by two blank lines:
[BLOCK_1]\n\n
[BLOCK_2]\n\n
...
[BLOCK_x]
where each block is a set of lines such as this:
data_1 [space] data_2 [space] ... [space] data_n
The data_x fields are somewhat changed, they're less human readable but automatic parsing is simpler (see the WOPR tool and the search_log.tcc file).
sr is no longer available, but a large part of its functionality is now accessible via the wopr test or wopr test --nogui command (see WOPR). One important difference is that wopr runs tests in parallel, which may put significant stress on the system.