Skip to content

Commit

Permalink
cli programs: allow selection of the objective in the command line
Browse files Browse the repository at this point in the history
  • Loading branch information
foolnotion committed Jan 24, 2024
1 parent dd38e57 commit 8080aa2
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 49 deletions.
64 changes: 34 additions & 30 deletions cli/source/operator_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ auto ParseSelector(std::string const& str, ComparisonCallback&& comp) -> std::un
} else if (name == "random") {
selector = std::make_unique<Operon::RandomSelector>();
}

return selector;
}

Expand All @@ -81,51 +81,55 @@ auto ParseCreator(std::string const& str, PrimitiveSet const& pset, std::vector<
return creator;
}

auto ParseEvaluator(std::string const& str, Problem& problem, DefaultDispatch& dtable) -> std::unique_ptr<EvaluatorBase>
auto ParseEvaluator(std::string const& str, Problem& problem, DefaultDispatch& dtable, bool scale) -> std::unique_ptr<EvaluatorBase>
{
using T = DefaultDispatch;

std::unique_ptr<EvaluatorBase> evaluator;
if (str == "r2") {
evaluator = std::make_unique<Operon::Evaluator<T>>(problem, dtable, Operon::R2{}, true);
evaluator = std::make_unique<Operon::Evaluator<T>>(problem, dtable, Operon::R2{}, scale);
} else if (str == "c2") {
evaluator = std::make_unique<Operon::Evaluator<T>>(problem, dtable, Operon::C2{}, false);
evaluator = std::make_unique<Operon::Evaluator<T>>(problem, dtable, Operon::C2{}, scale);
} else if (str == "nmse") {
evaluator = std::make_unique<Operon::Evaluator<T>>(problem, dtable, Operon::NMSE{}, true);
evaluator = std::make_unique<Operon::Evaluator<T>>(problem, dtable, Operon::NMSE{}, scale);
} else if (str == "mse") {
evaluator = std::make_unique<Operon::Evaluator<T>>(problem, dtable, Operon::MSE{}, true);
evaluator = std::make_unique<Operon::Evaluator<T>>(problem, dtable, Operon::MSE{}, scale);
} else if (str == "rmse") {
evaluator = std::make_unique<Operon::Evaluator<T>>(problem, dtable, Operon::RMSE{}, true);
evaluator = std::make_unique<Operon::Evaluator<T>>(problem, dtable, Operon::RMSE{}, scale);
} else if (str == "mae") {
evaluator = std::make_unique<Operon::Evaluator<T>>(problem, dtable, Operon::MAE{}, true);
evaluator = std::make_unique<Operon::Evaluator<T>>(problem, dtable, Operon::MAE{}, scale);
} else if (str == "mdl") {
evaluator = std::make_unique<Operon::MinimumDescriptionLengthEvaluator<T>>(problem, dtable);
} else if (str == "gauss") {
evaluator = std::make_unique<Operon::GaussianLikelihoodEvaluator<T>>(problem, dtable);
} else {
throw std::runtime_error(fmt::format("Unknown metric {}\n", str));
}
return evaluator;
}

auto ParseErrorMetric(std::string const& str) -> std::tuple<std::unique_ptr<ErrorMetric>, bool>
{
std::unique_ptr<ErrorMetric> error;
bool scale{true};
if (str == "r2") {
error = std::make_unique<Operon::R2>();
} else if (str == "c2") {
scale = false;
error = std::make_unique<Operon::C2>();
} else if (str == "nmse") {
error = std::make_unique<Operon::NMSE>();
} else if (str == "mse") {
error = std::make_unique<Operon::MSE>();
} else if (str == "rmse") {
error = std::make_unique<Operon::RMSE>();
} else if (str == "mae") {
error = std::make_unique<Operon::MAE>();
} else {
throw std::runtime_error(fmt::format("Unknown metric {}\n", str));
}
return std::make_tuple(std::move(error), scale);
}
// auto ParseErrorMetric(std::string const& str) -> std::tuple<std::unique_ptr<ErrorMetric>, bool>
// {
// std::unique_ptr<ErrorMetric> error;
// bool scale{true};
// if (str == "r2") {
// error = std::make_unique<Operon::R2>();
// } else if (str == "c2") {
// scale = false;
// error = std::make_unique<Operon::C2>();
// } else if (str == "nmse") {
// error = std::make_unique<Operon::NMSE>();
// } else if (str == "mse") {
// error = std::make_unique<Operon::MSE>();
// } else if (str == "rmse") {
// error = std::make_unique<Operon::RMSE>();
// } else if (str == "mae") {
// error = std::make_unique<Operon::MAE>();
// } else {
// throw std::runtime_error(fmt::format("Unknown metric {}\n", str));
// }
// return std::make_tuple(std::move(error), scale);
// }

auto ParseGenerator(std::string const& str, EvaluatorBase& eval, CrossoverBase& cx, MutatorBase& mut, SelectorBase& femSel, SelectorBase& maleSel) -> std::unique_ptr<OffspringGeneratorBase>
{
Expand Down
2 changes: 1 addition & 1 deletion cli/source/operator_factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ auto ParseSelector(std::string const& str, ComparisonCallback&& comp) -> std::un

auto ParseCreator(std::string const& str, PrimitiveSet const& pset, std::vector<Operon::Hash> const& inputs) -> std::unique_ptr<CreatorBase>;

auto ParseEvaluator(std::string const& str, Problem& problem, DefaultDispatch& dtable) -> std::unique_ptr<EvaluatorBase>;
auto ParseEvaluator(std::string const& str, Problem& problem, DefaultDispatch& dtable, bool scale = true) -> std::unique_ptr<EvaluatorBase>;

auto ParseErrorMetric(std::string const& str) -> std::tuple<std::unique_ptr<Operon::ErrorMetric>, bool>;

Expand Down
19 changes: 9 additions & 10 deletions cli/source/operon_gp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,14 +215,14 @@ auto main(int argc, char** argv) -> int
mutator.Add(removeSubtree, 1.0);
mutator.Add(discretePoint, 1.0);

auto const& [error, scale] = Operon::ParseErrorMetric(result["error-metric"].as<std::string>());
Operon::DefaultDispatch dtable;
Operon::Evaluator evaluator(problem, dtable, *error, scale);
evaluator.SetBudget(config.Evaluations);
auto scale = result["linear-scaling"].as<bool>();
auto evaluator = Operon::ParseEvaluator(result["objective"].as<std::string>(), problem, dtable, scale);
evaluator->SetBudget(config.Evaluations);

auto optimizer = std::make_unique<Operon::LevenbergMarquardtOptimizer<decltype(dtable), Operon::OptimizerType::Eigen>>(dtable, problem);
optimizer->SetIterations(config.Iterations);
evaluator.SetOptimizer(optimizer.get());
dynamic_cast<Operon::Evaluator<Operon::DefaultDispatch>*>(evaluator.get())->SetOptimizer(optimizer.get());

EXPECT(problem.TrainingRange().Size() > 0);

Expand All @@ -231,7 +231,7 @@ auto main(int argc, char** argv) -> int
auto femaleSelector = Operon::ParseSelector(result["female-selector"].as<std::string>(), comp);
auto maleSelector = Operon::ParseSelector(result["male-selector"].as<std::string>(), comp);

auto generator = Operon::ParseGenerator(result["offspring-generator"].as<std::string>(), evaluator, crossover, mutator, *femaleSelector, *maleSelector);
auto generator = Operon::ParseGenerator(result["offspring-generator"].as<std::string>(), *evaluator, crossover, mutator, *femaleSelector, *maleSelector);
auto reinserter = Operon::ParseReinserter(result["reinserter"].as<std::string>(), comp);

Operon::RandomGenerator random(config.Seed);
Expand Down Expand Up @@ -372,10 +372,10 @@ auto main(int argc, char** argv) -> int
T{ "nmse_te", nmseTest, format },
T{ "avg_fit", avgQuality, format },
T{ "avg_len", avgLength, format },
T{ "eval_cnt", evaluator.CallCount , ":>" },
T{ "res_eval", evaluator.ResidualEvaluations, ":>" },
T{ "jac_eval", evaluator.JacobianEvaluations, ":>" },
T{ "opt_time", evaluator.CostFunctionTime, ":>" },
T{ "eval_cnt", evaluator->CallCount , ":>" },
T{ "res_eval", evaluator->ResidualEvaluations, ":>" },
T{ "jac_eval", evaluator->JacobianEvaluations, ":>" },
T{ "opt_time", evaluator->CostFunctionTime, ":>" },
T{ "seed", config.Seed, ":>" },
T{ "elapsed", elapsed, ":>"},
};
Expand All @@ -391,4 +391,3 @@ auto main(int argc, char** argv) -> int

return 0;
}

12 changes: 5 additions & 7 deletions cli/source/operon_nsgp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,20 +222,19 @@ auto main(int argc, char** argv) -> int
mutator.Add(removeSubtree, 1.0);
mutator.Add(discretePoint, 1.0);

auto const& [error, scale] = Operon::ParseErrorMetric(result["error-metric"].as<std::string>());
Operon::DefaultDispatch dtable;

Operon::Evaluator errorEvaluator(problem, dtable, *error, scale);
errorEvaluator.SetBudget(config.Evaluations);
auto scale = result["linear-scaling"].as<bool>();
auto errorEvaluator = Operon::ParseEvaluator(result["objective"].as<std::string>(), problem, dtable, scale);
errorEvaluator->SetBudget(config.Evaluations);

auto optimizer = std::make_unique<Operon::LevenbergMarquardtOptimizer<decltype(dtable), Operon::OptimizerType::Eigen>>(dtable, problem);
optimizer->SetIterations(config.Iterations);
errorEvaluator.SetOptimizer(optimizer.get());
dynamic_cast<Operon::Evaluator<Operon::DefaultDispatch>*>(errorEvaluator.get())->SetOptimizer(optimizer.get());
Operon::LengthEvaluator lengthEvaluator(problem, maxLength);

Operon::MultiEvaluator evaluator(problem);
evaluator.SetBudget(config.Evaluations);
evaluator.Add(errorEvaluator);
evaluator.Add(*errorEvaluator);
evaluator.Add(lengthEvaluator);

EXPECT(problem.TrainingRange().Size() > 0);
Expand Down Expand Up @@ -405,4 +404,3 @@ auto main(int argc, char** argv) -> int

return 0;
}

3 changes: 2 additions & 1 deletion cli/source/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ auto InitOptions(std::string const& name, std::string const& desc, int width) ->
("target", "Name of the target variable (required)", cxxopts::value<std::string>())
("inputs", "Comma-separated list of input variables", cxxopts::value<std::string>())
("epsilon", "Tolerance for fitness comparison (needed e.g. for eps-dominance)", cxxopts::value<Operon::Scalar>()->default_value("1e-6"))
("error-metric", "The error metric used for calculating fitness", cxxopts::value<std::string>()->default_value("r2"))
("objective", "The error metric used for calculating fitness", cxxopts::value<std::string>()->default_value("r2"))
("linear-scaling", "Apply linear scaling on model predictions", cxxopts::value<bool>()->default_value("true"))
("population-size", "Population size", cxxopts::value<size_t>()->default_value("1000"))
("pool-size", "Recombination pool size (how many generated offspring per generation)", cxxopts::value<size_t>()->default_value("1000"))
("seed", "Random number seed", cxxopts::value<Operon::RandomGenerator::result_type>()->default_value("0"))
Expand Down

0 comments on commit 8080aa2

Please sign in to comment.