pymoo 0.6.1.3__cp39-cp39-macosx_11_0_arm64.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.

Files changed (316) 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 +109 -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 +89 -0
  10. pymoo/algorithms/moo/__init__.py +0 -0
  11. pymoo/algorithms/moo/age.py +304 -0
  12. pymoo/algorithms/moo/age2.py +164 -0
  13. pymoo/algorithms/moo/ctaea.py +298 -0
  14. pymoo/algorithms/moo/dnsga2.py +76 -0
  15. pymoo/algorithms/moo/kgb.py +446 -0
  16. pymoo/algorithms/moo/moead.py +183 -0
  17. pymoo/algorithms/moo/nsga2.py +113 -0
  18. pymoo/algorithms/moo/nsga3.py +358 -0
  19. pymoo/algorithms/moo/rnsga2.py +188 -0
  20. pymoo/algorithms/moo/rnsga3.py +246 -0
  21. pymoo/algorithms/moo/rvea.py +214 -0
  22. pymoo/algorithms/moo/sms.py +195 -0
  23. pymoo/algorithms/moo/spea2.py +190 -0
  24. pymoo/algorithms/moo/unsga3.py +47 -0
  25. pymoo/algorithms/soo/__init__.py +0 -0
  26. pymoo/algorithms/soo/convex/__init__.py +0 -0
  27. pymoo/algorithms/soo/nonconvex/__init__.py +0 -0
  28. pymoo/algorithms/soo/nonconvex/brkga.py +161 -0
  29. pymoo/algorithms/soo/nonconvex/cmaes.py +554 -0
  30. pymoo/algorithms/soo/nonconvex/de.py +279 -0
  31. pymoo/algorithms/soo/nonconvex/direct.py +149 -0
  32. pymoo/algorithms/soo/nonconvex/es.py +202 -0
  33. pymoo/algorithms/soo/nonconvex/g3pcx.py +94 -0
  34. pymoo/algorithms/soo/nonconvex/ga.py +93 -0
  35. pymoo/algorithms/soo/nonconvex/ga_niching.py +223 -0
  36. pymoo/algorithms/soo/nonconvex/isres.py +74 -0
  37. pymoo/algorithms/soo/nonconvex/nelder.py +251 -0
  38. pymoo/algorithms/soo/nonconvex/optuna.py +80 -0
  39. pymoo/algorithms/soo/nonconvex/pattern.py +183 -0
  40. pymoo/algorithms/soo/nonconvex/pso.py +399 -0
  41. pymoo/algorithms/soo/nonconvex/pso_ep.py +297 -0
  42. pymoo/algorithms/soo/nonconvex/random_search.py +25 -0
  43. pymoo/algorithms/soo/nonconvex/sres.py +56 -0
  44. pymoo/algorithms/soo/univariate/__init__.py +0 -0
  45. pymoo/algorithms/soo/univariate/backtracking.py +59 -0
  46. pymoo/algorithms/soo/univariate/exp.py +46 -0
  47. pymoo/algorithms/soo/univariate/golden.py +65 -0
  48. pymoo/algorithms/soo/univariate/quadr_interp.py +81 -0
  49. pymoo/algorithms/soo/univariate/wolfe.py +163 -0
  50. pymoo/config.py +33 -0
  51. pymoo/constraints/__init__.py +3 -0
  52. pymoo/constraints/adaptive.py +62 -0
  53. pymoo/constraints/as_obj.py +56 -0
  54. pymoo/constraints/as_penalty.py +41 -0
  55. pymoo/constraints/eps.py +26 -0
  56. pymoo/constraints/from_bounds.py +36 -0
  57. pymoo/core/__init__.py +0 -0
  58. pymoo/core/algorithm.py +394 -0
  59. pymoo/core/callback.py +38 -0
  60. pymoo/core/crossover.py +77 -0
  61. pymoo/core/decision_making.py +102 -0
  62. pymoo/core/decomposition.py +76 -0
  63. pymoo/core/duplicate.py +163 -0
  64. pymoo/core/evaluator.py +116 -0
  65. pymoo/core/indicator.py +34 -0
  66. pymoo/core/individual.py +783 -0
  67. pymoo/core/infill.py +64 -0
  68. pymoo/core/initialization.py +42 -0
  69. pymoo/core/mating.py +39 -0
  70. pymoo/core/meta.py +21 -0
  71. pymoo/core/mixed.py +165 -0
  72. pymoo/core/mutation.py +44 -0
  73. pymoo/core/operator.py +40 -0
  74. pymoo/core/parameters.py +134 -0
  75. pymoo/core/plot.py +210 -0
  76. pymoo/core/population.py +180 -0
  77. pymoo/core/problem.py +460 -0
  78. pymoo/core/recorder.py +99 -0
  79. pymoo/core/repair.py +23 -0
  80. pymoo/core/replacement.py +96 -0
  81. pymoo/core/result.py +52 -0
  82. pymoo/core/sampling.py +43 -0
  83. pymoo/core/selection.py +61 -0
  84. pymoo/core/solution.py +10 -0
  85. pymoo/core/survival.py +103 -0
  86. pymoo/core/termination.py +70 -0
  87. pymoo/core/variable.py +399 -0
  88. pymoo/cython/__init__.py +0 -0
  89. pymoo/cython/calc_perpendicular_distance.cpython-39-darwin.so +0 -0
  90. pymoo/cython/decomposition.cpython-39-darwin.so +0 -0
  91. pymoo/cython/hv.cpython-39-darwin.so +0 -0
  92. pymoo/cython/info.cpython-39-darwin.so +0 -0
  93. pymoo/cython/mnn.cpython-39-darwin.so +0 -0
  94. pymoo/cython/non_dominated_sorting.cpython-39-darwin.so +0 -0
  95. pymoo/cython/pruning_cd.cpython-39-darwin.so +0 -0
  96. pymoo/cython/stochastic_ranking.cpython-39-darwin.so +0 -0
  97. pymoo/cython/utils.pxd +129 -0
  98. pymoo/cython/vendor/__init__.py +0 -0
  99. pymoo/cython/vendor/hypervolume.h +63 -0
  100. pymoo/decomposition/__init__.py +0 -0
  101. pymoo/decomposition/aasf.py +24 -0
  102. pymoo/decomposition/asf.py +10 -0
  103. pymoo/decomposition/pbi.py +13 -0
  104. pymoo/decomposition/perp_dist.py +13 -0
  105. pymoo/decomposition/tchebicheff.py +11 -0
  106. pymoo/decomposition/util.py +13 -0
  107. pymoo/decomposition/weighted_sum.py +8 -0
  108. pymoo/docs.py +187 -0
  109. pymoo/experimental/__init__.py +0 -0
  110. pymoo/experimental/algorithms/__init__.py +0 -0
  111. pymoo/experimental/algorithms/gde3.py +57 -0
  112. pymoo/gradient/__init__.py +21 -0
  113. pymoo/gradient/automatic.py +57 -0
  114. pymoo/gradient/grad_autograd.py +105 -0
  115. pymoo/gradient/grad_complex.py +35 -0
  116. pymoo/gradient/grad_jax.py +51 -0
  117. pymoo/gradient/toolbox/__init__.py +6 -0
  118. pymoo/indicators/__init__.py +0 -0
  119. pymoo/indicators/distance_indicator.py +55 -0
  120. pymoo/indicators/gd.py +7 -0
  121. pymoo/indicators/gd_plus.py +7 -0
  122. pymoo/indicators/hv/__init__.py +63 -0
  123. pymoo/indicators/hv/exact.py +71 -0
  124. pymoo/indicators/hv/exact_2d.py +102 -0
  125. pymoo/indicators/hv/monte_carlo.py +74 -0
  126. pymoo/indicators/igd.py +7 -0
  127. pymoo/indicators/igd_plus.py +7 -0
  128. pymoo/indicators/kktpm.py +151 -0
  129. pymoo/indicators/migd.py +55 -0
  130. pymoo/indicators/rmetric.py +203 -0
  131. pymoo/indicators/spacing.py +52 -0
  132. pymoo/mcdm/__init__.py +0 -0
  133. pymoo/mcdm/compromise_programming.py +19 -0
  134. pymoo/mcdm/high_tradeoff.py +40 -0
  135. pymoo/mcdm/pseudo_weights.py +32 -0
  136. pymoo/operators/__init__.py +0 -0
  137. pymoo/operators/control.py +187 -0
  138. pymoo/operators/crossover/__init__.py +0 -0
  139. pymoo/operators/crossover/binx.py +45 -0
  140. pymoo/operators/crossover/dex.py +122 -0
  141. pymoo/operators/crossover/erx.py +162 -0
  142. pymoo/operators/crossover/expx.py +51 -0
  143. pymoo/operators/crossover/hux.py +37 -0
  144. pymoo/operators/crossover/nox.py +13 -0
  145. pymoo/operators/crossover/ox.py +84 -0
  146. pymoo/operators/crossover/pcx.py +82 -0
  147. pymoo/operators/crossover/pntx.py +49 -0
  148. pymoo/operators/crossover/sbx.py +125 -0
  149. pymoo/operators/crossover/spx.py +5 -0
  150. pymoo/operators/crossover/ux.py +20 -0
  151. pymoo/operators/mutation/__init__.py +0 -0
  152. pymoo/operators/mutation/bitflip.py +17 -0
  153. pymoo/operators/mutation/gauss.py +58 -0
  154. pymoo/operators/mutation/inversion.py +42 -0
  155. pymoo/operators/mutation/nom.py +7 -0
  156. pymoo/operators/mutation/pm.py +94 -0
  157. pymoo/operators/mutation/rm.py +23 -0
  158. pymoo/operators/repair/__init__.py +0 -0
  159. pymoo/operators/repair/bounce_back.py +32 -0
  160. pymoo/operators/repair/bounds_repair.py +95 -0
  161. pymoo/operators/repair/inverse_penalty.py +89 -0
  162. pymoo/operators/repair/rounding.py +18 -0
  163. pymoo/operators/repair/to_bound.py +31 -0
  164. pymoo/operators/repair/vtype.py +11 -0
  165. pymoo/operators/sampling/__init__.py +0 -0
  166. pymoo/operators/sampling/lhs.py +73 -0
  167. pymoo/operators/sampling/rnd.py +50 -0
  168. pymoo/operators/selection/__init__.py +0 -0
  169. pymoo/operators/selection/rnd.py +72 -0
  170. pymoo/operators/selection/tournament.py +76 -0
  171. pymoo/operators/survival/__init__.py +0 -0
  172. pymoo/operators/survival/rank_and_crowding/__init__.py +1 -0
  173. pymoo/operators/survival/rank_and_crowding/classes.py +209 -0
  174. pymoo/operators/survival/rank_and_crowding/metrics.py +208 -0
  175. pymoo/optimize.py +72 -0
  176. pymoo/problems/__init__.py +157 -0
  177. pymoo/problems/dyn.py +47 -0
  178. pymoo/problems/dynamic/__init__.py +0 -0
  179. pymoo/problems/dynamic/cec2015.py +108 -0
  180. pymoo/problems/dynamic/df.py +452 -0
  181. pymoo/problems/dynamic/misc.py +167 -0
  182. pymoo/problems/functional.py +48 -0
  183. pymoo/problems/many/__init__.py +5 -0
  184. pymoo/problems/many/cdtlz.py +159 -0
  185. pymoo/problems/many/dcdtlz.py +88 -0
  186. pymoo/problems/many/dtlz.py +264 -0
  187. pymoo/problems/many/wfg.py +550 -0
  188. pymoo/problems/multi/__init__.py +14 -0
  189. pymoo/problems/multi/bnh.py +34 -0
  190. pymoo/problems/multi/carside.py +48 -0
  191. pymoo/problems/multi/clutch.py +104 -0
  192. pymoo/problems/multi/csi.py +55 -0
  193. pymoo/problems/multi/ctp.py +198 -0
  194. pymoo/problems/multi/dascmop.py +213 -0
  195. pymoo/problems/multi/kursawe.py +25 -0
  196. pymoo/problems/multi/modact.py +68 -0
  197. pymoo/problems/multi/mw.py +400 -0
  198. pymoo/problems/multi/omnitest.py +48 -0
  199. pymoo/problems/multi/osy.py +32 -0
  200. pymoo/problems/multi/srn.py +28 -0
  201. pymoo/problems/multi/sympart.py +94 -0
  202. pymoo/problems/multi/tnk.py +24 -0
  203. pymoo/problems/multi/truss2d.py +83 -0
  204. pymoo/problems/multi/welded_beam.py +41 -0
  205. pymoo/problems/multi/wrm.py +36 -0
  206. pymoo/problems/multi/zdt.py +151 -0
  207. pymoo/problems/multi_to_single.py +22 -0
  208. pymoo/problems/single/__init__.py +12 -0
  209. pymoo/problems/single/ackley.py +24 -0
  210. pymoo/problems/single/cantilevered_beam.py +34 -0
  211. pymoo/problems/single/flowshop_scheduling.py +112 -0
  212. pymoo/problems/single/g.py +874 -0
  213. pymoo/problems/single/griewank.py +18 -0
  214. pymoo/problems/single/himmelblau.py +15 -0
  215. pymoo/problems/single/knapsack.py +48 -0
  216. pymoo/problems/single/mopta08.py +26 -0
  217. pymoo/problems/single/multimodal.py +20 -0
  218. pymoo/problems/single/pressure_vessel.py +30 -0
  219. pymoo/problems/single/rastrigin.py +20 -0
  220. pymoo/problems/single/rosenbrock.py +22 -0
  221. pymoo/problems/single/schwefel.py +18 -0
  222. pymoo/problems/single/simple.py +13 -0
  223. pymoo/problems/single/sphere.py +19 -0
  224. pymoo/problems/single/traveling_salesman.py +79 -0
  225. pymoo/problems/single/zakharov.py +19 -0
  226. pymoo/problems/static.py +14 -0
  227. pymoo/problems/util.py +42 -0
  228. pymoo/problems/zero_to_one.py +27 -0
  229. pymoo/termination/__init__.py +23 -0
  230. pymoo/termination/collection.py +12 -0
  231. pymoo/termination/cv.py +48 -0
  232. pymoo/termination/default.py +45 -0
  233. pymoo/termination/delta.py +64 -0
  234. pymoo/termination/fmin.py +16 -0
  235. pymoo/termination/ftol.py +144 -0
  236. pymoo/termination/indicator.py +49 -0
  237. pymoo/termination/max_eval.py +14 -0
  238. pymoo/termination/max_gen.py +15 -0
  239. pymoo/termination/max_time.py +20 -0
  240. pymoo/termination/robust.py +34 -0
  241. pymoo/termination/xtol.py +33 -0
  242. pymoo/util/__init__.py +0 -0
  243. pymoo/util/archive.py +150 -0
  244. pymoo/util/cache.py +29 -0
  245. pymoo/util/clearing.py +82 -0
  246. pymoo/util/display/__init__.py +0 -0
  247. pymoo/util/display/column.py +52 -0
  248. pymoo/util/display/display.py +34 -0
  249. pymoo/util/display/multi.py +96 -0
  250. pymoo/util/display/output.py +53 -0
  251. pymoo/util/display/progress.py +54 -0
  252. pymoo/util/display/single.py +67 -0
  253. pymoo/util/dominator.py +67 -0
  254. pymoo/util/function_loader.py +129 -0
  255. pymoo/util/hv.py +23 -0
  256. pymoo/util/matlab_engine.py +39 -0
  257. pymoo/util/misc.py +460 -0
  258. pymoo/util/mnn.py +70 -0
  259. pymoo/util/nds/__init__.py +0 -0
  260. pymoo/util/nds/dominance_degree_non_dominated_sort.py +159 -0
  261. pymoo/util/nds/efficient_non_dominated_sort.py +152 -0
  262. pymoo/util/nds/fast_non_dominated_sort.py +68 -0
  263. pymoo/util/nds/naive_non_dominated_sort.py +36 -0
  264. pymoo/util/nds/non_dominated_sorting.py +67 -0
  265. pymoo/util/nds/tree_based_non_dominated_sort.py +133 -0
  266. pymoo/util/normalization.py +315 -0
  267. pymoo/util/optimum.py +42 -0
  268. pymoo/util/plotting.py +177 -0
  269. pymoo/util/pruning_cd.py +89 -0
  270. pymoo/util/randomized_argsort.py +60 -0
  271. pymoo/util/ref_dirs/__init__.py +24 -0
  272. pymoo/util/ref_dirs/construction.py +88 -0
  273. pymoo/util/ref_dirs/das_dennis.py +52 -0
  274. pymoo/util/ref_dirs/energy.py +317 -0
  275. pymoo/util/ref_dirs/energy_layer.py +119 -0
  276. pymoo/util/ref_dirs/genetic_algorithm.py +63 -0
  277. pymoo/util/ref_dirs/incremental.py +68 -0
  278. pymoo/util/ref_dirs/misc.py +128 -0
  279. pymoo/util/ref_dirs/optimizer.py +59 -0
  280. pymoo/util/ref_dirs/performance.py +162 -0
  281. pymoo/util/ref_dirs/reduction.py +85 -0
  282. pymoo/util/ref_dirs/sample_and_map.py +24 -0
  283. pymoo/util/reference_direction.py +259 -0
  284. pymoo/util/remote.py +55 -0
  285. pymoo/util/roulette.py +27 -0
  286. pymoo/util/running_metric.py +128 -0
  287. pymoo/util/sliding_window.py +25 -0
  288. pymoo/util/stochastic_ranking.py +32 -0
  289. pymoo/util/vectors.py +40 -0
  290. pymoo/vendor/__init__.py +0 -0
  291. pymoo/vendor/cec2018.py +398 -0
  292. pymoo/vendor/gta.py +617 -0
  293. pymoo/vendor/hv.py +267 -0
  294. pymoo/vendor/vendor_cmaes.py +412 -0
  295. pymoo/vendor/vendor_coco.py +81 -0
  296. pymoo/vendor/vendor_scipy.py +232 -0
  297. pymoo/version.py +1 -0
  298. pymoo/visualization/__init__.py +8 -0
  299. pymoo/visualization/fitness_landscape.py +127 -0
  300. pymoo/visualization/heatmap.py +123 -0
  301. pymoo/visualization/pcp.py +120 -0
  302. pymoo/visualization/petal.py +91 -0
  303. pymoo/visualization/radar.py +108 -0
  304. pymoo/visualization/radviz.py +68 -0
  305. pymoo/visualization/scatter.py +150 -0
  306. pymoo/visualization/star_coordinate.py +75 -0
  307. pymoo/visualization/util.py +123 -0
  308. pymoo/visualization/video/__init__.py +0 -0
  309. pymoo/visualization/video/callback_video.py +82 -0
  310. pymoo/visualization/video/one_var_one_obj.py +57 -0
  311. pymoo/visualization/video/two_var_one_obj.py +62 -0
  312. pymoo-0.6.1.3.dist-info/LICENSE +191 -0
  313. pymoo-0.6.1.3.dist-info/METADATA +188 -0
  314. pymoo-0.6.1.3.dist-info/RECORD +316 -0
  315. pymoo-0.6.1.3.dist-info/WHEEL +5 -0
  316. pymoo-0.6.1.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,304 @@
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
+ distances = self.pairwise_distances(front, p) / (nn[:, None])
171
+
172
+ neighbors = 2
173
+ remaining = np.arange(m)
174
+ remaining = list(remaining[~selected])
175
+ for i in range(m - np.sum(selected)):
176
+ mg = np.meshgrid(np.arange(selected.shape[0])[selected], remaining, copy=False, sparse=False)
177
+ D_mg = distances[tuple(mg)] # avoid Numpy's future deprecation of array special indexing
178
+
179
+ if D_mg.shape[1] > 1:
180
+ # equivalent to mink(distances(remaining, selected),neighbors,2); in Matlab
181
+ maxim = np.argpartition(D_mg, neighbors - 1, axis=1)[:, :neighbors]
182
+ tmp = np.sum(np.take_along_axis(D_mg, maxim, axis=1), axis=1)
183
+ index: int = np.argmax(tmp)
184
+ d = tmp[index]
185
+ else:
186
+ index = D_mg[:, 0].argmax()
187
+ d = D_mg[index, 0]
188
+
189
+ best = remaining.pop(index)
190
+ selected[best] = True
191
+ crowd_dist[best] = d
192
+
193
+ return crowd_dist, p, normalization
194
+
195
+ @staticmethod
196
+ def compute_geometry(front, extreme, n):
197
+ # approximate p(norm)
198
+ d = point_2_line_distance(front, np.zeros(n), np.ones(n))
199
+ d[extreme] = np.inf
200
+ index = np.argmin(d)
201
+
202
+ p = np.log(n) / np.log(1.0 / np.mean(front[index, :]))
203
+
204
+ if np.isnan(p) or p <= 0.1:
205
+ p = 1.0
206
+ elif p > 20:
207
+ p = 20.0 # avoid numpy underflow
208
+
209
+ return p
210
+
211
+ @staticmethod
212
+ @jit(fastmath=True)
213
+ def pairwise_distances(front, p):
214
+ m = np.shape(front)[0]
215
+ distances = np.zeros((m, m))
216
+ for i in range(m):
217
+ distances[i] = np.sum(np.abs(front[i] - front) ** p, 1) ** (1 / p)
218
+
219
+ return distances
220
+
221
+ @staticmethod
222
+ @jit(fastmath=True)
223
+ def minkowski_distances(A, B, p):
224
+ m1 = np.shape(A)[0]
225
+ m2 = np.shape(B)[0]
226
+ distances = np.zeros((m1, m2))
227
+ for i in range(m1):
228
+ for j in range(m2):
229
+ distances[i][j] = sum(np.abs(A[i] - B[j]) ** p) ** (1 / p)
230
+
231
+ return distances
232
+
233
+
234
+ @jit(nopython=True, fastmath=True)
235
+ def find_corner_solutions(front):
236
+ """Return the indexes of the extreme points"""
237
+
238
+ m, n = front.shape
239
+
240
+ if m <= n:
241
+ return np.arange(m)
242
+
243
+ # let's define the axes of the n-dimensional spaces
244
+ W = 1e-6 + np.eye(n)
245
+ r = W.shape[0]
246
+ indexes = np.zeros(n, dtype=numba.intp)
247
+ selected = np.zeros(m, dtype=numba.boolean)
248
+ for i in range(r):
249
+ dists = point_2_line_distance(front, np.zeros(n), W[i, :])
250
+ dists[selected] = np.inf # prevent already selected to be reselected
251
+ index = np.argmin(dists)
252
+ indexes[i] = index
253
+ selected[index] = True
254
+ return indexes
255
+
256
+
257
+ @jit(fastmath=True)
258
+ def point_2_line_distance(P, A, B):
259
+ d = np.zeros(P.shape[0])
260
+
261
+ for i in range(P.shape[0]):
262
+ pa = P[i] - A
263
+ ba = B - A
264
+ t = np.dot(pa, ba) / np.dot(ba, ba)
265
+ d[i] = sum((pa - t * ba) ** 2)
266
+
267
+ return d
268
+
269
+
270
+ # =========================================================================================================
271
+ # Normalization
272
+ # =========================================================================================================
273
+
274
+ def normalize(front, extreme):
275
+ m, n = front.shape
276
+
277
+ if len(extreme) != len(np.unique(extreme, axis=0)):
278
+ normalization = np.max(front, axis=0)
279
+ front = front / normalization
280
+ return front, normalization
281
+
282
+ # Calculate the intercepts of the hyperplane constructed by the extreme
283
+ # points and the axes
284
+
285
+ try:
286
+ hyperplane = np.linalg.solve(front[extreme], np.ones(n))
287
+ if any(np.isnan(hyperplane)) or any(np.isinf(hyperplane)) or any(hyperplane <= 0):
288
+ normalization = np.max(front, axis=0)
289
+ else:
290
+ normalization = 1. / hyperplane
291
+ if any(np.isnan(normalization)) or any(np.isinf(normalization)):
292
+ normalization = np.max(front, axis=0)
293
+ except np.linalg.LinAlgError:
294
+ normalization = np.max(front, axis=0)
295
+
296
+ normalization[normalization == 0.0] = 1.0
297
+
298
+ # Normalization
299
+ front = front / normalization
300
+
301
+ return front, normalization
302
+
303
+
304
+ parse_doc_string(AGEMOEA.__init__)
@@ -0,0 +1,164 @@
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(fastmath=True)
68
+ def project_on_manifold(point, p):
69
+ dist = sum(point[point > 0] ** p) ** (1/p)
70
+ return np.multiply(point, 1 / dist)
71
+
72
+
73
+ def find_zero(point, n, precision):
74
+ x = 1
75
+
76
+ past_value = x
77
+ for i in range(0, 100):
78
+
79
+ # Original function
80
+ f = 0.0
81
+ for obj_index in range(0, n):
82
+ if point[obj_index] > 0:
83
+ f += np.power(point[obj_index], x)
84
+
85
+ f = np.log(f)
86
+
87
+ # Derivative
88
+ numerator = 0
89
+ denominator = 0
90
+ for obj_index in range(0, n):
91
+ if point[obj_index] > 0:
92
+ numerator = numerator + np.power(point[obj_index], x) * np.log(point[obj_index])
93
+ denominator = denominator + np.power(point[obj_index], x)
94
+
95
+ if denominator == 0:
96
+ return 1
97
+
98
+ ff = numerator / denominator
99
+
100
+ # zero of function
101
+ x = x - f / ff
102
+
103
+ if abs(x - past_value) <= precision:
104
+ break
105
+ else:
106
+ paste_value = x # update current point
107
+
108
+ if isinstance(x, complex):
109
+ return 1
110
+ else:
111
+ return x
112
+
113
+
114
+ class AGEMOEA2Survival(AGEMOEASurvival):
115
+
116
+ @staticmethod
117
+ def compute_geometry(front, extreme, n):
118
+ m, _ = np.shape(front)
119
+
120
+ # approximate p(norm)
121
+ d = np.zeros(m)
122
+ for i in range(0, m):
123
+ d[i] = sum(front[i] ** 2) ** 0.5
124
+
125
+ d[extreme] = np.inf
126
+ index = np.argmin(d)
127
+
128
+ p = find_zero(front[index], n, 0.001)
129
+
130
+ if np.isnan(p) or p <= 0.1:
131
+ p = 1.0
132
+ elif p > 20:
133
+ p = 20.0 # avoid numpy underflow
134
+
135
+ return p
136
+
137
+ @staticmethod
138
+ @jit(fastmath=True)
139
+ def pairwise_distances(front, p):
140
+ m, n = front.shape
141
+ projected_front = front.copy()
142
+
143
+ for index in range(0, m):
144
+ projected_front[index] = project_on_manifold(front[index], p=p)
145
+
146
+ distances = np.zeros((m, m), dtype=numba.float64)
147
+
148
+ if 0.95 < p < 1.05:
149
+ for row in range(0, m - 1):
150
+ for column in range(row + 1, m):
151
+ distances[row][column] = sum(np.abs(projected_front[row] - projected_front[column]) ** 2) ** 0.5
152
+
153
+ else:
154
+ for row in range(0, m-1):
155
+ for column in range(row+1, m):
156
+ mid_point = projected_front[row] * 0.5 + projected_front[column] * 0.5
157
+ mid_point = project_on_manifold(mid_point, p)
158
+
159
+ distances[row][column] = sum(np.abs(projected_front[row] - mid_point) ** 2) ** 0.5 + \
160
+ sum(np.abs(projected_front[column] - mid_point) ** 2) ** 0.5
161
+
162
+ return distances + distances.T
163
+
164
+ parse_doc_string(AGEMOEA2.__init__)