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,312 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
from abc import abstractmethod
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
7
|
+
# Object Oriented Interface
|
|
8
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
# ---- Abstract Class
|
|
11
|
+
from numpy.linalg import LinAlgError
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Normalization:
|
|
15
|
+
|
|
16
|
+
def __init__(self) -> None:
|
|
17
|
+
super().__init__()
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def forward(self, X):
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
@abstractmethod
|
|
24
|
+
def backward(self, X):
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# ---- Useful if normalization is optional - can be simply disabled by using this object
|
|
29
|
+
class NoNormalization(Normalization):
|
|
30
|
+
|
|
31
|
+
def forward(self, X):
|
|
32
|
+
return X
|
|
33
|
+
|
|
34
|
+
def backward(self, X):
|
|
35
|
+
return X
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# ---- Normalizes between zero and one given bounds or estimating them
|
|
39
|
+
class ZeroToOneNormalization(Normalization):
|
|
40
|
+
|
|
41
|
+
def __init__(self, xl=None, xu=None) -> None:
|
|
42
|
+
super().__init__()
|
|
43
|
+
|
|
44
|
+
# if both are None we are basically done because normalization is disabled
|
|
45
|
+
if xl is None and xu is None:
|
|
46
|
+
self.xl, self.xu = None, None
|
|
47
|
+
return
|
|
48
|
+
|
|
49
|
+
# if not set simply fall back no nan values
|
|
50
|
+
if xl is None:
|
|
51
|
+
xl = np.full_like(xu, np.nan)
|
|
52
|
+
if xu is None:
|
|
53
|
+
xu = np.full_like(xl, np.nan)
|
|
54
|
+
|
|
55
|
+
xl, xu = np.copy(xl).astype(float), np.copy(xu).astype(float)
|
|
56
|
+
|
|
57
|
+
# if both are equal then set the upper bound to none (always the 0 or lower bound will be returned then)
|
|
58
|
+
xu[xl == xu] = np.nan
|
|
59
|
+
|
|
60
|
+
# store the lower and upper bounds
|
|
61
|
+
self.xl, self.xu = xl, xu
|
|
62
|
+
|
|
63
|
+
# check out when the input values are nan
|
|
64
|
+
xl_nan, xu_nan = np.isnan(xl), np.isnan(xu)
|
|
65
|
+
|
|
66
|
+
# now create all the masks that are necessary
|
|
67
|
+
self.xl_only, self.xu_only = np.logical_and(~xl_nan, xu_nan), np.logical_and(xl_nan, ~xu_nan)
|
|
68
|
+
self.both_nan = np.logical_and(np.isnan(xl), np.isnan(xu))
|
|
69
|
+
self.neither_nan = np.logical_and(~np.isnan(xl), ~np.isnan(xu))
|
|
70
|
+
|
|
71
|
+
# if neither is nan than xu must be greater or equal than xl
|
|
72
|
+
any_nan = np.logical_or(np.isnan(xl), np.isnan(xu))
|
|
73
|
+
assert np.all(np.logical_or(xu >= xl, any_nan)), "xl must be less or equal than xu."
|
|
74
|
+
|
|
75
|
+
def forward(self, X):
|
|
76
|
+
if X is None or (self.xl is None and self.xu is None):
|
|
77
|
+
return X
|
|
78
|
+
|
|
79
|
+
# simple copy the input
|
|
80
|
+
N = np.copy(X)
|
|
81
|
+
|
|
82
|
+
# normalize between zero and one if neither of them is nan
|
|
83
|
+
N[..., self.neither_nan] = (X[..., self.neither_nan] - self.xl[self.neither_nan]) / (self.xu[self.neither_nan] - self.xl[self.neither_nan])
|
|
84
|
+
|
|
85
|
+
N[..., self.xl_only] = X[..., self.xl_only] - self.xl[self.xl_only]
|
|
86
|
+
|
|
87
|
+
N[..., self.xu_only] = 1.0 - (self.xu[self.xu_only] - X[..., self.xu_only])
|
|
88
|
+
|
|
89
|
+
return N
|
|
90
|
+
|
|
91
|
+
def backward(self, N):
|
|
92
|
+
if N is None or (self.xl is None and self.xu is None):
|
|
93
|
+
return N
|
|
94
|
+
|
|
95
|
+
xl, xu, xl_only, xu_only = self.xl, self.xu, self.xl_only, self.xu_only
|
|
96
|
+
both_nan, neither_nan = self.both_nan, self.neither_nan
|
|
97
|
+
|
|
98
|
+
X = N.copy()
|
|
99
|
+
X[..., neither_nan] = xl[neither_nan] + N[..., neither_nan] * (xu[neither_nan] - xl[neither_nan])
|
|
100
|
+
|
|
101
|
+
X[..., xl_only] = N[..., xl_only] + xl[xl_only]
|
|
102
|
+
|
|
103
|
+
X[..., xu_only] = xu[xu_only] - (1.0 - N[..., xu_only])
|
|
104
|
+
|
|
105
|
+
return X
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
109
|
+
# Simple Normalization
|
|
110
|
+
# Does not consider any none values and assumes lower as well as upper bounds are given.
|
|
111
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class SimpleZeroToOneNormalization(Normalization):
|
|
115
|
+
|
|
116
|
+
def __init__(self, xl=None, xu=None, estimate_bounds=True) -> None:
|
|
117
|
+
super().__init__()
|
|
118
|
+
self.xl = xl
|
|
119
|
+
self.xu = xu
|
|
120
|
+
self.estimate_bounds = estimate_bounds
|
|
121
|
+
|
|
122
|
+
def forward(self, X):
|
|
123
|
+
|
|
124
|
+
if self.estimate_bounds:
|
|
125
|
+
if self.xl is None:
|
|
126
|
+
self.xl = np.min(X, axis=0)
|
|
127
|
+
if self.xu is None:
|
|
128
|
+
self.xu = np.max(X, axis=0)
|
|
129
|
+
|
|
130
|
+
xl, xu = self.xl, self.xu
|
|
131
|
+
|
|
132
|
+
# if np.any(xl == xu):
|
|
133
|
+
# raise Exception("Normalization failed because lower and upper bounds are equal!")
|
|
134
|
+
|
|
135
|
+
# calculate the denominator
|
|
136
|
+
denom = xu - xl
|
|
137
|
+
|
|
138
|
+
# we can not divide by zero -> plus small epsilon
|
|
139
|
+
denom += (denom == 0) * 1e-32
|
|
140
|
+
|
|
141
|
+
# normalize the actual values
|
|
142
|
+
N = (X - xl) / denom
|
|
143
|
+
|
|
144
|
+
return N
|
|
145
|
+
|
|
146
|
+
def backward(self, X):
|
|
147
|
+
return X * (self.xu - self.xl) + self.xl
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
151
|
+
# Functional Interface
|
|
152
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def normalize(X, xl=None, xu=None, return_bounds=False, estimate_bounds_if_none=True):
|
|
156
|
+
if estimate_bounds_if_none:
|
|
157
|
+
if xl is None:
|
|
158
|
+
xl = np.min(X, axis=0)
|
|
159
|
+
if xu is None:
|
|
160
|
+
xu = np.max(X, axis=0)
|
|
161
|
+
|
|
162
|
+
if isinstance(xl, float) or isinstance(xl, int):
|
|
163
|
+
xl = np.full(X.shape[-1], xl)
|
|
164
|
+
|
|
165
|
+
if isinstance(xu, float) or isinstance(xu, int):
|
|
166
|
+
xu = np.full(X.shape[-1], xu)
|
|
167
|
+
|
|
168
|
+
norm = ZeroToOneNormalization(xl, xu)
|
|
169
|
+
X = norm.forward(X)
|
|
170
|
+
|
|
171
|
+
if not return_bounds:
|
|
172
|
+
return X
|
|
173
|
+
else:
|
|
174
|
+
return X, norm.xl, norm.xu
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def denormalize(x, xl, xu):
|
|
178
|
+
return ZeroToOneNormalization(xl, xu).backward(x)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def standardize(x, return_bounds=False):
|
|
182
|
+
mean = np.mean(x, axis=0)
|
|
183
|
+
std = np.std(x, axis=0)
|
|
184
|
+
|
|
185
|
+
# standardize
|
|
186
|
+
val = (x - mean) / std
|
|
187
|
+
|
|
188
|
+
if not return_bounds:
|
|
189
|
+
return val
|
|
190
|
+
else:
|
|
191
|
+
return val, mean, std
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def destandardize(x, mean, std):
|
|
195
|
+
return (x * std) + mean
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
199
|
+
# Pre Normalization
|
|
200
|
+
# A class inheriting from it can use the in-built feature of normalizing
|
|
201
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
class PreNormalization:
|
|
205
|
+
|
|
206
|
+
def __init__(self, zero_to_one=False, ideal=None, nadir=None, **kwargs):
|
|
207
|
+
|
|
208
|
+
# normalization related stuff if that should be performed beforehand
|
|
209
|
+
self.ideal, self.nadir = ideal, nadir
|
|
210
|
+
|
|
211
|
+
if zero_to_one:
|
|
212
|
+
assert self.ideal is not None and self.nadir is not None, "For normalization either provide pf or bounds!"
|
|
213
|
+
|
|
214
|
+
n_dim = len(self.ideal)
|
|
215
|
+
self.normalization = ZeroToOneNormalization(self.ideal, self.nadir)
|
|
216
|
+
|
|
217
|
+
# now the ideal and nadir points have change to only zeros and ones
|
|
218
|
+
self.ideal, self.nadir = np.zeros(n_dim), np.ones(n_dim)
|
|
219
|
+
|
|
220
|
+
else:
|
|
221
|
+
self.normalization = NoNormalization()
|
|
222
|
+
|
|
223
|
+
def do(self, *args, **kwargs):
|
|
224
|
+
pass
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
228
|
+
# Normalization in the Objective Space
|
|
229
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def find_ideal(F, current=None):
|
|
233
|
+
p = F.min(axis=0)
|
|
234
|
+
if current is not None:
|
|
235
|
+
p = np.minimum(current, p)
|
|
236
|
+
return p
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def get_extreme_points_c(F, ideal_point, extreme_points=None):
|
|
240
|
+
# calculate the asf which is used for the extreme point decomposition
|
|
241
|
+
weights = np.eye(F.shape[1])
|
|
242
|
+
weights[weights == 0] = 1e6
|
|
243
|
+
|
|
244
|
+
# add the old extreme points to never loose them for normalization
|
|
245
|
+
_F = F
|
|
246
|
+
if extreme_points is not None:
|
|
247
|
+
_F = np.concatenate([extreme_points, _F], axis=0)
|
|
248
|
+
|
|
249
|
+
# use __F because we substitute small values to be 0
|
|
250
|
+
__F = _F - ideal_point
|
|
251
|
+
__F[__F < 1e-3] = 0
|
|
252
|
+
|
|
253
|
+
# update the extreme points for the normalization having the highest asf value each
|
|
254
|
+
F_asf = np.max(__F * weights[:, None, :], axis=2)
|
|
255
|
+
|
|
256
|
+
I = np.argmin(F_asf, axis=1)
|
|
257
|
+
extreme_points = _F[I, :]
|
|
258
|
+
|
|
259
|
+
return extreme_points
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def get_nadir_point(extreme_points, ideal_point, worst_point, worst_of_front, worst_of_population):
|
|
263
|
+
try:
|
|
264
|
+
|
|
265
|
+
# find the intercepts using gaussian elimination
|
|
266
|
+
M = extreme_points - ideal_point
|
|
267
|
+
b = np.ones(extreme_points.shape[1])
|
|
268
|
+
plane = np.linalg.solve(M, b)
|
|
269
|
+
|
|
270
|
+
warnings.simplefilter("ignore")
|
|
271
|
+
intercepts = 1 / plane
|
|
272
|
+
|
|
273
|
+
nadir_point = ideal_point + intercepts
|
|
274
|
+
|
|
275
|
+
# check if the hyperplane makes sense
|
|
276
|
+
if not np.allclose(np.dot(M, plane), b) or np.any(intercepts <= 1e-6):
|
|
277
|
+
raise LinAlgError()
|
|
278
|
+
|
|
279
|
+
# if the nadir point should be larger than any value discovered so far set it to that value
|
|
280
|
+
# NOTE: different to the proposed version in the paper
|
|
281
|
+
b = nadir_point > worst_point
|
|
282
|
+
nadir_point[b] = worst_point[b]
|
|
283
|
+
|
|
284
|
+
except LinAlgError:
|
|
285
|
+
|
|
286
|
+
# fall back to worst of front otherwise
|
|
287
|
+
nadir_point = worst_of_front
|
|
288
|
+
|
|
289
|
+
# if the range is too small set it to worst of population
|
|
290
|
+
b = nadir_point - ideal_point <= 1e-6
|
|
291
|
+
nadir_point[b] = worst_of_population[b]
|
|
292
|
+
|
|
293
|
+
return nadir_point
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
class ObjectiveSpaceNormalization:
|
|
297
|
+
|
|
298
|
+
def __init__(self) -> None:
|
|
299
|
+
super().__init__()
|
|
300
|
+
self._ideal = None
|
|
301
|
+
self._infeas_ideal = None
|
|
302
|
+
self._worst = None
|
|
303
|
+
|
|
304
|
+
def update(self, pop):
|
|
305
|
+
F, feas = pop.get("F", "FEAS")
|
|
306
|
+
self._infeas_ideal = find_ideal(F, current=self._infeas_ideal)
|
|
307
|
+
|
|
308
|
+
if np.any(feas):
|
|
309
|
+
self._ideal = find_ideal(F[feas[:, 0]], self._ideal)
|
|
310
|
+
|
|
311
|
+
def ideal(self, only_feas=True):
|
|
312
|
+
return self._ideal if only_feas else self._infeas_ideal
|
pymoo/util/optimum.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pymoo.core.individual import Individual
|
|
4
|
+
from pymoo.core.population import Population
|
|
5
|
+
from pymoo.util.nds.non_dominated_sorting import NonDominatedSorting
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def filter_optimum(pop, least_infeasible=False):
|
|
9
|
+
|
|
10
|
+
# if the population is none to optimum can be found
|
|
11
|
+
if pop is None or len(pop) == 0:
|
|
12
|
+
return None
|
|
13
|
+
|
|
14
|
+
# first only choose feasible solutions
|
|
15
|
+
ret = pop[pop.get("feas")]
|
|
16
|
+
|
|
17
|
+
# if at least one feasible solution was found
|
|
18
|
+
if len(ret) > 0:
|
|
19
|
+
|
|
20
|
+
# then check the objective values
|
|
21
|
+
F = ret.get("F")
|
|
22
|
+
|
|
23
|
+
if F.shape[1] > 1:
|
|
24
|
+
I = NonDominatedSorting().do(F, only_non_dominated_front=True)
|
|
25
|
+
ret = ret[I]
|
|
26
|
+
|
|
27
|
+
else:
|
|
28
|
+
ret = ret[np.argmin(F[:, 0])]
|
|
29
|
+
|
|
30
|
+
# no feasible solution was found
|
|
31
|
+
else:
|
|
32
|
+
# if flag enable report the least infeasible
|
|
33
|
+
if least_infeasible:
|
|
34
|
+
ret = pop[np.argmin(pop.get("CV"))]
|
|
35
|
+
# otherwise just return none
|
|
36
|
+
else:
|
|
37
|
+
ret = None
|
|
38
|
+
|
|
39
|
+
if isinstance(ret, Individual):
|
|
40
|
+
ret = Population().create(ret)
|
|
41
|
+
|
|
42
|
+
return ret
|
pymoo/util/plotting.py
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import matplotlib.pyplot as plt
|
|
2
|
+
import numpy as np
|
|
3
|
+
from matplotlib import animation
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def plot(*args, show=True, labels=None, no_fill=False, **kwargs):
|
|
7
|
+
F = args[0]
|
|
8
|
+
|
|
9
|
+
if F.ndim == 1:
|
|
10
|
+
print("Cannot plot a one dimensional array.")
|
|
11
|
+
return
|
|
12
|
+
|
|
13
|
+
n_dim = F.shape[1]
|
|
14
|
+
|
|
15
|
+
if n_dim == 2:
|
|
16
|
+
ret = plot_2d(*args, labels=labels, no_fill=no_fill, **kwargs)
|
|
17
|
+
elif n_dim == 3:
|
|
18
|
+
ret = plot_3d(*args, labels=labels, no_fill=no_fill, **kwargs)
|
|
19
|
+
else:
|
|
20
|
+
print("Cannot plot a %s dimensional array." % n_dim)
|
|
21
|
+
return
|
|
22
|
+
|
|
23
|
+
if labels:
|
|
24
|
+
plt.legend()
|
|
25
|
+
|
|
26
|
+
if show:
|
|
27
|
+
plt.show()
|
|
28
|
+
|
|
29
|
+
return ret
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def plot_3d(*args, no_fill=False, labels=None, **kwargs):
|
|
33
|
+
fig = plt.figure()
|
|
34
|
+
ax = fig.add_subplot(111, projection='3d')
|
|
35
|
+
|
|
36
|
+
for i, F in enumerate(args):
|
|
37
|
+
|
|
38
|
+
if no_fill:
|
|
39
|
+
kwargs["s"] = 20
|
|
40
|
+
kwargs["marker"] = '.'
|
|
41
|
+
kwargs["facecolors"] = (0, 0, 0, 0)
|
|
42
|
+
kwargs["edgecolors"] = 'r'
|
|
43
|
+
|
|
44
|
+
if labels:
|
|
45
|
+
ax.scatter(F[:, 0], F[:, 1], F[:, 2], label=labels[i], **kwargs)
|
|
46
|
+
else:
|
|
47
|
+
ax.scatter(F[:, 0], F[:, 1], F[:, 2], **kwargs)
|
|
48
|
+
|
|
49
|
+
return ax
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def plot_2d(*args, labels=None, no_fill=False):
|
|
53
|
+
if no_fill:
|
|
54
|
+
kwargs = dict(
|
|
55
|
+
s=20,
|
|
56
|
+
facecolors='none',
|
|
57
|
+
edgecolors='r'
|
|
58
|
+
)
|
|
59
|
+
else:
|
|
60
|
+
kwargs = {}
|
|
61
|
+
|
|
62
|
+
for i, F in enumerate(args):
|
|
63
|
+
if labels:
|
|
64
|
+
plt.scatter(F[:, 0], F[:, 1], label=labels[i], **kwargs)
|
|
65
|
+
else:
|
|
66
|
+
plt.scatter(F[:, 0], F[:, 1], **kwargs)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def animate(path_to_file, H, problem=None, func_iter=None, plot_min=None, plot_max=None):
|
|
70
|
+
if H.ndim != 3 or H.shape[2] != 2:
|
|
71
|
+
print("Can only animate a two dimensional set of arrays.")
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
fig = plt.figure()
|
|
75
|
+
ax = plt.gca()
|
|
76
|
+
|
|
77
|
+
# plot the pareto front if it is known for the problem
|
|
78
|
+
if problem is not None:
|
|
79
|
+
pf = problem.pareto_front()
|
|
80
|
+
plt.scatter(pf[:, 0], pf[:, 1], label='Pareto Front', s=60, facecolors='none', edgecolors='r')
|
|
81
|
+
|
|
82
|
+
# plot the initial population
|
|
83
|
+
_F = H[0, :, :]
|
|
84
|
+
scat = plt.scatter(_F[:, 0], _F[:, 1])
|
|
85
|
+
plt.title("0")
|
|
86
|
+
|
|
87
|
+
if func_iter is not None:
|
|
88
|
+
func_iter(ax, H[0])
|
|
89
|
+
|
|
90
|
+
# the update method
|
|
91
|
+
def update(n):
|
|
92
|
+
_F = H[n, :, :]
|
|
93
|
+
scat.set_offsets(_F)
|
|
94
|
+
|
|
95
|
+
# get the bounds for plotting and add padding
|
|
96
|
+
min = np.min(_F, axis=0) - 0.1
|
|
97
|
+
max = np.max(_F, axis=0) + 0.1
|
|
98
|
+
|
|
99
|
+
# set the scatter object with padding
|
|
100
|
+
ax.set_xlim(min[0], max[0])
|
|
101
|
+
ax.set_ylim(min[1], max[1])
|
|
102
|
+
|
|
103
|
+
if func_iter is not None:
|
|
104
|
+
func_iter(ax, H[n])
|
|
105
|
+
|
|
106
|
+
plt.title(n)
|
|
107
|
+
|
|
108
|
+
# create the animation
|
|
109
|
+
ani = animation.FuncAnimation(fig, update, frames=H.shape[0])
|
|
110
|
+
|
|
111
|
+
# write the file
|
|
112
|
+
Writer = animation.writers['ffmpeg']
|
|
113
|
+
writer = Writer(fps=6, bitrate=1800)
|
|
114
|
+
ani.save(path_to_file, writer=writer)
|
|
115
|
+
|
|
116
|
+
print("Saving: ", path_to_file)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def plot_problem_surface(problem, n_samples, plot_type="wireframe", cmap="summer", show=True, return_figure=False):
|
|
120
|
+
try:
|
|
121
|
+
import matplotlib.pyplot as plt
|
|
122
|
+
from mpl_toolkits.mplot3d import Axes3D
|
|
123
|
+
except:
|
|
124
|
+
raise Exception("Please install 'matplotlib' to use the plotting functionality.")
|
|
125
|
+
|
|
126
|
+
fig = plt.figure()
|
|
127
|
+
|
|
128
|
+
if problem.n_var == 1 and problem.n_obj == 1:
|
|
129
|
+
|
|
130
|
+
X = np.linspace(problem.xl[0], problem.xu[0], num=n_samples)[:, None]
|
|
131
|
+
Y = problem.evaluate(X, return_values_of=["F"])
|
|
132
|
+
ax = plt.plot(X, Y)
|
|
133
|
+
|
|
134
|
+
elif problem.n_var == 2 and problem.n_obj == 1:
|
|
135
|
+
|
|
136
|
+
X_range = np.linspace(problem.xl[0], problem.xu[0], num=n_samples)
|
|
137
|
+
Y_range = np.linspace(problem.xl[1], problem.xu[1], num=n_samples)
|
|
138
|
+
X, Y = np.meshgrid(X_range, Y_range)
|
|
139
|
+
|
|
140
|
+
A = np.zeros((n_samples * n_samples, 2))
|
|
141
|
+
counter = 0
|
|
142
|
+
for i, x in enumerate(X_range):
|
|
143
|
+
for j, y in enumerate(Y_range):
|
|
144
|
+
A[counter, 0] = x
|
|
145
|
+
A[counter, 1] = y
|
|
146
|
+
counter += 1
|
|
147
|
+
|
|
148
|
+
F = np.reshape(problem.evaluate(A, return_values_of=["F"]), (n_samples, n_samples))
|
|
149
|
+
|
|
150
|
+
# Plot the surface.
|
|
151
|
+
if plot_type == "wireframe":
|
|
152
|
+
ax = fig.add_subplot(111, projection='3d')
|
|
153
|
+
ax.plot_wireframe(X, Y, F)
|
|
154
|
+
elif plot_type == "contour":
|
|
155
|
+
CS = plt.contour(X, Y, F)
|
|
156
|
+
plt.clabel(CS, inline=1, fontsize=10)
|
|
157
|
+
elif plot_type == "wireframe+contour":
|
|
158
|
+
ax = fig.add_subplot(111, projection="3d")
|
|
159
|
+
ax.plot_surface(X, Y, F, cmap=cmap, rstride=1, cstride=1)
|
|
160
|
+
ax.contour(X, Y, F, 10, linestyles="solid", offset=-1)
|
|
161
|
+
ax.set_xlabel("$x_1$")
|
|
162
|
+
ax.set_ylabel("$x_2$")
|
|
163
|
+
ax.set_zlabel("$f(x)$")
|
|
164
|
+
ax.view_init(45, 45)
|
|
165
|
+
else:
|
|
166
|
+
raise Exception("Unknown plotting method.")
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
else:
|
|
170
|
+
raise Exception("Can only plot single with less than two variables and one objective.")
|
|
171
|
+
|
|
172
|
+
if show:
|
|
173
|
+
plt.tight_layout()
|
|
174
|
+
plt.show()
|
|
175
|
+
|
|
176
|
+
if return_figure:
|
|
177
|
+
return fig, ax
|
pymoo/util/pruning_cd.py
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
def calc_pcd(X, n_remove=0):
|
|
4
|
+
|
|
5
|
+
N = X.shape[0]
|
|
6
|
+
M = X.shape[1]
|
|
7
|
+
|
|
8
|
+
if n_remove <= (N - M):
|
|
9
|
+
if n_remove < 0:
|
|
10
|
+
n_remove = 0
|
|
11
|
+
else:
|
|
12
|
+
pass
|
|
13
|
+
else:
|
|
14
|
+
n_remove = N - M
|
|
15
|
+
|
|
16
|
+
extremes_min = np.argmin(X, axis=0)
|
|
17
|
+
extremes_max = np.argmax(X, axis=0)
|
|
18
|
+
|
|
19
|
+
min_vals = np.min(X, axis=0)
|
|
20
|
+
max_vals = np.max(X, axis=0)
|
|
21
|
+
|
|
22
|
+
extremes = np.concatenate((extremes_min, extremes_max))
|
|
23
|
+
|
|
24
|
+
X = (X - min_vals) / (max_vals - min_vals)
|
|
25
|
+
|
|
26
|
+
H = np.arange(N)
|
|
27
|
+
d = np.full(N, np.inf)
|
|
28
|
+
|
|
29
|
+
I = np.argsort(X, axis=0, kind='mergesort')
|
|
30
|
+
|
|
31
|
+
# sort the objective space values for the whole matrix
|
|
32
|
+
_X = X[I, np.arange(M)]
|
|
33
|
+
|
|
34
|
+
# calculate the distance from each point to the last and next
|
|
35
|
+
dist = np.row_stack([_X, np.full(M, np.inf)]) - np.row_stack([np.full(M, -np.inf), _X])
|
|
36
|
+
|
|
37
|
+
# prepare the distance to last and next vectors
|
|
38
|
+
dist_to_last, dist_to_next = dist, np.copy(dist)
|
|
39
|
+
dist_to_last, dist_to_next = dist_to_last[:-1], dist_to_next[1:]
|
|
40
|
+
|
|
41
|
+
# if we divide by zero because all values in one columns are equal replace by none
|
|
42
|
+
dist_to_last[np.isnan(dist_to_last)] = 0.0
|
|
43
|
+
dist_to_next[np.isnan(dist_to_next)] = 0.0
|
|
44
|
+
|
|
45
|
+
# sum up the distance to next and last and norm by objectives - also reorder from sorted list
|
|
46
|
+
J = np.argsort(I, axis=0)
|
|
47
|
+
_d = np.sum(dist_to_last[J, np.arange(M)] + dist_to_next[J, np.arange(M)], axis=1)
|
|
48
|
+
d[H] = _d
|
|
49
|
+
d[extremes] = np.inf
|
|
50
|
+
|
|
51
|
+
n_removed = 0
|
|
52
|
+
|
|
53
|
+
#While n_remove not acheived
|
|
54
|
+
while n_removed < (n_remove - 1):
|
|
55
|
+
|
|
56
|
+
#Obtain element to drop
|
|
57
|
+
_d = d[H]
|
|
58
|
+
_k = np.argmin(_d)
|
|
59
|
+
k = H[_k]
|
|
60
|
+
|
|
61
|
+
H = H[H != k]
|
|
62
|
+
|
|
63
|
+
#Update index
|
|
64
|
+
n_removed = n_removed + 1
|
|
65
|
+
|
|
66
|
+
I = np.argsort(X[H].copy(), axis=0, kind='mergesort')
|
|
67
|
+
|
|
68
|
+
# sort the objective space values for the whole matrix
|
|
69
|
+
_X = X[H].copy()[I, np.arange(M)]
|
|
70
|
+
|
|
71
|
+
# calculate the distance from each point to the last and next
|
|
72
|
+
dist = np.row_stack([_X, np.full(M, np.inf)]) - np.row_stack([np.full(M, -np.inf), _X])
|
|
73
|
+
|
|
74
|
+
# prepare the distance to last and next vectors
|
|
75
|
+
dist_to_last, dist_to_next = dist, np.copy(dist)
|
|
76
|
+
dist_to_last, dist_to_next = dist_to_last[:-1], dist_to_next[1:]
|
|
77
|
+
|
|
78
|
+
# if we divide by zero because all values in one columns are equal replace by none
|
|
79
|
+
dist_to_last[np.isnan(dist_to_last)] = 0.0
|
|
80
|
+
dist_to_next[np.isnan(dist_to_next)] = 0.0
|
|
81
|
+
|
|
82
|
+
# sum up the distance to next and last and norm by objectives - also reorder from sorted list
|
|
83
|
+
J = np.argsort(I, axis=0)
|
|
84
|
+
_d = np.sum(dist_to_last[J, np.arange(M)] + dist_to_next[J, np.arange(M)], axis=1)
|
|
85
|
+
d[H] = _d
|
|
86
|
+
d[extremes] = np.inf
|
|
87
|
+
|
|
88
|
+
return d
|
|
89
|
+
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pymoo.util.misc import swap
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def randomized_argsort(A, method="numpy", order='ascending'):
|
|
7
|
+
if method == "numpy":
|
|
8
|
+
P = np.random.permutation(len(A))
|
|
9
|
+
I = np.argsort(A[P], kind='quicksort')
|
|
10
|
+
I = P[I]
|
|
11
|
+
|
|
12
|
+
elif method == "quicksort":
|
|
13
|
+
I = quicksort(A)
|
|
14
|
+
|
|
15
|
+
else:
|
|
16
|
+
raise Exception("Randomized sort method not known.")
|
|
17
|
+
|
|
18
|
+
if order == 'ascending':
|
|
19
|
+
return I
|
|
20
|
+
elif order == 'descending':
|
|
21
|
+
return np.flip(I, axis=0)
|
|
22
|
+
else:
|
|
23
|
+
raise Exception("Unknown sorting order: ascending or descending.")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def quicksort(A):
|
|
27
|
+
I = np.arange(len(A))
|
|
28
|
+
_quicksort(A, I, 0, len(A) - 1)
|
|
29
|
+
return I
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _quicksort(A, I, left, right):
|
|
33
|
+
if left < right:
|
|
34
|
+
|
|
35
|
+
index = np.random.randint(left, right + 1)
|
|
36
|
+
swap(I, right, index)
|
|
37
|
+
|
|
38
|
+
pivot = A[I[right]]
|
|
39
|
+
|
|
40
|
+
i = left - 1
|
|
41
|
+
|
|
42
|
+
for j in range(left, right):
|
|
43
|
+
|
|
44
|
+
if A[I[j]] <= pivot:
|
|
45
|
+
i += 1
|
|
46
|
+
swap(I, i, j)
|
|
47
|
+
|
|
48
|
+
index = i + 1
|
|
49
|
+
swap(I, right, index)
|
|
50
|
+
|
|
51
|
+
_quicksort(A, I, left, index - 1)
|
|
52
|
+
_quicksort(A, I, index + 1, right)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
if __name__ == '__main__':
|
|
56
|
+
a = np.array([5, 9, 10, 0, 0, 0, 100, -2])
|
|
57
|
+
|
|
58
|
+
for i in range(200):
|
|
59
|
+
I = randomized_argsort(a, method="numpy")
|
|
60
|
+
print(I)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from pymoo.util.ref_dirs.energy import RieszEnergyReferenceDirectionFactory
|
|
2
|
+
from pymoo.util.ref_dirs.energy_layer import LayerwiseRieszEnergyReferenceDirectionFactory
|
|
3
|
+
from pymoo.util.ref_dirs.reduction import ReductionBasedReferenceDirectionFactory
|
|
4
|
+
from pymoo.util.ref_dirs.incremental import IncrementalReferenceDirectionFactory
|
|
5
|
+
from pymoo.util.reference_direction import MultiLayerReferenceDirectionFactory
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_reference_directions(name, *args, **kwargs):
|
|
9
|
+
from pymoo.util.reference_direction import UniformReferenceDirectionFactory
|
|
10
|
+
|
|
11
|
+
REF = {
|
|
12
|
+
"uniform": UniformReferenceDirectionFactory,
|
|
13
|
+
"das-dennis": UniformReferenceDirectionFactory,
|
|
14
|
+
"energy": RieszEnergyReferenceDirectionFactory,
|
|
15
|
+
"multi-layer": MultiLayerReferenceDirectionFactory,
|
|
16
|
+
"layer-energy": LayerwiseRieszEnergyReferenceDirectionFactory,
|
|
17
|
+
"reduction": ReductionBasedReferenceDirectionFactory,
|
|
18
|
+
"incremental": IncrementalReferenceDirectionFactory,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if name not in REF:
|
|
22
|
+
raise Exception("Reference directions factory not found.")
|
|
23
|
+
|
|
24
|
+
return REF[name](*args, **kwargs)()
|