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