Skip to content

Commit b22e53f

Browse files
XueSongTaprcurtin
andauthored
Refactor calculatedObjectives in NSGA2 optimizer (#434)
* Refactor calculatedObjectives in NSGA2 optimizer Signed-off-by: yexiaochuan <[email protected]> * Use Mat instead of Cube. --------- Signed-off-by: yexiaochuan <[email protected]> Co-authored-by: Ryan Curtin <[email protected]>
1 parent a8f6e78 commit b22e53f

File tree

2 files changed

+56
-66
lines changed

2 files changed

+56
-66
lines changed

include/ensmallen_bits/nsga2/nsga2.hpp

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -203,30 +203,28 @@ class NSGA2
203203
*
204204
* @tparam ArbitraryFunctionType std::tuple of multiple function types.
205205
* @tparam InputMatType Type of matrix to optimize.
206-
* @tparam ObjectiveMatType Type of matrix to store objective values.
207206
* @param population The elite population.
208207
* @param objectives The set of objectives.
209-
* @param calculatedObjectives Vector to store calculated objectives.
208+
* @param calculatedObjectives Matrix to store calculated objectives (numObjectives x 1 x populationSize).
210209
*/
211210
template<std::size_t I = 0,
212-
typename InputMatType,
211+
typename MatType,
213212
typename ObjectiveMatType,
214213
typename ...ArbitraryFunctionType>
215214
typename std::enable_if<I == sizeof...(ArbitraryFunctionType), void>::type
216-
EvaluateObjectives(
217-
std::vector<InputMatType>&,
218-
std::tuple<ArbitraryFunctionType...>&,
219-
std::vector<ObjectiveMatType>&);
215+
EvaluateObjectives(std::vector<MatType>&,
216+
std::tuple<ArbitraryFunctionType...>&,
217+
ObjectiveMatType&);
220218

221219
template<std::size_t I = 0,
222-
typename InputMatType,
220+
typename MatType,
223221
typename ObjectiveMatType,
224222
typename ...ArbitraryFunctionType>
225223
typename std::enable_if<I < sizeof...(ArbitraryFunctionType), void>::type
226224
EvaluateObjectives(
227-
std::vector<InputMatType>& population,
225+
std::vector<MatType>& population,
228226
std::tuple<ArbitraryFunctionType...>& objectives,
229-
std::vector<ObjectiveMatType>& calculatedObjectives);
227+
ObjectiveMatType& calculatedObjectives);
230228

231229
/**
232230
* Reproduce candidates from the elite population to generate a new
@@ -285,11 +283,11 @@ class NSGA2
285283
* @param ranks The assigned ranks, used for crowding distance based sorting.
286284
* @param calculatedObjectives The previously calculated objectives.
287285
*/
288-
template<typename InputMatType, typename ObjectiveMatType>
286+
template<typename MatType>
289287
void FastNonDominatedSort(
290288
std::vector<std::vector<size_t> >& fronts,
291289
std::vector<size_t>& ranks,
292-
std::vector<ObjectiveMatType>& calculatedObjectives);
290+
MatType& calculatedObjectives);
293291

294292
/**
295293
* Operator to check if one candidate Pareto-dominates the other.
@@ -304,9 +302,9 @@ class NSGA2
304302
* @param candidateQ The candidate being compared against.
305303
* @return true if candidateP Pareto dominates candidateQ, otherwise, false.
306304
*/
307-
template<typename InputMatType, typename ObjectiveMatType>
305+
template<typename MatType>
308306
bool Dominates(
309-
std::vector<ObjectiveMatType>& calculatedObjectives,
307+
MatType& calculatedObjectives,
310308
size_t candidateP,
311309
size_t candidateQ);
312310

@@ -318,11 +316,11 @@ class NSGA2
318316
* @param crowdingDistance The crowding distance for each individual in
319317
* the population.
320318
*/
321-
template <typename InputMatType, typename ObjectiveMatType>
319+
template <typename MatType>
322320
void CrowdingDistanceAssignment(
323321
const std::vector<size_t>& front,
324-
std::vector<ObjectiveMatType>& calculatedObjectives,
325-
std::vector<typename InputMatType::elem_type>& crowdingDistance);
322+
MatType& calculatedObjectives,
323+
std::vector<typename MatType::elem_type>& crowdingDistance);
326324

327325
/**
328326
* The operator used in the crowding distance based sorting.

include/ensmallen_bits/nsga2/nsga2_impl.hpp

Lines changed: 41 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ typename MatType::elem_type NSGA2::Optimize(
9797
// Convenience typedefs.
9898
typedef typename MatType::elem_type ElemType;
9999
typedef typename MatTypeTraits<MatType>::BaseMatType BaseMatType;
100-
typedef typename ForwardType<MatType>::bcol BaseColType;
101100
typedef typename ForwardType<CubeType>::bmat CubeBaseMatType;
102101

103102
BaseMatType& iterate = (BaseMatType&) iterateIn;
@@ -124,8 +123,9 @@ typename MatType::elem_type NSGA2::Optimize(
124123
numObjectives = sizeof...(ArbitraryFunctionType);
125124
numVariables = iterate.n_rows;
126125

127-
// Cache calculated objectives.
128-
std::vector<BaseColType> calculatedObjectives(populationSize);
126+
// Cache calculated objectives as a matrix: (numObjectives x populationSize).
127+
arma::Mat<ElemType> calculatedObjectives(numObjectives, populationSize,
128+
arma::fill::zeros);
129129

130130
// Population size reserved to 2 * populationSize + 1 to accommodate
131131
// for the size of intermediate candidate population.
@@ -175,22 +175,20 @@ typename MatType::elem_type NSGA2::Optimize(
175175
BinaryTournamentSelection(population, castedLowerBound, castedUpperBound);
176176

177177
// Evaluate the objectives for the new population.
178-
calculatedObjectives.resize(population.size());
179-
std::fill(calculatedObjectives.begin(), calculatedObjectives.end(),
180-
BaseColType(numObjectives, GetFillType<MatType>::zeros));
178+
calculatedObjectives.zeros(numObjectives, population.size());
181179
EvaluateObjectives(population, objectives, calculatedObjectives);
182180

183181
// Perform fast non dominated sort on P_t ∪ G_t.
184182
ranks.resize(population.size());
185-
FastNonDominatedSort<BaseMatType>(fronts, ranks, calculatedObjectives);
183+
FastNonDominatedSort(fronts, ranks, calculatedObjectives);
186184

187185
// Perform crowding distance assignment.
188186
crowdingDistance.resize(population.size());
189187
std::fill(crowdingDistance.begin(), crowdingDistance.end(), 0.);
190188
for (size_t fNum = 0; fNum < fronts.size(); fNum++)
191189
{
192-
CrowdingDistanceAssignment<BaseMatType, BaseColType>(
193-
fronts[fNum], calculatedObjectives, crowdingDistance);
190+
CrowdingDistanceAssignment(fronts[fNum], calculatedObjectives,
191+
crowdingDistance);
194192
}
195193

196194
// Sort based on crowding distance.
@@ -234,12 +232,11 @@ typename MatType::elem_type NSGA2::Optimize(
234232
}
235233

236234
// Set the candidates from the Pareto Front as the output.
237-
paretoFrontIn.set_size(calculatedObjectives[0].n_rows,
238-
calculatedObjectives[0].n_cols, fronts[0].size());
235+
paretoFrontIn.set_size(calculatedObjectives.n_rows, 1, fronts[0].size());
239236
for (size_t solutionIdx = 0; solutionIdx < fronts[0].size(); ++solutionIdx)
240237
{
241238
paretoFrontIn.slice(solutionIdx) = conv_to<CubeBaseMatType>::from(
242-
calculatedObjectives[fronts[0][solutionIdx]]);
239+
calculatedObjectives.col(fronts[0][solutionIdx]));
243240
}
244241

245242
// Assign iterate to first element of the Pareto Set.
@@ -249,45 +246,43 @@ typename MatType::elem_type NSGA2::Optimize(
249246

250247
ElemType performance = std::numeric_limits<ElemType>::max();
251248

252-
for (const BaseColType& objective: calculatedObjectives)
253-
if (accu(objective) < performance)
254-
performance = accu(objective);
249+
for (size_t i = 0; i < calculatedObjectives.n_cols; ++i)
250+
performance = std::min(performance, arma::accu(calculatedObjectives.col(i)));
255251

256252
return performance;
257253
}
258254

259255
//! No objectives to evaluate.
260256
template<std::size_t I,
261-
typename InputMatType,
257+
typename MatType,
262258
typename ObjectiveMatType,
263259
typename ...ArbitraryFunctionType>
264260
typename std::enable_if<I == sizeof...(ArbitraryFunctionType), void>::type
265261
NSGA2::EvaluateObjectives(
266-
std::vector<InputMatType>&,
262+
std::vector<MatType>&,
267263
std::tuple<ArbitraryFunctionType...>&,
268-
std::vector<ObjectiveMatType>&)
264+
ObjectiveMatType&)
269265
{
270266
// Nothing to do here.
271267
}
272268

273269
//! Evaluate the objectives for the entire population.
274270
template<std::size_t I,
275-
typename InputMatType,
271+
typename MatType,
276272
typename ObjectiveMatType,
277273
typename ...ArbitraryFunctionType>
278274
typename std::enable_if<I < sizeof...(ArbitraryFunctionType), void>::type
279275
NSGA2::EvaluateObjectives(
280-
std::vector<InputMatType>& population,
276+
std::vector<MatType>& population,
281277
std::tuple<ArbitraryFunctionType...>& objectives,
282-
std::vector<ObjectiveMatType>& calculatedObjectives)
278+
ObjectiveMatType& calculatedObjectives)
283279
{
284280
for (size_t i = 0; i < populationSize; i++)
285281
{
286-
calculatedObjectives[i](I) = std::get<I>(objectives).Evaluate(
287-
population[i]);
288-
EvaluateObjectives<
289-
I + 1, InputMatType, ObjectiveMatType, ArbitraryFunctionType...>(
290-
population, objectives, calculatedObjectives);
282+
calculatedObjectives(I, i) =
283+
std::get<I>(objectives).Evaluate(population[i]);
284+
EvaluateObjectives<I + 1, MatType, ObjectiveMatType,
285+
ArbitraryFunctionType...>(population, objectives, calculatedObjectives);
291286
}
292287
}
293288

@@ -375,11 +370,11 @@ void NSGA2::Mutate(
375370
}
376371

377372
//! Sort population into Pareto fronts.
378-
template<typename InputMatType, typename ObjectiveMatType>
373+
template<typename MatType>
379374
void NSGA2::FastNonDominatedSort(
380375
std::vector<std::vector<size_t> >& fronts,
381376
std::vector<size_t>& ranks,
382-
std::vector<ObjectiveMatType>& calculatedObjectives)
377+
MatType& calculatedObjectives)
383378
{
384379
std::map<size_t, size_t> dominationCount;
385380
std::map<size_t, std::set<size_t> > dominated;
@@ -395,9 +390,9 @@ void NSGA2::FastNonDominatedSort(
395390

396391
for (size_t q = 0; q < populationSize; q++)
397392
{
398-
if (Dominates<InputMatType>(calculatedObjectives, p, q))
393+
if (Dominates<MatType>(calculatedObjectives, p, q))
399394
dominated[p].insert(q);
400-
else if (Dominates<InputMatType>(calculatedObjectives, q, p))
395+
else if (Dominates<MatType>(calculatedObjectives, q, p))
401396
dominationCount[p] += 1;
402397
}
403398

@@ -436,43 +431,43 @@ void NSGA2::FastNonDominatedSort(
436431
}
437432

438433
//! Check if a candidate Pareto dominates another candidate.
439-
template<typename InputMatType, typename ObjectiveMatType>
440-
bool NSGA2::Dominates(
441-
std::vector<ObjectiveMatType>& calculatedObjectives,
434+
template<typename MatType>
435+
inline bool NSGA2::Dominates(
436+
MatType& calculatedObjectives,
442437
size_t candidateP,
443438
size_t candidateQ)
444439
{
445440
bool allBetterOrEqual = true;
446441
bool atleastOneBetter = false;
447-
size_t n_objectives = calculatedObjectives[0].n_elem;
442+
const size_t n_objectives = calculatedObjectives.n_rows;
448443

449444
for (size_t i = 0; i < n_objectives; i++)
450445
{
451446
// P is worse than Q for the i-th objective function.
452-
if (calculatedObjectives[candidateP](i) >
453-
calculatedObjectives[candidateQ](i))
447+
if (calculatedObjectives(i, candidateP) >
448+
calculatedObjectives(i, candidateQ))
454449
allBetterOrEqual = false;
455450

456451
// P is better than Q for the i-th objective function.
457-
else if (calculatedObjectives[candidateP](i) <
458-
calculatedObjectives[candidateQ](i))
452+
else if (calculatedObjectives(i, candidateP) <
453+
calculatedObjectives(i, candidateQ))
459454
atleastOneBetter = true;
460455
}
461456

462457
return allBetterOrEqual && atleastOneBetter;
463458
}
464459

465460
//! Assign crowding distance to the population.
466-
template <typename InputMatType, typename ObjectiveMatType>
461+
template <typename MatType>
467462
void NSGA2::CrowdingDistanceAssignment(
468463
const std::vector<size_t>& front,
469-
std::vector<ObjectiveMatType>& calculatedObjectives,
470-
std::vector<typename InputMatType::elem_type>& crowdingDistance)
464+
MatType& calculatedObjectives,
465+
std::vector<typename MatType::elem_type>& crowdingDistance)
471466
{
472467
// Convenience typedefs.
473-
typedef typename InputMatType::elem_type ElemType;
474-
typedef typename ForwardType<InputMatType>::uvec UVecType;
475-
typedef typename ForwardType<ObjectiveMatType>::bcol BaseColType;
468+
typedef typename MatType::elem_type ElemType;
469+
typedef typename ForwardType<MatType>::uvec UVecType;
470+
typedef typename ForwardType<MatType>::bcol BaseColType;
476471

477472
size_t fSize = front.size();
478473
// Stores the sorted indices of the fronts.
@@ -482,11 +477,8 @@ void NSGA2::CrowdingDistanceAssignment(
482477
{
483478
// Cache fValues of individuals for current objective.
484479
BaseColType fValues(fSize);
485-
for (size_t i = 0; i < front.size(); ++i)
486-
{
487-
size_t individual = front[i];
488-
fValues[i] = calculatedObjectives[individual](m);
489-
}
480+
for (size_t k = 0; k < fSize; ++k)
481+
fValues(k) = calculatedObjectives(m, size_t(front[k]));
490482

491483
// Sort front indices by ascending fValues for current objective.
492484
sortedIdx = sort_index(fValues, "ascend");

0 commit comments

Comments
 (0)