pymoo 0.6.1.5.dev0__cp312-cp312-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-312-x86_64-linux-gnu.so +0 -0
- pymoo/cython/calc_perpendicular_distance.pyx +67 -0
- pymoo/cython/decomposition.cpython-312-x86_64-linux-gnu.so +0 -0
- pymoo/cython/decomposition.pyx +165 -0
- pymoo/cython/hv.cpython-312-x86_64-linux-gnu.so +0 -0
- pymoo/cython/hv.pyx +18 -0
- pymoo/cython/info.cpython-312-x86_64-linux-gnu.so +0 -0
- pymoo/cython/info.pyx +5 -0
- pymoo/cython/mnn.cpython-312-x86_64-linux-gnu.so +0 -0
- pymoo/cython/mnn.pyx +273 -0
- pymoo/cython/non_dominated_sorting.cpython-312-x86_64-linux-gnu.so +0 -0
- pymoo/cython/non_dominated_sorting.pyx +645 -0
- pymoo/cython/pruning_cd.cpython-312-x86_64-linux-gnu.so +0 -0
- pymoo/cython/pruning_cd.pyx +197 -0
- pymoo/cython/stochastic_ranking.cpython-312-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,152 @@
|
|
|
1
|
+
from math import floor
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from pymoo.util.dominator import Dominator
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def efficient_non_dominated_sort(F, strategy="sequential"):
|
|
9
|
+
"""
|
|
10
|
+
Efficient Non-dominated Sorting (ENS)
|
|
11
|
+
|
|
12
|
+
Parameters
|
|
13
|
+
----------
|
|
14
|
+
F: numpy.ndarray
|
|
15
|
+
objective values for each individual.
|
|
16
|
+
strategy: str
|
|
17
|
+
search strategy, can be "sequential" or "binary".
|
|
18
|
+
|
|
19
|
+
Returns
|
|
20
|
+
-------
|
|
21
|
+
fronts: list
|
|
22
|
+
Indices of the individuals in each front.
|
|
23
|
+
|
|
24
|
+
References
|
|
25
|
+
----------
|
|
26
|
+
X. Zhang, Y. Tian, R. Cheng, and Y. Jin,
|
|
27
|
+
An efficient approach to nondominated sorting for evolutionary multiobjective optimization,
|
|
28
|
+
IEEE Transactions on Evolutionary Computation, 2015, 19(2): 201-213.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
assert (strategy in ["sequential", 'binary']), "Invalid search strategy"
|
|
32
|
+
|
|
33
|
+
# the shape of the input
|
|
34
|
+
N, M = F.shape
|
|
35
|
+
|
|
36
|
+
# do a lexicographic ordering
|
|
37
|
+
I = np.lexsort(F.T[::-1])
|
|
38
|
+
F = F[I]
|
|
39
|
+
|
|
40
|
+
# front ranks for each individual
|
|
41
|
+
fronts = []
|
|
42
|
+
|
|
43
|
+
for i in range(N):
|
|
44
|
+
|
|
45
|
+
if strategy == 'sequential':
|
|
46
|
+
k = sequential_search(F, i, fronts)
|
|
47
|
+
else:
|
|
48
|
+
k = binary_search(F, i, fronts)
|
|
49
|
+
|
|
50
|
+
# create empty fronts if necessary
|
|
51
|
+
if k >= len(fronts):
|
|
52
|
+
fronts.append([])
|
|
53
|
+
|
|
54
|
+
# append the current individual to a front
|
|
55
|
+
fronts[k].append(i)
|
|
56
|
+
|
|
57
|
+
# now map the fronts back to the originally sorting
|
|
58
|
+
ret = []
|
|
59
|
+
for front in fronts:
|
|
60
|
+
ret.append(I[front])
|
|
61
|
+
|
|
62
|
+
return ret
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def sequential_search(F, i, fronts) -> int:
|
|
66
|
+
"""
|
|
67
|
+
Find the front rank for the i-th individual through sequential search.
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
F: np.ndarray
|
|
72
|
+
the objective values
|
|
73
|
+
i: int
|
|
74
|
+
the index of the individual
|
|
75
|
+
fronts: list
|
|
76
|
+
individuals in each front
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
num_found_fronts = len(fronts)
|
|
80
|
+
k = 0 # the front now checked
|
|
81
|
+
current = F[i]
|
|
82
|
+
while True:
|
|
83
|
+
if num_found_fronts == 0:
|
|
84
|
+
return 0
|
|
85
|
+
# solutions in the k-th front, examine in reverse order
|
|
86
|
+
fk_indices = fronts[k]
|
|
87
|
+
solutions = F[fk_indices[::-1]]
|
|
88
|
+
non_dominated = True
|
|
89
|
+
for f in solutions:
|
|
90
|
+
relation = Dominator.get_relation(current, f)
|
|
91
|
+
if relation == -1:
|
|
92
|
+
non_dominated = False
|
|
93
|
+
break
|
|
94
|
+
if non_dominated:
|
|
95
|
+
return k
|
|
96
|
+
else:
|
|
97
|
+
k += 1
|
|
98
|
+
if k >= num_found_fronts:
|
|
99
|
+
# move the individual to a new front
|
|
100
|
+
return num_found_fronts
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def binary_search(F, i, fronts):
|
|
104
|
+
"""
|
|
105
|
+
Find the front rank for the i-th individual through binary search.
|
|
106
|
+
|
|
107
|
+
Parameters
|
|
108
|
+
----------
|
|
109
|
+
F: np.ndarray
|
|
110
|
+
the objective values
|
|
111
|
+
i: int
|
|
112
|
+
the index of the individual
|
|
113
|
+
fronts: list
|
|
114
|
+
individuals in each front
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
num_found_fronts = len(fronts)
|
|
118
|
+
if num_found_fronts == 0:
|
|
119
|
+
return 0
|
|
120
|
+
|
|
121
|
+
k_min = 0 # the lower bound for checking
|
|
122
|
+
k_max = num_found_fronts # the upper bound for checking
|
|
123
|
+
k = floor((k_max + k_min) / 2 + 0.5) # the front now checked
|
|
124
|
+
current = F[i]
|
|
125
|
+
while True:
|
|
126
|
+
|
|
127
|
+
# solutions in the k-th front, examine in reverse order
|
|
128
|
+
fk_indices = fronts[k - 1]
|
|
129
|
+
solutions = F[fk_indices[::-1]]
|
|
130
|
+
non_dominated = True
|
|
131
|
+
|
|
132
|
+
for f in solutions:
|
|
133
|
+
relation = Dominator.get_relation(current, f)
|
|
134
|
+
if relation == -1:
|
|
135
|
+
non_dominated = False
|
|
136
|
+
break
|
|
137
|
+
|
|
138
|
+
# binary search
|
|
139
|
+
if non_dominated:
|
|
140
|
+
if k == k_min + 1:
|
|
141
|
+
return k - 1
|
|
142
|
+
else:
|
|
143
|
+
k_max = k
|
|
144
|
+
k = floor((k_max + k_min) / 2 + 0.5)
|
|
145
|
+
else:
|
|
146
|
+
k_min = k
|
|
147
|
+
if k_max == k_min + 1 and k_max < num_found_fronts:
|
|
148
|
+
return k_max - 1
|
|
149
|
+
elif k_min == num_found_fronts:
|
|
150
|
+
return num_found_fronts
|
|
151
|
+
else:
|
|
152
|
+
k = floor((k_max + k_min) / 2 + 0.5)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pymoo.util.dominator import Dominator
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def fast_non_dominated_sort(F, dominator=Dominator(), **kwargs):
|
|
7
|
+
if "dominator" in kwargs:
|
|
8
|
+
M = Dominator.calc_domination_matrix(F)
|
|
9
|
+
else:
|
|
10
|
+
M = dominator.calc_domination_matrix(F)
|
|
11
|
+
|
|
12
|
+
# calculate the dominance matrix
|
|
13
|
+
n = M.shape[0]
|
|
14
|
+
|
|
15
|
+
fronts = []
|
|
16
|
+
|
|
17
|
+
if n == 0:
|
|
18
|
+
return fronts
|
|
19
|
+
|
|
20
|
+
# final rank that will be returned
|
|
21
|
+
n_ranked = 0
|
|
22
|
+
ranked = np.zeros(n, dtype=int)
|
|
23
|
+
|
|
24
|
+
# for each individual a list of all individuals that are dominated by this one
|
|
25
|
+
is_dominating = [[] for _ in range(n)]
|
|
26
|
+
|
|
27
|
+
# storage for the number of solutions dominated this one
|
|
28
|
+
n_dominated = np.zeros(n)
|
|
29
|
+
|
|
30
|
+
current_front = []
|
|
31
|
+
|
|
32
|
+
for i in range(n):
|
|
33
|
+
|
|
34
|
+
for j in range(i + 1, n):
|
|
35
|
+
rel = M[i, j]
|
|
36
|
+
if rel == 1:
|
|
37
|
+
is_dominating[i].append(j)
|
|
38
|
+
n_dominated[j] += 1
|
|
39
|
+
elif rel == -1:
|
|
40
|
+
is_dominating[j].append(i)
|
|
41
|
+
n_dominated[i] += 1
|
|
42
|
+
|
|
43
|
+
if n_dominated[i] == 0:
|
|
44
|
+
current_front.append(i)
|
|
45
|
+
ranked[i] = 1.0
|
|
46
|
+
n_ranked += 1
|
|
47
|
+
|
|
48
|
+
# append the first front to the current front
|
|
49
|
+
fronts.append(current_front)
|
|
50
|
+
|
|
51
|
+
# while not all solutions are assigned to a pareto front
|
|
52
|
+
while n_ranked < n:
|
|
53
|
+
|
|
54
|
+
next_front = []
|
|
55
|
+
|
|
56
|
+
# for each individual in the current front
|
|
57
|
+
for i in current_front:
|
|
58
|
+
|
|
59
|
+
# all solutions that are dominated by this individuals
|
|
60
|
+
for j in is_dominating[i]:
|
|
61
|
+
n_dominated[j] -= 1
|
|
62
|
+
if n_dominated[j] == 0:
|
|
63
|
+
next_front.append(j)
|
|
64
|
+
ranked[j] = 1.0
|
|
65
|
+
n_ranked += 1
|
|
66
|
+
|
|
67
|
+
fronts.append(next_front)
|
|
68
|
+
current_front = next_front
|
|
69
|
+
|
|
70
|
+
return fronts
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from pymoo.util.dominator import Dominator
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def naive_non_dominated_sort(F, **kwargs):
|
|
5
|
+
M = Dominator.calc_domination_matrix(F)
|
|
6
|
+
|
|
7
|
+
fronts = []
|
|
8
|
+
remaining = set(range(M.shape[0]))
|
|
9
|
+
|
|
10
|
+
while len(remaining) > 0:
|
|
11
|
+
|
|
12
|
+
front = []
|
|
13
|
+
|
|
14
|
+
for i in remaining:
|
|
15
|
+
|
|
16
|
+
is_dominated = False
|
|
17
|
+
dominating = set()
|
|
18
|
+
|
|
19
|
+
for j in front:
|
|
20
|
+
rel = M[i, j]
|
|
21
|
+
if rel == 1:
|
|
22
|
+
dominating.add(j)
|
|
23
|
+
elif rel == -1:
|
|
24
|
+
is_dominated = True
|
|
25
|
+
break
|
|
26
|
+
|
|
27
|
+
if is_dominated:
|
|
28
|
+
continue
|
|
29
|
+
else:
|
|
30
|
+
front = [x for x in front if x not in dominating]
|
|
31
|
+
front.append(i)
|
|
32
|
+
|
|
33
|
+
[remaining.remove(e) for e in front]
|
|
34
|
+
fronts.append(front)
|
|
35
|
+
|
|
36
|
+
return fronts
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import sys
|
|
3
|
+
from pymoo.util.dominator import Dominator
|
|
4
|
+
from pymoo.util.function_loader import load_function
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class NonDominatedSorting:
|
|
8
|
+
|
|
9
|
+
def __init__(self, epsilon=None, method="fast_non_dominated_sort") -> None:
|
|
10
|
+
super().__init__()
|
|
11
|
+
self.epsilon = epsilon
|
|
12
|
+
self.method = method
|
|
13
|
+
|
|
14
|
+
def do(self, F, return_rank=False, only_non_dominated_front=False, n_stop_if_ranked=None, **kwargs):
|
|
15
|
+
F = F.astype(float)
|
|
16
|
+
|
|
17
|
+
# if not set just set it to a very large values because the cython algorithms do not take None
|
|
18
|
+
if n_stop_if_ranked is None:
|
|
19
|
+
n_stop_if_ranked = int(1e8)
|
|
20
|
+
func = load_function(self.method)
|
|
21
|
+
|
|
22
|
+
# set the epsilon if it should be set
|
|
23
|
+
if self.epsilon is not None:
|
|
24
|
+
kwargs["epsilon"] = float(self.epsilon)
|
|
25
|
+
|
|
26
|
+
fronts = func(F, **kwargs)
|
|
27
|
+
|
|
28
|
+
# convert to numpy array for each front and filter by n_stop_if_ranked if desired
|
|
29
|
+
_fronts = []
|
|
30
|
+
n_ranked = 0
|
|
31
|
+
for front in fronts:
|
|
32
|
+
|
|
33
|
+
_fronts.append(np.array(front, dtype=int))
|
|
34
|
+
|
|
35
|
+
# increment the n_ranked solution counter
|
|
36
|
+
n_ranked += len(front)
|
|
37
|
+
|
|
38
|
+
# stop if more than this solutions are n_ranked
|
|
39
|
+
if n_ranked >= n_stop_if_ranked:
|
|
40
|
+
break
|
|
41
|
+
|
|
42
|
+
fronts = _fronts
|
|
43
|
+
|
|
44
|
+
if only_non_dominated_front:
|
|
45
|
+
return fronts[0]
|
|
46
|
+
|
|
47
|
+
if return_rank:
|
|
48
|
+
rank = rank_from_fronts(fronts, F.shape[0])
|
|
49
|
+
return fronts, rank
|
|
50
|
+
|
|
51
|
+
return fronts
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def rank_from_fronts(fronts, n):
|
|
55
|
+
# create the rank array and set values
|
|
56
|
+
rank = np.full(n, sys.maxsize, dtype=int)
|
|
57
|
+
for i, front in enumerate(fronts):
|
|
58
|
+
rank[front] = i
|
|
59
|
+
|
|
60
|
+
return rank
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
# Returns all indices of F that are not dominated by the other objective values
|
|
64
|
+
def find_non_dominated(F, _F=None):
|
|
65
|
+
M = Dominator.calc_domination_matrix(F, _F)
|
|
66
|
+
I = np.where(np.all(M >= 0, axis=1))[0]
|
|
67
|
+
return I
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import weakref
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Tree:
|
|
8
|
+
'''
|
|
9
|
+
Implementation of Nary-tree.
|
|
10
|
+
The source code is modified based on https://github.com/lianemeth/forest/blob/master/forest/NaryTree.py
|
|
11
|
+
|
|
12
|
+
Parameters
|
|
13
|
+
----------
|
|
14
|
+
key: object
|
|
15
|
+
key of the node
|
|
16
|
+
num_branch: int
|
|
17
|
+
how many branches in each node
|
|
18
|
+
children: Iterable[Tree]
|
|
19
|
+
reference of the children
|
|
20
|
+
parent: Tree
|
|
21
|
+
reference of the parent node
|
|
22
|
+
Returns
|
|
23
|
+
-------
|
|
24
|
+
an N-ary tree.
|
|
25
|
+
'''
|
|
26
|
+
|
|
27
|
+
def __init__(self, key, num_branch, children=None, parent=None):
|
|
28
|
+
self.key = key
|
|
29
|
+
self.children = children or [None for _ in range(num_branch)]
|
|
30
|
+
|
|
31
|
+
self._parent = weakref.ref(parent) if parent else None
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def parent(self):
|
|
35
|
+
if self._parent:
|
|
36
|
+
return self._parent()
|
|
37
|
+
|
|
38
|
+
def __getstate__(self):
|
|
39
|
+
self._parent = None
|
|
40
|
+
|
|
41
|
+
def __setstate__(self, state):
|
|
42
|
+
self.__dict__ = state
|
|
43
|
+
for child in self.children:
|
|
44
|
+
child._parent = weakref.ref(self)
|
|
45
|
+
|
|
46
|
+
def traversal(self, visit=None, *args, **kwargs):
|
|
47
|
+
if visit is not None:
|
|
48
|
+
visit(self, *args, **kwargs)
|
|
49
|
+
l = [self]
|
|
50
|
+
for child in self.children:
|
|
51
|
+
if child is not None:
|
|
52
|
+
l += child.traversal(visit, *args, **kwargs)
|
|
53
|
+
return l
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def tree_based_non_dominated_sort(F):
|
|
57
|
+
"""
|
|
58
|
+
Tree-based efficient non-dominated sorting (T-ENS).
|
|
59
|
+
This algorithm is very efficient in many-objective optimization problems (MaOPs).
|
|
60
|
+
Parameters
|
|
61
|
+
----------
|
|
62
|
+
F: np.array
|
|
63
|
+
objective values for each individual.
|
|
64
|
+
Returns
|
|
65
|
+
-------
|
|
66
|
+
indices of the individuals in each front.
|
|
67
|
+
References
|
|
68
|
+
----------
|
|
69
|
+
X. Zhang, Y. Tian, R. Cheng, and Y. Jin,
|
|
70
|
+
A decision variable clustering based evolutionary algorithm for large-scale many-objective optimization,
|
|
71
|
+
IEEE Transactions on Evolutionary Computation, 2018, 22(1): 97-112.
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
N, M = F.shape
|
|
75
|
+
# sort the rows in F
|
|
76
|
+
indices = np.lexsort(F.T[::-1])
|
|
77
|
+
F = F[indices]
|
|
78
|
+
|
|
79
|
+
obj_seq = np.argsort(F[:, :0:-1], axis=1) + 1
|
|
80
|
+
|
|
81
|
+
k = 0
|
|
82
|
+
|
|
83
|
+
forest = []
|
|
84
|
+
|
|
85
|
+
left = np.full(N, True)
|
|
86
|
+
while np.any(left):
|
|
87
|
+
forest.append(None)
|
|
88
|
+
for p, flag in enumerate(left):
|
|
89
|
+
if flag:
|
|
90
|
+
update_tree(F, p, forest, k, left, obj_seq)
|
|
91
|
+
k += 1
|
|
92
|
+
|
|
93
|
+
# convert forest to fronts
|
|
94
|
+
fronts = [[] for _ in range(k)]
|
|
95
|
+
for k, tree in enumerate(forest):
|
|
96
|
+
fronts[k].extend([indices[node.key] for node in tree.traversal()])
|
|
97
|
+
return fronts
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def update_tree(F, p, forest, k, left, obj_seq):
|
|
101
|
+
_, M = F.shape
|
|
102
|
+
if forest[k] is None:
|
|
103
|
+
forest[k] = Tree(key=p, num_branch=M - 1)
|
|
104
|
+
left[p] = False
|
|
105
|
+
elif check_tree(F, p, forest[k], obj_seq, True):
|
|
106
|
+
left[p] = False
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def check_tree(F, p, tree, obj_seq, add_pos):
|
|
110
|
+
if tree is None:
|
|
111
|
+
return True
|
|
112
|
+
|
|
113
|
+
N, M = F.shape
|
|
114
|
+
|
|
115
|
+
# find the minimal index m satisfying that p[obj_seq[tree.root][m]] < tree.root[obj_seq[tree.root][m]]
|
|
116
|
+
m = 0
|
|
117
|
+
while m < M - 1 and F[p, obj_seq[tree.key, m]] >= F[tree.key, obj_seq[tree.key, m]]:
|
|
118
|
+
m += 1
|
|
119
|
+
|
|
120
|
+
# if m not found
|
|
121
|
+
if m == M - 1:
|
|
122
|
+
# p is dominated by the solution at the root
|
|
123
|
+
return False
|
|
124
|
+
else:
|
|
125
|
+
for i in range(m + 1):
|
|
126
|
+
# p is dominated by a solution in the branch of the tree
|
|
127
|
+
if not check_tree(F, p, tree.children[i], obj_seq, i == m and add_pos):
|
|
128
|
+
return False
|
|
129
|
+
|
|
130
|
+
if tree.children[m] is None and add_pos:
|
|
131
|
+
# add p to the branch of the tree
|
|
132
|
+
tree.children[m] = Tree(key=p, num_branch=M - 1)
|
|
133
|
+
return True
|