pymoo 0.6.1.6__cp312-cp312-macosx_10_13_universal2.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.
Files changed (337) hide show
  1. pymoo/__init__.py +3 -0
  2. pymoo/algorithms/__init__.py +0 -0
  3. pymoo/algorithms/base/__init__.py +0 -0
  4. pymoo/algorithms/base/bracket.py +38 -0
  5. pymoo/algorithms/base/genetic.py +110 -0
  6. pymoo/algorithms/base/line.py +62 -0
  7. pymoo/algorithms/base/local.py +39 -0
  8. pymoo/algorithms/base/meta.py +79 -0
  9. pymoo/algorithms/hyperparameters.py +91 -0
  10. pymoo/algorithms/moo/__init__.py +0 -0
  11. pymoo/algorithms/moo/age.py +310 -0
  12. pymoo/algorithms/moo/age2.py +194 -0
  13. pymoo/algorithms/moo/cmopso.py +239 -0
  14. pymoo/algorithms/moo/ctaea.py +305 -0
  15. pymoo/algorithms/moo/dnsga2.py +80 -0
  16. pymoo/algorithms/moo/kgb.py +450 -0
  17. pymoo/algorithms/moo/moead.py +183 -0
  18. pymoo/algorithms/moo/mopso_cd.py +309 -0
  19. pymoo/algorithms/moo/nsga2.py +113 -0
  20. pymoo/algorithms/moo/nsga3.py +361 -0
  21. pymoo/algorithms/moo/pinsga2.py +370 -0
  22. pymoo/algorithms/moo/rnsga2.py +188 -0
  23. pymoo/algorithms/moo/rnsga3.py +246 -0
  24. pymoo/algorithms/moo/rvea.py +214 -0
  25. pymoo/algorithms/moo/sms.py +196 -0
  26. pymoo/algorithms/moo/spea2.py +191 -0
  27. pymoo/algorithms/moo/unsga3.py +49 -0
  28. pymoo/algorithms/soo/__init__.py +0 -0
  29. pymoo/algorithms/soo/convex/__init__.py +0 -0
  30. pymoo/algorithms/soo/nonconvex/__init__.py +0 -0
  31. pymoo/algorithms/soo/nonconvex/brkga.py +162 -0
  32. pymoo/algorithms/soo/nonconvex/cmaes.py +556 -0
  33. pymoo/algorithms/soo/nonconvex/de.py +283 -0
  34. pymoo/algorithms/soo/nonconvex/direct.py +148 -0
  35. pymoo/algorithms/soo/nonconvex/es.py +213 -0
  36. pymoo/algorithms/soo/nonconvex/g3pcx.py +94 -0
  37. pymoo/algorithms/soo/nonconvex/ga.py +95 -0
  38. pymoo/algorithms/soo/nonconvex/ga_niching.py +223 -0
  39. pymoo/algorithms/soo/nonconvex/isres.py +74 -0
  40. pymoo/algorithms/soo/nonconvex/nelder.py +251 -0
  41. pymoo/algorithms/soo/nonconvex/nrbo.py +191 -0
  42. pymoo/algorithms/soo/nonconvex/optuna.py +80 -0
  43. pymoo/algorithms/soo/nonconvex/pattern.py +185 -0
  44. pymoo/algorithms/soo/nonconvex/pso.py +337 -0
  45. pymoo/algorithms/soo/nonconvex/pso_ep.py +307 -0
  46. pymoo/algorithms/soo/nonconvex/random_search.py +25 -0
  47. pymoo/algorithms/soo/nonconvex/sres.py +56 -0
  48. pymoo/algorithms/soo/univariate/__init__.py +0 -0
  49. pymoo/algorithms/soo/univariate/exp.py +46 -0
  50. pymoo/algorithms/soo/univariate/golden.py +65 -0
  51. pymoo/algorithms/soo/univariate/quadr_interp.py +81 -0
  52. pymoo/algorithms/soo/univariate/wolfe.py +163 -0
  53. pymoo/config.py +33 -0
  54. pymoo/constraints/__init__.py +3 -0
  55. pymoo/constraints/adaptive.py +66 -0
  56. pymoo/constraints/as_obj.py +56 -0
  57. pymoo/constraints/as_penalty.py +41 -0
  58. pymoo/constraints/eps.py +34 -0
  59. pymoo/constraints/from_bounds.py +36 -0
  60. pymoo/core/__init__.py +0 -0
  61. pymoo/core/algorithm.py +408 -0
  62. pymoo/core/callback.py +38 -0
  63. pymoo/core/crossover.py +79 -0
  64. pymoo/core/decision_making.py +102 -0
  65. pymoo/core/decomposition.py +76 -0
  66. pymoo/core/duplicate.py +163 -0
  67. pymoo/core/evaluator.py +116 -0
  68. pymoo/core/indicator.py +34 -0
  69. pymoo/core/individual.py +784 -0
  70. pymoo/core/infill.py +65 -0
  71. pymoo/core/initialization.py +44 -0
  72. pymoo/core/mating.py +39 -0
  73. pymoo/core/meta.py +21 -0
  74. pymoo/core/mixed.py +164 -0
  75. pymoo/core/mutation.py +44 -0
  76. pymoo/core/operator.py +46 -0
  77. pymoo/core/parameters.py +134 -0
  78. pymoo/core/plot.py +208 -0
  79. pymoo/core/population.py +180 -0
  80. pymoo/core/problem.py +373 -0
  81. pymoo/core/recorder.py +99 -0
  82. pymoo/core/repair.py +23 -0
  83. pymoo/core/replacement.py +96 -0
  84. pymoo/core/result.py +52 -0
  85. pymoo/core/sampling.py +45 -0
  86. pymoo/core/selection.py +61 -0
  87. pymoo/core/solution.py +10 -0
  88. pymoo/core/survival.py +107 -0
  89. pymoo/core/termination.py +70 -0
  90. pymoo/core/variable.py +415 -0
  91. pymoo/decomposition/__init__.py +0 -0
  92. pymoo/decomposition/aasf.py +24 -0
  93. pymoo/decomposition/asf.py +10 -0
  94. pymoo/decomposition/pbi.py +13 -0
  95. pymoo/decomposition/perp_dist.py +13 -0
  96. pymoo/decomposition/tchebicheff.py +11 -0
  97. pymoo/decomposition/util.py +13 -0
  98. pymoo/decomposition/weighted_sum.py +8 -0
  99. pymoo/docs.py +187 -0
  100. pymoo/experimental/__init__.py +0 -0
  101. pymoo/experimental/algorithms/__init__.py +0 -0
  102. pymoo/experimental/algorithms/gde3.py +57 -0
  103. pymoo/functions/__init__.py +135 -0
  104. pymoo/functions/compiled/__init__.py +0 -0
  105. pymoo/functions/compiled/calc_perpendicular_distance.cpp +27464 -0
  106. pymoo/functions/compiled/calc_perpendicular_distance.cpython-312-darwin.so +0 -0
  107. pymoo/functions/compiled/decomposition.cpp +28853 -0
  108. pymoo/functions/compiled/decomposition.cpython-312-darwin.so +0 -0
  109. pymoo/functions/compiled/info.cpp +7058 -0
  110. pymoo/functions/compiled/info.cpython-312-darwin.so +0 -0
  111. pymoo/functions/compiled/mnn.cpp +30095 -0
  112. pymoo/functions/compiled/mnn.cpython-312-darwin.so +0 -0
  113. pymoo/functions/compiled/non_dominated_sorting.cpp +35692 -0
  114. pymoo/functions/compiled/non_dominated_sorting.cpython-312-darwin.so +0 -0
  115. pymoo/functions/compiled/pruning_cd.cpp +29248 -0
  116. pymoo/functions/compiled/pruning_cd.cpython-312-darwin.so +0 -0
  117. pymoo/functions/compiled/stochastic_ranking.cpp +28042 -0
  118. pymoo/functions/compiled/stochastic_ranking.cpython-312-darwin.so +0 -0
  119. pymoo/functions/standard/__init__.py +1 -0
  120. pymoo/functions/standard/calc_perpendicular_distance.py +20 -0
  121. pymoo/functions/standard/decomposition.py +18 -0
  122. pymoo/functions/standard/hv.py +5 -0
  123. pymoo/functions/standard/mnn.py +78 -0
  124. pymoo/functions/standard/non_dominated_sorting.py +474 -0
  125. pymoo/functions/standard/pruning_cd.py +93 -0
  126. pymoo/functions/standard/stochastic_ranking.py +42 -0
  127. pymoo/gradient/__init__.py +24 -0
  128. pymoo/gradient/automatic.py +85 -0
  129. pymoo/gradient/grad_autograd.py +105 -0
  130. pymoo/gradient/grad_complex.py +35 -0
  131. pymoo/gradient/grad_jax.py +51 -0
  132. pymoo/gradient/numpy.py +22 -0
  133. pymoo/gradient/toolbox/__init__.py +19 -0
  134. pymoo/indicators/__init__.py +0 -0
  135. pymoo/indicators/distance_indicator.py +55 -0
  136. pymoo/indicators/gd.py +7 -0
  137. pymoo/indicators/gd_plus.py +7 -0
  138. pymoo/indicators/hv/__init__.py +59 -0
  139. pymoo/indicators/hv/approximate.py +105 -0
  140. pymoo/indicators/hv/exact.py +68 -0
  141. pymoo/indicators/hv/exact_2d.py +102 -0
  142. pymoo/indicators/igd.py +7 -0
  143. pymoo/indicators/igd_plus.py +7 -0
  144. pymoo/indicators/kktpm.py +151 -0
  145. pymoo/indicators/migd.py +55 -0
  146. pymoo/indicators/rmetric.py +203 -0
  147. pymoo/indicators/spacing.py +52 -0
  148. pymoo/mcdm/__init__.py +0 -0
  149. pymoo/mcdm/compromise_programming.py +19 -0
  150. pymoo/mcdm/high_tradeoff.py +40 -0
  151. pymoo/mcdm/pseudo_weights.py +32 -0
  152. pymoo/operators/__init__.py +0 -0
  153. pymoo/operators/control.py +190 -0
  154. pymoo/operators/crossover/__init__.py +0 -0
  155. pymoo/operators/crossover/binx.py +47 -0
  156. pymoo/operators/crossover/dex.py +125 -0
  157. pymoo/operators/crossover/erx.py +164 -0
  158. pymoo/operators/crossover/expx.py +53 -0
  159. pymoo/operators/crossover/hux.py +37 -0
  160. pymoo/operators/crossover/nox.py +25 -0
  161. pymoo/operators/crossover/ox.py +88 -0
  162. pymoo/operators/crossover/pcx.py +84 -0
  163. pymoo/operators/crossover/pntx.py +49 -0
  164. pymoo/operators/crossover/sbx.py +137 -0
  165. pymoo/operators/crossover/spx.py +5 -0
  166. pymoo/operators/crossover/ux.py +20 -0
  167. pymoo/operators/mutation/__init__.py +0 -0
  168. pymoo/operators/mutation/bitflip.py +17 -0
  169. pymoo/operators/mutation/gauss.py +60 -0
  170. pymoo/operators/mutation/inversion.py +42 -0
  171. pymoo/operators/mutation/nom.py +7 -0
  172. pymoo/operators/mutation/pm.py +96 -0
  173. pymoo/operators/mutation/rm.py +23 -0
  174. pymoo/operators/repair/__init__.py +0 -0
  175. pymoo/operators/repair/bounce_back.py +32 -0
  176. pymoo/operators/repair/bounds_repair.py +97 -0
  177. pymoo/operators/repair/inverse_penalty.py +91 -0
  178. pymoo/operators/repair/rounding.py +18 -0
  179. pymoo/operators/repair/to_bound.py +31 -0
  180. pymoo/operators/repair/vtype.py +11 -0
  181. pymoo/operators/sampling/__init__.py +0 -0
  182. pymoo/operators/sampling/lhs.py +76 -0
  183. pymoo/operators/sampling/rnd.py +52 -0
  184. pymoo/operators/selection/__init__.py +0 -0
  185. pymoo/operators/selection/rnd.py +75 -0
  186. pymoo/operators/selection/tournament.py +78 -0
  187. pymoo/operators/survival/__init__.py +0 -0
  188. pymoo/operators/survival/rank_and_crowding/__init__.py +1 -0
  189. pymoo/operators/survival/rank_and_crowding/classes.py +212 -0
  190. pymoo/operators/survival/rank_and_crowding/metrics.py +208 -0
  191. pymoo/optimize.py +72 -0
  192. pymoo/parallelization/__init__.py +15 -0
  193. pymoo/parallelization/dask.py +25 -0
  194. pymoo/parallelization/joblib.py +28 -0
  195. pymoo/parallelization/ray.py +31 -0
  196. pymoo/parallelization/starmap.py +24 -0
  197. pymoo/problems/__init__.py +157 -0
  198. pymoo/problems/dyn.py +47 -0
  199. pymoo/problems/dynamic/__init__.py +0 -0
  200. pymoo/problems/dynamic/cec2015.py +108 -0
  201. pymoo/problems/dynamic/df.py +451 -0
  202. pymoo/problems/dynamic/misc.py +167 -0
  203. pymoo/problems/functional.py +48 -0
  204. pymoo/problems/many/__init__.py +5 -0
  205. pymoo/problems/many/cdtlz.py +159 -0
  206. pymoo/problems/many/dcdtlz.py +88 -0
  207. pymoo/problems/many/dtlz.py +264 -0
  208. pymoo/problems/many/wfg.py +553 -0
  209. pymoo/problems/multi/__init__.py +14 -0
  210. pymoo/problems/multi/bnh.py +34 -0
  211. pymoo/problems/multi/carside.py +48 -0
  212. pymoo/problems/multi/clutch.py +104 -0
  213. pymoo/problems/multi/csi.py +55 -0
  214. pymoo/problems/multi/ctp.py +198 -0
  215. pymoo/problems/multi/dascmop.py +213 -0
  216. pymoo/problems/multi/kursawe.py +25 -0
  217. pymoo/problems/multi/modact.py +68 -0
  218. pymoo/problems/multi/mw.py +400 -0
  219. pymoo/problems/multi/omnitest.py +48 -0
  220. pymoo/problems/multi/osy.py +32 -0
  221. pymoo/problems/multi/srn.py +28 -0
  222. pymoo/problems/multi/sympart.py +94 -0
  223. pymoo/problems/multi/tnk.py +24 -0
  224. pymoo/problems/multi/truss2d.py +83 -0
  225. pymoo/problems/multi/welded_beam.py +41 -0
  226. pymoo/problems/multi/wrm.py +36 -0
  227. pymoo/problems/multi/zdt.py +151 -0
  228. pymoo/problems/multi_to_single.py +22 -0
  229. pymoo/problems/single/__init__.py +12 -0
  230. pymoo/problems/single/ackley.py +24 -0
  231. pymoo/problems/single/cantilevered_beam.py +34 -0
  232. pymoo/problems/single/flowshop_scheduling.py +113 -0
  233. pymoo/problems/single/g.py +874 -0
  234. pymoo/problems/single/griewank.py +18 -0
  235. pymoo/problems/single/himmelblau.py +15 -0
  236. pymoo/problems/single/knapsack.py +49 -0
  237. pymoo/problems/single/mopta08.py +26 -0
  238. pymoo/problems/single/multimodal.py +20 -0
  239. pymoo/problems/single/pressure_vessel.py +30 -0
  240. pymoo/problems/single/rastrigin.py +20 -0
  241. pymoo/problems/single/rosenbrock.py +22 -0
  242. pymoo/problems/single/schwefel.py +18 -0
  243. pymoo/problems/single/simple.py +13 -0
  244. pymoo/problems/single/sphere.py +19 -0
  245. pymoo/problems/single/traveling_salesman.py +79 -0
  246. pymoo/problems/single/zakharov.py +19 -0
  247. pymoo/problems/static.py +14 -0
  248. pymoo/problems/util.py +42 -0
  249. pymoo/problems/zero_to_one.py +27 -0
  250. pymoo/termination/__init__.py +23 -0
  251. pymoo/termination/collection.py +12 -0
  252. pymoo/termination/cv.py +48 -0
  253. pymoo/termination/default.py +45 -0
  254. pymoo/termination/delta.py +64 -0
  255. pymoo/termination/fmin.py +16 -0
  256. pymoo/termination/ftol.py +144 -0
  257. pymoo/termination/indicator.py +49 -0
  258. pymoo/termination/max_eval.py +14 -0
  259. pymoo/termination/max_gen.py +15 -0
  260. pymoo/termination/max_time.py +20 -0
  261. pymoo/termination/robust.py +34 -0
  262. pymoo/termination/xtol.py +33 -0
  263. pymoo/util/__init__.py +33 -0
  264. pymoo/util/archive.py +152 -0
  265. pymoo/util/cache.py +29 -0
  266. pymoo/util/clearing.py +82 -0
  267. pymoo/util/display/__init__.py +0 -0
  268. pymoo/util/display/column.py +52 -0
  269. pymoo/util/display/display.py +34 -0
  270. pymoo/util/display/multi.py +100 -0
  271. pymoo/util/display/output.py +53 -0
  272. pymoo/util/display/progress.py +54 -0
  273. pymoo/util/display/single.py +67 -0
  274. pymoo/util/dominator.py +67 -0
  275. pymoo/util/hv.py +21 -0
  276. pymoo/util/matlab_engine.py +39 -0
  277. pymoo/util/misc.py +447 -0
  278. pymoo/util/nds/__init__.py +0 -0
  279. pymoo/util/nds/dominance_degree_non_dominated_sort.py +159 -0
  280. pymoo/util/nds/efficient_non_dominated_sort.py +152 -0
  281. pymoo/util/nds/fast_non_dominated_sort.py +70 -0
  282. pymoo/util/nds/find_non_dominated.py +54 -0
  283. pymoo/util/nds/naive_non_dominated_sort.py +36 -0
  284. pymoo/util/nds/non_dominated_sorting.py +94 -0
  285. pymoo/util/nds/tree_based_non_dominated_sort.py +133 -0
  286. pymoo/util/normalization.py +312 -0
  287. pymoo/util/optimum.py +42 -0
  288. pymoo/util/randomized_argsort.py +63 -0
  289. pymoo/util/ref_dirs/__init__.py +24 -0
  290. pymoo/util/ref_dirs/construction.py +89 -0
  291. pymoo/util/ref_dirs/das_dennis.py +52 -0
  292. pymoo/util/ref_dirs/energy.py +317 -0
  293. pymoo/util/ref_dirs/energy_layer.py +119 -0
  294. pymoo/util/ref_dirs/genetic_algorithm.py +64 -0
  295. pymoo/util/ref_dirs/incremental.py +69 -0
  296. pymoo/util/ref_dirs/misc.py +128 -0
  297. pymoo/util/ref_dirs/optimizer.py +59 -0
  298. pymoo/util/ref_dirs/performance.py +162 -0
  299. pymoo/util/ref_dirs/reduction.py +85 -0
  300. pymoo/util/ref_dirs/sample_and_map.py +24 -0
  301. pymoo/util/reference_direction.py +258 -0
  302. pymoo/util/remote.py +55 -0
  303. pymoo/util/roulette.py +29 -0
  304. pymoo/util/running_metric.py +128 -0
  305. pymoo/util/sliding_window.py +25 -0
  306. pymoo/util/value_functions.py +720 -0
  307. pymoo/util/vectors.py +40 -0
  308. pymoo/util/vf_dominator.py +102 -0
  309. pymoo/vendor/__init__.py +0 -0
  310. pymoo/vendor/cec2018.py +398 -0
  311. pymoo/vendor/gta.py +617 -0
  312. pymoo/vendor/vendor_cmaes.py +421 -0
  313. pymoo/vendor/vendor_coco.py +81 -0
  314. pymoo/vendor/vendor_scipy.py +232 -0
  315. pymoo/version.py +1 -0
  316. pymoo/visualization/__init__.py +21 -0
  317. pymoo/visualization/app/__init__.py +0 -0
  318. pymoo/visualization/app/pso.py +61 -0
  319. pymoo/visualization/fitness_landscape.py +128 -0
  320. pymoo/visualization/heatmap.py +123 -0
  321. pymoo/visualization/matplotlib.py +61 -0
  322. pymoo/visualization/pcp.py +121 -0
  323. pymoo/visualization/petal.py +91 -0
  324. pymoo/visualization/radar.py +108 -0
  325. pymoo/visualization/radviz.py +68 -0
  326. pymoo/visualization/scatter.py +150 -0
  327. pymoo/visualization/star_coordinate.py +75 -0
  328. pymoo/visualization/util.py +296 -0
  329. pymoo/visualization/video/__init__.py +0 -0
  330. pymoo/visualization/video/callback_video.py +82 -0
  331. pymoo/visualization/video/one_var_one_obj.py +57 -0
  332. pymoo/visualization/video/two_var_one_obj.py +62 -0
  333. pymoo-0.6.1.6.dist-info/METADATA +209 -0
  334. pymoo-0.6.1.6.dist-info/RECORD +337 -0
  335. pymoo-0.6.1.6.dist-info/WHEEL +6 -0
  336. pymoo-0.6.1.6.dist-info/licenses/LICENSE +191 -0
  337. pymoo-0.6.1.6.dist-info/top_level.txt +1 -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__)