73 real_value_genetic_optimizer<ObjectiveFunction, BitsPerDimension>> {
80 using objective_function_type = ObjectiveFunction;
83 using variable_type =
typename objective_function_type::variable_type;
86 using variable_scalar_type =
typename variable_type::Scalar;
89 using value_type =
typename objective_function_type::value_type;
92 using random_number_generator_type = std::mt19937;
100 const ObjectiveFunction& obj_fun = ObjectiveFunction())
109 void change_objective_function(
const objective_function_type& obj_fun) {
119 void init(
const variable_type& lower,
const variable_type& upper) {
121 "Lower and upper limits must have the same size.");
124 width_ = upper_ - lower_;
125 dim_ = lower_.size();
127 opt_value_ = std::numeric_limits<value_type>::max();
132 buffer_variable_ = lower_;
134 binary_population_.reserve(population_size_);
136 std::back_inserter(binary_population_), population_size_, [
this]() {
137 binary_variable_type binary_var(dim_);
138 std::generate(binary_var.begin(), binary_var.end(), [
this]() {
139 return random_number_generator_() & binary_mask;
144 population_values_.resize(population_size_);
145 std::transform(binary_population_.begin(), binary_population_.end(),
146 population_values_.begin(),
147 [
this](
const auto& binary_var) { return evaluate_on(binary_var); });
150 prev_binary_population_ = binary_population_;
151 buffer_probabilities_.resize(population_size_);
160 buffer_probabilities_ = (-population_values_).array().exp();
163 for (
index_type i = 1; i < population_size_; ++i) {
164 buffer_probabilities_[i] += buffer_probabilities_[i - 1];
166 const variable_scalar_type sum =
167 buffer_probabilities_(population_size_ - 1);
168 buffer_probabilities_ /= sum;
169 buffer_probabilities_(population_size_ - 1) =
170 static_cast<variable_scalar_type
>(1);
173 std::swap(binary_population_, prev_binary_population_);
175 binary_population_.begin(), binary_population_.end(), [
this]() {
176 const variable_scalar_type probability =
177 probability_distribution_(random_number_generator_);
179 std::lower_bound(buffer_probabilities_.begin(),
180 buffer_probabilities_.end(), probability);
181 const index_type index = iter - buffer_probabilities_.begin();
182 NUM_COLLECT_DEBUG_ASSERT(index < population_size_);
183 return prev_binary_population_[index];
187 for (
index_type i = 0; i < population_size_; i += 2) {
188 const bool do_crossover =
189 crossover_distribution_(random_number_generator_);
194 const binary_scalar_type mask =
195 random_number_generator_() & binary_mask;
196 const binary_scalar_type mask_inv = (~mask) & binary_mask;
197 const binary_scalar_type first_child_scalar =
198 (binary_population_[i][d] & mask) |
199 (binary_population_[i + 1][d] & mask_inv);
200 const binary_scalar_type second_child_scalar =
201 (binary_population_[i][d] & mask_inv) |
202 (binary_population_[i + 1][d] & mask);
203 binary_population_[i][d] = first_child_scalar;
204 binary_population_[i + 1][d] = second_child_scalar;
209 for (
auto& binary_variable : binary_population_) {
210 for (
auto& binary_scalar : binary_variable) {
211 auto mask =
static_cast<binary_scalar_type
>(1);
212 for (
index_type b = 0; b < num_bits_per_dimension; ++b) {
213 if (mutation_distribution_(random_number_generator_)) {
214 binary_scalar ^= mask;
222 std::transform(binary_population_.begin(), binary_population_.end(),
223 population_values_.begin(),
224 [
this](
const auto& binary_var) { return evaluate_on(binary_var); });
232 [[nodiscard]]
auto is_stop_criteria_satisfied() const ->
bool {
233 return evaluations_ >= max_evaluations_;
239 void configure_iteration_logger(logging::iterations::iteration_logger<
240 real_value_genetic_optimizer<ObjectiveFunction>>& iteration_logger)
242 iteration_logger.template append<index_type>(
243 "Iter.", &this_type::iterations);
244 iteration_logger.template append<index_type>(
245 "Eval.", &this_type::evaluations);
246 iteration_logger.template append<value_type>(
247 "Value", &this_type::opt_value);
253 [[nodiscard]]
auto opt_variable() const -> const variable_type& {
254 return opt_variable_;
260 [[nodiscard]]
auto opt_value() const -> const value_type& {
267 [[nodiscard]]
auto iterations() const noexcept ->
index_type {
274 [[nodiscard]]
auto evaluations() const noexcept ->
index_type {
284 auto max_evaluations(
index_type value) -> this_type& {
286 "Maximum number of function evaluations must be a positive "
288 max_evaluations_ = value;
298 auto seed(random_number_generator_type::result_type value) -> this_type& {
299 random_number_generator_.seed(value);
309 auto population_size(
index_type value) -> this_type& {
311 "Population size must be a positive integer.");
313 "Population size must be an even number.");
314 population_size_ = value;
324 auto crossover_probability(variable_scalar_type value) -> this_type& {
326 static_cast<variable_scalar_type
>(0) <= value &&
327 value <=
static_cast<variable_scalar_type
>(1),
328 this->logger(),
"Probability of crossover must be in [0, 1].");
329 crossover_distribution_ = std::bernoulli_distribution(value);
339 auto mutation_probability(variable_scalar_type value) -> this_type& {
341 static_cast<variable_scalar_type
>(0) <= value &&
342 value <=
static_cast<variable_scalar_type
>(1),
343 this->logger(),
"Probability of mutation must be in [0, 1].");
344 mutation_distribution_ = std::bernoulli_distribution(value);
350 static constexpr index_type num_bits_per_dimension = BitsPerDimension;
353 using binary_scalar_type = std::uint32_t;
356 static constexpr index_type dim_at_compile_time =
357 variable_type::RowsAtCompileTime;
360 using binary_variable_type =
361 Eigen::Vector<binary_scalar_type, dim_at_compile_time>;
364 static constexpr binary_scalar_type binary_mask =
365 (
static_cast<binary_scalar_type
>(1)
366 <<
static_cast<binary_scalar_type
>(num_bits_per_dimension)) -
367 static_cast<binary_scalar_type
>(1);
375 [[nodiscard]]
auto evaluate_on(
const binary_variable_type& binary_variable)
377 static constexpr variable_scalar_type binary_to_rate =
378 static_cast<variable_scalar_type
>(1) /
379 static_cast<variable_scalar_type
>(binary_mask);
381 const binary_scalar_type binary_scalar =
383 buffer_variable_(d) =
384 static_cast<variable_scalar_type
>(binary_scalar) *
385 binary_to_rate * width_(d) +
389 obj_fun_.evaluate_on(buffer_variable_);
390 const value_type value = correct_value_if_needed(obj_fun_.value());
391 if (value < opt_value_) {
392 opt_variable_ = buffer_variable_;
405 [[nodiscard]]
static auto correct_value_if_needed(value_type value)
noexcept
407 constexpr auto safe_limit = std::numeric_limits<value_type>::max();
415 objective_function_type obj_fun_;
418 variable_type lower_{};
421 variable_type upper_{};
424 variable_type width_{};
430 static constexpr index_type default_population_size = 200;
433 index_type population_size_{default_population_size};
436 util::vector<binary_variable_type> binary_population_;
439 util::vector<binary_variable_type> prev_binary_population_;
442 Eigen::VectorX<value_type> population_values_;
445 random_number_generator_type random_number_generator_{
446 std::random_device()()};
449 std::uniform_real_distribution<variable_scalar_type>
450 probability_distribution_{
static_cast<variable_scalar_type
>(0),
451 static_cast<variable_scalar_type
>(1)};
454 static constexpr auto default_crossover_probability =
455 static_cast<variable_scalar_type
>(0.6);
458 std::bernoulli_distribution crossover_distribution_{
459 default_crossover_probability};
462 static constexpr auto default_mutation_probability =
463 static_cast<variable_scalar_type
>(0.1);
466 std::bernoulli_distribution mutation_distribution_{
467 default_mutation_probability};
470 variable_type buffer_variable_{};
473 Eigen::VectorX<variable_scalar_type> buffer_probabilities_{};
476 variable_type opt_variable_{};
479 value_type opt_value_{std::numeric_limits<value_type>::max()};
488 static constexpr index_type default_max_evaluations = 10000;
491 index_type max_evaluations_{default_max_evaluations};
Definition of assertion macros.
Class of tags of logs without memory management.
Base class of implementations of optimization algorithms.
Class to perform optimization for real-valued variables using genetic algorithm iba1994.
Concept of multi-variate objective functions in optimization.
Concept of objective functions in optimization.
Definition of functions for gray code.
Definition of index_type type.
Definition of isfinite function.
Definition of iteration_logger class.
Definition of log_tag_view class.
Definition of multi_variate_objective_function concept.
std::ptrdiff_t index_type
Type of indices in this library.
auto isfinite(const T &val) -> bool
Check whether a number is finite.
Namespace of optimization algorithms.
constexpr auto real_value_genetic_optimizer_tag
Tag of real_value_genetic_optimizer.
constexpr auto gray_code_to_binary(std::uint32_t gray_code) -> std::uint32_t
Convert an integer from Gray code to binary warren2013.
Definition of objective_function concept.
Definition of optimizer_base class.
Definition of NUM_COLLECT_PRECONDITION macro.
#define NUM_COLLECT_PRECONDITION(CONDITION,...)
Check whether a precondition is satisfied and throw an exception if not.
Definition of vector class.