Skip to content

Commit

Permalink
- Added bounds checking in most optimizers for initial population
Browse files Browse the repository at this point in the history
- Added tests for most optimizers for bounds checking for initial population
  • Loading branch information
Dave-Poissant committed Mar 6, 2024
1 parent 1166e3e commit 86e7bc1
Show file tree
Hide file tree
Showing 46 changed files with 1,231 additions and 15 deletions.
20 changes: 20 additions & 0 deletions src/algorithms/bee_colony.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,26 @@ population bee_colony::evolve(population pop) const
if (m_gen == 0u) {
return pop;
}
// make sure all genes respect the bounds
for (decltype(NP) i = 0u; i < NP; ++i) {
for (decltype(dim) j = 0u; j < dim; ++j) {
double x = pop.get_x()[i][j];
if (std::isnan(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to NaN" + std::to_string(x));
}

if (std::isinf(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to infinity" + std::to_string(x));
}

if (x < bounds.first[j] || x > bounds.second[j]) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " out of bounds: " + std::to_string(x));
}
}
}
// ---------------------------------------------------------------------------------------------------------

// No throws, all valid: we clear the logs
Expand Down
24 changes: 24 additions & 0 deletions src/algorithms/cmaes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,30 @@ population cmaes::evolve(population pop) const
+ this->get_name() + " cannot deal with it.");
}
}
// Verify all decision variables respect the bounds if force_bounds is true
if (m_force_bounds)
{
for (decltype(lam) i = 0u; i < lam; ++i) {
for (decltype(dim) j = 0u; j < dim; ++j) {
double x = pop.get_x()[i][j];
if (std::isnan(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to NaN" + std::to_string(x));
}

if (std::isinf(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to infinity" + std::to_string(x));
}

if (x < bounds.first[j] || x > bounds.second[j]) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " out of bounds: " + std::to_string(x));
}
}
}
}

// Get out if there is nothing to do.
if (m_gen == 0u) {
return pop;
Expand Down
21 changes: 21 additions & 0 deletions src/algorithms/compass_search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ population compass_search::evolve(population pop) const
// We store some useful variables
const auto &prob = pop.get_problem(); // This is a const reference, so using set_seed for example will not be
// allowed
auto NP = pop.size();
auto dim = prob.get_nx(); // This getter does not return a const reference but a copy
const auto bounds = prob.get_bounds();
const auto &lb = bounds.first;
Expand Down Expand Up @@ -105,6 +106,26 @@ population compass_search::evolve(population pop) const
if (m_max_fevals == 0u) {
return pop;
}
// Verify all decision variables respect the bounds
for (decltype(NP) i = 0u; i < NP; ++i) {
for (decltype(dim) j = 0u; j < dim; ++j) {
double x = pop.get_x()[i][j];
if (std::isnan(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to NaN" + std::to_string(x));
}

if (std::isinf(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to infinity" + std::to_string(x));
}

if (x < bounds.first[j] || x > bounds.second[j]) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " out of bounds: " + std::to_string(x));
}
}
}
// ---------------------------------------------------------------------------------------------------------

// No throws, all valid: we clear the logs
Expand Down
21 changes: 21 additions & 0 deletions src/algorithms/cstrs_self_adaptive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@ population cstrs_self_adaptive::evolve(population pop) const
auto nec = prob.get_nec(); // This getter does not return a const reference but a copy
const auto bounds = prob.get_bounds();
auto NP = pop.size();
auto dim = prob.get_nx();

auto fevals0 = prob.get_fevals(); // discount for the already made fevals
unsigned count = 1u; // regulates the screen output
Expand All @@ -429,6 +430,26 @@ population cstrs_self_adaptive::evolve(population pop) const
pagmo_throw(std::invalid_argument,
"Cannot use " + prob.get_name() + " on a population with less than 4 individuals");
}
// Verify all decision variables respect the bounds
for (decltype(NP) i = 0u; i < NP; ++i) {
for (decltype(dim) j = 0u; j < dim; ++j) {
double x = pop.get_x()[i][j];
if (std::isnan(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to NaN" + std::to_string(x));
}

if (std::isinf(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to infinity" + std::to_string(x));
}

if (x < bounds.first[j] || x > bounds.second[j]) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " out of bounds: " + std::to_string(x));
}
}
}
// ---------------------------------------------------------------------------------------------------------

// No throws, all valid: we clear the logs
Expand Down
20 changes: 20 additions & 0 deletions src/algorithms/de.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,26 @@ population de::evolve(population pop) const
pagmo_throw(std::invalid_argument, get_name() + " needs at least 5 individuals in the population, "
+ std::to_string(pop.size()) + " detected");
}
// Verify all decision variables respect the bounds
for (decltype(NP) i = 0u; i < NP; ++i) {
for (decltype(dim) j = 0u; j < dim; ++j) {
double x = pop.get_x()[i][j];
if (std::isnan(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to NaN" + std::to_string(x));
}

if (std::isinf(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to infinity" + std::to_string(x));
}

if (x < bounds.first[j] || x > bounds.second[j]) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " out of bounds: " + std::to_string(x));
}
}
}
// ---------------------------------------------------------------------------------------------------------

// No throws, all valid: we clear the logs
Expand Down
20 changes: 20 additions & 0 deletions src/algorithms/de1220.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,26 @@ population de1220::evolve(population pop) const
pagmo_throw(std::invalid_argument, get_name() + " needs at least 7 individuals in the population, "
+ std::to_string(pop.size()) + " detected");
}
// Verify all decision variables respect the bounds
for (decltype(NP) i = 0u; i < NP; ++i) {
for (decltype(dim) j = 0u; j < dim; ++j) {
double x = pop.get_x()[i][j];
if (std::isnan(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to NaN" + std::to_string(x));
}

if (std::isinf(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to infinity" + std::to_string(x));
}

if (x < bounds.first[j] || x > bounds.second[j]) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " out of bounds: " + std::to_string(x));
}
}
}
// ---------------------------------------------------------------------------------------------------------

// No throws, all valid: we clear the logs
Expand Down
21 changes: 21 additions & 0 deletions src/algorithms/gaco.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ population gaco::evolve(population pop) const
auto n_x = prob.get_nx(); // This getter does not return a const reference but a copy of the number of
// all the variables
auto pop_size = pop.size(); // Population size
auto bounds = prob.get_bounds(); // Bounds of the problem
unsigned count_screen = 1u; // regulates the screen output

// Note that the number of equality and inequality constraints has to be set up manually in the problem
Expand Down Expand Up @@ -167,6 +168,26 @@ population gaco::evolve(population pop) const
pagmo_throw(std::invalid_argument, "Multiple objectives detected in " + prob.get_name() + " instance. "
+ get_name() + " cannot deal with them");
}
// Verify all decision variables respect the bounds
for (decltype(pop_size) i = 0u; i < pop_size; ++i) {
for (decltype(n_x) j = 0u; j < n_x; ++j) {
double x = pop.get_x()[i][j];
if (std::isnan(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to NaN" + std::to_string(x));
}

if (std::isinf(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to infinity" + std::to_string(x));
}

if (x < bounds.first[j] || x > bounds.second[j]) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " out of bounds: " + std::to_string(x));
}
}
}

// ---------------------------------------------------------------------------------------------------------

Expand Down
20 changes: 20 additions & 0 deletions src/algorithms/gwo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,26 @@ population gwo::evolve(population pop) const
pagmo_throw(std::invalid_argument, get_name() + " needs at least 3 individuals in the population, "
+ std::to_string(pop.size()) + " detected");
}
// Verify all decision variables respect the bounds
for (decltype(NP) i = 0u; i < NP; ++i) {
for (decltype(dim) j = 0u; j < dim; ++j) {
double x = pop.get_x()[i][j];
if (std::isnan(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to NaN" + std::to_string(x));
}

if (std::isinf(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to infinity" + std::to_string(x));
}

if (x < bounds.first[j] || x > bounds.second[j]) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " out of bounds: " + std::to_string(x));
}
}
}
// ---------------------------------------------------------------------------------------------------------

// No throws, all valid: we clear the logs
Expand Down
33 changes: 27 additions & 6 deletions src/algorithms/ihs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ population ihs::evolve(population pop) const
// We store some useful properties
const auto &prob = pop.get_problem(); // This is a const reference, so using set_seed for example will not be
// allowed
auto NP = pop.size();
auto dim = prob.get_nx();
auto int_dim = prob.get_nix();
const auto bounds = prob.get_bounds();
Expand All @@ -90,7 +91,7 @@ population ihs::evolve(population pop) const
if (m_gen == 0u) {
return pop;
}
if (!pop.size()) {
if (!NP) {
pagmo_throw(std::invalid_argument, get_name() + " does not work on an empty population");
}
if (prob.get_nc() != 0u && prob.get_nobj() > 1u) {
Expand All @@ -102,6 +103,26 @@ population ihs::evolve(population pop) const
pagmo_throw(std::invalid_argument,
"The problem appears to be stochastic " + get_name() + " cannot deal with it");
}
// Verify all decision variables respect the bounds
for (decltype(NP) i = 0u; i < NP; ++i) {
for (decltype(dim) j = 0u; j < dim; ++j) {
double x = pop.get_x()[i][j];
if (std::isnan(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to NaN" + std::to_string(x));
}

if (std::isinf(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to infinity" + std::to_string(x));
}

if (x < bounds.first[j] || x > bounds.second[j]) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " out of bounds: " + std::to_string(x));
}
}
}
// ---------------------------------------------------------------------------------------------------------

// No throws, all valid: we clear the logs
Expand All @@ -112,15 +133,15 @@ population ihs::evolve(population pop) const
lu_diff[i] = ub[i] - lb[i];
}
// Distributions used
std::uniform_int_distribution<decltype(pop.size())> uni_int(0, pop.size() - 1u); // to pick an individual
std::uniform_int_distribution<decltype(NP)> uni_int(0, NP - 1u); // to pick an individual
std::uniform_real_distribution<double> drng(0., 1.); // to generate a number in [0, 1)

// Used for parameter control
const double c = std::log(m_bw_min / m_bw_max) / m_gen;

// Declarations
vector_double new_x(dim, 0.);
std::vector<vector_double::size_type> best_idxs(pop.size());
std::vector<vector_double::size_type> best_idxs(NP);

// Main loop
for (decltype(m_gen) gen = 1u; gen <= m_gen; ++gen) {
Expand Down Expand Up @@ -185,10 +206,10 @@ population ihs::evolve(population pop) const
// we augment the list with the new fitness
fitnesses.push_back(new_f);
// select the best pop.size() individuals
best_idxs = select_best_N_mo(fitnesses, pop.size());
best_idxs = select_best_N_mo(fitnesses, NP);
// define the new population
for (population::size_type i = 0u; i < pop.size(); ++i) {
if (best_idxs[i] == pop.size()) { // this is the new guy
for (population::size_type i = 0u; i < NP; ++i) {
if (best_idxs[i] == NP) { // this is the new guy
pop.set_xf(i, new_x, new_f);
} else { // these were already in the pop somewhere
pop.set_xf(i, pop.get_x()[best_idxs[i]], pop.get_f()[best_idxs[i]]);
Expand Down
21 changes: 21 additions & 0 deletions src/algorithms/maco.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ population maco::evolve(population pop) const
const auto &prob = pop.get_problem();
auto n_x = prob.get_nx();
auto pop_size = pop.size();
auto bounds = prob.get_bounds();
unsigned count_screen = 1u; // regulates the screen output
auto fevals0 = prob.get_fevals(); // discount for the already made fevals
auto n_f = prob.get_nf(); // n_f=prob.get_nobj()+prob.get_nec()+prob.get_nic()
Expand Down Expand Up @@ -148,6 +149,26 @@ population maco::evolve(population pop) const
pagmo_throw(std::invalid_argument, "This is a multiobjective algorithm, while number of objectives detected in "
+ prob.get_name() + " is " + std::to_string(prob.get_nf()));
}
// Verify all decision variables respect the bounds
for (decltype(pop_size) i = 0u; i < pop_size; ++i) {
for (decltype(n_x) j = 0u; j < n_x; ++j) {
double x = pop.get_x()[i][j];
if (std::isnan(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to NaN" + std::to_string(x));
}

if (std::isinf(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to infinity" + std::to_string(x));
}

if (x < bounds.first[j] || x > bounds.second[j]) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " out of bounds: " + std::to_string(x));
}
}
}
// ---------------------------------------------------------------------------------------------------------

// No throws, all valid: we clear the logs
Expand Down
20 changes: 20 additions & 0 deletions src/algorithms/mbh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,26 @@ population mbh::evolve(population pop) const
+ ", while the problem dimension is: " + std::to_string(dim)
+ ". They need to be equal for MBH to work.");
}
// Verify all decision variables respect the bounds
for (decltype(NP) i = 0u; i < NP; ++i) {
for (decltype(dim) j = 0u; j < dim; ++j) {
double x = pop.get_x()[i][j];
if (std::isnan(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to NaN" + std::to_string(x));
}

if (std::isinf(x)) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " equal to infinity" + std::to_string(x));
}

if (x < bounds.first[j] || x > bounds.second[j]) {
pagmo_throw(std::invalid_argument, "Individual " + std::to_string(i) + " has a gene " + std::to_string(j)
+ " out of bounds: " + std::to_string(x));
}
}
}
// ---------------------------------------------------------------------------------------------------------

// No throws, all valid: we clear the logs
Expand Down
Loading

0 comments on commit 86e7bc1

Please sign in to comment.