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,203 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from scipy.spatial.distance import cdist
|
|
3
|
+
|
|
4
|
+
from pymoo.core.indicator import Indicator
|
|
5
|
+
from pymoo.indicators.hv import Hypervolume
|
|
6
|
+
from pymoo.indicators.igd import IGD
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class RMetric(Indicator):
|
|
10
|
+
|
|
11
|
+
def __init__(self, problem, ref_points, w=None, delta=0.2, pf=None):
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
Parameters
|
|
15
|
+
----------
|
|
16
|
+
|
|
17
|
+
problem : class
|
|
18
|
+
problem instance
|
|
19
|
+
|
|
20
|
+
ref_points : numpy.array
|
|
21
|
+
list of reference points
|
|
22
|
+
|
|
23
|
+
w : numpy.array
|
|
24
|
+
weights for each objective
|
|
25
|
+
|
|
26
|
+
delta : float
|
|
27
|
+
The delta value representing the region of interest
|
|
28
|
+
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
Indicator.__init__(self)
|
|
32
|
+
self.ref_points = ref_points
|
|
33
|
+
self.problem = problem
|
|
34
|
+
w_ = np.ones(self.ref_points.shape[1]) if not w else w
|
|
35
|
+
self.w_points = self.ref_points + 2 * w_
|
|
36
|
+
self.delta = delta
|
|
37
|
+
|
|
38
|
+
self.pf = pf
|
|
39
|
+
self.F = None
|
|
40
|
+
self.others = None
|
|
41
|
+
|
|
42
|
+
def _filter(self):
|
|
43
|
+
|
|
44
|
+
def check_dominance(a, b, n_obj):
|
|
45
|
+
flag1 = False
|
|
46
|
+
flag2 = False
|
|
47
|
+
for i in range(n_obj):
|
|
48
|
+
if a[i] < b[i]:
|
|
49
|
+
flag1 = True
|
|
50
|
+
else:
|
|
51
|
+
if a[i] > b[i]:
|
|
52
|
+
flag2 = True
|
|
53
|
+
if flag1 and not flag2:
|
|
54
|
+
return 1
|
|
55
|
+
elif not flag1 and flag2:
|
|
56
|
+
return -1
|
|
57
|
+
else:
|
|
58
|
+
return 0
|
|
59
|
+
|
|
60
|
+
num_objs = np.size(self.F, axis=1)
|
|
61
|
+
index_array = np.zeros(np.size(self.F, axis=0))
|
|
62
|
+
|
|
63
|
+
# filter out all solutions that are dominated by solutions found by other algorithms
|
|
64
|
+
if self.others is not None:
|
|
65
|
+
for i in range(np.size(self.F, 0)):
|
|
66
|
+
for j in range(np.size(self.others, 0)):
|
|
67
|
+
flag = check_dominance(self.F[i, :], self.others[j, :], num_objs)
|
|
68
|
+
if flag == -1:
|
|
69
|
+
index_array[i] = 1
|
|
70
|
+
break
|
|
71
|
+
|
|
72
|
+
final_index = np.logical_not(index_array)
|
|
73
|
+
filtered_pop = self.F[final_index, :]
|
|
74
|
+
|
|
75
|
+
return filtered_pop
|
|
76
|
+
|
|
77
|
+
def _preprocess(self, data, ref_point, w_point):
|
|
78
|
+
|
|
79
|
+
datasize = np.size(data, 0)
|
|
80
|
+
|
|
81
|
+
# Identify representative point
|
|
82
|
+
ref_matrix = np.tile(ref_point, (datasize, 1))
|
|
83
|
+
w_matrix = np.tile(w_point, (datasize, 1))
|
|
84
|
+
# ratio of distance to the ref point over the distance between the w_point and the ref_point
|
|
85
|
+
diff_matrix = (data - ref_matrix) / (w_matrix - ref_matrix)
|
|
86
|
+
agg_value = np.amax(diff_matrix, axis=1)
|
|
87
|
+
idx = np.argmin(agg_value)
|
|
88
|
+
zp = [data[idx, :]]
|
|
89
|
+
|
|
90
|
+
return zp,
|
|
91
|
+
|
|
92
|
+
def _translate(self, zp, trimmed_data, ref_point, w_point):
|
|
93
|
+
# Solution translation - Matlab reproduction
|
|
94
|
+
# find k
|
|
95
|
+
temp = ((zp[0] - ref_point) / (w_point - ref_point))
|
|
96
|
+
kIdx = np.argmax(temp)
|
|
97
|
+
|
|
98
|
+
# find zl
|
|
99
|
+
temp = (zp[0][kIdx] - ref_point[kIdx]) / (w_point[kIdx] - ref_point[kIdx])
|
|
100
|
+
zl = ref_point + temp * (w_point - ref_point)
|
|
101
|
+
|
|
102
|
+
temp = zl - zp
|
|
103
|
+
shift_direction = np.tile(temp, (trimmed_data.shape[0], 1))
|
|
104
|
+
# new_size = self.curr_pop.shape[0]
|
|
105
|
+
return trimmed_data + shift_direction
|
|
106
|
+
|
|
107
|
+
def _trim(self, pop, centeroid, range=0.2):
|
|
108
|
+
popsize, objDim = pop.shape
|
|
109
|
+
diff_matrix = pop - np.tile(centeroid, (popsize, 1))[0]
|
|
110
|
+
flags = np.sum(abs(diff_matrix) < range / 2, axis=1)
|
|
111
|
+
filtered_matrix = pop[np.where(flags == objDim)]
|
|
112
|
+
return filtered_matrix
|
|
113
|
+
|
|
114
|
+
def _trim_fast(self, pop, centeroid, range=0.2):
|
|
115
|
+
centeroid_matrix = cdist(pop, centeroid, metric='euclidean')
|
|
116
|
+
filtered_matrix = pop[np.where(centeroid_matrix < range / 2), :][0]
|
|
117
|
+
return filtered_matrix
|
|
118
|
+
|
|
119
|
+
def do(self, F, others=None, calc_hv=True):
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
This method calculates the R-IGD and R-HV based off of the values provided.
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
Parameters
|
|
126
|
+
----------
|
|
127
|
+
|
|
128
|
+
F : numpy.ndarray
|
|
129
|
+
The objective space values
|
|
130
|
+
|
|
131
|
+
others : numpy.ndarray
|
|
132
|
+
Results from other algorithms which should be used for filtering nds solutions
|
|
133
|
+
|
|
134
|
+
calc_hv : bool
|
|
135
|
+
Whether the hv is calculate - (None if more than 3 dimensions)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
Returns
|
|
139
|
+
-------
|
|
140
|
+
rigd : float
|
|
141
|
+
R-IGD
|
|
142
|
+
|
|
143
|
+
rhv : float
|
|
144
|
+
R-HV if calc_hv is true and less or equal to 3 dimensions
|
|
145
|
+
|
|
146
|
+
"""
|
|
147
|
+
self.F, self.others = F, others
|
|
148
|
+
|
|
149
|
+
translated = []
|
|
150
|
+
final_PF = []
|
|
151
|
+
|
|
152
|
+
# 1. Prescreen Procedure - NDS Filtering
|
|
153
|
+
pop = self._filter()
|
|
154
|
+
|
|
155
|
+
pf = self.pf
|
|
156
|
+
if pf is None:
|
|
157
|
+
pf = self.problem.pareto_front()
|
|
158
|
+
|
|
159
|
+
if pf is None:
|
|
160
|
+
raise Exception("Please provide the Pareto front to calculate the R-Metric!")
|
|
161
|
+
|
|
162
|
+
labels = np.argmin(cdist(pop, self.ref_points), axis=1)
|
|
163
|
+
|
|
164
|
+
for i in range(len(self.ref_points)):
|
|
165
|
+
cluster = pop[np.where(labels == i)]
|
|
166
|
+
if len(cluster) != 0:
|
|
167
|
+
# 2. Representative Point Identification
|
|
168
|
+
zp = self._preprocess(cluster, self.ref_points[i], w_point=self.w_points[i])[0]
|
|
169
|
+
# 3. Filtering Procedure - Filter points
|
|
170
|
+
trimmed_data = self._trim(cluster, zp, range=self.delta)
|
|
171
|
+
# 4. Solution Translation
|
|
172
|
+
pop_t = self._translate(zp, trimmed_data, self.ref_points[i], w_point=self.w_points[i])
|
|
173
|
+
translated.extend(pop_t)
|
|
174
|
+
|
|
175
|
+
# 5. R-Metric Computation
|
|
176
|
+
target = self._preprocess(data=pf, ref_point=self.ref_points[i], w_point=self.w_points[i])
|
|
177
|
+
PF = self._trim(pf, target)
|
|
178
|
+
final_PF.extend(PF)
|
|
179
|
+
|
|
180
|
+
translated = np.array(translated)
|
|
181
|
+
final_PF = np.array(final_PF)
|
|
182
|
+
|
|
183
|
+
rigd, rhv = None, None
|
|
184
|
+
|
|
185
|
+
if len(translated) > 0:
|
|
186
|
+
|
|
187
|
+
# IGD Computation
|
|
188
|
+
rigd = IGD(final_PF).do(translated)
|
|
189
|
+
|
|
190
|
+
nadir_point = np.amax(self.w_points, axis=0)
|
|
191
|
+
front = translated
|
|
192
|
+
dim = self.ref_points[0].shape[0]
|
|
193
|
+
if calc_hv:
|
|
194
|
+
if dim <= 3:
|
|
195
|
+
try:
|
|
196
|
+
rhv = Hypervolume(ref_point=nadir_point).do(front)
|
|
197
|
+
except:
|
|
198
|
+
pass
|
|
199
|
+
|
|
200
|
+
if calc_hv:
|
|
201
|
+
return rigd, rhv
|
|
202
|
+
else:
|
|
203
|
+
return rigd
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from pymoo.core.indicator import Indicator
|
|
3
|
+
from pymoo.indicators.distance_indicator import at_least_2d_array, derive_ideal_and_nadir_from_pf
|
|
4
|
+
from scipy.spatial.distance import pdist, squareform
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class SpacingIndicator(Indicator):
|
|
8
|
+
|
|
9
|
+
def __init__(self,
|
|
10
|
+
pf=None,
|
|
11
|
+
zero_to_one=False,
|
|
12
|
+
ideal=None,
|
|
13
|
+
nadir=None):
|
|
14
|
+
"""Spacing indicator
|
|
15
|
+
|
|
16
|
+
The smaller the value this indicator assumes, the most uniform is the distribution of elements on the pareto front.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
pf : 2d array, optional
|
|
21
|
+
Pareto front, by default None
|
|
22
|
+
zero_to_one : bool, optional
|
|
23
|
+
Whether or not the objective values should be normalized in calculations, by default False
|
|
24
|
+
ideal : 1d array, optional
|
|
25
|
+
Ideal point, by default None
|
|
26
|
+
nadir : 1d array, optional
|
|
27
|
+
Nadir point, by default None
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
# the pareto front if necessary to calculate the indicator
|
|
31
|
+
pf = at_least_2d_array(pf, extend_as="row")
|
|
32
|
+
ideal, nadir = derive_ideal_and_nadir_from_pf(pf, ideal=ideal, nadir=nadir)
|
|
33
|
+
|
|
34
|
+
super().__init__(pf=pf,
|
|
35
|
+
zero_to_one=zero_to_one,
|
|
36
|
+
ideal=ideal,
|
|
37
|
+
nadir=nadir)
|
|
38
|
+
|
|
39
|
+
def _do(self, F, *args, **kwargs):
|
|
40
|
+
|
|
41
|
+
# Get F dimensions
|
|
42
|
+
n_points, n_obj = F.shape
|
|
43
|
+
|
|
44
|
+
# knn
|
|
45
|
+
D = squareform(pdist(F, metric="cityblock"))
|
|
46
|
+
d = np.partition(D, 1, axis=1)[:, 1]
|
|
47
|
+
dm = np.mean(d)
|
|
48
|
+
|
|
49
|
+
# Get spacing
|
|
50
|
+
S = np.sqrt(np.sum(np.square(d - dm)) / n_points)
|
|
51
|
+
|
|
52
|
+
return S
|
pymoo/mcdm/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from pymoo.core.decision_making import DecisionMaking
|
|
2
|
+
from pymoo.util.normalization import normalize
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class CompromiseProgramming(DecisionMaking):
|
|
6
|
+
|
|
7
|
+
def __init__(self, metric="euclidean", **kwargs) -> None:
|
|
8
|
+
super().__init__(**kwargs)
|
|
9
|
+
self.metric = metric
|
|
10
|
+
|
|
11
|
+
def _do(self, F, **kwargs):
|
|
12
|
+
|
|
13
|
+
F, _, ideal_point, nadir_point = normalize(F,
|
|
14
|
+
xl=self.ideal_point,
|
|
15
|
+
xu=self.nadir_point,
|
|
16
|
+
estimate_bounds_if_none=True,
|
|
17
|
+
return_bounds=True)
|
|
18
|
+
|
|
19
|
+
return None
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from pymoo.core.decision_making import DecisionMaking, find_outliers_upper_tail, NeighborFinder
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class HighTradeoffPoints(DecisionMaking):
|
|
9
|
+
|
|
10
|
+
def __init__(self, epsilon=0.125, **kwargs) -> None:
|
|
11
|
+
super().__init__(**kwargs)
|
|
12
|
+
self.epsilon = epsilon
|
|
13
|
+
|
|
14
|
+
def _do(self, F, **kwargs):
|
|
15
|
+
n, m = F.shape
|
|
16
|
+
|
|
17
|
+
neighbors_finder = NeighborFinder(F, epsilon=0.125, n_min_neigbors="auto", consider_2d=False)
|
|
18
|
+
|
|
19
|
+
mu = np.full(n, - np.inf)
|
|
20
|
+
|
|
21
|
+
# for each solution in the set calculate the least amount of improvement per unit deterioration
|
|
22
|
+
for i in range(n):
|
|
23
|
+
|
|
24
|
+
# for each neighbour in a specific radius of that solution
|
|
25
|
+
neighbors = neighbors_finder.find(i)
|
|
26
|
+
|
|
27
|
+
# calculate the trade-off to all neighbours
|
|
28
|
+
diff = F[neighbors] - F[i]
|
|
29
|
+
|
|
30
|
+
# calculate sacrifice and gain
|
|
31
|
+
sacrifice = np.maximum(0, diff).sum(axis=1)
|
|
32
|
+
gain = np.maximum(0, -diff).sum(axis=1)
|
|
33
|
+
|
|
34
|
+
warnings.filterwarnings('ignore')
|
|
35
|
+
tradeoff = sacrifice / gain
|
|
36
|
+
|
|
37
|
+
# otherwise find the one with the smalled one
|
|
38
|
+
mu[i] = np.nanmin(tradeoff)
|
|
39
|
+
|
|
40
|
+
return find_outliers_upper_tail(mu)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pymoo.core.decision_making import DecisionMaking
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class PseudoWeights(DecisionMaking):
|
|
7
|
+
|
|
8
|
+
def __init__(self, weights, **kwargs) -> None:
|
|
9
|
+
super().__init__(**kwargs)
|
|
10
|
+
self.weights = weights
|
|
11
|
+
|
|
12
|
+
def _do(self, F, return_pseudo_weights=False, **kwargs):
|
|
13
|
+
ideal, nadir = self.ideal, self.nadir
|
|
14
|
+
|
|
15
|
+
if ideal is None:
|
|
16
|
+
ideal = F.min(axis=0)
|
|
17
|
+
if nadir is None:
|
|
18
|
+
nadir = F.max(axis=0)
|
|
19
|
+
|
|
20
|
+
# normalized distance to the worst solution
|
|
21
|
+
pseudo_weights = ((nadir - F) / (nadir - ideal))
|
|
22
|
+
|
|
23
|
+
# normalize weights to sum up to one
|
|
24
|
+
pseudo_weights = pseudo_weights / np.sum(pseudo_weights, axis=1)[:, None]
|
|
25
|
+
|
|
26
|
+
# search for the closest individual having this pseudo weights
|
|
27
|
+
I = np.argmin(np.sum(np.abs(pseudo_weights - self.weights), axis=1))
|
|
28
|
+
|
|
29
|
+
if return_pseudo_weights:
|
|
30
|
+
return I, pseudo_weights
|
|
31
|
+
else:
|
|
32
|
+
return I
|
|
File without changes
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import math
|
|
2
|
+
from abc import abstractmethod
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from pymoo.core.duplicate import NoDuplicateElimination
|
|
7
|
+
from pymoo.core.individual import Individual
|
|
8
|
+
from pymoo.core.infill import InfillCriterion
|
|
9
|
+
from pymoo.core.mixed import MixedVariableMating
|
|
10
|
+
from pymoo.core.parameters import get_params, flatten
|
|
11
|
+
from pymoo.core.problem import Problem
|
|
12
|
+
from pymoo.core.variable import Choice, Real, Integer, Binary
|
|
13
|
+
from pymoo.operators.crossover.sbx import SBX
|
|
14
|
+
from pymoo.operators.crossover.ux import UX
|
|
15
|
+
from pymoo.operators.mutation.bitflip import BFM
|
|
16
|
+
from pymoo.operators.mutation.pm import PM
|
|
17
|
+
from pymoo.operators.mutation.rm import ChoiceRandomMutation
|
|
18
|
+
from pymoo.operators.repair.rounding import RoundingRepair
|
|
19
|
+
from pymoo.operators.selection.tournament import TournamentSelection, compare
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ParameterControl:
|
|
23
|
+
|
|
24
|
+
def __init__(self, obj) -> None:
|
|
25
|
+
super().__init__()
|
|
26
|
+
|
|
27
|
+
self.data = None
|
|
28
|
+
|
|
29
|
+
params = flatten({"ParameterControl": get_params(obj)})
|
|
30
|
+
self.params = params
|
|
31
|
+
|
|
32
|
+
# print("PARAMETER CONTROL:", list(self.params))
|
|
33
|
+
|
|
34
|
+
def do(self, N, set_to_params=True):
|
|
35
|
+
vals = self._do(N)
|
|
36
|
+
if set_to_params:
|
|
37
|
+
if vals is not None:
|
|
38
|
+
for k, v in vals.items():
|
|
39
|
+
self.params[k].set(v)
|
|
40
|
+
return vals
|
|
41
|
+
|
|
42
|
+
@abstractmethod
|
|
43
|
+
def _do(self, N):
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
def tell(self, **kwargs):
|
|
47
|
+
self.data = dict(kwargs)
|
|
48
|
+
|
|
49
|
+
def advance(self, infills=None):
|
|
50
|
+
for k, v in self.params.items():
|
|
51
|
+
assert len(v.get()) == len(
|
|
52
|
+
infills), "Make sure that the infills and parameters asked for have the same size."
|
|
53
|
+
infills.set(k, v.get())
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class NoParameterControl(ParameterControl):
|
|
57
|
+
|
|
58
|
+
def __init__(self, _) -> None:
|
|
59
|
+
super().__init__(None)
|
|
60
|
+
|
|
61
|
+
def _do(self, N):
|
|
62
|
+
return {}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class RandomParameterControl(ParameterControl):
|
|
66
|
+
|
|
67
|
+
def _do(self, N):
|
|
68
|
+
return {key: value.sample(N) for key, value in self.params.items()}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class EvolutionaryParameterControl(ParameterControl):
|
|
72
|
+
|
|
73
|
+
def __init__(self, obj) -> None:
|
|
74
|
+
super().__init__(obj)
|
|
75
|
+
self.eps = 0.05
|
|
76
|
+
|
|
77
|
+
def _do(self, N):
|
|
78
|
+
params = self.params
|
|
79
|
+
pop = self.data.get("pop")
|
|
80
|
+
|
|
81
|
+
# make sure that for each parameter a value exists - if not simply set it randomly
|
|
82
|
+
for name, param in params.items():
|
|
83
|
+
is_none = np.where(pop.get(name) == None)[0]
|
|
84
|
+
if len(is_none) > 0:
|
|
85
|
+
pop[is_none].set(name, param.sample(len(is_none)))
|
|
86
|
+
|
|
87
|
+
selection = AgeBasedTournamentSelection()
|
|
88
|
+
|
|
89
|
+
crossover = {
|
|
90
|
+
Binary: UX(),
|
|
91
|
+
Real: SBX(),
|
|
92
|
+
Integer: SBX(vtype=float, repair=RoundingRepair()),
|
|
93
|
+
Choice: UX(),
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
mutation = {
|
|
97
|
+
Binary: BFM(),
|
|
98
|
+
Real: PM(),
|
|
99
|
+
Integer: PM(vtype=float, repair=RoundingRepair()),
|
|
100
|
+
Choice: ChoiceRandomMutation(),
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
mating = MixedVariableMating(
|
|
104
|
+
crossover=crossover,
|
|
105
|
+
mutation=mutation,
|
|
106
|
+
eliminate_duplicates=NoDuplicateElimination()
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
problem = Problem(vars=params)
|
|
110
|
+
|
|
111
|
+
parents = selection(problem, pop, N, n_parents=2)
|
|
112
|
+
parents = [[Individual(X={key: parent.get(key) for key in params}) for parent in mating] for mating in parents]
|
|
113
|
+
|
|
114
|
+
off = mating(problem, parents, N, parents=True)
|
|
115
|
+
|
|
116
|
+
Xp = off.get("X")
|
|
117
|
+
ret = {param: np.array([Xp[i][param] for i in range(len(Xp))]) for param in params}
|
|
118
|
+
|
|
119
|
+
return ret
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class AgeBasedTournamentSelection(TournamentSelection):
|
|
123
|
+
|
|
124
|
+
def __init__(self, pressure=2):
|
|
125
|
+
super().__init__(age_binary_tournament, pressure)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def age_binary_tournament(pop, P, **kwargs):
|
|
129
|
+
n_tournaments, n_parents = P.shape
|
|
130
|
+
|
|
131
|
+
if n_parents != 2:
|
|
132
|
+
raise ValueError("Only implemented for binary tournament!")
|
|
133
|
+
|
|
134
|
+
S = np.full(n_tournaments, np.nan)
|
|
135
|
+
|
|
136
|
+
for i in range(n_tournaments):
|
|
137
|
+
a, b = P[i, 0], P[i, 1]
|
|
138
|
+
a_gen, b_gen = pop[a].get("n_gen"), pop[b].get("n_gen")
|
|
139
|
+
S[i] = compare(a, a_gen, b, b_gen, method='larger_is_better', return_random_if_equal=True)
|
|
140
|
+
|
|
141
|
+
return S[:, None].astype(int, copy=False)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class ParameterControlMating(InfillCriterion):
|
|
145
|
+
|
|
146
|
+
def __init__(self,
|
|
147
|
+
selection,
|
|
148
|
+
crossover,
|
|
149
|
+
mutation,
|
|
150
|
+
control=NoParameterControl,
|
|
151
|
+
**kwargs):
|
|
152
|
+
super().__init__(**kwargs)
|
|
153
|
+
self.selection = selection
|
|
154
|
+
self.crossover = crossover
|
|
155
|
+
self.mutation = mutation
|
|
156
|
+
self.control = control(self)
|
|
157
|
+
|
|
158
|
+
def _do(self, problem, pop, n_offsprings, parents=None, **kwargs):
|
|
159
|
+
|
|
160
|
+
# how many parents need to be select for the mating - depending on number of offsprings remaining
|
|
161
|
+
n_matings = math.ceil(n_offsprings / self.crossover.n_offsprings)
|
|
162
|
+
|
|
163
|
+
# do the parameter control for the mating
|
|
164
|
+
control = self.control
|
|
165
|
+
control.tell(pop=pop)
|
|
166
|
+
control.do(n_matings)
|
|
167
|
+
|
|
168
|
+
# if the parents for the mating are not provided directly - usually selection will be used
|
|
169
|
+
if parents is None:
|
|
170
|
+
|
|
171
|
+
# select the parents for the mating - just an index array
|
|
172
|
+
parents = self.selection.do(problem, pop, n_matings, n_parents=self.crossover.n_parents, **kwargs)
|
|
173
|
+
|
|
174
|
+
# do the crossover using the parents index and the population - additional data provided if necessary
|
|
175
|
+
off = self.crossover(problem, parents, **kwargs)
|
|
176
|
+
|
|
177
|
+
# now we have to consider during parameter control that a crossover can produce multiple offsprings
|
|
178
|
+
for name, param in control.params.items():
|
|
179
|
+
param.set(np.repeat(param.get(), self.crossover.n_offsprings))
|
|
180
|
+
|
|
181
|
+
# do the mutation on the offsprings created through crossover
|
|
182
|
+
off = self.mutation(problem, off, **kwargs)
|
|
183
|
+
|
|
184
|
+
# finally attach the parameters back to the offsprings
|
|
185
|
+
control.advance(off)
|
|
186
|
+
|
|
187
|
+
return off
|
|
File without changes
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pymoo.core.crossover import Crossover
|
|
4
|
+
from pymoo.core.variable import Real, get
|
|
5
|
+
from pymoo.util.misc import row_at_least_once_true
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def mut_binomial(n, m, prob, at_least_once=True):
|
|
9
|
+
prob = np.ones(n) * prob
|
|
10
|
+
M = np.random.random((n, m)) < prob[:, None]
|
|
11
|
+
|
|
12
|
+
if at_least_once:
|
|
13
|
+
M = row_at_least_once_true(M)
|
|
14
|
+
|
|
15
|
+
return M
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class BinomialCrossover(Crossover):
|
|
19
|
+
|
|
20
|
+
def __init__(self, bias=0.5, n_offsprings=2, **kwargs):
|
|
21
|
+
super().__init__(2, n_offsprings, **kwargs)
|
|
22
|
+
self.bias = Real(bias, bounds=(0.1, 0.9), strict=(0.0, 1.0))
|
|
23
|
+
|
|
24
|
+
def _do(self, problem, X, **kwargs):
|
|
25
|
+
_, n_matings, n_var = X.shape
|
|
26
|
+
|
|
27
|
+
bias = get(self.bias, size=n_matings)
|
|
28
|
+
M = mut_binomial(n_matings, n_var, bias, at_least_once=True)
|
|
29
|
+
|
|
30
|
+
if self.n_offsprings == 1:
|
|
31
|
+
Xp = X[0].copy()
|
|
32
|
+
Xp[~M] = X[1][~M]
|
|
33
|
+
Xp = Xp[None, ...]
|
|
34
|
+
elif self.n_offsprings == 2:
|
|
35
|
+
Xp = np.copy(X)
|
|
36
|
+
Xp[0][~M] = X[1][~M]
|
|
37
|
+
Xp[1][~M] = X[0][~M]
|
|
38
|
+
else:
|
|
39
|
+
raise Exception
|
|
40
|
+
|
|
41
|
+
return Xp
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class BX(BinomialCrossover):
|
|
45
|
+
pass
|