1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
|
// SPDX-License-Identifier: LGPL-3.0-or-later
// Author: Kristian Lytje
#include <mini/Minimizer.h>
#include <mini/detail/Evaluation.h>
#include <mini/detail/Parameter.h>
#include <mini/detail/FittedParameter.h>
#include <utility/Exceptions.h>
#include <settings/GeneralSettings.h>
#include <functional>
using namespace ausaxs;
using namespace ausaxs::mini;
Minimizer::Minimizer() = default;
Minimizer::~Minimizer() = default;
Minimizer::Minimizer(double(&f)(std::vector<double>)) {
set_function(f);
}
Minimizer::Minimizer(std::function<double(std::vector<double>)>&& f) {
set_function(std::move(f));
}
Result Minimizer::minimize() {
if (!is_parameter_set()) {throw except::bad_order("Minimizer::minimize: No parameters were supplied.");}
if (!is_function_set()) {throw except::bad_order("Minimizer::minimize: No function was set.");}
clear_evaluated_points();
return minimize_override();
}
void Minimizer::set_function(double(&f)(std::vector<double>)) {
raw = std::bind(f, std::placeholders::_1);
set_function(std::move(raw));
}
void Minimizer::set_function(std::function<double(std::vector<double>)>&& f) {
raw = std::move(f);
wrapper = [this] (std::vector<double> p) {
double fval = raw(p);
evaluations.evals.push_back(Evaluation(std::move(p), fval));
fevals++;
return fval;
};
function = wrapper;
}
bool Minimizer::empty() const noexcept {
return !is_function_set() && !is_parameter_set();
}
void Minimizer::clear_parameters() noexcept {
parameters.clear();
}
void Minimizer::record_evaluations(bool setting) {
function = setting ? wrapper : raw;
}
void Minimizer::add_parameter(const Parameter& param) {
if (!param.has_bounds() && !param.has_guess()) {
throw except::invalid_argument("Minimizer::add_parameter: Parameter \"" + param.name + "\"must either have a limit or a guess value.");
}
parameters.push_back(param);
}
void Minimizer::clear_evaluated_points() noexcept {
evaluations.evals.clear();
}
bool Minimizer::is_function_set() const noexcept {
return bool(function); // functions are explicitly convertable to a bool which is true if a function has been set
}
bool Minimizer::is_parameter_set() const noexcept {
return !parameters.empty();
}
mini::Landscape Minimizer::get_evaluated_points() const {
if (evaluations.evals.empty()) {throw except::bad_order("Minimizer::get_evaluated_points: Cannot get evaluated points before a minimization call has been made.");}
return evaluations;
}
mini::Landscape Minimizer::landscape(unsigned int bins) {
if (parameters.empty()) {throw except::bad_order("Minimizer::landscape: No parameters were supplied.");}
mini::Landscape l;
auto bx = parameters[0].bounds.value();
for (unsigned int i = 0; i < bins; i++) {
double vx = bx.min + i*bx.span()/(bins-1);
double fval;
if (parameters.size() == 2) {
auto by = parameters[1].bounds.value();
for (unsigned int j = 0; j < bins; j++) {
double vy = by.min + j*by.span()/(bins-1);
fval = function({vx, vy});
l.evals.emplace_back(Evaluation{{vx, vy}, fval});
}
} else {
fval = function({vx});
l.evals.emplace_back(Evaluation{{vx}, fval});
}
// sanity check
if (std::isnan(fval) || std::isinf(fval)) {
if (settings::general::verbose) {std::cout << "Warning in Minimizer::landscape: Function value is nan or inf and will be skipped." << std::endl;}
l.evals.pop_back();
continue;
}
}
return l;
}
void Minimizer::set_max_evals(unsigned int max_evals) {
this->max_evals = max_evals;
}
|