pymoo 0.6.1.5.dev0__cp39-cp39-musllinux_1_2_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-39-x86_64-linux-gnu.so +0 -0
- pymoo/cython/calc_perpendicular_distance.pyx +67 -0
- pymoo/cython/decomposition.cpython-39-x86_64-linux-gnu.so +0 -0
- pymoo/cython/decomposition.pyx +165 -0
- pymoo/cython/hv.cpython-39-x86_64-linux-gnu.so +0 -0
- pymoo/cython/hv.pyx +18 -0
- pymoo/cython/info.cpython-39-x86_64-linux-gnu.so +0 -0
- pymoo/cython/info.pyx +5 -0
- pymoo/cython/mnn.cpython-39-x86_64-linux-gnu.so +0 -0
- pymoo/cython/mnn.pyx +273 -0
- pymoo/cython/non_dominated_sorting.cpython-39-x86_64-linux-gnu.so +0 -0
- pymoo/cython/non_dominated_sorting.pyx +645 -0
- pymoo/cython/pruning_cd.cpython-39-x86_64-linux-gnu.so +0 -0
- pymoo/cython/pruning_cd.pyx +197 -0
- pymoo/cython/stochastic_ranking.cpython-39-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 +330 -0
- pymoo-0.6.1.5.dev0.dist-info/WHEEL +5 -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
- pymoo.libs/libgcc_s-2298274a.so.1 +0 -0
- pymoo.libs/libstdc++-08d5c7eb.so.6.0.33 +0 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pymoo.indicators.hv import Hypervolume
|
|
4
|
+
from pymoo.indicators.igd import IGD
|
|
5
|
+
from pymoo.util.normalization import normalize
|
|
6
|
+
from pymoo.termination.delta import DeltaToleranceTermination
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def calc_delta(a, b):
|
|
10
|
+
return np.max(np.abs((a - b)))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def calc_delta_norm(a, b, norm):
|
|
14
|
+
return np.max(np.abs((a - b) / norm))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class SingleObjectiveSpaceTermination(DeltaToleranceTermination):
|
|
18
|
+
|
|
19
|
+
def __init__(self, tol=1e-6, only_feas=True, **kwargs) -> None:
|
|
20
|
+
super().__init__(tol, **kwargs)
|
|
21
|
+
self.only_feas = only_feas
|
|
22
|
+
|
|
23
|
+
def _delta(self, prev, current):
|
|
24
|
+
if prev == np.inf or current == np.inf:
|
|
25
|
+
return np.inf
|
|
26
|
+
else:
|
|
27
|
+
return max(0, prev - current)
|
|
28
|
+
|
|
29
|
+
def _data(self, algorithm):
|
|
30
|
+
opt = algorithm.opt
|
|
31
|
+
f = opt.get("f")
|
|
32
|
+
|
|
33
|
+
if self.only_feas:
|
|
34
|
+
f = f[opt.get("feas")]
|
|
35
|
+
|
|
36
|
+
if len(f) > 0:
|
|
37
|
+
return f.min()
|
|
38
|
+
else:
|
|
39
|
+
return np.inf
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class MultiObjectiveSpaceTermination(DeltaToleranceTermination):
|
|
43
|
+
|
|
44
|
+
def __init__(self, tol=0.0025, only_feas=True, **kwargs):
|
|
45
|
+
super().__init__(tol, **kwargs)
|
|
46
|
+
self.delta_ideal = None
|
|
47
|
+
self.delta_nadir = None
|
|
48
|
+
self.delta_f = None
|
|
49
|
+
self.only_feas = only_feas
|
|
50
|
+
|
|
51
|
+
def _data(self, algorithm):
|
|
52
|
+
feas, F = algorithm.opt.get("feas", "F")
|
|
53
|
+
|
|
54
|
+
if self.only_feas:
|
|
55
|
+
F = F[feas]
|
|
56
|
+
|
|
57
|
+
if len(F) > 0:
|
|
58
|
+
return dict(ideal=F.min(axis=0), nadir=F.max(axis=0), F=F, feas=True)
|
|
59
|
+
else:
|
|
60
|
+
return dict(ideal=None, nadir=None, F=F, feas=False)
|
|
61
|
+
|
|
62
|
+
def _delta(self, prev, current):
|
|
63
|
+
|
|
64
|
+
if not (prev["feas"] and current["feas"]):
|
|
65
|
+
return np.inf
|
|
66
|
+
|
|
67
|
+
# this is the range between the nadir and the ideal point
|
|
68
|
+
norm = current["nadir"] - current["ideal"]
|
|
69
|
+
|
|
70
|
+
# if the range is degenerated (very close to zero) - disable normalization by dividing by one
|
|
71
|
+
norm[norm < 1e-32] = 1.0
|
|
72
|
+
|
|
73
|
+
# calculate the change from last to current in ideal and nadir point
|
|
74
|
+
delta_ideal = calc_delta_norm(current["ideal"], prev["ideal"], norm)
|
|
75
|
+
delta_nadir = calc_delta_norm(current["nadir"], prev["nadir"], norm)
|
|
76
|
+
|
|
77
|
+
# get necessary data from the current population
|
|
78
|
+
c_F, c_ideal, c_nadir = current["F"], current["ideal"], current["nadir"]
|
|
79
|
+
p_F = prev["F"]
|
|
80
|
+
|
|
81
|
+
# normalize last and current with respect to most recent ideal and nadir
|
|
82
|
+
c_N = normalize(c_F, c_ideal, c_nadir)
|
|
83
|
+
p_N = normalize(p_F, c_ideal, c_nadir)
|
|
84
|
+
|
|
85
|
+
# calculate IGD from one to another
|
|
86
|
+
delta_f = IGD(c_N).do(p_N)
|
|
87
|
+
|
|
88
|
+
# store the delta values to the object
|
|
89
|
+
self.delta_ideal, self.delta_nadir, self.delta_f = delta_ideal, delta_nadir, delta_f
|
|
90
|
+
|
|
91
|
+
return max(delta_ideal, delta_nadir, delta_f)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class MultiObjectiveSpaceTerminationWithRenormalization(MultiObjectiveSpaceTermination):
|
|
95
|
+
|
|
96
|
+
def __init__(self,
|
|
97
|
+
n=30,
|
|
98
|
+
all_to_current=False,
|
|
99
|
+
sliding_window=True,
|
|
100
|
+
indicator="igd",
|
|
101
|
+
**kwargs) -> None:
|
|
102
|
+
|
|
103
|
+
super().__init__(**kwargs)
|
|
104
|
+
self.n = n
|
|
105
|
+
self.all_to_current = all_to_current
|
|
106
|
+
self.sliding_window = sliding_window
|
|
107
|
+
self.indicator = indicator
|
|
108
|
+
|
|
109
|
+
self.data = []
|
|
110
|
+
|
|
111
|
+
def _metric(self, data):
|
|
112
|
+
ret = super()._metric(data)
|
|
113
|
+
|
|
114
|
+
if not self.sliding_window:
|
|
115
|
+
data = self.data[-self.metric_window_size:]
|
|
116
|
+
|
|
117
|
+
# get necessary data from the current population
|
|
118
|
+
current = data[-1]
|
|
119
|
+
c_F, c_ideal, c_nadir = current["F"], current["ideal"], current["nadir"]
|
|
120
|
+
|
|
121
|
+
# normalize all previous generations with respect to current ideal and nadir
|
|
122
|
+
N = [normalize(e["F"], c_ideal, c_nadir) for e in data]
|
|
123
|
+
|
|
124
|
+
# check if the movement of all points is significant
|
|
125
|
+
if self.all_to_current:
|
|
126
|
+
|
|
127
|
+
c_N = normalize(c_F, c_ideal, c_nadir)
|
|
128
|
+
if self.indicator == "igd":
|
|
129
|
+
delta_f = [IGD(c_N).do(N[k]) for k in range(len(N))]
|
|
130
|
+
elif self.indicator == "hv":
|
|
131
|
+
hv = Hypervolume(ref_point=np.ones(c_F.shape[1]))
|
|
132
|
+
delta_f = [hv.do(N[k]) for k in range(len(N))]
|
|
133
|
+
else:
|
|
134
|
+
delta_f = [IGD(N[k + 1]).do(N[k]) for k in range(len(N) - 1)]
|
|
135
|
+
|
|
136
|
+
ret["delta_f"] = delta_f
|
|
137
|
+
|
|
138
|
+
return ret
|
|
139
|
+
|
|
140
|
+
def _decide(self, metrics):
|
|
141
|
+
delta_ideal = [e["delta_ideal"] for e in metrics]
|
|
142
|
+
delta_nadir = [e["delta_nadir"] for e in metrics]
|
|
143
|
+
delta_f = [max(e["delta_f"]) for e in metrics]
|
|
144
|
+
return max(max(delta_ideal), max(delta_nadir), max(delta_f)) > self.tol
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from math import log
|
|
2
|
+
|
|
3
|
+
from pymoo.core.termination import Termination
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class IndicatorTermination(Termination):
|
|
7
|
+
|
|
8
|
+
def __init__(self, indicator, threshold, goal, **kwargs) -> None:
|
|
9
|
+
super().__init__()
|
|
10
|
+
|
|
11
|
+
# the indicator to be used
|
|
12
|
+
self.indicator = indicator
|
|
13
|
+
|
|
14
|
+
# define the threshold for termination
|
|
15
|
+
self.threshold = threshold
|
|
16
|
+
|
|
17
|
+
# what is the optimization goal for this indicator
|
|
18
|
+
self.goal = goal
|
|
19
|
+
assert goal in ["minimize", "maximize"]
|
|
20
|
+
|
|
21
|
+
# optional parameters when the indicator calculation is performed
|
|
22
|
+
self.kwargs = kwargs
|
|
23
|
+
|
|
24
|
+
# initial the minimum and maximum values of the indicator
|
|
25
|
+
self._min = float("inf")
|
|
26
|
+
self._max = -float("inf")
|
|
27
|
+
|
|
28
|
+
def _update(self, algorithm):
|
|
29
|
+
|
|
30
|
+
# get the objective space values
|
|
31
|
+
F = algorithm.opt.get("F")
|
|
32
|
+
|
|
33
|
+
# get the resulting value from the indicator
|
|
34
|
+
v = self.indicator.do(F, **self.kwargs)
|
|
35
|
+
|
|
36
|
+
threshold = self.threshold
|
|
37
|
+
|
|
38
|
+
# update the minimum and maximum boundary ranges
|
|
39
|
+
self._min = min(self._min, v)
|
|
40
|
+
self._max = max(self._max, v)
|
|
41
|
+
_min, _max = self._min, self._max
|
|
42
|
+
|
|
43
|
+
# depending on the goal either set the percentage
|
|
44
|
+
if self.goal == "minimize":
|
|
45
|
+
perc = 1 - (v - threshold) / (_max - threshold)
|
|
46
|
+
else:
|
|
47
|
+
perc = (v - _min) / (threshold - _min)
|
|
48
|
+
|
|
49
|
+
return perc
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from pymoo.core.termination import Termination
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class MaximumFunctionCallTermination(Termination):
|
|
5
|
+
|
|
6
|
+
def __init__(self, n_max_evals=float("inf")) -> None:
|
|
7
|
+
super().__init__()
|
|
8
|
+
self.n_max_evals = n_max_evals
|
|
9
|
+
|
|
10
|
+
def _update(self, algorithm):
|
|
11
|
+
if self.n_max_evals is None:
|
|
12
|
+
return 0.0
|
|
13
|
+
else:
|
|
14
|
+
return algorithm.evaluator.n_eval / self.n_max_evals
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from pymoo.core.termination import Termination
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class MaximumGenerationTermination(Termination):
|
|
5
|
+
|
|
6
|
+
def __init__(self, n_max_gen=float("inf")) -> None:
|
|
7
|
+
super().__init__()
|
|
8
|
+
self.n_max_gen = n_max_gen
|
|
9
|
+
|
|
10
|
+
def _update(self, algorithm):
|
|
11
|
+
if self.n_max_gen is None:
|
|
12
|
+
return 0.0
|
|
13
|
+
else:
|
|
14
|
+
return algorithm.n_gen / self.n_max_gen
|
|
15
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import time
|
|
2
|
+
|
|
3
|
+
from pymoo.core.termination import Termination
|
|
4
|
+
from pymoo.util.misc import time_to_int
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TimeBasedTermination(Termination):
|
|
8
|
+
|
|
9
|
+
def __init__(self, max_time) -> None:
|
|
10
|
+
super().__init__()
|
|
11
|
+
if isinstance(max_time, str):
|
|
12
|
+
self.max_time = time_to_int(max_time)
|
|
13
|
+
elif isinstance(max_time, int) or isinstance(max_time, float):
|
|
14
|
+
self.max_time = max_time
|
|
15
|
+
else:
|
|
16
|
+
raise Exception("Either provide the time as a string or an integer.")
|
|
17
|
+
|
|
18
|
+
def _update(self, algorithm):
|
|
19
|
+
elapsed = time.time() - algorithm.start_time
|
|
20
|
+
return elapsed / self.max_time
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from pymoo.core.termination import Termination
|
|
2
|
+
from pymoo.util.sliding_window import SlidingWindow
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class RobustTermination(Termination):
|
|
6
|
+
|
|
7
|
+
def __init__(self,
|
|
8
|
+
termination,
|
|
9
|
+
period=30,
|
|
10
|
+
) -> None:
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
Parameters
|
|
14
|
+
----------
|
|
15
|
+
|
|
16
|
+
termination : Termination
|
|
17
|
+
The termination criterion that shall become robust
|
|
18
|
+
|
|
19
|
+
period : int
|
|
20
|
+
The number of last generations to be considered for termination.
|
|
21
|
+
|
|
22
|
+
"""
|
|
23
|
+
super().__init__()
|
|
24
|
+
|
|
25
|
+
# create a collection in case number of max generation or evaluations is used
|
|
26
|
+
self.termination = termination
|
|
27
|
+
|
|
28
|
+
# the history calculated also in a sliding window
|
|
29
|
+
self.history = SlidingWindow(period)
|
|
30
|
+
|
|
31
|
+
def _update(self, algorithm):
|
|
32
|
+
perc = self.termination.update(algorithm)
|
|
33
|
+
self.history.append(perc)
|
|
34
|
+
return min(self.history)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pymoo.indicators.igd import IGD
|
|
4
|
+
from pymoo.termination.delta import DeltaToleranceTermination
|
|
5
|
+
from pymoo.util.normalization import normalize
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class DesignSpaceTermination(DeltaToleranceTermination):
|
|
10
|
+
|
|
11
|
+
def __init__(self, tol=0.005, **kwargs):
|
|
12
|
+
"""
|
|
13
|
+
Check the distance in the design-space and terminate based on tolerance.
|
|
14
|
+
(only works if variables can be converted to float)
|
|
15
|
+
"""
|
|
16
|
+
super().__init__(tol, **kwargs)
|
|
17
|
+
|
|
18
|
+
def _delta(self, prev, current):
|
|
19
|
+
try:
|
|
20
|
+
return IGD(current.astype(float)).do(prev.astype(float))
|
|
21
|
+
except:
|
|
22
|
+
return np.inf
|
|
23
|
+
|
|
24
|
+
def _data(self, algorithm):
|
|
25
|
+
|
|
26
|
+
X = algorithm.opt.get("X")
|
|
27
|
+
|
|
28
|
+
# do normalization if bounds are given
|
|
29
|
+
problem = algorithm.problem
|
|
30
|
+
if X.dtype != object and problem.has_bounds():
|
|
31
|
+
X = normalize(X, xl=problem.xl, xu=problem.xu)
|
|
32
|
+
|
|
33
|
+
return X
|
pymoo/util/__init__.py
ADDED
|
File without changes
|
pymoo/util/archive.py
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pymoo.core.duplicate import DefaultDuplicateElimination
|
|
4
|
+
from pymoo.core.population import Population, merge
|
|
5
|
+
from pymoo.util.nds.non_dominated_sorting import NonDominatedSorting
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Truncation:
|
|
9
|
+
|
|
10
|
+
def __call__(self, sols, k):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class RandomTruncation(Truncation):
|
|
15
|
+
|
|
16
|
+
def __call__(self, sols, k):
|
|
17
|
+
return np.random.choice(sols, size=k, replace=False)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class SurvivalTruncation(Truncation):
|
|
21
|
+
|
|
22
|
+
def __init__(self, survival, problem=None) -> None:
|
|
23
|
+
super().__init__()
|
|
24
|
+
self.survival = survival
|
|
25
|
+
|
|
26
|
+
if problem is None:
|
|
27
|
+
from pymoo.core.problem import Problem
|
|
28
|
+
problem = Problem()
|
|
29
|
+
|
|
30
|
+
self.problem = problem
|
|
31
|
+
|
|
32
|
+
def __call__(self, sols, k):
|
|
33
|
+
return self.survival.do(self.problem, sols, n_survive=k)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Archive(Population):
|
|
37
|
+
|
|
38
|
+
def __new__(cls,
|
|
39
|
+
individuals=[],
|
|
40
|
+
max_size=None,
|
|
41
|
+
truncate_size=None,
|
|
42
|
+
truncation=RandomTruncation(),
|
|
43
|
+
duplicate_elimination=DefaultDuplicateElimination(epsilon=1e-32)):
|
|
44
|
+
|
|
45
|
+
obj = super().__new__(cls, individuals)
|
|
46
|
+
obj.max_size = max_size
|
|
47
|
+
obj.truncate_size = min(max_size, truncate_size) if truncate_size is not None else max_size
|
|
48
|
+
obj.truncation = truncation
|
|
49
|
+
obj.duplicate_elimination = duplicate_elimination
|
|
50
|
+
|
|
51
|
+
return obj
|
|
52
|
+
|
|
53
|
+
def __array_finalize__(self, obj):
|
|
54
|
+
if obj is None: # __new__ handles instantiation
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
max_size = getattr(obj, 'max_size', None)
|
|
58
|
+
truncate_size = getattr(obj, 'truncate_size', None)
|
|
59
|
+
truncation = getattr(obj, 'truncation', RandomTruncation())
|
|
60
|
+
duplicate_elimination = getattr(obj, 'duplicate_elimination', DefaultDuplicateElimination(epsilon=1e-32))
|
|
61
|
+
|
|
62
|
+
self.max_size = max_size
|
|
63
|
+
self.truncate_size = min(max_size, truncate_size) if truncate_size is not None else max_size
|
|
64
|
+
self.truncation = truncation
|
|
65
|
+
self.duplicate_elimination = duplicate_elimination
|
|
66
|
+
|
|
67
|
+
def add(self, sols):
|
|
68
|
+
|
|
69
|
+
if len(self) > 0:
|
|
70
|
+
sols = merge(self, sols)
|
|
71
|
+
|
|
72
|
+
opt = self._find_opt(sols)
|
|
73
|
+
|
|
74
|
+
if self.duplicate_elimination:
|
|
75
|
+
opt = self.duplicate_elimination.do(opt)
|
|
76
|
+
|
|
77
|
+
if self.max_size and len(opt) > self.max_size:
|
|
78
|
+
opt = self.truncation(opt, self.truncate_size)
|
|
79
|
+
|
|
80
|
+
cls = self.__class__
|
|
81
|
+
obj = cls.__new__(cls, individuals=opt, **self.view(Archive).__dict__)
|
|
82
|
+
return obj
|
|
83
|
+
|
|
84
|
+
def _find_opt(self, sols):
|
|
85
|
+
pass
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class VoidArchive(Archive):
|
|
89
|
+
|
|
90
|
+
def add(self, sols):
|
|
91
|
+
return self
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class SingleObjectiveArchive(Archive):
|
|
95
|
+
|
|
96
|
+
def __new__(cls, max_size=10, **kwargs):
|
|
97
|
+
return super().__new__(cls, max_size=max_size, **kwargs).view(cls)
|
|
98
|
+
|
|
99
|
+
def _find_opt(self, sols):
|
|
100
|
+
feas = sols.get("feas")
|
|
101
|
+
|
|
102
|
+
if np.any(feas):
|
|
103
|
+
sols = sols[feas]
|
|
104
|
+
|
|
105
|
+
f = sols.get("f")
|
|
106
|
+
I, = np.where(f == f[f.argmin()])
|
|
107
|
+
|
|
108
|
+
else:
|
|
109
|
+
cv = sols.get("cv")
|
|
110
|
+
I, = np.where(cv == cv[cv.argmin()])
|
|
111
|
+
|
|
112
|
+
return sols[I]
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class MultiObjectiveArchive(Archive):
|
|
116
|
+
|
|
117
|
+
def __new__(cls, max_size=200, truncate_size=100, **kwargs):
|
|
118
|
+
return super().__new__(cls,
|
|
119
|
+
max_size=max_size,
|
|
120
|
+
truncate_size=truncate_size,
|
|
121
|
+
**kwargs)
|
|
122
|
+
|
|
123
|
+
def _find_opt(self, sols):
|
|
124
|
+
feas = sols.get("feas")
|
|
125
|
+
|
|
126
|
+
if np.any(feas):
|
|
127
|
+
sols = sols[feas]
|
|
128
|
+
|
|
129
|
+
F = sols.get("F")
|
|
130
|
+
I = NonDominatedSorting().do(F, only_non_dominated_front=True)
|
|
131
|
+
else:
|
|
132
|
+
cv = sols.get("cv")
|
|
133
|
+
I, = np.where(cv == cv[cv.argmin()])
|
|
134
|
+
|
|
135
|
+
return sols[I]
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def default_archive(problem, **kwargs):
|
|
139
|
+
if problem.n_obj == 1:
|
|
140
|
+
return SingleObjectiveArchive(**kwargs)
|
|
141
|
+
|
|
142
|
+
elif problem.n_obj == 2:
|
|
143
|
+
from pymoo.algorithms.moo.sms import LeastHypervolumeContributionSurvival
|
|
144
|
+
survival = LeastHypervolumeContributionSurvival()
|
|
145
|
+
return MultiObjectiveArchive(truncation=SurvivalTruncation(survival, problem=problem), **kwargs)
|
|
146
|
+
|
|
147
|
+
elif problem.n_obj >= 3:
|
|
148
|
+
from pymoo.algorithms.moo.spea2 import SPEA2Survival
|
|
149
|
+
survival = SPEA2Survival()
|
|
150
|
+
return MultiObjectiveArchive(truncation=SurvivalTruncation(survival, problem=problem), **kwargs)
|
pymoo/util/cache.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
def Cache(func):
|
|
2
|
+
"""
|
|
3
|
+
|
|
4
|
+
This is a function decorator for class attributes. It just remembers the result of the FIRST function call
|
|
5
|
+
and returns this from there on. Other cashes like LRU are difficult to use because the input can be unhashable
|
|
6
|
+
or bigger numpy arrays. Thus the user has to choose how to use this cache.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
func_name = func.__name__
|
|
10
|
+
|
|
11
|
+
def wrapper(self, *args, use_cache=True, set_cache=True, **kwargs):
|
|
12
|
+
|
|
13
|
+
if "cache" not in self.__dict__:
|
|
14
|
+
self.__dict__["cache"] = {}
|
|
15
|
+
|
|
16
|
+
cache = self.__dict__["cache"]
|
|
17
|
+
|
|
18
|
+
if use_cache and func_name in cache:
|
|
19
|
+
return cache[func_name]
|
|
20
|
+
else:
|
|
21
|
+
|
|
22
|
+
obj = func(self, *args, **kwargs)
|
|
23
|
+
|
|
24
|
+
if set_cache:
|
|
25
|
+
cache[func_name] = obj
|
|
26
|
+
|
|
27
|
+
return obj
|
|
28
|
+
|
|
29
|
+
return wrapper
|
pymoo/util/clearing.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def func_select_by_objective(pop):
|
|
5
|
+
F = pop.get("F")
|
|
6
|
+
return F[:, 0].argmin()
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def func_select_from_sorted(_):
|
|
10
|
+
return 0
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def select_by_clearing(pop, D, n_select, func_select, delta=0.05):
|
|
14
|
+
clearing = EpsilonClearing(D, delta)
|
|
15
|
+
|
|
16
|
+
while len(clearing.selected()) < n_select:
|
|
17
|
+
remaining = clearing.remaining()
|
|
18
|
+
|
|
19
|
+
if len(remaining) == 0:
|
|
20
|
+
clearing.reset()
|
|
21
|
+
remaining = clearing.remaining()
|
|
22
|
+
|
|
23
|
+
best = remaining[func_select(pop[remaining])]
|
|
24
|
+
clearing.select(best)
|
|
25
|
+
|
|
26
|
+
S = clearing.selected()
|
|
27
|
+
return S
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class EpsilonClearing:
|
|
31
|
+
|
|
32
|
+
def __init__(self,
|
|
33
|
+
D,
|
|
34
|
+
epsilon) -> None:
|
|
35
|
+
|
|
36
|
+
super().__init__()
|
|
37
|
+
|
|
38
|
+
if isinstance(D, tuple):
|
|
39
|
+
self.n, self.D = D
|
|
40
|
+
else:
|
|
41
|
+
self.D = D
|
|
42
|
+
self.n = len(D)
|
|
43
|
+
|
|
44
|
+
self.epsilon = epsilon
|
|
45
|
+
|
|
46
|
+
self.S = []
|
|
47
|
+
self.C = np.full(self.n, False)
|
|
48
|
+
|
|
49
|
+
def remaining(self):
|
|
50
|
+
return np.where(~self.C)[0]
|
|
51
|
+
|
|
52
|
+
def has_remaining(self):
|
|
53
|
+
return self.C.sum() != self.n
|
|
54
|
+
|
|
55
|
+
def cleared(self):
|
|
56
|
+
return self.C
|
|
57
|
+
|
|
58
|
+
def selected(self):
|
|
59
|
+
return self.S
|
|
60
|
+
|
|
61
|
+
def reset(self):
|
|
62
|
+
self.C = np.full(self.n, False)
|
|
63
|
+
self.C[self.S] = True
|
|
64
|
+
|
|
65
|
+
def select(self, k):
|
|
66
|
+
self.S.append(k)
|
|
67
|
+
self.C[k] = True
|
|
68
|
+
|
|
69
|
+
if callable(self.D):
|
|
70
|
+
dist_to_other = self.D(k)
|
|
71
|
+
else:
|
|
72
|
+
dist_to_other = self.D[k]
|
|
73
|
+
|
|
74
|
+
less_than_epsilon = dist_to_other < self.epsilon
|
|
75
|
+
|
|
76
|
+
# problems which are currently not cleared and are supposed to
|
|
77
|
+
cleared = np.where(np.logical_and(~self.C, less_than_epsilon))[0]
|
|
78
|
+
|
|
79
|
+
# set them to be cleared
|
|
80
|
+
self.C[cleared] = True
|
|
81
|
+
|
|
82
|
+
return cleared
|
|
File without changes
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Column:
|
|
5
|
+
|
|
6
|
+
def __init__(self, name, width=13, func=None, truncate=True) -> None:
|
|
7
|
+
super().__init__()
|
|
8
|
+
self.name = name
|
|
9
|
+
self.func = func
|
|
10
|
+
self.width = width
|
|
11
|
+
self.truncate = truncate
|
|
12
|
+
self.value = None
|
|
13
|
+
|
|
14
|
+
def update(self, algorithm):
|
|
15
|
+
if self.func:
|
|
16
|
+
self.value = self.func(algorithm)
|
|
17
|
+
|
|
18
|
+
def header(self):
|
|
19
|
+
return str(self.name).center(self.width)
|
|
20
|
+
|
|
21
|
+
def text(self):
|
|
22
|
+
value = self.value
|
|
23
|
+
if value is None:
|
|
24
|
+
value = "-"
|
|
25
|
+
|
|
26
|
+
return format_text(value, self.width, self.truncate)
|
|
27
|
+
|
|
28
|
+
def set(self, value):
|
|
29
|
+
self.value = value
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def number_to_text(number, width):
|
|
33
|
+
if number >= 10 or number * 1e5 < 1:
|
|
34
|
+
return f"%.{width - 7}E" % number
|
|
35
|
+
else:
|
|
36
|
+
return f"%.{width - 3}f" % number
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def format_text(value, width, truncate):
|
|
40
|
+
if value is not None:
|
|
41
|
+
|
|
42
|
+
if isinstance(value, (np.floating, float)):
|
|
43
|
+
text = number_to_text(value, width)
|
|
44
|
+
else:
|
|
45
|
+
text = str(value)
|
|
46
|
+
|
|
47
|
+
if truncate and len(text) > width:
|
|
48
|
+
text = text[:width]
|
|
49
|
+
else:
|
|
50
|
+
text = "-"
|
|
51
|
+
text = text.rjust(width)
|
|
52
|
+
return text
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from pymoo.core.callback import Callback
|
|
2
|
+
from pymoo.util.display.progress import ProgressBar
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Display(Callback):
|
|
6
|
+
|
|
7
|
+
def __init__(self, output=None, progress=False, verbose=False):
|
|
8
|
+
super().__init__()
|
|
9
|
+
self.output = output
|
|
10
|
+
self.verbose = verbose
|
|
11
|
+
self.progress = ProgressBar() if progress else None
|
|
12
|
+
|
|
13
|
+
def update(self, algorithm, **kwargs):
|
|
14
|
+
output, progress = self.output, self.progress
|
|
15
|
+
|
|
16
|
+
if self.verbose and output:
|
|
17
|
+
text = ""
|
|
18
|
+
header = not output.is_initialized
|
|
19
|
+
output(algorithm)
|
|
20
|
+
|
|
21
|
+
if header:
|
|
22
|
+
text += output.header(border=True) + '\n'
|
|
23
|
+
text += output.text()
|
|
24
|
+
|
|
25
|
+
print(text)
|
|
26
|
+
|
|
27
|
+
if progress:
|
|
28
|
+
perc = algorithm.termination.perc
|
|
29
|
+
progress.set(perc)
|
|
30
|
+
|
|
31
|
+
def finalize(self):
|
|
32
|
+
|
|
33
|
+
if self.progress:
|
|
34
|
+
self.progress.close()
|