From 0419469103c1662ce055159142e10308974d6a99 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sun, 7 Mar 2021 19:05:24 +0530 Subject: [PATCH 001/128] - Import previous work - populationSize > neighborSize + 1 - fix initNeighborhood - neighborHoodSize => neighborSize --- HISTORY.md | 3 + doc/function_types.md | 1 + doc/optimizers.md | 56 +++ include/ensmallen.hpp | 1 + include/ensmallen_bits/moead/moead.hpp | 290 ++++++++++++ include/ensmallen_bits/moead/moead_impl.hpp | 411 ++++++++++++++++++ .../problems/fonseca_fleming_function.hpp | 6 + .../problems/schaffer_function_n1.hpp | 5 + tests/CMakeLists.txt | 1 + tests/moead_test.cpp | 182 ++++++++ tests/nsga2_test.cpp | 1 + 11 files changed, 957 insertions(+) create mode 100644 include/ensmallen_bits/moead/moead.hpp create mode 100644 include/ensmallen_bits/moead/moead_impl.hpp create mode 100644 tests/moead_test.cpp diff --git a/HISTORY.md b/HISTORY.md index 024f113a1..eb28e7309 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -80,6 +80,9 @@ * Adjust tolerance for AugLagrangian convergence based on element type ([#217](https://github.com/mlpack/ensmallen/pull/217)). + + * Add MOEA/D optimizer for multi-objective functions + ([#210](https://github.com/mlpack/ensmallen/pull/210)) ### ensmallen 2.14.0: "No Direction Home" ###### 2020-08-10 diff --git a/doc/function_types.md b/doc/function_types.md index 4cf4dcc1b..81553a1ad 100644 --- a/doc/function_types.md +++ b/doc/function_types.md @@ -888,6 +888,7 @@ front. The following optimizers can be used with multi-objective functions: - [NSGA2](#nsga2) +- [MOEA/D](#moead) ## Constrained functions diff --git a/doc/optimizers.md b/doc/optimizers.md index 2317a92c1..cee70b4a2 100644 --- a/doc/optimizers.md +++ b/doc/optimizers.md @@ -1563,6 +1563,62 @@ optimizer.Optimize(f, coordinates); * [SGD in Wikipedia](https://en.wikipedia.org/wiki/Stochastic_gradient_descent) * [Differentiable separable functions](#differentiable-separable-functions) +## MOEA/D +*An optimizer for arbitrary multi-objective functions.* +MOEA/D (Multi Objective Evolutionary Algorithm based on Decomposition) is a multi +objective optimization algorithm. The algorithm works by decomposing a multi objective +problem to a single objective one by employing different decomposition approaches such +as Tchebycheff approach, Boundary-intersection approach and weighted sum approach. +These approaches are based on a weight vector, random choices of weight vectors produce +random single objective problems. Solving each problem, we get a different solution which +will be a part of the Pareto Front. + +#### Constructors +* `MOEAD()` +* `MOEAD(`_`populationSize, crossoverProb, mutationProb, mutationStrength, neighbourhoodSize, lowerBound, upperBound`_`)` + +#### Attributes + +| **type** | **name** | **description** | **default** | +|----------|----------|-----------------|-------------| +| `size_t` | **`populationSize`** | The number of candidates in the population. This should be at least 4 in size and a multiple of 4. | `100` | +| `double` | **`crossoverProb`** | Probability that a crossover will occur. | `0.6` | +| `double` | **`mutationProb`** | Probability that a weight will get mutated. | `0.3` | +| `double` | **`mutationStrength`** | The range of mutation noise to be added. This range is between 0 and mutationStrength. | `0.001` | +| `size_t` | **`neighbourhoodSize`** | The number of nearest-neighbours to consider for each weight. | `50` | +| `arma::vec` | **`lowerBound`** | Lower bound of the coordinates of the initial population. | `1` | +| `arma::vec` | **`upperBound`** | Lower bound of the coordinates of the initial population. | `1` | + +Attributes of the optimizer may also be changed via the member methods +`PopulationSize()`, `CrossoverRate()`, `MutationProbability()`, `NeighbourhoodSize()`, `LowerBound()` and `UpperBound()`. + +#### Examples: + +
+Click to collapse/expand example code. + + +```c++ +SchafferFunctionN1 SCH; +arma::vec lowerBound("-1000 -1000"); +arma::vec upperBound("1000 1000"); +MOEAD opt(1000, 0.5, 0.5, 1e-3, 50, lowerBound, upperBound); +typedef decltype(SCH.objectiveA) ObjectiveTypeA; +typedef decltype(SCH.objectiveB) ObjectiveTypeB; +arma::mat coords = SCH.GetInitialPoint(); +std::tuple objectives = SCH.GetObjectives(); +// obj will contain the minimum sum of objectiveA and objectiveB found on the best front. +double obj = opt.Optimize(objectives, coords); +// Now obtain the best front. +std::vector bestFront = opt.Front(); +``` +
+ +#### See also +* [MOEA/D Algorithm](https://www.researchgate.net/publication/3418989_MOEAD_A_Multiobjective_Evolutionary_Algorithm_Based_on_Decomposition/link/0912f50c77bae013b5000000/download) +* [Multi-objective Functions in Wikipedia](https://en.wikipedia.org/wiki/Test_functions_for_optimization#Test_functions_for_multi-objective_optimization) +* [Multi-objective functions](#multi-objective-functions) + ## NSGA2 *An optimizer for arbitrary multi-objective functions.* diff --git a/include/ensmallen.hpp b/include/ensmallen.hpp index 75316514a..0f6520708 100644 --- a/include/ensmallen.hpp +++ b/include/ensmallen.hpp @@ -103,6 +103,7 @@ #include "ensmallen_bits/katyusha/katyusha.hpp" #include "ensmallen_bits/lbfgs/lbfgs.hpp" #include "ensmallen_bits/lookahead/lookahead.hpp" +#include "ensmallen_bits/moead/moead.hpp" #include "ensmallen_bits/nsga2/nsga2.hpp" #include "ensmallen_bits/padam/padam.hpp" #include "ensmallen_bits/parallel_sgd/parallel_sgd.hpp" diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp new file mode 100644 index 000000000..d9c0bb76f --- /dev/null +++ b/include/ensmallen_bits/moead/moead.hpp @@ -0,0 +1,290 @@ +/** + * @file moead.hpp + * @author Utkarsh Rai + * + * MOEA/D, Multi Objective Evolutionary Algorithm based on Decompositon is a + * multi objective optimization algorithm. It employs evolutionary algorithms, + * to find better solutions by iterating on the previous solutions and + * decomposition approaches, to convert the multi objective problem to a single + * objective one, to find the best Pareto Front for the given problem. + * + * ensmallen is free software; you may redistribute it and/or modify it under + * the terms of the 3-clause BSD license. You should have received a copy of + * the 3-clause BSD license along with ensmallen. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + */ + +#ifndef ENSMALLEN_MOEAD_MOEAD_HPP +#define ENSMALLEN_MOEAD_MOEAD_HPP + +namespace ens { + +/** + * This class implements the MOEA/D algorithm with Differential Evolution + * crossover. Step numbers used in different parts of the implementation + * correspond to the step number used in the original algorithm by the author. + * + * For more information, see the following: + * @code + * @article{article, + * author = {Zhang, Qingfu and Li, Hui}, + * year = {2008}, + * pages = {712 - 731}, + * title = {MOEA/D: A Multiobjective Evolutionary Algorithm Based on + * Decomposition}, + * journal = {Evolutionary Computation, IEEE Transactions on}, + * + * @article{4633340, + * author={H. {Li} and Q. {Zhang}}, + * year={2009}, + * pages={284-302},} + * title={Multiobjective Optimization Problems With Complicated Pareto Sets, MOEA/D and NSGA-II}, + * journal={IEEE Transactions on Evolutionary Computation}, + * @endcode + * + * MOEA/D can optimize arbitrary multi-objective functions. For more details, + * see the documentation on function types included with this distribution or + * on the ensmallen website. + */ +class MOEAD { + public: + /** + * Constructor for the MOEA/D optimizer. + * + * The default values provided here are not necessarily suitable for a + * given function. Therefore, it is highly recommended to adjust the + * parameters according to the problem. + * + * @param populationSize The number of elements in the population. + * @param numGeneration The number of generations the algorithm runs. + * @param crossoverProb The probability that a crossover will occur. + * @param mutationProb The probability that a mutation will occur. + * @param mutationStrength The strength of mutation. + * @param neighborSize The number of nearest neighbours of weights + * to find. + * @param distributionIndex The distribution index for polynomial mutation. + * @param lowerBound The lower bound on each variable of a member + * of the variable space. + * @param upperBound The upper bound on each variable of a member + * of the variable space. + */ + MOEAD(const size_t populationSize = 100, + const size_t numGeneration = 100, + const double crossoverProb = 0.6, + const double mutationProb = 0.3, + const double mutationStrength = 1e-3, + const size_t neighborSize = 50, + const double distributionIndex = 0.5, + const double neighborProb = 0.5, + const arma::vec& lowerBound = arma::zeros(1, 1), + const arma::vec& upperBound = arma::ones(1, 1)); + + /** + * Constructor for the MOEA/D optimizer. This constructor is provides an + * overload to use lowerBound and upperBound as doubles, in case all the + * variables in the problem have the same limits. + * + * The default values provided here are not necessarily suitable for a + * given function. Therefore, it is highly recommended to adjust the + * parameters according to the problem. + * + * @param populationSize The number of elements in the population. + * @param numGeneration The number of generations the algorithm runs. + * @param crossoverProb The probability that a crossover will occur. + * @param mutationProb The probability that a mutation will occur. + * @param mutationStrength The strength of mutation. + * @param neighborSize The number of nearest neighbours of weights + * to find. + * @param distributionIndex The distribution index for polynomial mutation. + * @param lowerBound The lower bound on each variable of a member + * of the variable space. + * @param upperBound The upper bound on each variable of a member + * of the variable space. + */ + MOEAD(const size_t populationSize = 100, + const size_t numGeneration = 100, + const double crossoverProb = 0.6, + const double mutationProb = 0.3, + const double mutationStrength = 1e-3, + const size_t neighborSize = 50, + const double distributionIndex = 0.5, + const double neighborProb = 0.5, + const double lowerBound = 0, + const double upperBound = 1); + + /** + * Optimize a set of objectives. The initial population is generated + * using the initial point. The output is the best generated front. + * + * @tparam MatType The type of matrix used to store coordinates. + * @tparam ArbitraryFunctionType The type of objective function. + * @tparam CallbackTypes Types of callback function. + * @param objectives std::tuple of the objective functions. + * @param iterate The initial reference point for generating population. + * @param callbacks The callback functions. + */ + template + typename MatType::elem_type Optimize(std::tuple& objectives, + MatType& iterate, + CallbackTypes&&... callbacks); + + //! Get the population size. + size_t PopulationSize() const { return populationSize; } + //! Modify the population size. + size_t& PopulationSize() { return populationSize; } + + //! Get the number of generations. + size_t NumGeneration() const { return numGeneration; } + //! Modify the number of generations. + size_t& NumGeneration() { return numGeneration; } + + //! Get the crossover rate. + double CrossoverRate() const { return crossoverProb; } + //! Modify the crossover rate. + double& CrossoverRate() { return crossoverProb; } + + //! Get the mutation probability. + double MutationProbability() const { return mutationProb; } + //! Modify the mutation probability. + double& MutationProbability() { return mutationProb; } + + //! Get the size of the weight neighbor. + size_t NeighborSize() const { return neighborSize; } + //! Modify the size of the weight neighbor. + size_t& NeighborSize() { return neighborSize; } + + //! Get the value of the distribution index. + double DistributionIndex() const { return distributionIndex; } + //! Modify the value of the distribution index. + double& DistributionIndex() { return distributionIndex; } + + //! Get the value of neighbor probability. + double NeighborProb() const { return neighborProb; } + //! Modify the value of neigbourhood probability. + double& NeighborProb() { return neighborProb; } + + //! Retrieve value of lowerBound. + const arma::vec& LowerBound() const { return lowerBound; } + //! Modify value of lowerBound. + arma::vec& LowerBound() { return lowerBound; } + + //! Retrieve value of upperBound. + const arma::vec& UpperBound() const { return upperBound; } + //! Modify value of upperBound. + arma::vec& UpperBound() { return upperBound; } + + //! Retrieve the best front (the Pareto frontier). This returns an empty + //! vector until `Optimize()` has been called. + const std::vector& Front() const { return bestFront; } + + private: + + /** + * Mutate child formed by the crossover of two random members of the + * population. + * + * @tparam MatType The type of matrix used to store coordinates. + * @param child The matrix to mutate. + * @param rate To determine whether mutation happens at a particular index. + * @param lowerBound The lower bound on each variable in the matrix. + * @param upperBound The upper bound on each variable in the matrix. + */ + template + void Mutate(MatType& child, + const double& rate, + const arma::vec& lowerBound, + const arma::vec& upperBound); + + /** + * Decompose the multi objective problem to a single objetive problem + * using the Tchebycheff approach. + * + * @param weights A set of)real number which act as weights. + * @param idealPoint Ideal point z in Tchebycheff decomposition. + * @param evaluatedCandidate Value of the candidate per objective. + * @return The single value obtained from decomposed function. + */ + double DecomposedSingleObjective(const arma::vec& weights, + const arma::vec& idealPoint, + const arma::vec& evaluatedCandidate); + + /** + * Check domination between two vectors. + * + * @param first, the first of the two vectors to compare. + * @param second, the second of the two vectors to compare. + * @return true if first dominates second else false. + */ + bool Dominates(const arma::vec& first, + const arma::vec& second); + + /** + * Evaluate objectives for the elite population. + * + * @tparam ArbitraryFunctionType std::tuple of multiple function types. + * @tparam MatType Type of matrix to optimize. + * @param population The elite population. + * @param objectives The set of objectives. + * @param calculatedObjectives Vector to store calculated objectives. + */ + template + typename std::enable_if::type + EvaluateObjectives(std::vector&, + std::tuple&, + arma::mat&); + + template + typename std::enable_if::type + EvaluateObjectives(std::vector& population, + std::tuple& objectives, + arma::mat& calculatedObjectives); + + //! Size of the population. + size_t populationSize; + + //! Number of generations. + size_t numGeneration; + + //! Probability of crossover between two members. + double crossoverProb; + + //! Probability of mutation of a child. + double mutationProb; + + //! Strength of mutation. + double mutationStrength; + + //! Number of nearest neighbours of weights to consider. + size_t neighborSize; + + //! Distribution index for the polynomial distribution. + double distributionIndex; + + //! The probability that two elements will be chosen from the neighbor. + double neighborProb; + + //! Lower bound on each variable in the variable space. + arma::vec lowerBound; + + //! Upper bound on each variable in the variable space. + arma::vec upperBound; + + //! The number of objectives in multi objective optimisation problem. + size_t numObjectives; + + //! The Pareto Optimal Front. + std::vector bestFront; +}; + +} // namespace ens + +// Include implementation. +#include "moead_impl.hpp" + +#endif diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp new file mode 100644 index 000000000..e6890c037 --- /dev/null +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -0,0 +1,411 @@ +/** + * @file moead_impl.hpp + * @author Utkarsh Rai + * + * Implementation of the MOEA/D algorithm. Used for multi-objective + * optimization problems on arbitrary functions. + * + * ensmallen is free software; you may redistribute it and/or modify it under + * the terms of the 3-clause BSD license. You should have received a copy of + * the 3-clause BSD license along with ensmallen. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more Information. + */ + +#ifndef ENSMALLEN_MOEAD_MOEAD_IMPL_HPP +#define ENSMALLEN_MOEAD_MOEAD_IMPL_HPP + +#include "moead.hpp" + +namespace ens { + +inline MOEAD::MOEAD(const size_t populationSize, + const size_t numGeneration, + const double crossoverProb, + const double mutationProb, + const double mutationStrength, + const size_t neighborSize, + const double distributionIndex, + const double neighborProb, + const arma::vec& lowerBound, + const arma::vec& upperBound) : + populationSize(populationSize), + numGeneration(numGeneration), + crossoverProb(crossoverProb), + mutationProb(mutationProb), + mutationStrength(mutationStrength), + neighborSize(neighborSize), + distributionIndex(distributionIndex), + neighborProb(neighborProb), + lowerBound(lowerBound), + upperBound(upperBound), + numObjectives(0) + { /* Nothing to do here. */ } + +inline MOEAD::MOEAD(const size_t populationSize, + const size_t numGeneration, + const double crossoverProb, + const double mutationProb, + const double mutationStrength, + const size_t neighborSize, + const double distributionIndex, + const double neighborProb, + const double lowerBound, + const double upperBound) : + populationSize(populationSize), + numGeneration(numGeneration), + crossoverProb(crossoverProb), + mutationProb(mutationProb), + mutationStrength(mutationStrength), + neighborSize(neighborSize), + distributionIndex(distributionIndex), + neighborProb(neighborProb), + lowerBound(lowerBound * arma::ones(1, 1)), + upperBound(upperBound * arma::ones(1, 1)), + numObjectives(0) + { /* Nothing to do here. */ } + +//! Optimize the function. +template +typename MatType::elem_type MOEAD::Optimize(std::tuple& objectives, + MatType& iterate, + CallbackTypes&&... callbacks) +{ + // Check if lower bound is a vector of a single dimension. + if (lowerBound.n_rows == 1) + lowerBound = lowerBound(0, 0) * arma::ones(iterate.n_rows, iterate.n_cols); + + // Check if lower bound is a vector of a single dimension. + if (upperBound.n_rows == 1) + upperBound = upperBound(0, 0) * arma::ones(iterate.n_rows, iterate.n_cols); + // Convenience typedefs. + typedef typename MatType::elem_type ElemType; + + if(lowerBound.size() != upperBound.size()) + { + throw std::logic_error("MOEAD::Optimize(): size of lowerBound and upperBound " + "must be equal."); + } + + if(lowerBound.size() != iterate.n_elem) + { + throw std::logic_error("MOEAD::Optimize(): there should be a lower bound and " + "an upper bound for each variable in the initial point."); + } + + if(populationSize < neighborSize + 1) + { + std::ostringstream oss; + oss << "MOEAD::Optimize(): " << "neighborSize is " << neighborSize + << "but populationSize is " << populationSize << "(should be" + << " atleast " << neighborSize + 1 << std::endl; + throw std::logic_error(oss.str()); + } + + // Number of objective functions. Represented by m in the paper. + numObjectives = sizeof...(ArbitraryFunctionType); + + // Controls early termination of the optimization process. + bool terminate = false; + + // 1.1 The external population, non-dominated solutions. + std::vector externalPopulation; + std::vector externalPopulationFValue; + + arma::Col shuffle; + // The Lambda matrix. Each vector represents a decomposition subproblem. + arma::Mat weights(numObjectives, populationSize, arma::fill::randu); + + // 1.2 Storing the indices of nearest neighbours of each weight vector. + arma::Mat weightNeighbourIndices(neighborSize, populationSize); + for (size_t i = 0; i < populationSize; ++i) + { + // To temporarily store the distance between weights(i) and each other weights. + arma::rowvec distances(populationSize); + distances = + arma::sqrt(arma::sum(arma::pow(weights.col(i) - weights.each_col(), 2))); + arma::uvec sortedIndices = arma::stable_sort_index(distances); + // Ignore distance from self + weightNeighbourIndices.col(i) = sortedIndices(arma::span(1, neighborSize)); + } + + // 1.3 Random generation of the initial population. + std::vector population(populationSize); + for (size_t i = 0; i < populationSize; ++i) + { + population[i] = arma::randu(iterate.n_rows, iterate.n_cols) + - 0.5 + iterate; + + population[i] = population[i] < lowerBound ? lowerBound : population[i]; + population[i] = population[i] > upperBound ? upperBound : population[i]; + } + + // 1.3 F-value initialisation for the population. + arma::mat FValue(numObjectives, populationSize); + EvaluateObjectives(population, objectives, FValue); + + // 1.4 Initialize the ideal point z. + arma::mat idealPoint(numObjectives, 1); + idealPoint.fill(std::numeric_limits::max()); + for (size_t i = 0; i < numObjectives; ++i) + { + for (size_t j = 0; j < populationSize; ++j) + { + idealPoint(i, 0) = std::min(idealPoint(i, 0), FValue(i, j)); + } + } + + terminate |= Callback::BeginOptimization(*this, objectives, iterate, callbacks...); + + // 2 The main loop. + for (size_t g = 0; g < numGeneration; ++g) + { + shuffle = std::get<0>(objectives).Shuffle(populationSize); + for (size_t i : shuffle) + { + terminate |= Callback::StepTaken(*this, objectives, iterate, callbacks...); + + // 2.1 Randomly select two indices in weightNeighbourIndices(i) and use them + // to make a child. + size_t k, l; + if(arma::randu() < neighborProb) + { + k = weightNeighbourIndices(i, arma::randi(arma::distr_param(0, neighborSize - 1))); + l = weightNeighbourIndices(i, arma::randi(arma::distr_param(0, neighborSize - 1))); + if(k == l) + { + if(k == neighborSize - 1) + --k; + else + ++k; + } + } + else + { + k = arma::randi(arma::distr_param(0, populationSize - 1)); + l = arma::randi(arma::distr_param(0, populationSize - 1)); + if(k == l) + { + if(k == populationSize - 1) + --k; + else + ++k; + } + } + std::vector candidate(1); + double determiner1 = arma::randu(); + if(determiner1 < crossoverProb) + { + candidate[0].resize(iterate.n_rows, iterate.n_cols); + for (size_t idx = 0;idx < iterate.n_rows; ++idx) + { + double determiner2 = arma::randu(); + if (determiner2 < 0.5) + candidate[0][idx] = population[k][idx]; + else + candidate[0][idx] = population[l][idx]; + if(candidate[0][idx] < lowerBound(idx)) + candidate[0][idx] = lowerBound(idx); + if(candidate[0][idx]>upperBound(idx)) + candidate[0][idx] = upperBound(idx); + } + } + else + candidate[0] = population[i]; + + // 2.2 Improve the child. + Mutate(candidate[0], 1 / numObjectives, lowerBound, upperBound); + + // Store solution for candidate. + arma::mat evaluatedCandidate(numObjectives, 1); + EvaluateObjectives(candidate, objectives, evaluatedCandidate); + + // 2.3 Update of ideal point. + for (size_t idx = 0;idx < numObjectives;++idx) + { + idealPoint(idx, 0) = std::min(idealPoint(idx, 0), + evaluatedCandidate(idx, 0)); + } + + // 2.4 Update of the neighbouring solutions. + for (size_t idx = 0;idx < neighborSize;++idx) + { + if (DecomposedSingleObjective(weights.col(weightNeighbourIndices(i, idx)), + idealPoint.col(0), evaluatedCandidate.col(0)) + <= DecomposedSingleObjective( + weights.col(weightNeighbourIndices(i,idx)), + idealPoint.col(0), FValue.col(weightNeighbourIndices(i, idx)))) + { + population.at(weightNeighbourIndices(i, idx)) = candidate[0]; + FValue.col(weightNeighbourIndices(i, idx)) = evaluatedCandidate.col(0); + } + } + + // 2.5 Updating External Population. + if (!externalPopulation.empty()) + { + arma::mat first(numObjectives, 1); + auto df = [&](MatType firstMat) -> bool + { + std::vector wrapperFirst(1), wrapperSecond(1); + wrapperFirst[0] = firstMat; + EvaluateObjectives(wrapperFirst, objectives, first); + return Dominates(evaluatedCandidate.col(0), first.col(0)); + }; + //! Remove the part that is dominated by candidate. + externalPopulation.erase( + std::remove_if( + externalPopulation.begin(), + externalPopulation.end(), + df), externalPopulation.end()); + + //! Check if any of the remaining members of external population dominate + //! candidate. + bool flag = 0; + std::vector wrapperFirst(1); + for (size_t idx = 0; idx < externalPopulation.size(); ++idx) + { + wrapperFirst[0]=externalPopulation[idx]; + first.clear(); + first.resize(numObjectives, 1); + EvaluateObjectives(wrapperFirst, objectives, first); + if (Dominates(first.col(0), evaluatedCandidate.col(0))) + { + flag = 1; + break; + } + } + if (flag == 0) + { + externalPopulation.push_back(candidate[0]); + externalPopulationFValue.push_back(evaluatedCandidate.col(0)); + } + } + else + { + externalPopulation.push_back(candidate[0]); + externalPopulationFValue.push_back(evaluatedCandidate.col(0)); + } + } + } + bestFront = std::move(externalPopulation); + + Callback::EndOptimization(*this, objectives, iterate, callbacks...); + + ElemType performance = std::numeric_limits::max(); + for (arma::Col objective: externalPopulationFValue) + { + if (arma::accu(objective) < performance) + performance = arma::accu(objective); + } + + return performance; +} + +//! Perform mutation of the candidate. +template +inline void MOEAD::Mutate(MatType& child, + const double& rate, + const arma::vec& lowerBound, + const arma::vec& upperBound) +{ + size_t numVariables = lowerBound.n_elem; + double rnd, delta1, delta2, mutationPower, deltaq; + double current, currentLower, currentUpper, value, upperDelta; + + for (size_t j = 0; j < numVariables; ++j) + { + double determiner = arma::randu(); + if (determiner <= rate) + { + current = child[j]; + currentLower = lowerBound(j); + currentUpper = upperBound(j); + delta1 = (current - currentLower) / (currentUpper - currentLower); + delta2 = (currentUpper - current) / (currentUpper - currentLower); + rnd = arma::randu(); + mutationPower= 1 / distributionIndex; + if (rnd <= 0.5) + { + upperDelta = 1.0 - delta1; + value = 2.0 * rnd + (1.0 - 2.0 * rnd) * + (std::pow(upperDelta, (distributionIndex + 1.0))); + deltaq = std::pow(value, mutationPower) - 1.0; + } + else + { + upperDelta = 1.0 - delta2; + value = 2.0 * (1.0 - rnd) + 2.0 * (rnd - 0.5) * + (pow(upperDelta, (distributionIndex + 1.0))); + deltaq = 1.0 - (pow(value, mutationPower)); + } + current = current + deltaq * (currentUpper - currentLower); + if (current < currentLower) current = currentLower; + if (current > currentUpper) current = currentUpper; + child[j] = current; + } + } +} + +//! Calculate the output for single objective function using the Tchebycheff +//! approach. +inline double MOEAD::DecomposedSingleObjective(const arma::vec& weights, + const arma::vec& idealPoint, + const arma::vec& evaluatedCandidate) +{ + return arma::min(weights % arma::abs(evaluatedCandidate - idealPoint)); +} + +inline bool MOEAD::Dominates(const arma::vec& first, + const arma::vec& second) +{ + int flag = 0; + for (size_t i = 0; i < numObjectives; ++i) + { + if (first(i) > second(i)) + return false; + + if(first(i) < second(i)) + flag = 1; + } + if (flag) + return true; + + return false; +} + +//! No objectives to evaluate. +template + typename std::enable_if::type +MOEAD::EvaluateObjectives( + std::vector&, + std::tuple&, + arma::mat &) +{ + // Nothing to do here. +} + +//! Evaluate the objectives for the entire population. +template + typename std::enable_if::type +MOEAD::EvaluateObjectives( + std::vector& population, + std::tuple& objectives, + arma::mat& calculatedObjectives) +{ + for (size_t i = 0; i < population.size(); ++i) + { + calculatedObjectives(I, i) = std::get(objectives).Evaluate(population[i]); + EvaluateObjectives(population, objectives, + calculatedObjectives); + } +} +} + +#endif + diff --git a/include/ensmallen_bits/problems/fonseca_fleming_function.hpp b/include/ensmallen_bits/problems/fonseca_fleming_function.hpp index 34bc95b0f..3e2726eef 100644 --- a/include/ensmallen_bits/problems/fonseca_fleming_function.hpp +++ b/include/ensmallen_bits/problems/fonseca_fleming_function.hpp @@ -80,6 +80,12 @@ class FonsecaFlemingFunction -pow(static_cast(coords[2]) - 1.0 / sqrt(3.0), 2.0) ); } + arma::Col Shuffle(size_t& populationSize) + { + return arma::shuffle(arma::linspace >(0, + populationSize -1)); + + } } objectiveA; struct ObjectiveB diff --git a/include/ensmallen_bits/problems/schaffer_function_n1.hpp b/include/ensmallen_bits/problems/schaffer_function_n1.hpp index 4c31974ea..bf3c7c417 100644 --- a/include/ensmallen_bits/problems/schaffer_function_n1.hpp +++ b/include/ensmallen_bits/problems/schaffer_function_n1.hpp @@ -75,6 +75,11 @@ class SchafferFunctionN1 { return std::pow(coords[0], 2); } + arma::Col Shuffle(size_t& populationSize) + { + return arma::shuffle(arma::linspace >(0, + populationSize -1)); + } } objectiveA; struct ObjectiveB diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6b55d4a4a..e17ec5a34 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -23,6 +23,7 @@ set(ENSMALLEN_TESTS_SOURCES line_search_test.cpp lookahead_test.cpp lrsdp_test.cpp + moead_test.cpp momentum_sgd_test.cpp nesterov_momentum_sgd_test.cpp nsga2_test.cpp diff --git a/tests/moead_test.cpp b/tests/moead_test.cpp new file mode 100644 index 000000000..567eaf5ac --- /dev/null +++ b/tests/moead_test.cpp @@ -0,0 +1,182 @@ + +/** + * @file moead_test.cpp + * @author Sayan Goswami + * @author Utkarsh Rai + * + * ensmallen is free software; you may redistribute it and/or modify it under + * the terms of the 3-clause BSD license. You should have received a copy of + * the 3-clause BSD license along with ensmallen. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + */ + +#include +#include "catch.hpp" +#include "test_function_tools.hpp" + +using namespace ens; +using namespace ens::test; +using namespace std; + +/** + * Checks if low <= value <= high. Used by MOEADFonsecaFlemingTest. + * + * @param value The value being checked. + * @param low The lower bound. + * @param high The upper bound. + * @return true if value lies in the range [low, high]. + * @return false if value does not lie in the range [low, high]. + */ +bool InBounds(const double& value, const double& low, const double& high) +{ + return !(value < low) && !(high < value); +} + +/** + * Optimize for the Fonseca Fleming function using MOEA/D optimizer. + */ +TEST_CASE("MOEADFonsecaFlemingTest", "[MOEADTest]") +{ + FonsecaFlemingFunction FON; + const double lowerBound = -4; + const double upperBound = 4; + const double strength = 1e-3; + const double expectedLowerBound = -1.0 / sqrt(3); + const double expectedUpperBound = 1.0 / sqrt(3); + MOEAD opt(150, 10, 0.6, 0.7, strength, 10, 0.5, 0.5, lowerBound, upperBound); + + typedef decltype(FON.objectiveA) ObjectiveTypeA; + typedef decltype(FON.objectiveB) ObjectiveTypeB; + arma::mat coords = FON.GetInitialPoint(); + std::tuple objectives = FON.GetObjectives(); + opt.Optimize(objectives, coords); + std::vector bestFront = opt.Front(); + bool allInRange = true; + for (size_t i = 0; i < bestFront.size(); i++) + { + const arma::mat solution = bestFront[i]; + double valX = arma::as_scalar(solution(0)); + double valY = arma::as_scalar(solution(1)); + double valZ = arma::as_scalar(solution(2)); + std::cout< FON; + const arma::vec lowerBound("-4 -4 -4"); + const arma::vec upperBound("4 4 4"); + const double strength = 1e-3; + const double expectedLowerBound = -1.0 / sqrt(3); + const double expectedUpperBound = 1.0 / sqrt(3); + MOEAD opt(150, 10, 0.6, 0.7, strength, 10, 0.5, 0.5, lowerBound, upperBound); + + typedef decltype(FON.objectiveA) ObjectiveTypeA; + typedef decltype(FON.objectiveB) ObjectiveTypeB; + arma::mat coords = FON.GetInitialPoint(); + std::tuple objectives = FON.GetObjectives(); + opt.Optimize(objectives, coords); + std::vector bestFront = opt.Front(); + bool allInRange = true; + for (size_t i = 0; i < bestFront.size(); i++) + { + const arma::mat solution = bestFront[i]; + double valX = arma::as_scalar(solution(0)); + double valY = arma::as_scalar(solution(1)); + double valZ = arma::as_scalar(solution(2)); + + if (!InBounds(valX, expectedLowerBound, expectedUpperBound) || + !InBounds(valY, expectedLowerBound, expectedUpperBound) || + !InBounds(valZ, expectedLowerBound, expectedUpperBound)) + { + allInRange = false; + break; + } + } + REQUIRE(allInRange); +} +/** + * Optimize for the function using MOEA/D optimizer. + */ +TEST_CASE("MOEADSchafferN1Test", "[MOEADTest]") +{ + SchafferFunctionN1 SCH; + double lowerBound = {-1000}; + const double upperBound = {1000}; + + MOEAD opt(150, 10, 0.6, 0.7, 1e-3, 9, 0.5, 0.5, lowerBound, upperBound); + + typedef decltype(SCH.objectiveA) ObjectiveTypeA; + typedef decltype(SCH.objectiveB) ObjectiveTypeB; + + arma::mat coords = SCH.GetInitialPoint(); + std::tuple objectives = + SCH.GetObjectives(); + + opt.Optimize(objectives, coords); + std::vector bestFronts = opt.Front(); + + bool allInRange = true; + double minimumPositive = 1000; + + for (arma::mat solution: bestFronts) + { + const double val = arma::as_scalar(solution); + minimumPositive = std::min(minimumPositive, val>=0 ? val : 1000); + std::cout< 2.0) + { + allInRange = false; + break; + } + } + REQUIRE(allInRange); +} +/** + * Optimize for the function using MOEA/D optimizer. + */ +TEST_CASE("MOEADSchafferN1VectorBoundsTest", "[MOEADTest]") +{ + SchafferFunctionN1 SCH; + arma::vec lowerBound = {-1000}; + arma::vec upperBound = {1000}; + + MOEAD opt(150, 10, 0.6, 0.7, 1e-3, 9, 0.5, 0.5, lowerBound, upperBound); + + typedef decltype(SCH.objectiveA) ObjectiveTypeA; + typedef decltype(SCH.objectiveB) ObjectiveTypeB; + + arma::mat coords = SCH.GetInitialPoint(); + std::tuple objectives = + SCH.GetObjectives(); + + opt.Optimize(objectives, coords); + std::vector bestFronts = opt.Front(); + + bool allInRange = true; + double minimumPositive = 1000; + + for (arma::mat solution: bestFronts) + { + double val = arma::as_scalar(solution); + minimumPositive = std::min(minimumPositive, val>=0 ? val : 1000); + if (val < 0.00 || val > 2.0) + { + allInRange = false; + break; + } + } + REQUIRE(allInRange); +} diff --git a/tests/nsga2_test.cpp b/tests/nsga2_test.cpp index 3715c5ffb..578a78071 100644 --- a/tests/nsga2_test.cpp +++ b/tests/nsga2_test.cpp @@ -62,6 +62,7 @@ TEST_CASE("NSGA2SchafferN1DoubleTest", "[NSGA2Test]") arma::cube paretoSet= opt.ParetoSet(); bool allInRange = true; + double minimumPositive = 1000; for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx) { From 19425d4d78db5bcbefe8e72a0a022ed475ccdba5 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Mon, 8 Mar 2021 18:12:25 +0530 Subject: [PATCH 002/128] - wrap mating in a function - declare DifferentialCrossover --- include/ensmallen_bits/moead/moead.hpp | 26 +++++++- include/ensmallen_bits/moead/moead_impl.hpp | 74 +++++++++++++-------- 2 files changed, 73 insertions(+), 27 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index d9c0bb76f..e0e7d84ab 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -180,7 +180,28 @@ class MOEAD { const std::vector& Front() const { return bestFront; } private: - + /** + * @brief Randomly select two members from the population. + * + * @param weightNeighbourIndices + * @return std::tuple + */ + std::tuple + MatingSelection(const arma::Mat& weightNeighbourIndices); + /** + * @brief Produces an offspring using the Differential Operator. + * Note that r1 != r2 != r3. + * + * @param x_r1 The randomly chosen vector form the population + * @param x_r2 The randomly chosen vector from the population. + * @param x_r3 The randomly chosen vector from the population. + * @return The solution vector + */ + template + MatType DifferentialCrossover( + const MatType& x_r1, + const MatType& x_r2, + const MatType& x_r3); /** * Mutate child formed by the crossover of two random members of the * population. @@ -278,6 +299,9 @@ class MOEAD { //! The number of objectives in multi objective optimisation problem. size_t numObjectives; + //! + doubel + //! The Pareto Optimal Front. std::vector bestFront; }; diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index e6890c037..01d3d6ccd 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -168,31 +168,12 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // 2.1 Randomly select two indices in weightNeighbourIndices(i) and use them // to make a child. - size_t k, l; - if(arma::randu() < neighborProb) - { - k = weightNeighbourIndices(i, arma::randi(arma::distr_param(0, neighborSize - 1))); - l = weightNeighbourIndices(i, arma::randi(arma::distr_param(0, neighborSize - 1))); - if(k == l) - { - if(k == neighborSize - 1) - --k; - else - ++k; - } - } - else - { - k = arma::randi(arma::distr_param(0, populationSize - 1)); - l = arma::randi(arma::distr_param(0, populationSize - 1)); - if(k == l) - { - if(k == populationSize - 1) - --k; - else - ++k; - } - } + size_t r1, r2, r3; + r1 = i; + std::tie(r2, r3) = MatingSelection(weightNeighbourIndices); + + // 2.2 Reproduction: Apply the Differential Operator on the selected indices + // followed by Mutation. std::vector candidate(1); double determiner1 = arma::randu(); if(determiner1 < crossoverProb) @@ -214,7 +195,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple else candidate[0] = population[i]; - // 2.2 Improve the child. + Mutate(candidate[0], 1 / numObjectives, lowerBound, upperBound); // Store solution for candidate. @@ -303,6 +284,47 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple return performance; } +inline std::tuple +MOEAD::MatingSelection(const arma::Mat& weightNeighbourIndices) +{ + size_t k, l; + if (arma::randu() < neighborProb) + { + k = weightNeighbourIndices( + i, arma::randi(arma::distr_param(0, neighborSize - 1))); + l = weightNeighbourIndices( + i, arma::randi(arma::distr_param(0, neighborSize - 1))); + if (k == l) + { + if (k == neighborSize - 1) + --k; + else + ++k; + } + } + else + { + k = arma::randi(arma::distr_param(0, populationSize - 1)); + l = arma::randi(arma::distr_param(0, populationSize - 1)); + if (k == l) + { + if (k == populationSize - 1) + --k; + else + ++k; + } + } + + return std::make_tuple(k, l); +} + +template +MatType DifferentialCrossover(const MatType& x_r1, + const MatType& x_r2, + const MatType& x_r3) +{ + +} //! Perform mutation of the candidate. template inline void MOEAD::Mutate(MatType& child, From 91df7068c5528bcc2c5ebe3a54f6e6644f8c6f3b Mon Sep 17 00:00:00 2001 From: NanuSai Date: Mon, 8 Mar 2021 18:38:12 +0530 Subject: [PATCH 003/128] crossover inside mainloop --- include/ensmallen_bits/moead/moead.hpp | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index e0e7d84ab..bf4a6f5ea 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -188,20 +188,7 @@ class MOEAD { */ std::tuple MatingSelection(const arma::Mat& weightNeighbourIndices); - /** - * @brief Produces an offspring using the Differential Operator. - * Note that r1 != r2 != r3. - * - * @param x_r1 The randomly chosen vector form the population - * @param x_r2 The randomly chosen vector from the population. - * @param x_r3 The randomly chosen vector from the population. - * @return The solution vector - */ - template - MatType DifferentialCrossover( - const MatType& x_r1, - const MatType& x_r2, - const MatType& x_r3); + /** * Mutate child formed by the crossover of two random members of the * population. From 3d91ccc37fc7e9fc1e32823362477b7c568063ea Mon Sep 17 00:00:00 2001 From: NanuSai Date: Mon, 8 Mar 2021 18:41:15 +0530 Subject: [PATCH 004/128] differential crossover --- include/ensmallen_bits/moead/moead.hpp | 4 +- include/ensmallen_bits/moead/moead_impl.hpp | 47 ++++++++++----------- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index bf4a6f5ea..36c3290f4 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -286,8 +286,8 @@ class MOEAD { //! The number of objectives in multi objective optimisation problem. size_t numObjectives; - //! - doubel + //! Scale the difference between two random points during crossover. + double scalingFactor; //! The Pareto Optimal Front. std::vector bestFront; diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 01d3d6ccd..15e5397ae 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -174,29 +174,35 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // 2.2 Reproduction: Apply the Differential Operator on the selected indices // followed by Mutation. - std::vector candidate(1); - double determiner1 = arma::randu(); - if(determiner1 < crossoverProb) + MatType candidate(iterate.nrows, iterate.ncols); //TODO: Potentially wrong, because iterate can be a population swarm + double delta = arma::randu(); + if (delta < crossoverProb) { - candidate[0].resize(iterate.n_rows, iterate.n_cols); - for (size_t idx = 0;idx < iterate.n_rows; ++idx) + for (size_t geneIdx = 0; geneIdx < iterate.n_rows, ++geneIdx) { - double determiner2 = arma::randu(); - if (determiner2 < 0.5) - candidate[0][idx] = population[k][idx]; + candidate[geneIdx] = population[r1][geneIdx] + + scaleFactor * (population[r2][geneIdx] - + population[r3][geneIdx]); + + // Handle boundary condition + if (candidate[geneIdx] < lowerBound[geneIdx]) + { + candidate[geneIdx] = lowerBound[geneIdx] + + arma::randu() * (population[i][geneIdx] - + lowerBound[geneIdx]); + } + else if (candidate[geneIdx] > upperBound[geneIdx]) + { + candidate[geneIdx] = upperrBound[geneIdx] + + arma::randu() * (upperBound[geneIdx] - + population[i][geneIdx]); + } else - candidate[0][idx] = population[l][idx]; - if(candidate[0][idx] < lowerBound(idx)) - candidate[0][idx] = lowerBound(idx); - if(candidate[0][idx]>upperBound(idx)) - candidate[0][idx] = upperBound(idx); + candidate[geneIdx] = population[i][geneIdx]; } } - else - candidate[0] = population[i]; - - Mutate(candidate[0], 1 / numObjectives, lowerBound, upperBound); + Mutate(candidate[0], 1 / numObjectives, lowerBound, upperBound); // Store solution for candidate. arma::mat evaluatedCandidate(numObjectives, 1); @@ -318,13 +324,6 @@ MOEAD::MatingSelection(const arma::Mat& weightNeighbourIndices) return std::make_tuple(k, l); } -template -MatType DifferentialCrossover(const MatType& x_r1, - const MatType& x_r2, - const MatType& x_r3) -{ - -} //! Perform mutation of the candidate. template inline void MOEAD::Mutate(MatType& child, From a52f1ad5f4455c8b6a60357d537731ace0e03740 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Mon, 8 Mar 2021 18:44:04 +0530 Subject: [PATCH 005/128] cast to vector only at EvaluateObjectives --- include/ensmallen_bits/moead/moead_impl.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 15e5397ae..7362df779 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -202,11 +202,11 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple } } - Mutate(candidate[0], 1 / numObjectives, lowerBound, upperBound); + Mutate(candidate, 1 / numObjectives, lowerBound, upperBound); // Store solution for candidate. arma::mat evaluatedCandidate(numObjectives, 1); - EvaluateObjectives(candidate, objectives, evaluatedCandidate); + EvaluateObjectives(std::vector(candidate), objectives, evaluatedCandidate); // 2.3 Update of ideal point. for (size_t idx = 0;idx < numObjectives;++idx) From bb414e68edce830d98a963f6476b20c346c97592 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Mon, 8 Mar 2021 18:46:19 +0530 Subject: [PATCH 006/128] convention --- include/ensmallen_bits/moead/moead_impl.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 7362df779..8657f9563 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -188,17 +188,17 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple if (candidate[geneIdx] < lowerBound[geneIdx]) { candidate[geneIdx] = lowerBound[geneIdx] + - arma::randu() * (population[i][geneIdx] - + arma::randu() * (population[r1][geneIdx] - lowerBound[geneIdx]); } else if (candidate[geneIdx] > upperBound[geneIdx]) { candidate[geneIdx] = upperrBound[geneIdx] + arma::randu() * (upperBound[geneIdx] - - population[i][geneIdx]); + population[r1][geneIdx]); } else - candidate[geneIdx] = population[i][geneIdx]; + candidate[geneIdx] = population[r1][geneIdx]; } } From 3cd94aeb67a5dc96dd351652b22d53429ec85ccc Mon Sep 17 00:00:00 2001 From: NanuSai Date: Mon, 8 Mar 2021 19:45:53 +0530 Subject: [PATCH 007/128] scalingFactor getter setter --- include/ensmallen_bits/moead/moead.hpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 36c3290f4..440323884 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -165,6 +165,11 @@ class MOEAD { //! Modify the value of neigbourhood probability. double& NeighborProb() { return neighborProb; } + //! Get the value of scaling factor. + double ScalingFactor() const { return scalingFactor; } + //! Modify the value of scaling factor. + double& ScalingFactor() { return scalingFactor; } + //! Retrieve value of lowerBound. const arma::vec& LowerBound() const { return lowerBound; } //! Modify value of lowerBound. @@ -277,6 +282,9 @@ class MOEAD { //! The probability that two elements will be chosen from the neighbor. double neighborProb; + //! Scale the difference between two random points during crossover. + double scalingFactor; + //! Lower bound on each variable in the variable space. arma::vec lowerBound; @@ -286,9 +294,6 @@ class MOEAD { //! The number of objectives in multi objective optimisation problem. size_t numObjectives; - //! Scale the difference between two random points during crossover. - double scalingFactor; - //! The Pareto Optimal Front. std::vector bestFront; }; From 28be655f0571065b8a6e588873735a7c725e4e11 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Mon, 8 Mar 2021 19:46:22 +0530 Subject: [PATCH 008/128] numVariables --- include/ensmallen_bits/moead/moead_impl.hpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 8657f9563..16524b5d8 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -103,8 +103,10 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple throw std::logic_error(oss.str()); } - // Number of objective functions. Represented by m in the paper. + // Number of objective functions. Represented by M in the paper. numObjectives = sizeof...(ArbitraryFunctionType); + // Dimensionality of variable space. Also referred to as number of genes. + size_t numVariables = iterate.n_rows; // Controls early termination of the optimization process. bool terminate = false; @@ -134,11 +136,16 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple std::vector population(populationSize); for (size_t i = 0; i < populationSize; ++i) { - population[i] = arma::randu(iterate.n_rows, iterate.n_cols) - - 0.5 + iterate; - - population[i] = population[i] < lowerBound ? lowerBound : population[i]; - population[i] = population[i] > upperBound ? upperBound : population[i]; + population[i] = + arma::randu(iterate.n_rows, iterate.n_cols) - 0.5 + iterate; + + for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) + { + if (population[i][geneIdx] < lowerBound[geneIdx]) + population[i][geneIdx] = lowerBound[geneIdx]; + else if (population[i][geneIdx] > upperBound[geneIdx]) + population[i][geneIdx] = upperBound[geneIdx]; + } } // 1.3 F-value initialisation for the population. @@ -178,7 +185,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple double delta = arma::randu(); if (delta < crossoverProb) { - for (size_t geneIdx = 0; geneIdx < iterate.n_rows, ++geneIdx) + for (size_t geneIdx = 0; geneIdx < numVariables, ++geneIdx) { candidate[geneIdx] = population[r1][geneIdx] + scaleFactor * (population[r2][geneIdx] - From ded4a43837e0ab18dd697a4d0215b5006ab67b9e Mon Sep 17 00:00:00 2001 From: NanuSai Date: Mon, 8 Mar 2021 20:18:33 +0530 Subject: [PATCH 009/128] 1.f / numVariables, should pass float --- include/ensmallen_bits/moead/moead_impl.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 16524b5d8..0daeb25ca 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -209,7 +209,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple } } - Mutate(candidate, 1 / numObjectives, lowerBound, upperBound); + Mutate(candidate, 1.f / numVariables, lowerBound, upperBound); // Store solution for candidate. arma::mat evaluatedCandidate(numObjectives, 1); @@ -353,8 +353,8 @@ inline void MOEAD::Mutate(MatType& child, delta1 = (current - currentLower) / (currentUpper - currentLower); delta2 = (currentUpper - current) / (currentUpper - currentLower); rnd = arma::randu(); - mutationPower= 1 / distributionIndex; - if (rnd <= 0.5) + mutationPower = 1.0 /( distributionIndex + 1.0 ); + if (rnd < 0.5) { upperDelta = 1.0 - delta1; value = 2.0 * rnd + (1.0 - 2.0 * rnd) * @@ -368,7 +368,8 @@ inline void MOEAD::Mutate(MatType& child, (pow(upperDelta, (distributionIndex + 1.0))); deltaq = 1.0 - (pow(value, mutationPower)); } - current = current + deltaq * (currentUpper - currentLower); + + current += deltaq * (currentUpper - currentLower); if (current < currentLower) current = currentLower; if (current > currentUpper) current = currentUpper; child[j] = current; From b01e7fab18bd6d4d38f48cbfc808cf49924dd754 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Mon, 8 Mar 2021 20:23:09 +0530 Subject: [PATCH 010/128] * scalingFactor in ctor * paper says 0.4 -> 1 is a good for scaling factor --- include/ensmallen_bits/moead/moead.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 440323884..a3d153651 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -76,6 +76,7 @@ class MOEAD { const size_t neighborSize = 50, const double distributionIndex = 0.5, const double neighborProb = 0.5, + const double scalingFactor = 0.6, const arma::vec& lowerBound = arma::zeros(1, 1), const arma::vec& upperBound = arma::ones(1, 1)); @@ -109,6 +110,7 @@ class MOEAD { const size_t neighborSize = 50, const double distributionIndex = 0.5, const double neighborProb = 0.5, + const double scalingFactor = 0.6, const double lowerBound = 0, const double upperBound = 1); From 5a07b38a3ac876295fda2f1b2e96075305deb0c8 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Mon, 8 Mar 2021 20:25:34 +0530 Subject: [PATCH 011/128] evaluatedCandidate => candidateFval --- include/ensmallen_bits/moead/moead_impl.hpp | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 0daeb25ca..7be6fbfe2 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -212,27 +212,27 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple Mutate(candidate, 1.f / numVariables, lowerBound, upperBound); // Store solution for candidate. - arma::mat evaluatedCandidate(numObjectives, 1); - EvaluateObjectives(std::vector(candidate), objectives, evaluatedCandidate); + arma::mat candidateFval(numObjectives, 1); + EvaluateObjectives(std::vector(candidate), objectives, candidateFval); // 2.3 Update of ideal point. for (size_t idx = 0;idx < numObjectives;++idx) { idealPoint(idx, 0) = std::min(idealPoint(idx, 0), - evaluatedCandidate(idx, 0)); + candidateFval(idx, 0)); } // 2.4 Update of the neighbouring solutions. for (size_t idx = 0;idx < neighborSize;++idx) { if (DecomposedSingleObjective(weights.col(weightNeighbourIndices(i, idx)), - idealPoint.col(0), evaluatedCandidate.col(0)) + idealPoint.col(0), candidateFval.col(0)) <= DecomposedSingleObjective( weights.col(weightNeighbourIndices(i,idx)), idealPoint.col(0), FValue.col(weightNeighbourIndices(i, idx)))) { population.at(weightNeighbourIndices(i, idx)) = candidate[0]; - FValue.col(weightNeighbourIndices(i, idx)) = evaluatedCandidate.col(0); + FValue.col(weightNeighbourIndices(i, idx)) = candidateFval.col(0); } } @@ -245,7 +245,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple std::vector wrapperFirst(1), wrapperSecond(1); wrapperFirst[0] = firstMat; EvaluateObjectives(wrapperFirst, objectives, first); - return Dominates(evaluatedCandidate.col(0), first.col(0)); + return Dominates(candidateFval.col(0), first.col(0)); }; //! Remove the part that is dominated by candidate. externalPopulation.erase( @@ -264,7 +264,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple first.clear(); first.resize(numObjectives, 1); EvaluateObjectives(wrapperFirst, objectives, first); - if (Dominates(first.col(0), evaluatedCandidate.col(0))) + if (Dominates(first.col(0), candidateFval.col(0))) { flag = 1; break; @@ -273,13 +273,13 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple if (flag == 0) { externalPopulation.push_back(candidate[0]); - externalPopulationFValue.push_back(evaluatedCandidate.col(0)); + externalPopulationFValue.push_back(candidateFval.col(0)); } } else { externalPopulation.push_back(candidate[0]); - externalPopulationFValue.push_back(evaluatedCandidate.col(0)); + externalPopulationFValue.push_back(candidateFval.col(0)); } } } @@ -381,9 +381,9 @@ inline void MOEAD::Mutate(MatType& child, //! approach. inline double MOEAD::DecomposedSingleObjective(const arma::vec& weights, const arma::vec& idealPoint, - const arma::vec& evaluatedCandidate) + const arma::vec& candidateFval) { - return arma::min(weights % arma::abs(evaluatedCandidate - idealPoint)); + return arma::min(weights % arma::abs(candidateFval - idealPoint)); } inline bool MOEAD::Dominates(const arma::vec& first, From f4c348a316c43c3321b816add7c6cbf95cedbabc Mon Sep 17 00:00:00 2001 From: NanuSai Date: Mon, 8 Mar 2021 20:32:36 +0530 Subject: [PATCH 012/128] MatingSelection needs popIdx weighNeighbourMatrix idx fix --- include/ensmallen_bits/moead/moead.hpp | 2 +- include/ensmallen_bits/moead/moead_impl.hpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index a3d153651..e062e114f 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -194,7 +194,7 @@ class MOEAD { * @return std::tuple */ std::tuple - MatingSelection(const arma::Mat& weightNeighbourIndices); + MatingSelection(const size_t popIdx, const arma::Mat& weightNeighbourIndices); /** * Mutate child formed by the crossover of two random members of the diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 7be6fbfe2..234cd60b9 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -177,7 +177,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // to make a child. size_t r1, r2, r3; r1 = i; - std::tie(r2, r3) = MatingSelection(weightNeighbourIndices); + std::tie(r2, r3) = MatingSelection(i, weightNeighbourIndices); // 2.2 Reproduction: Apply the Differential Operator on the selected indices // followed by Mutation. @@ -298,15 +298,15 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple } inline std::tuple -MOEAD::MatingSelection(const arma::Mat& weightNeighbourIndices) +MOEAD::MatingSelection(const size_t popIdx, const arma::Mat& weightNeighbourIndices) { size_t k, l; if (arma::randu() < neighborProb) { k = weightNeighbourIndices( - i, arma::randi(arma::distr_param(0, neighborSize - 1))); + arma::randi(arma::distr_param(0, neighborSize - 1)), popIdx); l = weightNeighbourIndices( - i, arma::randi(arma::distr_param(0, neighborSize - 1))); + arma::randi(arma::distr_param(0, neighborSize - 1)), popIdx); if (k == l) { if (k == neighborSize - 1) From a3b812a2834d9d5406d61780efc13c567c62080b Mon Sep 17 00:00:00 2001 From: NanuSai Date: Mon, 8 Mar 2021 21:20:49 +0530 Subject: [PATCH 013/128] weightNeighborIndex fix --- include/ensmallen_bits/moead/moead_impl.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 234cd60b9..edcf38d2f 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -225,14 +225,14 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // 2.4 Update of the neighbouring solutions. for (size_t idx = 0;idx < neighborSize;++idx) { - if (DecomposedSingleObjective(weights.col(weightNeighbourIndices(i, idx)), + if (DecomposedSingleObjective(weights.col(weightNeighbourIndices(idx, i)), idealPoint.col(0), candidateFval.col(0)) <= DecomposedSingleObjective( - weights.col(weightNeighbourIndices(i,idx)), - idealPoint.col(0), FValue.col(weightNeighbourIndices(i, idx)))) + weights.col(weightNeighbourIndices(idx,i)), + idealPoint.col(0), FValue.col(weightNeighbourIndices(idx, i)))) { - population.at(weightNeighbourIndices(i, idx)) = candidate[0]; - FValue.col(weightNeighbourIndices(i, idx)) = candidateFval.col(0); + population.at(weightNeighbourIndices(idx, i)) = candidate[0]; + FValue.col(weightNeighbourIndices(idx, i)) = candidateFval.col(0); } } From ad8383ebadd0757df97b5b70f4898d2be493c97a Mon Sep 17 00:00:00 2001 From: NanuSai Date: Tue, 9 Mar 2021 14:27:00 +0530 Subject: [PATCH 014/128] Add enum for P type --- include/ensmallen_bits/moead/moead.hpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index e062e114f..22a63c479 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -185,6 +185,13 @@ class MOEAD { //! Retrieve the best front (the Pareto frontier). This returns an empty //! vector until `Optimize()` has been called. const std::vector& Front() const { return bestFront; } + + enum class P_TYPE : unsigned char //TODO: Add doc + { + NONE = 0x00, + FROM_POPULATION = 0x01, + FROM_NEIGHBOR = 0x02, + }; private: /** @@ -194,7 +201,9 @@ class MOEAD { * @return std::tuple */ std::tuple - MatingSelection(const size_t popIdx, const arma::Mat& weightNeighbourIndices); + MatingSelection(const size_t popIdx, + const arma::Mat& weightNeighbourIndices, + P_TYPE pFlag); /** * Mutate child formed by the crossover of two random members of the From 09ec4a23ac6f7f1872d25fe3e6d22c927291f3a3 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Tue, 9 Mar 2021 14:27:31 +0530 Subject: [PATCH 015/128] Scalingfactor in impl pFlag switch Mating --- include/ensmallen_bits/moead/moead_impl.hpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index edcf38d2f..35ab69ba0 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -24,6 +24,7 @@ inline MOEAD::MOEAD(const size_t populationSize, const double mutationProb, const double mutationStrength, const size_t neighborSize, + const double scalingFactor, const double distributionIndex, const double neighborProb, const arma::vec& lowerBound, @@ -34,6 +35,7 @@ inline MOEAD::MOEAD(const size_t populationSize, mutationProb(mutationProb), mutationStrength(mutationStrength), neighborSize(neighborSize), + scalingFactor(scalingFactor), distributionIndex(distributionIndex), neighborProb(neighborProb), lowerBound(lowerBound), @@ -47,6 +49,7 @@ inline MOEAD::MOEAD(const size_t populationSize, const double mutationProb, const double mutationStrength, const size_t neighborSize, + const double scalingFactor, const double distributionIndex, const double neighborProb, const double lowerBound, @@ -57,6 +60,7 @@ inline MOEAD::MOEAD(const size_t populationSize, mutationProb(mutationProb), mutationStrength(mutationStrength), neighborSize(neighborSize), + scalingFactor(scalingFactor), distributionIndex(distributionIndex), neighborProb(neighborProb), lowerBound(lowerBound * arma::ones(1, 1)), @@ -177,7 +181,10 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // to make a child. size_t r1, r2, r3; r1 = i; - std::tie(r2, r3) = MatingSelection(i, weightNeighbourIndices); + P_TYPE pFlag = P_TYPE::NONE; + (arma::randu < neighborProb) ? pFlag = P_TYPE::FROM_NEIGHBOR + : pFlag = P_TYPE::FROM_POPULATION; + std::tie(r2, r3) = MatingSelection(i, weightNeighbourIndices, pFlag); // 2.2 Reproduction: Apply the Differential Operator on the selected indices // followed by Mutation. @@ -298,10 +305,12 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple } inline std::tuple -MOEAD::MatingSelection(const size_t popIdx, const arma::Mat& weightNeighbourIndices) +MOEAD::MatingSelection(const size_t popIdx, + const arma::Mat& weightNeighbourIndices, + P_TYPE pFlag) { size_t k, l; - if (arma::randu() < neighborProb) + if (pFlag == P_TYPE::FROM_NEIGHBOR) { k = weightNeighbourIndices( arma::randi(arma::distr_param(0, neighborSize - 1)), popIdx); From 0ae80352d852c33052784d5358053b7b7f0d6fbe Mon Sep 17 00:00:00 2001 From: NanuSai Date: Tue, 9 Mar 2021 15:35:18 +0530 Subject: [PATCH 016/128] - add TODO - add FIXME - neighborIndices --- include/ensmallen_bits/moead/moead_impl.hpp | 35 +++++++++++---------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 35ab69ba0..4cc7cccd0 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -114,17 +114,17 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // Controls early termination of the optimization process. bool terminate = false; - + //TODO: Add more checks? // 1.1 The external population, non-dominated solutions. std::vector externalPopulation; std::vector externalPopulationFValue; arma::Col shuffle; // The Lambda matrix. Each vector represents a decomposition subproblem. - arma::Mat weights(numObjectives, populationSize, arma::fill::randu); + arma::Mat weights(numObjectives, populationSize, arma::fill::randu); //FIXME: Should use weight generation method // 1.2 Storing the indices of nearest neighbours of each weight vector. - arma::Mat weightNeighbourIndices(neighborSize, populationSize); + arma::Mat neighborIndices(neighborSize, populationSize); for (size_t i = 0; i < populationSize; ++i) { // To temporarily store the distance between weights(i) and each other weights. @@ -133,7 +133,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple arma::sqrt(arma::sum(arma::pow(weights.col(i) - weights.each_col(), 2))); arma::uvec sortedIndices = arma::stable_sort_index(distances); // Ignore distance from self - weightNeighbourIndices.col(i) = sortedIndices(arma::span(1, neighborSize)); + neighborIndices.col(i) = sortedIndices(arma::span(1, neighborSize)); } // 1.3 Random generation of the initial population. @@ -177,14 +177,14 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple { terminate |= Callback::StepTaken(*this, objectives, iterate, callbacks...); - // 2.1 Randomly select two indices in weightNeighbourIndices(i) and use them + // 2.1 Randomly select two indices in neighborIndices(i) and use them // to make a child. size_t r1, r2, r3; r1 = i; - P_TYPE pFlag = P_TYPE::NONE; + P_TYPE pFlag = P_TYPE::NONE; //TODO: Perhaps a boolean with comment would be better (arma::randu < neighborProb) ? pFlag = P_TYPE::FROM_NEIGHBOR : pFlag = P_TYPE::FROM_POPULATION; - std::tie(r2, r3) = MatingSelection(i, weightNeighbourIndices, pFlag); + std::tie(r2, r3) = MatingSelection(i, neighborIndices, pFlag); // 2.2 Reproduction: Apply the Differential Operator on the selected indices // followed by Mutation. @@ -229,17 +229,17 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple candidateFval(idx, 0)); } - // 2.4 Update of the neighbouring solutions. + // 2.4 Update of the neighbouring solutions. //FIXME: Sample from either the population OR neighbor based on pFlag for (size_t idx = 0;idx < neighborSize;++idx) { - if (DecomposedSingleObjective(weights.col(weightNeighbourIndices(idx, i)), + if (DecomposedSingleObjective(weights.col(neighborIndices(idx, i)), idealPoint.col(0), candidateFval.col(0)) <= DecomposedSingleObjective( - weights.col(weightNeighbourIndices(idx,i)), - idealPoint.col(0), FValue.col(weightNeighbourIndices(idx, i)))) + weights.col(neighborIndices(idx,i)), + idealPoint.col(0), FValue.col(neighborIndices(idx, i)))) { - population.at(weightNeighbourIndices(idx, i)) = candidate[0]; - FValue.col(weightNeighbourIndices(idx, i)) = candidateFval.col(0); + population.at(neighborIndices(idx, i)) = candidate[0]; + FValue.col(neighborIndices(idx, i)) = candidateFval.col(0); } } @@ -306,15 +306,15 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple inline std::tuple MOEAD::MatingSelection(const size_t popIdx, - const arma::Mat& weightNeighbourIndices, + const arma::Mat& neighborIndices, P_TYPE pFlag) { size_t k, l; if (pFlag == P_TYPE::FROM_NEIGHBOR) { - k = weightNeighbourIndices( + k = neighborIndices( arma::randi(arma::distr_param(0, neighborSize - 1)), popIdx); - l = weightNeighbourIndices( + l = neighborIndices( arma::randi(arma::distr_param(0, neighborSize - 1)), popIdx); if (k == l) { @@ -391,7 +391,8 @@ inline void MOEAD::Mutate(MatType& child, inline double MOEAD::DecomposedSingleObjective(const arma::vec& weights, const arma::vec& idealPoint, const arma::vec& candidateFval) -{ +{ //FIXME: weights[i] == 0? 1e-4 : weights[i] + //TODO: Add more methods perhaps? (BI, TCHEBYCHEFF, WEIGHTED) return arma::min(weights % arma::abs(candidateFval - idealPoint)); } From 89f6b8fb4134a41ad8eb18eff547d1d976b1f8e4 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Tue, 9 Mar 2021 20:48:36 +0530 Subject: [PATCH 017/128] - fix compile errors - test still fail --- include/ensmallen_bits/moead/moead.hpp | 9 +------- include/ensmallen_bits/moead/moead_impl.hpp | 25 ++++++++++----------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 22a63c479..88d69a35b 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -185,13 +185,6 @@ class MOEAD { //! Retrieve the best front (the Pareto frontier). This returns an empty //! vector until `Optimize()` has been called. const std::vector& Front() const { return bestFront; } - - enum class P_TYPE : unsigned char //TODO: Add doc - { - NONE = 0x00, - FROM_POPULATION = 0x01, - FROM_NEIGHBOR = 0x02, - }; private: /** @@ -203,7 +196,7 @@ class MOEAD { std::tuple MatingSelection(const size_t popIdx, const arma::Mat& weightNeighbourIndices, - P_TYPE pFlag); + bool sampleNeighbor); /** * Mutate child formed by the crossover of two random members of the diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 4cc7cccd0..be8272d03 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -24,9 +24,9 @@ inline MOEAD::MOEAD(const size_t populationSize, const double mutationProb, const double mutationStrength, const size_t neighborSize, - const double scalingFactor, const double distributionIndex, const double neighborProb, + const double scalingFactor, const arma::vec& lowerBound, const arma::vec& upperBound) : populationSize(populationSize), @@ -35,9 +35,9 @@ inline MOEAD::MOEAD(const size_t populationSize, mutationProb(mutationProb), mutationStrength(mutationStrength), neighborSize(neighborSize), - scalingFactor(scalingFactor), distributionIndex(distributionIndex), neighborProb(neighborProb), + scalingFactor(scalingFactor), lowerBound(lowerBound), upperBound(upperBound), numObjectives(0) @@ -49,9 +49,9 @@ inline MOEAD::MOEAD(const size_t populationSize, const double mutationProb, const double mutationStrength, const size_t neighborSize, - const double scalingFactor, const double distributionIndex, const double neighborProb, + const double scalingFactor, const double lowerBound, const double upperBound) : populationSize(populationSize), @@ -60,9 +60,9 @@ inline MOEAD::MOEAD(const size_t populationSize, mutationProb(mutationProb), mutationStrength(mutationStrength), neighborSize(neighborSize), - scalingFactor(scalingFactor), distributionIndex(distributionIndex), neighborProb(neighborProb), + scalingFactor(scalingFactor), lowerBound(lowerBound * arma::ones(1, 1)), upperBound(upperBound * arma::ones(1, 1)), numObjectives(0) @@ -181,10 +181,9 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // to make a child. size_t r1, r2, r3; r1 = i; - P_TYPE pFlag = P_TYPE::NONE; //TODO: Perhaps a boolean with comment would be better - (arma::randu < neighborProb) ? pFlag = P_TYPE::FROM_NEIGHBOR - : pFlag = P_TYPE::FROM_POPULATION; - std::tie(r2, r3) = MatingSelection(i, neighborIndices, pFlag); + bool sampleNeighbor; // If true, sample from neighbor; otherwise sample from population. + sampleNeighbor = ( arma::randu() < neighborProb ); + std::tie(r2, r3) = MatingSelection(i, neighborIndices, sampleNeighbor); // 2.2 Reproduction: Apply the Differential Operator on the selected indices // followed by Mutation. @@ -192,10 +191,10 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple double delta = arma::randu(); if (delta < crossoverProb) { - for (size_t geneIdx = 0; geneIdx < numVariables, ++geneIdx) + for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) { candidate[geneIdx] = population[r1][geneIdx] + - scaleFactor * (population[r2][geneIdx] - + scalingFactor * (population[r2][geneIdx] - population[r3][geneIdx]); // Handle boundary condition @@ -207,7 +206,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple } else if (candidate[geneIdx] > upperBound[geneIdx]) { - candidate[geneIdx] = upperrBound[geneIdx] + + candidate[geneIdx] = upperBound[geneIdx] + arma::randu() * (upperBound[geneIdx] - population[r1][geneIdx]); } @@ -307,10 +306,10 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple inline std::tuple MOEAD::MatingSelection(const size_t popIdx, const arma::Mat& neighborIndices, - P_TYPE pFlag) + bool sampleNeighbor) { size_t k, l; - if (pFlag == P_TYPE::FROM_NEIGHBOR) + if (sampleNeighbor) { k = neighborIndices( arma::randi(arma::distr_param(0, neighborSize - 1)), popIdx); From d69c899bfd67dbbcc62ec4a77aa10cd9fa5614c6 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Tue, 9 Mar 2021 23:19:30 +0530 Subject: [PATCH 018/128] Add params - maxReplace - preserveDiversity - Add docs --- include/ensmallen_bits/moead/moead.hpp | 42 ++++++++++++++++++--- include/ensmallen_bits/moead/moead_impl.hpp | 40 ++++++++++++-------- 2 files changed, 61 insertions(+), 21 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 88d69a35b..74670732c 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -1,6 +1,6 @@ /** * @file moead.hpp - * @author Utkarsh Rai + * @authors Utkarsh Rai, Nanubala Gnana Sai * * MOEA/D, Multi Objective Evolutionary Algorithm based on Decompositon is a * multi objective optimization algorithm. It employs evolutionary algorithms, @@ -62,7 +62,11 @@ class MOEAD { * @param mutationStrength The strength of mutation. * @param neighborSize The number of nearest neighbours of weights * to find. - * @param distributionIndex The distribution index for polynomial mutation. + * @param distributionIndex The crowding degree of the mutation. + * @param neighborProb The probability of sampling from neighbor. + * @param scalingFactor The F parameter of the differential operator. + * @param maxReplace The limit of solutions allowed to be replaced by a child. + * @param preserveDiversity Enforce preserving diversity. * @param lowerBound The lower bound on each variable of a member * of the variable space. * @param upperBound The upper bound on each variable of a member @@ -76,7 +80,9 @@ class MOEAD { const size_t neighborSize = 50, const double distributionIndex = 0.5, const double neighborProb = 0.5, - const double scalingFactor = 0.6, + const double scalingFactor = 0.5, + const size_t maxReplace = 10, + const bool preserveDiversity = true, const arma::vec& lowerBound = arma::zeros(1, 1), const arma::vec& upperBound = arma::ones(1, 1)); @@ -96,7 +102,11 @@ class MOEAD { * @param mutationStrength The strength of mutation. * @param neighborSize The number of nearest neighbours of weights * to find. - * @param distributionIndex The distribution index for polynomial mutation. + * @param distributionIndex The crowding degree of the mutation. + * @param neighborProb The probability of sampling from neighbor. + * @param scalingFactor The F parameter of the differential operator. + * @param maxReplace The limit of solutions allowed to be replaced by a child. + * @param preserveDiversity Enforce preserving diversity. * @param lowerBound The lower bound on each variable of a member * of the variable space. * @param upperBound The upper bound on each variable of a member @@ -110,7 +120,9 @@ class MOEAD { const size_t neighborSize = 50, const double distributionIndex = 0.5, const double neighborProb = 0.5, - const double scalingFactor = 0.6, + const double scalingFactor = 0.5, + const size_t maxReplace = 10, + const bool preserveDiversity = true, const double lowerBound = 0, const double upperBound = 1); @@ -172,6 +184,16 @@ class MOEAD { //! Modify the value of scaling factor. double& ScalingFactor() { return scalingFactor; } + //! Retrieve value of maxReplace. + size_t MaxReplace() const { return maxReplace; } + //! Modify value of maxReplace. + size_t& MaxReplace() { return maxReplace; } + + //! Modify value of preserveDiversity. + bool PreserveDiversity() const { return preserveDiversity; } + //! Modify value of preserveDiversity. + bool& PreserveDiversity() { return preserveDiversity; } + //! Retrieve value of lowerBound. const arma::vec& LowerBound() const { return lowerBound; } //! Modify value of lowerBound. @@ -280,7 +302,8 @@ class MOEAD { //! Number of nearest neighbours of weights to consider. size_t neighborSize; - //! Distribution index for the polynomial distribution. + //! The crowding degree of the mutation. Higher value produces a mutant + //! resembling its parent. double distributionIndex; //! The probability that two elements will be chosen from the neighbor. @@ -289,6 +312,13 @@ class MOEAD { //! Scale the difference between two random points during crossover. double scalingFactor; + //! Maximum number of childs which can replace the parent. Higher value + //! leads to a loss of diversity. + size_t maxReplace; + + //! If enabled, the optimizer favors a diversity in solutions. + bool preserveDiversity; + //! Lower bound on each variable in the variable space. arma::vec lowerBound; diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index be8272d03..a606e9721 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -1,6 +1,6 @@ /** * @file moead_impl.hpp - * @author Utkarsh Rai + * @authors Utkarsh Rai, Nanubala Gnana Sai * * Implementation of the MOEA/D algorithm. Used for multi-objective * optimization problems on arbitrary functions. @@ -27,6 +27,8 @@ inline MOEAD::MOEAD(const size_t populationSize, const double distributionIndex, const double neighborProb, const double scalingFactor, + const size_t maxReplace, + const bool preserveDiversity, const arma::vec& lowerBound, const arma::vec& upperBound) : populationSize(populationSize), @@ -38,6 +40,8 @@ inline MOEAD::MOEAD(const size_t populationSize, distributionIndex(distributionIndex), neighborProb(neighborProb), scalingFactor(scalingFactor), + maxReplace(maxReplace), + preserveDiversity(preserveDiversity), lowerBound(lowerBound), upperBound(upperBound), numObjectives(0) @@ -52,6 +56,8 @@ inline MOEAD::MOEAD(const size_t populationSize, const double distributionIndex, const double neighborProb, const double scalingFactor, + const size_t maxReplace, + const bool preserveDiversity, const double lowerBound, const double upperBound) : populationSize(populationSize), @@ -63,6 +69,8 @@ inline MOEAD::MOEAD(const size_t populationSize, distributionIndex(distributionIndex), neighborProb(neighborProb), scalingFactor(scalingFactor), + maxReplace(maxReplace), + preserveDiversity(preserveDiversity), lowerBound(lowerBound * arma::ones(1, 1)), upperBound(upperBound * arma::ones(1, 1)), numObjectives(0) @@ -228,22 +236,24 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple candidateFval(idx, 0)); } - // 2.4 Update of the neighbouring solutions. //FIXME: Sample from either the population OR neighbor based on pFlag - for (size_t idx = 0;idx < neighborSize;++idx) - { - if (DecomposedSingleObjective(weights.col(neighborIndices(idx, i)), - idealPoint.col(0), candidateFval.col(0)) - <= DecomposedSingleObjective( - weights.col(neighborIndices(idx,i)), - idealPoint.col(0), FValue.col(neighborIndices(idx, i)))) - { - population.at(neighborIndices(idx, i)) = candidate[0]; - FValue.col(neighborIndices(idx, i)) = candidateFval.col(0); - } - } + // 2.4 Update of the neighbouring solutions. //FIXME: MOAD implementation not MOEAD-DE + // for (size_t idx = 0;idx < neighborSize;++idx) + // { + // if (DecomposedSingleObjective(weights.col(neighborIndices(idx, i)), + // idealPoint.col(0), candidateFval.col(0)) + // <= DecomposedSingleObjective( + // weights.col(neighborIndices(idx,i)), + // idealPoint.col(0), FValue.col(neighborIndices(idx, i)))) + // { + // population.at(neighborIndices(idx, i)) = candidate[0]; + // FValue.col(neighborIndices(idx, i)) = candidateFval.col(0); + // } + // } + + size_t replaceCounter = 0; // 2.5 Updating External Population. - if (!externalPopulation.empty()) + if (!externalPopulation.empty()) //FIXME: MOAD implementation not MOEAD-DE { arma::mat first(numObjectives, 1); auto df = [&](MatType firstMat) -> bool From a4dcccd26a030e8bbfbf137e8c253a317cfdca0f Mon Sep 17 00:00:00 2001 From: NanuSai Date: Wed, 10 Mar 2021 01:19:54 +0530 Subject: [PATCH 019/128] rename - DecomposeObjectives --- include/ensmallen_bits/moead/moead.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 74670732c..18fab2186 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -189,7 +189,7 @@ class MOEAD { //! Modify value of maxReplace. size_t& MaxReplace() { return maxReplace; } - //! Modify value of preserveDiversity. + //! Retreive value of preserveDiversity. bool PreserveDiversity() const { return preserveDiversity; } //! Modify value of preserveDiversity. bool& PreserveDiversity() { return preserveDiversity; } @@ -245,9 +245,9 @@ class MOEAD { * @param evaluatedCandidate Value of the candidate per objective. * @return The single value obtained from decomposed function. */ - double DecomposedSingleObjective(const arma::vec& weights, - const arma::vec& idealPoint, - const arma::vec& evaluatedCandidate); + double DecomposeObjectives(const arma::vec& weights, + const arma::vec& idealPoint, + const arma::vec& evaluatedCandidate); /** * Check domination between two vectors. From 99f6f2b630fe9f5487657549e83c67fa489d5972 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Wed, 10 Mar 2021 01:30:19 +0530 Subject: [PATCH 020/128] rm: - externalPopulation - externalPopulationFval - update neighbor of MOEA/D rename: - FValue => populationFval - Add - update solutions as MOEA/D-DE prefers - use diversity preserve conditions - idealPoint and candidateFval are arma::vec ======== REMAINING - Fixing the final stuff - Some additional touches - Possible code fixes --- include/ensmallen_bits/moead/moead_impl.hpp | 118 +++++++------------- 1 file changed, 42 insertions(+), 76 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index a606e9721..f2c9608aa 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -94,19 +94,19 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // Convenience typedefs. typedef typename MatType::elem_type ElemType; - if(lowerBound.size() != upperBound.size()) + if (lowerBound.size() != upperBound.size()) { throw std::logic_error("MOEAD::Optimize(): size of lowerBound and upperBound " "must be equal."); } - if(lowerBound.size() != iterate.n_elem) + if (lowerBound.size() != iterate.n_elem) { throw std::logic_error("MOEAD::Optimize(): there should be a lower bound and " "an upper bound for each variable in the initial point."); } - if(populationSize < neighborSize + 1) + if (populationSize < neighborSize + 1) { std::ostringstream oss; oss << "MOEAD::Optimize(): " << "neighborSize is " << neighborSize @@ -123,10 +123,6 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // Controls early termination of the optimization process. bool terminate = false; //TODO: Add more checks? - // 1.1 The external population, non-dominated solutions. - std::vector externalPopulation; - std::vector externalPopulationFValue; - arma::Col shuffle; // The Lambda matrix. Each vector represents a decomposition subproblem. arma::Mat weights(numObjectives, populationSize, arma::fill::randu); //FIXME: Should use weight generation method @@ -161,17 +157,17 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple } // 1.3 F-value initialisation for the population. - arma::mat FValue(numObjectives, populationSize); - EvaluateObjectives(population, objectives, FValue); + arma::mat populationFval(numObjectives, populationSize); + EvaluateObjectives(population, objectives, populationFval); // 1.4 Initialize the ideal point z. - arma::mat idealPoint(numObjectives, 1); - idealPoint.fill(std::numeric_limits::max()); + arma::vec idealPoint(numObjectives); + idealPoint.fill(std::numeric_limits::max()); for (size_t i = 0; i < numObjectives; ++i) { for (size_t j = 0; j < populationSize; ++j) { - idealPoint(i, 0) = std::min(idealPoint(i, 0), FValue(i, j)); + idealPoint(i) = std::min(idealPoint(i), populationFval(i, j)); } } @@ -184,13 +180,16 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple for (size_t i : shuffle) { terminate |= Callback::StepTaken(*this, objectives, iterate, callbacks...); + + Info << "MOEA/D-DE initialized successfully. Optimization started." << std::endl; // 2.1 Randomly select two indices in neighborIndices(i) and use them // to make a child. size_t r1, r2, r3; r1 = i; - bool sampleNeighbor; // If true, sample from neighbor; otherwise sample from population. - sampleNeighbor = ( arma::randu() < neighborProb ); + // When preserveDiversity is active, randomly choose from the population + // or the neighbors. + bool sampleNeighbor = ( arma::randu() < neighborProb || !preserveDiversity ); std::tie(r2, r3) = MatingSelection(i, neighborIndices, sampleNeighbor); // 2.2 Reproduction: Apply the Differential Operator on the selected indices @@ -226,85 +225,52 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple Mutate(candidate, 1.f / numVariables, lowerBound, upperBound); // Store solution for candidate. - arma::mat candidateFval(numObjectives, 1); + arma::vec candidateFval(numObjectives); EvaluateObjectives(std::vector(candidate), objectives, candidateFval); // 2.3 Update of ideal point. for (size_t idx = 0;idx < numObjectives;++idx) { - idealPoint(idx, 0) = std::min(idealPoint(idx, 0), - candidateFval(idx, 0)); + idealPoint(idx) = std::min(idealPoint(idx), + candidateFval(idx)); } - // 2.4 Update of the neighbouring solutions. //FIXME: MOAD implementation not MOEAD-DE - // for (size_t idx = 0;idx < neighborSize;++idx) - // { - // if (DecomposedSingleObjective(weights.col(neighborIndices(idx, i)), - // idealPoint.col(0), candidateFval.col(0)) - // <= DecomposedSingleObjective( - // weights.col(neighborIndices(idx,i)), - // idealPoint.col(0), FValue.col(neighborIndices(idx, i)))) - // { - // population.at(neighborIndices(idx, i)) = candidate[0]; - // FValue.col(neighborIndices(idx, i)) = candidateFval.col(0); - // } - // } - + // 2.4 Update of the neighbouring solutions. size_t replaceCounter = 0; + size_t sampleSize = sampleNeighbor ? neighborSize : populationSize; + + arma::Col idxShuffle = std::get<0>(objectives).Shuffle(sampleSize); - // 2.5 Updating External Population. - if (!externalPopulation.empty()) //FIXME: MOAD implementation not MOEAD-DE + for (size_t idx : idxShuffle) { - arma::mat first(numObjectives, 1); - auto df = [&](MatType firstMat) -> bool - { - std::vector wrapperFirst(1), wrapperSecond(1); - wrapperFirst[0] = firstMat; - EvaluateObjectives(wrapperFirst, objectives, first); - return Dominates(candidateFval.col(0), first.col(0)); - }; - //! Remove the part that is dominated by candidate. - externalPopulation.erase( - std::remove_if( - externalPopulation.begin(), - externalPopulation.end(), - df), externalPopulation.end()); - - //! Check if any of the remaining members of external population dominate - //! candidate. - bool flag = 0; - std::vector wrapperFirst(1); - for (size_t idx = 0; idx < externalPopulation.size(); ++idx) - { - wrapperFirst[0]=externalPopulation[idx]; - first.clear(); - first.resize(numObjectives, 1); - EvaluateObjectives(wrapperFirst, objectives, first); - if (Dominates(first.col(0), candidateFval.col(0))) - { - flag = 1; - break; - } - } - if (flag == 0) + // Number of solutions shouldn't exceed maxReplace if + // we wish to preserve diversity. + if (replaceCounter >= maxReplace && preserveDiversity) + break; + + size_t pick = sampleNeighbor ? neighborIndices(idx, i) : idx; + + double candidateDecomposition = DecomposeObjectives( + weights.col(pick), idealPoint, candidateFval); + double parentDecomposition = DecomposeObjectives( + weights.col(pick), idealPoint, populationFval.col(pick)); + + if (candidateDecomposition < parentDecomposition) { - externalPopulation.push_back(candidate[0]); - externalPopulationFValue.push_back(candidateFval.col(0)); + population[pick] = candidate; + populationFval.col(pick) = candidateFval; + replaceCounter++; } } - else - { - externalPopulation.push_back(candidate[0]); - externalPopulationFValue.push_back(candidateFval.col(0)); - } } } - bestFront = std::move(externalPopulation); + + bestFront = std::move(population); Callback::EndOptimization(*this, objectives, iterate, callbacks...); ElemType performance = std::numeric_limits::max(); - for (arma::Col objective: externalPopulationFValue) + for (arma::Col objective: populationFval) { if (arma::accu(objective) < performance) performance = arma::accu(objective); @@ -397,7 +363,7 @@ inline void MOEAD::Mutate(MatType& child, //! Calculate the output for single objective function using the Tchebycheff //! approach. -inline double MOEAD::DecomposedSingleObjective(const arma::vec& weights, +inline double MOEAD::DecomposeObjectives(const arma::vec& weights, const arma::vec& idealPoint, const arma::vec& candidateFval) { //FIXME: weights[i] == 0? 1e-4 : weights[i] @@ -414,7 +380,7 @@ inline bool MOEAD::Dominates(const arma::vec& first, if (first(i) > second(i)) return false; - if(first(i) < second(i)) + if (first(i) < second(i)) flag = 1; } if (flag) From 73a3b90c1cdae0f6293cffcabfa92095e43068b1 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Wed, 10 Mar 2021 19:43:37 +0530 Subject: [PATCH 021/128] tchebycheff is max --- include/ensmallen_bits/moead/moead_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index f2c9608aa..d7ecab4b2 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -368,7 +368,7 @@ inline double MOEAD::DecomposeObjectives(const arma::vec& weights, const arma::vec& candidateFval) { //FIXME: weights[i] == 0? 1e-4 : weights[i] //TODO: Add more methods perhaps? (BI, TCHEBYCHEFF, WEIGHTED) - return arma::min(weights % arma::abs(candidateFval - idealPoint)); + return arma::max(weights % arma::abs(candidateFval - idealPoint)); } inline bool MOEAD::Dominates(const arma::vec& first, From d67ed85dd0fe1683b054d0736eb3dc247282ae3f Mon Sep 17 00:00:00 2001 From: NanuSai Date: Wed, 10 Mar 2021 23:06:02 +0530 Subject: [PATCH 022/128] remove - dominates rename - differentialWeight, changed default value - add weight stability --- include/ensmallen_bits/moead/moead.hpp | 34 ++++++++++--------- include/ensmallen_bits/moead/moead_impl.hpp | 36 ++++++--------------- 2 files changed, 27 insertions(+), 43 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 18fab2186..8d9d44595 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -64,7 +64,8 @@ class MOEAD { * to find. * @param distributionIndex The crowding degree of the mutation. * @param neighborProb The probability of sampling from neighbor. - * @param scalingFactor The F parameter of the differential operator. + * @param differentialWeight A parameter used in the mutation of candidate + * solutions controls amplification factor of the differentiation. * @param maxReplace The limit of solutions allowed to be replaced by a child. * @param preserveDiversity Enforce preserving diversity. * @param lowerBound The lower bound on each variable of a member @@ -80,7 +81,7 @@ class MOEAD { const size_t neighborSize = 50, const double distributionIndex = 0.5, const double neighborProb = 0.5, - const double scalingFactor = 0.5, + const double differentialWeight = 0.8, const size_t maxReplace = 10, const bool preserveDiversity = true, const arma::vec& lowerBound = arma::zeros(1, 1), @@ -104,7 +105,8 @@ class MOEAD { * to find. * @param distributionIndex The crowding degree of the mutation. * @param neighborProb The probability of sampling from neighbor. - * @param scalingFactor The F parameter of the differential operator. + * @param differentialWeight A parameter used in the mutation of candidate + * solutions controls amplification factor of the differentiation. * @param maxReplace The limit of solutions allowed to be replaced by a child. * @param preserveDiversity Enforce preserving diversity. * @param lowerBound The lower bound on each variable of a member @@ -120,7 +122,7 @@ class MOEAD { const size_t neighborSize = 50, const double distributionIndex = 0.5, const double neighborProb = 0.5, - const double scalingFactor = 0.5, + const double differentialWeight = 0.8, const size_t maxReplace = 10, const bool preserveDiversity = true, const double lowerBound = 0, @@ -144,45 +146,45 @@ class MOEAD { MatType& iterate, CallbackTypes&&... callbacks); - //! Get the population size. + //! Retrieve population size. size_t PopulationSize() const { return populationSize; } //! Modify the population size. size_t& PopulationSize() { return populationSize; } - //! Get the number of generations. + //! Retrieve number of generations. size_t NumGeneration() const { return numGeneration; } //! Modify the number of generations. size_t& NumGeneration() { return numGeneration; } - //! Get the crossover rate. + //! Retrieve crossover rate. double CrossoverRate() const { return crossoverProb; } //! Modify the crossover rate. double& CrossoverRate() { return crossoverProb; } - //! Get the mutation probability. + //! Retrieve mutation probability. double MutationProbability() const { return mutationProb; } //! Modify the mutation probability. double& MutationProbability() { return mutationProb; } - //! Get the size of the weight neighbor. + //! Retrieve size of the weight neighbor. size_t NeighborSize() const { return neighborSize; } //! Modify the size of the weight neighbor. size_t& NeighborSize() { return neighborSize; } - //! Get the value of the distribution index. + //! Retrieve value of the distribution index. double DistributionIndex() const { return distributionIndex; } //! Modify the value of the distribution index. double& DistributionIndex() { return distributionIndex; } - //! Get the value of neighbor probability. + //! Retrieve value of neighbor probability. double NeighborProb() const { return neighborProb; } //! Modify the value of neigbourhood probability. double& NeighborProb() { return neighborProb; } - //! Get the value of scaling factor. - double ScalingFactor() const { return scalingFactor; } + //! Retrieve value of scaling factor. + double differentialWeight() const { return differentialWeight; } //! Modify the value of scaling factor. - double& ScalingFactor() { return scalingFactor; } + double& differentialWeight() { return differentialWeight; } //! Retrieve value of maxReplace. size_t MaxReplace() const { return maxReplace; } @@ -309,8 +311,8 @@ class MOEAD { //! The probability that two elements will be chosen from the neighbor. double neighborProb; - //! Scale the difference between two random points during crossover. - double scalingFactor; + //! Amplification factor for differentiation. + double differentialWeight; //! Maximum number of childs which can replace the parent. Higher value //! leads to a loss of diversity. diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index d7ecab4b2..163fe02d8 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -26,7 +26,7 @@ inline MOEAD::MOEAD(const size_t populationSize, const size_t neighborSize, const double distributionIndex, const double neighborProb, - const double scalingFactor, + const double differentialWeight, const size_t maxReplace, const bool preserveDiversity, const arma::vec& lowerBound, @@ -39,7 +39,7 @@ inline MOEAD::MOEAD(const size_t populationSize, neighborSize(neighborSize), distributionIndex(distributionIndex), neighborProb(neighborProb), - scalingFactor(scalingFactor), + differentialWeight(differentialWeight), maxReplace(maxReplace), preserveDiversity(preserveDiversity), lowerBound(lowerBound), @@ -55,7 +55,7 @@ inline MOEAD::MOEAD(const size_t populationSize, const size_t neighborSize, const double distributionIndex, const double neighborProb, - const double scalingFactor, + const double differentialWeight, const size_t maxReplace, const bool preserveDiversity, const double lowerBound, @@ -68,7 +68,7 @@ inline MOEAD::MOEAD(const size_t populationSize, neighborSize(neighborSize), distributionIndex(distributionIndex), neighborProb(neighborProb), - scalingFactor(scalingFactor), + differentialWeight(differentialWeight), maxReplace(maxReplace), preserveDiversity(preserveDiversity), lowerBound(lowerBound * arma::ones(1, 1)), @@ -120,12 +120,12 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // Dimensionality of variable space. Also referred to as number of genes. size_t numVariables = iterate.n_rows; - // Controls early termination of the optimization process. bool terminate = false; - //TODO: Add more checks? + arma::Col shuffle; - // The Lambda matrix. Each vector represents a decomposition subproblem. - arma::Mat weights(numObjectives, populationSize, arma::fill::randu); //FIXME: Should use weight generation method + // The weight matrix. Each vector represents a decomposition subproblem. + arma::Mat weights(numObjectives, populationSize, arma::fill::randu()); + weights += 1e-10; //Handles zero weight case. // 1.2 Storing the indices of nearest neighbours of each weight vector. arma::Mat neighborIndices(neighborSize, populationSize); @@ -201,7 +201,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) { candidate[geneIdx] = population[r1][geneIdx] + - scalingFactor * (population[r2][geneIdx] - + differentialWeight * (population[r2][geneIdx] - population[r3][geneIdx]); // Handle boundary condition @@ -371,24 +371,6 @@ inline double MOEAD::DecomposeObjectives(const arma::vec& weights, return arma::max(weights % arma::abs(candidateFval - idealPoint)); } -inline bool MOEAD::Dominates(const arma::vec& first, - const arma::vec& second) -{ - int flag = 0; - for (size_t i = 0; i < numObjectives; ++i) - { - if (first(i) > second(i)) - return false; - - if (first(i) < second(i)) - flag = 1; - } - if (flag) - return true; - - return false; -} - //! No objectives to evaluate. template Date: Wed, 10 Mar 2021 23:09:50 +0530 Subject: [PATCH 023/128] fix chronology in docs --- include/ensmallen_bits/moead/moead_impl.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 163fe02d8..4efd610c2 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -140,7 +140,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple neighborIndices.col(i) = sortedIndices(arma::span(1, neighborSize)); } - // 1.3 Random generation of the initial population. + // 1.2 Random generation of the initial population. std::vector population(populationSize); for (size_t i = 0; i < populationSize; ++i) { @@ -156,11 +156,11 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple } } - // 1.3 F-value initialisation for the population. + // F-value initialisation for the population. arma::mat populationFval(numObjectives, populationSize); EvaluateObjectives(population, objectives, populationFval); - // 1.4 Initialize the ideal point z. + // 1.3 Initialize the ideal point z. arma::vec idealPoint(numObjectives); idealPoint.fill(std::numeric_limits::max()); for (size_t i = 0; i < numObjectives; ++i) @@ -192,7 +192,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple bool sampleNeighbor = ( arma::randu() < neighborProb || !preserveDiversity ); std::tie(r2, r3) = MatingSelection(i, neighborIndices, sampleNeighbor); - // 2.2 Reproduction: Apply the Differential Operator on the selected indices + // 2.2 - 2.3 Reproduction and Repair: Apply the Differential Operator on the selected indices // followed by Mutation. MatType candidate(iterate.nrows, iterate.ncols); //TODO: Potentially wrong, because iterate can be a population swarm double delta = arma::randu(); @@ -228,14 +228,14 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple arma::vec candidateFval(numObjectives); EvaluateObjectives(std::vector(candidate), objectives, candidateFval); - // 2.3 Update of ideal point. + // 2.4 Update of ideal point. for (size_t idx = 0;idx < numObjectives;++idx) { idealPoint(idx) = std::min(idealPoint(idx), candidateFval(idx)); } - // 2.4 Update of the neighbouring solutions. + // 2.5 Update of the population. size_t replaceCounter = 0; size_t sampleSize = sampleNeighbor ? neighborSize : populationSize; From d794746062fcb190ecbf14c496906ebee8d67b14 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Wed, 10 Mar 2021 23:50:54 +0530 Subject: [PATCH 024/128] styling fix --- include/ensmallen_bits/moead/moead.hpp | 32 +++++-------- include/ensmallen_bits/moead/moead_impl.hpp | 53 +++++++++++++-------- 2 files changed, 43 insertions(+), 42 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 8d9d44595..9791f3efe 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -38,8 +38,8 @@ namespace ens { * author={H. {Li} and Q. {Zhang}}, * year={2009}, * pages={284-302},} - * title={Multiobjective Optimization Problems With Complicated Pareto Sets, MOEA/D and NSGA-II}, - * journal={IEEE Transactions on Evolutionary Computation}, + * title={Multiobjective Optimization Problems With Complicated Pareto Sets, MOEA/D and NSGA-II}, + * journal={IEEE Transactions on Evolutionary Computation}, * @endcode * * MOEA/D can optimize arbitrary multi-objective functions. For more details, @@ -182,9 +182,9 @@ class MOEAD { double& NeighborProb() { return neighborProb; } //! Retrieve value of scaling factor. - double differentialWeight() const { return differentialWeight; } + double DifferentialWeight() const { return differentialWeight; } //! Modify the value of scaling factor. - double& differentialWeight() { return differentialWeight; } + double& DifferentialWeight() { return differentialWeight; } //! Retrieve value of maxReplace. size_t MaxReplace() const { return maxReplace; } @@ -213,9 +213,9 @@ class MOEAD { private: /** * @brief Randomly select two members from the population. - * - * @param weightNeighbourIndices - * @return std::tuple + * + * @param weightNeighbourIndices + * @return std::tuple */ std::tuple MatingSelection(const size_t popIdx, @@ -223,8 +223,8 @@ class MOEAD { bool sampleNeighbor); /** - * Mutate child formed by the crossover of two random members of the - * population. + * Mutate the child formed by the crossover of two random members of the + * population. Uses polynomial mutation. * * @tparam MatType The type of matrix used to store coordinates. * @param child The matrix to mutate. @@ -251,16 +251,6 @@ class MOEAD { const arma::vec& idealPoint, const arma::vec& evaluatedCandidate); - /** - * Check domination between two vectors. - * - * @param first, the first of the two vectors to compare. - * @param second, the second of the two vectors to compare. - * @return true if first dominates second else false. - */ - bool Dominates(const arma::vec& first, - const arma::vec& second); - /** * Evaluate objectives for the elite population. * @@ -269,7 +259,7 @@ class MOEAD { * @param population The elite population. * @param objectives The set of objectives. * @param calculatedObjectives Vector to store calculated objectives. - */ + */ template @@ -318,7 +308,7 @@ class MOEAD { //! leads to a loss of diversity. size_t maxReplace; - //! If enabled, the optimizer favors a diversity in solutions. + //! If enabled, the optimizer produces diverse set of solutions. bool preserveDiversity; //! Lower bound on each variable in the variable space. diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 4efd610c2..f0e80b969 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -91,9 +91,26 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // Check if lower bound is a vector of a single dimension. if (upperBound.n_rows == 1) upperBound = upperBound(0, 0) * arma::ones(iterate.n_rows, iterate.n_cols); + // Convenience typedefs. typedef typename MatType::elem_type ElemType; + // Number of objective functions. Represented by M in the paper. + numObjectives = sizeof...(ArbitraryFunctionType); + // Dimensionality of variable space. Also referred to as number of genes. + size_t numVariables = iterate.n_rows; + + if (populationSize <= 0) + { + throw std::logic_error("MOEAD::Optimize(): populationSize should be positive."); + } + + if (numObjectives < 2u) + { + throw std::logic_error("MOEAD::Optimize(): This is a multiobjective problem, + numObjectives must be atleast 2."); + } +//TODO: Check if any of lowerBound is equal to upperBound if (lowerBound.size() != upperBound.size()) { throw std::logic_error("MOEAD::Optimize(): size of lowerBound and upperBound " @@ -106,32 +123,27 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple "an upper bound for each variable in the initial point."); } - if (populationSize < neighborSize + 1) + if (populationSize < neighborSize + 1u) { std::ostringstream oss; oss << "MOEAD::Optimize(): " << "neighborSize is " << neighborSize << "but populationSize is " << populationSize << "(should be" - << " atleast " << neighborSize + 1 << std::endl; + << " atleast " << (neighborSize + 1u) << ")" << std::endl; throw std::logic_error(oss.str()); } - // Number of objective functions. Represented by M in the paper. - numObjectives = sizeof...(ArbitraryFunctionType); - // Dimensionality of variable space. Also referred to as number of genes. - size_t numVariables = iterate.n_rows; - bool terminate = false; arma::Col shuffle; // The weight matrix. Each vector represents a decomposition subproblem. - arma::Mat weights(numObjectives, populationSize, arma::fill::randu()); + arma::Mat weights(numObjectives, populationSize, arma::fill::randu); weights += 1e-10; //Handles zero weight case. - // 1.2 Storing the indices of nearest neighbours of each weight vector. + // 1.2 Storing the indices of nearest neighbors of each weight vector. arma::Mat neighborIndices(neighborSize, populationSize); for (size_t i = 0; i < populationSize; ++i) { - // To temporarily store the distance between weights(i) and each other weights. + // Cache the distance between weights(i) and other weights. arma::rowvec distances(populationSize); distances = arma::sqrt(arma::sum(arma::pow(weights.col(i) - weights.each_col(), 2))); @@ -146,7 +158,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple { population[i] = arma::randu(iterate.n_rows, iterate.n_cols) - 0.5 + iterate; - + for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) { if (population[i][geneIdx] < lowerBound[geneIdx]) @@ -180,7 +192,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple for (size_t i : shuffle) { terminate |= Callback::StepTaken(*this, objectives, iterate, callbacks...); - + Info << "MOEA/D-DE initialized successfully. Optimization started." << std::endl; // 2.1 Randomly select two indices in neighborIndices(i) and use them @@ -192,9 +204,9 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple bool sampleNeighbor = ( arma::randu() < neighborProb || !preserveDiversity ); std::tie(r2, r3) = MatingSelection(i, neighborIndices, sampleNeighbor); - // 2.2 - 2.3 Reproduction and Repair: Apply the Differential Operator on the selected indices - // followed by Mutation. - MatType candidate(iterate.nrows, iterate.ncols); //TODO: Potentially wrong, because iterate can be a population swarm + // 2.2 - 2.3 Reproduction and Repair: Differential Operator followed by + // Mutation. + MatType candidate(iterate.nrows, iterate.ncols); double delta = arma::randu(); if (delta < crossoverProb) { @@ -224,7 +236,6 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple Mutate(candidate, 1.f / numVariables, lowerBound, upperBound); - // Store solution for candidate. arma::vec candidateFval(numObjectives); EvaluateObjectives(std::vector(candidate), objectives, candidateFval); @@ -247,7 +258,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // we wish to preserve diversity. if (replaceCounter >= maxReplace && preserveDiversity) break; - + size_t pick = sampleNeighbor ? neighborIndices(idx, i) : idx; double candidateDecomposition = DecomposeObjectives( @@ -279,6 +290,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple return performance; } +//! Randomly chooses to select from parents or neighbors. inline std::tuple MOEAD::MatingSelection(const size_t popIdx, const arma::Mat& neighborIndices, @@ -315,7 +327,7 @@ MOEAD::MatingSelection(const size_t popIdx, return std::make_tuple(k, l); } -//! Perform mutation of the candidate. +//! Perform Polynomial mutation of the candidate. template inline void MOEAD::Mutate(MatType& child, const double& rate, @@ -335,7 +347,7 @@ inline void MOEAD::Mutate(MatType& child, currentLower = lowerBound(j); currentUpper = upperBound(j); delta1 = (current - currentLower) / (currentUpper - currentLower); - delta2 = (currentUpper - current) / (currentUpper - currentLower); + delta2 = (currentUpper - current) / (currentUpper - currentLower); rnd = arma::randu(); mutationPower = 1.0 /( distributionIndex + 1.0 ); if (rnd < 0.5) @@ -366,8 +378,7 @@ inline void MOEAD::Mutate(MatType& child, inline double MOEAD::DecomposeObjectives(const arma::vec& weights, const arma::vec& idealPoint, const arma::vec& candidateFval) -{ //FIXME: weights[i] == 0? 1e-4 : weights[i] - //TODO: Add more methods perhaps? (BI, TCHEBYCHEFF, WEIGHTED) +{ return arma::max(weights % arma::abs(candidateFval - idealPoint)); } From 7d50c879fc0778260b7acd4dcf471e96beb1b194 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Thu, 11 Mar 2021 00:28:06 +0530 Subject: [PATCH 025/128] Nits on MatingSelection - assert neighborSize > 1 - minors --- include/ensmallen_bits/moead/moead.hpp | 4 ++-- include/ensmallen_bits/moead/moead_impl.hpp | 19 +++++++++++-------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 9791f3efe..f9ea7d2be 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -215,9 +215,9 @@ class MOEAD { * @brief Randomly select two members from the population. * * @param weightNeighbourIndices - * @return std::tuple + * @return std::tuple */ - std::tuple + std::tuple MatingSelection(const size_t popIdx, const arma::Mat& weightNeighbourIndices, bool sampleNeighbor); diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index f0e80b969..52e14c166 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -15,6 +15,7 @@ #define ENSMALLEN_MOEAD_MOEAD_IMPL_HPP #include "moead.hpp" +#include namespace ens { @@ -123,7 +124,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple "an upper bound for each variable in the initial point."); } - if (populationSize < neighborSize + 1u) + if (neighborSize > populationSize - 1u) { std::ostringstream oss; oss << "MOEAD::Optimize(): " << "neighborSize is " << neighborSize @@ -291,21 +292,23 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple } //! Randomly chooses to select from parents or neighbors. -inline std::tuple +inline std::tuple MOEAD::MatingSelection(const size_t popIdx, const arma::Mat& neighborIndices, bool sampleNeighbor) { size_t k, l; + assert(neighborSize > 1u); + if (sampleNeighbor) { k = neighborIndices( - arma::randi(arma::distr_param(0, neighborSize - 1)), popIdx); + arma::randi(arma::distr_param(0, neighborSize - 1u)), popIdx); l = neighborIndices( - arma::randi(arma::distr_param(0, neighborSize - 1)), popIdx); + arma::randi(arma::distr_param(0, neighborSize - 1u)), popIdx); if (k == l) { - if (k == neighborSize - 1) + if (k == neighborSize - 1u) --k; else ++k; @@ -313,11 +316,11 @@ MOEAD::MatingSelection(const size_t popIdx, } else { - k = arma::randi(arma::distr_param(0, populationSize - 1)); - l = arma::randi(arma::distr_param(0, populationSize - 1)); + k = arma::randi(arma::distr_param(0, populationSize - 1u)); + l = arma::randi(arma::distr_param(0, populationSize - 1u)); if (k == l) { - if (k == populationSize - 1) + if (k == populationSize - 1u) --k; else ++k; From ed5ad0e53b0821ae17cbdb462c852066bba66b21 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Thu, 11 Mar 2021 00:40:28 +0530 Subject: [PATCH 026/128] DE done --- include/ensmallen_bits/moead/moead_impl.hpp | 43 +++++++++++---------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 52e14c166..901617c6b 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -209,32 +209,35 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // Mutation. MatType candidate(iterate.nrows, iterate.ncols); double delta = arma::randu(); + for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) + { + if (delta < crossoverProb) { - for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) + candidate[geneIdx] = population[r1][geneIdx] + + differentialWeight * (population[r2][geneIdx] - + population[r3][geneIdx]); + + // Boundary conditions. + if (candidate[geneIdx] < lowerBound[geneIdx]) + { + candidate[geneIdx] = lowerBound[geneIdx] + + arma::randu() * (population[r1][geneIdx] - + lowerBound[geneIdx]); + } + if (candidate[geneIdx] > upperBound[geneIdx]) { - candidate[geneIdx] = population[r1][geneIdx] + - differentialWeight * (population[r2][geneIdx] - - population[r3][geneIdx]); - - // Handle boundary condition - if (candidate[geneIdx] < lowerBound[geneIdx]) - { - candidate[geneIdx] = lowerBound[geneIdx] + - arma::randu() * (population[r1][geneIdx] - - lowerBound[geneIdx]); - } - else if (candidate[geneIdx] > upperBound[geneIdx]) - { - candidate[geneIdx] = upperBound[geneIdx] + - arma::randu() * (upperBound[geneIdx] - - population[r1][geneIdx]); - } - else - candidate[geneIdx] = population[r1][geneIdx]; + candidate[geneIdx] = upperBound[geneIdx] - + arma::randu() * (upperBound[geneIdx] - + population[r1][geneIdx]); } } + else + candidate[geneIdx] = population[r1][geneIdx]; + } + + Mutate(candidate, 1.f / numVariables, lowerBound, upperBound); arma::vec candidateFval(numObjectives); From 101137095336d1993282a3f164f2e612ac6e1f45 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Thu, 11 Mar 2021 00:56:19 +0530 Subject: [PATCH 027/128] mutation fixed --- include/ensmallen_bits/moead/moead_impl.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 901617c6b..446af1eed 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -238,7 +238,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple } - Mutate(candidate, 1.f / numVariables, lowerBound, upperBound); + Mutate(candidate, 1.f / static_cast(numVariables), lowerBound, upperBound); arma::vec candidateFval(numObjectives); EvaluateObjectives(std::vector(candidate), objectives, candidateFval); @@ -347,7 +347,7 @@ inline void MOEAD::Mutate(MatType& child, for (size_t j = 0; j < numVariables; ++j) { double determiner = arma::randu(); - if (determiner <= rate) + if (determiner <= rate && lowerBound(j) != upperBound(j)) { current = child[j]; currentLower = lowerBound(j); @@ -367,8 +367,8 @@ inline void MOEAD::Mutate(MatType& child, { upperDelta = 1.0 - delta2; value = 2.0 * (1.0 - rnd) + 2.0 * (rnd - 0.5) * - (pow(upperDelta, (distributionIndex + 1.0))); - deltaq = 1.0 - (pow(value, mutationPower)); + (std::pow(upperDelta, (distributionIndex + 1.0))); + deltaq = 1.0 - (std::pow(value, mutationPower)); } current += deltaq * (currentUpper - currentLower); From 41d58bc65233182a625b0670d60080f3c4518127 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Thu, 11 Mar 2021 01:39:25 +0530 Subject: [PATCH 028/128] minor --- include/ensmallen_bits/moead/moead_impl.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 446af1eed..0fd6aede6 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -108,8 +108,8 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple if (numObjectives < 2u) { - throw std::logic_error("MOEAD::Optimize(): This is a multiobjective problem, - numObjectives must be atleast 2."); + throw std::logic_error("MOEAD::Optimize(): This is a multiobjective problem, " + "numObjectives must be atleast 2."); } //TODO: Check if any of lowerBound is equal to upperBound if (lowerBound.size() != upperBound.size()) @@ -169,7 +169,6 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple } } - // F-value initialisation for the population. arma::mat populationFval(numObjectives, populationSize); EvaluateObjectives(population, objectives, populationFval); From 8b8fe49f7c63b945cd41a0f9cf3c3906f9754488 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Thu, 11 Mar 2021 01:59:03 +0530 Subject: [PATCH 029/128] use arma::datum::eps add check for lowerBound and upperBound --- include/ensmallen_bits/moead/moead_impl.hpp | 29 +++++++++++++++------ 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 0fd6aede6..cf942da3a 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -111,7 +111,16 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple throw std::logic_error("MOEAD::Optimize(): This is a multiobjective problem, " "numObjectives must be atleast 2."); } -//TODO: Check if any of lowerBound is equal to upperBound + + if (neighborSize > populationSize - 1u) + { + std::ostringstream oss; + oss << "MOEAD::Optimize(): " << "neighborSize is " << neighborSize + << "but populationSize is " << populationSize << "(should be" + << " atleast " << (neighborSize + 1u) << ")" << std::endl; + throw std::logic_error(oss.str()); + } + if (lowerBound.size() != upperBound.size()) { throw std::logic_error("MOEAD::Optimize(): size of lowerBound and upperBound " @@ -124,13 +133,17 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple "an upper bound for each variable in the initial point."); } - if (neighborSize > populationSize - 1u) + for(size_t geneIdx = 0; geneIdx < lowerBound.size(); geneIdx++) { - std::ostringstream oss; - oss << "MOEAD::Optimize(): " << "neighborSize is " << neighborSize - << "but populationSize is " << populationSize << "(should be" - << " atleast " << (neighborSize + 1u) << ")" << std::endl; - throw std::logic_error(oss.str()); + if(lowerBound[geneIdx] >= upperBound[geneIdx]) + { + std::ostringstream ss; + ss << "MOEAD::Optimize():" << "the lowerBound value: " << lowerBound[geneIdx] + << " is greater than upperBound value: " << upperBound[geneIdx] + << " at index: " << geneIdx << std::endl; + + throw std::logic_error(ss.str()); + } } bool terminate = false; @@ -138,7 +151,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple arma::Col shuffle; // The weight matrix. Each vector represents a decomposition subproblem. arma::Mat weights(numObjectives, populationSize, arma::fill::randu); - weights += 1e-10; //Handles zero weight case. + weights += arma::datum::eps; // Numerical stability // 1.2 Storing the indices of nearest neighbors of each weight vector. arma::Mat neighborIndices(neighborSize, populationSize); From b1ba5a21236068c8b2b30387d16ca05838593c78 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Thu, 11 Mar 2021 02:26:48 +0530 Subject: [PATCH 030/128] - n_rows - evaluate should take const population --- include/ensmallen_bits/moead/moead.hpp | 4 ++-- include/ensmallen_bits/moead/moead_impl.hpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index f9ea7d2be..db43bd921 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -264,7 +264,7 @@ class MOEAD { typename MatType, typename ...ArbitraryFunctionType> typename std::enable_if::type - EvaluateObjectives(std::vector&, + EvaluateObjectives(const std::vector&, std::tuple&, arma::mat&); @@ -272,7 +272,7 @@ class MOEAD { typename MatType, typename ...ArbitraryFunctionType> typename std::enable_if::type - EvaluateObjectives(std::vector& population, + EvaluateObjectives(const std::vector& population, std::tuple& objectives, arma::mat& calculatedObjectives); diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index cf942da3a..e66c6d57c 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -219,7 +219,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // 2.2 - 2.3 Reproduction and Repair: Differential Operator followed by // Mutation. - MatType candidate(iterate.nrows, iterate.ncols); + MatType candidate(iterate.n_rows, iterate.n_cols); double delta = arma::randu(); for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) { @@ -253,7 +253,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple Mutate(candidate, 1.f / static_cast(numVariables), lowerBound, upperBound); arma::vec candidateFval(numObjectives); - EvaluateObjectives(std::vector(candidate), objectives, candidateFval); + EvaluateObjectives(std::vector{candidate}, objectives, candidateFval); // 2.4 Update of ideal point. for (size_t idx = 0;idx < numObjectives;++idx) @@ -406,7 +406,7 @@ template typename std::enable_if::type MOEAD::EvaluateObjectives( - std::vector&, + const std::vector&, std::tuple&, arma::mat &) { @@ -419,7 +419,7 @@ template typename std::enable_if::type MOEAD::EvaluateObjectives( - std::vector& population, + const std::vector& population, std::tuple& objectives, arma::mat& calculatedObjectives) { From 08b24f1bc8e0ddd78fce97983b5c811b016af849 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Fri, 12 Mar 2021 00:20:53 +0530 Subject: [PATCH 031/128] - Everything compiles - All tests fail - debug shows weight 0? Finally hit the "wall". --- include/ensmallen_bits/moead/moead_impl.hpp | 18 +++--- tests/moead_test.cpp | 65 +++++++++++++++++++-- 2 files changed, 68 insertions(+), 15 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index e66c6d57c..e55b5bad3 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -133,9 +133,9 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple "an upper bound for each variable in the initial point."); } - for(size_t geneIdx = 0; geneIdx < lowerBound.size(); geneIdx++) + for (size_t geneIdx = 0; geneIdx < lowerBound.size(); geneIdx++) { - if(lowerBound[geneIdx] >= upperBound[geneIdx]) + if (lowerBound[geneIdx] >= upperBound[geneIdx]) { std::ostringstream ss; ss << "MOEAD::Optimize():" << "the lowerBound value: " << lowerBound[geneIdx] @@ -151,7 +151,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple arma::Col shuffle; // The weight matrix. Each vector represents a decomposition subproblem. arma::Mat weights(numObjectives, populationSize, arma::fill::randu); - weights += arma::datum::eps; // Numerical stability + weights += 1E-10; // Numerical stability // 1.2 Storing the indices of nearest neighbors of each weight vector. arma::Mat neighborIndices(neighborSize, populationSize); @@ -249,14 +249,13 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple candidate[geneIdx] = population[r1][geneIdx]; } - - Mutate(candidate, 1.f / static_cast(numVariables), lowerBound, upperBound); + Mutate(candidate, 1.0 / static_cast(numVariables), lowerBound, upperBound); arma::vec candidateFval(numObjectives); EvaluateObjectives(std::vector{candidate}, objectives, candidateFval); // 2.4 Update of ideal point. - for (size_t idx = 0;idx < numObjectives;++idx) + for (size_t idx = 0; idx < numObjectives; ++idx) { idealPoint(idx) = std::min(idealPoint(idx), candidateFval(idx)); @@ -297,10 +296,11 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple Callback::EndOptimization(*this, objectives, iterate, callbacks...); ElemType performance = std::numeric_limits::max(); - for (arma::Col objective: populationFval) + + for (size_t geneIdx = 0; geneIdx < numObjectives; ++geneIdx) { - if (arma::accu(objective) < performance) - performance = arma::accu(objective); + if (arma::accu(populationFval[geneIdx]) < performance) + performance = arma::accu(populationFval[geneIdx]); } return performance; diff --git a/tests/moead_test.cpp b/tests/moead_test.cpp index 567eaf5ac..69982c9a2 100644 --- a/tests/moead_test.cpp +++ b/tests/moead_test.cpp @@ -43,7 +43,20 @@ TEST_CASE("MOEADFonsecaFlemingTest", "[MOEADTest]") const double strength = 1e-3; const double expectedLowerBound = -1.0 / sqrt(3); const double expectedUpperBound = 1.0 / sqrt(3); - MOEAD opt(150, 10, 0.6, 0.7, strength, 10, 0.5, 0.5, lowerBound, upperBound); + MOEAD opt(150, // population size + 10, // num generations + 0.6, // cross over prob + 0.7, // mutation prob + strength, // mutation strength + 10, //neighbor size + 0.5, //distribution index + 0.5, //neighbor prob + 0.8, //differential weight + 10, //maxreplace, + true, //Preserve diversity + lowerBound, //lower bound + upperBound //upper bound + ); typedef decltype(FON.objectiveA) ObjectiveTypeA; typedef decltype(FON.objectiveB) ObjectiveTypeB; @@ -70,6 +83,7 @@ TEST_CASE("MOEADFonsecaFlemingTest", "[MOEADTest]") } REQUIRE(allInRange); } + /** * Optimize for the Fonseca Fleming function using MOEA/D optimizer. */ @@ -81,8 +95,20 @@ TEST_CASE("MOEADFonsecaFlemingVectorBoundsTest", "[MOEADTest]") const double strength = 1e-3; const double expectedLowerBound = -1.0 / sqrt(3); const double expectedUpperBound = 1.0 / sqrt(3); - MOEAD opt(150, 10, 0.6, 0.7, strength, 10, 0.5, 0.5, lowerBound, upperBound); - + MOEAD opt(150, // population size + 10, // num generations + 0.6, // cross over prob + 0.7, // mutation prob + strength, // mutation strength + 10, //neighbor size + 0.5, //distribution index + 0.5, //neighbor prob + 0.8, //differential weight + 10, //maxreplace, + true, //Preserve diversity + lowerBound, //lower bound + upperBound //upper bound + ); typedef decltype(FON.objectiveA) ObjectiveTypeA; typedef decltype(FON.objectiveB) ObjectiveTypeB; arma::mat coords = FON.GetInitialPoint(); @@ -115,8 +141,22 @@ TEST_CASE("MOEADSchafferN1Test", "[MOEADTest]") SchafferFunctionN1 SCH; double lowerBound = {-1000}; const double upperBound = {1000}; + const double strength = 1e-3; - MOEAD opt(150, 10, 0.6, 0.7, 1e-3, 9, 0.5, 0.5, lowerBound, upperBound); + MOEAD opt(150, // population size + 10, // num generations + 0.6, // cross over prob + 0.7, // mutation prob + strength, // mutation strength + 10, //neighbor size + 0.5, //distribution index + 0.5, //neighbor prob + 0.8, //differential weight + 10, //maxreplace, + true, //Preserve diversity + lowerBound, //lower bound + upperBound //upper bound + ); typedef decltype(SCH.objectiveA) ObjectiveTypeA; typedef decltype(SCH.objectiveB) ObjectiveTypeB; @@ -152,8 +192,21 @@ TEST_CASE("MOEADSchafferN1VectorBoundsTest", "[MOEADTest]") SchafferFunctionN1 SCH; arma::vec lowerBound = {-1000}; arma::vec upperBound = {1000}; - - MOEAD opt(150, 10, 0.6, 0.7, 1e-3, 9, 0.5, 0.5, lowerBound, upperBound); + const double strength = 1e-3; + MOEAD opt(150, // population size + 10, // num generations + 0.6, // cross over prob + 0.7, // mutation prob + strength, // mutation strength + 10, //neighbor size + 0.5, //distribution index + 0.5, //neighbor prob + 0.8, //differential weight + 10, //maxreplace, + true, //Preserve diversity + lowerBound, //lower bound + upperBound //upper bound + ); typedef decltype(SCH.objectiveA) ObjectiveTypeA; typedef decltype(SCH.objectiveB) ObjectiveTypeB; From fefcaa6b1fb6effb480e55f38918a415bf0a60e5 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Fri, 12 Mar 2021 14:00:14 +0530 Subject: [PATCH 032/128] minor style change test --- tests/moead_test.cpp | 231 ++++++++++++++++++++++++------------------- 1 file changed, 128 insertions(+), 103 deletions(-) diff --git a/tests/moead_test.cpp b/tests/moead_test.cpp index 69982c9a2..e92da5585 100644 --- a/tests/moead_test.cpp +++ b/tests/moead_test.cpp @@ -33,7 +33,130 @@ bool InBounds(const double& value, const double& low, const double& high) } /** - * Optimize for the Fonseca Fleming function using MOEA/D optimizer. + * Optimize for the Schaffer N.1 function using MOEA/D-DE optimizer. + */ +TEST_CASE("MOEADSchafferN1Test", "[MOEADTest]") +{ + SchafferFunctionN1 SCH; + double lowerBound = -1000; + const double upperBound = 1000; + const double strength = 1e-3; + + MOEAD opt(150, // population size + 10, // num generations + 0.6, // cross over prob + 0.7, // mutation prob + strength, // mutation strength + 10, //neighbor size + 0.5, //distribution index + 0.5, //neighbor prob + 0.8, //differential weight + 10, //maxreplace, + true, //Preserve diversity + lowerBound, //lower bound + upperBound //upper bound + ); + + typedef decltype(SCH.objectiveA) ObjectiveTypeA; + typedef decltype(SCH.objectiveB) ObjectiveTypeB; + + // We allow a few trials in case of poor convergence. + bool success = false; + for (size_t trial = 0; trial < 3; ++trial) + { + arma::mat coords = SCH.GetInitialPoint(); + std::tuple objectives = SCH.GetObjectives(); + + opt.Optimize(objectives, coords); + std::vector bestFront = opt.Front(); + + bool allInRange = true; + double minimumPositive = 1000; + + for (arma::mat solution: bestFront) + { + double val = arma::as_scalar(solution); + if(val >= 0.0) + minimumPositive = std::min(minimumPositive, val); + + if ((val < 0.0 && std::abs(val) >= minimumPositive) || val > 2.0) + { + allInRange = false; + break; + } + } + + if (allInRange) + { + success = true; + break; + } + } + + REQUIRE(success == true); +} + +/** + * Optimize for the Schaffer N.1 function using MOEA/D-DE optimizer. + */ +TEST_CASE("MOEADSchafferN1VectorBoundsTest", "[MOEADTest]") +{ + SchafferFunctionN1 SCH; + arma::vec lowerBound = {-1000}; + arma::vec upperBound = {1000}; + const double strength = 1e-3; + MOEAD opt(150, // population size + 10, // num generations + 0.6, // cross over prob + 0.7, // mutation prob + strength, // mutation strength + 10, //neighbor size + 0.5, //distribution index + 0.5, //neighbor prob + 0.8, //differential weight + 10, //maxreplace, + true, //Preserve diversity + lowerBound, //lower bound + upperBound //upper bound + ); + + typedef decltype(SCH.objectiveA) ObjectiveTypeA; + typedef decltype(SCH.objectiveB) ObjectiveTypeB; + + bool success = false; + for (size_t trial = 0; trial < 3; ++trial) + { + arma::mat coords = SCH.GetInitialPoint(); + std::tuple objectives = SCH.GetObjectives(); + + opt.Optimize(objectives, coords); + std::vector bestFront = opt.Front(); + + bool allInRange = true; + + for (arma::mat solution: bestFront) + { + double val = arma::as_scalar(solution); + + if (val < 0.0 || val > 2.0) + { + allInRange = false; + break; + } + } + + if (allInRange) + { + success = true; + break; + } + } + + REQUIRE(success == true); +} + +/** + * Optimize for the Fonseca Fleming function using MOEA/D-DE optimizer. */ TEST_CASE("MOEADFonsecaFlemingTest", "[MOEADTest]") { @@ -43,6 +166,7 @@ TEST_CASE("MOEADFonsecaFlemingTest", "[MOEADTest]") const double strength = 1e-3; const double expectedLowerBound = -1.0 / sqrt(3); const double expectedUpperBound = 1.0 / sqrt(3); + MOEAD opt(150, // population size 10, // num generations 0.6, // cross over prob @@ -60,6 +184,7 @@ TEST_CASE("MOEADFonsecaFlemingTest", "[MOEADTest]") typedef decltype(FON.objectiveA) ObjectiveTypeA; typedef decltype(FON.objectiveB) ObjectiveTypeB; + arma::mat coords = FON.GetInitialPoint(); std::tuple objectives = FON.GetObjectives(); opt.Optimize(objectives, coords); @@ -85,7 +210,7 @@ TEST_CASE("MOEADFonsecaFlemingTest", "[MOEADTest]") } /** - * Optimize for the Fonseca Fleming function using MOEA/D optimizer. + * Optimize for the Fonseca Fleming function using MOEA/D-DE optimizer. */ TEST_CASE("MOEADFonsecaFlemingVectorBoundsTest", "[MOEADTest]") { @@ -132,104 +257,4 @@ TEST_CASE("MOEADFonsecaFlemingVectorBoundsTest", "[MOEADTest]") } } REQUIRE(allInRange); -} -/** - * Optimize for the function using MOEA/D optimizer. - */ -TEST_CASE("MOEADSchafferN1Test", "[MOEADTest]") -{ - SchafferFunctionN1 SCH; - double lowerBound = {-1000}; - const double upperBound = {1000}; - const double strength = 1e-3; - - MOEAD opt(150, // population size - 10, // num generations - 0.6, // cross over prob - 0.7, // mutation prob - strength, // mutation strength - 10, //neighbor size - 0.5, //distribution index - 0.5, //neighbor prob - 0.8, //differential weight - 10, //maxreplace, - true, //Preserve diversity - lowerBound, //lower bound - upperBound //upper bound - ); - - typedef decltype(SCH.objectiveA) ObjectiveTypeA; - typedef decltype(SCH.objectiveB) ObjectiveTypeB; - - arma::mat coords = SCH.GetInitialPoint(); - std::tuple objectives = - SCH.GetObjectives(); - - opt.Optimize(objectives, coords); - std::vector bestFronts = opt.Front(); - - bool allInRange = true; - double minimumPositive = 1000; - - for (arma::mat solution: bestFronts) - { - const double val = arma::as_scalar(solution); - minimumPositive = std::min(minimumPositive, val>=0 ? val : 1000); - std::cout< 2.0) - { - allInRange = false; - break; - } - } - REQUIRE(allInRange); -} -/** - * Optimize for the function using MOEA/D optimizer. - */ -TEST_CASE("MOEADSchafferN1VectorBoundsTest", "[MOEADTest]") -{ - SchafferFunctionN1 SCH; - arma::vec lowerBound = {-1000}; - arma::vec upperBound = {1000}; - const double strength = 1e-3; - MOEAD opt(150, // population size - 10, // num generations - 0.6, // cross over prob - 0.7, // mutation prob - strength, // mutation strength - 10, //neighbor size - 0.5, //distribution index - 0.5, //neighbor prob - 0.8, //differential weight - 10, //maxreplace, - true, //Preserve diversity - lowerBound, //lower bound - upperBound //upper bound - ); - - typedef decltype(SCH.objectiveA) ObjectiveTypeA; - typedef decltype(SCH.objectiveB) ObjectiveTypeB; - - arma::mat coords = SCH.GetInitialPoint(); - std::tuple objectives = - SCH.GetObjectives(); - - opt.Optimize(objectives, coords); - std::vector bestFronts = opt.Front(); - - bool allInRange = true; - double minimumPositive = 1000; - - for (arma::mat solution: bestFronts) - { - double val = arma::as_scalar(solution); - minimumPositive = std::min(minimumPositive, val>=0 ? val : 1000); - if (val < 0.00 || val > 2.0) - { - allInRange = false; - break; - } - } - REQUIRE(allInRange); -} +} \ No newline at end of file From 57815a59b057fcba13145aa878889080380173fa Mon Sep 17 00:00:00 2001 From: NanuSai Date: Fri, 12 Mar 2021 20:31:49 +0530 Subject: [PATCH 033/128] Shuffle func is wrong --- include/ensmallen_bits/problems/schaffer_function_n1.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/ensmallen_bits/problems/schaffer_function_n1.hpp b/include/ensmallen_bits/problems/schaffer_function_n1.hpp index bf3c7c417..88d203573 100644 --- a/include/ensmallen_bits/problems/schaffer_function_n1.hpp +++ b/include/ensmallen_bits/problems/schaffer_function_n1.hpp @@ -77,9 +77,9 @@ class SchafferFunctionN1 } arma::Col Shuffle(size_t& populationSize) { - return arma::shuffle(arma::linspace >(0, - populationSize -1)); - } + return arma::shuffle(arma::linspace>( + 0, populationSize - 1, populationSize)); + } } objectiveA; struct ObjectiveB From 8b2ae1312dce879a143e86eebd33cc22664a2739 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Fri, 12 Mar 2021 21:52:45 +0530 Subject: [PATCH 034/128] rm preserve diversity --- include/ensmallen_bits/moead/moead.hpp | 10 ---------- include/ensmallen_bits/moead/moead_impl.hpp | 13 +++---------- 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index db43bd921..15733aa68 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -83,7 +83,6 @@ class MOEAD { const double neighborProb = 0.5, const double differentialWeight = 0.8, const size_t maxReplace = 10, - const bool preserveDiversity = true, const arma::vec& lowerBound = arma::zeros(1, 1), const arma::vec& upperBound = arma::ones(1, 1)); @@ -124,7 +123,6 @@ class MOEAD { const double neighborProb = 0.5, const double differentialWeight = 0.8, const size_t maxReplace = 10, - const bool preserveDiversity = true, const double lowerBound = 0, const double upperBound = 1); @@ -191,11 +189,6 @@ class MOEAD { //! Modify value of maxReplace. size_t& MaxReplace() { return maxReplace; } - //! Retreive value of preserveDiversity. - bool PreserveDiversity() const { return preserveDiversity; } - //! Modify value of preserveDiversity. - bool& PreserveDiversity() { return preserveDiversity; } - //! Retrieve value of lowerBound. const arma::vec& LowerBound() const { return lowerBound; } //! Modify value of lowerBound. @@ -308,9 +301,6 @@ class MOEAD { //! leads to a loss of diversity. size_t maxReplace; - //! If enabled, the optimizer produces diverse set of solutions. - bool preserveDiversity; - //! Lower bound on each variable in the variable space. arma::vec lowerBound; diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index e55b5bad3..34c6f4563 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -29,7 +29,6 @@ inline MOEAD::MOEAD(const size_t populationSize, const double neighborProb, const double differentialWeight, const size_t maxReplace, - const bool preserveDiversity, const arma::vec& lowerBound, const arma::vec& upperBound) : populationSize(populationSize), @@ -42,7 +41,6 @@ inline MOEAD::MOEAD(const size_t populationSize, neighborProb(neighborProb), differentialWeight(differentialWeight), maxReplace(maxReplace), - preserveDiversity(preserveDiversity), lowerBound(lowerBound), upperBound(upperBound), numObjectives(0) @@ -58,7 +56,6 @@ inline MOEAD::MOEAD(const size_t populationSize, const double neighborProb, const double differentialWeight, const size_t maxReplace, - const bool preserveDiversity, const double lowerBound, const double upperBound) : populationSize(populationSize), @@ -71,7 +68,6 @@ inline MOEAD::MOEAD(const size_t populationSize, neighborProb(neighborProb), differentialWeight(differentialWeight), maxReplace(maxReplace), - preserveDiversity(preserveDiversity), lowerBound(lowerBound * arma::ones(1, 1)), upperBound(upperBound * arma::ones(1, 1)), numObjectives(0) @@ -212,9 +208,8 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // to make a child. size_t r1, r2, r3; r1 = i; - // When preserveDiversity is active, randomly choose from the population - // or the neighbors. - bool sampleNeighbor = ( arma::randu() < neighborProb || !preserveDiversity ); + // Randomly choose to sample from the population or the neighbors. + bool sampleNeighbor = ( arma::randu() < neighborProb ); std::tie(r2, r3) = MatingSelection(i, neighborIndices, sampleNeighbor); // 2.2 - 2.3 Reproduction and Repair: Differential Operator followed by @@ -269,9 +264,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple for (size_t idx : idxShuffle) { - // Number of solutions shouldn't exceed maxReplace if - // we wish to preserve diversity. - if (replaceCounter >= maxReplace && preserveDiversity) + if (replaceCounter >= maxReplace) break; size_t pick = sampleNeighbor ? neighborIndices(idx, i) : idx; From aecbe43c3be2e643e4edfc9e7582e85732d75aee Mon Sep 17 00:00:00 2001 From: NanuSai Date: Fri, 12 Mar 2021 23:10:59 +0530 Subject: [PATCH 035/128] - Removed preserveDiversity for now - ALL TESTS PASSED!!! --- include/ensmallen_bits/moead/moead_impl.hpp | 33 ++++++++------------- tests/moead_test.cpp | 13 +++----- 2 files changed, 16 insertions(+), 30 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 34c6f4563..91675e60e 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -308,31 +308,22 @@ MOEAD::MatingSelection(const size_t popIdx, size_t k, l; assert(neighborSize > 1u); - if (sampleNeighbor) - { - k = neighborIndices( - arma::randi(arma::distr_param(0, neighborSize - 1u)), popIdx); - l = neighborIndices( - arma::randi(arma::distr_param(0, neighborSize - 1u)), popIdx); - if (k == l) - { - if (k == neighborSize - 1u) - --k; - else - ++k; - } - } - else + k = sampleNeighbor + ? neighborIndices( + arma::randi(arma::distr_param(0, neighborSize - 1u)), popIdx) + : arma::randi(arma::distr_param(0, populationSize - 1u)); + + l = sampleNeighbor + ? neighborIndices( + arma::randi(arma::distr_param(0, neighborSize - 1u)), popIdx) + : arma::randi(arma::distr_param(0, populationSize - 1u)); + + if (k == l) { - k = arma::randi(arma::distr_param(0, populationSize - 1u)); - l = arma::randi(arma::distr_param(0, populationSize - 1u)); - if (k == l) - { if (k == populationSize - 1u) --k; - else + else ++k; - } } return std::make_tuple(k, l); diff --git a/tests/moead_test.cpp b/tests/moead_test.cpp index e92da5585..d40c989a5 100644 --- a/tests/moead_test.cpp +++ b/tests/moead_test.cpp @@ -43,7 +43,7 @@ TEST_CASE("MOEADSchafferN1Test", "[MOEADTest]") const double strength = 1e-3; MOEAD opt(150, // population size - 10, // num generations + 2000, // num generations 0.6, // cross over prob 0.7, // mutation prob strength, // mutation strength @@ -52,7 +52,6 @@ TEST_CASE("MOEADSchafferN1Test", "[MOEADTest]") 0.5, //neighbor prob 0.8, //differential weight 10, //maxreplace, - true, //Preserve diversity lowerBound, //lower bound upperBound //upper bound ); @@ -106,7 +105,7 @@ TEST_CASE("MOEADSchafferN1VectorBoundsTest", "[MOEADTest]") arma::vec upperBound = {1000}; const double strength = 1e-3; MOEAD opt(150, // population size - 10, // num generations + 2000, // num generations 0.6, // cross over prob 0.7, // mutation prob strength, // mutation strength @@ -115,7 +114,6 @@ TEST_CASE("MOEADSchafferN1VectorBoundsTest", "[MOEADTest]") 0.5, //neighbor prob 0.8, //differential weight 10, //maxreplace, - true, //Preserve diversity lowerBound, //lower bound upperBound //upper bound ); @@ -168,7 +166,7 @@ TEST_CASE("MOEADFonsecaFlemingTest", "[MOEADTest]") const double expectedUpperBound = 1.0 / sqrt(3); MOEAD opt(150, // population size - 10, // num generations + 2000, // num generations 0.6, // cross over prob 0.7, // mutation prob strength, // mutation strength @@ -177,7 +175,6 @@ TEST_CASE("MOEADFonsecaFlemingTest", "[MOEADTest]") 0.5, //neighbor prob 0.8, //differential weight 10, //maxreplace, - true, //Preserve diversity lowerBound, //lower bound upperBound //upper bound ); @@ -196,7 +193,6 @@ TEST_CASE("MOEADFonsecaFlemingTest", "[MOEADTest]") double valX = arma::as_scalar(solution(0)); double valY = arma::as_scalar(solution(1)); double valZ = arma::as_scalar(solution(2)); - std::cout< Date: Sat, 13 Mar 2021 00:26:59 +0530 Subject: [PATCH 036/128] undo nsga2_test changes --- tests/nsga2_test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/nsga2_test.cpp b/tests/nsga2_test.cpp index 578a78071..3715c5ffb 100644 --- a/tests/nsga2_test.cpp +++ b/tests/nsga2_test.cpp @@ -62,7 +62,6 @@ TEST_CASE("NSGA2SchafferN1DoubleTest", "[NSGA2Test]") arma::cube paretoSet= opt.ParetoSet(); bool allInRange = true; - double minimumPositive = 1000; for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx) { From c067fcc68e48a8a84da2dca4c1996bdd19fdee58 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 13 Mar 2021 01:00:14 +0530 Subject: [PATCH 037/128] fonseca shuffle fix --- .../ensmallen_bits/problems/fonseca_fleming_function.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/ensmallen_bits/problems/fonseca_fleming_function.hpp b/include/ensmallen_bits/problems/fonseca_fleming_function.hpp index 3e2726eef..36c2577b2 100644 --- a/include/ensmallen_bits/problems/fonseca_fleming_function.hpp +++ b/include/ensmallen_bits/problems/fonseca_fleming_function.hpp @@ -82,10 +82,9 @@ class FonsecaFlemingFunction } arma::Col Shuffle(size_t& populationSize) { - return arma::shuffle(arma::linspace >(0, - populationSize -1)); - - } + return arma::shuffle(arma::linspace>( + 0, populationSize - 1, populationSize)); + } } objectiveA; struct ObjectiveB From ee92ed0f7ba58669b118c23fe90d15ae16929c68 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 13 Mar 2021 01:24:17 +0530 Subject: [PATCH 038/128] HISTORY.md updated --- HISTORY.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index eb28e7309..cc6fc7041 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -28,6 +28,9 @@ * Make Callback flexible for MultiObjective Optimizers ([#289](https://github.com/mlpack/ensmallen/pull/289)). + * Add MOEA-D/DE Optimizer + ([#269](https://github.com/mlpack/ensmallen/pull/269)). + ### ensmallen 2.16.1: "Severely Dented Can Of Polyurethane" ###### 2021-03-02 * Fix test compilation issue when `ENS_USE_OPENMP` is set @@ -80,9 +83,6 @@ * Adjust tolerance for AugLagrangian convergence based on element type ([#217](https://github.com/mlpack/ensmallen/pull/217)). - - * Add MOEA/D optimizer for multi-objective functions - ([#210](https://github.com/mlpack/ensmallen/pull/210)) ### ensmallen 2.14.0: "No Direction Home" ###### 2020-08-10 From cf9ec55754e7898e636f735f890da73999b4f29c Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 13 Mar 2021 01:25:24 +0530 Subject: [PATCH 039/128] some work on optimizer.md --- doc/optimizers.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/doc/optimizers.md b/doc/optimizers.md index cee70b4a2..73715a76a 100644 --- a/doc/optimizers.md +++ b/doc/optimizers.md @@ -1563,19 +1563,17 @@ optimizer.Optimize(f, coordinates); * [SGD in Wikipedia](https://en.wikipedia.org/wiki/Stochastic_gradient_descent) * [Differentiable separable functions](#differentiable-separable-functions) -## MOEA/D +## MOEA/D-DE *An optimizer for arbitrary multi-objective functions.* -MOEA/D (Multi Objective Evolutionary Algorithm based on Decomposition) is a multi -objective optimization algorithm. The algorithm works by decomposing a multi objective -problem to a single objective one by employing different decomposition approaches such -as Tchebycheff approach, Boundary-intersection approach and weighted sum approach. -These approaches are based on a weight vector, random choices of weight vectors produce -random single objective problems. Solving each problem, we get a different solution which -will be a part of the Pareto Front. +MOEA/D-DE (Multi Objective Evolutionary Algorithm based on Decomposition - Differential Evolution) is a multi +objective optimization algorithm. It decomposes a multiobjective optimization problem into a number of scalar +optimization subproblems and optimizes them simultaneously. Each subproblem randomly use information from neighboring +subproblems during the evolution stage. The Differential Evolution variant introduces further measures to encourage +diversity in the produced solution. #### Constructors * `MOEAD()` -* `MOEAD(`_`populationSize, crossoverProb, mutationProb, mutationStrength, neighbourhoodSize, lowerBound, upperBound`_`)` +* `MOEAD(`_`populationSize, numGeneration, crossoverProb, mutationProb, mutationStrength, neighborSize, distributionIndex, lowerBound, neighborProb, differentialWeight, maxReplace, upperBound`_`)` #### Attributes From e04519b9369d8254e2149aa9715c44d145ad3fad Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 13 Mar 2021 01:28:44 +0530 Subject: [PATCH 040/128] fix authors --- tests/moead_test.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/moead_test.cpp b/tests/moead_test.cpp index d40c989a5..a4ecdf7bd 100644 --- a/tests/moead_test.cpp +++ b/tests/moead_test.cpp @@ -1,8 +1,7 @@ /** * @file moead_test.cpp - * @author Sayan Goswami - * @author Utkarsh Rai + * @authors Sayan Goswami, Utkarsh Rai, Nanubala Gnana Sai * * ensmallen is free software; you may redistribute it and/or modify it under * the terms of the 3-clause BSD license. You should have received a copy of From c380dd5d7d117a7758ac8a1c739bb246f647b6a3 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 13 Mar 2021 01:32:57 +0530 Subject: [PATCH 041/128] rname MOEAD => MOEA/D-DE --- doc/function_types.md | 2 +- include/ensmallen_bits/moead/moead_impl.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/function_types.md b/doc/function_types.md index 81553a1ad..28139cce2 100644 --- a/doc/function_types.md +++ b/doc/function_types.md @@ -888,7 +888,7 @@ front. The following optimizers can be used with multi-objective functions: - [NSGA2](#nsga2) -- [MOEA/D](#moead) +- [MOEA/D-DE](#moead) ## Constrained functions diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 91675e60e..fb5d63144 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -2,7 +2,7 @@ * @file moead_impl.hpp * @authors Utkarsh Rai, Nanubala Gnana Sai * - * Implementation of the MOEA/D algorithm. Used for multi-objective + * Implementation of the MOEA/D-DE algorithm. Used for multi-objective * optimization problems on arbitrary functions. * * ensmallen is free software; you may redistribute it and/or modify it under From cab48a009d94f8db9466cbbad0ac18c4adfd76fe Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Sun, 14 Mar 2021 06:05:55 +0530 Subject: [PATCH 042/128] Update doc/optimizers.md Co-authored-by: Marcus Edel --- doc/optimizers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/optimizers.md b/doc/optimizers.md index 73715a76a..50a779cb9 100644 --- a/doc/optimizers.md +++ b/doc/optimizers.md @@ -1567,7 +1567,7 @@ optimizer.Optimize(f, coordinates); *An optimizer for arbitrary multi-objective functions.* MOEA/D-DE (Multi Objective Evolutionary Algorithm based on Decomposition - Differential Evolution) is a multi objective optimization algorithm. It decomposes a multiobjective optimization problem into a number of scalar -optimization subproblems and optimizes them simultaneously. Each subproblem randomly use information from neighboring +optimization subproblems and optimizes them simultaneously. Each subproblem randomly uses information from neighboring subproblems during the evolution stage. The Differential Evolution variant introduces further measures to encourage diversity in the produced solution. From eaf86e9c221cec050ee8c3f19dc2b416b1f03473 Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Sun, 14 Mar 2021 06:06:07 +0530 Subject: [PATCH 043/128] Update doc/optimizers.md Co-authored-by: Marcus Edel --- doc/optimizers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/optimizers.md b/doc/optimizers.md index 50a779cb9..7573d4809 100644 --- a/doc/optimizers.md +++ b/doc/optimizers.md @@ -1573,7 +1573,7 @@ diversity in the produced solution. #### Constructors * `MOEAD()` -* `MOEAD(`_`populationSize, numGeneration, crossoverProb, mutationProb, mutationStrength, neighborSize, distributionIndex, lowerBound, neighborProb, differentialWeight, maxReplace, upperBound`_`)` +* `MOEAD(`_`populationSize, numGeneration, crossoverProb, mutationProb, mutationStrength, neighborSize, distributionIndex, lowerBound, neighborProb, differentialWeight, maxReplace, upperBound`_`)` #### Attributes From e73e79de9bec96a52ff807542dff68348522dc65 Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Sun, 14 Mar 2021 08:04:12 +0530 Subject: [PATCH 044/128] Update include/ensmallen_bits/moead/moead.hpp Co-authored-by: Marcus Edel --- include/ensmallen_bits/moead/moead.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 15733aa68..6bd623802 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -1,6 +1,7 @@ /** * @file moead.hpp - * @authors Utkarsh Rai, Nanubala Gnana Sai + * @author Utkarsh Rai + * @author Nanubala Gnana Sai * * MOEA/D, Multi Objective Evolutionary Algorithm based on Decompositon is a * multi objective optimization algorithm. It employs evolutionary algorithms, From b1bd1445ce071488379a694043eceb82cf9e0455 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 13 Mar 2021 16:07:49 +0530 Subject: [PATCH 045/128] numGenerations => maxGenerations --- include/ensmallen_bits/moead/moead.hpp | 16 ++++++++-------- include/ensmallen_bits/moead/moead_impl.hpp | 10 +++++----- tests/moead_test.cpp | 8 ++++---- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 6bd623802..007e70750 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -57,7 +57,7 @@ class MOEAD { * parameters according to the problem. * * @param populationSize The number of elements in the population. - * @param numGeneration The number of generations the algorithm runs. + * @param maxGenerations The maximum number of generations allowed. * @param crossoverProb The probability that a crossover will occur. * @param mutationProb The probability that a mutation will occur. * @param mutationStrength The strength of mutation. @@ -75,7 +75,7 @@ class MOEAD { * of the variable space. */ MOEAD(const size_t populationSize = 100, - const size_t numGeneration = 100, + const size_t maxGenerations = 100, const double crossoverProb = 0.6, const double mutationProb = 0.3, const double mutationStrength = 1e-3, @@ -97,7 +97,7 @@ class MOEAD { * parameters according to the problem. * * @param populationSize The number of elements in the population. - * @param numGeneration The number of generations the algorithm runs. + * @param maxGenerations The maximum number of generations allowed. * @param crossoverProb The probability that a crossover will occur. * @param mutationProb The probability that a mutation will occur. * @param mutationStrength The strength of mutation. @@ -115,7 +115,7 @@ class MOEAD { * of the variable space. */ MOEAD(const size_t populationSize = 100, - const size_t numGeneration = 100, + const size_t maxGenerations = 100, const double crossoverProb = 0.6, const double mutationProb = 0.3, const double mutationStrength = 1e-3, @@ -151,9 +151,9 @@ class MOEAD { size_t& PopulationSize() { return populationSize; } //! Retrieve number of generations. - size_t NumGeneration() const { return numGeneration; } + size_t MaxGenerations() const { return maxGenerations; } //! Modify the number of generations. - size_t& NumGeneration() { return numGeneration; } + size_t& MaxGenerations() { return maxGenerations; } //! Retrieve crossover rate. double CrossoverRate() const { return crossoverProb; } @@ -273,8 +273,8 @@ class MOEAD { //! Size of the population. size_t populationSize; - //! Number of generations. - size_t numGeneration; + //! Maximum number of generations before termination criteria is met. + size_t maxGenerations; //! Probability of crossover between two members. double crossoverProb; diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index fb5d63144..d60280c4f 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -20,7 +20,7 @@ namespace ens { inline MOEAD::MOEAD(const size_t populationSize, - const size_t numGeneration, + const size_t maxGenerations, const double crossoverProb, const double mutationProb, const double mutationStrength, @@ -32,7 +32,7 @@ inline MOEAD::MOEAD(const size_t populationSize, const arma::vec& lowerBound, const arma::vec& upperBound) : populationSize(populationSize), - numGeneration(numGeneration), + maxGenerations(maxGenerations), crossoverProb(crossoverProb), mutationProb(mutationProb), mutationStrength(mutationStrength), @@ -47,7 +47,7 @@ inline MOEAD::MOEAD(const size_t populationSize, { /* Nothing to do here. */ } inline MOEAD::MOEAD(const size_t populationSize, - const size_t numGeneration, + const size_t maxGenerations, const double crossoverProb, const double mutationProb, const double mutationStrength, @@ -59,7 +59,7 @@ inline MOEAD::MOEAD(const size_t populationSize, const double lowerBound, const double upperBound) : populationSize(populationSize), - numGeneration(numGeneration), + maxGenerations(maxGenerations), crossoverProb(crossoverProb), mutationProb(mutationProb), mutationStrength(mutationStrength), @@ -195,7 +195,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple terminate |= Callback::BeginOptimization(*this, objectives, iterate, callbacks...); // 2 The main loop. - for (size_t g = 0; g < numGeneration; ++g) + for (size_t g = 0; g < maxGenerations; ++g) { shuffle = std::get<0>(objectives).Shuffle(populationSize); for (size_t i : shuffle) diff --git a/tests/moead_test.cpp b/tests/moead_test.cpp index a4ecdf7bd..f7c06675f 100644 --- a/tests/moead_test.cpp +++ b/tests/moead_test.cpp @@ -42,7 +42,7 @@ TEST_CASE("MOEADSchafferN1Test", "[MOEADTest]") const double strength = 1e-3; MOEAD opt(150, // population size - 2000, // num generations + 2000, // max generations 0.6, // cross over prob 0.7, // mutation prob strength, // mutation strength @@ -104,7 +104,7 @@ TEST_CASE("MOEADSchafferN1VectorBoundsTest", "[MOEADTest]") arma::vec upperBound = {1000}; const double strength = 1e-3; MOEAD opt(150, // population size - 2000, // num generations + 2000, // max generations 0.6, // cross over prob 0.7, // mutation prob strength, // mutation strength @@ -165,7 +165,7 @@ TEST_CASE("MOEADFonsecaFlemingTest", "[MOEADTest]") const double expectedUpperBound = 1.0 / sqrt(3); MOEAD opt(150, // population size - 2000, // num generations + 2000, // max generations 0.6, // cross over prob 0.7, // mutation prob strength, // mutation strength @@ -216,7 +216,7 @@ TEST_CASE("MOEADFonsecaFlemingVectorBoundsTest", "[MOEADTest]") const double expectedLowerBound = -1.0 / sqrt(3); const double expectedUpperBound = 1.0 / sqrt(3); MOEAD opt(150, // population size - 2000, // num generations + 2000, // max generations 0.6, // cross over prob 0.7, // mutation prob strength, // mutation strength From 288b3d710a8a94291ceb7078effb39290f030b49 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 13 Mar 2021 18:18:32 +0530 Subject: [PATCH 046/128] change def args: - numGen should be 2k - paper says neighborProb should be less (for diversity) => 0.3 --- include/ensmallen_bits/moead/moead.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 007e70750..235f1f468 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -75,13 +75,13 @@ class MOEAD { * of the variable space. */ MOEAD(const size_t populationSize = 100, - const size_t maxGenerations = 100, + const size_t maxGenerations = 2000, const double crossoverProb = 0.6, const double mutationProb = 0.3, const double mutationStrength = 1e-3, const size_t neighborSize = 50, const double distributionIndex = 0.5, - const double neighborProb = 0.5, + const double neighborProb = 0.3, const double differentialWeight = 0.8, const size_t maxReplace = 10, const arma::vec& lowerBound = arma::zeros(1, 1), @@ -115,13 +115,13 @@ class MOEAD { * of the variable space. */ MOEAD(const size_t populationSize = 100, - const size_t maxGenerations = 100, + const size_t maxGenerations = 2000, const double crossoverProb = 0.6, const double mutationProb = 0.3, const double mutationStrength = 1e-3, const size_t neighborSize = 50, const double distributionIndex = 0.5, - const double neighborProb = 0.5, + const double neighborProb = 0.3, const double differentialWeight = 0.8, const size_t maxReplace = 10, const double lowerBound = 0, From 33bcfca29d86c4673b82ee18ccbb5c8872d39d68 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 13 Mar 2021 18:27:14 +0530 Subject: [PATCH 047/128] optimizer.md updated --- doc/optimizers.md | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/doc/optimizers.md b/doc/optimizers.md index 7573d4809..05f188dd0 100644 --- a/doc/optimizers.md +++ b/doc/optimizers.md @@ -1566,29 +1566,36 @@ optimizer.Optimize(f, coordinates); ## MOEA/D-DE *An optimizer for arbitrary multi-objective functions.* MOEA/D-DE (Multi Objective Evolutionary Algorithm based on Decomposition - Differential Evolution) is a multi -objective optimization algorithm. It decomposes a multiobjective optimization problem into a number of scalar -optimization subproblems and optimizes them simultaneously. Each subproblem randomly uses information from neighboring -subproblems during the evolution stage. The Differential Evolution variant introduces further measures to encourage -diversity in the produced solution. +objective optimization algorithm. It works by decomposing the problem into a number of scalar optimization +subproblems which are solved simultaneously per generation. MOEA/D in itself is a framework, this particular +algorithm uses Differential Crossover followed by polynomial mutation to create offsprings which are then +decomposed using Tchebycheff's approach. A diversity preserving mechanism is also employed which produces +a varied set of solution. #### Constructors * `MOEAD()` -* `MOEAD(`_`populationSize, numGeneration, crossoverProb, mutationProb, mutationStrength, neighborSize, distributionIndex, lowerBound, neighborProb, differentialWeight, maxReplace, upperBound`_`)` +* `MOEAD(`_`populationSize, maxGenerations, crossoverProb, mutationProb, mutationStrength, neighborSize, distributionIndex, lowerBound, neighborProb, differentialWeight, maxReplace, upperBound`_`)` #### Attributes | **type** | **name** | **description** | **default** | |----------|----------|-----------------|-------------| -| `size_t` | **`populationSize`** | The number of candidates in the population. This should be at least 4 in size and a multiple of 4. | `100` | +| `size_t` | **`populationSize`** | The number of candidates in the population. | `100` | +| `size_t` | **`maxGenerations`** | The maximum number of generations allowed. | `2000` | | `double` | **`crossoverProb`** | Probability that a crossover will occur. | `0.6` | | `double` | **`mutationProb`** | Probability that a weight will get mutated. | `0.3` | | `double` | **`mutationStrength`** | The range of mutation noise to be added. This range is between 0 and mutationStrength. | `0.001` | -| `size_t` | **`neighbourhoodSize`** | The number of nearest-neighbours to consider for each weight. | `50` | -| `arma::vec` | **`lowerBound`** | Lower bound of the coordinates of the initial population. | `1` | -| `arma::vec` | **`upperBound`** | Lower bound of the coordinates of the initial population. | `1` | +| `size_t` | **`neighborSize`** | The number of nearest-neighbours to consider for each weight. | `50` | +| `double` | **`distributionIndex`** | The crowding degree of the mutation. | `0.5` | +| `double` | **`neighborProb`** | The probability of sampling from neighbor. | `0.3` | +| `double` | **`differentialWeight`** | Amplification factor of the differentiation. | `0.8` | +| `size_t` | **`maxReplace`** | The limit of solutions allowed to be replaced by a child. | `10` | +| `double`, `arma::vec` | **`lowerBound`** | Lower bound of the coordinates on the coordinates of the whole population during the search process. | `0` | +| `double`, `arma::vec` | **`upperBound`** | Lower bound of the coordinates on the coordinates of the whole population during the search process. | `1` | Attributes of the optimizer may also be changed via the member methods -`PopulationSize()`, `CrossoverRate()`, `MutationProbability()`, `NeighbourhoodSize()`, `LowerBound()` and `UpperBound()`. +`PopulationSize()`, `MaxGenerations()`, `CrossoverRate()`, `MutationProbability()`, `NeighborSize()`, `DistributionIndex()`, +`NeighborProb()`, `DifferentialWeight()`, `MaxReplace()`, `LowerBound()` and `UpperBound()`. #### Examples: From c388bde9ea151b6d1caebbe9bef12e19b5cc739e Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 13 Mar 2021 20:29:57 +0530 Subject: [PATCH 048/128] rm redundant args --- include/ensmallen_bits/moead/moead.hpp | 53 ++++++++------------------ 1 file changed, 16 insertions(+), 37 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 235f1f468..3ca2b613f 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -59,8 +59,6 @@ class MOEAD { * @param populationSize The number of elements in the population. * @param maxGenerations The maximum number of generations allowed. * @param crossoverProb The probability that a crossover will occur. - * @param mutationProb The probability that a mutation will occur. - * @param mutationStrength The strength of mutation. * @param neighborSize The number of nearest neighbours of weights * to find. * @param distributionIndex The crowding degree of the mutation. @@ -68,22 +66,19 @@ class MOEAD { * @param differentialWeight A parameter used in the mutation of candidate * solutions controls amplification factor of the differentiation. * @param maxReplace The limit of solutions allowed to be replaced by a child. - * @param preserveDiversity Enforce preserving diversity. * @param lowerBound The lower bound on each variable of a member * of the variable space. * @param upperBound The upper bound on each variable of a member * of the variable space. */ - MOEAD(const size_t populationSize = 100, - const size_t maxGenerations = 2000, - const double crossoverProb = 0.6, - const double mutationProb = 0.3, - const double mutationStrength = 1e-3, - const size_t neighborSize = 50, - const double distributionIndex = 0.5, - const double neighborProb = 0.3, - const double differentialWeight = 0.8, - const size_t maxReplace = 10, + MOEAD(const size_t populationSize = 150, + const size_t maxGenerations = 1000, + const double crossoverProb = 1.0, + const size_t neighborSize = 20, + const double distributionIndex = 20, + const double neighborProb = 0.9, + const double differentialWeight = 0.5, + const size_t maxReplace = 2, const arma::vec& lowerBound = arma::zeros(1, 1), const arma::vec& upperBound = arma::ones(1, 1)); @@ -99,8 +94,6 @@ class MOEAD { * @param populationSize The number of elements in the population. * @param maxGenerations The maximum number of generations allowed. * @param crossoverProb The probability that a crossover will occur. - * @param mutationProb The probability that a mutation will occur. - * @param mutationStrength The strength of mutation. * @param neighborSize The number of nearest neighbours of weights * to find. * @param distributionIndex The crowding degree of the mutation. @@ -108,22 +101,19 @@ class MOEAD { * @param differentialWeight A parameter used in the mutation of candidate * solutions controls amplification factor of the differentiation. * @param maxReplace The limit of solutions allowed to be replaced by a child. - * @param preserveDiversity Enforce preserving diversity. * @param lowerBound The lower bound on each variable of a member * of the variable space. * @param upperBound The upper bound on each variable of a member * of the variable space. */ - MOEAD(const size_t populationSize = 100, - const size_t maxGenerations = 2000, - const double crossoverProb = 0.6, - const double mutationProb = 0.3, - const double mutationStrength = 1e-3, - const size_t neighborSize = 50, - const double distributionIndex = 0.5, - const double neighborProb = 0.3, - const double differentialWeight = 0.8, - const size_t maxReplace = 10, + MOEAD(const size_t populationSize = 150, + const size_t maxGenerations = 1000, + const double crossoverProb = 1.0, + const size_t neighborSize = 20, + const double distributionIndex = 20, + const double neighborProb = 0.9, + const double differentialWeight = 0.5, + const size_t maxReplace = 2, const double lowerBound = 0, const double upperBound = 1); @@ -160,11 +150,6 @@ class MOEAD { //! Modify the crossover rate. double& CrossoverRate() { return crossoverProb; } - //! Retrieve mutation probability. - double MutationProbability() const { return mutationProb; } - //! Modify the mutation probability. - double& MutationProbability() { return mutationProb; } - //! Retrieve size of the weight neighbor. size_t NeighborSize() const { return neighborSize; } //! Modify the size of the weight neighbor. @@ -279,12 +264,6 @@ class MOEAD { //! Probability of crossover between two members. double crossoverProb; - //! Probability of mutation of a child. - double mutationProb; - - //! Strength of mutation. - double mutationStrength; - //! Number of nearest neighbours of weights to consider. size_t neighborSize; From be8e45b45ac7cb803f15b7c97be83c556c2af02f Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sun, 14 Mar 2021 09:01:27 +0530 Subject: [PATCH 049/128] rm a) mutationProb b) mutationStrength add Sanity checks for all params Styling fix --- include/ensmallen_bits/moead/moead_impl.hpp | 179 ++++++++++++-------- 1 file changed, 108 insertions(+), 71 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index d60280c4f..58445b346 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -22,8 +22,6 @@ namespace ens { inline MOEAD::MOEAD(const size_t populationSize, const size_t maxGenerations, const double crossoverProb, - const double mutationProb, - const double mutationStrength, const size_t neighborSize, const double distributionIndex, const double neighborProb, @@ -34,8 +32,6 @@ inline MOEAD::MOEAD(const size_t populationSize, populationSize(populationSize), maxGenerations(maxGenerations), crossoverProb(crossoverProb), - mutationProb(mutationProb), - mutationStrength(mutationStrength), neighborSize(neighborSize), distributionIndex(distributionIndex), neighborProb(neighborProb), @@ -49,8 +45,6 @@ inline MOEAD::MOEAD(const size_t populationSize, inline MOEAD::MOEAD(const size_t populationSize, const size_t maxGenerations, const double crossoverProb, - const double mutationProb, - const double mutationStrength, const size_t neighborSize, const double distributionIndex, const double neighborProb, @@ -61,8 +55,6 @@ inline MOEAD::MOEAD(const size_t populationSize, populationSize(populationSize), maxGenerations(maxGenerations), crossoverProb(crossoverProb), - mutationProb(mutationProb), - mutationStrength(mutationStrength), neighborSize(neighborSize), distributionIndex(distributionIndex), neighborProb(neighborProb), @@ -81,6 +73,66 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple MatType& iterate, CallbackTypes&&... callbacks) { + // Sanity checks + if (populationSize < 3) + { + throw std::invalid_argument( + "populationSize should be atleast 3 however " + + std::to_string(populationSize) + " was detected."); + } + + if (crossoverProb > 1.0 || crossoverProb < 0.0) + { + throw std::invalid_argument( + "The parameter crossoverProb needs to be in [0,1], however " + + std::to_string(crossoverProb) + " was detected."); + } + + if (neighborSize < 2) + { + throw std::invalid_argument( + "neighborSize should be atleast 2, however " + + std::to_string(neighborSize) + " was detected." + ); + } + + if (neighborSize > populationSize - 1u) + { + std::ostringstream oss; + oss << "MOEAD::Optimize(): " << "neighborSize is " << neighborSize + << " but populationSize is " << populationSize << "(should be" + << " atleast " << (neighborSize + 1u) << ")" << std::endl; + throw std::logic_error(oss.str()); + } + + if (distributionIndex < 0) + { + throw std::invalid_argument( + "distributionIndex should be positive, however " + + std::to_string(distributionIndex) + " was detected."); + } + + if (differentialWeight > 1.0 || differentialWeight < 0.0) + { + throw std::invalid_argument( + "The parameter differentialWeight needs to be in [0,1], however " + + std::to_string(differentialWeight) + " was detected."); + } + + if (neighborProb > 1.0 || neighborProb < 0.0) + { + throw std::invalid_argument( + "The parameter neighborProb needs to be in [0,1], however " + + std::to_string(neighborProb) + " was detected."); + } + + if(maxReplace < 0) + { + throw std::invalid_argument( + "maxReplace should be positive, however " + + std::to_string(maxReplace) + " was detected."); + } + // Check if lower bound is a vector of a single dimension. if (lowerBound.n_rows == 1) lowerBound = lowerBound(0, 0) * arma::ones(iterate.n_rows, iterate.n_cols); @@ -97,26 +149,12 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // Dimensionality of variable space. Also referred to as number of genes. size_t numVariables = iterate.n_rows; - if (populationSize <= 0) - { - throw std::logic_error("MOEAD::Optimize(): populationSize should be positive."); - } - if (numObjectives < 2u) { throw std::logic_error("MOEAD::Optimize(): This is a multiobjective problem, " "numObjectives must be atleast 2."); } - if (neighborSize > populationSize - 1u) - { - std::ostringstream oss; - oss << "MOEAD::Optimize(): " << "neighborSize is " << neighborSize - << "but populationSize is " << populationSize << "(should be" - << " atleast " << (neighborSize + 1u) << ")" << std::endl; - throw std::logic_error(oss.str()); - } - if (lowerBound.size() != upperBound.size()) { throw std::logic_error("MOEAD::Optimize(): size of lowerBound and upperBound " @@ -131,15 +169,15 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple for (size_t geneIdx = 0; geneIdx < lowerBound.size(); geneIdx++) { - if (lowerBound[geneIdx] >= upperBound[geneIdx]) - { - std::ostringstream ss; - ss << "MOEAD::Optimize():" << "the lowerBound value: " << lowerBound[geneIdx] - << " is greater than upperBound value: " << upperBound[geneIdx] - << " at index: " << geneIdx << std::endl; + if (lowerBound[geneIdx] >= upperBound[geneIdx]) + { + std::ostringstream ss; + ss << "MOEAD::Optimize():" << "the lowerBound value: " << lowerBound[geneIdx] + << " is greater than upperBound value: " << upperBound[geneIdx] + << " at index: " << geneIdx << std::endl; - throw std::logic_error(ss.str()); - } + throw std::logic_error(ss.str()); + } } bool terminate = false; @@ -153,13 +191,13 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple arma::Mat neighborIndices(neighborSize, populationSize); for (size_t i = 0; i < populationSize; ++i) { - // Cache the distance between weights(i) and other weights. - arma::rowvec distances(populationSize); - distances = - arma::sqrt(arma::sum(arma::pow(weights.col(i) - weights.each_col(), 2))); - arma::uvec sortedIndices = arma::stable_sort_index(distances); - // Ignore distance from self - neighborIndices.col(i) = sortedIndices(arma::span(1, neighborSize)); + // Cache the distance between weights(i) and other weights. + arma::rowvec distances(populationSize); + distances = + arma::sqrt(arma::sum(arma::pow(weights.col(i) - weights.each_col(), 2))); + arma::uvec sortedIndices = arma::stable_sort_index(distances); + // Ignore distance from self + neighborIndices.col(i) = sortedIndices(arma::span(1, neighborSize)); } // 1.2 Random generation of the initial population. @@ -167,7 +205,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple for (size_t i = 0; i < populationSize; ++i) { population[i] = - arma::randu(iterate.n_rows, iterate.n_cols) - 0.5 + iterate; + arma::randu(iterate.n_rows, iterate.n_cols) - 0.5 + iterate; for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) { @@ -178,8 +216,8 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple } } - arma::mat populationFval(numObjectives, populationSize); - EvaluateObjectives(population, objectives, populationFval); + arma::mat populationFitness(numObjectives, populationSize); + EvaluateObjectives(population, objectives, populationFitness); // 1.3 Initialize the ideal point z. arma::vec idealPoint(numObjectives); @@ -188,7 +226,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple { for (size_t j = 0; j < populationSize; ++j) { - idealPoint(i) = std::min(idealPoint(i), populationFval(i, j)); + idealPoint(i) = std::min(idealPoint(i), populationFitness(i, j)); } } @@ -219,30 +257,30 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) { - if (delta < crossoverProb) - { - candidate[geneIdx] = population[r1][geneIdx] + - differentialWeight * (population[r2][geneIdx] - + if (delta < crossoverProb) + { + candidate[geneIdx] = population[r1][geneIdx] + + differentialWeight * (population[r2][geneIdx] - population[r3][geneIdx]); - // Boundary conditions. - if (candidate[geneIdx] < lowerBound[geneIdx]) - { - candidate[geneIdx] = lowerBound[geneIdx] + - arma::randu() * (population[r1][geneIdx] - - lowerBound[geneIdx]); - } - if (candidate[geneIdx] > upperBound[geneIdx]) - { - candidate[geneIdx] = upperBound[geneIdx] - - arma::randu() * (upperBound[geneIdx] - - population[r1][geneIdx]); + // Boundary conditions. + if (candidate[geneIdx] < lowerBound[geneIdx]) + { + candidate[geneIdx] = lowerBound[geneIdx] + + arma::randu() * (population[r1][geneIdx] - + lowerBound[geneIdx]); + } + if (candidate[geneIdx] > upperBound[geneIdx]) + { + candidate[geneIdx] = upperBound[geneIdx] - + arma::randu() * (upperBound[geneIdx] - + population[r1][geneIdx]); + } } - } - else - candidate[geneIdx] = population[r1][geneIdx]; - } + else + candidate[geneIdx] = population[r1][geneIdx]; + } Mutate(candidate, 1.0 / static_cast(numVariables), lowerBound, upperBound); @@ -270,14 +308,14 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple size_t pick = sampleNeighbor ? neighborIndices(idx, i) : idx; double candidateDecomposition = DecomposeObjectives( - weights.col(pick), idealPoint, candidateFval); + weights.col(pick), idealPoint, candidateFval); double parentDecomposition = DecomposeObjectives( - weights.col(pick), idealPoint, populationFval.col(pick)); + weights.col(pick), idealPoint, populationFitness.col(pick)); if (candidateDecomposition < parentDecomposition) { population[pick] = candidate; - populationFval.col(pick) = candidateFval; + populationFitness.col(pick) = candidateFval; replaceCounter++; } } @@ -292,8 +330,8 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple for (size_t geneIdx = 0; geneIdx < numObjectives; ++geneIdx) { - if (arma::accu(populationFval[geneIdx]) < performance) - performance = arma::accu(populationFval[geneIdx]); + if (arma::accu(populationFitness[geneIdx]) < performance) + performance = arma::accu(populationFitness[geneIdx]); } return performance; @@ -306,7 +344,6 @@ MOEAD::MatingSelection(const size_t popIdx, bool sampleNeighbor) { size_t k, l; - assert(neighborSize > 1u); k = sampleNeighbor ? neighborIndices( @@ -320,10 +357,10 @@ MOEAD::MatingSelection(const size_t popIdx, if (k == l) { - if (k == populationSize - 1u) - --k; - else - ++k; + if (k == populationSize - 1u) + --k; + else + ++k; } return std::make_tuple(k, l); From 3f30929c310c2e13b932b3835edbf8c3e480df41 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sun, 14 Mar 2021 10:20:11 +0530 Subject: [PATCH 050/128] => test with def args : pass => rm arma::Mat<> => arma::umat --- include/ensmallen_bits/moead/moead.hpp | 2 +- include/ensmallen_bits/moead/moead_impl.hpp | 8 +- .../problems/fonseca_fleming_function.hpp | 4 +- .../problems/schaffer_function_n1.hpp | 4 +- tests/moead_test.cpp | 107 +++++++++--------- 5 files changed, 60 insertions(+), 65 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 3ca2b613f..3d410d7bc 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -198,7 +198,7 @@ class MOEAD { */ std::tuple MatingSelection(const size_t popIdx, - const arma::Mat& weightNeighbourIndices, + const arma::umat& weightNeighbourIndices, bool sampleNeighbor); /** diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 58445b346..d737a9764 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -182,13 +182,13 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple bool terminate = false; - arma::Col shuffle; + arma::uvec shuffle; // The weight matrix. Each vector represents a decomposition subproblem. arma::Mat weights(numObjectives, populationSize, arma::fill::randu); weights += 1E-10; // Numerical stability // 1.2 Storing the indices of nearest neighbors of each weight vector. - arma::Mat neighborIndices(neighborSize, populationSize); + arma::umat neighborIndices(neighborSize, populationSize); for (size_t i = 0; i < populationSize; ++i) { // Cache the distance between weights(i) and other weights. @@ -298,7 +298,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple size_t replaceCounter = 0; size_t sampleSize = sampleNeighbor ? neighborSize : populationSize; - arma::Col idxShuffle = std::get<0>(objectives).Shuffle(sampleSize); + arma::uvec idxShuffle = std::get<0>(objectives).Shuffle(sampleSize); for (size_t idx : idxShuffle) { @@ -340,7 +340,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple //! Randomly chooses to select from parents or neighbors. inline std::tuple MOEAD::MatingSelection(const size_t popIdx, - const arma::Mat& neighborIndices, + const arma::umat& neighborIndices, bool sampleNeighbor) { size_t k, l; diff --git a/include/ensmallen_bits/problems/fonseca_fleming_function.hpp b/include/ensmallen_bits/problems/fonseca_fleming_function.hpp index 36c2577b2..71b809a27 100644 --- a/include/ensmallen_bits/problems/fonseca_fleming_function.hpp +++ b/include/ensmallen_bits/problems/fonseca_fleming_function.hpp @@ -80,9 +80,9 @@ class FonsecaFlemingFunction -pow(static_cast(coords[2]) - 1.0 / sqrt(3.0), 2.0) ); } - arma::Col Shuffle(size_t& populationSize) + arma::uvec Shuffle(size_t& populationSize) { - return arma::shuffle(arma::linspace>( + return arma::shuffle(arma::linspace( 0, populationSize - 1, populationSize)); } } objectiveA; diff --git a/include/ensmallen_bits/problems/schaffer_function_n1.hpp b/include/ensmallen_bits/problems/schaffer_function_n1.hpp index 88d203573..50cdaa7ce 100644 --- a/include/ensmallen_bits/problems/schaffer_function_n1.hpp +++ b/include/ensmallen_bits/problems/schaffer_function_n1.hpp @@ -75,9 +75,9 @@ class SchafferFunctionN1 { return std::pow(coords[0], 2); } - arma::Col Shuffle(size_t& populationSize) + arma::uvec Shuffle(size_t& populationSize) { - return arma::shuffle(arma::linspace>( + return arma::shuffle(arma::linspace( 0, populationSize - 1, populationSize)); } } objectiveA; diff --git a/tests/moead_test.cpp b/tests/moead_test.cpp index f7c06675f..49c9e9912 100644 --- a/tests/moead_test.cpp +++ b/tests/moead_test.cpp @@ -39,21 +39,19 @@ TEST_CASE("MOEADSchafferN1Test", "[MOEADTest]") SchafferFunctionN1 SCH; double lowerBound = -1000; const double upperBound = 1000; - const double strength = 1e-3; - - MOEAD opt(150, // population size - 2000, // max generations - 0.6, // cross over prob - 0.7, // mutation prob - strength, // mutation strength - 10, //neighbor size - 0.5, //distribution index - 0.5, //neighbor prob - 0.8, //differential weight - 10, //maxreplace, - lowerBound, //lower bound - upperBound //upper bound - ); + + MOEAD opt( + 150, // population size + 1000, // max generations + 1.0, // crossover prob + 20, //neighbor size + 20, //distribution index + 0.9, //neighbor prob + 0.5, //differential weight + 2, //maxreplace, + lowerBound, //lower bound + upperBound //upper bound + ); typedef decltype(SCH.objectiveA) ObjectiveTypeA; typedef decltype(SCH.objectiveB) ObjectiveTypeB; @@ -102,20 +100,19 @@ TEST_CASE("MOEADSchafferN1VectorBoundsTest", "[MOEADTest]") SchafferFunctionN1 SCH; arma::vec lowerBound = {-1000}; arma::vec upperBound = {1000}; - const double strength = 1e-3; - MOEAD opt(150, // population size - 2000, // max generations - 0.6, // cross over prob - 0.7, // mutation prob - strength, // mutation strength - 10, //neighbor size - 0.5, //distribution index - 0.5, //neighbor prob - 0.8, //differential weight - 10, //maxreplace, - lowerBound, //lower bound - upperBound //upper bound - ); + + MOEAD opt( + 150, // population size + 1000, // max generations + 1.0, // crossover prob + 20, //neighbor size + 20, //distribution index + 0.9, //neighbor prob + 0.5, //differential weight + 2, //maxreplace, + lowerBound, //lower bound + upperBound //upper bound + ); typedef decltype(SCH.objectiveA) ObjectiveTypeA; typedef decltype(SCH.objectiveB) ObjectiveTypeB; @@ -160,23 +157,21 @@ TEST_CASE("MOEADFonsecaFlemingTest", "[MOEADTest]") FonsecaFlemingFunction FON; const double lowerBound = -4; const double upperBound = 4; - const double strength = 1e-3; const double expectedLowerBound = -1.0 / sqrt(3); const double expectedUpperBound = 1.0 / sqrt(3); - MOEAD opt(150, // population size - 2000, // max generations - 0.6, // cross over prob - 0.7, // mutation prob - strength, // mutation strength - 10, //neighbor size - 0.5, //distribution index - 0.5, //neighbor prob - 0.8, //differential weight - 10, //maxreplace, - lowerBound, //lower bound - upperBound //upper bound - ); + MOEAD opt( + 150, // population size + 1000, // max generations + 1.0, // crossover prob + 20, //neighbor size + 20, //distribution index + 0.9, //neighbor prob + 0.5, //differential weight + 2, //maxreplace, + lowerBound, //lower bound + upperBound //upper bound + ); typedef decltype(FON.objectiveA) ObjectiveTypeA; typedef decltype(FON.objectiveB) ObjectiveTypeB; @@ -210,24 +205,24 @@ TEST_CASE("MOEADFonsecaFlemingTest", "[MOEADTest]") TEST_CASE("MOEADFonsecaFlemingVectorBoundsTest", "[MOEADTest]") { FonsecaFlemingFunction FON; - const arma::vec lowerBound("-4 -4 -4"); - const arma::vec upperBound("4 4 4"); - const double strength = 1e-3; + const arma::vec lowerBound = {-4, -4, -4}; + const arma::vec upperBound = {4, 4, 4}; const double expectedLowerBound = -1.0 / sqrt(3); const double expectedUpperBound = 1.0 / sqrt(3); - MOEAD opt(150, // population size - 2000, // max generations - 0.6, // cross over prob - 0.7, // mutation prob - strength, // mutation strength - 10, //neighbor size - 0.5, //distribution index - 0.5, //neighbor prob - 0.8, //differential weight - 10, //maxreplace, + + MOEAD opt( + 150, // population size + 1000, // max generations + 1.0, // crossover prob + 20, //neighbor size + 20, //distribution index + 0.9, //neighbor prob + 0.5, //differential weight + 2, //maxreplace, lowerBound, //lower bound upperBound //upper bound ); + typedef decltype(FON.objectiveA) ObjectiveTypeA; typedef decltype(FON.objectiveB) ObjectiveTypeB; arma::mat coords = FON.GetInitialPoint(); From f1488ab44e1117982759a6e1d2a34073301d28e9 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sun, 14 Mar 2021 10:33:07 +0530 Subject: [PATCH 051/128] candidateFval => candidateFitness --- include/ensmallen_bits/moead/moead_impl.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index d737a9764..fdf012b99 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -284,14 +284,14 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple Mutate(candidate, 1.0 / static_cast(numVariables), lowerBound, upperBound); - arma::vec candidateFval(numObjectives); - EvaluateObjectives(std::vector{candidate}, objectives, candidateFval); + arma::vec candidateFitness(numObjectives); + EvaluateObjectives(std::vector{candidate}, objectives, candidateFitness); // 2.4 Update of ideal point. for (size_t idx = 0; idx < numObjectives; ++idx) { idealPoint(idx) = std::min(idealPoint(idx), - candidateFval(idx)); + candidateFitness(idx)); } // 2.5 Update of the population. @@ -308,14 +308,14 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple size_t pick = sampleNeighbor ? neighborIndices(idx, i) : idx; double candidateDecomposition = DecomposeObjectives( - weights.col(pick), idealPoint, candidateFval); + weights.col(pick), idealPoint, candidateFitness); double parentDecomposition = DecomposeObjectives( weights.col(pick), idealPoint, populationFitness.col(pick)); if (candidateDecomposition < parentDecomposition) { population[pick] = candidate; - populationFitness.col(pick) = candidateFval; + populationFitness.col(pick) = candidateFitness; replaceCounter++; } } @@ -416,9 +416,9 @@ inline void MOEAD::Mutate(MatType& child, //! approach. inline double MOEAD::DecomposeObjectives(const arma::vec& weights, const arma::vec& idealPoint, - const arma::vec& candidateFval) + const arma::vec& candidateFitness) { - return arma::max(weights % arma::abs(candidateFval - idealPoint)); + return arma::max(weights % arma::abs(candidateFitness - idealPoint)); } //! No objectives to evaluate. From 5e27bdf1f237299940fdefdb49844848cf762e6b Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sun, 14 Mar 2021 12:02:17 +0530 Subject: [PATCH 052/128] minor doc changes --- include/ensmallen_bits/moead/moead.hpp | 30 ++++++++++----------- include/ensmallen_bits/moead/moead_impl.hpp | 11 ++++---- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 3d410d7bc..93fa7d352 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -191,14 +191,15 @@ class MOEAD { private: /** - * @brief Randomly select two members from the population. + * @brief Randomly selects two members from the population. * - * @param weightNeighbourIndices - * @return std::tuple + * @param subProblemIdx Index of the current subproblem. + * @param neighborSize A matrix containing indices of the neighbors. + * @return std::tuple The chosen pair of indices. */ std::tuple - MatingSelection(const size_t popIdx, - const arma::umat& weightNeighbourIndices, + MatingSelection(const size_t subProblemIdx, + const arma::umat& neighborSize, bool sampleNeighbor); /** @@ -206,29 +207,28 @@ class MOEAD { * population. Uses polynomial mutation. * * @tparam MatType The type of matrix used to store coordinates. - * @param child The matrix to mutate. - * @param rate To determine whether mutation happens at a particular index. + * @param child The candidate to be mutated. + * @param mutationRate The probability of mutation. * @param lowerBound The lower bound on each variable in the matrix. * @param upperBound The upper bound on each variable in the matrix. */ template void Mutate(MatType& child, - const double& rate, + const double& mutationRate, const arma::vec& lowerBound, const arma::vec& upperBound); /** - * Decompose the multi objective problem to a single objetive problem - * using the Tchebycheff approach. + * Decompose the multi objective problem to a single objective problem. * - * @param weights A set of)real number which act as weights. - * @param idealPoint Ideal point z in Tchebycheff decomposition. - * @param evaluatedCandidate Value of the candidate per objective. - * @return The single value obtained from decomposed function. + * @param weights Decomposition weights. + * @param idealPoint The reference point z for a decomposition problem. + * @param candidateFitness The fitness value of the candidate. + * @return The real value obtained from the decomposed function. */ double DecomposeObjectives(const arma::vec& weights, const arma::vec& idealPoint, - const arma::vec& evaluatedCandidate); + const arma::vec& candidateFitness); /** * Evaluate objectives for the elite population. diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index fdf012b99..a1cee5e9c 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -339,7 +339,8 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple //! Randomly chooses to select from parents or neighbors. inline std::tuple -MOEAD::MatingSelection(const size_t popIdx, +MOEAD::MatingSelection( + const size_t subProblemIdx, const arma::umat& neighborIndices, bool sampleNeighbor) { @@ -347,12 +348,12 @@ MOEAD::MatingSelection(const size_t popIdx, k = sampleNeighbor ? neighborIndices( - arma::randi(arma::distr_param(0, neighborSize - 1u)), popIdx) + arma::randi(arma::distr_param(0, neighborSize - 1u)), subProblemIdx) : arma::randi(arma::distr_param(0, populationSize - 1u)); l = sampleNeighbor ? neighborIndices( - arma::randi(arma::distr_param(0, neighborSize - 1u)), popIdx) + arma::randi(arma::distr_param(0, neighborSize - 1u)), subProblemIdx) : arma::randi(arma::distr_param(0, populationSize - 1u)); if (k == l) @@ -369,7 +370,7 @@ MOEAD::MatingSelection(const size_t popIdx, //! Perform Polynomial mutation of the candidate. template inline void MOEAD::Mutate(MatType& child, - const double& rate, + const double& mutationRate, const arma::vec& lowerBound, const arma::vec& upperBound) { @@ -380,7 +381,7 @@ inline void MOEAD::Mutate(MatType& child, for (size_t j = 0; j < numVariables; ++j) { double determiner = arma::randu(); - if (determiner <= rate && lowerBound(j) != upperBound(j)) + if (determiner <= mutationRate && lowerBound(j) != upperBound(j)) { current = child[j]; currentLower = lowerBound(j); From d2615d5471b50d174d132459d095796e5be05d34 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sun, 14 Mar 2021 12:17:25 +0530 Subject: [PATCH 053/128] optimizer.MD update --- doc/optimizers.md | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/doc/optimizers.md b/doc/optimizers.md index 05f188dd0..c61a7fea3 100644 --- a/doc/optimizers.md +++ b/doc/optimizers.md @@ -1574,27 +1574,25 @@ a varied set of solution. #### Constructors * `MOEAD()` -* `MOEAD(`_`populationSize, maxGenerations, crossoverProb, mutationProb, mutationStrength, neighborSize, distributionIndex, lowerBound, neighborProb, differentialWeight, maxReplace, upperBound`_`)` +* `MOEAD(`_`populationSize, maxGenerations, crossoverProb, neighborSize, distributionIndex, neighborProb, differentialWeight, maxReplace, lowerBound, upperBound`_`)` #### Attributes | **type** | **name** | **description** | **default** | |----------|----------|-----------------|-------------| -| `size_t` | **`populationSize`** | The number of candidates in the population. | `100` | -| `size_t` | **`maxGenerations`** | The maximum number of generations allowed. | `2000` | -| `double` | **`crossoverProb`** | Probability that a crossover will occur. | `0.6` | -| `double` | **`mutationProb`** | Probability that a weight will get mutated. | `0.3` | -| `double` | **`mutationStrength`** | The range of mutation noise to be added. This range is between 0 and mutationStrength. | `0.001` | -| `size_t` | **`neighborSize`** | The number of nearest-neighbours to consider for each weight. | `50` | -| `double` | **`distributionIndex`** | The crowding degree of the mutation. | `0.5` | -| `double` | **`neighborProb`** | The probability of sampling from neighbor. | `0.3` | -| `double` | **`differentialWeight`** | Amplification factor of the differentiation. | `0.8` | -| `size_t` | **`maxReplace`** | The limit of solutions allowed to be replaced by a child. | `10` | +| `size_t` | **`populationSize`** | The number of candidates in the population. | `150` | +| `size_t` | **`maxGenerations`** | The maximum number of generations allowed. | `1000` | +| `double` | **`crossoverProb`** | Probability that a crossover will occur. | `1.0` | +| `size_t` | **`neighborSize`** | The number of nearest-neighbours to consider for each weight. | `20` | +| `double` | **`distributionIndex`** | The crowding degree of the mutation. | `20` | +| `double` | **`neighborProb`** | The probability of sampling from neighbor. | `0.9` | +| `double` | **`differentialWeight`** | Amplification factor of the differentiation. | `0.5` | +| `size_t` | **`maxReplace`** | The limit of solutions allowed to be replaced by a child. | `2` | | `double`, `arma::vec` | **`lowerBound`** | Lower bound of the coordinates on the coordinates of the whole population during the search process. | `0` | | `double`, `arma::vec` | **`upperBound`** | Lower bound of the coordinates on the coordinates of the whole population during the search process. | `1` | Attributes of the optimizer may also be changed via the member methods -`PopulationSize()`, `MaxGenerations()`, `CrossoverRate()`, `MutationProbability()`, `NeighborSize()`, `DistributionIndex()`, +`PopulationSize()`, `MaxGenerations()`, `CrossoverRate()`, `NeighborSize()`, `DistributionIndex()`, `NeighborProb()`, `DifferentialWeight()`, `MaxReplace()`, `LowerBound()` and `UpperBound()`. #### Examples: @@ -1607,7 +1605,7 @@ Attributes of the optimizer may also be changed via the member methods SchafferFunctionN1 SCH; arma::vec lowerBound("-1000 -1000"); arma::vec upperBound("1000 1000"); -MOEAD opt(1000, 0.5, 0.5, 1e-3, 50, lowerBound, upperBound); +MOEAD opt(150, 1000, 1.0, 20, 20, 0.9, 0.5, 2, lowerBound, upperBound); typedef decltype(SCH.objectiveA) ObjectiveTypeA; typedef decltype(SCH.objectiveB) ObjectiveTypeB; arma::mat coords = SCH.GetInitialPoint(); @@ -1620,7 +1618,7 @@ std::vector bestFront = opt.Front(); #### See also -* [MOEA/D Algorithm](https://www.researchgate.net/publication/3418989_MOEAD_A_Multiobjective_Evolutionary_Algorithm_Based_on_Decomposition/link/0912f50c77bae013b5000000/download) +* [MOEA/D-DE Algorithm](https://ieeexplore.ieee.org/document/4633340) * [Multi-objective Functions in Wikipedia](https://en.wikipedia.org/wiki/Test_functions_for_optimization#Test_functions_for_multi-objective_optimization) * [Multi-objective functions](#multi-objective-functions) From 73ef983352b520d47b677179cac5fa71d51ebfd8 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sun, 14 Mar 2021 12:46:45 +0530 Subject: [PATCH 054/128] maxreplace is always positive --- include/ensmallen_bits/moead/moead_impl.hpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index a1cee5e9c..198f8aef3 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -126,13 +126,6 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple + std::to_string(neighborProb) + " was detected."); } - if(maxReplace < 0) - { - throw std::invalid_argument( - "maxReplace should be positive, however " - + std::to_string(maxReplace) + " was detected."); - } - // Check if lower bound is a vector of a single dimension. if (lowerBound.n_rows == 1) lowerBound = lowerBound(0, 0) * arma::ones(iterate.n_rows, iterate.n_cols); From f38f6a1d44e22e75577b0e206831ce1674ec9b07 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sun, 14 Mar 2021 12:55:58 +0530 Subject: [PATCH 055/128] modify test a bit --- include/ensmallen_bits/problems/fonseca_fleming_function.hpp | 4 ++-- include/ensmallen_bits/problems/schaffer_function_n1.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/ensmallen_bits/problems/fonseca_fleming_function.hpp b/include/ensmallen_bits/problems/fonseca_fleming_function.hpp index 71b809a27..6fad15031 100644 --- a/include/ensmallen_bits/problems/fonseca_fleming_function.hpp +++ b/include/ensmallen_bits/problems/fonseca_fleming_function.hpp @@ -80,10 +80,10 @@ class FonsecaFlemingFunction -pow(static_cast(coords[2]) - 1.0 / sqrt(3.0), 2.0) ); } - arma::uvec Shuffle(size_t& populationSize) + arma::uvec Shuffle(const size_t& populationSize) { return arma::shuffle(arma::linspace( - 0, populationSize - 1, populationSize)); + 0, populationSize - 1, populationSize)); } } objectiveA; diff --git a/include/ensmallen_bits/problems/schaffer_function_n1.hpp b/include/ensmallen_bits/problems/schaffer_function_n1.hpp index 50cdaa7ce..7df7e212f 100644 --- a/include/ensmallen_bits/problems/schaffer_function_n1.hpp +++ b/include/ensmallen_bits/problems/schaffer_function_n1.hpp @@ -75,10 +75,10 @@ class SchafferFunctionN1 { return std::pow(coords[0], 2); } - arma::uvec Shuffle(size_t& populationSize) + arma::uvec Shuffle(const size_t& populationSize) { return arma::shuffle(arma::linspace( - 0, populationSize - 1, populationSize)); + 0, populationSize - 1, populationSize)); } } objectiveA; From a95c0e647a3a2668ba72c1cfdf108480de607c53 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Mon, 15 Mar 2021 23:53:17 +0530 Subject: [PATCH 056/128] Remove shuffle from problems --- include/ensmallen_bits/moead/moead_impl.hpp | 6 ++++-- .../ensmallen_bits/problems/fonseca_fleming_function.hpp | 5 ----- include/ensmallen_bits/problems/schaffer_function_n1.hpp | 5 ----- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 198f8aef3..1ba7ec5b7 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -228,7 +228,8 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // 2 The main loop. for (size_t g = 0; g < maxGenerations; ++g) { - shuffle = std::get<0>(objectives).Shuffle(populationSize); + shuffle = arma::shuffle( + arma::linspace(0, populationSize - 1, populationSize)); for (size_t i : shuffle) { terminate |= Callback::StepTaken(*this, objectives, iterate, callbacks...); @@ -291,7 +292,8 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple size_t replaceCounter = 0; size_t sampleSize = sampleNeighbor ? neighborSize : populationSize; - arma::uvec idxShuffle = std::get<0>(objectives).Shuffle(sampleSize); + arma::uvec idxShuffle = arma::shuffle( + arma::linspace(0, sampleSize - 1, sampleSize)); for (size_t idx : idxShuffle) { diff --git a/include/ensmallen_bits/problems/fonseca_fleming_function.hpp b/include/ensmallen_bits/problems/fonseca_fleming_function.hpp index 6fad15031..34bc95b0f 100644 --- a/include/ensmallen_bits/problems/fonseca_fleming_function.hpp +++ b/include/ensmallen_bits/problems/fonseca_fleming_function.hpp @@ -80,11 +80,6 @@ class FonsecaFlemingFunction -pow(static_cast(coords[2]) - 1.0 / sqrt(3.0), 2.0) ); } - arma::uvec Shuffle(const size_t& populationSize) - { - return arma::shuffle(arma::linspace( - 0, populationSize - 1, populationSize)); - } } objectiveA; struct ObjectiveB diff --git a/include/ensmallen_bits/problems/schaffer_function_n1.hpp b/include/ensmallen_bits/problems/schaffer_function_n1.hpp index 7df7e212f..4c31974ea 100644 --- a/include/ensmallen_bits/problems/schaffer_function_n1.hpp +++ b/include/ensmallen_bits/problems/schaffer_function_n1.hpp @@ -75,11 +75,6 @@ class SchafferFunctionN1 { return std::pow(coords[0], 2); } - arma::uvec Shuffle(const size_t& populationSize) - { - return arma::shuffle(arma::linspace( - 0, populationSize - 1, populationSize)); - } } objectiveA; struct ObjectiveB From 8a52d9ab101258b2ed792cf9d2c047aef04c3086 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Tue, 16 Mar 2021 11:33:35 +0530 Subject: [PATCH 057/128] add callbacktest --- tests/callbacks_test.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/callbacks_test.cpp b/tests/callbacks_test.cpp index 90c1ddc0b..8dffc166a 100644 --- a/tests/callbacks_test.cpp +++ b/tests/callbacks_test.cpp @@ -387,6 +387,18 @@ TEST_CASE("KatyushaCallbacksFullFunctionTest", "[CallbacksTest]") false, false, true); } +/** + * Make sure we invoke all callbacks (MOEAD). + */ +TEST_CASE("MOEADCallbacksFullFunctionTest", "[CallbackTest]") +{ + arma::vec lowerBound = {-1000}; + arma::vec upperBound = {1000}; + MOEAD optimizer(150,1000, 1.0, 20, 20, 0.9, 0.5, 2, lowerBound, upperBound); + CallbacksFullMultiobjectiveFunctionTest(optimizer, false, false, false, false, + true, true, false, false, true); +} + /** * Make sure we invoke all callbacks (NSGA2). */ From 9c888154b08c85f19816df4b6eaecbe722deed0f Mon Sep 17 00:00:00 2001 From: NanuSai Date: Tue, 16 Mar 2021 11:37:13 +0530 Subject: [PATCH 058/128] fix bounds --- tests/callbacks_test.cpp | 4 ++-- tests/moead_test.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/callbacks_test.cpp b/tests/callbacks_test.cpp index 8dffc166a..ca7740379 100644 --- a/tests/callbacks_test.cpp +++ b/tests/callbacks_test.cpp @@ -392,8 +392,8 @@ TEST_CASE("KatyushaCallbacksFullFunctionTest", "[CallbacksTest]") */ TEST_CASE("MOEADCallbacksFullFunctionTest", "[CallbackTest]") { - arma::vec lowerBound = {-1000}; - arma::vec upperBound = {1000}; + arma::vec lowerBound = {-10}; + arma::vec upperBound = {10}; MOEAD optimizer(150,1000, 1.0, 20, 20, 0.9, 0.5, 2, lowerBound, upperBound); CallbacksFullMultiobjectiveFunctionTest(optimizer, false, false, false, false, true, true, false, false, true); diff --git a/tests/moead_test.cpp b/tests/moead_test.cpp index 49c9e9912..a78510da8 100644 --- a/tests/moead_test.cpp +++ b/tests/moead_test.cpp @@ -37,8 +37,8 @@ bool InBounds(const double& value, const double& low, const double& high) TEST_CASE("MOEADSchafferN1Test", "[MOEADTest]") { SchafferFunctionN1 SCH; - double lowerBound = -1000; - const double upperBound = 1000; + const double lowerBound = -10; + const double upperBound = 10; MOEAD opt( 150, // population size @@ -98,8 +98,8 @@ TEST_CASE("MOEADSchafferN1Test", "[MOEADTest]") TEST_CASE("MOEADSchafferN1VectorBoundsTest", "[MOEADTest]") { SchafferFunctionN1 SCH; - arma::vec lowerBound = {-1000}; - arma::vec upperBound = {1000}; + arma::vec lowerBound = {-10}; + arma::vec upperBound = {10}; MOEAD opt( 150, // population size From c602dc13869697007d51ddb515b0f8b43320b208 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Tue, 16 Mar 2021 11:39:23 +0530 Subject: [PATCH 059/128] bound fix in optimizer.MD --- doc/optimizers.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/optimizers.md b/doc/optimizers.md index c61a7fea3..07af3c83a 100644 --- a/doc/optimizers.md +++ b/doc/optimizers.md @@ -1603,8 +1603,8 @@ Attributes of the optimizer may also be changed via the member methods ```c++ SchafferFunctionN1 SCH; -arma::vec lowerBound("-1000 -1000"); -arma::vec upperBound("1000 1000"); +arma::vec lowerBound("-10 -10"); +arma::vec upperBound("10 10"); MOEAD opt(150, 1000, 1.0, 20, 20, 0.9, 0.5, 2, lowerBound, upperBound); typedef decltype(SCH.objectiveA) ObjectiveTypeA; typedef decltype(SCH.objectiveB) ObjectiveTypeB; From f516864104e943bbb75881f3307a32a465babb00 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Thu, 18 Mar 2021 01:07:46 +0530 Subject: [PATCH 060/128] arma::square --- include/ensmallen_bits/moead/moead_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 1ba7ec5b7..9d9180c92 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -187,7 +187,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // Cache the distance between weights(i) and other weights. arma::rowvec distances(populationSize); distances = - arma::sqrt(arma::sum(arma::pow(weights.col(i) - weights.each_col(), 2))); + arma::sqrt(arma::sum(arma::square(weights.col(i) - weights.each_col()))); arma::uvec sortedIndices = arma::stable_sort_index(distances); // Ignore distance from self neighborIndices.col(i) = sortedIndices(arma::span(1, neighborSize)); From 83e0850cc7be997e19bd3f0f51506652b2b9bb7b Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Thu, 18 Mar 2021 08:36:56 +0530 Subject: [PATCH 061/128] Update include/ensmallen_bits/moead/moead_impl.hpp Co-authored-by: Marcus Edel --- include/ensmallen_bits/moead/moead_impl.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 9d9180c92..599193a3e 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -73,7 +73,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple MatType& iterate, CallbackTypes&&... callbacks) { - // Sanity checks + // Sanity checks. if (populationSize < 3) { throw std::invalid_argument( @@ -450,4 +450,3 @@ MOEAD::EvaluateObjectives( } #endif - From faa94ab15bc3c1877b11aeb2884c13b75151fe36 Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Thu, 18 Mar 2021 08:37:04 +0530 Subject: [PATCH 062/128] Update include/ensmallen_bits/moead/moead_impl.hpp Co-authored-by: Marcus Edel --- include/ensmallen_bits/moead/moead_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 599193a3e..d449187c9 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -189,7 +189,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple distances = arma::sqrt(arma::sum(arma::square(weights.col(i) - weights.each_col()))); arma::uvec sortedIndices = arma::stable_sort_index(distances); - // Ignore distance from self + // Ignore distance from self. neighborIndices.col(i) = sortedIndices(arma::span(1, neighborSize)); } From c849873522c1ddb0ab529337c603cfcf5e1feff9 Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Thu, 18 Mar 2021 08:37:15 +0530 Subject: [PATCH 063/128] Update include/ensmallen_bits/moead/moead_impl.hpp Co-authored-by: Marcus Edel --- include/ensmallen_bits/moead/moead_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index d449187c9..30bb48264 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -241,7 +241,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple size_t r1, r2, r3; r1 = i; // Randomly choose to sample from the population or the neighbors. - bool sampleNeighbor = ( arma::randu() < neighborProb ); + bool sampleNeighbor = arma::randu() < neighborProb; std::tie(r2, r3) = MatingSelection(i, neighborIndices, sampleNeighbor); // 2.2 - 2.3 Reproduction and Repair: Differential Operator followed by From 9d7eec84b9e72cad9158d759eec0934ffa6a5c3e Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Thu, 18 Mar 2021 08:37:24 +0530 Subject: [PATCH 064/128] Update include/ensmallen_bits/moead/moead_impl.hpp Co-authored-by: Marcus Edel --- include/ensmallen_bits/moead/moead_impl.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 30bb48264..421ce9cb8 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -250,7 +250,6 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple double delta = arma::randu(); for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) { - if (delta < crossoverProb) { candidate[geneIdx] = population[r1][geneIdx] + From bfde39de2f326377246cff7bc3f8979ec09fe55f Mon Sep 17 00:00:00 2001 From: NanuSai Date: Thu, 18 Mar 2021 09:05:19 +0530 Subject: [PATCH 065/128] tab v space --- include/ensmallen_bits/moead/moead.hpp | 7 ++-- include/ensmallen_bits/moead/moead_impl.hpp | 36 ++++++++++----------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 93fa7d352..21d446953 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -197,10 +197,9 @@ class MOEAD { * @param neighborSize A matrix containing indices of the neighbors. * @return std::tuple The chosen pair of indices. */ - std::tuple - MatingSelection(const size_t subProblemIdx, - const arma::umat& neighborSize, - bool sampleNeighbor); + std::tuple MatingSelection(const size_t subProblemIdx, + const arma::umat& neighborSize, + bool sampleNeighbor); /** * Mutate the child formed by the crossover of two random members of the diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 421ce9cb8..7c12bd50b 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -202,10 +202,10 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) { - if (population[i][geneIdx] < lowerBound[geneIdx]) - population[i][geneIdx] = lowerBound[geneIdx]; - else if (population[i][geneIdx] > upperBound[geneIdx]) - population[i][geneIdx] = upperBound[geneIdx]; + if (population[i][geneIdx] < lowerBound[geneIdx]) + population[i][geneIdx] = lowerBound[geneIdx]; + else if (population[i][geneIdx] > upperBound[geneIdx]) + population[i][geneIdx] = upperBound[geneIdx]; } } @@ -254,20 +254,18 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple { candidate[geneIdx] = population[r1][geneIdx] + differentialWeight * (population[r2][geneIdx] - - population[r3][geneIdx]); + population[r3][geneIdx]); // Boundary conditions. if (candidate[geneIdx] < lowerBound[geneIdx]) { candidate[geneIdx] = lowerBound[geneIdx] + - arma::randu() * (population[r1][geneIdx] - - lowerBound[geneIdx]); + arma::randu() * (population[r1][geneIdx] - lowerBound[geneIdx]); } if (candidate[geneIdx] > upperBound[geneIdx]) { candidate[geneIdx] = upperBound[geneIdx] - - arma::randu() * (upperBound[geneIdx] - - population[r1][geneIdx]); + arma::randu() * (upperBound[geneIdx] - population[r1][geneIdx]); } } @@ -275,7 +273,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple candidate[geneIdx] = population[r1][geneIdx]; } - Mutate(candidate, 1.0 / static_cast(numVariables), lowerBound, upperBound); + Mutate(candidate, 1.0 / static_cast(numVariables), lowerBound, upperBound); arma::vec candidateFitness(numObjectives); EvaluateObjectives(std::vector{candidate}, objectives, candidateFitness); @@ -301,10 +299,10 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple size_t pick = sampleNeighbor ? neighborIndices(idx, i) : idx; - double candidateDecomposition = DecomposeObjectives( - weights.col(pick), idealPoint, candidateFitness); - double parentDecomposition = DecomposeObjectives( - weights.col(pick), idealPoint, populationFitness.col(pick)); + double candidateDecomposition = DecomposeObjectives( + weights.col(pick), idealPoint, candidateFitness); + double parentDecomposition = DecomposeObjectives( + weights.col(pick), idealPoint, populationFitness.col(pick)); if (candidateDecomposition < parentDecomposition) { @@ -351,12 +349,12 @@ MOEAD::MatingSelection( : arma::randi(arma::distr_param(0, populationSize - 1u)); if (k == l) - { - if (k == populationSize - 1u) - --k; + { + if (k == populationSize - 1u) + --k; else - ++k; - } + ++k; + } return std::make_tuple(k, l); } From 47c981ec3a9daa2b4f5a622e71b68e3f1ffcc332 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Thu, 18 Mar 2021 09:25:05 +0530 Subject: [PATCH 066/128] fix indendations pt2 --- include/ensmallen_bits/moead/moead_impl.hpp | 24 ++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 7c12bd50b..4cd27f4a5 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -197,16 +197,16 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple std::vector population(populationSize); for (size_t i = 0; i < populationSize; ++i) { - population[i] = - arma::randu(iterate.n_rows, iterate.n_cols) - 0.5 + iterate; + population[i] = + arma::randu(iterate.n_rows, iterate.n_cols) - 0.5 + iterate; - for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) - { - if (population[i][geneIdx] < lowerBound[geneIdx]) + for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) + { + if (population[i][geneIdx] < lowerBound[geneIdx]) population[i][geneIdx] = lowerBound[geneIdx]; else if (population[i][geneIdx] > upperBound[geneIdx]) population[i][geneIdx] = upperBound[geneIdx]; - } + } } arma::mat populationFitness(numObjectives, populationSize); @@ -339,14 +339,14 @@ MOEAD::MatingSelection( size_t k, l; k = sampleNeighbor - ? neighborIndices( - arma::randi(arma::distr_param(0, neighborSize - 1u)), subProblemIdx) - : arma::randi(arma::distr_param(0, populationSize - 1u)); + ? neighborIndices( + arma::randi(arma::distr_param(0, neighborSize - 1u)), subProblemIdx) + : arma::randi(arma::distr_param(0, populationSize - 1u)); l = sampleNeighbor - ? neighborIndices( - arma::randi(arma::distr_param(0, neighborSize - 1u)), subProblemIdx) - : arma::randi(arma::distr_param(0, populationSize - 1u)); + ? neighborIndices( + arma::randi(arma::distr_param(0, neighborSize - 1u)), subProblemIdx) + : arma::randi(arma::distr_param(0, populationSize - 1u)); if (k == l) { From e515851b405196946d7cb3cc33baafd02da75a54 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Thu, 18 Mar 2021 09:44:50 +0530 Subject: [PATCH 067/128] author fix impl test comments fixed. --- include/ensmallen_bits/moead/moead_impl.hpp | 5 +- tests/moead_test.cpp | 80 ++++++++++----------- 2 files changed, 43 insertions(+), 42 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 4cd27f4a5..6a9cc26df 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -1,6 +1,7 @@ /** * @file moead_impl.hpp - * @authors Utkarsh Rai, Nanubala Gnana Sai + * @author Utkarsh Rai + * @author Nanubala Gnana Sai * * Implementation of the MOEA/D-DE algorithm. Used for multi-objective * optimization problems on arbitrary functions. @@ -242,7 +243,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple r1 = i; // Randomly choose to sample from the population or the neighbors. bool sampleNeighbor = arma::randu() < neighborProb; - std::tie(r2, r3) = MatingSelection(i, neighborIndices, sampleNeighbor); + std::tie(r2, r3) = MatingSelection(i, neighborIndices, sampleNeighbor); // 2.2 - 2.3 Reproduction and Repair: Differential Operator followed by // Mutation. diff --git a/tests/moead_test.cpp b/tests/moead_test.cpp index a78510da8..c87a51fa6 100644 --- a/tests/moead_test.cpp +++ b/tests/moead_test.cpp @@ -41,16 +41,16 @@ TEST_CASE("MOEADSchafferN1Test", "[MOEADTest]") const double upperBound = 10; MOEAD opt( - 150, // population size - 1000, // max generations - 1.0, // crossover prob - 20, //neighbor size - 20, //distribution index - 0.9, //neighbor prob - 0.5, //differential weight - 2, //maxreplace, - lowerBound, //lower bound - upperBound //upper bound + 150, // Population size. + 1000, // Max generations. + 1.0, // Crossover probability. + 20, // Neighborhood size. + 20, // Distribution index. + 0.9, // Probability of sampling from neighbor. + 0.5, // Differential weight. + 2, // Max childrens to replace parents. + lowerBound, // Lower bound. + upperBound // Upper bound. ); typedef decltype(SCH.objectiveA) ObjectiveTypeA; @@ -102,16 +102,16 @@ TEST_CASE("MOEADSchafferN1VectorBoundsTest", "[MOEADTest]") arma::vec upperBound = {10}; MOEAD opt( - 150, // population size - 1000, // max generations - 1.0, // crossover prob - 20, //neighbor size - 20, //distribution index - 0.9, //neighbor prob - 0.5, //differential weight - 2, //maxreplace, - lowerBound, //lower bound - upperBound //upper bound + 150, // Population size. + 1000, // Max generations. + 1.0, // Crossover probability. + 20, // Neighborhood size. + 20, // Distribution index. + 0.9, // Probability of sampling from neighbor. + 0.5, // Differential weight. + 2, // Max childrens to replace parents. + lowerBound, // Lower bound. + upperBound // Upper bound. ); typedef decltype(SCH.objectiveA) ObjectiveTypeA; @@ -161,16 +161,16 @@ TEST_CASE("MOEADFonsecaFlemingTest", "[MOEADTest]") const double expectedUpperBound = 1.0 / sqrt(3); MOEAD opt( - 150, // population size - 1000, // max generations - 1.0, // crossover prob - 20, //neighbor size - 20, //distribution index - 0.9, //neighbor prob - 0.5, //differential weight - 2, //maxreplace, - lowerBound, //lower bound - upperBound //upper bound + 150, // Population size. + 1000, // Max generations. + 1.0, // Crossover probability. + 20, // Neighborhood size. + 20, // Distribution index. + 0.9, // Probability of sampling from neighbor. + 0.5, // Differential weight. + 2, // Max childrens to replace parents. + lowerBound, // Lower bound. + upperBound // Upper bound. ); typedef decltype(FON.objectiveA) ObjectiveTypeA; @@ -211,16 +211,16 @@ TEST_CASE("MOEADFonsecaFlemingVectorBoundsTest", "[MOEADTest]") const double expectedUpperBound = 1.0 / sqrt(3); MOEAD opt( - 150, // population size - 1000, // max generations - 1.0, // crossover prob - 20, //neighbor size - 20, //distribution index - 0.9, //neighbor prob - 0.5, //differential weight - 2, //maxreplace, - lowerBound, //lower bound - upperBound //upper bound + 150, // Population size. + 1000, // Max generations. + 1.0, // Crossover probability. + 20, // Neighborhood size. + 20, // Distribution index. + 0.9, // Probability of sampling from neighbor. + 0.5, // Differential weight. + 2, // Max childrens to replace parents. + lowerBound, // Lower bound. + upperBound // Upper bound. ); typedef decltype(FON.objectiveA) ObjectiveTypeA; From 2ce3bd3d140fc22051099fdb3711dd027871a98b Mon Sep 17 00:00:00 2001 From: NanuSai Date: Thu, 18 Mar 2021 14:39:25 +0530 Subject: [PATCH 068/128] tab v space pt3 --- include/ensmallen_bits/moead/moead.hpp | 8 ++++---- tests/moead_test.cpp | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 21d446953..370b73db1 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -243,16 +243,16 @@ class MOEAD { typename ...ArbitraryFunctionType> typename std::enable_if::type EvaluateObjectives(const std::vector&, - std::tuple&, - arma::mat&); + std::tuple&, + arma::mat&); template typename std::enable_if::type EvaluateObjectives(const std::vector& population, - std::tuple& objectives, - arma::mat& calculatedObjectives); + std::tuple& objectives, + arma::mat& calculatedObjectives); //! Size of the population. size_t populationSize; diff --git a/tests/moead_test.cpp b/tests/moead_test.cpp index c87a51fa6..ee5f0750f 100644 --- a/tests/moead_test.cpp +++ b/tests/moead_test.cpp @@ -1,7 +1,9 @@ /** * @file moead_test.cpp - * @authors Sayan Goswami, Utkarsh Rai, Nanubala Gnana Sai + * @author Sayan Goswami + * @author Utkarsh Rai + * @author Nanubala Gnana Sai * * ensmallen is free software; you may redistribute it and/or modify it under * the terms of the 3-clause BSD license. You should have received a copy of From 1149301fa59405c9cd3f886ea42c3fb1bb2f6623 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Tue, 8 Jun 2021 10:29:43 +0530 Subject: [PATCH 069/128] use ParetoSet & ParetoFront in declaration file --- include/ensmallen_bits/moead/moead.hpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 370b73db1..dd10faef2 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -185,9 +185,14 @@ class MOEAD { //! Modify value of upperBound. arma::vec& UpperBound() { return upperBound; } - //! Retrieve the best front (the Pareto frontier). This returns an empty - //! vector until `Optimize()` has been called. - const std::vector& Front() const { return bestFront; } + //! Retrieve the Pareto optimal points in variable space. This returns an empty cube + //! until `Optimize()` has been called. + const arma::cube& ParetoSet() const { return paretoSet; } + + //! Retrieve the best front (the Pareto frontier). This returns an empty cube until + //! `Optimize()` has been called. + const arma::cube& ParetoFront() const { return paretoFront; } + private: /** @@ -289,8 +294,13 @@ class MOEAD { //! The number of objectives in multi objective optimisation problem. size_t numObjectives; - //! The Pareto Optimal Front. - std::vector bestFront; + //! The set of all the Pareto optimal points. + //! Stored after Optimize() is called. + arma::cube paretoSet; + + //! The set of all the Pareto optimal objective vectors. + //! Stored after Optimize() is called. + arma::cube paretoFront; }; } // namespace ens From 391e164fb700ae528b3d158acf00feb795204b2f Mon Sep 17 00:00:00 2001 From: NanuSai Date: Tue, 8 Jun 2021 19:47:58 +0530 Subject: [PATCH 070/128] moead_impl.hpp => Use BaseMatType => Remove redundant checks --- include/ensmallen_bits/moead/moead_impl.hpp | 91 +++++---------------- 1 file changed, 20 insertions(+), 71 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 6a9cc26df..95ae786ca 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -71,23 +71,21 @@ template typename MatType::elem_type MOEAD::Optimize(std::tuple& objectives, - MatType& iterate, + MatType& iterateIn, CallbackTypes&&... callbacks) { - // Sanity checks. + // Population Size must be at least 3 for MOEA/D-DE to work. if (populationSize < 3) { - throw std::invalid_argument( - "populationSize should be atleast 3 however " - + std::to_string(populationSize) + " was detected."); + throw std::logic_error("MOEA/D-DE::Optimize(): population size should be at least" + " 3!"); } - if (crossoverProb > 1.0 || crossoverProb < 0.0) - { - throw std::invalid_argument( - "The parameter crossoverProb needs to be in [0,1], however " - + std::to_string(crossoverProb) + " was detected."); - } + // Convenience typedefs. + typedef typename MatType::elem_type ElemType; + typedef typename MatTypeTraits::BaseMatType BaseMatType; + + BaseMatType& iterate = (BaseMatType&) iterateIn; if (neighborSize < 2) { @@ -106,27 +104,6 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple throw std::logic_error(oss.str()); } - if (distributionIndex < 0) - { - throw std::invalid_argument( - "distributionIndex should be positive, however " - + std::to_string(distributionIndex) + " was detected."); - } - - if (differentialWeight > 1.0 || differentialWeight < 0.0) - { - throw std::invalid_argument( - "The parameter differentialWeight needs to be in [0,1], however " - + std::to_string(differentialWeight) + " was detected."); - } - - if (neighborProb > 1.0 || neighborProb < 0.0) - { - throw std::invalid_argument( - "The parameter neighborProb needs to be in [0,1], however " - + std::to_string(neighborProb) + " was detected."); - } - // Check if lower bound is a vector of a single dimension. if (lowerBound.n_rows == 1) lowerBound = lowerBound(0, 0) * arma::ones(iterate.n_rows, iterate.n_cols); @@ -135,45 +112,17 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple if (upperBound.n_rows == 1) upperBound = upperBound(0, 0) * arma::ones(iterate.n_rows, iterate.n_cols); - // Convenience typedefs. - typedef typename MatType::elem_type ElemType; + // Check the dimensions of lowerBound and upperBound. + assert(lowerBound.n_rows == iterate.n_rows && "The dimensions of " + "lowerBound are not the same as the dimensions of iterate."); + assert(upperBound.n_rows == iterate.n_rows && "The dimensions of " + "upperBound are not the same as the dimensions of iterate."); // Number of objective functions. Represented by M in the paper. numObjectives = sizeof...(ArbitraryFunctionType); // Dimensionality of variable space. Also referred to as number of genes. size_t numVariables = iterate.n_rows; - if (numObjectives < 2u) - { - throw std::logic_error("MOEAD::Optimize(): This is a multiobjective problem, " - "numObjectives must be atleast 2."); - } - - if (lowerBound.size() != upperBound.size()) - { - throw std::logic_error("MOEAD::Optimize(): size of lowerBound and upperBound " - "must be equal."); - } - - if (lowerBound.size() != iterate.n_elem) - { - throw std::logic_error("MOEAD::Optimize(): there should be a lower bound and " - "an upper bound for each variable in the initial point."); - } - - for (size_t geneIdx = 0; geneIdx < lowerBound.size(); geneIdx++) - { - if (lowerBound[geneIdx] >= upperBound[geneIdx]) - { - std::ostringstream ss; - ss << "MOEAD::Optimize():" << "the lowerBound value: " << lowerBound[geneIdx] - << " is greater than upperBound value: " << upperBound[geneIdx] - << " at index: " << geneIdx << std::endl; - - throw std::logic_error(ss.str()); - } - } - bool terminate = false; arma::uvec shuffle; @@ -195,11 +144,11 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple } // 1.2 Random generation of the initial population. - std::vector population(populationSize); + std::vector population(populationSize); for (size_t i = 0; i < populationSize; ++i) { population[i] = - arma::randu(iterate.n_rows, iterate.n_cols) - 0.5 + iterate; + arma::randu(iterate.n_rows, iterate.n_cols) - 0.5 + iterate; for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) { @@ -210,6 +159,8 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple } } + Info << "MOEA/D-DE initialized successfully. Optimization started." << std::endl; + arma::mat populationFitness(numObjectives, populationSize); EvaluateObjectives(population, objectives, populationFitness); @@ -235,8 +186,6 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple { terminate |= Callback::StepTaken(*this, objectives, iterate, callbacks...); - Info << "MOEA/D-DE initialized successfully. Optimization started." << std::endl; - // 2.1 Randomly select two indices in neighborIndices(i) and use them // to make a child. size_t r1, r2, r3; @@ -247,7 +196,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // 2.2 - 2.3 Reproduction and Repair: Differential Operator followed by // Mutation. - MatType candidate(iterate.n_rows, iterate.n_cols); + BaseMatType candidate(iterate.n_rows, iterate.n_cols); double delta = arma::randu(); for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) { @@ -277,7 +226,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple Mutate(candidate, 1.0 / static_cast(numVariables), lowerBound, upperBound); arma::vec candidateFitness(numObjectives); - EvaluateObjectives(std::vector{candidate}, objectives, candidateFitness); + EvaluateObjectives(std::vector{candidate}, objectives, candidateFitness); // 2.4 Update of ideal point. for (size_t idx = 0; idx < numObjectives; ++idx) From e086bf2bd05a2bb9df318b69ac552398da3405e1 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Tue, 8 Jun 2021 19:58:29 +0530 Subject: [PATCH 071/128] Doc fix --- include/ensmallen_bits/moead/moead_impl.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 95ae786ca..95ebb56b0 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -118,11 +118,10 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple assert(upperBound.n_rows == iterate.n_rows && "The dimensions of " "upperBound are not the same as the dimensions of iterate."); - // Number of objective functions. Represented by M in the paper. numObjectives = sizeof...(ArbitraryFunctionType); - // Dimensionality of variable space. Also referred to as number of genes. size_t numVariables = iterate.n_rows; + // Controls early termination of the optimization process. bool terminate = false; arma::uvec shuffle; @@ -130,7 +129,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple arma::Mat weights(numObjectives, populationSize, arma::fill::randu); weights += 1E-10; // Numerical stability - // 1.2 Storing the indices of nearest neighbors of each weight vector. + // 1.1 Storing the indices of nearest neighbors of each weight vector. arma::umat neighborIndices(neighborSize, populationSize); for (size_t i = 0; i < populationSize; ++i) { @@ -150,12 +149,13 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple population[i] = arma::randu(iterate.n_rows, iterate.n_cols) - 0.5 + iterate; + // Constrain all genes to be between bounds. for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) { - if (population[i][geneIdx] < lowerBound[geneIdx]) - population[i][geneIdx] = lowerBound[geneIdx]; - else if (population[i][geneIdx] > upperBound[geneIdx]) - population[i][geneIdx] = upperBound[geneIdx]; + if (population[i](geneIdx) < lowerBound(geneIdx)) + population[i](geneIdx) = lowerBound(geneIdx); + else if (population[i](geneIdx) > upperBound(geneIdx)) + population[i](geneIdx) = upperBound(geneIdx); } } From 410eb50fd27b0ff8d2d6aecf52a726321c3ff509 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Tue, 8 Jun 2021 20:19:32 +0530 Subject: [PATCH 072/128] Maintain EvaluateObjectives of NSGA-II --- include/ensmallen_bits/moead/moead.hpp | 9 ++++--- include/ensmallen_bits/moead/moead_impl.hpp | 30 ++++++++++----------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index dd10faef2..4d58fdf1f 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -247,17 +247,18 @@ class MOEAD { typename MatType, typename ...ArbitraryFunctionType> typename std::enable_if::type - EvaluateObjectives(const std::vector&, + EvaluateObjectives(std::vector&, std::tuple&, - arma::mat&); + std::vector >&); template typename std::enable_if::type - EvaluateObjectives(const std::vector& population, + EvaluateObjectives(std::vector& population, std::tuple& objectives, - arma::mat& calculatedObjectives); + std::vector >& + calculatedObjectives); //! Size of the population. size_t populationSize; diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 95ebb56b0..f5e6ed6a9 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -161,7 +161,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple Info << "MOEA/D-DE initialized successfully. Optimization started." << std::endl; - arma::mat populationFitness(numObjectives, populationSize); + std::vector> populationFitness(numObjectives, populationSize); EvaluateObjectives(population, objectives, populationFitness); // 1.3 Initialize the ideal point z. @@ -366,32 +366,32 @@ inline double MOEAD::DecomposeObjectives(const arma::vec& weights, //! No objectives to evaluate. template - typename std::enable_if::type + typename MatType, + typename ...ArbitraryFunctionType> +typename std::enable_if::type MOEAD::EvaluateObjectives( - const std::vector&, + std::vector&, std::tuple&, - arma::mat &) + std::vector >&) { // Nothing to do here. } //! Evaluate the objectives for the entire population. template - typename std::enable_if::type + typename MatType, + typename ...ArbitraryFunctionType> +typename std::enable_if::type MOEAD::EvaluateObjectives( - const std::vector& population, + std::vector& population, std::tuple& objectives, - arma::mat& calculatedObjectives) + std::vector >& calculatedObjectives) { - for (size_t i = 0; i < population.size(); ++i) + for (size_t i = 0; i < populationSize; i++) { - calculatedObjectives(I, i) = std::get(objectives).Evaluate(population[i]); - EvaluateObjectives(population, objectives, - calculatedObjectives); + calculatedObjectives[i](I) = std::get(objectives).Evaluate(population[i]); + EvaluateObjectives(population, objectives, + calculatedObjectives); } } } From 6703d070016c0e7693a6e1185aa31bdaded2fbfd Mon Sep 17 00:00:00 2001 From: NanuSai Date: Tue, 8 Jun 2021 20:22:22 +0530 Subject: [PATCH 073/128] Tab fix Remove const ref for primitive --- include/ensmallen_bits/moead/moead.hpp | 4 ++-- include/ensmallen_bits/moead/moead_impl.hpp | 17 ++++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 4d58fdf1f..c33a7a043 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -202,7 +202,7 @@ class MOEAD { * @param neighborSize A matrix containing indices of the neighbors. * @return std::tuple The chosen pair of indices. */ - std::tuple MatingSelection(const size_t subProblemIdx, + std::tuple MatingSelection(size_t subProblemIdx, const arma::umat& neighborSize, bool sampleNeighbor); @@ -218,7 +218,7 @@ class MOEAD { */ template void Mutate(MatType& child, - const double& mutationRate, + double mutationRate, const arma::vec& lowerBound, const arma::vec& upperBound); diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index f5e6ed6a9..e615ddbf2 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -281,10 +281,9 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple //! Randomly chooses to select from parents or neighbors. inline std::tuple -MOEAD::MatingSelection( - const size_t subProblemIdx, - const arma::umat& neighborIndices, - bool sampleNeighbor) +MOEAD::MatingSelection(size_t subProblemIdx, + const arma::umat& neighborIndices, + bool sampleNeighbor) { size_t k, l; @@ -312,9 +311,9 @@ MOEAD::MatingSelection( //! Perform Polynomial mutation of the candidate. template inline void MOEAD::Mutate(MatType& child, - const double& mutationRate, - const arma::vec& lowerBound, - const arma::vec& upperBound) + double mutationRate, + const arma::vec& lowerBound, + const arma::vec& upperBound) { size_t numVariables = lowerBound.n_elem; double rnd, delta1, delta2, mutationPower, deltaq; @@ -358,8 +357,8 @@ inline void MOEAD::Mutate(MatType& child, //! Calculate the output for single objective function using the Tchebycheff //! approach. inline double MOEAD::DecomposeObjectives(const arma::vec& weights, - const arma::vec& idealPoint, - const arma::vec& candidateFitness) + const arma::vec& idealPoint, + const arma::vec& candidateFitness) { return arma::max(weights % arma::abs(candidateFitness - idealPoint)); } From a44da082b2376d8d458670234207697f4b62e0cd Mon Sep 17 00:00:00 2001 From: NanuSai Date: Tue, 8 Jun 2021 20:23:52 +0530 Subject: [PATCH 074/128] rm StepTaken --- include/ensmallen_bits/moead/moead_impl.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index e615ddbf2..28a6d66be 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -184,8 +184,6 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple arma::linspace(0, populationSize - 1, populationSize)); for (size_t i : shuffle) { - terminate |= Callback::StepTaken(*this, objectives, iterate, callbacks...); - // 2.1 Randomly select two indices in neighborIndices(i) and use them // to make a child. size_t r1, r2, r3; From 57c8d70a024782304f0b0bb918fa2148a146af62 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Tue, 8 Jun 2021 20:30:58 +0530 Subject: [PATCH 075/128] ideal point uses ElemType --- include/ensmallen_bits/moead/moead_impl.hpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 28a6d66be..555680e99 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -161,17 +161,19 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple Info << "MOEA/D-DE initialized successfully. Optimization started." << std::endl; - std::vector> populationFitness(numObjectives, populationSize); + std::vector> populationFitness; + populationFitness.resize(populationSize); + EvaluateObjectives(population, objectives, populationFitness); // 1.3 Initialize the ideal point z. - arma::vec idealPoint(numObjectives); - idealPoint.fill(std::numeric_limits::max()); - for (size_t i = 0; i < numObjectives; ++i) + arma::Col idealPoint(numObjectives); + idealPoint.fill(std::numeric_limits::max()); + for (size_t objectiveIdx = 0; objectiveIdx < numObjectives; ++objectiveIdx) { - for (size_t j = 0; j < populationSize; ++j) + for (size_t popIdx = 0; j < popIdx; ++popIdx) { - idealPoint(i) = std::min(idealPoint(i), populationFitness(i, j)); + idealPoint(objectiveIdx) = std::min(idealPoint(objectiveIdx), populationFitness[popIdx](objectiveIdx)); } } From 80a2f851b6e9a610a58e2e737f6bb997a43facc3 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Tue, 8 Jun 2021 20:32:17 +0530 Subject: [PATCH 076/128] g => generation: main loop --- include/ensmallen_bits/moead/moead_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 555680e99..127ced21c 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -180,7 +180,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple terminate |= Callback::BeginOptimization(*this, objectives, iterate, callbacks...); // 2 The main loop. - for (size_t g = 0; g < maxGenerations; ++g) + for (size_t generation = 1; generation <= maxGenerations && !terminate; ++generation) { shuffle = arma::shuffle( arma::linspace(0, populationSize - 1, populationSize)); From b4f862d73f01e493a9b1d8ddcd027d17fab3a227 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Tue, 8 Jun 2021 20:48:28 +0530 Subject: [PATCH 077/128] ] => ) --- include/ensmallen_bits/moead/moead_impl.hpp | 27 +++++++++++---------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 127ced21c..20152ba46 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -202,31 +202,32 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple { if (delta < crossoverProb) { - candidate[geneIdx] = population[r1][geneIdx] + - differentialWeight * (population[r2][geneIdx] - - population[r3][geneIdx]); + candidate(geneIdx) = population[r1](geneIdx) + + differentialWeight * (population[r2](geneIdx) - + population[r3](geneIdx)); // Boundary conditions. - if (candidate[geneIdx] < lowerBound[geneIdx]) + if (candidate(geneIdx) < lowerBound(geneIdx)) { - candidate[geneIdx] = lowerBound[geneIdx] + - arma::randu() * (population[r1][geneIdx] - lowerBound[geneIdx]); + candidate(geneIdx) = lowerBound(geneIdx) + + arma::randu() * (population[r1](geneIdx) - lowerBound(geneIdx)); } - if (candidate[geneIdx] > upperBound[geneIdx]) + if (candidate(geneIdx) > upperBound(geneIdx)) { - candidate[geneIdx] = upperBound[geneIdx] - - arma::randu() * (upperBound[geneIdx] - population[r1][geneIdx]); + candidate(geneIdx) = upperBound(geneIdx) - + arma::randu() * (upperBound(geneIdx) - population[r1](geneIdx)); } } else - candidate[geneIdx] = population[r1][geneIdx]; + candidate(geneIdx) = population[r1](geneIdx); } Mutate(candidate, 1.0 / static_cast(numVariables), lowerBound, upperBound); - arma::vec candidateFitness(numObjectives); - EvaluateObjectives(std::vector{candidate}, objectives, candidateFitness); + arma::Col candidateFitness(numObjectives); + EvaluateObjectives(std::vector{candidate}, objectives, + std::vector{candidateFitness}); // 2.4 Update of ideal point. for (size_t idx = 0; idx < numObjectives; ++idx) @@ -257,7 +258,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple if (candidateDecomposition < parentDecomposition) { population[pick] = candidate; - populationFitness.col(pick) = candidateFitness; + populationFitness[pick] = candidateFitness; replaceCounter++; } } From efa5a2efbd597da5ec2fff6014495daa989d6ac0 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Tue, 8 Jun 2021 21:29:16 +0530 Subject: [PATCH 078/128] Additional docs remove callback tests --- include/ensmallen_bits/moead/moead_impl.hpp | 12 ++++++------ tests/callbacks_test.cpp | 12 ------------ 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 20152ba46..e986f0202 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -125,7 +125,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple bool terminate = false; arma::uvec shuffle; - // The weight matrix. Each vector represents a decomposition subproblem. + // The weight matrix. Each vector represents a decomposition subproblem (M X N). arma::Mat weights(numObjectives, populationSize, arma::fill::randu); weights += 1E-10; // Numerical stability @@ -184,15 +184,15 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple { shuffle = arma::shuffle( arma::linspace(0, populationSize - 1, populationSize)); - for (size_t i : shuffle) + for (size_t subProblemIdx : shuffle) { - // 2.1 Randomly select two indices in neighborIndices(i) and use them + // 2.1 Randomly select two indices in neighborIndices(subProblemIdx) and use them // to make a child. size_t r1, r2, r3; - r1 = i; + r1 = subProblemIdx; // Randomly choose to sample from the population or the neighbors. bool sampleNeighbor = arma::randu() < neighborProb; - std::tie(r2, r3) = MatingSelection(i, neighborIndices, sampleNeighbor); + std::tie(r2, r3) = MatingSelection(subProblemIdx, neighborIndices, sampleNeighbor); // 2.2 - 2.3 Reproduction and Repair: Differential Operator followed by // Mutation. @@ -248,7 +248,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple if (replaceCounter >= maxReplace) break; - size_t pick = sampleNeighbor ? neighborIndices(idx, i) : idx; + size_t pick = sampleNeighbor ? neighborIndices(idx, subProblemIdx) : idx; double candidateDecomposition = DecomposeObjectives( weights.col(pick), idealPoint, candidateFitness); diff --git a/tests/callbacks_test.cpp b/tests/callbacks_test.cpp index ca7740379..90c1ddc0b 100644 --- a/tests/callbacks_test.cpp +++ b/tests/callbacks_test.cpp @@ -387,18 +387,6 @@ TEST_CASE("KatyushaCallbacksFullFunctionTest", "[CallbacksTest]") false, false, true); } -/** - * Make sure we invoke all callbacks (MOEAD). - */ -TEST_CASE("MOEADCallbacksFullFunctionTest", "[CallbackTest]") -{ - arma::vec lowerBound = {-10}; - arma::vec upperBound = {10}; - MOEAD optimizer(150,1000, 1.0, 20, 20, 0.9, 0.5, 2, lowerBound, upperBound); - CallbacksFullMultiobjectiveFunctionTest(optimizer, false, false, false, false, - true, true, false, false, true); -} - /** * Make sure we invoke all callbacks (NSGA2). */ From 5c11b532bcf5c4623d8e7df6cecd9126324aabef Mon Sep 17 00:00:00 2001 From: NanuSai Date: Wed, 9 Jun 2021 09:17:07 +0530 Subject: [PATCH 079/128] => Indent fix. => Use ElemType in DecomposeObjectives. => paretoSet and paretoFront filled. => Additional docs. --- include/ensmallen_bits/moead/moead_impl.hpp | 53 +++++++++++++++------ 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index e986f0202..320e44014 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -171,7 +171,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple idealPoint.fill(std::numeric_limits::max()); for (size_t objectiveIdx = 0; objectiveIdx < numObjectives; ++objectiveIdx) { - for (size_t popIdx = 0; j < popIdx; ++popIdx) + for (size_t popIdx = 0; popIdx < populationSize; ++popIdx) { idealPoint(objectiveIdx) = std::min(idealPoint(objectiveIdx), populationFitness[popIdx](objectiveIdx)); } @@ -245,27 +245,49 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple for (size_t idx : idxShuffle) { + // Preserve diversity by controlling replacement of neighbors + // by child solution. if (replaceCounter >= maxReplace) break; size_t pick = sampleNeighbor ? neighborIndices(idx, subProblemIdx) : idx; - double candidateDecomposition = DecomposeObjectives( + ElemType candidateDecomposition = DecomposeObjectives( weights.col(pick), idealPoint, candidateFitness); - double parentDecomposition = DecomposeObjectives( - weights.col(pick), idealPoint, populationFitness.col(pick)); + ElemType parentDecomposition = DecomposeObjectives( + weights.col(pick), idealPoint, populationFitness[pick]); if (candidateDecomposition < parentDecomposition) { population[pick] = candidate; populationFitness[pick] = candidateFitness; - replaceCounter++; + ++replaceCounter; } } } } - bestFront = std::move(population); + // Set the candidates from the Pareto Set as the output. + paretoSet.resize(population[0].n_rows, population[0].n_cols, population.size()); + + // The Pareto Front is stored, can be obtained via ParetoSet() getter. + for (size_t solutionIdx = 0; solutionIdx < population.size(); ++solutionIdx) + { + paretoSet.slice(solutionIdx) = + arma::conv_to::from(population[solutionIdx]); + } + + EvaluateObjectives(population, objectives, populationFitness); + // Set the candidates from the Pareto Front as the output. + paretoFront.resize(populationFitness[0].n_rows, populationFitness[0].n_cols, + populationFitness.size()); + + // The Pareto Front is stored, can be obtained via ParetoFront() getter. + for (size_t solutionIdx = 0; solutionIdx < populationFitness.size(); ++solutionIdx) + { + paretoFront.slice(solutionIdx) = + arma::conv_to::from(populationFitness[solutionIdx]); + } Callback::EndOptimization(*this, objectives, iterate, callbacks...); @@ -283,8 +305,8 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple //! Randomly chooses to select from parents or neighbors. inline std::tuple MOEAD::MatingSelection(size_t subProblemIdx, - const arma::umat& neighborIndices, - bool sampleNeighbor) + const arma::umat& neighborIndices, + bool sampleNeighbor) { size_t k, l; @@ -312,9 +334,9 @@ MOEAD::MatingSelection(size_t subProblemIdx, //! Perform Polynomial mutation of the candidate. template inline void MOEAD::Mutate(MatType& child, - double mutationRate, - const arma::vec& lowerBound, - const arma::vec& upperBound) + double mutationRate, + const arma::vec& lowerBound, + const arma::vec& upperBound) { size_t numVariables = lowerBound.n_elem; double rnd, delta1, delta2, mutationPower, deltaq; @@ -357,11 +379,12 @@ inline void MOEAD::Mutate(MatType& child, //! Calculate the output for single objective function using the Tchebycheff //! approach. -inline double MOEAD::DecomposeObjectives(const arma::vec& weights, - const arma::vec& idealPoint, - const arma::vec& candidateFitness) +template +inline ElemType MOEAD::DecomposeObjectives(const arma::Col& subProblemWeight, + const arma::Col& idealPoint, + const arma::Col& candidateFitness) { - return arma::max(weights % arma::abs(candidateFitness - idealPoint)); + return arma::max(subProblemWeight % arma::abs(candidateFitness - idealPoint)); } //! No objectives to evaluate. From 2822fae878a1424b92f0214dd66ce77abedc5f2c Mon Sep 17 00:00:00 2001 From: NanuSai Date: Wed, 9 Jun 2021 09:17:36 +0530 Subject: [PATCH 080/128] Additional docs in declare file --- include/ensmallen_bits/moead/moead.hpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index c33a7a043..1e16da048 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -203,8 +203,8 @@ class MOEAD { * @return std::tuple The chosen pair of indices. */ std::tuple MatingSelection(size_t subProblemIdx, - const arma::umat& neighborSize, - bool sampleNeighbor); + const arma::umat& neighborSize, + bool sampleNeighbor); /** * Mutate the child formed by the crossover of two random members of the @@ -218,21 +218,22 @@ class MOEAD { */ template void Mutate(MatType& child, - double mutationRate, - const arma::vec& lowerBound, - const arma::vec& upperBound); + double mutationRate, + const arma::vec& lowerBound, + const arma::vec& upperBound); /** * Decompose the multi objective problem to a single objective problem. * - * @param weights Decomposition weights. + * @param subProblemWeight The Decomposition weight vector of the current subproblem. * @param idealPoint The reference point z for a decomposition problem. * @param candidateFitness The fitness value of the candidate. * @return The real value obtained from the decomposed function. */ - double DecomposeObjectives(const arma::vec& weights, - const arma::vec& idealPoint, - const arma::vec& candidateFitness); + template + ElemType DecomposeObjectives(const arma::Col& subProblemWeight, + const arma::Col& idealPoint, + const arma::Col& candidateFitness); /** * Evaluate objectives for the elite population. @@ -247,7 +248,8 @@ class MOEAD { typename MatType, typename ...ArbitraryFunctionType> typename std::enable_if::type - EvaluateObjectives(std::vector&, + EvaluateObjectives( + std::vector&, std::tuple&, std::vector >&); @@ -255,7 +257,8 @@ class MOEAD { typename MatType, typename ...ArbitraryFunctionType> typename std::enable_if::type - EvaluateObjectives(std::vector& population, + EvaluateObjectives( + std::vector& population, std::tuple& objectives, std::vector >& calculatedObjectives); From 5fb082a95ad317a7c1b8d5c0b2e98c7c936cf963 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Wed, 9 Jun 2021 11:03:24 +0530 Subject: [PATCH 081/128] distributionIndex => perturbationIndex --- include/ensmallen_bits/moead/moead.hpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 1e16da048..f2ba49ec7 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -61,7 +61,7 @@ class MOEAD { * @param crossoverProb The probability that a crossover will occur. * @param neighborSize The number of nearest neighbours of weights * to find. - * @param distributionIndex The crowding degree of the mutation. + * @param perturbationIndex The crowding degree of the mutation. * @param neighborProb The probability of sampling from neighbor. * @param differentialWeight A parameter used in the mutation of candidate * solutions controls amplification factor of the differentiation. @@ -75,7 +75,7 @@ class MOEAD { const size_t maxGenerations = 1000, const double crossoverProb = 1.0, const size_t neighborSize = 20, - const double distributionIndex = 20, + const double perturbationIndex = 20, const double neighborProb = 0.9, const double differentialWeight = 0.5, const size_t maxReplace = 2, @@ -96,7 +96,7 @@ class MOEAD { * @param crossoverProb The probability that a crossover will occur. * @param neighborSize The number of nearest neighbours of weights * to find. - * @param distributionIndex The crowding degree of the mutation. + * @param perturbationIndex The crowding degree of the mutation. * @param neighborProb The probability of sampling from neighbor. * @param differentialWeight A parameter used in the mutation of candidate * solutions controls amplification factor of the differentiation. @@ -110,7 +110,7 @@ class MOEAD { const size_t maxGenerations = 1000, const double crossoverProb = 1.0, const size_t neighborSize = 20, - const double distributionIndex = 20, + const double perturbationIndex = 20, const double neighborProb = 0.9, const double differentialWeight = 0.5, const size_t maxReplace = 2, @@ -155,10 +155,10 @@ class MOEAD { //! Modify the size of the weight neighbor. size_t& NeighborSize() { return neighborSize; } - //! Retrieve value of the distribution index. - double DistributionIndex() const { return distributionIndex; } - //! Modify the value of the distribution index. - double& DistributionIndex() { return distributionIndex; } + //! Retrieve value of the perturbation index. + double PerturbationIndex() const { return perturbationIndex; } + //! Modify the value of the perturbation index. + double& PerturbationIndex() { return perturbationIndex; } //! Retrieve value of neighbor probability. double NeighborProb() const { return neighborProb; } @@ -277,7 +277,7 @@ class MOEAD { //! The crowding degree of the mutation. Higher value produces a mutant //! resembling its parent. - double distributionIndex; + double perturbationIndex; //! The probability that two elements will be chosen from the neighbor. double neighborProb; From 274f9f06e98aef5682e98f2a2dea69af49393297 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Wed, 9 Jun 2021 11:04:41 +0530 Subject: [PATCH 082/128] => Use cleaner Mutate code. => Remove redundant for loops. --- include/ensmallen_bits/moead/moead_impl.hpp | 90 ++++++++------------- 1 file changed, 35 insertions(+), 55 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 320e44014..7c0183b58 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -144,20 +144,14 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // 1.2 Random generation of the initial population. std::vector population(populationSize); - for (size_t i = 0; i < populationSize; ++i) + std::generate(population.begin(), population.end(), + [](BaseMatType& individual) { - population[i] = - arma::randu(iterate.n_rows, iterate.n_cols) - 0.5 + iterate; - - // Constrain all genes to be between bounds. - for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) - { - if (population[i](geneIdx) < lowerBound(geneIdx)) - population[i](geneIdx) = lowerBound(geneIdx); - else if (population[i](geneIdx) > upperBound(geneIdx)) - population[i](geneIdx) = upperBound(geneIdx); - } - } + individual = + arma::randu(iterate.n_rows, iterate.n_cols - 0.5) + iterate; + // Constrain all genes to be within bounds. + individual = arma::min(arma::max(individual, lowerBound), upperBound); + }); Info << "MOEA/D-DE initialized successfully. Optimization started." << std::endl; @@ -169,13 +163,9 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // 1.3 Initialize the ideal point z. arma::Col idealPoint(numObjectives); idealPoint.fill(std::numeric_limits::max()); - for (size_t objectiveIdx = 0; objectiveIdx < numObjectives; ++objectiveIdx) - { - for (size_t popIdx = 0; popIdx < populationSize; ++popIdx) - { - idealPoint(objectiveIdx) = std::min(idealPoint(objectiveIdx), populationFitness[popIdx](objectiveIdx)); - } - } + + for (const arma::Col& individualFitness : populationFitness) + idealPoint = arma::min(idealPoint, individualFitness); terminate |= Callback::BeginOptimization(*this, objectives, iterate, callbacks...); @@ -230,11 +220,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple std::vector{candidateFitness}); // 2.4 Update of ideal point. - for (size_t idx = 0; idx < numObjectives; ++idx) - { - idealPoint(idx) = std::min(idealPoint(idx), - candidateFitness(idx)); - } + idealPoint = arma::min(idealPoint, candidateFitness); // 2.5 Update of the population. size_t replaceCounter = 0; @@ -333,48 +319,42 @@ MOEAD::MatingSelection(size_t subProblemIdx, //! Perform Polynomial mutation of the candidate. template -inline void MOEAD::Mutate(MatType& child, +inline void MOEAD::Mutate(MatType& candidate, double mutationRate, const arma::vec& lowerBound, const arma::vec& upperBound) { - size_t numVariables = lowerBound.n_elem; - double rnd, delta1, delta2, mutationPower, deltaq; - double current, currentLower, currentUpper, value, upperDelta; - - for (size_t j = 0; j < numVariables; ++j) - { - double determiner = arma::randu(); - if (determiner <= mutationRate && lowerBound(j) != upperBound(j)) + for (size_t geneIdx=0; geneIdx < numVariables; ++geneIdx) { - current = child[j]; - currentLower = lowerBound(j); - currentUpper = upperBound(j); - delta1 = (current - currentLower) / (currentUpper - currentLower); - delta2 = (currentUpper - current) / (currentUpper - currentLower); - rnd = arma::randu(); - mutationPower = 1.0 /( distributionIndex + 1.0 ); - if (rnd < 0.5) + // Should this gene be mutated? + if (arma::randu() > mutationRate) + continue; + + const double geneRange = upperBound[geneIdx] - lowerBound[geneIdx]; + // Normalised distance from the bounds. + const double lowerDelta = (candidate[geneIdx] - lowerBound[geneIdx]) / geneRange; + const double upperDelta = (upperBound[geneIdx] - candidate[geneIdx]) / geneRange; + const double mutationPower = 1. / (perturbationIndex + 1.0); + const double value; + const double perturbationFactor; + const double rand = arma::randu(); + if(rand < 0.5) { - upperDelta = 1.0 - delta1; - value = 2.0 * rnd + (1.0 - 2.0 * rnd) * - (std::pow(upperDelta, (distributionIndex + 1.0))); - deltaq = std::pow(value, mutationPower) - 1.0; + value = 2. * rand + (1. - 2. * rand) * + std::pow(upperDelta, perturbationIndex + 1.0); + perturbationFactor = std::pow(value, mutationPower) - 1.; } else { - upperDelta = 1.0 - delta2; - value = 2.0 * (1.0 - rnd) + 2.0 * (rnd - 0.5) * - (std::pow(upperDelta, (distributionIndex + 1.0))); - deltaq = 1.0 - (std::pow(value, mutationPower)); + value = 2. * (1. - rand) + 2.*(rand - 0.5) * + std::pow(lowerDelta, perturbationIndex + 1.0); + perturbationFactor = 1. - std::pow(value, mutationPower); } - current += deltaq * (currentUpper - currentLower); - if (current < currentLower) current = currentLower; - if (current > currentUpper) current = currentUpper; - child[j] = current; + candidate[geneIdx] += perturbationFactor * geneRange; } - } + //! Enforce bounds. + candidate= arma::min(arma::max(candidate, lowerBound), upperBound); } //! Calculate the output for single objective function using the Tchebycheff From 34366e7237e9153e896db8ddfafa56aa7b945576 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Wed, 9 Jun 2021 11:07:12 +0530 Subject: [PATCH 083/128] perturbationIndex pt.2 --- include/ensmallen_bits/moead/moead_impl.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 7c0183b58..c5fe18438 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -24,7 +24,7 @@ inline MOEAD::MOEAD(const size_t populationSize, const size_t maxGenerations, const double crossoverProb, const size_t neighborSize, - const double distributionIndex, + const double perturbationIndex, const double neighborProb, const double differentialWeight, const size_t maxReplace, @@ -34,7 +34,7 @@ inline MOEAD::MOEAD(const size_t populationSize, maxGenerations(maxGenerations), crossoverProb(crossoverProb), neighborSize(neighborSize), - distributionIndex(distributionIndex), + perturbationIndex(perturbationIndex), neighborProb(neighborProb), differentialWeight(differentialWeight), maxReplace(maxReplace), @@ -47,7 +47,7 @@ inline MOEAD::MOEAD(const size_t populationSize, const size_t maxGenerations, const double crossoverProb, const size_t neighborSize, - const double distributionIndex, + const double perturbationIndex, const double neighborProb, const double differentialWeight, const size_t maxReplace, @@ -57,7 +57,7 @@ inline MOEAD::MOEAD(const size_t populationSize, maxGenerations(maxGenerations), crossoverProb(crossoverProb), neighborSize(neighborSize), - distributionIndex(distributionIndex), + perturbationIndex(perturbationIndex), neighborProb(neighborProb), differentialWeight(differentialWeight), maxReplace(maxReplace), From 556ded8c4850d06e734d485c3647b11ed95ed37e Mon Sep 17 00:00:00 2001 From: NanuSai Date: Wed, 9 Jun 2021 11:14:45 +0530 Subject: [PATCH 084/128] Everything compiles. --- include/ensmallen_bits/moead/moead_impl.hpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index c5fe18438..176d72fd3 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -145,7 +145,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // 1.2 Random generation of the initial population. std::vector population(populationSize); std::generate(population.begin(), population.end(), - [](BaseMatType& individual) + [this](BaseMatType& individual) { individual = arma::randu(iterate.n_rows, iterate.n_cols - 0.5) + iterate; @@ -211,7 +211,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple else candidate(geneIdx) = population[r1](geneIdx); - } + } Mutate(candidate, 1.0 / static_cast(numVariables), lowerBound, upperBound); @@ -250,8 +250,8 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple ++replaceCounter; } } - } - } + } // End of pass over all subproblems. + } // End of pass over all the generations. // Set the candidates from the Pareto Set as the output. paretoSet.resize(population[0].n_rows, population[0].n_cols, population.size()); @@ -324,6 +324,7 @@ inline void MOEAD::Mutate(MatType& candidate, const arma::vec& lowerBound, const arma::vec& upperBound) { + size_t numVariables = candidate.n_rows; for (size_t geneIdx=0; geneIdx < numVariables; ++geneIdx) { // Should this gene be mutated? @@ -397,6 +398,7 @@ MOEAD::EvaluateObjectives( calculatedObjectives); } } -} + +} // namespace ens #endif From 62dc59099ccf794cd9ed59d4da37f48f08b0271c Mon Sep 17 00:00:00 2001 From: NanuSai Date: Wed, 9 Jun 2021 12:47:53 +0530 Subject: [PATCH 085/128] use MatType lowerBound --- include/ensmallen_bits/moead/moead.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index f2ba49ec7..0203f2f6c 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -219,8 +219,8 @@ class MOEAD { template void Mutate(MatType& child, double mutationRate, - const arma::vec& lowerBound, - const arma::vec& upperBound); + const MatType& lowerBound, + const MatType& upperBound); /** * Decompose the multi objective problem to a single objective problem. From 7d7ad342ee30afe4e3b5305667d784a3a9a5a553 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Wed, 9 Jun 2021 12:49:12 +0530 Subject: [PATCH 086/128] => cache converted upper and lowerBound => PreciisonType flexible => Created containers to pass to evaluateobjectives --- include/ensmallen_bits/moead/moead_impl.hpp | 43 ++++++++++++--------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 176d72fd3..a039f0b6a 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -121,6 +121,10 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple numObjectives = sizeof...(ArbitraryFunctionType); size_t numVariables = iterate.n_rows; + //! Useful temporaries for float-like comparisons. + BaseMatType castedLowerBound = arma::conv_to::from(lowerBound); + BaseMatType castedUpperBound = arma::conv_to::from(upperBound); + // Controls early termination of the optimization process. bool terminate = false; @@ -134,7 +138,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple for (size_t i = 0; i < populationSize; ++i) { // Cache the distance between weights(i) and other weights. - arma::rowvec distances(populationSize); + arma::Row distances(populationSize); distances = arma::sqrt(arma::sum(arma::square(weights.col(i) - weights.each_col()))); arma::uvec sortedIndices = arma::stable_sort_index(distances); @@ -144,14 +148,14 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // 1.2 Random generation of the initial population. std::vector population(populationSize); - std::generate(population.begin(), population.end(), - [this](BaseMatType& individual) + for (BaseMatType& individual : population) { individual = arma::randu(iterate.n_rows, iterate.n_cols - 0.5) + iterate; + // Constrain all genes to be within bounds. - individual = arma::min(arma::max(individual, lowerBound), upperBound); - }); + individual = arma::min(arma::max(individual, castedLowerBound), castedUpperBound); + } Info << "MOEA/D-DE initialized successfully. Optimization started." << std::endl; @@ -185,7 +189,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple std::tie(r2, r3) = MatingSelection(subProblemIdx, neighborIndices, sampleNeighbor); // 2.2 - 2.3 Reproduction and Repair: Differential Operator followed by - // Mutation. + // Polynomial Mutation. BaseMatType candidate(iterate.n_rows, iterate.n_cols); double delta = arma::randu(); for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) @@ -197,15 +201,15 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple population[r3](geneIdx)); // Boundary conditions. - if (candidate(geneIdx) < lowerBound(geneIdx)) + if (candidate(geneIdx) < castedLowerBound(geneIdx)) { - candidate(geneIdx) = lowerBound(geneIdx) + - arma::randu() * (population[r1](geneIdx) - lowerBound(geneIdx)); + candidate(geneIdx) = castedLowerBound(geneIdx) + + arma::randu() * (population[r1](geneIdx) - castedLowerBound(geneIdx)); } - if (candidate(geneIdx) > upperBound(geneIdx)) + if (candidate(geneIdx) > castedUpperBound(geneIdx)) { - candidate(geneIdx) = upperBound(geneIdx) - - arma::randu() * (upperBound(geneIdx) - population[r1](geneIdx)); + candidate(geneIdx) = castedUpperBound(geneIdx) - + arma::randu() * (castedUpperBound(geneIdx) - population[r1](geneIdx)); } } @@ -213,11 +217,13 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple candidate(geneIdx) = population[r1](geneIdx); } - Mutate(candidate, 1.0 / static_cast(numVariables), lowerBound, upperBound); + Mutate(candidate, 1.0 / static_cast(numVariables), castedLowerBound, castedUpperBound); arma::Col candidateFitness(numObjectives); - EvaluateObjectives(std::vector{candidate}, objectives, - std::vector{candidateFitness}); + //! Creating temp vectors to pass to EvaluateObjectives. + std::vector candidateContainer{ candidate }; + std::vector> fitnessContainer { candidateFitness }; + EvaluateObjectives(candidateContainer, objectives, fitnessContainer); // 2.4 Update of ideal point. idealPoint = arma::min(idealPoint, candidateFitness); @@ -321,8 +327,8 @@ MOEAD::MatingSelection(size_t subProblemIdx, template inline void MOEAD::Mutate(MatType& candidate, double mutationRate, - const arma::vec& lowerBound, - const arma::vec& upperBound) + const MatType& lowerBound, + const MatType& upperBound) { size_t numVariables = candidate.n_rows; for (size_t geneIdx=0; geneIdx < numVariables; ++geneIdx) @@ -336,9 +342,8 @@ inline void MOEAD::Mutate(MatType& candidate, const double lowerDelta = (candidate[geneIdx] - lowerBound[geneIdx]) / geneRange; const double upperDelta = (upperBound[geneIdx] - candidate[geneIdx]) / geneRange; const double mutationPower = 1. / (perturbationIndex + 1.0); - const double value; - const double perturbationFactor; const double rand = arma::randu(); + double value, perturbationFactor; if(rand < 0.5) { value = 2. * rand + (1. - 2. * rand) * From dd4b475b8caffd05cc63212a566d09e30985d115 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Wed, 9 Jun 2021 12:49:28 +0530 Subject: [PATCH 087/128] All tests compile --- tests/moead_test.cpp | 413 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 327 insertions(+), 86 deletions(-) diff --git a/tests/moead_test.cpp b/tests/moead_test.cpp index ee5f0750f..7081e9954 100644 --- a/tests/moead_test.cpp +++ b/tests/moead_test.cpp @@ -1,4 +1,3 @@ - /** * @file moead_test.cpp * @author Sayan Goswami @@ -25,35 +24,41 @@ using namespace std; * @param value The value being checked. * @param low The lower bound. * @param high The upper bound. + * @tparam The type of elements in the population set. * @return true if value lies in the range [low, high]. * @return false if value does not lie in the range [low, high]. */ -bool InBounds(const double& value, const double& low, const double& high) +template +bool IsInBounds(const ElemType& value, const ElemType& low, const ElemType& high) { - return !(value < low) && !(high < value); + ElemType roundoff = 0.1; + return !(value < (low - roundoff)) && !((high + roundoff) < value); } /** - * Optimize for the Schaffer N.1 function using MOEA/D-DE optimizer. + * Optimize for the Schaffer N.1 function using NSGA-II optimizer. + * Tests for data of type double. */ -TEST_CASE("MOEADSchafferN1Test", "[MOEADTest]") +TEST_CASE("MOEADSchafferN1DoubleTest", "[MOEADTest]") { SchafferFunctionN1 SCH; - const double lowerBound = -10; - const double upperBound = 10; + const double lowerBound = -1000; + const double upperBound = 1000; + const double expectedLowerBound = 0.0; + const double expectedUpperBound = 2.0; MOEAD opt( - 150, // Population size. - 1000, // Max generations. - 1.0, // Crossover probability. - 20, // Neighborhood size. - 20, // Distribution index. - 0.9, // Probability of sampling from neighbor. - 0.5, // Differential weight. - 2, // Max childrens to replace parents. - lowerBound, // Lower bound. - upperBound // Upper bound. - ); + 150, // Population size. + 1000, // Max generations. + 1.0, // Crossover probability. + 20, // Neighborhood size. + 20, // Perturbation index. + 0.9, // Probability of sampling from neighbor. + 0.5, // Differential weight. + 2, // Max childrens to replace parents. + lowerBound, // Lower bound. + upperBound // Upper bound. + ); typedef decltype(SCH.objectiveA) ObjectiveTypeA; typedef decltype(SCH.objectiveB) ObjectiveTypeB; @@ -66,18 +71,14 @@ TEST_CASE("MOEADSchafferN1Test", "[MOEADTest]") std::tuple objectives = SCH.GetObjectives(); opt.Optimize(objectives, coords); - std::vector bestFront = opt.Front(); + arma::cube paretoSet= opt.ParetoSet(); bool allInRange = true; - double minimumPositive = 1000; - for (arma::mat solution: bestFront) + for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx) { - double val = arma::as_scalar(solution); - if(val >= 0.0) - minimumPositive = std::min(minimumPositive, val); - - if ((val < 0.0 && std::abs(val) >= minimumPositive) || val > 2.0) + double val = arma::as_scalar(paretoSet.slice(solutionIdx)); + if (!IsInBounds(val, expectedLowerBound, expectedUpperBound)) { allInRange = false; break; @@ -95,26 +96,30 @@ TEST_CASE("MOEADSchafferN1Test", "[MOEADTest]") } /** - * Optimize for the Schaffer N.1 function using MOEA/D-DE optimizer. + * Optimize for the Schaffer N.1 function using NSGA-II optimizer. + * Tests for data of type double. */ -TEST_CASE("MOEADSchafferN1VectorBoundsTest", "[MOEADTest]") +TEST_CASE("MOEADSchafferN1TestVectorDoubleBounds", "[MOEADTest]") { + // This test can be a little flaky, so we try it a few times. SchafferFunctionN1 SCH; - arma::vec lowerBound = {-10}; - arma::vec upperBound = {10}; + const arma::vec lowerBound = {-1000}; + const arma::vec upperBound = {1000}; + const double expectedLowerBound = 0.0; + const double expectedUpperBound = 2.0; MOEAD opt( - 150, // Population size. - 1000, // Max generations. - 1.0, // Crossover probability. - 20, // Neighborhood size. - 20, // Distribution index. - 0.9, // Probability of sampling from neighbor. - 0.5, // Differential weight. - 2, // Max childrens to replace parents. - lowerBound, // Lower bound. - upperBound // Upper bound. - ); + 150, // Population size. + 1000, // Max generations. + 1.0, // Crossover probability. + 20, // Neighborhood size. + 20, // Perturbation index. + 0.9, // Probability of sampling from neighbor. + 0.5, // Differential weight. + 2, // Max childrens to replace parents. + lowerBound, // Lower bound. + upperBound // Upper bound. + ); typedef decltype(SCH.objectiveA) ObjectiveTypeA; typedef decltype(SCH.objectiveB) ObjectiveTypeB; @@ -126,15 +131,14 @@ TEST_CASE("MOEADSchafferN1VectorBoundsTest", "[MOEADTest]") std::tuple objectives = SCH.GetObjectives(); opt.Optimize(objectives, coords); - std::vector bestFront = opt.Front(); + arma::cube paretoSet= opt.ParetoSet(); bool allInRange = true; - for (arma::mat solution: bestFront) + for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx) { - double val = arma::as_scalar(solution); - - if (val < 0.0 || val > 2.0) + double val = arma::as_scalar(paretoSet.slice(solutionIdx)); + if (!IsInBounds(val, expectedLowerBound, expectedUpperBound)) { allInRange = false; break; @@ -152,9 +156,10 @@ TEST_CASE("MOEADSchafferN1VectorBoundsTest", "[MOEADTest]") } /** - * Optimize for the Fonseca Fleming function using MOEA/D-DE optimizer. + * Optimize for the Fonseca Fleming function using NSGA-II optimizer. + * Tests for data of type double. */ -TEST_CASE("MOEADFonsecaFlemingTest", "[MOEADTest]") +TEST_CASE("MOEADFonsecaFlemingDoubleTest", "[MOEADTest]") { FonsecaFlemingFunction FON; const double lowerBound = -4; @@ -163,48 +168,52 @@ TEST_CASE("MOEADFonsecaFlemingTest", "[MOEADTest]") const double expectedUpperBound = 1.0 / sqrt(3); MOEAD opt( - 150, // Population size. - 1000, // Max generations. - 1.0, // Crossover probability. - 20, // Neighborhood size. - 20, // Distribution index. - 0.9, // Probability of sampling from neighbor. - 0.5, // Differential weight. - 2, // Max childrens to replace parents. - lowerBound, // Lower bound. - upperBound // Upper bound. - ); - + 150, // Population size. + 1000, // Max generations. + 1.0, // Crossover probability. + 20, // Neighborhood size. + 20, // Perturbation index. + 0.9, // Probability of sampling from neighbor. + 0.5, // Differential weight. + 2, // Max childrens to replace parents. + lowerBound, // Lower bound. + upperBound // Upper bound. + ); typedef decltype(FON.objectiveA) ObjectiveTypeA; typedef decltype(FON.objectiveB) ObjectiveTypeB; arma::mat coords = FON.GetInitialPoint(); std::tuple objectives = FON.GetObjectives(); + opt.Optimize(objectives, coords); - std::vector bestFront = opt.Front(); + arma::cube paretoSet = opt.ParetoSet(); + bool allInRange = true; - for (size_t i = 0; i < bestFront.size(); i++) + + for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx) { - const arma::mat solution = bestFront[i]; + const arma::mat solution = paretoSet.slice(solutionIdx); double valX = arma::as_scalar(solution(0)); double valY = arma::as_scalar(solution(1)); double valZ = arma::as_scalar(solution(2)); - if (!InBounds(valX, expectedLowerBound, expectedUpperBound) || - !InBounds(valY, expectedLowerBound, expectedUpperBound) || - !InBounds(valZ, expectedLowerBound, expectedUpperBound)) + if (!IsInBounds(valX, expectedLowerBound, expectedUpperBound) || + !IsInBounds(valY, expectedLowerBound, expectedUpperBound) || + !IsInBounds(valZ, expectedLowerBound, expectedUpperBound)) { allInRange = false; break; } } + REQUIRE(allInRange); } /** - * Optimize for the Fonseca Fleming function using MOEA/D-DE optimizer. + * Optimize for the Fonseca Fleming function using NSGA-II optimizer. + * Tests for data of type double. */ -TEST_CASE("MOEADFonsecaFlemingVectorBoundsTest", "[MOEADTest]") +TEST_CASE("MOEADFonsecaFlemingTestVectorDoubleBounds", "[MOEADTest]") { FonsecaFlemingFunction FON; const arma::vec lowerBound = {-4, -4, -4}; @@ -213,39 +222,271 @@ TEST_CASE("MOEADFonsecaFlemingVectorBoundsTest", "[MOEADTest]") const double expectedUpperBound = 1.0 / sqrt(3); MOEAD opt( - 150, // Population size. - 1000, // Max generations. - 1.0, // Crossover probability. - 20, // Neighborhood size. - 20, // Distribution index. - 0.9, // Probability of sampling from neighbor. - 0.5, // Differential weight. - 2, // Max childrens to replace parents. - lowerBound, // Lower bound. - upperBound // Upper bound. - ); - + 150, // Population size. + 1000, // Max generations. + 1.0, // Crossover probability. + 20, // Neighborhood size. + 20, // Perturbation index. + 0.9, // Probability of sampling from neighbor. + 0.5, // Differential weight. + 2, // Max childrens to replace parents. + lowerBound, // Lower bound. + upperBound // Upper bound. + ); typedef decltype(FON.objectiveA) ObjectiveTypeA; typedef decltype(FON.objectiveB) ObjectiveTypeB; + arma::mat coords = FON.GetInitialPoint(); std::tuple objectives = FON.GetObjectives(); + opt.Optimize(objectives, coords); - std::vector bestFront = opt.Front(); + arma::cube paretoSet = opt.ParetoSet(); + bool allInRange = true; - for (size_t i = 0; i < bestFront.size(); i++) + + for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx) { - const arma::mat solution = bestFront[i]; + const arma::mat solution = paretoSet.slice(solutionIdx); double valX = arma::as_scalar(solution(0)); double valY = arma::as_scalar(solution(1)); double valZ = arma::as_scalar(solution(2)); - if (!InBounds(valX, expectedLowerBound, expectedUpperBound) || - !InBounds(valY, expectedLowerBound, expectedUpperBound) || - !InBounds(valZ, expectedLowerBound, expectedUpperBound)) + if (!IsInBounds(valX, expectedLowerBound, expectedUpperBound) || + !IsInBounds(valY, expectedLowerBound, expectedUpperBound) || + !IsInBounds(valZ, expectedLowerBound, expectedUpperBound)) { allInRange = false; break; } } + + REQUIRE(allInRange); +} + +/** + * Optimize for the Schaffer N.1 function using NSGA-II optimizer. + * Tests for data of type float. + */ +TEST_CASE("MOEADSchafferN1FloatTest", "[MOEADTest]") +{ + SchafferFunctionN1 SCH; + const double lowerBound = -1000; + const double upperBound = 1000; + const double expectedLowerBound = 0.0; + const double expectedUpperBound = 2.0; + + MOEAD opt( + 150, // Population size. + 1000, // Max generations. + 1.0, // Crossover probability. + 20, // Neighborhood size. + 20, // Perturbation index. + 0.9, // Probability of sampling from neighbor. + 0.5, // Differential weight. + 2, // Max childrens to replace parents. + lowerBound, // Lower bound. + upperBound // Upper bound. + ); + + typedef decltype(SCH.objectiveA) ObjectiveTypeA; + typedef decltype(SCH.objectiveB) ObjectiveTypeB; + + // We allow a few trials in case of poor convergence. + bool success = false; + for (size_t trial = 0; trial < 3; ++trial) + { + arma::fmat coords = SCH.GetInitialPoint(); + std::tuple objectives = SCH.GetObjectives(); + + opt.Optimize(objectives, coords); + arma::fcube paretoSet = arma::conv_to::from(opt.ParetoSet()); + + bool allInRange = true; + + for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx) + { + float val = arma::as_scalar(paretoSet.slice(solutionIdx)); + if (!IsInBounds(val, expectedLowerBound, expectedUpperBound)) + { + allInRange = false; + break; + } + } + + if (allInRange) + { + success = true; + break; + } + } + + REQUIRE(success == true); +} + +/** + * Optimize for the Schaffer N.1 function using NSGA-II optimizer. + * Tests for data of type float. + */ +TEST_CASE("MOEADSchafferN1TestVectorFloatBounds", "[MOEADTest]") +{ + // This test can be a little flaky, so we try it a few times. + SchafferFunctionN1 SCH; + const arma::vec lowerBound = {-1000}; + const arma::vec upperBound = {1000}; + const double expectedLowerBound = 0.0; + const double expectedUpperBound = 2.0; + + MOEAD opt( + 150, // Population size. + 1000, // Max generations. + 1.0, // Crossover probability. + 20, // Neighborhood size. + 20, // Perturbation index. + 0.9, // Probability of sampling from neighbor. + 0.5, // Differential weight. + 2, // Max childrens to replace parents. + lowerBound, // Lower bound. + upperBound // Upper bound. + ); + + typedef decltype(SCH.objectiveA) ObjectiveTypeA; + typedef decltype(SCH.objectiveB) ObjectiveTypeB; + + bool success = false; + for (size_t trial = 0; trial < 3; ++trial) + { + arma::fmat coords = SCH.GetInitialPoint(); + std::tuple objectives = SCH.GetObjectives(); + + opt.Optimize(objectives, coords); + arma::fcube paretoSet = arma::conv_to::from(opt.ParetoSet()); + + bool allInRange = true; + + for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx) + { + float val = arma::as_scalar(paretoSet.slice(solutionIdx)); + if (!IsInBounds(val, expectedLowerBound, expectedUpperBound)) + { + allInRange = false; + break; + } + } + + if (allInRange) + { + success = true; + break; + } + } + + REQUIRE(success == true); +} + +/** + * Optimize for the Fonseca Fleming function using NSGA-II optimizer. + * Tests for data of type float. + */ +TEST_CASE("MOEADFonsecaFlemingFloatTest", "[MOEADTest]") +{ + FonsecaFlemingFunction FON; + const double lowerBound = -4; + const double upperBound = 4; + const float expectedLowerBound = -1.0 / sqrt(3); + const float expectedUpperBound = 1.0 / sqrt(3); + + MOEAD opt( + 150, // Population size. + 1000, // Max generations. + 1.0, // Crossover probability. + 20, // Neighborhood size. + 20, // Perturbation index. + 0.9, // Probability of sampling from neighbor. + 0.5, // Differential weight. + 2, // Max childrens to replace parents. + lowerBound, // Lower bound. + upperBound // Upper bound. + ); + typedef decltype(FON.objectiveA) ObjectiveTypeA; + typedef decltype(FON.objectiveB) ObjectiveTypeB; + + arma::fmat coords = FON.GetInitialPoint(); + std::tuple objectives = FON.GetObjectives(); + + opt.Optimize(objectives, coords); + arma::fcube paretoSet = arma::conv_to::from(opt.ParetoSet()); + + bool allInRange = true; + + for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx) + { + const arma::fmat solution = paretoSet.slice(solutionIdx); + float valX = arma::as_scalar(solution(0)); + float valY = arma::as_scalar(solution(1)); + float valZ = arma::as_scalar(solution(2)); + + if (!IsInBounds(valX, expectedLowerBound, expectedUpperBound) || + !IsInBounds(valY, expectedLowerBound, expectedUpperBound) || + !IsInBounds(valZ, expectedLowerBound, expectedUpperBound)) + { + allInRange = false; + break; + } + } + + REQUIRE(allInRange); +} + +/** + * Optimize for the Fonseca Fleming function using NSGA-II optimizer. + * Tests for data of type float. + */ +TEST_CASE("MOEADFonsecaFlemingTestVectorFloatBounds", "[MOEADTest]") +{ + FonsecaFlemingFunction FON; + const arma::vec lowerBound = {-4, -4, -4}; + const arma::vec upperBound = {4, 4, 4}; + const float expectedLowerBound = -1.0 / sqrt(3); + const float expectedUpperBound = 1.0 / sqrt(3); + + MOEAD opt( + 150, // Population size. + 1000, // Max generations. + 1.0, // Crossover probability. + 20, // Neighborhood size. + 20, // Perturbation index. + 0.9, // Probability of sampling from neighbor. + 0.5, // Differential weight. + 2, // Max childrens to replace parents. + lowerBound, // Lower bound. + upperBound // Upper bound. + ); + typedef decltype(FON.objectiveA) ObjectiveTypeA; + typedef decltype(FON.objectiveB) ObjectiveTypeB; + + arma::fmat coords = FON.GetInitialPoint(); + std::tuple objectives = FON.GetObjectives(); + + opt.Optimize(objectives, coords); + arma::fcube paretoSet = arma::conv_to::from(opt.ParetoSet()); + + bool allInRange = true; + + for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx) + { + const arma::fmat solution = paretoSet.slice(solutionIdx); + float valX = arma::as_scalar(solution(0)); + float valY = arma::as_scalar(solution(1)); + float valZ = arma::as_scalar(solution(2)); + + if (!IsInBounds(valX, expectedLowerBound, expectedUpperBound) || + !IsInBounds(valY, expectedLowerBound, expectedUpperBound) || + !IsInBounds(valZ, expectedLowerBound, expectedUpperBound)) + { + allInRange = false; + break; + } + } + REQUIRE(allInRange); } \ No newline at end of file From 0f597ddd11f5419cc25ef355ca0e215c984a84dd Mon Sep 17 00:00:00 2001 From: NanuSai Date: Wed, 9 Jun 2021 19:23:35 +0530 Subject: [PATCH 088/128] initialize fitness --- include/ensmallen_bits/moead/moead_impl.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index a039f0b6a..e76fb8b31 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -150,8 +150,8 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple std::vector population(populationSize); for (BaseMatType& individual : population) { - individual = - arma::randu(iterate.n_rows, iterate.n_cols - 0.5) + iterate; + individual = arma::randu( + iterate.n_rows, iterate.n_cols) -0.5 + iterate; // Constrain all genes to be within bounds. individual = arma::min(arma::max(individual, castedLowerBound), castedUpperBound); @@ -159,9 +159,9 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple Info << "MOEA/D-DE initialized successfully. Optimization started." << std::endl; - std::vector> populationFitness; - populationFitness.resize(populationSize); - + std::vector> populationFitness(populationSize); + std::fill(populationFitness.begin(), populationFitness.end(), + arma::Col(numObjectives, arma::fill::zeros)); EvaluateObjectives(population, objectives, populationFitness); // 1.3 Initialize the ideal point z. From 08fa726dc188f39a40076f9c5e3de1d68b3bc2ac Mon Sep 17 00:00:00 2001 From: NanuSai Date: Wed, 9 Jun 2021 21:26:23 +0530 Subject: [PATCH 089/128] Tests pass --- include/ensmallen_bits/moead/moead_impl.hpp | 6 +++++- tests/moead_test.cpp | 16 ++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index e76fb8b31..9e4ae52ad 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -224,6 +224,10 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple std::vector candidateContainer{ candidate }; std::vector> fitnessContainer { candidateFitness }; EvaluateObjectives(candidateContainer, objectives, fitnessContainer); + candidateFitness = std::move(fitnessContainer[0]); + //! Flush out the dummy containers. + fitnessContainer.clear(); + candidateContainer.clear(); // 2.4 Update of ideal point. idealPoint = arma::min(idealPoint, candidateFitness); @@ -396,7 +400,7 @@ MOEAD::EvaluateObjectives( std::tuple& objectives, std::vector >& calculatedObjectives) { - for (size_t i = 0; i < populationSize; i++) + for (size_t i = 0; i < population.size(); i++) { calculatedObjectives[i](I) = std::get(objectives).Evaluate(population[i]); EvaluateObjectives(population, objectives, diff --git a/tests/moead_test.cpp b/tests/moead_test.cpp index 7081e9954..7582601c8 100644 --- a/tests/moead_test.cpp +++ b/tests/moead_test.cpp @@ -49,7 +49,7 @@ TEST_CASE("MOEADSchafferN1DoubleTest", "[MOEADTest]") MOEAD opt( 150, // Population size. - 1000, // Max generations. + 300, // Max generations. 1.0, // Crossover probability. 20, // Neighborhood size. 20, // Perturbation index. @@ -110,7 +110,7 @@ TEST_CASE("MOEADSchafferN1TestVectorDoubleBounds", "[MOEADTest]") MOEAD opt( 150, // Population size. - 1000, // Max generations. + 300, // Max generations. 1.0, // Crossover probability. 20, // Neighborhood size. 20, // Perturbation index. @@ -169,7 +169,7 @@ TEST_CASE("MOEADFonsecaFlemingDoubleTest", "[MOEADTest]") MOEAD opt( 150, // Population size. - 1000, // Max generations. + 300, // Max generations. 1.0, // Crossover probability. 20, // Neighborhood size. 20, // Perturbation index. @@ -223,7 +223,7 @@ TEST_CASE("MOEADFonsecaFlemingTestVectorDoubleBounds", "[MOEADTest]") MOEAD opt( 150, // Population size. - 1000, // Max generations. + 300, // Max generations. 1.0, // Crossover probability. 20, // Neighborhood size. 20, // Perturbation index. @@ -277,7 +277,7 @@ TEST_CASE("MOEADSchafferN1FloatTest", "[MOEADTest]") MOEAD opt( 150, // Population size. - 1000, // Max generations. + 300, // Max generations. 1.0, // Crossover probability. 20, // Neighborhood size. 20, // Perturbation index. @@ -338,7 +338,7 @@ TEST_CASE("MOEADSchafferN1TestVectorFloatBounds", "[MOEADTest]") MOEAD opt( 150, // Population size. - 1000, // Max generations. + 300, // Max generations. 1.0, // Crossover probability. 20, // Neighborhood size. 20, // Perturbation index. @@ -397,7 +397,7 @@ TEST_CASE("MOEADFonsecaFlemingFloatTest", "[MOEADTest]") MOEAD opt( 150, // Population size. - 1000, // Max generations. + 300, // Max generations. 1.0, // Crossover probability. 20, // Neighborhood size. 20, // Perturbation index. @@ -451,7 +451,7 @@ TEST_CASE("MOEADFonsecaFlemingTestVectorFloatBounds", "[MOEADTest]") MOEAD opt( 150, // Population size. - 1000, // Max generations. + 300, // Max generations. 1.0, // Crossover probability. 20, // Neighborhood size. 20, // Perturbation index. From 5adfba0bbdbbbf2c4c3c382f73cad2f0ea782981 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Thu, 10 Jun 2021 09:53:14 +0530 Subject: [PATCH 090/128] use distributionIndex again --- include/ensmallen_bits/moead/moead.hpp | 18 +++++++++--------- include/ensmallen_bits/moead/moead_impl.hpp | 14 +++++++------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 0203f2f6c..2ece43e5e 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -61,7 +61,7 @@ class MOEAD { * @param crossoverProb The probability that a crossover will occur. * @param neighborSize The number of nearest neighbours of weights * to find. - * @param perturbationIndex The crowding degree of the mutation. + * @param distributionIndex The crowding degree of the mutation. * @param neighborProb The probability of sampling from neighbor. * @param differentialWeight A parameter used in the mutation of candidate * solutions controls amplification factor of the differentiation. @@ -75,7 +75,7 @@ class MOEAD { const size_t maxGenerations = 1000, const double crossoverProb = 1.0, const size_t neighborSize = 20, - const double perturbationIndex = 20, + const double distributionIndex = 20, const double neighborProb = 0.9, const double differentialWeight = 0.5, const size_t maxReplace = 2, @@ -96,7 +96,7 @@ class MOEAD { * @param crossoverProb The probability that a crossover will occur. * @param neighborSize The number of nearest neighbours of weights * to find. - * @param perturbationIndex The crowding degree of the mutation. + * @param distributionIndex The crowding degree of the mutation. * @param neighborProb The probability of sampling from neighbor. * @param differentialWeight A parameter used in the mutation of candidate * solutions controls amplification factor of the differentiation. @@ -110,7 +110,7 @@ class MOEAD { const size_t maxGenerations = 1000, const double crossoverProb = 1.0, const size_t neighborSize = 20, - const double perturbationIndex = 20, + const double distributionIndex = 20, const double neighborProb = 0.9, const double differentialWeight = 0.5, const size_t maxReplace = 2, @@ -155,10 +155,10 @@ class MOEAD { //! Modify the size of the weight neighbor. size_t& NeighborSize() { return neighborSize; } - //! Retrieve value of the perturbation index. - double PerturbationIndex() const { return perturbationIndex; } - //! Modify the value of the perturbation index. - double& PerturbationIndex() { return perturbationIndex; } + //! Retrieve value of the distribution index. + double DistributionIndex() const { return distributionIndex; } + //! Modify the value of the distribution index. + double& DistributionIndex() { return distributionIndex; } //! Retrieve value of neighbor probability. double NeighborProb() const { return neighborProb; } @@ -277,7 +277,7 @@ class MOEAD { //! The crowding degree of the mutation. Higher value produces a mutant //! resembling its parent. - double perturbationIndex; + double distributionIndex; //! The probability that two elements will be chosen from the neighbor. double neighborProb; diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 9e4ae52ad..fe2a21fef 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -24,7 +24,7 @@ inline MOEAD::MOEAD(const size_t populationSize, const size_t maxGenerations, const double crossoverProb, const size_t neighborSize, - const double perturbationIndex, + const double distributionIndex, const double neighborProb, const double differentialWeight, const size_t maxReplace, @@ -34,7 +34,7 @@ inline MOEAD::MOEAD(const size_t populationSize, maxGenerations(maxGenerations), crossoverProb(crossoverProb), neighborSize(neighborSize), - perturbationIndex(perturbationIndex), + distributionIndex(distributionIndex), neighborProb(neighborProb), differentialWeight(differentialWeight), maxReplace(maxReplace), @@ -47,7 +47,7 @@ inline MOEAD::MOEAD(const size_t populationSize, const size_t maxGenerations, const double crossoverProb, const size_t neighborSize, - const double perturbationIndex, + const double distributionIndex, const double neighborProb, const double differentialWeight, const size_t maxReplace, @@ -57,7 +57,7 @@ inline MOEAD::MOEAD(const size_t populationSize, maxGenerations(maxGenerations), crossoverProb(crossoverProb), neighborSize(neighborSize), - perturbationIndex(perturbationIndex), + distributionIndex(distributionIndex), neighborProb(neighborProb), differentialWeight(differentialWeight), maxReplace(maxReplace), @@ -345,19 +345,19 @@ inline void MOEAD::Mutate(MatType& candidate, // Normalised distance from the bounds. const double lowerDelta = (candidate[geneIdx] - lowerBound[geneIdx]) / geneRange; const double upperDelta = (upperBound[geneIdx] - candidate[geneIdx]) / geneRange; - const double mutationPower = 1. / (perturbationIndex + 1.0); + const double mutationPower = 1. / (distributionIndex + 1.0); const double rand = arma::randu(); double value, perturbationFactor; if(rand < 0.5) { value = 2. * rand + (1. - 2. * rand) * - std::pow(upperDelta, perturbationIndex + 1.0); + std::pow(upperDelta, distributionIndex + 1.0); perturbationFactor = std::pow(value, mutationPower) - 1.; } else { value = 2. * (1. - rand) + 2.*(rand - 0.5) * - std::pow(lowerDelta, perturbationIndex + 1.0); + std::pow(lowerDelta, distributionIndex + 1.0); perturbationFactor = 1. - std::pow(value, mutationPower); } From a068a6e40dc5c5aeee17b3ca6e0e1ac37f56f87f Mon Sep 17 00:00:00 2001 From: NanuSai Date: Thu, 10 Jun 2021 09:53:25 +0530 Subject: [PATCH 091/128] Fix docs for optimizers.md --- doc/optimizers.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/optimizers.md b/doc/optimizers.md index 07af3c83a..657111b14 100644 --- a/doc/optimizers.md +++ b/doc/optimizers.md @@ -1568,8 +1568,8 @@ optimizer.Optimize(f, coordinates); MOEA/D-DE (Multi Objective Evolutionary Algorithm based on Decomposition - Differential Evolution) is a multi objective optimization algorithm. It works by decomposing the problem into a number of scalar optimization subproblems which are solved simultaneously per generation. MOEA/D in itself is a framework, this particular -algorithm uses Differential Crossover followed by polynomial mutation to create offsprings which are then -decomposed using Tchebycheff's approach. A diversity preserving mechanism is also employed which produces +algorithm uses Differential Crossover followed by Polynomial Mutation to create offsprings which are then +decomposed to form a Single Objective Problem. A diversity preserving mechanism is also employed which encourages a varied set of solution. #### Constructors @@ -1583,7 +1583,7 @@ a varied set of solution. | `size_t` | **`populationSize`** | The number of candidates in the population. | `150` | | `size_t` | **`maxGenerations`** | The maximum number of generations allowed. | `1000` | | `double` | **`crossoverProb`** | Probability that a crossover will occur. | `1.0` | -| `size_t` | **`neighborSize`** | The number of nearest-neighbours to consider for each weight. | `20` | +| `size_t` | **`neighborSize`** | The number of nearest-neighbours to consider per weight vector. | `20` | | `double` | **`distributionIndex`** | The crowding degree of the mutation. | `20` | | `double` | **`neighborProb`** | The probability of sampling from neighbor. | `0.9` | | `double` | **`differentialWeight`** | Amplification factor of the differentiation. | `0.5` | @@ -1605,7 +1605,7 @@ Attributes of the optimizer may also be changed via the member methods SchafferFunctionN1 SCH; arma::vec lowerBound("-10 -10"); arma::vec upperBound("10 10"); -MOEAD opt(150, 1000, 1.0, 20, 20, 0.9, 0.5, 2, lowerBound, upperBound); +MOEAD opt(150, 300, 1.0, 20, 20, 0.9, 0.5, 2, lowerBound, upperBound); typedef decltype(SCH.objectiveA) ObjectiveTypeA; typedef decltype(SCH.objectiveB) ObjectiveTypeB; arma::mat coords = SCH.GetInitialPoint(); @@ -1613,7 +1613,7 @@ std::tuple objectives = SCH.GetObjectives(); // obj will contain the minimum sum of objectiveA and objectiveB found on the best front. double obj = opt.Optimize(objectives, coords); // Now obtain the best front. -std::vector bestFront = opt.Front(); +arma::cube bestFront = opt.ParetoFront(); ``` @@ -1678,7 +1678,7 @@ std::tuple objectives = SCH.GetObjectives(); // obj will contain the minimum sum of objectiveA and objectiveB found on the best front. double obj = opt.Optimize(objectives, coords); // Now obtain the best front. -std::vector bestFront = opt.Front(); +arma::cube bestFront = opt.Front(); ``` From b5f49a00a284aaa58ecf584233dcb8e894eaf101 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Thu, 10 Jun 2021 10:08:38 +0530 Subject: [PATCH 092/128] Fix callbacks --- include/ensmallen_bits/moead/moead_impl.hpp | 7 +++++++ tests/callbacks_test.cpp | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index fe2a21fef..169214b49 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -261,6 +261,13 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple } } } // End of pass over all subproblems. + + // The final population itself is the best front. + const arma::uvec frontIndices = arma::shuffle( + arma::linspace(0, populationSize - 1, populationSize)); + + terminate |= Callback::GenerationalStepTaken(*this, objectives, iterate, + populationFitness, frontIndices, callbacks...); } // End of pass over all the generations. // Set the candidates from the Pareto Set as the output. diff --git a/tests/callbacks_test.cpp b/tests/callbacks_test.cpp index 90c1ddc0b..2354f52c4 100644 --- a/tests/callbacks_test.cpp +++ b/tests/callbacks_test.cpp @@ -399,6 +399,18 @@ TEST_CASE("NSGA2CallbacksFullFunctionTest", "[CallbackTest]") true, true, false, false, false, true); } +/** + * Make sure we invoke all callbacks (MOEA/D-DE). + */ +TEST_CASE("MOEADCallbacksFullFunctionTest", "[CallbackTest]") +{ + arma::vec lowerBound = {-1000}; + arma::vec upperBound = {1000}; + MOEAD optimizer(150, 300, 1.0, 20, 20, 0.9, 0.5, 2, lowerBound, upperBound); + CallbacksFullMultiobjectiveFunctionTest(optimizer, false, false, false, false, + true, true, false, false, false, true); +} + /** * Make sure we invoke all callbacks (Lookahead). */ From d2a396cde113297140196a4980011396cc9b7015 Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Thu, 10 Jun 2021 11:55:30 +0530 Subject: [PATCH 093/128] Update moead.hpp Fix indent --- include/ensmallen_bits/moead/moead.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 2ece43e5e..9cad39139 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -203,8 +203,8 @@ class MOEAD { * @return std::tuple The chosen pair of indices. */ std::tuple MatingSelection(size_t subProblemIdx, - const arma::umat& neighborSize, - bool sampleNeighbor); + const arma::umat& neighborSize, + bool sampleNeighbor); /** * Mutate the child formed by the crossover of two random members of the @@ -218,9 +218,9 @@ class MOEAD { */ template void Mutate(MatType& child, - double mutationRate, - const MatType& lowerBound, - const MatType& upperBound); + double mutationRate, + const MatType& lowerBound, + const MatType& upperBound); /** * Decompose the multi objective problem to a single objective problem. @@ -232,8 +232,8 @@ class MOEAD { */ template ElemType DecomposeObjectives(const arma::Col& subProblemWeight, - const arma::Col& idealPoint, - const arma::Col& candidateFitness); + const arma::Col& idealPoint, + const arma::Col& candidateFitness); /** * Evaluate objectives for the elite population. From 950e36c2d0c1da619518d5ab472c2724264e899e Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Thu, 10 Jun 2021 11:57:40 +0530 Subject: [PATCH 094/128] Update moead_impl.hpp Indent fix --- include/ensmallen_bits/moead/moead_impl.hpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 169214b49..44fe554dd 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -186,7 +186,8 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple r1 = subProblemIdx; // Randomly choose to sample from the population or the neighbors. bool sampleNeighbor = arma::randu() < neighborProb; - std::tie(r2, r3) = MatingSelection(subProblemIdx, neighborIndices, sampleNeighbor); + std::tie(r2, r3) = + Selection(subProblemIdx, neighborIndices, sampleNeighbor); // 2.2 - 2.3 Reproduction and Repair: Differential Operator followed by // Polynomial Mutation. @@ -308,10 +309,10 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple //! Randomly chooses to select from parents or neighbors. inline std::tuple MOEAD::MatingSelection(size_t subProblemIdx, - const arma::umat& neighborIndices, - bool sampleNeighbor) + const arma::umat& neighborIndices, + bool sampleNeighbor) { - size_t k, l; + size_t k, l; k = sampleNeighbor ? neighborIndices( @@ -337,9 +338,9 @@ MOEAD::MatingSelection(size_t subProblemIdx, //! Perform Polynomial mutation of the candidate. template inline void MOEAD::Mutate(MatType& candidate, - double mutationRate, - const MatType& lowerBound, - const MatType& upperBound) + double mutationRate, + const MatType& lowerBound, + const MatType& upperBound) { size_t numVariables = candidate.n_rows; for (size_t geneIdx=0; geneIdx < numVariables; ++geneIdx) @@ -378,8 +379,8 @@ inline void MOEAD::Mutate(MatType& candidate, //! approach. template inline ElemType MOEAD::DecomposeObjectives(const arma::Col& subProblemWeight, - const arma::Col& idealPoint, - const arma::Col& candidateFitness) + const arma::Col& idealPoint, + const arma::Col& candidateFitness) { return arma::max(subProblemWeight % arma::abs(candidateFitness - idealPoint)); } From 6acbe14bfbf916ba18982e0ee2b2812d4af08f41 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Thu, 10 Jun 2021 11:59:36 +0530 Subject: [PATCH 095/128] minor style --- include/ensmallen_bits/moead/moead.hpp | 1 + include/ensmallen_bits/moead/moead_impl.hpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 9cad39139..55127c5eb 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -215,6 +215,7 @@ class MOEAD { * @param mutationRate The probability of mutation. * @param lowerBound The lower bound on each variable in the matrix. * @param upperBound The upper bound on each variable in the matrix. + * @return The mutated child. */ template void Mutate(MatType& child, diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 44fe554dd..abe402542 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -186,7 +186,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple r1 = subProblemIdx; // Randomly choose to sample from the population or the neighbors. bool sampleNeighbor = arma::randu() < neighborProb; - std::tie(r2, r3) = + std::tie(r2, r3) = Selection(subProblemIdx, neighborIndices, sampleNeighbor); // 2.2 - 2.3 Reproduction and Repair: Differential Operator followed by From fb587225d4a2c62128b6e6bb81f219b03e5f19da Mon Sep 17 00:00:00 2001 From: NanuSai Date: Thu, 10 Jun 2021 14:51:56 +0530 Subject: [PATCH 096/128] fix error --- include/ensmallen_bits/moead/moead_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index abe402542..a5d0d0f20 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -187,7 +187,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // Randomly choose to sample from the population or the neighbors. bool sampleNeighbor = arma::randu() < neighborProb; std::tie(r2, r3) = - Selection(subProblemIdx, neighborIndices, sampleNeighbor); + MatingSelection(subProblemIdx, neighborIndices, sampleNeighbor); // 2.2 - 2.3 Reproduction and Repair: Differential Operator followed by // Polynomial Mutation. From bd2522667ed80feb929b6e19cfa1b924dd2ebd92 Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Fri, 11 Jun 2021 23:08:17 +0530 Subject: [PATCH 097/128] Update include/ensmallen_bits/moead/moead_impl.hpp Co-authored-by: Marcus Edel --- include/ensmallen_bits/moead/moead_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index a5d0d0f20..2fb2db6f6 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -151,7 +151,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple for (BaseMatType& individual : population) { individual = arma::randu( - iterate.n_rows, iterate.n_cols) -0.5 + iterate; + iterate.n_rows, iterate.n_cols) - 0.5 + iterate; // Constrain all genes to be within bounds. individual = arma::min(arma::max(individual, castedLowerBound), castedUpperBound); From 7505121ee6985a3b9ae0d907b42537a9aa37b9ca Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Fri, 11 Jun 2021 23:08:28 +0530 Subject: [PATCH 098/128] Update include/ensmallen_bits/moead/moead_impl.hpp Co-authored-by: Marcus Edel --- include/ensmallen_bits/moead/moead_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 2fb2db6f6..26fe593f5 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -108,7 +108,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple if (lowerBound.n_rows == 1) lowerBound = lowerBound(0, 0) * arma::ones(iterate.n_rows, iterate.n_cols); - // Check if lower bound is a vector of a single dimension. + // Check if upper bound is a vector of a single dimension. if (upperBound.n_rows == 1) upperBound = upperBound(0, 0) * arma::ones(iterate.n_rows, iterate.n_cols); From 0828c7bfe490fe54920b6ea669bf569d4eef531c Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Fri, 11 Jun 2021 23:08:45 +0530 Subject: [PATCH 099/128] Update include/ensmallen_bits/moead/moead_impl.hpp Co-authored-by: Marcus Edel --- include/ensmallen_bits/moead/moead_impl.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 26fe593f5..06317718b 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -213,7 +213,6 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple arma::randu() * (castedUpperBound(geneIdx) - population[r1](geneIdx)); } } - else candidate(geneIdx) = population[r1](geneIdx); } From 4e4fa69b08c3eef0a79657c920641365e2d9f566 Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Fri, 11 Jun 2021 23:08:56 +0530 Subject: [PATCH 100/128] Update include/ensmallen_bits/moead/moead_impl.hpp Co-authored-by: Marcus Edel --- include/ensmallen_bits/moead/moead_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 06317718b..d1d843af3 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -342,7 +342,7 @@ inline void MOEAD::Mutate(MatType& candidate, const MatType& upperBound) { size_t numVariables = candidate.n_rows; - for (size_t geneIdx=0; geneIdx < numVariables; ++geneIdx) + for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) { // Should this gene be mutated? if (arma::randu() > mutationRate) From 3404708708e362b66379b50ce1d83d809752d9b6 Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Fri, 11 Jun 2021 23:09:09 +0530 Subject: [PATCH 101/128] Update include/ensmallen_bits/moead/moead_impl.hpp Co-authored-by: Marcus Edel --- include/ensmallen_bits/moead/moead_impl.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index d1d843af3..ca71753a5 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -357,9 +357,9 @@ inline void MOEAD::Mutate(MatType& candidate, double value, perturbationFactor; if(rand < 0.5) { - value = 2. * rand + (1. - 2. * rand) * + value = 2.0 * rand + (1.0 - 2. * rand) * std::pow(upperDelta, distributionIndex + 1.0); - perturbationFactor = std::pow(value, mutationPower) - 1.; + perturbationFactor = std::pow(value, mutationPower) - 1.0; } else { From 4824e72f93d6e85ffdb5ad357772419712ae00a4 Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Fri, 11 Jun 2021 23:09:17 +0530 Subject: [PATCH 102/128] Update include/ensmallen_bits/moead/moead_impl.hpp Co-authored-by: Marcus Edel --- include/ensmallen_bits/moead/moead_impl.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index ca71753a5..5219163ba 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -363,9 +363,9 @@ inline void MOEAD::Mutate(MatType& candidate, } else { - value = 2. * (1. - rand) + 2.*(rand - 0.5) * + value = 2.0 * (1.0 - rand) + 2.0 *(rand - 0.5) * std::pow(lowerDelta, distributionIndex + 1.0); - perturbationFactor = 1. - std::pow(value, mutationPower); + perturbationFactor = 1.0 - std::pow(value, mutationPower); } candidate[geneIdx] += perturbationFactor * geneRange; From 9d93405f5b6665d814973e383643bf3f524bdd09 Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Sat, 12 Jun 2021 00:23:02 +0530 Subject: [PATCH 103/128] Update moead_impl.hpp delta should be generated per gene. --- include/ensmallen_bits/moead/moead_impl.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 5219163ba..93bce6905 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -192,9 +192,10 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // 2.2 - 2.3 Reproduction and Repair: Differential Operator followed by // Polynomial Mutation. BaseMatType candidate(iterate.n_rows, iterate.n_cols); - double delta = arma::randu(); + for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) { + const double delta = arma::randu(); if (delta < crossoverProb) { candidate(geneIdx) = population[r1](geneIdx) + From cf850f50d16622de4969c5b750a847e2f004eb73 Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Sat, 12 Jun 2021 00:23:33 +0530 Subject: [PATCH 104/128] Update moead_impl.hpp pick is const --- include/ensmallen_bits/moead/moead_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 93bce6905..fe3e5cb7c 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -247,7 +247,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple if (replaceCounter >= maxReplace) break; - size_t pick = sampleNeighbor ? neighborIndices(idx, subProblemIdx) : idx; + const size_t pick = sampleNeighbor ? neighborIndices(idx, subProblemIdx) : idx; ElemType candidateDecomposition = DecomposeObjectives( weights.col(pick), idealPoint, candidateFitness); From 27404cdaad554457c0f50654dee51804b9e2456c Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Sat, 12 Jun 2021 00:25:33 +0530 Subject: [PATCH 105/128] Update moead_impl.hpp --- include/ensmallen_bits/moead/moead_impl.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index fe3e5cb7c..7718561e8 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -323,7 +323,9 @@ MOEAD::MatingSelection(size_t subProblemIdx, ? neighborIndices( arma::randi(arma::distr_param(0, neighborSize - 1u)), subProblemIdx) : arma::randi(arma::distr_param(0, populationSize - 1u)); - + + //! If the sampled points are equal, then modify one of them + //! within reasonable bounds. if (k == l) { if (k == populationSize - 1u) From ad9f355503df3b0c94bf8e05e09b7bd3333f89e3 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 12 Jun 2021 08:32:22 +0530 Subject: [PATCH 106/128] Mating more clear --- include/ensmallen_bits/moead/moead.hpp | 2 +- include/ensmallen_bits/moead/moead_impl.hpp | 23 ++++++++++----------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 55127c5eb..3bafe89a4 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -202,7 +202,7 @@ class MOEAD { * @param neighborSize A matrix containing indices of the neighbors. * @return std::tuple The chosen pair of indices. */ - std::tuple MatingSelection(size_t subProblemIdx, + std::tuple Mating(size_t subProblemIdx, const arma::umat& neighborSize, bool sampleNeighbor); diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 7718561e8..3f5d1dc58 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -187,12 +187,12 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // Randomly choose to sample from the population or the neighbors. bool sampleNeighbor = arma::randu() < neighborProb; std::tie(r2, r3) = - MatingSelection(subProblemIdx, neighborIndices, sampleNeighbor); + Mating(subProblemIdx, neighborIndices, sampleNeighbor); // 2.2 - 2.3 Reproduction and Repair: Differential Operator followed by // Polynomial Mutation. BaseMatType candidate(iterate.n_rows, iterate.n_cols); - + for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) { const double delta = arma::randu(); @@ -308,30 +308,29 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple //! Randomly chooses to select from parents or neighbors. inline std::tuple -MOEAD::MatingSelection(size_t subProblemIdx, +MOEAD::Mating(size_t subProblemIdx, const arma::umat& neighborIndices, bool sampleNeighbor) { - size_t k, l; - - k = sampleNeighbor + //! Indexes of two points from the sample space. + size_t pointA = sampleNeighbor ? neighborIndices( arma::randi(arma::distr_param(0, neighborSize - 1u)), subProblemIdx) : arma::randi(arma::distr_param(0, populationSize - 1u)); - l = sampleNeighbor + size_t pointB = sampleNeighbor ? neighborIndices( arma::randi(arma::distr_param(0, neighborSize - 1u)), subProblemIdx) : arma::randi(arma::distr_param(0, populationSize - 1u)); - + //! If the sampled points are equal, then modify one of them //! within reasonable bounds. - if (k == l) + if (pointA == pointB) { - if (k == populationSize - 1u) - --k; + if (pointA == populationSize - 1u) + --pointA; else - ++k; + ++pointA; } return std::make_tuple(k, l); From 80fbf6c9e803c747b517ea46edbd89fa28460a67 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 12 Jun 2021 08:46:30 +0530 Subject: [PATCH 107/128] Mate fix --- include/ensmallen_bits/moead/moead_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 3f5d1dc58..c23ff3a52 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -333,7 +333,7 @@ MOEAD::Mating(size_t subProblemIdx, ++pointA; } - return std::make_tuple(k, l); + return std::make_tuple(pointA, pointB); } //! Perform Polynomial mutation of the candidate. From 1dadc1bbb0bcb5f516dd69bb02d0b711268716f9 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 12 Jun 2021 08:46:53 +0530 Subject: [PATCH 108/128] delta indent fix --- include/ensmallen_bits/moead/moead_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index c23ff3a52..2b57ca2b0 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -195,7 +195,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) { - const double delta = arma::randu(); + const double delta = arma::randu(); if (delta < crossoverProb) { candidate(geneIdx) = population[r1](geneIdx) + From 604209a0f7bd12e87a8b4f6a7e6f5dbd56895e2e Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 12 Jun 2021 09:00:30 +0530 Subject: [PATCH 109/128] added epsilon --- include/ensmallen_bits/moead/moead.hpp | 17 +++++++++++++++-- include/ensmallen_bits/moead/moead_impl.hpp | 6 +++++- tests/moead_test.cpp | 8 ++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 3bafe89a4..03efffcb0 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -66,19 +66,21 @@ class MOEAD { * @param differentialWeight A parameter used in the mutation of candidate * solutions controls amplification factor of the differentiation. * @param maxReplace The limit of solutions allowed to be replaced by a child. + * @param epsilon Handle numerical stability after weight initialization. * @param lowerBound The lower bound on each variable of a member * of the variable space. * @param upperBound The upper bound on each variable of a member * of the variable space. */ MOEAD(const size_t populationSize = 150, - const size_t maxGenerations = 1000, + const size_t maxGenerations = 300, const double crossoverProb = 1.0, const size_t neighborSize = 20, const double distributionIndex = 20, const double neighborProb = 0.9, const double differentialWeight = 0.5, const size_t maxReplace = 2, + const double epsilon = 1E-10, const arma::vec& lowerBound = arma::zeros(1, 1), const arma::vec& upperBound = arma::ones(1, 1)); @@ -101,19 +103,21 @@ class MOEAD { * @param differentialWeight A parameter used in the mutation of candidate * solutions controls amplification factor of the differentiation. * @param maxReplace The limit of solutions allowed to be replaced by a child. + * @param epsilon Handle numerical stability after weight initialization. * @param lowerBound The lower bound on each variable of a member * of the variable space. * @param upperBound The upper bound on each variable of a member * of the variable space. */ MOEAD(const size_t populationSize = 150, - const size_t maxGenerations = 1000, + const size_t maxGenerations = 300, const double crossoverProb = 1.0, const size_t neighborSize = 20, const double distributionIndex = 20, const double neighborProb = 0.9, const double differentialWeight = 0.5, const size_t maxReplace = 2, + const double epsilon = 1E-10, const double lowerBound = 0, const double upperBound = 1); @@ -175,6 +179,11 @@ class MOEAD { //! Modify value of maxReplace. size_t& MaxReplace() { return maxReplace; } + //! Retrieve value of epsilon. + double Epsilon() const { return epsilon; } + //! Modify value of maxReplace. + double& Epsilon() { return epsilon; } + //! Retrieve value of lowerBound. const arma::vec& LowerBound() const { return lowerBound; } //! Modify value of lowerBound. @@ -290,6 +299,10 @@ class MOEAD { //! leads to a loss of diversity. size_t maxReplace; + //! A small numeric value to be added to the weights after initialization. + //! Prevents zero value inside inited weights. + double epsilon; + //! Lower bound on each variable in the variable space. arma::vec lowerBound; diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 2b57ca2b0..ca7b85f90 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -28,6 +28,7 @@ inline MOEAD::MOEAD(const size_t populationSize, const double neighborProb, const double differentialWeight, const size_t maxReplace, + const double epsilon, const arma::vec& lowerBound, const arma::vec& upperBound) : populationSize(populationSize), @@ -38,6 +39,7 @@ inline MOEAD::MOEAD(const size_t populationSize, neighborProb(neighborProb), differentialWeight(differentialWeight), maxReplace(maxReplace), + epsilon(epsilon), lowerBound(lowerBound), upperBound(upperBound), numObjectives(0) @@ -51,6 +53,7 @@ inline MOEAD::MOEAD(const size_t populationSize, const double neighborProb, const double differentialWeight, const size_t maxReplace, + const double epsilon, const double lowerBound, const double upperBound) : populationSize(populationSize), @@ -61,6 +64,7 @@ inline MOEAD::MOEAD(const size_t populationSize, neighborProb(neighborProb), differentialWeight(differentialWeight), maxReplace(maxReplace), + epsilon(epsilon), lowerBound(lowerBound * arma::ones(1, 1)), upperBound(upperBound * arma::ones(1, 1)), numObjectives(0) @@ -131,7 +135,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple arma::uvec shuffle; // The weight matrix. Each vector represents a decomposition subproblem (M X N). arma::Mat weights(numObjectives, populationSize, arma::fill::randu); - weights += 1E-10; // Numerical stability + weights += epsilon; // Numerical stability // 1.1 Storing the indices of nearest neighbors of each weight vector. arma::umat neighborIndices(neighborSize, populationSize); diff --git a/tests/moead_test.cpp b/tests/moead_test.cpp index 7582601c8..eca693aa2 100644 --- a/tests/moead_test.cpp +++ b/tests/moead_test.cpp @@ -56,6 +56,7 @@ TEST_CASE("MOEADSchafferN1DoubleTest", "[MOEADTest]") 0.9, // Probability of sampling from neighbor. 0.5, // Differential weight. 2, // Max childrens to replace parents. + 1E-10, // epsilon. lowerBound, // Lower bound. upperBound // Upper bound. ); @@ -117,6 +118,7 @@ TEST_CASE("MOEADSchafferN1TestVectorDoubleBounds", "[MOEADTest]") 0.9, // Probability of sampling from neighbor. 0.5, // Differential weight. 2, // Max childrens to replace parents. + 1E-10, // epsilon. lowerBound, // Lower bound. upperBound // Upper bound. ); @@ -176,6 +178,7 @@ TEST_CASE("MOEADFonsecaFlemingDoubleTest", "[MOEADTest]") 0.9, // Probability of sampling from neighbor. 0.5, // Differential weight. 2, // Max childrens to replace parents. + 1E-10, // epsilon. lowerBound, // Lower bound. upperBound // Upper bound. ); @@ -230,6 +233,7 @@ TEST_CASE("MOEADFonsecaFlemingTestVectorDoubleBounds", "[MOEADTest]") 0.9, // Probability of sampling from neighbor. 0.5, // Differential weight. 2, // Max childrens to replace parents. + 1E-10, // epsilon. lowerBound, // Lower bound. upperBound // Upper bound. ); @@ -284,6 +288,7 @@ TEST_CASE("MOEADSchafferN1FloatTest", "[MOEADTest]") 0.9, // Probability of sampling from neighbor. 0.5, // Differential weight. 2, // Max childrens to replace parents. + 1E-10, // epsilon. lowerBound, // Lower bound. upperBound // Upper bound. ); @@ -345,6 +350,7 @@ TEST_CASE("MOEADSchafferN1TestVectorFloatBounds", "[MOEADTest]") 0.9, // Probability of sampling from neighbor. 0.5, // Differential weight. 2, // Max childrens to replace parents. + 1E-10, // epsilon. lowerBound, // Lower bound. upperBound // Upper bound. ); @@ -404,6 +410,7 @@ TEST_CASE("MOEADFonsecaFlemingFloatTest", "[MOEADTest]") 0.9, // Probability of sampling from neighbor. 0.5, // Differential weight. 2, // Max childrens to replace parents. + 1E-10, // epsilon. lowerBound, // Lower bound. upperBound // Upper bound. ); @@ -458,6 +465,7 @@ TEST_CASE("MOEADFonsecaFlemingTestVectorFloatBounds", "[MOEADTest]") 0.9, // Probability of sampling from neighbor. 0.5, // Differential weight. 2, // Max childrens to replace parents. + 1E-10, // epsilon. lowerBound, // Lower bound. upperBound // Upper bound. ); From 81e07bf4555331c805e749212f878449d4cd8868 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 12 Jun 2021 09:37:21 +0530 Subject: [PATCH 110/128] minor style + numobjectives remvoed from opt --- include/ensmallen_bits/moead/moead.hpp | 9 ++--- include/ensmallen_bits/moead/moead_impl.hpp | 43 +++++++++++---------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 03efffcb0..89f13cc60 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -285,13 +285,13 @@ class MOEAD { //! Number of nearest neighbours of weights to consider. size_t neighborSize; + //! The probability that two elements will be chosen from the neighbor. + double neighborProb; + //! The crowding degree of the mutation. Higher value produces a mutant //! resembling its parent. double distributionIndex; - //! The probability that two elements will be chosen from the neighbor. - double neighborProb; - //! Amplification factor for differentiation. double differentialWeight; @@ -309,9 +309,6 @@ class MOEAD { //! Upper bound on each variable in the variable space. arma::vec upperBound; - //! The number of objectives in multi objective optimisation problem. - size_t numObjectives; - //! The set of all the Pareto optimal points. //! Stored after Optimize() is called. arma::cube paretoSet; diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index ca7b85f90..17343c39d 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -122,17 +122,16 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple assert(upperBound.n_rows == iterate.n_rows && "The dimensions of " "upperBound are not the same as the dimensions of iterate."); - numObjectives = sizeof...(ArbitraryFunctionType); - size_t numVariables = iterate.n_rows; + const size_t numObjectives = sizeof...(ArbitraryFunctionType); + const size_t numVariables = iterate.n_rows; //! Useful temporaries for float-like comparisons. - BaseMatType castedLowerBound = arma::conv_to::from(lowerBound); - BaseMatType castedUpperBound = arma::conv_to::from(upperBound); + const BaseMatType castedLowerBound = arma::conv_to::from(lowerBound); + const BaseMatType castedUpperBound = arma::conv_to::from(upperBound); // Controls early termination of the optimization process. bool terminate = false; - arma::uvec shuffle; // The weight matrix. Each vector represents a decomposition subproblem (M X N). arma::Mat weights(numObjectives, populationSize, arma::fill::randu); weights += epsilon; // Numerical stability @@ -142,8 +141,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple for (size_t i = 0; i < populationSize; ++i) { // Cache the distance between weights(i) and other weights. - arma::Row distances(populationSize); - distances = + arma::Row distances = arma::sqrt(arma::sum(arma::square(weights.col(i) - weights.each_col()))); arma::uvec sortedIndices = arma::stable_sort_index(distances); // Ignore distance from self. @@ -180,7 +178,8 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // 2 The main loop. for (size_t generation = 1; generation <= maxGenerations && !terminate; ++generation) { - shuffle = arma::shuffle( + // Shuffle indexes of subproblems. + const arma::uvec shuffle = arma::shuffle( arma::linspace(0, populationSize - 1, populationSize)); for (size_t subProblemIdx : shuffle) { @@ -189,7 +188,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple size_t r1, r2, r3; r1 = subProblemIdx; // Randomly choose to sample from the population or the neighbors. - bool sampleNeighbor = arma::randu() < neighborProb; + const bool sampleNeighbor = arma::randu() < neighborProb; std::tie(r2, r3) = Mating(subProblemIdx, neighborIndices, sampleNeighbor); @@ -210,23 +209,26 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple if (candidate(geneIdx) < castedLowerBound(geneIdx)) { candidate(geneIdx) = castedLowerBound(geneIdx) + - arma::randu() * (population[r1](geneIdx) - castedLowerBound(geneIdx)); + arma::randu() * (population[r1](geneIdx) - + castedLowerBound(geneIdx)); } if (candidate(geneIdx) > castedUpperBound(geneIdx)) { candidate(geneIdx) = castedUpperBound(geneIdx) - - arma::randu() * (castedUpperBound(geneIdx) - population[r1](geneIdx)); + arma::randu() * (castedUpperBound(geneIdx) - + population[r1](geneIdx)); } } else candidate(geneIdx) = population[r1](geneIdx); } - Mutate(candidate, 1.0 / static_cast(numVariables), castedLowerBound, castedUpperBound); + Mutate(candidate, 1.0 / static_cast(numVariables), + castedLowerBound, castedUpperBound); arma::Col candidateFitness(numObjectives); //! Creating temp vectors to pass to EvaluateObjectives. - std::vector candidateContainer{ candidate }; + std::vector candidateContainer { candidate }; std::vector> fitnessContainer { candidateFitness }; EvaluateObjectives(candidateContainer, objectives, fitnessContainer); candidateFitness = std::move(fitnessContainer[0]); @@ -238,10 +240,10 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple idealPoint = arma::min(idealPoint, candidateFitness); // 2.5 Update of the population. - size_t replaceCounter = 0; - size_t sampleSize = sampleNeighbor ? neighborSize : populationSize; + size_t replaceCounter {0}; + const size_t sampleSize = sampleNeighbor ? neighborSize : populationSize; - arma::uvec idxShuffle = arma::shuffle( + const arma::uvec idxShuffle = arma::shuffle( arma::linspace(0, sampleSize - 1, sampleSize)); for (size_t idx : idxShuffle) @@ -251,11 +253,12 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple if (replaceCounter >= maxReplace) break; - const size_t pick = sampleNeighbor ? neighborIndices(idx, subProblemIdx) : idx; + const size_t pick = sampleNeighbor ? + neighborIndices(idx, subProblemIdx) : idx; - ElemType candidateDecomposition = DecomposeObjectives( + const ElemType candidateDecomposition = DecomposeObjectives( weights.col(pick), idealPoint, candidateFitness); - ElemType parentDecomposition = DecomposeObjectives( + const ElemType parentDecomposition = DecomposeObjectives( weights.col(pick), idealPoint, populationFitness[pick]); if (candidateDecomposition < parentDecomposition) @@ -347,7 +350,7 @@ inline void MOEAD::Mutate(MatType& candidate, const MatType& lowerBound, const MatType& upperBound) { - size_t numVariables = candidate.n_rows; + const size_t numVariables = candidate.n_rows; for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) { // Should this gene be mutated? From a646f7c1361499e46355a71d35c96f8bf1854421 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 12 Jun 2021 09:55:29 +0530 Subject: [PATCH 111/128] re-ordered state variables --- include/ensmallen_bits/moead/moead.hpp | 14 +++++++------- include/ensmallen_bits/moead/moead_impl.hpp | 14 ++++++-------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 89f13cc60..2b462cc9b 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -59,10 +59,10 @@ class MOEAD { * @param populationSize The number of elements in the population. * @param maxGenerations The maximum number of generations allowed. * @param crossoverProb The probability that a crossover will occur. + * @param neighborProb The probability of sampling from neighbor. * @param neighborSize The number of nearest neighbours of weights * to find. * @param distributionIndex The crowding degree of the mutation. - * @param neighborProb The probability of sampling from neighbor. * @param differentialWeight A parameter used in the mutation of candidate * solutions controls amplification factor of the differentiation. * @param maxReplace The limit of solutions allowed to be replaced by a child. @@ -75,9 +75,9 @@ class MOEAD { MOEAD(const size_t populationSize = 150, const size_t maxGenerations = 300, const double crossoverProb = 1.0, + const double neighborProb = 0.9, const size_t neighborSize = 20, const double distributionIndex = 20, - const double neighborProb = 0.9, const double differentialWeight = 0.5, const size_t maxReplace = 2, const double epsilon = 1E-10, @@ -96,10 +96,10 @@ class MOEAD { * @param populationSize The number of elements in the population. * @param maxGenerations The maximum number of generations allowed. * @param crossoverProb The probability that a crossover will occur. + * @param neighborProb The probability of sampling from neighbor. * @param neighborSize The number of nearest neighbours of weights * to find. * @param distributionIndex The crowding degree of the mutation. - * @param neighborProb The probability of sampling from neighbor. * @param differentialWeight A parameter used in the mutation of candidate * solutions controls amplification factor of the differentiation. * @param maxReplace The limit of solutions allowed to be replaced by a child. @@ -112,9 +112,9 @@ class MOEAD { MOEAD(const size_t populationSize = 150, const size_t maxGenerations = 300, const double crossoverProb = 1.0, + const double neighborProb = 0.9, const size_t neighborSize = 20, const double distributionIndex = 20, - const double neighborProb = 0.9, const double differentialWeight = 0.5, const size_t maxReplace = 2, const double epsilon = 1E-10, @@ -282,12 +282,12 @@ class MOEAD { //! Probability of crossover between two members. double crossoverProb; - //! Number of nearest neighbours of weights to consider. - size_t neighborSize; - //! The probability that two elements will be chosen from the neighbor. double neighborProb; + //! Number of nearest neighbours of weights to consider. + size_t neighborSize; + //! The crowding degree of the mutation. Higher value produces a mutant //! resembling its parent. double distributionIndex; diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 17343c39d..1d7cdc836 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -23,9 +23,9 @@ namespace ens { inline MOEAD::MOEAD(const size_t populationSize, const size_t maxGenerations, const double crossoverProb, + const double neighborProb, const size_t neighborSize, const double distributionIndex, - const double neighborProb, const double differentialWeight, const size_t maxReplace, const double epsilon, @@ -34,23 +34,22 @@ inline MOEAD::MOEAD(const size_t populationSize, populationSize(populationSize), maxGenerations(maxGenerations), crossoverProb(crossoverProb), + neighborProb(neighborProb), neighborSize(neighborSize), distributionIndex(distributionIndex), - neighborProb(neighborProb), differentialWeight(differentialWeight), maxReplace(maxReplace), epsilon(epsilon), lowerBound(lowerBound), - upperBound(upperBound), - numObjectives(0) + upperBound(upperBound) { /* Nothing to do here. */ } inline MOEAD::MOEAD(const size_t populationSize, const size_t maxGenerations, const double crossoverProb, + const double neighborProb, const size_t neighborSize, const double distributionIndex, - const double neighborProb, const double differentialWeight, const size_t maxReplace, const double epsilon, @@ -59,15 +58,14 @@ inline MOEAD::MOEAD(const size_t populationSize, populationSize(populationSize), maxGenerations(maxGenerations), crossoverProb(crossoverProb), + neighborProb(neighborProb), neighborSize(neighborSize), distributionIndex(distributionIndex), - neighborProb(neighborProb), differentialWeight(differentialWeight), maxReplace(maxReplace), epsilon(epsilon), lowerBound(lowerBound * arma::ones(1, 1)), - upperBound(upperBound * arma::ones(1, 1)), - numObjectives(0) + upperBound(upperBound * arma::ones(1, 1)) { /* Nothing to do here. */ } //! Optimize the function. From 3267c42e4d4908aadd17d4de068f3ef70b70818a Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 12 Jun 2021 09:58:26 +0530 Subject: [PATCH 112/128] RequireDenseFloatingCheck --- include/ensmallen_bits/moead/moead_impl.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 1d7cdc836..894868a33 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -89,6 +89,11 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple BaseMatType& iterate = (BaseMatType&) iterateIn; + // Make sure that we have the methods that we need. Long name... + traits::CheckArbitraryFunctionTypeAPI(); + RequireDenseFloatingPointType(); + if (neighborSize < 2) { throw std::invalid_argument( From b0c4c1b7b12de9ad6b0b7ab1944f5fb181d6b3a1 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 12 Jun 2021 09:59:26 +0530 Subject: [PATCH 113/128] reorder tests --- tests/moead_test.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/moead_test.cpp b/tests/moead_test.cpp index eca693aa2..cb7e8643d 100644 --- a/tests/moead_test.cpp +++ b/tests/moead_test.cpp @@ -51,9 +51,9 @@ TEST_CASE("MOEADSchafferN1DoubleTest", "[MOEADTest]") 150, // Population size. 300, // Max generations. 1.0, // Crossover probability. + 0.9, // Probability of sampling from neighbor. 20, // Neighborhood size. 20, // Perturbation index. - 0.9, // Probability of sampling from neighbor. 0.5, // Differential weight. 2, // Max childrens to replace parents. 1E-10, // epsilon. @@ -113,9 +113,9 @@ TEST_CASE("MOEADSchafferN1TestVectorDoubleBounds", "[MOEADTest]") 150, // Population size. 300, // Max generations. 1.0, // Crossover probability. + 0.9, // Probability of sampling from neighbor. 20, // Neighborhood size. 20, // Perturbation index. - 0.9, // Probability of sampling from neighbor. 0.5, // Differential weight. 2, // Max childrens to replace parents. 1E-10, // epsilon. @@ -173,9 +173,9 @@ TEST_CASE("MOEADFonsecaFlemingDoubleTest", "[MOEADTest]") 150, // Population size. 300, // Max generations. 1.0, // Crossover probability. + 0.9, // Probability of sampling from neighbor. 20, // Neighborhood size. 20, // Perturbation index. - 0.9, // Probability of sampling from neighbor. 0.5, // Differential weight. 2, // Max childrens to replace parents. 1E-10, // epsilon. @@ -228,9 +228,9 @@ TEST_CASE("MOEADFonsecaFlemingTestVectorDoubleBounds", "[MOEADTest]") 150, // Population size. 300, // Max generations. 1.0, // Crossover probability. + 0.9, // Probability of sampling from neighbor. 20, // Neighborhood size. 20, // Perturbation index. - 0.9, // Probability of sampling from neighbor. 0.5, // Differential weight. 2, // Max childrens to replace parents. 1E-10, // epsilon. @@ -283,9 +283,9 @@ TEST_CASE("MOEADSchafferN1FloatTest", "[MOEADTest]") 150, // Population size. 300, // Max generations. 1.0, // Crossover probability. + 0.9, // Probability of sampling from neighbor. 20, // Neighborhood size. 20, // Perturbation index. - 0.9, // Probability of sampling from neighbor. 0.5, // Differential weight. 2, // Max childrens to replace parents. 1E-10, // epsilon. @@ -345,9 +345,9 @@ TEST_CASE("MOEADSchafferN1TestVectorFloatBounds", "[MOEADTest]") 150, // Population size. 300, // Max generations. 1.0, // Crossover probability. + 0.9, // Probability of sampling from neighbor. 20, // Neighborhood size. 20, // Perturbation index. - 0.9, // Probability of sampling from neighbor. 0.5, // Differential weight. 2, // Max childrens to replace parents. 1E-10, // epsilon. @@ -405,9 +405,9 @@ TEST_CASE("MOEADFonsecaFlemingFloatTest", "[MOEADTest]") 150, // Population size. 300, // Max generations. 1.0, // Crossover probability. + 0.9, // Probability of sampling from neighbor. 20, // Neighborhood size. 20, // Perturbation index. - 0.9, // Probability of sampling from neighbor. 0.5, // Differential weight. 2, // Max childrens to replace parents. 1E-10, // epsilon. @@ -460,9 +460,9 @@ TEST_CASE("MOEADFonsecaFlemingTestVectorFloatBounds", "[MOEADTest]") 150, // Population size. 300, // Max generations. 1.0, // Crossover probability. + 0.9, // Probability of sampling from neighbor. 20, // Neighborhood size. 20, // Perturbation index. - 0.9, // Probability of sampling from neighbor. 0.5, // Differential weight. 2, // Max childrens to replace parents. 1E-10, // epsilon. From aa54aade4aa50013d894f6738e054d7428505de3 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 12 Jun 2021 10:02:13 +0530 Subject: [PATCH 114/128] BaseMatType --- include/ensmallen_bits/moead/moead_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 894868a33..c4ba0fec8 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -136,7 +136,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple bool terminate = false; // The weight matrix. Each vector represents a decomposition subproblem (M X N). - arma::Mat weights(numObjectives, populationSize, arma::fill::randu); + BaseMatType weights(numObjectives, populationSize, arma::fill::randu); weights += epsilon; // Numerical stability // 1.1 Storing the indices of nearest neighbors of each weight vector. From 5d9e73c13934b519cc117981b9ac74f997faef31 Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Sat, 12 Jun 2021 10:14:42 +0530 Subject: [PATCH 115/128] Update moead_impl.hpp Another day, another indent --- include/ensmallen_bits/moead/moead_impl.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index c4ba0fec8..d9feace8c 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -145,7 +145,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple { // Cache the distance between weights(i) and other weights. arma::Row distances = - arma::sqrt(arma::sum(arma::square(weights.col(i) - weights.each_col()))); + arma::sqrt(arma::sum(arma::square(weights.col(i) - weights.each_col()))); arma::uvec sortedIndices = arma::stable_sort_index(distances); // Ignore distance from self. neighborIndices.col(i) = sortedIndices(arma::span(1, neighborSize)); @@ -155,11 +155,11 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple std::vector population(populationSize); for (BaseMatType& individual : population) { - individual = arma::randu( - iterate.n_rows, iterate.n_cols) - 0.5 + iterate; + individual = arma::randu( + iterate.n_rows, iterate.n_cols) - 0.5 + iterate; - // Constrain all genes to be within bounds. - individual = arma::min(arma::max(individual, castedLowerBound), castedUpperBound); + // Constrain all genes to be within bounds. + individual = arma::min(arma::max(individual, castedLowerBound), castedUpperBound); } Info << "MOEA/D-DE initialized successfully. Optimization started." << std::endl; @@ -193,7 +193,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // Randomly choose to sample from the population or the neighbors. const bool sampleNeighbor = arma::randu() < neighborProb; std::tie(r2, r3) = - Mating(subProblemIdx, neighborIndices, sampleNeighbor); + Mating(subProblemIdx, neighborIndices, sampleNeighbor); // 2.2 - 2.3 Reproduction and Repair: Differential Operator followed by // Polynomial Mutation. @@ -319,8 +319,8 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple //! Randomly chooses to select from parents or neighbors. inline std::tuple MOEAD::Mating(size_t subProblemIdx, - const arma::umat& neighborIndices, - bool sampleNeighbor) + const arma::umat& neighborIndices, + bool sampleNeighbor) { //! Indexes of two points from the sample space. size_t pointA = sampleNeighbor From 287bf825fa8c356a4a51f6d485f2782b2b39abce Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 12 Jun 2021 10:20:49 +0530 Subject: [PATCH 116/128] style fix --- include/ensmallen_bits/moead/moead_impl.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index d9feace8c..28fb5d3de 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -143,9 +143,9 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple arma::umat neighborIndices(neighborSize, populationSize); for (size_t i = 0; i < populationSize; ++i) { - // Cache the distance between weights(i) and other weights. + // Cache the distance between weights[i] and other weights. arma::Row distances = - arma::sqrt(arma::sum(arma::square(weights.col(i) - weights.each_col()))); + arma::sqrt(arma::sum(arma::square(weights.col(i) - weights.each_col()))); arma::uvec sortedIndices = arma::stable_sort_index(distances); // Ignore distance from self. neighborIndices.col(i) = sortedIndices(arma::span(1, neighborSize)); @@ -186,7 +186,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple arma::linspace(0, populationSize - 1, populationSize)); for (size_t subProblemIdx : shuffle) { - // 2.1 Randomly select two indices in neighborIndices(subProblemIdx) and use them + // 2.1 Randomly select two indices in neighborIndices[subProblemIdx] and use them // to make a child. size_t r1, r2, r3; r1 = subProblemIdx; @@ -360,10 +360,10 @@ inline void MOEAD::Mutate(MatType& candidate, if (arma::randu() > mutationRate) continue; - const double geneRange = upperBound[geneIdx] - lowerBound[geneIdx]; + const double geneRange = upperBound(geneIdx) - lowerBound(geneIdx); // Normalised distance from the bounds. - const double lowerDelta = (candidate[geneIdx] - lowerBound[geneIdx]) / geneRange; - const double upperDelta = (upperBound[geneIdx] - candidate[geneIdx]) / geneRange; + const double lowerDelta = (candidate(geneIdx) - lowerBound(geneIdx)) / geneRange; + const double upperDelta = (upperBound(geneIdx) - candidate(geneIdx)) / geneRange; const double mutationPower = 1. / (distributionIndex + 1.0); const double rand = arma::randu(); double value, perturbationFactor; @@ -380,7 +380,7 @@ inline void MOEAD::Mutate(MatType& candidate, perturbationFactor = 1.0 - std::pow(value, mutationPower); } - candidate[geneIdx] += perturbationFactor * geneRange; + candidate(geneIdx) += perturbationFactor * geneRange; } //! Enforce bounds. candidate= arma::min(arma::max(candidate, lowerBound), upperBound); From 60d19c48d7b3b2d662f4c6ca1f71fd876a9d473f Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 12 Jun 2021 10:21:19 +0530 Subject: [PATCH 117/128] if( --- include/ensmallen_bits/moead/moead_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 28fb5d3de..e8ae64363 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -367,7 +367,7 @@ inline void MOEAD::Mutate(MatType& candidate, const double mutationPower = 1. / (distributionIndex + 1.0); const double rand = arma::randu(); double value, perturbationFactor; - if(rand < 0.5) + if (rand < 0.5) { value = 2.0 * rand + (1.0 - 2. * rand) * std::pow(upperDelta, distributionIndex + 1.0); From edd089a72b3c21efe7d667bcc956f191255f9949 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 12 Jun 2021 10:22:03 +0530 Subject: [PATCH 118/128] 2. => 2.0 --- include/ensmallen_bits/moead/moead_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index e8ae64363..29d720256 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -369,7 +369,7 @@ inline void MOEAD::Mutate(MatType& candidate, double value, perturbationFactor; if (rand < 0.5) { - value = 2.0 * rand + (1.0 - 2. * rand) * + value = 2.0 * rand + (1.0 - 2.0 * rand) * std::pow(upperDelta, distributionIndex + 1.0); perturbationFactor = std::pow(value, mutationPower) - 1.0; } From b7178fef0e5ec159cd374619eeb0f0aff4c948db Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 12 Jun 2021 10:28:51 +0530 Subject: [PATCH 119/128] Added epsilon to docs --- doc/optimizers.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/doc/optimizers.md b/doc/optimizers.md index 657111b14..a9dfbe90d 100644 --- a/doc/optimizers.md +++ b/doc/optimizers.md @@ -1574,7 +1574,7 @@ a varied set of solution. #### Constructors * `MOEAD()` -* `MOEAD(`_`populationSize, maxGenerations, crossoverProb, neighborSize, distributionIndex, neighborProb, differentialWeight, maxReplace, lowerBound, upperBound`_`)` +* `MOEAD(`_`populationSize, maxGenerations, crossoverProb, neighborProb, neighborSize, distributionIndex, differentialWeight, maxReplace, epsilon, lowerBound, upperBound`_`)` #### Attributes @@ -1583,17 +1583,18 @@ a varied set of solution. | `size_t` | **`populationSize`** | The number of candidates in the population. | `150` | | `size_t` | **`maxGenerations`** | The maximum number of generations allowed. | `1000` | | `double` | **`crossoverProb`** | Probability that a crossover will occur. | `1.0` | +| `double` | **`neighborProb`** | The probability of sampling from neighbor. | `0.9` | | `size_t` | **`neighborSize`** | The number of nearest-neighbours to consider per weight vector. | `20` | | `double` | **`distributionIndex`** | The crowding degree of the mutation. | `20` | -| `double` | **`neighborProb`** | The probability of sampling from neighbor. | `0.9` | | `double` | **`differentialWeight`** | Amplification factor of the differentiation. | `0.5` | -| `size_t` | **`maxReplace`** | The limit of solutions allowed to be replaced by a child. | `2` | +| `size_t` | **`maxReplace`** | The limit of solutions allowed to be replaced by a child. | `2`| +| `double` | **`epsilon`** | Handles numerical stability after weight initialization. | `1E-10`| | `double`, `arma::vec` | **`lowerBound`** | Lower bound of the coordinates on the coordinates of the whole population during the search process. | `0` | | `double`, `arma::vec` | **`upperBound`** | Lower bound of the coordinates on the coordinates of the whole population during the search process. | `1` | Attributes of the optimizer may also be changed via the member methods -`PopulationSize()`, `MaxGenerations()`, `CrossoverRate()`, `NeighborSize()`, `DistributionIndex()`, -`NeighborProb()`, `DifferentialWeight()`, `MaxReplace()`, `LowerBound()` and `UpperBound()`. +`PopulationSize()`, `MaxGenerations()`, `CrossoverRate()`, `NeighborProb()`, `NeighborSize()`, `DistributionIndex()`, +`DifferentialWeight()`, `MaxReplace()`, `Epsilon()`, `LowerBound()` and `UpperBound()`. #### Examples: @@ -1605,7 +1606,7 @@ Attributes of the optimizer may also be changed via the member methods SchafferFunctionN1 SCH; arma::vec lowerBound("-10 -10"); arma::vec upperBound("10 10"); -MOEAD opt(150, 300, 1.0, 20, 20, 0.9, 0.5, 2, lowerBound, upperBound); +MOEAD opt(150, 300, 1.0, 0.9, 20, 20, 0.5, 2, 1E-10, lowerBound, upperBound); typedef decltype(SCH.objectiveA) ObjectiveTypeA; typedef decltype(SCH.objectiveB) ObjectiveTypeB; arma::mat coords = SCH.GetInitialPoint(); From 53cae18ff6338a7a73cc9c811411e5e57833f8e8 Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 12 Jun 2021 10:42:04 +0530 Subject: [PATCH 120/128] fix default arg in ctor fix callback test --- doc/optimizers.md | 2 +- tests/callbacks_test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/optimizers.md b/doc/optimizers.md index a9dfbe90d..103ff855d 100644 --- a/doc/optimizers.md +++ b/doc/optimizers.md @@ -1581,7 +1581,7 @@ a varied set of solution. | **type** | **name** | **description** | **default** | |----------|----------|-----------------|-------------| | `size_t` | **`populationSize`** | The number of candidates in the population. | `150` | -| `size_t` | **`maxGenerations`** | The maximum number of generations allowed. | `1000` | +| `size_t` | **`maxGenerations`** | The maximum number of generations allowed. | `300` | | `double` | **`crossoverProb`** | Probability that a crossover will occur. | `1.0` | | `double` | **`neighborProb`** | The probability of sampling from neighbor. | `0.9` | | `size_t` | **`neighborSize`** | The number of nearest-neighbours to consider per weight vector. | `20` | diff --git a/tests/callbacks_test.cpp b/tests/callbacks_test.cpp index 2354f52c4..924278f38 100644 --- a/tests/callbacks_test.cpp +++ b/tests/callbacks_test.cpp @@ -406,7 +406,7 @@ TEST_CASE("MOEADCallbacksFullFunctionTest", "[CallbackTest]") { arma::vec lowerBound = {-1000}; arma::vec upperBound = {1000}; - MOEAD optimizer(150, 300, 1.0, 20, 20, 0.9, 0.5, 2, lowerBound, upperBound); + MOEAD optimizer(150, 300, 1.0, 0.9, 20, 20, 0.5, 2, 1E-10, lowerBound, upperBound); CallbacksFullMultiobjectiveFunctionTest(optimizer, false, false, false, false, true, true, false, false, false, true); } From e893dfd3ee3bcb5abf5ae0d1ce06821b7dd7e8ee Mon Sep 17 00:00:00 2001 From: NanuSai Date: Sat, 12 Jun 2021 19:27:03 +0530 Subject: [PATCH 121/128] weights are fixed bruh --- include/ensmallen_bits/moead/moead_impl.hpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 29d720256..6803f985b 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -136,15 +136,15 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple bool terminate = false; // The weight matrix. Each vector represents a decomposition subproblem (M X N). - BaseMatType weights(numObjectives, populationSize, arma::fill::randu); - weights += epsilon; // Numerical stability + const BaseMatType weights = BaseMatType(numObjectives, populationSize, + arma::fill::randu) + epsilon; // 1.1 Storing the indices of nearest neighbors of each weight vector. arma::umat neighborIndices(neighborSize, populationSize); for (size_t i = 0; i < populationSize; ++i) { // Cache the distance between weights[i] and other weights. - arma::Row distances = + const arma::Row distances = arma::sqrt(arma::sum(arma::square(weights.col(i) - weights.each_col()))); arma::uvec sortedIndices = arma::stable_sort_index(distances); // Ignore distance from self. @@ -212,14 +212,12 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple if (candidate(geneIdx) < castedLowerBound(geneIdx)) { candidate(geneIdx) = castedLowerBound(geneIdx) + - arma::randu() * (population[r1](geneIdx) - - castedLowerBound(geneIdx)); + arma::randu() * (population[r1](geneIdx) - castedLowerBound(geneIdx)); } if (candidate(geneIdx) > castedUpperBound(geneIdx)) { candidate(geneIdx) = castedUpperBound(geneIdx) - - arma::randu() * (castedUpperBound(geneIdx) - - population[r1](geneIdx)); + arma::randu() * (castedUpperBound(geneIdx) - population[r1](geneIdx)); } } else From b1fa440fda5f62a66cf7becced5443922ef80ce4 Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Sun, 13 Jun 2021 09:15:39 +0530 Subject: [PATCH 122/128] Update include/ensmallen_bits/moead/moead_impl.hpp Co-authored-by: Marcus Edel --- include/ensmallen_bits/moead/moead_impl.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 6803f985b..568d57073 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -201,8 +201,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx) { - const double delta = arma::randu(); - if (delta < crossoverProb) + if (arma::randu() < crossoverProb) { candidate(geneIdx) = population[r1](geneIdx) + differentialWeight * (population[r2](geneIdx) - From a2a7ef166b7d469a8c0fcc153266f51f03ddbe83 Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Sun, 13 Jun 2021 09:16:03 +0530 Subject: [PATCH 123/128] Update include/ensmallen_bits/moead/moead_impl.hpp Co-authored-by: Marcus Edel --- include/ensmallen_bits/moead/moead_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 568d57073..bd1c48067 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -193,7 +193,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple // Randomly choose to sample from the population or the neighbors. const bool sampleNeighbor = arma::randu() < neighborProb; std::tie(r2, r3) = - Mating(subProblemIdx, neighborIndices, sampleNeighbor); + Mating(subProblemIdx, neighborIndices, sampleNeighbor); // 2.2 - 2.3 Reproduction and Repair: Differential Operator followed by // Polynomial Mutation. From 7d794cb4bc47f5d2a59d58e8830e14975d8f338c Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Sun, 13 Jun 2021 09:16:40 +0530 Subject: [PATCH 124/128] Update include/ensmallen_bits/moead/moead_impl.hpp Co-authored-by: Marcus Edel --- include/ensmallen_bits/moead/moead_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index bd1c48067..1a1b89911 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -156,7 +156,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple for (BaseMatType& individual : population) { individual = arma::randu( - iterate.n_rows, iterate.n_cols) - 0.5 + iterate; + iterate.n_rows, iterate.n_cols) - 0.5 + iterate; // Constrain all genes to be within bounds. individual = arma::min(arma::max(individual, castedLowerBound), castedUpperBound); From 40e44d4ede078d7347ee6d84874638c99e3afcb2 Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Sun, 13 Jun 2021 09:16:47 +0530 Subject: [PATCH 125/128] Update include/ensmallen_bits/moead/moead_impl.hpp Co-authored-by: Marcus Edel --- include/ensmallen_bits/moead/moead_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 1a1b89911..43054909a 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -380,7 +380,7 @@ inline void MOEAD::Mutate(MatType& candidate, candidate(geneIdx) += perturbationFactor * geneRange; } //! Enforce bounds. - candidate= arma::min(arma::max(candidate, lowerBound), upperBound); + candidate = arma::min(arma::max(candidate, lowerBound), upperBound); } //! Calculate the output for single objective function using the Tchebycheff From 5cd6bc8c29b02ef69632af9055e4e084355ce426 Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Sun, 13 Jun 2021 09:16:56 +0530 Subject: [PATCH 126/128] Update tests/moead_test.cpp Co-authored-by: Marcus Edel --- tests/moead_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/moead_test.cpp b/tests/moead_test.cpp index cb7e8643d..8e89872b0 100644 --- a/tests/moead_test.cpp +++ b/tests/moead_test.cpp @@ -133,7 +133,7 @@ TEST_CASE("MOEADSchafferN1TestVectorDoubleBounds", "[MOEADTest]") std::tuple objectives = SCH.GetObjectives(); opt.Optimize(objectives, coords); - arma::cube paretoSet= opt.ParetoSet(); + arma::cube paretoSet = opt.ParetoSet(); bool allInRange = true; @@ -497,4 +497,4 @@ TEST_CASE("MOEADFonsecaFlemingTestVectorFloatBounds", "[MOEADTest]") } REQUIRE(allInRange); -} \ No newline at end of file +} From da7683b770867355c8d9c5d03f3b5ed363931089 Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Sun, 13 Jun 2021 09:17:04 +0530 Subject: [PATCH 127/128] Update include/ensmallen_bits/moead/moead_impl.hpp Co-authored-by: Marcus Edel --- include/ensmallen_bits/moead/moead_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ensmallen_bits/moead/moead_impl.hpp b/include/ensmallen_bits/moead/moead_impl.hpp index 43054909a..26d08aa49 100644 --- a/include/ensmallen_bits/moead/moead_impl.hpp +++ b/include/ensmallen_bits/moead/moead_impl.hpp @@ -240,7 +240,7 @@ typename MatType::elem_type MOEAD::Optimize(std::tuple idealPoint = arma::min(idealPoint, candidateFitness); // 2.5 Update of the population. - size_t replaceCounter {0}; + size_t replaceCounter = 0; const size_t sampleSize = sampleNeighbor ? neighborSize : populationSize; const arma::uvec idxShuffle = arma::shuffle( From 973d4a7bccfa9a4dce3c02428dcffa3abbff2373 Mon Sep 17 00:00:00 2001 From: Nanubala Gnana Sai <45007169+jonpsy@users.noreply.github.com> Date: Sun, 13 Jun 2021 09:17:14 +0530 Subject: [PATCH 128/128] Update include/ensmallen_bits/moead/moead.hpp Co-authored-by: Marcus Edel --- include/ensmallen_bits/moead/moead.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/ensmallen_bits/moead/moead.hpp b/include/ensmallen_bits/moead/moead.hpp index 2b462cc9b..9fa34cc09 100644 --- a/include/ensmallen_bits/moead/moead.hpp +++ b/include/ensmallen_bits/moead/moead.hpp @@ -212,8 +212,8 @@ class MOEAD { * @return std::tuple The chosen pair of indices. */ std::tuple Mating(size_t subProblemIdx, - const arma::umat& neighborSize, - bool sampleNeighbor); + const arma::umat& neighborSize, + bool sampleNeighbor); /** * Mutate the child formed by the crossover of two random members of the