pymoo 0.6.1.5.dev0__cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pymoo might be problematic. Click here for more details.

Files changed (328) 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 +310 -0
  12. pymoo/algorithms/moo/age2.py +194 -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/pinsga2.py +370 -0
  20. pymoo/algorithms/moo/rnsga2.py +188 -0
  21. pymoo/algorithms/moo/rnsga3.py +246 -0
  22. pymoo/algorithms/moo/rvea.py +214 -0
  23. pymoo/algorithms/moo/sms.py +195 -0
  24. pymoo/algorithms/moo/spea2.py +190 -0
  25. pymoo/algorithms/moo/unsga3.py +47 -0
  26. pymoo/algorithms/soo/__init__.py +0 -0
  27. pymoo/algorithms/soo/convex/__init__.py +0 -0
  28. pymoo/algorithms/soo/nonconvex/__init__.py +0 -0
  29. pymoo/algorithms/soo/nonconvex/brkga.py +161 -0
  30. pymoo/algorithms/soo/nonconvex/cmaes.py +554 -0
  31. pymoo/algorithms/soo/nonconvex/de.py +279 -0
  32. pymoo/algorithms/soo/nonconvex/direct.py +149 -0
  33. pymoo/algorithms/soo/nonconvex/es.py +203 -0
  34. pymoo/algorithms/soo/nonconvex/g3pcx.py +94 -0
  35. pymoo/algorithms/soo/nonconvex/ga.py +93 -0
  36. pymoo/algorithms/soo/nonconvex/ga_niching.py +223 -0
  37. pymoo/algorithms/soo/nonconvex/isres.py +74 -0
  38. pymoo/algorithms/soo/nonconvex/nelder.py +251 -0
  39. pymoo/algorithms/soo/nonconvex/optuna.py +80 -0
  40. pymoo/algorithms/soo/nonconvex/pattern.py +183 -0
  41. pymoo/algorithms/soo/nonconvex/pso.py +399 -0
  42. pymoo/algorithms/soo/nonconvex/pso_ep.py +297 -0
  43. pymoo/algorithms/soo/nonconvex/random_search.py +25 -0
  44. pymoo/algorithms/soo/nonconvex/sres.py +56 -0
  45. pymoo/algorithms/soo/univariate/__init__.py +0 -0
  46. pymoo/algorithms/soo/univariate/backtracking.py +59 -0
  47. pymoo/algorithms/soo/univariate/exp.py +46 -0
  48. pymoo/algorithms/soo/univariate/golden.py +65 -0
  49. pymoo/algorithms/soo/univariate/quadr_interp.py +81 -0
  50. pymoo/algorithms/soo/univariate/wolfe.py +163 -0
  51. pymoo/config.py +33 -0
  52. pymoo/constraints/__init__.py +3 -0
  53. pymoo/constraints/adaptive.py +62 -0
  54. pymoo/constraints/as_obj.py +56 -0
  55. pymoo/constraints/as_penalty.py +41 -0
  56. pymoo/constraints/eps.py +26 -0
  57. pymoo/constraints/from_bounds.py +36 -0
  58. pymoo/core/__init__.py +0 -0
  59. pymoo/core/algorithm.py +394 -0
  60. pymoo/core/callback.py +38 -0
  61. pymoo/core/crossover.py +77 -0
  62. pymoo/core/decision_making.py +102 -0
  63. pymoo/core/decomposition.py +76 -0
  64. pymoo/core/duplicate.py +163 -0
  65. pymoo/core/evaluator.py +116 -0
  66. pymoo/core/indicator.py +34 -0
  67. pymoo/core/individual.py +784 -0
  68. pymoo/core/infill.py +64 -0
  69. pymoo/core/initialization.py +42 -0
  70. pymoo/core/mating.py +39 -0
  71. pymoo/core/meta.py +21 -0
  72. pymoo/core/mixed.py +165 -0
  73. pymoo/core/mutation.py +44 -0
  74. pymoo/core/operator.py +40 -0
  75. pymoo/core/parameters.py +134 -0
  76. pymoo/core/plot.py +210 -0
  77. pymoo/core/population.py +180 -0
  78. pymoo/core/problem.py +460 -0
  79. pymoo/core/recorder.py +99 -0
  80. pymoo/core/repair.py +23 -0
  81. pymoo/core/replacement.py +96 -0
  82. pymoo/core/result.py +52 -0
  83. pymoo/core/sampling.py +43 -0
  84. pymoo/core/selection.py +61 -0
  85. pymoo/core/solution.py +10 -0
  86. pymoo/core/survival.py +103 -0
  87. pymoo/core/termination.py +70 -0
  88. pymoo/core/variable.py +399 -0
  89. pymoo/cython/__init__.py +0 -0
  90. pymoo/cython/calc_perpendicular_distance.cpython-312-x86_64-linux-gnu.so +0 -0
  91. pymoo/cython/calc_perpendicular_distance.pyx +67 -0
  92. pymoo/cython/decomposition.cpython-312-x86_64-linux-gnu.so +0 -0
  93. pymoo/cython/decomposition.pyx +165 -0
  94. pymoo/cython/hv.cpython-312-x86_64-linux-gnu.so +0 -0
  95. pymoo/cython/hv.pyx +18 -0
  96. pymoo/cython/info.cpython-312-x86_64-linux-gnu.so +0 -0
  97. pymoo/cython/info.pyx +5 -0
  98. pymoo/cython/mnn.cpython-312-x86_64-linux-gnu.so +0 -0
  99. pymoo/cython/mnn.pyx +273 -0
  100. pymoo/cython/non_dominated_sorting.cpython-312-x86_64-linux-gnu.so +0 -0
  101. pymoo/cython/non_dominated_sorting.pyx +645 -0
  102. pymoo/cython/pruning_cd.cpython-312-x86_64-linux-gnu.so +0 -0
  103. pymoo/cython/pruning_cd.pyx +197 -0
  104. pymoo/cython/stochastic_ranking.cpython-312-x86_64-linux-gnu.so +0 -0
  105. pymoo/cython/stochastic_ranking.pyx +49 -0
  106. pymoo/cython/utils.pxd +129 -0
  107. pymoo/cython/vendor/__init__.py +0 -0
  108. pymoo/cython/vendor/hypervolume.cpp +1621 -0
  109. pymoo/cython/vendor/hypervolume.h +63 -0
  110. pymoo/decomposition/__init__.py +0 -0
  111. pymoo/decomposition/aasf.py +24 -0
  112. pymoo/decomposition/asf.py +10 -0
  113. pymoo/decomposition/pbi.py +13 -0
  114. pymoo/decomposition/perp_dist.py +13 -0
  115. pymoo/decomposition/tchebicheff.py +11 -0
  116. pymoo/decomposition/util.py +13 -0
  117. pymoo/decomposition/weighted_sum.py +8 -0
  118. pymoo/docs.py +187 -0
  119. pymoo/experimental/__init__.py +0 -0
  120. pymoo/experimental/algorithms/__init__.py +0 -0
  121. pymoo/experimental/algorithms/gde3.py +57 -0
  122. pymoo/gradient/__init__.py +21 -0
  123. pymoo/gradient/automatic.py +57 -0
  124. pymoo/gradient/grad_autograd.py +105 -0
  125. pymoo/gradient/grad_complex.py +35 -0
  126. pymoo/gradient/grad_jax.py +51 -0
  127. pymoo/gradient/toolbox/__init__.py +6 -0
  128. pymoo/indicators/__init__.py +0 -0
  129. pymoo/indicators/distance_indicator.py +55 -0
  130. pymoo/indicators/gd.py +7 -0
  131. pymoo/indicators/gd_plus.py +7 -0
  132. pymoo/indicators/hv/__init__.py +63 -0
  133. pymoo/indicators/hv/exact.py +71 -0
  134. pymoo/indicators/hv/exact_2d.py +102 -0
  135. pymoo/indicators/hv/monte_carlo.py +74 -0
  136. pymoo/indicators/igd.py +7 -0
  137. pymoo/indicators/igd_plus.py +7 -0
  138. pymoo/indicators/kktpm.py +151 -0
  139. pymoo/indicators/migd.py +55 -0
  140. pymoo/indicators/rmetric.py +203 -0
  141. pymoo/indicators/spacing.py +52 -0
  142. pymoo/mcdm/__init__.py +0 -0
  143. pymoo/mcdm/compromise_programming.py +19 -0
  144. pymoo/mcdm/high_tradeoff.py +40 -0
  145. pymoo/mcdm/pseudo_weights.py +32 -0
  146. pymoo/operators/__init__.py +0 -0
  147. pymoo/operators/control.py +187 -0
  148. pymoo/operators/crossover/__init__.py +0 -0
  149. pymoo/operators/crossover/binx.py +45 -0
  150. pymoo/operators/crossover/dex.py +122 -0
  151. pymoo/operators/crossover/erx.py +162 -0
  152. pymoo/operators/crossover/expx.py +51 -0
  153. pymoo/operators/crossover/hux.py +37 -0
  154. pymoo/operators/crossover/nox.py +13 -0
  155. pymoo/operators/crossover/ox.py +84 -0
  156. pymoo/operators/crossover/pcx.py +82 -0
  157. pymoo/operators/crossover/pntx.py +49 -0
  158. pymoo/operators/crossover/sbx.py +125 -0
  159. pymoo/operators/crossover/spx.py +5 -0
  160. pymoo/operators/crossover/ux.py +20 -0
  161. pymoo/operators/mutation/__init__.py +0 -0
  162. pymoo/operators/mutation/bitflip.py +17 -0
  163. pymoo/operators/mutation/gauss.py +58 -0
  164. pymoo/operators/mutation/inversion.py +42 -0
  165. pymoo/operators/mutation/nom.py +7 -0
  166. pymoo/operators/mutation/pm.py +94 -0
  167. pymoo/operators/mutation/rm.py +23 -0
  168. pymoo/operators/repair/__init__.py +0 -0
  169. pymoo/operators/repair/bounce_back.py +32 -0
  170. pymoo/operators/repair/bounds_repair.py +95 -0
  171. pymoo/operators/repair/inverse_penalty.py +89 -0
  172. pymoo/operators/repair/rounding.py +18 -0
  173. pymoo/operators/repair/to_bound.py +31 -0
  174. pymoo/operators/repair/vtype.py +11 -0
  175. pymoo/operators/sampling/__init__.py +0 -0
  176. pymoo/operators/sampling/lhs.py +73 -0
  177. pymoo/operators/sampling/rnd.py +50 -0
  178. pymoo/operators/selection/__init__.py +0 -0
  179. pymoo/operators/selection/rnd.py +72 -0
  180. pymoo/operators/selection/tournament.py +76 -0
  181. pymoo/operators/survival/__init__.py +0 -0
  182. pymoo/operators/survival/rank_and_crowding/__init__.py +1 -0
  183. pymoo/operators/survival/rank_and_crowding/classes.py +209 -0
  184. pymoo/operators/survival/rank_and_crowding/metrics.py +208 -0
  185. pymoo/optimize.py +72 -0
  186. pymoo/problems/__init__.py +157 -0
  187. pymoo/problems/dyn.py +47 -0
  188. pymoo/problems/dynamic/__init__.py +0 -0
  189. pymoo/problems/dynamic/cec2015.py +108 -0
  190. pymoo/problems/dynamic/df.py +452 -0
  191. pymoo/problems/dynamic/misc.py +167 -0
  192. pymoo/problems/functional.py +48 -0
  193. pymoo/problems/many/__init__.py +5 -0
  194. pymoo/problems/many/cdtlz.py +159 -0
  195. pymoo/problems/many/dcdtlz.py +88 -0
  196. pymoo/problems/many/dtlz.py +264 -0
  197. pymoo/problems/many/wfg.py +550 -0
  198. pymoo/problems/multi/__init__.py +14 -0
  199. pymoo/problems/multi/bnh.py +34 -0
  200. pymoo/problems/multi/carside.py +48 -0
  201. pymoo/problems/multi/clutch.py +104 -0
  202. pymoo/problems/multi/csi.py +55 -0
  203. pymoo/problems/multi/ctp.py +198 -0
  204. pymoo/problems/multi/dascmop.py +213 -0
  205. pymoo/problems/multi/kursawe.py +25 -0
  206. pymoo/problems/multi/modact.py +68 -0
  207. pymoo/problems/multi/mw.py +400 -0
  208. pymoo/problems/multi/omnitest.py +48 -0
  209. pymoo/problems/multi/osy.py +32 -0
  210. pymoo/problems/multi/srn.py +28 -0
  211. pymoo/problems/multi/sympart.py +94 -0
  212. pymoo/problems/multi/tnk.py +24 -0
  213. pymoo/problems/multi/truss2d.py +83 -0
  214. pymoo/problems/multi/welded_beam.py +41 -0
  215. pymoo/problems/multi/wrm.py +36 -0
  216. pymoo/problems/multi/zdt.py +151 -0
  217. pymoo/problems/multi_to_single.py +22 -0
  218. pymoo/problems/single/__init__.py +12 -0
  219. pymoo/problems/single/ackley.py +24 -0
  220. pymoo/problems/single/cantilevered_beam.py +34 -0
  221. pymoo/problems/single/flowshop_scheduling.py +112 -0
  222. pymoo/problems/single/g.py +874 -0
  223. pymoo/problems/single/griewank.py +18 -0
  224. pymoo/problems/single/himmelblau.py +15 -0
  225. pymoo/problems/single/knapsack.py +48 -0
  226. pymoo/problems/single/mopta08.py +26 -0
  227. pymoo/problems/single/multimodal.py +20 -0
  228. pymoo/problems/single/pressure_vessel.py +30 -0
  229. pymoo/problems/single/rastrigin.py +20 -0
  230. pymoo/problems/single/rosenbrock.py +22 -0
  231. pymoo/problems/single/schwefel.py +18 -0
  232. pymoo/problems/single/simple.py +13 -0
  233. pymoo/problems/single/sphere.py +19 -0
  234. pymoo/problems/single/traveling_salesman.py +79 -0
  235. pymoo/problems/single/zakharov.py +19 -0
  236. pymoo/problems/static.py +14 -0
  237. pymoo/problems/util.py +42 -0
  238. pymoo/problems/zero_to_one.py +27 -0
  239. pymoo/termination/__init__.py +23 -0
  240. pymoo/termination/collection.py +12 -0
  241. pymoo/termination/cv.py +48 -0
  242. pymoo/termination/default.py +45 -0
  243. pymoo/termination/delta.py +64 -0
  244. pymoo/termination/fmin.py +16 -0
  245. pymoo/termination/ftol.py +144 -0
  246. pymoo/termination/indicator.py +49 -0
  247. pymoo/termination/max_eval.py +14 -0
  248. pymoo/termination/max_gen.py +15 -0
  249. pymoo/termination/max_time.py +20 -0
  250. pymoo/termination/robust.py +34 -0
  251. pymoo/termination/xtol.py +33 -0
  252. pymoo/util/__init__.py +0 -0
  253. pymoo/util/archive.py +150 -0
  254. pymoo/util/cache.py +29 -0
  255. pymoo/util/clearing.py +82 -0
  256. pymoo/util/display/__init__.py +0 -0
  257. pymoo/util/display/column.py +52 -0
  258. pymoo/util/display/display.py +34 -0
  259. pymoo/util/display/multi.py +96 -0
  260. pymoo/util/display/output.py +53 -0
  261. pymoo/util/display/progress.py +54 -0
  262. pymoo/util/display/single.py +67 -0
  263. pymoo/util/dominator.py +67 -0
  264. pymoo/util/function_loader.py +129 -0
  265. pymoo/util/hv.py +23 -0
  266. pymoo/util/matlab_engine.py +39 -0
  267. pymoo/util/misc.py +460 -0
  268. pymoo/util/mnn.py +70 -0
  269. pymoo/util/nds/__init__.py +0 -0
  270. pymoo/util/nds/dominance_degree_non_dominated_sort.py +159 -0
  271. pymoo/util/nds/efficient_non_dominated_sort.py +152 -0
  272. pymoo/util/nds/fast_non_dominated_sort.py +70 -0
  273. pymoo/util/nds/naive_non_dominated_sort.py +36 -0
  274. pymoo/util/nds/non_dominated_sorting.py +67 -0
  275. pymoo/util/nds/tree_based_non_dominated_sort.py +133 -0
  276. pymoo/util/normalization.py +312 -0
  277. pymoo/util/optimum.py +42 -0
  278. pymoo/util/plotting.py +177 -0
  279. pymoo/util/pruning_cd.py +89 -0
  280. pymoo/util/randomized_argsort.py +60 -0
  281. pymoo/util/ref_dirs/__init__.py +24 -0
  282. pymoo/util/ref_dirs/construction.py +88 -0
  283. pymoo/util/ref_dirs/das_dennis.py +52 -0
  284. pymoo/util/ref_dirs/energy.py +319 -0
  285. pymoo/util/ref_dirs/energy_layer.py +119 -0
  286. pymoo/util/ref_dirs/genetic_algorithm.py +63 -0
  287. pymoo/util/ref_dirs/incremental.py +68 -0
  288. pymoo/util/ref_dirs/misc.py +128 -0
  289. pymoo/util/ref_dirs/optimizer.py +59 -0
  290. pymoo/util/ref_dirs/performance.py +162 -0
  291. pymoo/util/ref_dirs/reduction.py +85 -0
  292. pymoo/util/ref_dirs/sample_and_map.py +24 -0
  293. pymoo/util/reference_direction.py +260 -0
  294. pymoo/util/remote.py +55 -0
  295. pymoo/util/roulette.py +27 -0
  296. pymoo/util/running_metric.py +128 -0
  297. pymoo/util/sliding_window.py +25 -0
  298. pymoo/util/stochastic_ranking.py +32 -0
  299. pymoo/util/value_functions.py +719 -0
  300. pymoo/util/vectors.py +40 -0
  301. pymoo/util/vf_dominator.py +99 -0
  302. pymoo/vendor/__init__.py +0 -0
  303. pymoo/vendor/cec2018.py +398 -0
  304. pymoo/vendor/gta.py +617 -0
  305. pymoo/vendor/hv.py +267 -0
  306. pymoo/vendor/vendor_cmaes.py +412 -0
  307. pymoo/vendor/vendor_coco.py +81 -0
  308. pymoo/vendor/vendor_scipy.py +232 -0
  309. pymoo/version.py +1 -0
  310. pymoo/visualization/__init__.py +8 -0
  311. pymoo/visualization/fitness_landscape.py +127 -0
  312. pymoo/visualization/heatmap.py +123 -0
  313. pymoo/visualization/pcp.py +120 -0
  314. pymoo/visualization/petal.py +91 -0
  315. pymoo/visualization/radar.py +108 -0
  316. pymoo/visualization/radviz.py +68 -0
  317. pymoo/visualization/scatter.py +150 -0
  318. pymoo/visualization/star_coordinate.py +75 -0
  319. pymoo/visualization/util.py +123 -0
  320. pymoo/visualization/video/__init__.py +0 -0
  321. pymoo/visualization/video/callback_video.py +82 -0
  322. pymoo/visualization/video/one_var_one_obj.py +57 -0
  323. pymoo/visualization/video/two_var_one_obj.py +62 -0
  324. pymoo-0.6.1.5.dev0.dist-info/METADATA +187 -0
  325. pymoo-0.6.1.5.dev0.dist-info/RECORD +328 -0
  326. pymoo-0.6.1.5.dev0.dist-info/WHEEL +6 -0
  327. pymoo-0.6.1.5.dev0.dist-info/licenses/LICENSE +191 -0
  328. pymoo-0.6.1.5.dev0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,298 @@
1
+ import math
2
+
3
+ import numpy as np
4
+ from scipy.spatial.distance import cdist, pdist, squareform
5
+
6
+ from pymoo.algorithms.base.genetic import GeneticAlgorithm
7
+ from pymoo.core.population import Population
8
+ from pymoo.decomposition.asf import ASF
9
+ from pymoo.docs import parse_doc_string
10
+ from pymoo.operators.crossover.sbx import SBX
11
+ from pymoo.operators.mutation.pm import PM
12
+ from pymoo.operators.sampling.rnd import FloatRandomSampling
13
+ from pymoo.operators.selection.tournament import TournamentSelection
14
+ from pymoo.util.display.multi import MultiObjectiveOutput
15
+ from pymoo.util.dominator import Dominator
16
+ from pymoo.util.function_loader import load_function
17
+ from pymoo.util.misc import has_feasible, random_permutations
18
+ from pymoo.util.nds.non_dominated_sorting import NonDominatedSorting
19
+
20
+
21
+ # =========================================================================================================
22
+ # Implementation
23
+ # Following original code by K. Li https://cola-laboratory.github.io/codes/CTAEA.zip
24
+ # =========================================================================================================
25
+
26
+
27
+ def comp_by_cv_dom_then_random(pop, P, **kwargs):
28
+ S = np.full(P.shape[0], np.nan)
29
+
30
+ for i in range(P.shape[0]):
31
+ a, b = P[i, 0], P[i, 1]
32
+
33
+ if pop[a].CV <= 0.0 and pop[b].CV <= 0.0:
34
+ rel = Dominator.get_relation(pop[a].F, pop[b].F)
35
+ if rel == 1:
36
+ S[i] = a
37
+ elif rel == -1:
38
+ S[i] = b
39
+ else:
40
+ S[i] = np.random.choice([a, b])
41
+ elif pop[a].CV <= 0.0:
42
+ S[i] = a
43
+ elif pop[b].CV <= 0.0:
44
+ S[i] = b
45
+ else:
46
+ S[i] = np.random.choice([a, b])
47
+
48
+ return S[:, None].astype(int)
49
+
50
+
51
+ class RestrictedMating(TournamentSelection):
52
+ """Restricted mating approach to balance convergence and diversity archives"""
53
+
54
+ def _do(self, problem, Hm, n_select, n_parents, **kwargs):
55
+ n_pop = len(Hm) // 2
56
+
57
+ _, rank = NonDominatedSorting().do(Hm.get('F'), return_rank=True)
58
+
59
+ Pc = (rank[:n_pop] == 0).sum() / len(Hm)
60
+ Pd = (rank[n_pop:] == 0).sum() / len(Hm)
61
+
62
+ # number of random individuals needed
63
+ n_random = n_select * n_parents * self.pressure
64
+ n_perms = math.ceil(n_random / n_pop)
65
+ # get random permutations and reshape them
66
+ P = random_permutations(n_perms, n_pop)[:n_random]
67
+ P = np.reshape(P, (n_select * n_parents, self.pressure))
68
+ if Pc <= Pd:
69
+ # Choose from DA
70
+ P[::n_parents, :] += n_pop
71
+ pf = np.random.random(n_select)
72
+ P[1::n_parents, :][pf >= Pc] += n_pop
73
+
74
+ # compare using tournament function
75
+ S = self.func_comp(Hm, P, **kwargs)
76
+
77
+ return np.reshape(S, (n_select, n_parents))
78
+
79
+
80
+ class CADASurvival:
81
+
82
+ def __init__(self, ref_dirs):
83
+ self.ref_dirs = ref_dirs
84
+ self.opt = None
85
+ self.ideal_point = np.full(ref_dirs.shape[1], np.inf)
86
+ self._decomposition = ASF()
87
+ self._calc_perpendicular_distance = load_function("calc_perpendicular_distance")
88
+
89
+ def do(self, _, pop, da, n_survive=None, **kwargs):
90
+ # Offspring are last of merged population
91
+ off = pop[-n_survive:]
92
+ # Update ideal point
93
+ self.ideal_point = np.min(np.vstack((self.ideal_point, off.get("F"))), axis=0)
94
+ # Update CA
95
+ pop = self._updateCA(pop, n_survive)
96
+ # Update DA
97
+ Hd = Population.merge(da, off)
98
+ da = self._updateDA(pop, Hd, n_survive)
99
+ return pop, da
100
+
101
+ def _associate(self, pop):
102
+ """Associate each individual with a F vector and calculate decomposed fitness"""
103
+ F = pop.get("F")
104
+ dist_matrix = self._calc_perpendicular_distance(F - self.ideal_point, self.ref_dirs)
105
+ niche_of_individuals = np.argmin(dist_matrix, axis=1)
106
+ FV = self._decomposition.do(F, weights=self.ref_dirs[niche_of_individuals, :],
107
+ ideal_point=self.ideal_point, weight_0=1e-4)
108
+ pop.set("niche", niche_of_individuals)
109
+ pop.set("FV", FV)
110
+ return niche_of_individuals, FV
111
+
112
+ def _updateCA(self, pop, n_survive):
113
+ """Update the Convergence archive (CA)"""
114
+ CV = pop.get("CV").flatten()
115
+
116
+ Sc = pop[CV == 0] # ConstraintsAsObjective population
117
+ if len(Sc) == n_survive: # Exactly n_survive feasible individuals
118
+ F = Sc.get("F")
119
+ fronts, rank = NonDominatedSorting().do(F, return_rank=True)
120
+ Sc.set('rank', rank)
121
+ self.opt = Sc[fronts[0]]
122
+ return Sc
123
+ elif len(Sc) < n_survive: # Not enough feasible individuals
124
+ remainder = n_survive - len(Sc)
125
+ # Solve sub-problem CV, tche
126
+ SI = pop[CV > 0]
127
+ f1 = SI.get("CV")
128
+ _, f2 = self._associate(SI)
129
+ sub_F = np.column_stack([f1, f2])
130
+ fronts = NonDominatedSorting().do(sub_F, n_stop_if_ranked=remainder)
131
+ I = []
132
+ for front in fronts:
133
+ if len(I) + len(front) <= remainder:
134
+ I.extend(front)
135
+ else:
136
+ n_missing = remainder - len(I)
137
+ last_front_CV = np.argsort(f1.flatten()[front])
138
+ I.extend(front[last_front_CV[:n_missing]])
139
+ SI = SI[I]
140
+ S = Population.merge(Sc, SI)
141
+ F = S.get("F")
142
+ fronts, rank = NonDominatedSorting().do(F, return_rank=True)
143
+ S.set('rank', rank)
144
+ self.opt = S[fronts[0]]
145
+ return S
146
+ else: # Too many feasible individuals
147
+ F = Sc.get("F")
148
+ # Filter by non-dominated sorting
149
+ fronts, rank = NonDominatedSorting().do(F, return_rank=True, n_stop_if_ranked=n_survive)
150
+ I = np.concatenate(fronts)
151
+ S, rank, F = Sc[I], rank[I], F[I]
152
+ if len(S) > n_survive:
153
+ # Remove individual in most crowded niche and with worst fitness
154
+ niche_of_individuals, FV = self._associate(S)
155
+ index, count = np.unique(niche_of_individuals, return_counts=True)
156
+ survivors = np.full(S.shape[0], True)
157
+ while survivors.sum() > n_survive:
158
+ crowdest_niches, = np.where(count == count.max())
159
+ worst_idx = None
160
+ worst_niche = None
161
+ worst_fit = -1
162
+ for crowdest_niche in crowdest_niches:
163
+ crowdest, = np.where((niche_of_individuals == index[crowdest_niche]) & survivors)
164
+ niche_worst = crowdest[FV[crowdest].argmax()]
165
+ dist_to_max_fit = cdist(F[[niche_worst], :], F).flatten()
166
+ dist_to_max_fit[niche_worst] = np.inf
167
+ dist_to_max_fit[~survivors] = np.inf
168
+ min_d_to_max_fit = dist_to_max_fit.min()
169
+
170
+ dist_in_niche = squareform(pdist(F[crowdest]))
171
+ np.fill_diagonal(dist_in_niche, np.inf)
172
+
173
+ delta_d = dist_in_niche - min_d_to_max_fit
174
+ min_d_i = np.unravel_index(np.argmin(delta_d, axis=None), dist_in_niche.shape)
175
+ if (delta_d[min_d_i] < 0) or (
176
+ delta_d[min_d_i] == 0 and (FV[crowdest[list(min_d_i)]] > niche_worst).any()):
177
+ min_d_i = list(min_d_i)
178
+ np.random.shuffle(min_d_i)
179
+ closest = crowdest[min_d_i]
180
+ niche_worst = closest[np.argmax(FV[closest])]
181
+ if (FV[niche_worst] > worst_fit).all():
182
+ worst_fit = FV[niche_worst]
183
+ worst_idx = niche_worst
184
+ worst_niche = crowdest_niche
185
+ survivors[worst_idx] = False
186
+ count[worst_niche] -= 1
187
+ S, rank = S[survivors], rank[survivors]
188
+ S.set('rank', rank)
189
+ self.opt = S[rank == 0]
190
+ return S
191
+
192
+ def _updateDA(self, pop, Hd, n_survive):
193
+ """Update the Diversity archive (DA)"""
194
+ niche_Hd, FV = self._associate(Hd)
195
+ niche_CA, _ = self._associate(pop)
196
+
197
+ itr = 1
198
+ S = []
199
+ while len(S) < n_survive:
200
+ for i in range(n_survive):
201
+ current_ca, = np.where(niche_CA == i)
202
+ if len(current_ca) < itr:
203
+ for _ in range(itr - len(current_ca)):
204
+ current_da = np.where(niche_Hd == i)[0]
205
+ if current_da.size > 0:
206
+ F = Hd[current_da].get('F')
207
+ nd = NonDominatedSorting().do(F, only_non_dominated_front=True, n_stop_if_ranked=0)
208
+ i_best = current_da[nd[np.argmin(FV[current_da[nd]])]]
209
+ niche_Hd[i_best] = -1
210
+ if len(S) < n_survive:
211
+ S.append(i_best)
212
+ else:
213
+ break
214
+ if len(S) == n_survive:
215
+ break
216
+ itr += 1
217
+ return Hd[S]
218
+
219
+
220
+ class CTAEA(GeneticAlgorithm):
221
+
222
+ def __init__(self,
223
+ ref_dirs,
224
+ sampling=FloatRandomSampling(),
225
+ selection=RestrictedMating(func_comp=comp_by_cv_dom_then_random),
226
+ crossover=SBX(n_offsprings=1, eta=30, prob=1.0),
227
+ mutation=PM(prob_var=None, eta=20),
228
+ eliminate_duplicates=True,
229
+ output=MultiObjectiveOutput(),
230
+ **kwargs):
231
+ """
232
+ CTAEA
233
+
234
+ Parameters
235
+ ----------
236
+ ref_dirs : {ref_dirs}
237
+ sampling : {sampling}
238
+ selection : {selection}
239
+ crossover : {crossover}
240
+ mutation : {mutation}
241
+ eliminate_duplicates : {eliminate_duplicates}
242
+ """
243
+
244
+ self.ref_dirs = ref_dirs
245
+ pop_size = len(ref_dirs)
246
+
247
+ if 'survival' in kwargs:
248
+ survival = kwargs['survival']
249
+ del kwargs['survival']
250
+ else:
251
+ survival = CADASurvival(ref_dirs)
252
+
253
+ # Initialize diversity archives
254
+ self.da = None
255
+
256
+ super().__init__(pop_size=pop_size,
257
+ sampling=sampling,
258
+ selection=selection,
259
+ crossover=crossover,
260
+ mutation=mutation,
261
+ survival=survival,
262
+ eliminate_duplicates=eliminate_duplicates,
263
+ n_offsprings=pop_size,
264
+ output=output,
265
+ **kwargs)
266
+
267
+ def _setup(self, problem, **kwargs):
268
+
269
+ if self.ref_dirs is not None and self.ref_dirs.shape[1] != problem.n_obj:
270
+ raise Exception(
271
+ "Dimensionality of reference points must be equal to the number of objectives: %s != %s" %
272
+ (self.ref_dirs.shape[1], problem.n_obj))
273
+
274
+ def _initialize_infill(self):
275
+ return self.initialization.do(self.problem, self.pop_size, algorithm=self)
276
+
277
+ def _initialize_advance(self, infills=None, **kwargs):
278
+ super()._initialize_advance(infills, **kwargs)
279
+ self.pop, self.da = self.survival.do(self.problem, self.pop, Population(), n_survive=len(self.pop),
280
+ algorithm=self)
281
+
282
+ def _infill(self):
283
+ Hm = Population.merge(self.pop, self.da)
284
+ return self.mating.do(self.problem, Hm, n_offsprings=self.n_offsprings, algorithm=self)
285
+
286
+ def _advance(self, infills=None, **kwargs):
287
+ assert infills is not None, "This algorithms uses the AskAndTell interface thus infills must to be provided."
288
+ pop = Population.merge(self.pop, infills)
289
+ self.pop, self.da = self.survival.do(self.problem, pop, self.da, self.pop_size, algorithm=self)
290
+
291
+ def _set_optimum(self, **kwargs):
292
+ if not has_feasible(self.pop):
293
+ self.opt = self.pop[[np.argmin(self.pop.get("CV"))]]
294
+ else:
295
+ self.opt = self.survival.opt
296
+
297
+
298
+ parse_doc_string(CTAEA.__init__)
@@ -0,0 +1,76 @@
1
+ import numpy as np
2
+
3
+ from pymoo.algorithms.moo.nsga2 import NSGA2
4
+ from pymoo.core.population import Population
5
+
6
+
7
+ class DNSGA2(NSGA2):
8
+
9
+ def __init__(self,
10
+ perc_detect_change=0.1,
11
+ perc_diversity=0.3,
12
+ eps=0.0,
13
+ version="A",
14
+ **kwargs):
15
+
16
+ super().__init__(**kwargs)
17
+ self.perc_detect_change = perc_detect_change
18
+ self.perc_diversity = perc_diversity
19
+ self.eps = eps
20
+ self.version = version
21
+
22
+ def setup(self, problem, **kwargs):
23
+ assert not problem.has_constraints(), "DNSGA2 only works for unconstrained problems."
24
+ return super().setup(problem, **kwargs)
25
+
26
+ def _advance(self, **kwargs):
27
+
28
+ pop = self.pop
29
+ X, F = pop.get("X", "F")
30
+
31
+ # the number of solutions to sample from the population to detect the change
32
+ n_samples = int(np.ceil(len(pop) * self.perc_detect_change))
33
+
34
+ # choose randomly some individuals of the current population to test if there was a change
35
+ I = np.random.choice(np.arange(len(pop)), size=n_samples)
36
+ samples = self.evaluator.eval(self.problem, Population.new(X=X[I]))
37
+
38
+ # calculate the differences between the old and newly evaluated pop
39
+ delta = ((samples.get("F") - F[I]) ** 2).mean()
40
+
41
+ # if there is an average deviation bigger than eps -> we have a change detected
42
+ change_detected = delta > self.eps
43
+
44
+ if change_detected:
45
+
46
+ # recreate the current population without being evaluated
47
+ pop = Population.new(X=X)
48
+
49
+ # find indices to be replaced (introduce diversity)
50
+ I = np.where(np.random.random(len(pop)) < self.perc_diversity)[0]
51
+
52
+ # replace with randomly sampled individuals
53
+ if self.version == "A":
54
+ pop[I] = self.initialization.sampling(self.problem, len(I))
55
+
56
+ # replace by mutations of existing solutions (this occurs inplace)
57
+ elif self.version == "B":
58
+ self.mating.mutation(self.problem, pop[I])
59
+ else:
60
+ raise Exception(f"Unknown version of D-NSGA-II: {self.version}")
61
+
62
+ # reevaluate because we know there was a change
63
+ self.evaluator.eval(self.problem, pop)
64
+
65
+ # do a survival to recreate rank and crowding of all individuals
66
+ pop = self.survival.do(self.problem, pop, n_survive=len(pop))
67
+
68
+ # create the offsprings from the current population
69
+ off = self.mating.do(self.problem, pop, self.n_offsprings, algorithm=self)
70
+ self.evaluator.eval(self.problem, off)
71
+
72
+ # merge the parent population and offsprings
73
+ pop = Population.merge(pop, off)
74
+
75
+ # execute the survival to find the fittest solutions
76
+ self.pop = self.survival.do(self.problem, pop, n_survive=self.pop_size, algorithm=self)