pymoo 0.6.1.5.dev0__cp311-cp311-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-311-x86_64-linux-musl.so +0 -0
- pymoo/cython/calc_perpendicular_distance.pyx +67 -0
- pymoo/cython/decomposition.cpython-311-x86_64-linux-musl.so +0 -0
- pymoo/cython/decomposition.pyx +165 -0
- pymoo/cython/hv.cpython-311-x86_64-linux-musl.so +0 -0
- pymoo/cython/hv.pyx +18 -0
- pymoo/cython/info.cpython-311-x86_64-linux-musl.so +0 -0
- pymoo/cython/info.pyx +5 -0
- pymoo/cython/mnn.cpython-311-x86_64-linux-musl.so +0 -0
- pymoo/cython/mnn.pyx +273 -0
- pymoo/cython/non_dominated_sorting.cpython-311-x86_64-linux-musl.so +0 -0
- pymoo/cython/non_dominated_sorting.pyx +645 -0
- pymoo/cython/pruning_cd.cpython-311-x86_64-linux-musl.so +0 -0
- pymoo/cython/pruning_cd.pyx +197 -0
- pymoo/cython/stochastic_ranking.cpython-311-x86_64-linux-musl.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,310 @@
|
|
|
1
|
+
try:
|
|
2
|
+
import numba
|
|
3
|
+
from numba import jit
|
|
4
|
+
except:
|
|
5
|
+
raise Exception("Please install numba to use AGEMOEA: pip install numba")
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
from pymoo.algorithms.base.genetic import GeneticAlgorithm
|
|
10
|
+
from pymoo.algorithms.moo.nsga2 import binary_tournament
|
|
11
|
+
from pymoo.core.survival import Survival
|
|
12
|
+
from pymoo.docs import parse_doc_string
|
|
13
|
+
from pymoo.operators.crossover.sbx import SBX
|
|
14
|
+
from pymoo.operators.mutation.pm import PM
|
|
15
|
+
from pymoo.operators.sampling.rnd import FloatRandomSampling
|
|
16
|
+
from pymoo.operators.selection.tournament import TournamentSelection
|
|
17
|
+
from pymoo.termination.default import DefaultMultiObjectiveTermination
|
|
18
|
+
from pymoo.util.display.multi import MultiObjectiveOutput
|
|
19
|
+
from pymoo.util.misc import has_feasible
|
|
20
|
+
from pymoo.util.nds.non_dominated_sorting import NonDominatedSorting
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# =========================================================================================================
|
|
24
|
+
# Implementation
|
|
25
|
+
# =========================================================================================================
|
|
26
|
+
|
|
27
|
+
class AGEMOEA(GeneticAlgorithm):
|
|
28
|
+
|
|
29
|
+
def __init__(self,
|
|
30
|
+
pop_size=100,
|
|
31
|
+
sampling=FloatRandomSampling(),
|
|
32
|
+
selection=TournamentSelection(func_comp=binary_tournament),
|
|
33
|
+
crossover=SBX(eta=15, prob=0.9),
|
|
34
|
+
mutation=PM(eta=20),
|
|
35
|
+
eliminate_duplicates=True,
|
|
36
|
+
n_offsprings=None,
|
|
37
|
+
output=MultiObjectiveOutput(),
|
|
38
|
+
**kwargs):
|
|
39
|
+
"""
|
|
40
|
+
Adapted from:
|
|
41
|
+
Panichella, A. (2019). An adaptive evolutionary algorithm based on non-euclidean geometry for many-objective
|
|
42
|
+
optimization. GECCO 2019 - Proceedings of the 2019 Genetic and Evolutionary Computation Conference, July, 595–603.
|
|
43
|
+
https://doi.org/10.1145/3321707.3321839
|
|
44
|
+
|
|
45
|
+
Parameters
|
|
46
|
+
----------
|
|
47
|
+
pop_size : {pop_size}
|
|
48
|
+
sampling : {sampling}
|
|
49
|
+
selection : {selection}
|
|
50
|
+
crossover : {crossover}
|
|
51
|
+
mutation : {mutation}
|
|
52
|
+
eliminate_duplicates : {eliminate_duplicates}
|
|
53
|
+
n_offsprings : {n_offsprings}
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
super().__init__(pop_size=pop_size,
|
|
57
|
+
sampling=sampling,
|
|
58
|
+
selection=selection,
|
|
59
|
+
crossover=crossover,
|
|
60
|
+
mutation=mutation,
|
|
61
|
+
survival=AGEMOEASurvival(),
|
|
62
|
+
eliminate_duplicates=eliminate_duplicates,
|
|
63
|
+
n_offsprings=n_offsprings,
|
|
64
|
+
output=output,
|
|
65
|
+
advance_after_initial_infill=True,
|
|
66
|
+
**kwargs)
|
|
67
|
+
self.default_termination = DefaultMultiObjectiveTermination()
|
|
68
|
+
|
|
69
|
+
self.tournament_type = 'comp_by_rank_and_crowding'
|
|
70
|
+
|
|
71
|
+
def _set_optimum(self, **kwargs):
|
|
72
|
+
if not has_feasible(self.pop):
|
|
73
|
+
self.opt = self.pop[[np.argmin(self.pop.get("CV"))]]
|
|
74
|
+
else:
|
|
75
|
+
self.opt = self.pop[self.pop.get("rank") == 0]
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
79
|
+
# Survival Selection
|
|
80
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
81
|
+
|
|
82
|
+
class AGEMOEASurvival(Survival):
|
|
83
|
+
|
|
84
|
+
def __init__(self) -> None:
|
|
85
|
+
super().__init__(filter_infeasible=True)
|
|
86
|
+
self.nds = NonDominatedSorting()
|
|
87
|
+
|
|
88
|
+
def _do(self, problem, pop, *args, n_survive=None, **kwargs):
|
|
89
|
+
|
|
90
|
+
# get the objective values
|
|
91
|
+
F = pop.get("F")
|
|
92
|
+
|
|
93
|
+
N = n_survive
|
|
94
|
+
|
|
95
|
+
# Non-dominated sorting
|
|
96
|
+
fronts = self.nds.do(F, n_stop_if_ranked=N)
|
|
97
|
+
|
|
98
|
+
# get max int value
|
|
99
|
+
max_val = np.iinfo(int).max
|
|
100
|
+
|
|
101
|
+
# initialize population ranks with max int value
|
|
102
|
+
front_no = np.full(F.shape[0], max_val, dtype=int)
|
|
103
|
+
|
|
104
|
+
# assign the rank to each individual
|
|
105
|
+
for i, fr in enumerate(fronts):
|
|
106
|
+
front_no[fr] = i
|
|
107
|
+
|
|
108
|
+
pop.set("rank", front_no)
|
|
109
|
+
|
|
110
|
+
# get the index of the front to be sorted and cut
|
|
111
|
+
max_f_no = np.max(front_no[front_no != max_val])
|
|
112
|
+
|
|
113
|
+
# keep fronts that have lower rank than the front to cut
|
|
114
|
+
selected: np.ndarray = front_no < max_f_no
|
|
115
|
+
|
|
116
|
+
n_ind, _ = F.shape
|
|
117
|
+
|
|
118
|
+
# crowding distance is positive and has to be maximized
|
|
119
|
+
crowd_dist = np.zeros(n_ind)
|
|
120
|
+
|
|
121
|
+
# get the first front for normalization
|
|
122
|
+
front1 = F[front_no == 0, :]
|
|
123
|
+
|
|
124
|
+
# follows from the definition of the ideal point but with current non dominated solutions
|
|
125
|
+
ideal_point = np.min(front1, axis=0)
|
|
126
|
+
|
|
127
|
+
# Calculate the crowding distance of the first front as well as p and the normalization constants
|
|
128
|
+
crowd_dist[front_no == 0], p, normalization = self.survival_score(front1, ideal_point)
|
|
129
|
+
for i in range(1, max_f_no): # skip first front since it is normalized by survival_score
|
|
130
|
+
front = F[front_no == i, :]
|
|
131
|
+
m, _ = front.shape
|
|
132
|
+
front = front / normalization
|
|
133
|
+
crowd_dist[front_no == i] = 1. / self.minkowski_distances(front, ideal_point[None, :], p=p).squeeze()
|
|
134
|
+
|
|
135
|
+
# Select the solutions in the last front based on their crowding distances
|
|
136
|
+
last = np.arange(selected.shape[0])[front_no == max_f_no]
|
|
137
|
+
rank = np.argsort(crowd_dist[last])[::-1]
|
|
138
|
+
selected[last[rank[: N - np.sum(selected)]]] = True
|
|
139
|
+
|
|
140
|
+
pop.set("crowding", crowd_dist)
|
|
141
|
+
|
|
142
|
+
# return selected solutions, number of selected should be equal to population size
|
|
143
|
+
return pop[selected]
|
|
144
|
+
|
|
145
|
+
def survival_score(self, front, ideal_point):
|
|
146
|
+
front = np.round(front, 12, out=front)
|
|
147
|
+
m, n = front.shape
|
|
148
|
+
crowd_dist = np.zeros(m)
|
|
149
|
+
|
|
150
|
+
if m < n:
|
|
151
|
+
p = 1
|
|
152
|
+
normalization = np.max(front, axis=0)
|
|
153
|
+
return crowd_dist, p, normalization
|
|
154
|
+
|
|
155
|
+
# shift the ideal point to the origin
|
|
156
|
+
front = front - ideal_point
|
|
157
|
+
|
|
158
|
+
# Detect the extreme points and normalize the front
|
|
159
|
+
extreme = find_corner_solutions(front)
|
|
160
|
+
front, normalization = normalize(front, extreme)
|
|
161
|
+
|
|
162
|
+
# set the distance for the extreme solutions
|
|
163
|
+
crowd_dist[extreme] = np.inf
|
|
164
|
+
selected = np.full(m, False)
|
|
165
|
+
selected[extreme] = True
|
|
166
|
+
|
|
167
|
+
p = self.compute_geometry(front, extreme, n)
|
|
168
|
+
|
|
169
|
+
nn = np.linalg.norm(front, p, axis=1)
|
|
170
|
+
# Replace very small norms with 1 to prevent division by zero
|
|
171
|
+
nn[nn < 1e-8] = 1
|
|
172
|
+
|
|
173
|
+
distances = self.pairwise_distances(front, p)
|
|
174
|
+
distances[distances < 1e-8] = 1e-8 # Replace very small entries to prevent division by zero
|
|
175
|
+
|
|
176
|
+
distances = distances / (nn[:, None])
|
|
177
|
+
|
|
178
|
+
neighbors = 2
|
|
179
|
+
remaining = np.arange(m)
|
|
180
|
+
remaining = list(remaining[~selected])
|
|
181
|
+
for i in range(m - np.sum(selected)):
|
|
182
|
+
mg = np.meshgrid(np.arange(selected.shape[0])[selected], remaining, copy=False, sparse=False)
|
|
183
|
+
D_mg = distances[tuple(mg)] # avoid Numpy's future deprecation of array special indexing
|
|
184
|
+
|
|
185
|
+
if D_mg.shape[1] > 1:
|
|
186
|
+
# equivalent to mink(distances(remaining, selected),neighbors,2); in Matlab
|
|
187
|
+
maxim = np.argpartition(D_mg, neighbors - 1, axis=1)[:, :neighbors]
|
|
188
|
+
tmp = np.sum(np.take_along_axis(D_mg, maxim, axis=1), axis=1)
|
|
189
|
+
index: int = np.argmax(tmp)
|
|
190
|
+
d = tmp[index]
|
|
191
|
+
else:
|
|
192
|
+
index = D_mg[:, 0].argmax()
|
|
193
|
+
d = D_mg[index, 0]
|
|
194
|
+
|
|
195
|
+
best = remaining.pop(index)
|
|
196
|
+
selected[best] = True
|
|
197
|
+
crowd_dist[best] = d
|
|
198
|
+
|
|
199
|
+
return crowd_dist, p, normalization
|
|
200
|
+
|
|
201
|
+
@staticmethod
|
|
202
|
+
def compute_geometry(front, extreme, n):
|
|
203
|
+
# approximate p(norm)
|
|
204
|
+
d = point_2_line_distance(front, np.zeros(n), np.ones(n))
|
|
205
|
+
d[extreme] = np.inf
|
|
206
|
+
index = np.argmin(d)
|
|
207
|
+
|
|
208
|
+
p = np.log(n) / np.log(1.0 / np.mean(front[index, :]))
|
|
209
|
+
|
|
210
|
+
if np.isnan(p) or p <= 0.1:
|
|
211
|
+
p = 1.0
|
|
212
|
+
elif p > 20:
|
|
213
|
+
p = 20.0 # avoid numpy underflow
|
|
214
|
+
|
|
215
|
+
return p
|
|
216
|
+
|
|
217
|
+
@staticmethod
|
|
218
|
+
#@jit(nopython=True, fastmath=True)
|
|
219
|
+
def pairwise_distances(front, p):
|
|
220
|
+
m = np.shape(front)[0]
|
|
221
|
+
distances = np.zeros((m, m))
|
|
222
|
+
for i in range(m):
|
|
223
|
+
distances[i] = np.sum(np.abs(front[i] - front) ** p, 1) ** (1 / p)
|
|
224
|
+
|
|
225
|
+
return distances
|
|
226
|
+
|
|
227
|
+
@staticmethod
|
|
228
|
+
@jit(nopython=True, fastmath=True)
|
|
229
|
+
def minkowski_distances(A, B, p):
|
|
230
|
+
m1 = np.shape(A)[0]
|
|
231
|
+
m2 = np.shape(B)[0]
|
|
232
|
+
distances = np.zeros((m1, m2))
|
|
233
|
+
for i in range(m1):
|
|
234
|
+
for j in range(m2):
|
|
235
|
+
distances[i][j] = np.sum(np.abs(A[i] - B[j]) ** p) ** (1 / p)
|
|
236
|
+
|
|
237
|
+
return distances
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
@jit(nopython=True, fastmath=True)
|
|
241
|
+
def find_corner_solutions(front):
|
|
242
|
+
"""Return the indexes of the extreme points"""
|
|
243
|
+
|
|
244
|
+
m, n = front.shape
|
|
245
|
+
|
|
246
|
+
if m <= n:
|
|
247
|
+
return np.arange(m)
|
|
248
|
+
|
|
249
|
+
# let's define the axes of the n-dimensional spaces
|
|
250
|
+
W = 1e-6 + np.eye(n)
|
|
251
|
+
r = W.shape[0]
|
|
252
|
+
indexes = np.zeros(n, dtype=numba.intp)
|
|
253
|
+
selected = np.zeros(m, dtype=numba.boolean)
|
|
254
|
+
for i in range(r):
|
|
255
|
+
dists = point_2_line_distance(front, np.zeros(n), W[i, :])
|
|
256
|
+
dists[selected] = np.inf # prevent already selected to be reselected
|
|
257
|
+
index = np.argmin(dists)
|
|
258
|
+
indexes[i] = index
|
|
259
|
+
selected[index] = True
|
|
260
|
+
return indexes
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
@jit(nopython=True, fastmath=True)
|
|
264
|
+
def point_2_line_distance(P, A, B):
|
|
265
|
+
d = np.zeros(P.shape[0], dtype=numba.float64)
|
|
266
|
+
|
|
267
|
+
for i in range(P.shape[0]):
|
|
268
|
+
pa = P[i] - A
|
|
269
|
+
ba = B - A
|
|
270
|
+
t = np.dot(pa, ba) / np.dot(ba, ba)
|
|
271
|
+
d[i] = np.sum((pa - t * ba) ** 2)
|
|
272
|
+
|
|
273
|
+
return d
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
# =========================================================================================================
|
|
277
|
+
# Normalization
|
|
278
|
+
# =========================================================================================================
|
|
279
|
+
|
|
280
|
+
def normalize(front, extreme):
|
|
281
|
+
m, n = front.shape
|
|
282
|
+
|
|
283
|
+
if len(extreme) != len(np.unique(extreme, axis=0)):
|
|
284
|
+
normalization = np.max(front, axis=0)
|
|
285
|
+
front = front / normalization
|
|
286
|
+
return front, normalization
|
|
287
|
+
|
|
288
|
+
# Calculate the intercepts of the hyperplane constructed by the extreme
|
|
289
|
+
# points and the axes
|
|
290
|
+
|
|
291
|
+
try:
|
|
292
|
+
hyperplane = np.linalg.solve(front[extreme], np.ones(n))
|
|
293
|
+
if any(np.isnan(hyperplane)) or any(np.isinf(hyperplane)) or any(hyperplane <= 0):
|
|
294
|
+
normalization = np.max(front, axis=0)
|
|
295
|
+
else:
|
|
296
|
+
normalization = 1. / hyperplane
|
|
297
|
+
if any(np.isnan(normalization)) or any(np.isinf(normalization)):
|
|
298
|
+
normalization = np.max(front, axis=0)
|
|
299
|
+
except np.linalg.LinAlgError:
|
|
300
|
+
normalization = np.max(front, axis=0)
|
|
301
|
+
|
|
302
|
+
normalization[normalization == 0.0] = 1.0
|
|
303
|
+
|
|
304
|
+
# Normalization
|
|
305
|
+
front = front / normalization
|
|
306
|
+
|
|
307
|
+
return front, normalization
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
parse_doc_string(AGEMOEA.__init__)
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
from pymoo.docs import parse_doc_string
|
|
2
|
+
|
|
3
|
+
try:
|
|
4
|
+
import numba
|
|
5
|
+
from numba import jit
|
|
6
|
+
except:
|
|
7
|
+
raise Exception("Please install numba to use AGEMOEA2: pip install numba")
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
from pymoo.algorithms.base.genetic import GeneticAlgorithm
|
|
13
|
+
from pymoo.algorithms.moo.age import AGEMOEASurvival
|
|
14
|
+
from pymoo.algorithms.moo.nsga2 import binary_tournament
|
|
15
|
+
from pymoo.operators.crossover.sbx import SBX
|
|
16
|
+
from pymoo.operators.mutation.pm import PM
|
|
17
|
+
from pymoo.operators.sampling.rnd import FloatRandomSampling
|
|
18
|
+
from pymoo.operators.selection.tournament import TournamentSelection
|
|
19
|
+
from pymoo.util.display.multi import MultiObjectiveOutput
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class AGEMOEA2(GeneticAlgorithm):
|
|
23
|
+
|
|
24
|
+
def __init__(self,
|
|
25
|
+
pop_size=100,
|
|
26
|
+
sampling=FloatRandomSampling(),
|
|
27
|
+
selection=TournamentSelection(func_comp=binary_tournament),
|
|
28
|
+
crossover=SBX(prob=0.9, eta=15),
|
|
29
|
+
mutation=PM(eta=20),
|
|
30
|
+
eliminate_duplicates=True,
|
|
31
|
+
n_offsprings=None,
|
|
32
|
+
output=MultiObjectiveOutput(),
|
|
33
|
+
**kwargs):
|
|
34
|
+
"""
|
|
35
|
+
Adapted from:
|
|
36
|
+
Panichella, A. (2022). An Improved Pareto Front Modeling Algorithm for Large-scale Many-Objective Optimization.
|
|
37
|
+
Proceedings of the 2022 Genetic and Evolutionary Computation Conference (GECCO 2022).
|
|
38
|
+
https://doi.org/10.1145/3512290.3528732
|
|
39
|
+
|
|
40
|
+
@author: Annibale Panichella
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
pop_size : {pop_size}
|
|
45
|
+
sampling : {sampling}
|
|
46
|
+
selection : {selection}
|
|
47
|
+
crossover : {crossover}
|
|
48
|
+
mutation : {mutation}
|
|
49
|
+
eliminate_duplicates : {eliminate_duplicates}
|
|
50
|
+
n_offsprings : {n_offsprings}
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
super().__init__(pop_size=pop_size,
|
|
54
|
+
sampling=sampling,
|
|
55
|
+
selection=selection,
|
|
56
|
+
crossover=crossover,
|
|
57
|
+
mutation=mutation,
|
|
58
|
+
survival=AGEMOEA2Survival(),
|
|
59
|
+
eliminate_duplicates=eliminate_duplicates,
|
|
60
|
+
n_offsprings=n_offsprings,
|
|
61
|
+
output=output,
|
|
62
|
+
advance_after_initial_infill=True,
|
|
63
|
+
**kwargs)
|
|
64
|
+
self.tournament_type = 'comp_by_rank_and_crowding'
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@jit(nopython=True, fastmath=True)
|
|
68
|
+
def project_on_manifold(point, p):
|
|
69
|
+
dist = np.sum(point[point > 0] ** p) ** (1/p)
|
|
70
|
+
return np.multiply(point, 1 / dist)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
import numpy as np
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def find_zero(point, n, precision):
|
|
77
|
+
x = 1
|
|
78
|
+
epsilon = 1e-10 # Small constant for regularization
|
|
79
|
+
past_value = x
|
|
80
|
+
max_float = np.finfo(np.float64).max # Maximum representable float value
|
|
81
|
+
log_max_float = np.log(max_float) # Logarithm of the maximum float
|
|
82
|
+
|
|
83
|
+
for i in range(0, 100):
|
|
84
|
+
|
|
85
|
+
# Original function with regularization
|
|
86
|
+
f = 0.0
|
|
87
|
+
for obj_index in range(0, n):
|
|
88
|
+
if point[obj_index] > 0:
|
|
89
|
+
log_value = x * np.log(point[obj_index] + epsilon)
|
|
90
|
+
if log_value < log_max_float:
|
|
91
|
+
f += np.exp(log_value)
|
|
92
|
+
else:
|
|
93
|
+
return 1 # Handle overflow by returning a fallback value
|
|
94
|
+
|
|
95
|
+
f = np.log(f) if f > 0 else 0 # Avoid log of non-positive numbers
|
|
96
|
+
|
|
97
|
+
# Derivative with regularization
|
|
98
|
+
numerator = 0
|
|
99
|
+
denominator = 0
|
|
100
|
+
for obj_index in range(0, n):
|
|
101
|
+
if point[obj_index] > 0:
|
|
102
|
+
log_value = x * np.log(point[obj_index] + epsilon)
|
|
103
|
+
if log_value < log_max_float:
|
|
104
|
+
power_value = np.exp(log_value)
|
|
105
|
+
log_term = np.log(point[obj_index] + epsilon)
|
|
106
|
+
|
|
107
|
+
# Use logarithmic comparison to avoid overflow
|
|
108
|
+
if log_value + np.log(abs(log_term) + epsilon) < log_max_float:
|
|
109
|
+
result = power_value * log_term
|
|
110
|
+
numerator += result
|
|
111
|
+
denominator += power_value
|
|
112
|
+
else:
|
|
113
|
+
# Handle extreme cases by capping the result
|
|
114
|
+
numerator += max_float
|
|
115
|
+
denominator += power_value
|
|
116
|
+
else:
|
|
117
|
+
return 1 # Handle overflow by returning a fallback value
|
|
118
|
+
|
|
119
|
+
if denominator == 0 or np.isnan(denominator) or np.isinf(denominator):
|
|
120
|
+
return 1 # Handle division by zero or NaN
|
|
121
|
+
|
|
122
|
+
if np.isnan(numerator) or np.isinf(numerator):
|
|
123
|
+
return 1 # Handle invalid numerator
|
|
124
|
+
|
|
125
|
+
ff = numerator / denominator
|
|
126
|
+
|
|
127
|
+
if ff == 0: # Check for zero before division
|
|
128
|
+
return 1 # Handle by returning a fallback value
|
|
129
|
+
|
|
130
|
+
# Update x using Newton's method
|
|
131
|
+
x = x - f / ff
|
|
132
|
+
|
|
133
|
+
if abs(x - past_value) <= precision:
|
|
134
|
+
break
|
|
135
|
+
else:
|
|
136
|
+
past_value = x # Update current point
|
|
137
|
+
|
|
138
|
+
if isinstance(x, complex) or np.isinf(x) or np.isnan(x):
|
|
139
|
+
return 1
|
|
140
|
+
else:
|
|
141
|
+
return x
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class AGEMOEA2Survival(AGEMOEASurvival):
|
|
145
|
+
|
|
146
|
+
@staticmethod
|
|
147
|
+
def compute_geometry(front, extreme, n):
|
|
148
|
+
m, _ = np.shape(front)
|
|
149
|
+
|
|
150
|
+
# approximate p(norm)
|
|
151
|
+
d = np.zeros(m)
|
|
152
|
+
for i in range(0, m):
|
|
153
|
+
d[i] = sum(front[i] ** 2) ** 0.5
|
|
154
|
+
|
|
155
|
+
d[extreme] = np.inf
|
|
156
|
+
index = np.argmin(d)
|
|
157
|
+
|
|
158
|
+
p = find_zero(front[index], n, 0.001)
|
|
159
|
+
|
|
160
|
+
if np.isnan(p) or p <= 0.1:
|
|
161
|
+
p = 1.0
|
|
162
|
+
elif p > 20:
|
|
163
|
+
p = 20.0 # avoid numpy underflow
|
|
164
|
+
|
|
165
|
+
return p
|
|
166
|
+
|
|
167
|
+
@staticmethod
|
|
168
|
+
@jit(nopython=True, fastmath=True)
|
|
169
|
+
def pairwise_distances(front, p):
|
|
170
|
+
m, n = front.shape
|
|
171
|
+
projected_front = front.copy()
|
|
172
|
+
|
|
173
|
+
for index in range(0, m):
|
|
174
|
+
projected_front[index] = project_on_manifold(front[index], p=p)
|
|
175
|
+
|
|
176
|
+
distances = np.zeros((m, m), dtype=numba.float64)
|
|
177
|
+
|
|
178
|
+
if 0.95 < p < 1.05:
|
|
179
|
+
for row in range(0, m - 1):
|
|
180
|
+
for column in range(row + 1, m):
|
|
181
|
+
distances[row][column] = np.sum(np.abs(projected_front[row] - projected_front[column]) ** 2) ** 0.5
|
|
182
|
+
|
|
183
|
+
else:
|
|
184
|
+
for row in range(0, m-1):
|
|
185
|
+
for column in range(row+1, m):
|
|
186
|
+
mid_point = projected_front[row] * 0.5 + projected_front[column] * 0.5
|
|
187
|
+
mid_point = project_on_manifold(mid_point, p)
|
|
188
|
+
|
|
189
|
+
distances[row][column] = np.sum(np.abs(projected_front[row] - mid_point) ** 2) ** 0.5 + \
|
|
190
|
+
np.sum(np.abs(projected_front[column] - mid_point) ** 2) ** 0.5
|
|
191
|
+
|
|
192
|
+
return distances + distances.T
|
|
193
|
+
|
|
194
|
+
parse_doc_string(AGEMOEA2.__init__)
|