-
-
Notifications
You must be signed in to change notification settings - Fork 0
symbolic_regression_part3
A custom evaluator is nice but not enough. What I really need is a way to evolve multiple programs at the same time and then apply my evaluator. Can it be done?
Yes, it's possible using a team.
This is similar to the previous problem but requires the evolution of multiple candidate solutions at the same time.
const auto a = get_vector(); // N-dimensional vector
const auto b = get_matrix(); // NxN matrix
This time a
and b
aren't scalar. We use two support functions to generate a random vector and a random matrix of the appropriate dimensions.
Once again, the evaluator needs various changes:
using candidate_solution = ultra::gp::team<ultra::gp::individual>;
// Given a team (i.e. a candidate solution of the problem), returns a score
// measuring how good it is.
[[nodiscard]] double my_evaluator(const candidate_solution &x)
{
using namespace ultra;
std::vector<double> f(N);
std::ranges::transform(
x, f.begin(),
[](const auto &prg)
{
const auto ret(run(prg));
return has_value(ret) ? std::get<D_DOUBLE>(ret) : 0.0;
});
std::vector<double> model(N, 0.0);
for (unsigned i(0); i < N; ++i)
for (unsigned j(0); j < N; ++j)
model[i] += b(i, j) * f[j];
double delta(std::inner_product(a.begin(), a.end(), model.begin(), 0.0,
std::plus{},
[](auto v1, auto v2)
{
return std::fabs(v1 - v2);
}));
return -delta;
}
The candidate_solution
is a team of individuals/programs. The members of a team are always selected, evaluated, and varied simultaneously, so they undergo a co-evolutionary process.
A line-by-line description of the evaluation process follows:
std::vector<double> f(N);
std::ranges::transform(
x, f.begin(),
[](const auto &prg)
{
const auto ret(run(prg));
return has_value(ret) ? std::get<D_DOUBLE>(ret) : 0.0;
});
This time f
is a vector (where we store the results of the components of the team/candidate solution).
std::vector<double> model(N, 0.0);
for (unsigned i(0); i < N; ++i)
for (unsigned j(0); j < N; ++j)
model[i] += b(i, j) * f[j];
Mathematically the code is equivalent to:
As before delta
is a measure of the error based on the absolute value:
double delta(std::inner_product(a.begin(), a.end(), model.begin(), 0.0,
std::plus{},
[](auto v1, auto v2)
{
return std::fabs(v1 - v2);
}));
std::inner_product
performs an ordered map/reduce operation on a
and model
. Mathematically:
Only one line of the main()
function varies:
prob.params.team.individuals = N;
to inform the search engine of the team size.
(for your ease, all the code is in the examples/symbolic_regression04.cc file)