pymoo 0.6.1.5.dev0__cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pymoo might be problematic. Click here for more details.
- pymoo/__init__.py +3 -0
- pymoo/algorithms/__init__.py +0 -0
- pymoo/algorithms/base/__init__.py +0 -0
- pymoo/algorithms/base/bracket.py +38 -0
- pymoo/algorithms/base/genetic.py +109 -0
- pymoo/algorithms/base/line.py +62 -0
- pymoo/algorithms/base/local.py +39 -0
- pymoo/algorithms/base/meta.py +79 -0
- pymoo/algorithms/hyperparameters.py +89 -0
- pymoo/algorithms/moo/__init__.py +0 -0
- pymoo/algorithms/moo/age.py +310 -0
- pymoo/algorithms/moo/age2.py +194 -0
- pymoo/algorithms/moo/ctaea.py +298 -0
- pymoo/algorithms/moo/dnsga2.py +76 -0
- pymoo/algorithms/moo/kgb.py +446 -0
- pymoo/algorithms/moo/moead.py +183 -0
- pymoo/algorithms/moo/nsga2.py +113 -0
- pymoo/algorithms/moo/nsga3.py +358 -0
- pymoo/algorithms/moo/pinsga2.py +370 -0
- pymoo/algorithms/moo/rnsga2.py +188 -0
- pymoo/algorithms/moo/rnsga3.py +246 -0
- pymoo/algorithms/moo/rvea.py +214 -0
- pymoo/algorithms/moo/sms.py +195 -0
- pymoo/algorithms/moo/spea2.py +190 -0
- pymoo/algorithms/moo/unsga3.py +47 -0
- pymoo/algorithms/soo/__init__.py +0 -0
- pymoo/algorithms/soo/convex/__init__.py +0 -0
- pymoo/algorithms/soo/nonconvex/__init__.py +0 -0
- pymoo/algorithms/soo/nonconvex/brkga.py +161 -0
- pymoo/algorithms/soo/nonconvex/cmaes.py +554 -0
- pymoo/algorithms/soo/nonconvex/de.py +279 -0
- pymoo/algorithms/soo/nonconvex/direct.py +149 -0
- pymoo/algorithms/soo/nonconvex/es.py +203 -0
- pymoo/algorithms/soo/nonconvex/g3pcx.py +94 -0
- pymoo/algorithms/soo/nonconvex/ga.py +93 -0
- pymoo/algorithms/soo/nonconvex/ga_niching.py +223 -0
- pymoo/algorithms/soo/nonconvex/isres.py +74 -0
- pymoo/algorithms/soo/nonconvex/nelder.py +251 -0
- pymoo/algorithms/soo/nonconvex/optuna.py +80 -0
- pymoo/algorithms/soo/nonconvex/pattern.py +183 -0
- pymoo/algorithms/soo/nonconvex/pso.py +399 -0
- pymoo/algorithms/soo/nonconvex/pso_ep.py +297 -0
- pymoo/algorithms/soo/nonconvex/random_search.py +25 -0
- pymoo/algorithms/soo/nonconvex/sres.py +56 -0
- pymoo/algorithms/soo/univariate/__init__.py +0 -0
- pymoo/algorithms/soo/univariate/backtracking.py +59 -0
- pymoo/algorithms/soo/univariate/exp.py +46 -0
- pymoo/algorithms/soo/univariate/golden.py +65 -0
- pymoo/algorithms/soo/univariate/quadr_interp.py +81 -0
- pymoo/algorithms/soo/univariate/wolfe.py +163 -0
- pymoo/config.py +33 -0
- pymoo/constraints/__init__.py +3 -0
- pymoo/constraints/adaptive.py +62 -0
- pymoo/constraints/as_obj.py +56 -0
- pymoo/constraints/as_penalty.py +41 -0
- pymoo/constraints/eps.py +26 -0
- pymoo/constraints/from_bounds.py +36 -0
- pymoo/core/__init__.py +0 -0
- pymoo/core/algorithm.py +394 -0
- pymoo/core/callback.py +38 -0
- pymoo/core/crossover.py +77 -0
- pymoo/core/decision_making.py +102 -0
- pymoo/core/decomposition.py +76 -0
- pymoo/core/duplicate.py +163 -0
- pymoo/core/evaluator.py +116 -0
- pymoo/core/indicator.py +34 -0
- pymoo/core/individual.py +784 -0
- pymoo/core/infill.py +64 -0
- pymoo/core/initialization.py +42 -0
- pymoo/core/mating.py +39 -0
- pymoo/core/meta.py +21 -0
- pymoo/core/mixed.py +165 -0
- pymoo/core/mutation.py +44 -0
- pymoo/core/operator.py +40 -0
- pymoo/core/parameters.py +134 -0
- pymoo/core/plot.py +210 -0
- pymoo/core/population.py +180 -0
- pymoo/core/problem.py +460 -0
- pymoo/core/recorder.py +99 -0
- pymoo/core/repair.py +23 -0
- pymoo/core/replacement.py +96 -0
- pymoo/core/result.py +52 -0
- pymoo/core/sampling.py +43 -0
- pymoo/core/selection.py +61 -0
- pymoo/core/solution.py +10 -0
- pymoo/core/survival.py +103 -0
- pymoo/core/termination.py +70 -0
- pymoo/core/variable.py +399 -0
- pymoo/cython/__init__.py +0 -0
- pymoo/cython/calc_perpendicular_distance.cpython-313-x86_64-linux-gnu.so +0 -0
- pymoo/cython/calc_perpendicular_distance.pyx +67 -0
- pymoo/cython/decomposition.cpython-313-x86_64-linux-gnu.so +0 -0
- pymoo/cython/decomposition.pyx +165 -0
- pymoo/cython/hv.cpython-313-x86_64-linux-gnu.so +0 -0
- pymoo/cython/hv.pyx +18 -0
- pymoo/cython/info.cpython-313-x86_64-linux-gnu.so +0 -0
- pymoo/cython/info.pyx +5 -0
- pymoo/cython/mnn.cpython-313-x86_64-linux-gnu.so +0 -0
- pymoo/cython/mnn.pyx +273 -0
- pymoo/cython/non_dominated_sorting.cpython-313-x86_64-linux-gnu.so +0 -0
- pymoo/cython/non_dominated_sorting.pyx +645 -0
- pymoo/cython/pruning_cd.cpython-313-x86_64-linux-gnu.so +0 -0
- pymoo/cython/pruning_cd.pyx +197 -0
- pymoo/cython/stochastic_ranking.cpython-313-x86_64-linux-gnu.so +0 -0
- pymoo/cython/stochastic_ranking.pyx +49 -0
- pymoo/cython/utils.pxd +129 -0
- pymoo/cython/vendor/__init__.py +0 -0
- pymoo/cython/vendor/hypervolume.cpp +1621 -0
- pymoo/cython/vendor/hypervolume.h +63 -0
- pymoo/decomposition/__init__.py +0 -0
- pymoo/decomposition/aasf.py +24 -0
- pymoo/decomposition/asf.py +10 -0
- pymoo/decomposition/pbi.py +13 -0
- pymoo/decomposition/perp_dist.py +13 -0
- pymoo/decomposition/tchebicheff.py +11 -0
- pymoo/decomposition/util.py +13 -0
- pymoo/decomposition/weighted_sum.py +8 -0
- pymoo/docs.py +187 -0
- pymoo/experimental/__init__.py +0 -0
- pymoo/experimental/algorithms/__init__.py +0 -0
- pymoo/experimental/algorithms/gde3.py +57 -0
- pymoo/gradient/__init__.py +21 -0
- pymoo/gradient/automatic.py +57 -0
- pymoo/gradient/grad_autograd.py +105 -0
- pymoo/gradient/grad_complex.py +35 -0
- pymoo/gradient/grad_jax.py +51 -0
- pymoo/gradient/toolbox/__init__.py +6 -0
- pymoo/indicators/__init__.py +0 -0
- pymoo/indicators/distance_indicator.py +55 -0
- pymoo/indicators/gd.py +7 -0
- pymoo/indicators/gd_plus.py +7 -0
- pymoo/indicators/hv/__init__.py +63 -0
- pymoo/indicators/hv/exact.py +71 -0
- pymoo/indicators/hv/exact_2d.py +102 -0
- pymoo/indicators/hv/monte_carlo.py +74 -0
- pymoo/indicators/igd.py +7 -0
- pymoo/indicators/igd_plus.py +7 -0
- pymoo/indicators/kktpm.py +151 -0
- pymoo/indicators/migd.py +55 -0
- pymoo/indicators/rmetric.py +203 -0
- pymoo/indicators/spacing.py +52 -0
- pymoo/mcdm/__init__.py +0 -0
- pymoo/mcdm/compromise_programming.py +19 -0
- pymoo/mcdm/high_tradeoff.py +40 -0
- pymoo/mcdm/pseudo_weights.py +32 -0
- pymoo/operators/__init__.py +0 -0
- pymoo/operators/control.py +187 -0
- pymoo/operators/crossover/__init__.py +0 -0
- pymoo/operators/crossover/binx.py +45 -0
- pymoo/operators/crossover/dex.py +122 -0
- pymoo/operators/crossover/erx.py +162 -0
- pymoo/operators/crossover/expx.py +51 -0
- pymoo/operators/crossover/hux.py +37 -0
- pymoo/operators/crossover/nox.py +13 -0
- pymoo/operators/crossover/ox.py +84 -0
- pymoo/operators/crossover/pcx.py +82 -0
- pymoo/operators/crossover/pntx.py +49 -0
- pymoo/operators/crossover/sbx.py +125 -0
- pymoo/operators/crossover/spx.py +5 -0
- pymoo/operators/crossover/ux.py +20 -0
- pymoo/operators/mutation/__init__.py +0 -0
- pymoo/operators/mutation/bitflip.py +17 -0
- pymoo/operators/mutation/gauss.py +58 -0
- pymoo/operators/mutation/inversion.py +42 -0
- pymoo/operators/mutation/nom.py +7 -0
- pymoo/operators/mutation/pm.py +94 -0
- pymoo/operators/mutation/rm.py +23 -0
- pymoo/operators/repair/__init__.py +0 -0
- pymoo/operators/repair/bounce_back.py +32 -0
- pymoo/operators/repair/bounds_repair.py +95 -0
- pymoo/operators/repair/inverse_penalty.py +89 -0
- pymoo/operators/repair/rounding.py +18 -0
- pymoo/operators/repair/to_bound.py +31 -0
- pymoo/operators/repair/vtype.py +11 -0
- pymoo/operators/sampling/__init__.py +0 -0
- pymoo/operators/sampling/lhs.py +73 -0
- pymoo/operators/sampling/rnd.py +50 -0
- pymoo/operators/selection/__init__.py +0 -0
- pymoo/operators/selection/rnd.py +72 -0
- pymoo/operators/selection/tournament.py +76 -0
- pymoo/operators/survival/__init__.py +0 -0
- pymoo/operators/survival/rank_and_crowding/__init__.py +1 -0
- pymoo/operators/survival/rank_and_crowding/classes.py +209 -0
- pymoo/operators/survival/rank_and_crowding/metrics.py +208 -0
- pymoo/optimize.py +72 -0
- pymoo/problems/__init__.py +157 -0
- pymoo/problems/dyn.py +47 -0
- pymoo/problems/dynamic/__init__.py +0 -0
- pymoo/problems/dynamic/cec2015.py +108 -0
- pymoo/problems/dynamic/df.py +452 -0
- pymoo/problems/dynamic/misc.py +167 -0
- pymoo/problems/functional.py +48 -0
- pymoo/problems/many/__init__.py +5 -0
- pymoo/problems/many/cdtlz.py +159 -0
- pymoo/problems/many/dcdtlz.py +88 -0
- pymoo/problems/many/dtlz.py +264 -0
- pymoo/problems/many/wfg.py +550 -0
- pymoo/problems/multi/__init__.py +14 -0
- pymoo/problems/multi/bnh.py +34 -0
- pymoo/problems/multi/carside.py +48 -0
- pymoo/problems/multi/clutch.py +104 -0
- pymoo/problems/multi/csi.py +55 -0
- pymoo/problems/multi/ctp.py +198 -0
- pymoo/problems/multi/dascmop.py +213 -0
- pymoo/problems/multi/kursawe.py +25 -0
- pymoo/problems/multi/modact.py +68 -0
- pymoo/problems/multi/mw.py +400 -0
- pymoo/problems/multi/omnitest.py +48 -0
- pymoo/problems/multi/osy.py +32 -0
- pymoo/problems/multi/srn.py +28 -0
- pymoo/problems/multi/sympart.py +94 -0
- pymoo/problems/multi/tnk.py +24 -0
- pymoo/problems/multi/truss2d.py +83 -0
- pymoo/problems/multi/welded_beam.py +41 -0
- pymoo/problems/multi/wrm.py +36 -0
- pymoo/problems/multi/zdt.py +151 -0
- pymoo/problems/multi_to_single.py +22 -0
- pymoo/problems/single/__init__.py +12 -0
- pymoo/problems/single/ackley.py +24 -0
- pymoo/problems/single/cantilevered_beam.py +34 -0
- pymoo/problems/single/flowshop_scheduling.py +112 -0
- pymoo/problems/single/g.py +874 -0
- pymoo/problems/single/griewank.py +18 -0
- pymoo/problems/single/himmelblau.py +15 -0
- pymoo/problems/single/knapsack.py +48 -0
- pymoo/problems/single/mopta08.py +26 -0
- pymoo/problems/single/multimodal.py +20 -0
- pymoo/problems/single/pressure_vessel.py +30 -0
- pymoo/problems/single/rastrigin.py +20 -0
- pymoo/problems/single/rosenbrock.py +22 -0
- pymoo/problems/single/schwefel.py +18 -0
- pymoo/problems/single/simple.py +13 -0
- pymoo/problems/single/sphere.py +19 -0
- pymoo/problems/single/traveling_salesman.py +79 -0
- pymoo/problems/single/zakharov.py +19 -0
- pymoo/problems/static.py +14 -0
- pymoo/problems/util.py +42 -0
- pymoo/problems/zero_to_one.py +27 -0
- pymoo/termination/__init__.py +23 -0
- pymoo/termination/collection.py +12 -0
- pymoo/termination/cv.py +48 -0
- pymoo/termination/default.py +45 -0
- pymoo/termination/delta.py +64 -0
- pymoo/termination/fmin.py +16 -0
- pymoo/termination/ftol.py +144 -0
- pymoo/termination/indicator.py +49 -0
- pymoo/termination/max_eval.py +14 -0
- pymoo/termination/max_gen.py +15 -0
- pymoo/termination/max_time.py +20 -0
- pymoo/termination/robust.py +34 -0
- pymoo/termination/xtol.py +33 -0
- pymoo/util/__init__.py +0 -0
- pymoo/util/archive.py +150 -0
- pymoo/util/cache.py +29 -0
- pymoo/util/clearing.py +82 -0
- pymoo/util/display/__init__.py +0 -0
- pymoo/util/display/column.py +52 -0
- pymoo/util/display/display.py +34 -0
- pymoo/util/display/multi.py +96 -0
- pymoo/util/display/output.py +53 -0
- pymoo/util/display/progress.py +54 -0
- pymoo/util/display/single.py +67 -0
- pymoo/util/dominator.py +67 -0
- pymoo/util/function_loader.py +129 -0
- pymoo/util/hv.py +23 -0
- pymoo/util/matlab_engine.py +39 -0
- pymoo/util/misc.py +460 -0
- pymoo/util/mnn.py +70 -0
- pymoo/util/nds/__init__.py +0 -0
- pymoo/util/nds/dominance_degree_non_dominated_sort.py +159 -0
- pymoo/util/nds/efficient_non_dominated_sort.py +152 -0
- pymoo/util/nds/fast_non_dominated_sort.py +70 -0
- pymoo/util/nds/naive_non_dominated_sort.py +36 -0
- pymoo/util/nds/non_dominated_sorting.py +67 -0
- pymoo/util/nds/tree_based_non_dominated_sort.py +133 -0
- pymoo/util/normalization.py +312 -0
- pymoo/util/optimum.py +42 -0
- pymoo/util/plotting.py +177 -0
- pymoo/util/pruning_cd.py +89 -0
- pymoo/util/randomized_argsort.py +60 -0
- pymoo/util/ref_dirs/__init__.py +24 -0
- pymoo/util/ref_dirs/construction.py +88 -0
- pymoo/util/ref_dirs/das_dennis.py +52 -0
- pymoo/util/ref_dirs/energy.py +319 -0
- pymoo/util/ref_dirs/energy_layer.py +119 -0
- pymoo/util/ref_dirs/genetic_algorithm.py +63 -0
- pymoo/util/ref_dirs/incremental.py +68 -0
- pymoo/util/ref_dirs/misc.py +128 -0
- pymoo/util/ref_dirs/optimizer.py +59 -0
- pymoo/util/ref_dirs/performance.py +162 -0
- pymoo/util/ref_dirs/reduction.py +85 -0
- pymoo/util/ref_dirs/sample_and_map.py +24 -0
- pymoo/util/reference_direction.py +260 -0
- pymoo/util/remote.py +55 -0
- pymoo/util/roulette.py +27 -0
- pymoo/util/running_metric.py +128 -0
- pymoo/util/sliding_window.py +25 -0
- pymoo/util/stochastic_ranking.py +32 -0
- pymoo/util/value_functions.py +719 -0
- pymoo/util/vectors.py +40 -0
- pymoo/util/vf_dominator.py +99 -0
- pymoo/vendor/__init__.py +0 -0
- pymoo/vendor/cec2018.py +398 -0
- pymoo/vendor/gta.py +617 -0
- pymoo/vendor/hv.py +267 -0
- pymoo/vendor/vendor_cmaes.py +412 -0
- pymoo/vendor/vendor_coco.py +81 -0
- pymoo/vendor/vendor_scipy.py +232 -0
- pymoo/version.py +1 -0
- pymoo/visualization/__init__.py +8 -0
- pymoo/visualization/fitness_landscape.py +127 -0
- pymoo/visualization/heatmap.py +123 -0
- pymoo/visualization/pcp.py +120 -0
- pymoo/visualization/petal.py +91 -0
- pymoo/visualization/radar.py +108 -0
- pymoo/visualization/radviz.py +68 -0
- pymoo/visualization/scatter.py +150 -0
- pymoo/visualization/star_coordinate.py +75 -0
- pymoo/visualization/util.py +123 -0
- pymoo/visualization/video/__init__.py +0 -0
- pymoo/visualization/video/callback_video.py +82 -0
- pymoo/visualization/video/one_var_one_obj.py +57 -0
- pymoo/visualization/video/two_var_one_obj.py +62 -0
- pymoo-0.6.1.5.dev0.dist-info/METADATA +187 -0
- pymoo-0.6.1.5.dev0.dist-info/RECORD +328 -0
- pymoo-0.6.1.5.dev0.dist-info/WHEEL +6 -0
- pymoo-0.6.1.5.dev0.dist-info/licenses/LICENSE +191 -0
- pymoo-0.6.1.5.dev0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from scipy.spatial.distance import cdist, pdist, squareform
|
|
5
|
+
|
|
6
|
+
from pymoo.algorithms.base.genetic import GeneticAlgorithm
|
|
7
|
+
from pymoo.core.population import Population
|
|
8
|
+
from pymoo.decomposition.asf import ASF
|
|
9
|
+
from pymoo.docs import parse_doc_string
|
|
10
|
+
from pymoo.operators.crossover.sbx import SBX
|
|
11
|
+
from pymoo.operators.mutation.pm import PM
|
|
12
|
+
from pymoo.operators.sampling.rnd import FloatRandomSampling
|
|
13
|
+
from pymoo.operators.selection.tournament import TournamentSelection
|
|
14
|
+
from pymoo.util.display.multi import MultiObjectiveOutput
|
|
15
|
+
from pymoo.util.dominator import Dominator
|
|
16
|
+
from pymoo.util.function_loader import load_function
|
|
17
|
+
from pymoo.util.misc import has_feasible, random_permutations
|
|
18
|
+
from pymoo.util.nds.non_dominated_sorting import NonDominatedSorting
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# =========================================================================================================
|
|
22
|
+
# Implementation
|
|
23
|
+
# Following original code by K. Li https://cola-laboratory.github.io/codes/CTAEA.zip
|
|
24
|
+
# =========================================================================================================
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def comp_by_cv_dom_then_random(pop, P, **kwargs):
|
|
28
|
+
S = np.full(P.shape[0], np.nan)
|
|
29
|
+
|
|
30
|
+
for i in range(P.shape[0]):
|
|
31
|
+
a, b = P[i, 0], P[i, 1]
|
|
32
|
+
|
|
33
|
+
if pop[a].CV <= 0.0 and pop[b].CV <= 0.0:
|
|
34
|
+
rel = Dominator.get_relation(pop[a].F, pop[b].F)
|
|
35
|
+
if rel == 1:
|
|
36
|
+
S[i] = a
|
|
37
|
+
elif rel == -1:
|
|
38
|
+
S[i] = b
|
|
39
|
+
else:
|
|
40
|
+
S[i] = np.random.choice([a, b])
|
|
41
|
+
elif pop[a].CV <= 0.0:
|
|
42
|
+
S[i] = a
|
|
43
|
+
elif pop[b].CV <= 0.0:
|
|
44
|
+
S[i] = b
|
|
45
|
+
else:
|
|
46
|
+
S[i] = np.random.choice([a, b])
|
|
47
|
+
|
|
48
|
+
return S[:, None].astype(int)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class RestrictedMating(TournamentSelection):
|
|
52
|
+
"""Restricted mating approach to balance convergence and diversity archives"""
|
|
53
|
+
|
|
54
|
+
def _do(self, problem, Hm, n_select, n_parents, **kwargs):
|
|
55
|
+
n_pop = len(Hm) // 2
|
|
56
|
+
|
|
57
|
+
_, rank = NonDominatedSorting().do(Hm.get('F'), return_rank=True)
|
|
58
|
+
|
|
59
|
+
Pc = (rank[:n_pop] == 0).sum() / len(Hm)
|
|
60
|
+
Pd = (rank[n_pop:] == 0).sum() / len(Hm)
|
|
61
|
+
|
|
62
|
+
# number of random individuals needed
|
|
63
|
+
n_random = n_select * n_parents * self.pressure
|
|
64
|
+
n_perms = math.ceil(n_random / n_pop)
|
|
65
|
+
# get random permutations and reshape them
|
|
66
|
+
P = random_permutations(n_perms, n_pop)[:n_random]
|
|
67
|
+
P = np.reshape(P, (n_select * n_parents, self.pressure))
|
|
68
|
+
if Pc <= Pd:
|
|
69
|
+
# Choose from DA
|
|
70
|
+
P[::n_parents, :] += n_pop
|
|
71
|
+
pf = np.random.random(n_select)
|
|
72
|
+
P[1::n_parents, :][pf >= Pc] += n_pop
|
|
73
|
+
|
|
74
|
+
# compare using tournament function
|
|
75
|
+
S = self.func_comp(Hm, P, **kwargs)
|
|
76
|
+
|
|
77
|
+
return np.reshape(S, (n_select, n_parents))
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class CADASurvival:
|
|
81
|
+
|
|
82
|
+
def __init__(self, ref_dirs):
|
|
83
|
+
self.ref_dirs = ref_dirs
|
|
84
|
+
self.opt = None
|
|
85
|
+
self.ideal_point = np.full(ref_dirs.shape[1], np.inf)
|
|
86
|
+
self._decomposition = ASF()
|
|
87
|
+
self._calc_perpendicular_distance = load_function("calc_perpendicular_distance")
|
|
88
|
+
|
|
89
|
+
def do(self, _, pop, da, n_survive=None, **kwargs):
|
|
90
|
+
# Offspring are last of merged population
|
|
91
|
+
off = pop[-n_survive:]
|
|
92
|
+
# Update ideal point
|
|
93
|
+
self.ideal_point = np.min(np.vstack((self.ideal_point, off.get("F"))), axis=0)
|
|
94
|
+
# Update CA
|
|
95
|
+
pop = self._updateCA(pop, n_survive)
|
|
96
|
+
# Update DA
|
|
97
|
+
Hd = Population.merge(da, off)
|
|
98
|
+
da = self._updateDA(pop, Hd, n_survive)
|
|
99
|
+
return pop, da
|
|
100
|
+
|
|
101
|
+
def _associate(self, pop):
|
|
102
|
+
"""Associate each individual with a F vector and calculate decomposed fitness"""
|
|
103
|
+
F = pop.get("F")
|
|
104
|
+
dist_matrix = self._calc_perpendicular_distance(F - self.ideal_point, self.ref_dirs)
|
|
105
|
+
niche_of_individuals = np.argmin(dist_matrix, axis=1)
|
|
106
|
+
FV = self._decomposition.do(F, weights=self.ref_dirs[niche_of_individuals, :],
|
|
107
|
+
ideal_point=self.ideal_point, weight_0=1e-4)
|
|
108
|
+
pop.set("niche", niche_of_individuals)
|
|
109
|
+
pop.set("FV", FV)
|
|
110
|
+
return niche_of_individuals, FV
|
|
111
|
+
|
|
112
|
+
def _updateCA(self, pop, n_survive):
|
|
113
|
+
"""Update the Convergence archive (CA)"""
|
|
114
|
+
CV = pop.get("CV").flatten()
|
|
115
|
+
|
|
116
|
+
Sc = pop[CV == 0] # ConstraintsAsObjective population
|
|
117
|
+
if len(Sc) == n_survive: # Exactly n_survive feasible individuals
|
|
118
|
+
F = Sc.get("F")
|
|
119
|
+
fronts, rank = NonDominatedSorting().do(F, return_rank=True)
|
|
120
|
+
Sc.set('rank', rank)
|
|
121
|
+
self.opt = Sc[fronts[0]]
|
|
122
|
+
return Sc
|
|
123
|
+
elif len(Sc) < n_survive: # Not enough feasible individuals
|
|
124
|
+
remainder = n_survive - len(Sc)
|
|
125
|
+
# Solve sub-problem CV, tche
|
|
126
|
+
SI = pop[CV > 0]
|
|
127
|
+
f1 = SI.get("CV")
|
|
128
|
+
_, f2 = self._associate(SI)
|
|
129
|
+
sub_F = np.column_stack([f1, f2])
|
|
130
|
+
fronts = NonDominatedSorting().do(sub_F, n_stop_if_ranked=remainder)
|
|
131
|
+
I = []
|
|
132
|
+
for front in fronts:
|
|
133
|
+
if len(I) + len(front) <= remainder:
|
|
134
|
+
I.extend(front)
|
|
135
|
+
else:
|
|
136
|
+
n_missing = remainder - len(I)
|
|
137
|
+
last_front_CV = np.argsort(f1.flatten()[front])
|
|
138
|
+
I.extend(front[last_front_CV[:n_missing]])
|
|
139
|
+
SI = SI[I]
|
|
140
|
+
S = Population.merge(Sc, SI)
|
|
141
|
+
F = S.get("F")
|
|
142
|
+
fronts, rank = NonDominatedSorting().do(F, return_rank=True)
|
|
143
|
+
S.set('rank', rank)
|
|
144
|
+
self.opt = S[fronts[0]]
|
|
145
|
+
return S
|
|
146
|
+
else: # Too many feasible individuals
|
|
147
|
+
F = Sc.get("F")
|
|
148
|
+
# Filter by non-dominated sorting
|
|
149
|
+
fronts, rank = NonDominatedSorting().do(F, return_rank=True, n_stop_if_ranked=n_survive)
|
|
150
|
+
I = np.concatenate(fronts)
|
|
151
|
+
S, rank, F = Sc[I], rank[I], F[I]
|
|
152
|
+
if len(S) > n_survive:
|
|
153
|
+
# Remove individual in most crowded niche and with worst fitness
|
|
154
|
+
niche_of_individuals, FV = self._associate(S)
|
|
155
|
+
index, count = np.unique(niche_of_individuals, return_counts=True)
|
|
156
|
+
survivors = np.full(S.shape[0], True)
|
|
157
|
+
while survivors.sum() > n_survive:
|
|
158
|
+
crowdest_niches, = np.where(count == count.max())
|
|
159
|
+
worst_idx = None
|
|
160
|
+
worst_niche = None
|
|
161
|
+
worst_fit = -1
|
|
162
|
+
for crowdest_niche in crowdest_niches:
|
|
163
|
+
crowdest, = np.where((niche_of_individuals == index[crowdest_niche]) & survivors)
|
|
164
|
+
niche_worst = crowdest[FV[crowdest].argmax()]
|
|
165
|
+
dist_to_max_fit = cdist(F[[niche_worst], :], F).flatten()
|
|
166
|
+
dist_to_max_fit[niche_worst] = np.inf
|
|
167
|
+
dist_to_max_fit[~survivors] = np.inf
|
|
168
|
+
min_d_to_max_fit = dist_to_max_fit.min()
|
|
169
|
+
|
|
170
|
+
dist_in_niche = squareform(pdist(F[crowdest]))
|
|
171
|
+
np.fill_diagonal(dist_in_niche, np.inf)
|
|
172
|
+
|
|
173
|
+
delta_d = dist_in_niche - min_d_to_max_fit
|
|
174
|
+
min_d_i = np.unravel_index(np.argmin(delta_d, axis=None), dist_in_niche.shape)
|
|
175
|
+
if (delta_d[min_d_i] < 0) or (
|
|
176
|
+
delta_d[min_d_i] == 0 and (FV[crowdest[list(min_d_i)]] > niche_worst).any()):
|
|
177
|
+
min_d_i = list(min_d_i)
|
|
178
|
+
np.random.shuffle(min_d_i)
|
|
179
|
+
closest = crowdest[min_d_i]
|
|
180
|
+
niche_worst = closest[np.argmax(FV[closest])]
|
|
181
|
+
if (FV[niche_worst] > worst_fit).all():
|
|
182
|
+
worst_fit = FV[niche_worst]
|
|
183
|
+
worst_idx = niche_worst
|
|
184
|
+
worst_niche = crowdest_niche
|
|
185
|
+
survivors[worst_idx] = False
|
|
186
|
+
count[worst_niche] -= 1
|
|
187
|
+
S, rank = S[survivors], rank[survivors]
|
|
188
|
+
S.set('rank', rank)
|
|
189
|
+
self.opt = S[rank == 0]
|
|
190
|
+
return S
|
|
191
|
+
|
|
192
|
+
def _updateDA(self, pop, Hd, n_survive):
|
|
193
|
+
"""Update the Diversity archive (DA)"""
|
|
194
|
+
niche_Hd, FV = self._associate(Hd)
|
|
195
|
+
niche_CA, _ = self._associate(pop)
|
|
196
|
+
|
|
197
|
+
itr = 1
|
|
198
|
+
S = []
|
|
199
|
+
while len(S) < n_survive:
|
|
200
|
+
for i in range(n_survive):
|
|
201
|
+
current_ca, = np.where(niche_CA == i)
|
|
202
|
+
if len(current_ca) < itr:
|
|
203
|
+
for _ in range(itr - len(current_ca)):
|
|
204
|
+
current_da = np.where(niche_Hd == i)[0]
|
|
205
|
+
if current_da.size > 0:
|
|
206
|
+
F = Hd[current_da].get('F')
|
|
207
|
+
nd = NonDominatedSorting().do(F, only_non_dominated_front=True, n_stop_if_ranked=0)
|
|
208
|
+
i_best = current_da[nd[np.argmin(FV[current_da[nd]])]]
|
|
209
|
+
niche_Hd[i_best] = -1
|
|
210
|
+
if len(S) < n_survive:
|
|
211
|
+
S.append(i_best)
|
|
212
|
+
else:
|
|
213
|
+
break
|
|
214
|
+
if len(S) == n_survive:
|
|
215
|
+
break
|
|
216
|
+
itr += 1
|
|
217
|
+
return Hd[S]
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class CTAEA(GeneticAlgorithm):
|
|
221
|
+
|
|
222
|
+
def __init__(self,
|
|
223
|
+
ref_dirs,
|
|
224
|
+
sampling=FloatRandomSampling(),
|
|
225
|
+
selection=RestrictedMating(func_comp=comp_by_cv_dom_then_random),
|
|
226
|
+
crossover=SBX(n_offsprings=1, eta=30, prob=1.0),
|
|
227
|
+
mutation=PM(prob_var=None, eta=20),
|
|
228
|
+
eliminate_duplicates=True,
|
|
229
|
+
output=MultiObjectiveOutput(),
|
|
230
|
+
**kwargs):
|
|
231
|
+
"""
|
|
232
|
+
CTAEA
|
|
233
|
+
|
|
234
|
+
Parameters
|
|
235
|
+
----------
|
|
236
|
+
ref_dirs : {ref_dirs}
|
|
237
|
+
sampling : {sampling}
|
|
238
|
+
selection : {selection}
|
|
239
|
+
crossover : {crossover}
|
|
240
|
+
mutation : {mutation}
|
|
241
|
+
eliminate_duplicates : {eliminate_duplicates}
|
|
242
|
+
"""
|
|
243
|
+
|
|
244
|
+
self.ref_dirs = ref_dirs
|
|
245
|
+
pop_size = len(ref_dirs)
|
|
246
|
+
|
|
247
|
+
if 'survival' in kwargs:
|
|
248
|
+
survival = kwargs['survival']
|
|
249
|
+
del kwargs['survival']
|
|
250
|
+
else:
|
|
251
|
+
survival = CADASurvival(ref_dirs)
|
|
252
|
+
|
|
253
|
+
# Initialize diversity archives
|
|
254
|
+
self.da = None
|
|
255
|
+
|
|
256
|
+
super().__init__(pop_size=pop_size,
|
|
257
|
+
sampling=sampling,
|
|
258
|
+
selection=selection,
|
|
259
|
+
crossover=crossover,
|
|
260
|
+
mutation=mutation,
|
|
261
|
+
survival=survival,
|
|
262
|
+
eliminate_duplicates=eliminate_duplicates,
|
|
263
|
+
n_offsprings=pop_size,
|
|
264
|
+
output=output,
|
|
265
|
+
**kwargs)
|
|
266
|
+
|
|
267
|
+
def _setup(self, problem, **kwargs):
|
|
268
|
+
|
|
269
|
+
if self.ref_dirs is not None and self.ref_dirs.shape[1] != problem.n_obj:
|
|
270
|
+
raise Exception(
|
|
271
|
+
"Dimensionality of reference points must be equal to the number of objectives: %s != %s" %
|
|
272
|
+
(self.ref_dirs.shape[1], problem.n_obj))
|
|
273
|
+
|
|
274
|
+
def _initialize_infill(self):
|
|
275
|
+
return self.initialization.do(self.problem, self.pop_size, algorithm=self)
|
|
276
|
+
|
|
277
|
+
def _initialize_advance(self, infills=None, **kwargs):
|
|
278
|
+
super()._initialize_advance(infills, **kwargs)
|
|
279
|
+
self.pop, self.da = self.survival.do(self.problem, self.pop, Population(), n_survive=len(self.pop),
|
|
280
|
+
algorithm=self)
|
|
281
|
+
|
|
282
|
+
def _infill(self):
|
|
283
|
+
Hm = Population.merge(self.pop, self.da)
|
|
284
|
+
return self.mating.do(self.problem, Hm, n_offsprings=self.n_offsprings, algorithm=self)
|
|
285
|
+
|
|
286
|
+
def _advance(self, infills=None, **kwargs):
|
|
287
|
+
assert infills is not None, "This algorithms uses the AskAndTell interface thus infills must to be provided."
|
|
288
|
+
pop = Population.merge(self.pop, infills)
|
|
289
|
+
self.pop, self.da = self.survival.do(self.problem, pop, self.da, self.pop_size, algorithm=self)
|
|
290
|
+
|
|
291
|
+
def _set_optimum(self, **kwargs):
|
|
292
|
+
if not has_feasible(self.pop):
|
|
293
|
+
self.opt = self.pop[[np.argmin(self.pop.get("CV"))]]
|
|
294
|
+
else:
|
|
295
|
+
self.opt = self.survival.opt
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
parse_doc_string(CTAEA.__init__)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pymoo.algorithms.moo.nsga2 import NSGA2
|
|
4
|
+
from pymoo.core.population import Population
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DNSGA2(NSGA2):
|
|
8
|
+
|
|
9
|
+
def __init__(self,
|
|
10
|
+
perc_detect_change=0.1,
|
|
11
|
+
perc_diversity=0.3,
|
|
12
|
+
eps=0.0,
|
|
13
|
+
version="A",
|
|
14
|
+
**kwargs):
|
|
15
|
+
|
|
16
|
+
super().__init__(**kwargs)
|
|
17
|
+
self.perc_detect_change = perc_detect_change
|
|
18
|
+
self.perc_diversity = perc_diversity
|
|
19
|
+
self.eps = eps
|
|
20
|
+
self.version = version
|
|
21
|
+
|
|
22
|
+
def setup(self, problem, **kwargs):
|
|
23
|
+
assert not problem.has_constraints(), "DNSGA2 only works for unconstrained problems."
|
|
24
|
+
return super().setup(problem, **kwargs)
|
|
25
|
+
|
|
26
|
+
def _advance(self, **kwargs):
|
|
27
|
+
|
|
28
|
+
pop = self.pop
|
|
29
|
+
X, F = pop.get("X", "F")
|
|
30
|
+
|
|
31
|
+
# the number of solutions to sample from the population to detect the change
|
|
32
|
+
n_samples = int(np.ceil(len(pop) * self.perc_detect_change))
|
|
33
|
+
|
|
34
|
+
# choose randomly some individuals of the current population to test if there was a change
|
|
35
|
+
I = np.random.choice(np.arange(len(pop)), size=n_samples)
|
|
36
|
+
samples = self.evaluator.eval(self.problem, Population.new(X=X[I]))
|
|
37
|
+
|
|
38
|
+
# calculate the differences between the old and newly evaluated pop
|
|
39
|
+
delta = ((samples.get("F") - F[I]) ** 2).mean()
|
|
40
|
+
|
|
41
|
+
# if there is an average deviation bigger than eps -> we have a change detected
|
|
42
|
+
change_detected = delta > self.eps
|
|
43
|
+
|
|
44
|
+
if change_detected:
|
|
45
|
+
|
|
46
|
+
# recreate the current population without being evaluated
|
|
47
|
+
pop = Population.new(X=X)
|
|
48
|
+
|
|
49
|
+
# find indices to be replaced (introduce diversity)
|
|
50
|
+
I = np.where(np.random.random(len(pop)) < self.perc_diversity)[0]
|
|
51
|
+
|
|
52
|
+
# replace with randomly sampled individuals
|
|
53
|
+
if self.version == "A":
|
|
54
|
+
pop[I] = self.initialization.sampling(self.problem, len(I))
|
|
55
|
+
|
|
56
|
+
# replace by mutations of existing solutions (this occurs inplace)
|
|
57
|
+
elif self.version == "B":
|
|
58
|
+
self.mating.mutation(self.problem, pop[I])
|
|
59
|
+
else:
|
|
60
|
+
raise Exception(f"Unknown version of D-NSGA-II: {self.version}")
|
|
61
|
+
|
|
62
|
+
# reevaluate because we know there was a change
|
|
63
|
+
self.evaluator.eval(self.problem, pop)
|
|
64
|
+
|
|
65
|
+
# do a survival to recreate rank and crowding of all individuals
|
|
66
|
+
pop = self.survival.do(self.problem, pop, n_survive=len(pop))
|
|
67
|
+
|
|
68
|
+
# create the offsprings from the current population
|
|
69
|
+
off = self.mating.do(self.problem, pop, self.n_offsprings, algorithm=self)
|
|
70
|
+
self.evaluator.eval(self.problem, off)
|
|
71
|
+
|
|
72
|
+
# merge the parent population and offsprings
|
|
73
|
+
pop = Population.merge(pop, off)
|
|
74
|
+
|
|
75
|
+
# execute the survival to find the fittest solutions
|
|
76
|
+
self.pop = self.survival.do(self.problem, pop, n_survive=self.pop_size, algorithm=self)
|