29 const std::vector<std::vector<double>>& epsilons,
30 const std::vector<double>& fitnesses,
double alpha,
32 if (epsilons.empty()) {
33 throw std::invalid_argument(
"ESUpdateGivenPerturbations: epsilons must not be empty");
35 if (epsilons.size() != fitnesses.size()) {
36 throw std::invalid_argument(
"ESUpdateGivenPerturbations: epsilons and fitnesses must have the same size");
39 throw std::invalid_argument(
"ESUpdateGivenPerturbations: sigma must be positive");
41 size_t dim = theta.size();
42 for (
const auto& eps : epsilons) {
43 if (eps.size() != dim) {
44 throw std::invalid_argument(
"ESUpdateGivenPerturbations: every epsilon must match theta's dimension");
48 std::vector<double> gradient_estimate(dim, 0.0);
49 for (
size_t i = 0; i < epsilons.size(); ++i) {
50 for (
size_t d = 0; d < dim; ++d) {
51 gradient_estimate[d] += fitnesses[i] * epsilons[i][d];
55 double scale = alpha / (
static_cast<double>(epsilons.size()) * sigma);
56 std::vector<double> updated(dim);
57 for (
size_t d = 0; d < dim; ++d) {
58 updated[d] = theta[d] + scale * gradient_estimate[d];
70template <
typename FitnessFn,
typename RNG>
71std::vector<double>
ESStep(
const std::vector<double>& theta, FitnessFn fitness_fn,
int population_size,
double sigma,
72 double alpha, RNG& rng) {
73 if (population_size <= 0 || population_size % 2 != 0) {
74 throw std::invalid_argument(
"ESStep: population_size must be a positive even number (mirrored sampling)");
77 throw std::invalid_argument(
"ESStep: sigma must be positive");
80 size_t dim = theta.size();
81 std::normal_distribution<double> noise(0.0, 1.0);
82 std::vector<std::vector<double>> epsilons;
83 std::vector<double> fitnesses;
84 epsilons.reserve(
static_cast<size_t>(population_size));
85 fitnesses.reserve(
static_cast<size_t>(population_size));
87 for (
int i = 0; i < population_size / 2; ++i) {
88 std::vector<double> eps(dim);
89 for (
size_t d = 0; d < dim; ++d) {
92 std::vector<double> neg_eps(dim);
93 for (
size_t d = 0; d < dim; ++d) {
97 std::vector<double> theta_plus(dim);
98 std::vector<double> theta_minus(dim);
99 for (
size_t d = 0; d < dim; ++d) {
100 theta_plus[d] = theta[d] + sigma * eps[d];
101 theta_minus[d] = theta[d] + sigma * neg_eps[d];
104 epsilons.push_back(eps);
105 fitnesses.push_back(fitness_fn(theta_plus));
106 epsilons.push_back(std::move(neg_eps));
107 fitnesses.push_back(fitness_fn(theta_minus));
130template <
typename FitnessFn,
typename RNG>
132 int population_size,
double sigma,
double alpha, RNG& rng) {
134 throw std::invalid_argument(
"RunEvolutionStrategies: initial theta must not be empty");
136 if (num_iterations <= 0) {
137 throw std::invalid_argument(
"RunEvolutionStrategies: num_iterations must be positive");
140 std::vector<double> best_theta = theta;
141 double best_fitness = fitness_fn(theta);
143 for (
int iter = 0; iter < num_iterations; ++iter) {
144 double current_fitness = fitness_fn(theta);
145 if (current_fitness > best_fitness) {
146 best_fitness = current_fitness;
149 theta =
ESStep(theta, fitness_fn, population_size, sigma, alpha, rng);
152 double final_fitness = fitness_fn(theta);
153 if (final_fitness > best_fitness) {
154 best_fitness = final_fitness;
155 best_theta = std::move(theta);
158 return ESResult{std::move(best_theta), best_fitness, num_iterations};
Definition acquisition_functions.hpp:16
std::vector< double > ESUpdateGivenPerturbations(const std::vector< double > &theta, const std::vector< std::vector< double > > &epsilons, const std::vector< double > &fitnesses, double alpha, double sigma)
Pure core: the exact ES parameter update given already-sampled perturbations and their fitness scores...
Definition evolution_strategies.hpp:28
ESResult RunEvolutionStrategies(std::vector< double > theta, FitnessFn fitness_fn, int num_iterations, int population_size, double sigma, double alpha, RNG &rng)
Runs num_iterations of Evolution Strategies starting from theta, tracking the best (theta,...
Definition evolution_strategies.hpp:131
std::vector< double > ESStep(const std::vector< double > &theta, FitnessFn fitness_fn, int population_size, double sigma, double alpha, RNG &rng)
RNG-driven wrapper: samples population_size/2 standard-normal perturbation vectors,...
Definition evolution_strategies.hpp:71
Result of a full Evolution Strategies run.
Definition evolution_strategies.hpp:114
double best_fitness
Definition evolution_strategies.hpp:116
int iterations_run
Definition evolution_strategies.hpp:117
std::vector< double > best_theta
Definition evolution_strategies.hpp:115