diff --git a/src/algorithms/bee_colony.cpp b/src/algorithms/bee_colony.cpp index 1e188adbf..e79c720f5 100644 --- a/src/algorithms/bee_colony.cpp +++ b/src/algorithms/bee_colony.cpp @@ -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 diff --git a/src/algorithms/cmaes.cpp b/src/algorithms/cmaes.cpp index 64e3ed6eb..c45ff98d2 100644 --- a/src/algorithms/cmaes.cpp +++ b/src/algorithms/cmaes.cpp @@ -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; diff --git a/src/algorithms/compass_search.cpp b/src/algorithms/compass_search.cpp index 01d2b3a6e..4ee7164d8 100644 --- a/src/algorithms/compass_search.cpp +++ b/src/algorithms/compass_search.cpp @@ -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; @@ -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 diff --git a/src/algorithms/cstrs_self_adaptive.cpp b/src/algorithms/cstrs_self_adaptive.cpp index 462063da3..b057aa519 100644 --- a/src/algorithms/cstrs_self_adaptive.cpp +++ b/src/algorithms/cstrs_self_adaptive.cpp @@ -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 @@ -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 diff --git a/src/algorithms/de.cpp b/src/algorithms/de.cpp index bdbb819ad..5deec07ce 100644 --- a/src/algorithms/de.cpp +++ b/src/algorithms/de.cpp @@ -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 diff --git a/src/algorithms/de1220.cpp b/src/algorithms/de1220.cpp index 0eddc8555..5705323f3 100644 --- a/src/algorithms/de1220.cpp +++ b/src/algorithms/de1220.cpp @@ -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 diff --git a/src/algorithms/gaco.cpp b/src/algorithms/gaco.cpp index e20456852..ea096968f 100644 --- a/src/algorithms/gaco.cpp +++ b/src/algorithms/gaco.cpp @@ -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 @@ -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)); + } + } + } // --------------------------------------------------------------------------------------------------------- diff --git a/src/algorithms/gwo.cpp b/src/algorithms/gwo.cpp index 01aa9f56f..e5eda7a66 100644 --- a/src/algorithms/gwo.cpp +++ b/src/algorithms/gwo.cpp @@ -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 diff --git a/src/algorithms/ihs.cpp b/src/algorithms/ihs.cpp index 5036bf245..caa42c7e3 100644 --- a/src/algorithms/ihs.cpp +++ b/src/algorithms/ihs.cpp @@ -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(); @@ -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) { @@ -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 @@ -112,7 +133,7 @@ population ihs::evolve(population pop) const lu_diff[i] = ub[i] - lb[i]; } // Distributions used - std::uniform_int_distribution uni_int(0, pop.size() - 1u); // to pick an individual + std::uniform_int_distribution uni_int(0, NP - 1u); // to pick an individual std::uniform_real_distribution drng(0., 1.); // to generate a number in [0, 1) // Used for parameter control @@ -120,7 +141,7 @@ population ihs::evolve(population pop) const // Declarations vector_double new_x(dim, 0.); - std::vector best_idxs(pop.size()); + std::vector best_idxs(NP); // Main loop for (decltype(m_gen) gen = 1u; gen <= m_gen; ++gen) { @@ -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]]); diff --git a/src/algorithms/maco.cpp b/src/algorithms/maco.cpp index 764c8b2c2..bac1477f5 100644 --- a/src/algorithms/maco.cpp +++ b/src/algorithms/maco.cpp @@ -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() @@ -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 diff --git a/src/algorithms/mbh.cpp b/src/algorithms/mbh.cpp index 694bfec22..3c23ea218 100644 --- a/src/algorithms/mbh.cpp +++ b/src/algorithms/mbh.cpp @@ -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 diff --git a/src/algorithms/moead.cpp b/src/algorithms/moead.cpp index 60f6ede1d..f58a7237c 100644 --- a/src/algorithms/moead.cpp +++ b/src/algorithms/moead.cpp @@ -146,6 +146,26 @@ population moead::evolve(population pop) const if (m_gen == 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)); + } + } + } // Generate NP weight vectors for the decomposed problems. Will throw if the population size is not compatible // with the weight generation scheme chosen auto weights = decomposition_weights(prob.get_nf(), NP, m_weight_generation, m_e); diff --git a/src/algorithms/moead_gen.cpp b/src/algorithms/moead_gen.cpp index 3a5d5fcda..41c4596f2 100644 --- a/src/algorithms/moead_gen.cpp +++ b/src/algorithms/moead_gen.cpp @@ -150,6 +150,26 @@ population moead_gen::evolve(population pop) const if (m_gen == 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)); + } + } + } // Generate NP weight vectors for the decomposed problems. Will throw if the population size is not compatible // with the weight generation scheme chosen auto weights = decomposition_weights(prob.get_nf(), NP, m_weight_generation, m_e); diff --git a/src/algorithms/nsga2.cpp b/src/algorithms/nsga2.cpp index 4ddd6b198..da8b0df9c 100644 --- a/src/algorithms/nsga2.cpp +++ b/src/algorithms/nsga2.cpp @@ -96,6 +96,7 @@ population nsga2::evolve(population pop) const const auto bounds = pop.get_problem().get_bounds(); auto dim_i = pop.get_problem().get_nix(); // integer dimension auto NP = pop.size(); + auto dim = prob.get_nx(); // This getter does not return a const reference but a copy auto fevals0 = prob.get_fevals(); // discount for the fevals already made unsigned count = 1u; // regulates the screen output @@ -126,6 +127,26 @@ population nsga2::evolve(population pop) const "population size must be a multiple of 4. Detected input population size is: " + std::to_string(NP)); } + // 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 diff --git a/src/algorithms/nspso.cpp b/src/algorithms/nspso.cpp index 356152a82..acfa02edb 100644 --- a/src/algorithms/nspso.cpp +++ b/src/algorithms/nspso.cpp @@ -116,6 +116,26 @@ population nspso::evolve(population pop) const if (m_gen == 0u) { return pop; } + // Verify all decision variables respect the bounds + for (decltype(swarm_size) i = 0u; i < swarm_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 m_log.clear(); diff --git a/src/algorithms/pso.cpp b/src/algorithms/pso.cpp index 53d146ab5..a93673e45 100644 --- a/src/algorithms/pso.cpp +++ b/src/algorithms/pso.cpp @@ -118,6 +118,7 @@ population pso::evolve(population pop) const const auto &prob = pop.get_problem(); // This is a const reference, so using set_seed for example will not be // allowed auto dim = prob.get_nx(); // not const as used type for counters + auto swarm_size = pop.size(); const auto bounds = prob.get_bounds(); const auto &lb = bounds.first; const auto &ub = bounds.second; @@ -138,14 +139,33 @@ population pso::evolve(population pop) const pagmo_throw(std::invalid_argument, "The problem appears to be stochastic " + get_name() + " cannot deal with it"); } - if (!pop.size()) { + if (!swarm_size) { pagmo_throw(std::invalid_argument, get_name() + " does not work on an empty population"); } + // Verify all decision variables respect the bounds + for (decltype(swarm_size) i = 0u; i < swarm_size; ++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 m_log.clear(); - - auto swarm_size = pop.size(); + // Some vectors used are allocated here. vector_double dummy(dim, 0.); // used for initialisation purposes diff --git a/src/algorithms/pso_gen.cpp b/src/algorithms/pso_gen.cpp index f7ef359ad..825d5c9be 100644 --- a/src/algorithms/pso_gen.cpp +++ b/src/algorithms/pso_gen.cpp @@ -123,6 +123,7 @@ population pso_gen::evolve(population pop) const const auto &prob = pop.get_problem(); // This is a const reference, so using set_seed for example will not be // allowed auto dim = prob.get_nx(); // not const as used type for counters + auto swarm_size = pop.size(); const auto bounds = prob.get_bounds(); const auto &lb = bounds.first; const auto &ub = bounds.second; @@ -139,14 +140,33 @@ population pso_gen::evolve(population pop) const pagmo_throw(std::invalid_argument, "Multiple objectives detected in " + prob.get_name() + " instance. " + get_name() + " cannot deal with them"); } - if (!pop.size()) { + if (!swarm_size) { pagmo_throw(std::invalid_argument, get_name() + " does not work on an empty population"); } + // Verify all decision variables respect the bounds + for (decltype(swarm_size) i = 0u; i < swarm_size; ++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 m_log.clear(); - auto swarm_size = pop.size(); // Some vectors used are allocated here. vector_double dummy(dim, 0.); // used for initialisation purposes diff --git a/src/algorithms/sade.cpp b/src/algorithms/sade.cpp index d827d82b1..7227fadd6 100644 --- a/src/algorithms/sade.cpp +++ b/src/algorithms/sade.cpp @@ -112,6 +112,26 @@ population sade::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 diff --git a/src/algorithms/sea.cpp b/src/algorithms/sea.cpp index d6403e97c..61fb1b672 100644 --- a/src/algorithms/sea.cpp +++ b/src/algorithms/sea.cpp @@ -56,7 +56,8 @@ population sea::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 - const auto dim = prob.get_nx(); // This getter does not return a const reference but a copy + auto dim = prob.get_nx(); // This getter does not return a const reference but a copy + auto NP = pop.size(); const auto bounds = prob.get_bounds(); const auto &lb = bounds.first; const auto &ub = bounds.second; @@ -78,9 +79,29 @@ population sea::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"); } + // 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 diff --git a/src/algorithms/sga.cpp b/src/algorithms/sga.cpp index 3443edd8c..b8eba6222 100644 --- a/src/algorithms/sga.cpp +++ b/src/algorithms/sga.cpp @@ -185,6 +185,7 @@ population sga::evolve(population pop) const { const auto &prob = pop.get_problem(); auto dim_i = prob.get_nix(); + auto dim = prob.get_nx(); const auto bounds = prob.get_bounds(); auto NP = pop.size(); auto fevals0 = prob.get_fevals(); // fevals already made @@ -218,6 +219,26 @@ population sga::evolve(population pop) const if (m_gen == 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 diff --git a/src/algorithms/simulated_annealing.cpp b/src/algorithms/simulated_annealing.cpp index 071fe09b1..332795966 100644 --- a/src/algorithms/simulated_annealing.cpp +++ b/src/algorithms/simulated_annealing.cpp @@ -97,6 +97,7 @@ population simulated_annealing::evolve(population pop) const const auto &prob = pop.get_problem(); // This is a const reference, so using set_seed for example will not be // allowed auto dim = prob.get_nx(); // not const as used type for counters + auto NP = pop.size(); const auto bounds = prob.get_bounds(); const auto &lb = bounds.first; const auto &ub = bounds.second; @@ -117,9 +118,29 @@ population simulated_annealing::evolve(population pop) const pagmo_throw(std::invalid_argument, "The problem appears to be stochastic " + get_name() + " cannot deal with it"); } - if (!pop.size()) { + if (!NP) { pagmo_throw(std::invalid_argument, get_name() + " does not work on an empty population"); } + // 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 diff --git a/src/algorithms/xnes.cpp b/src/algorithms/xnes.cpp index cb7f61997..4492bf261 100644 --- a/src/algorithms/xnes.cpp +++ b/src/algorithms/xnes.cpp @@ -137,6 +137,29 @@ population xnes::evolve(population pop) const if (m_gen == 0u) { return pop; } + // 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)); + } + } + } + } // ----------------------------------------------------------- // No throws, all valid: we clear the logs diff --git a/tests/bee_colony.cpp b/tests/bee_colony.cpp index b38ebd0d8..aa53b7b8a 100644 --- a/tests/bee_colony.cpp +++ b/tests/bee_colony.cpp @@ -173,3 +173,34 @@ BOOST_AUTO_TEST_CASE(bee_colony_serialization_test) BOOST_CHECK_CLOSE(std::get<3>(before_log[i]), std::get<3>(after_log[i]), 1e-8); } } + +BOOST_AUTO_TEST_CASE(bee_colony_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the bee_colony algorithm throws if the initial population does not respect the bounds + problem prob{rosenbrock{25u}}; + population pop{prob, 10u, 23u}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(bee_colony{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(bee_colony{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(bee_colony{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(bee_colony{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(bee_colony{10u}.evolve(pop)); +} diff --git a/tests/cmaes.cpp b/tests/cmaes.cpp index bf545a473..1241837fd 100644 --- a/tests/cmaes.cpp +++ b/tests/cmaes.cpp @@ -288,3 +288,35 @@ BOOST_AUTO_TEST_CASE(cmaes_memory_test) BOOST_CHECK_CLOSE(std::get<2>(log[0]), std::get<2>(log2[1]), 1e-8); // the 1 and 0 will be different as fevals is reset at each evolve } + +BOOST_AUTO_TEST_CASE(cmaes_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + cmaes user_algo{1u, -1, -1, -1, -1, 0.5, 1e-6, 1e-6, true, true, 23u}; + problem prob{rosenbrock{25u}}; + population pop{prob, 10u, 23u}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(user_algo.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(user_algo.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(user_algo.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(user_algo.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(user_algo.evolve(pop)); +} diff --git a/tests/compass_search.cpp b/tests/compass_search.cpp index 6e70441fd..1cdf81aa9 100644 --- a/tests/compass_search.cpp +++ b/tests/compass_search.cpp @@ -157,3 +157,34 @@ BOOST_AUTO_TEST_CASE(compass_search_serialization_test) BOOST_CHECK_CLOSE(std::get<4>(before_log[i]), std::get<4>(after_log[i]), 1e-8); } } + +BOOST_AUTO_TEST_CASE(compass_search_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + problem prob{rosenbrock{25u}}; + population pop{prob, 10u, 23u}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(compass_search{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(compass_search{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(compass_search{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(compass_search{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(compass_search{10u}.evolve(pop)); +} diff --git a/tests/cstrs_self_adaptive.cpp b/tests/cstrs_self_adaptive.cpp index c43f8007b..fe9438aba 100644 --- a/tests/cstrs_self_adaptive.cpp +++ b/tests/cstrs_self_adaptive.cpp @@ -363,4 +363,35 @@ BOOST_AUTO_TEST_CASE(cstrs_self_adaptive_all_infeasible_test) BOOST_CHECK((udp_p.m_f_hat_down == vector_double{1., 1., 1.})); BOOST_CHECK((udp_p.m_f_hat_round == vector_double{7, 22., 10.})); BOOST_CHECK_EQUAL(udp_p.m_apply_penalty_1, true); +} + +BOOST_AUTO_TEST_CASE(cstrs_self_adaptive_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + problem prob{hock_schittkowski_71{}}; + population pop{prob, 10u, 23u}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(cstrs_self_adaptive{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(cstrs_self_adaptive{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(cstrs_self_adaptive{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(cstrs_self_adaptive{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(cstrs_self_adaptive{10u}.evolve(pop)); } \ No newline at end of file diff --git a/tests/de.cpp b/tests/de.cpp index c79083202..def3a3295 100644 --- a/tests/de.cpp +++ b/tests/de.cpp @@ -174,3 +174,34 @@ BOOST_AUTO_TEST_CASE(de_serialization_test) BOOST_CHECK_CLOSE(std::get<4>(before_log[i]), std::get<4>(after_log[i]), 1e-8); } } + +BOOST_AUTO_TEST_CASE(de_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + problem prob{rosenbrock{25u}}; + population pop{prob, 10u, 23u}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(de{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(de{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(de{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(de{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(de{10u}.evolve(pop)); +} diff --git a/tests/de1220.cpp b/tests/de1220.cpp index 22ad5d258..b3e9b929e 100644 --- a/tests/de1220.cpp +++ b/tests/de1220.cpp @@ -185,3 +185,34 @@ BOOST_AUTO_TEST_CASE(serialization_test) BOOST_CHECK_CLOSE(std::get<7>(before_log[i]), std::get<7>(after_log[i]), 1e-8); } } + +BOOST_AUTO_TEST_CASE(de1220_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + problem prob{rosenbrock{25u}}; + population pop{prob, 10u, 23u}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(de1220{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(de1220{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(de1220{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(de1220{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(de1220{10u}.evolve(pop)); +} diff --git a/tests/gaco.cpp b/tests/gaco.cpp index 8ca1768ca..f3c868708 100644 --- a/tests/gaco.cpp +++ b/tests/gaco.cpp @@ -354,3 +354,35 @@ BOOST_AUTO_TEST_CASE(bfe_usage_test) BOOST_CHECK_EQUAL(pop.champion_f()[0], pop_2.champion_f()[0]); } + +BOOST_AUTO_TEST_CASE(gaco_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + problem prob{rosenbrock{10u}}; + population pop{prob, 200u, 23u}; + gaco uda{40u, 10u, 1.0, 25.0, 0.01, 5u, 7u, 1000u, 1000u, 0.0, false, 23u}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(uda.evolve(pop)); +} diff --git a/tests/gwo.cpp b/tests/gwo.cpp index 4b3e214bf..1bf5a1994 100644 --- a/tests/gwo.cpp +++ b/tests/gwo.cpp @@ -136,4 +136,35 @@ BOOST_AUTO_TEST_CASE(gwo_serialization_test) BOOST_CHECK_CLOSE(std::get<2>(before_log[i]), std::get<2>(after_log[i]), 1e-8); BOOST_CHECK_CLOSE(std::get<3>(before_log[i]), std::get<3>(after_log[i]), 1e-8); } -} \ No newline at end of file +} + +BOOST_AUTO_TEST_CASE(gwo_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + problem prob{rosenbrock{25u}}; + population pop{prob, 10u, 23u}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(gwo{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(gwo{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(gwo{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(gwo{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(gwo{10u}.evolve(pop)); +} diff --git a/tests/ihs.cpp b/tests/ihs.cpp index c167874a1..6b007761f 100644 --- a/tests/ihs.cpp +++ b/tests/ihs.cpp @@ -201,3 +201,34 @@ BOOST_AUTO_TEST_CASE(ihs_integer_test) } } } + +BOOST_AUTO_TEST_CASE(ihs_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + problem prob{rosenbrock{25u}}; + population pop{prob, 10u, 23u}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(ihs{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(ihs{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(ihs{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(ihs{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(ihs{10u}.evolve(pop)); +} diff --git a/tests/ipopt.cpp b/tests/ipopt.cpp index 3183680c5..6608d7e5d 100644 --- a/tests/ipopt.cpp +++ b/tests/ipopt.cpp @@ -345,3 +345,34 @@ BOOST_AUTO_TEST_CASE(ipopt_thread_safety) BOOST_CHECK((island{ipopt{}, luksan_vlcek1{4}, 10}.is())); #endif } + +BOOST_AUTO_TEST_CASE(ipopt_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + problem prob{hock_schittkowski_71{}}; + population pop{prob, 10u, 23u}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(ipopt{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(ipopt{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(ipopt{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(ipopt{10u}.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(ipopt{10u}.evolve(pop)); +} diff --git a/tests/maco.cpp b/tests/maco.cpp index 884362f93..982b44548 100644 --- a/tests/maco.cpp +++ b/tests/maco.cpp @@ -264,3 +264,35 @@ BOOST_AUTO_TEST_CASE(memory_test) pop_2 = uda_2.evolve(pop_2); BOOST_CHECK(pop_1.get_f() == pop_2.get_f()); } + +BOOST_AUTO_TEST_CASE(maco_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + maco uda{10u, 20u, 1.0, 8u, 7u, 10000u, 0., false, 23u}; + problem prob{wfg{5u, 16u, 15u, 14u}}; + population pop{prob, 20u, 23u}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(uda.evolve(pop)); +} diff --git a/tests/mbh.cpp b/tests/mbh.cpp index c9a927b4b..7b1b86c2a 100644 --- a/tests/mbh.cpp +++ b/tests/mbh.cpp @@ -255,3 +255,36 @@ BOOST_AUTO_TEST_CASE(mbh_inner_algo_get_test) BOOST_CHECK(!std::is_const::type>::value); } } + +BOOST_AUTO_TEST_CASE(mbh_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + problem prob{rosenbrock{5u}}; + population pop{prob, 5u, 23u}; + // prepare algo with perturbation 0.1 + mbh user_algo{compass_search{100u, 0.1, 0.001, 0.7}, 5u, 0.1}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(user_algo.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(user_algo.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(user_algo.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(user_algo.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(user_algo.evolve(pop)); +} diff --git a/tests/moead.cpp b/tests/moead.cpp index a649ae7d8..5c4f38788 100644 --- a/tests/moead.cpp +++ b/tests/moead.cpp @@ -254,3 +254,35 @@ BOOST_AUTO_TEST_CASE(moead_serialization_test) } } } + +BOOST_AUTO_TEST_CASE(moead_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + problem prob{zdt{1u, 30u}}; + population pop{prob, 40u, 23u}; + algorithm algo{moead{10u, "grid", "tchebycheff", 10u, 0.9, 0.5, 20., 0.9, 2u, true, 23u}}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(algo.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(algo.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(algo.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(algo.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(algo.evolve(pop)); +} diff --git a/tests/moead_gen.cpp b/tests/moead_gen.cpp index 273b55244..66c8ad62b 100644 --- a/tests/moead_gen.cpp +++ b/tests/moead_gen.cpp @@ -285,3 +285,35 @@ BOOST_AUTO_TEST_CASE(bfe_usage_test) pop2 = algo2.evolve(pop); BOOST_CHECK(algo1.extract()->get_log() == algo2.extract()->get_log()); } + +BOOST_AUTO_TEST_CASE(moead_gen_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + problem prob{zdt{1u, 30u}}; + population pop{prob, 24, 32u}; + moead_gen uda1{moead_gen{10u, "grid", "tchebycheff", 10u, 0.9, 0.5, 20., 0.9, 2u, true, 23u}}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(uda1.evolve(pop)); +} diff --git a/tests/nlopt.cpp b/tests/nlopt.cpp index 7aac48d31..605baabf7 100644 --- a/tests/nlopt.cpp +++ b/tests/nlopt.cpp @@ -381,3 +381,34 @@ BOOST_AUTO_TEST_CASE(nlopt_loc_opt) algo.evolve(pop); BOOST_CHECK(algo.extract()->get_last_opt_result() >= 0); } + +BOOST_AUTO_TEST_CASE(nlopt_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + auto pop = population{hs71{}, 1}; + auto a = nlopt{"slsqp"}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(nlopt.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(nlopt.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(nlopt.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(nlopt.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(nlopt.evolve(pop)); +} diff --git a/tests/nsga2.cpp b/tests/nsga2.cpp index 1982fc9b8..1867ff4fc 100644 --- a/tests/nsga2.cpp +++ b/tests/nsga2.cpp @@ -231,3 +231,35 @@ BOOST_AUTO_TEST_CASE(bfe_usage_test) pop2 = algo2.evolve(pop); BOOST_CHECK(algo1.extract()->get_log() == algo2.extract()->get_log()); } + +BOOST_AUTO_TEST_CASE(nsga2_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + problem prob{dtlz(1, 10, 2)}; + population pop{prob, 24, 32u}; + nsga2 uda1{nsga2{10}}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(uda1.evolve(pop)); +} diff --git a/tests/nspso.cpp b/tests/nspso.cpp index ae3f8deb4..6924d77aa 100644 --- a/tests/nspso.cpp +++ b/tests/nspso.cpp @@ -247,3 +247,35 @@ BOOST_AUTO_TEST_CASE(memory_test) pop_2 = uda_2.evolve(pop_2); BOOST_CHECK(pop_1.get_f() == pop_2.get_f()); } + +BOOST_AUTO_TEST_CASE(nspso_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + problem prob{wfg{5u, 16u, 15u, 14u}}; + population pop{prob, 20u, 23u}; + nspso uda1{1u, 0.95, 0.01, 0.5, 0.5, 0.5, 2u, "crowding distance", false, 24u}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(uda1.evolve(pop)); +} diff --git a/tests/pso.cpp b/tests/pso.cpp index f7bb37aad..72e8680ce 100644 --- a/tests/pso.cpp +++ b/tests/pso.cpp @@ -184,3 +184,35 @@ BOOST_AUTO_TEST_CASE(serialization_test) BOOST_CHECK_CLOSE(std::get<5>(before_log[i]), std::get<5>(after_log[i]), 1e-8); } } + +BOOST_AUTO_TEST_CASE(pso_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + problem prob{rosenbrock{25u}}; + population pop{prob, 5u, 23u}; + algorithm uda1{pso{500u, 0.79, 2., 2., 0.1, 5u, 2u, 4u, false, 23u}}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(uda1.evolve(pop)); +} diff --git a/tests/pso_gen.cpp b/tests/pso_gen.cpp index 695b1ac48..68d0509ef 100644 --- a/tests/pso_gen.cpp +++ b/tests/pso_gen.cpp @@ -334,3 +334,35 @@ BOOST_AUTO_TEST_CASE(bfe_usage_test_stoch) BOOST_CHECK(pop.get_f() == pop_2.get_f()); } + +BOOST_AUTO_TEST_CASE(pso_gen_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + problem prob{rosenbrock{10u}}; + population pop{prob, 30u, 23u}; + pso_gen uda1{40u, 0.79, 2., 2., 0.1, 5u, 2u, 4u, false, 23u}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(uda1.evolve(pop)); +} diff --git a/tests/sade.cpp b/tests/sade.cpp index e0c5110ed..4c453ca9d 100644 --- a/tests/sade.cpp +++ b/tests/sade.cpp @@ -173,3 +173,35 @@ BOOST_AUTO_TEST_CASE(serialization_test) BOOST_CHECK_CLOSE(std::get<6>(before_log[i]), std::get<6>(after_log[i]), 1e-8); } } + +BOOST_AUTO_TEST_CASE(sade_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + problem prob{rosenbrock{25u}}; + population pop{prob, 15u, 23u}; + algorithm uda1{sade{10u, 2, 1, 1e-3, 1e-3, false, 23u}}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(uda1.evolve(pop)); +} diff --git a/tests/sea.cpp b/tests/sea.cpp index c2feb6786..a17025f50 100644 --- a/tests/sea.cpp +++ b/tests/sea.cpp @@ -162,3 +162,35 @@ BOOST_AUTO_TEST_CASE(sea_serialization_test) BOOST_CHECK_CLOSE(std::get<3>(before_log[i]), std::get<3>(after_log[i]), 1e-8); } } + +BOOST_AUTO_TEST_CASE(sea_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + problem prob{rosenbrock{25u}}; + population pop{prob, 5u, 23u}; + algorithm uda1{sea{10u, 23u}}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(uda1.evolve(pop)); +} diff --git a/tests/sga.cpp b/tests/sga.cpp index 74da1cc5c..b7d2b597e 100644 --- a/tests/sga.cpp +++ b/tests/sga.cpp @@ -214,3 +214,35 @@ BOOST_AUTO_TEST_CASE(sga_serialization_test) BOOST_CHECK_CLOSE(std::get<3>(before_log[i]), std::get<3>(after_log[i]), 1e-8); } } + +BOOST_AUTO_TEST_CASE(sga_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + problem prob{schwefel{20u}}; + population pop{prob, 20u, 23u}; + algorithm uda1{sga{10u}}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(uda1.evolve(pop)); +} diff --git a/tests/simulated_annealing.cpp b/tests/simulated_annealing.cpp index 23043cc28..2e9b3d834 100644 --- a/tests/simulated_annealing.cpp +++ b/tests/simulated_annealing.cpp @@ -144,3 +144,35 @@ BOOST_AUTO_TEST_CASE(simulated_annealing_serialization_test) BOOST_CHECK_CLOSE(std::get<4>(before_log[i]), std::get<4>(after_log[i]), 1e-8); } } + +BOOST_AUTO_TEST_CASE(simulated_annealing_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + problem prob{rosenbrock{25u}}; + population pop{prob, 5u, 23u}; + algorithm uda1{simulated_annealing{10., 1e-5, 100u, 10u, 10u, 1., 23u}}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(uda1.evolve(pop)); +} diff --git a/tests/xnes.cpp b/tests/xnes.cpp index 39be59c47..3804feae5 100644 --- a/tests/xnes.cpp +++ b/tests/xnes.cpp @@ -292,3 +292,35 @@ BOOST_AUTO_TEST_CASE(xnes_memory_test) BOOST_CHECK_CLOSE(std::get<2>(log[0]), std::get<2>(log2[1]), 1e-8); // the 1 and 0 will be different as fevals is reset at each evolve } + +BOOST_AUTO_TEST_CASE(simulated_annealing_initial_population_not_respecting_bounds_throw_test) +{ + // We test that the algorithm throws if the initial population does not respect the bounds + problem prob{rosenbrock{25u}}; + population pop{prob, 10u, 23u}; + xnes uda1{1u, -1, -1, -1, -1, 1e-6, 1e-6, true, true, 23u}; + auto dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] - 1.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().second[0] + 2.; + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::quiet_NaN(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = std::numeric_limits::infinity(); + pop.set_x(0, dv); + BOOST_CHECK_THROW(uda1.evolve(pop), std::invalid_argument); + + dv = pop.get_x()[0]; + dv[0] = prob.get_bounds().first[0] + prob.get_bounds().second[0] / 2.0; + pop.set_x(0, dv); + BOOST_CHECK_NO_THROW(uda1.evolve(pop)); +}