pymoo 0.6.1.5.dev0__cp313-cp313-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-313-x86_64-linux-gnu.so +0 -0
  91. pymoo/cython/calc_perpendicular_distance.pyx +67 -0
  92. pymoo/cython/decomposition.cpython-313-x86_64-linux-gnu.so +0 -0
  93. pymoo/cython/decomposition.pyx +165 -0
  94. pymoo/cython/hv.cpython-313-x86_64-linux-gnu.so +0 -0
  95. pymoo/cython/hv.pyx +18 -0
  96. pymoo/cython/info.cpython-313-x86_64-linux-gnu.so +0 -0
  97. pymoo/cython/info.pyx +5 -0
  98. pymoo/cython/mnn.cpython-313-x86_64-linux-gnu.so +0 -0
  99. pymoo/cython/mnn.pyx +273 -0
  100. pymoo/cython/non_dominated_sorting.cpython-313-x86_64-linux-gnu.so +0 -0
  101. pymoo/cython/non_dominated_sorting.pyx +645 -0
  102. pymoo/cython/pruning_cd.cpython-313-x86_64-linux-gnu.so +0 -0
  103. pymoo/cython/pruning_cd.pyx +197 -0
  104. pymoo/cython/stochastic_ranking.cpython-313-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,312 @@
1
+ import warnings
2
+ from abc import abstractmethod
3
+
4
+ import numpy as np
5
+
6
+ # ---------------------------------------------------------------------------------------------------------
7
+ # Object Oriented Interface
8
+ # ---------------------------------------------------------------------------------------------------------
9
+
10
+ # ---- Abstract Class
11
+ from numpy.linalg import LinAlgError
12
+
13
+
14
+ class Normalization:
15
+
16
+ def __init__(self) -> None:
17
+ super().__init__()
18
+
19
+ @abstractmethod
20
+ def forward(self, X):
21
+ pass
22
+
23
+ @abstractmethod
24
+ def backward(self, X):
25
+ pass
26
+
27
+
28
+ # ---- Useful if normalization is optional - can be simply disabled by using this object
29
+ class NoNormalization(Normalization):
30
+
31
+ def forward(self, X):
32
+ return X
33
+
34
+ def backward(self, X):
35
+ return X
36
+
37
+
38
+ # ---- Normalizes between zero and one given bounds or estimating them
39
+ class ZeroToOneNormalization(Normalization):
40
+
41
+ def __init__(self, xl=None, xu=None) -> None:
42
+ super().__init__()
43
+
44
+ # if both are None we are basically done because normalization is disabled
45
+ if xl is None and xu is None:
46
+ self.xl, self.xu = None, None
47
+ return
48
+
49
+ # if not set simply fall back no nan values
50
+ if xl is None:
51
+ xl = np.full_like(xu, np.nan)
52
+ if xu is None:
53
+ xu = np.full_like(xl, np.nan)
54
+
55
+ xl, xu = np.copy(xl).astype(float), np.copy(xu).astype(float)
56
+
57
+ # if both are equal then set the upper bound to none (always the 0 or lower bound will be returned then)
58
+ xu[xl == xu] = np.nan
59
+
60
+ # store the lower and upper bounds
61
+ self.xl, self.xu = xl, xu
62
+
63
+ # check out when the input values are nan
64
+ xl_nan, xu_nan = np.isnan(xl), np.isnan(xu)
65
+
66
+ # now create all the masks that are necessary
67
+ self.xl_only, self.xu_only = np.logical_and(~xl_nan, xu_nan), np.logical_and(xl_nan, ~xu_nan)
68
+ self.both_nan = np.logical_and(np.isnan(xl), np.isnan(xu))
69
+ self.neither_nan = np.logical_and(~np.isnan(xl), ~np.isnan(xu))
70
+
71
+ # if neither is nan than xu must be greater or equal than xl
72
+ any_nan = np.logical_or(np.isnan(xl), np.isnan(xu))
73
+ assert np.all(np.logical_or(xu >= xl, any_nan)), "xl must be less or equal than xu."
74
+
75
+ def forward(self, X):
76
+ if X is None or (self.xl is None and self.xu is None):
77
+ return X
78
+
79
+ # simple copy the input
80
+ N = np.copy(X)
81
+
82
+ # normalize between zero and one if neither of them is nan
83
+ N[..., self.neither_nan] = (X[..., self.neither_nan] - self.xl[self.neither_nan]) / (self.xu[self.neither_nan] - self.xl[self.neither_nan])
84
+
85
+ N[..., self.xl_only] = X[..., self.xl_only] - self.xl[self.xl_only]
86
+
87
+ N[..., self.xu_only] = 1.0 - (self.xu[self.xu_only] - X[..., self.xu_only])
88
+
89
+ return N
90
+
91
+ def backward(self, N):
92
+ if N is None or (self.xl is None and self.xu is None):
93
+ return N
94
+
95
+ xl, xu, xl_only, xu_only = self.xl, self.xu, self.xl_only, self.xu_only
96
+ both_nan, neither_nan = self.both_nan, self.neither_nan
97
+
98
+ X = N.copy()
99
+ X[..., neither_nan] = xl[neither_nan] + N[..., neither_nan] * (xu[neither_nan] - xl[neither_nan])
100
+
101
+ X[..., xl_only] = N[..., xl_only] + xl[xl_only]
102
+
103
+ X[..., xu_only] = xu[xu_only] - (1.0 - N[..., xu_only])
104
+
105
+ return X
106
+
107
+
108
+ # ---------------------------------------------------------------------------------------------------------
109
+ # Simple Normalization
110
+ # Does not consider any none values and assumes lower as well as upper bounds are given.
111
+ # ---------------------------------------------------------------------------------------------------------
112
+
113
+
114
+ class SimpleZeroToOneNormalization(Normalization):
115
+
116
+ def __init__(self, xl=None, xu=None, estimate_bounds=True) -> None:
117
+ super().__init__()
118
+ self.xl = xl
119
+ self.xu = xu
120
+ self.estimate_bounds = estimate_bounds
121
+
122
+ def forward(self, X):
123
+
124
+ if self.estimate_bounds:
125
+ if self.xl is None:
126
+ self.xl = np.min(X, axis=0)
127
+ if self.xu is None:
128
+ self.xu = np.max(X, axis=0)
129
+
130
+ xl, xu = self.xl, self.xu
131
+
132
+ # if np.any(xl == xu):
133
+ # raise Exception("Normalization failed because lower and upper bounds are equal!")
134
+
135
+ # calculate the denominator
136
+ denom = xu - xl
137
+
138
+ # we can not divide by zero -> plus small epsilon
139
+ denom += (denom == 0) * 1e-32
140
+
141
+ # normalize the actual values
142
+ N = (X - xl) / denom
143
+
144
+ return N
145
+
146
+ def backward(self, X):
147
+ return X * (self.xu - self.xl) + self.xl
148
+
149
+
150
+ # ---------------------------------------------------------------------------------------------------------
151
+ # Functional Interface
152
+ # ---------------------------------------------------------------------------------------------------------
153
+
154
+
155
+ def normalize(X, xl=None, xu=None, return_bounds=False, estimate_bounds_if_none=True):
156
+ if estimate_bounds_if_none:
157
+ if xl is None:
158
+ xl = np.min(X, axis=0)
159
+ if xu is None:
160
+ xu = np.max(X, axis=0)
161
+
162
+ if isinstance(xl, float) or isinstance(xl, int):
163
+ xl = np.full(X.shape[-1], xl)
164
+
165
+ if isinstance(xu, float) or isinstance(xu, int):
166
+ xu = np.full(X.shape[-1], xu)
167
+
168
+ norm = ZeroToOneNormalization(xl, xu)
169
+ X = norm.forward(X)
170
+
171
+ if not return_bounds:
172
+ return X
173
+ else:
174
+ return X, norm.xl, norm.xu
175
+
176
+
177
+ def denormalize(x, xl, xu):
178
+ return ZeroToOneNormalization(xl, xu).backward(x)
179
+
180
+
181
+ def standardize(x, return_bounds=False):
182
+ mean = np.mean(x, axis=0)
183
+ std = np.std(x, axis=0)
184
+
185
+ # standardize
186
+ val = (x - mean) / std
187
+
188
+ if not return_bounds:
189
+ return val
190
+ else:
191
+ return val, mean, std
192
+
193
+
194
+ def destandardize(x, mean, std):
195
+ return (x * std) + mean
196
+
197
+
198
+ # ---------------------------------------------------------------------------------------------------------
199
+ # Pre Normalization
200
+ # A class inheriting from it can use the in-built feature of normalizing
201
+ # ---------------------------------------------------------------------------------------------------------
202
+
203
+
204
+ class PreNormalization:
205
+
206
+ def __init__(self, zero_to_one=False, ideal=None, nadir=None, **kwargs):
207
+
208
+ # normalization related stuff if that should be performed beforehand
209
+ self.ideal, self.nadir = ideal, nadir
210
+
211
+ if zero_to_one:
212
+ assert self.ideal is not None and self.nadir is not None, "For normalization either provide pf or bounds!"
213
+
214
+ n_dim = len(self.ideal)
215
+ self.normalization = ZeroToOneNormalization(self.ideal, self.nadir)
216
+
217
+ # now the ideal and nadir points have change to only zeros and ones
218
+ self.ideal, self.nadir = np.zeros(n_dim), np.ones(n_dim)
219
+
220
+ else:
221
+ self.normalization = NoNormalization()
222
+
223
+ def do(self, *args, **kwargs):
224
+ pass
225
+
226
+
227
+ # ---------------------------------------------------------------------------------------------------------
228
+ # Normalization in the Objective Space
229
+ # ---------------------------------------------------------------------------------------------------------
230
+
231
+
232
+ def find_ideal(F, current=None):
233
+ p = F.min(axis=0)
234
+ if current is not None:
235
+ p = np.minimum(current, p)
236
+ return p
237
+
238
+
239
+ def get_extreme_points_c(F, ideal_point, extreme_points=None):
240
+ # calculate the asf which is used for the extreme point decomposition
241
+ weights = np.eye(F.shape[1])
242
+ weights[weights == 0] = 1e6
243
+
244
+ # add the old extreme points to never loose them for normalization
245
+ _F = F
246
+ if extreme_points is not None:
247
+ _F = np.concatenate([extreme_points, _F], axis=0)
248
+
249
+ # use __F because we substitute small values to be 0
250
+ __F = _F - ideal_point
251
+ __F[__F < 1e-3] = 0
252
+
253
+ # update the extreme points for the normalization having the highest asf value each
254
+ F_asf = np.max(__F * weights[:, None, :], axis=2)
255
+
256
+ I = np.argmin(F_asf, axis=1)
257
+ extreme_points = _F[I, :]
258
+
259
+ return extreme_points
260
+
261
+
262
+ def get_nadir_point(extreme_points, ideal_point, worst_point, worst_of_front, worst_of_population):
263
+ try:
264
+
265
+ # find the intercepts using gaussian elimination
266
+ M = extreme_points - ideal_point
267
+ b = np.ones(extreme_points.shape[1])
268
+ plane = np.linalg.solve(M, b)
269
+
270
+ warnings.simplefilter("ignore")
271
+ intercepts = 1 / plane
272
+
273
+ nadir_point = ideal_point + intercepts
274
+
275
+ # check if the hyperplane makes sense
276
+ if not np.allclose(np.dot(M, plane), b) or np.any(intercepts <= 1e-6):
277
+ raise LinAlgError()
278
+
279
+ # if the nadir point should be larger than any value discovered so far set it to that value
280
+ # NOTE: different to the proposed version in the paper
281
+ b = nadir_point > worst_point
282
+ nadir_point[b] = worst_point[b]
283
+
284
+ except LinAlgError:
285
+
286
+ # fall back to worst of front otherwise
287
+ nadir_point = worst_of_front
288
+
289
+ # if the range is too small set it to worst of population
290
+ b = nadir_point - ideal_point <= 1e-6
291
+ nadir_point[b] = worst_of_population[b]
292
+
293
+ return nadir_point
294
+
295
+
296
+ class ObjectiveSpaceNormalization:
297
+
298
+ def __init__(self) -> None:
299
+ super().__init__()
300
+ self._ideal = None
301
+ self._infeas_ideal = None
302
+ self._worst = None
303
+
304
+ def update(self, pop):
305
+ F, feas = pop.get("F", "FEAS")
306
+ self._infeas_ideal = find_ideal(F, current=self._infeas_ideal)
307
+
308
+ if np.any(feas):
309
+ self._ideal = find_ideal(F[feas[:, 0]], self._ideal)
310
+
311
+ def ideal(self, only_feas=True):
312
+ return self._ideal if only_feas else self._infeas_ideal
pymoo/util/optimum.py ADDED
@@ -0,0 +1,42 @@
1
+ import numpy as np
2
+
3
+ from pymoo.core.individual import Individual
4
+ from pymoo.core.population import Population
5
+ from pymoo.util.nds.non_dominated_sorting import NonDominatedSorting
6
+
7
+
8
+ def filter_optimum(pop, least_infeasible=False):
9
+
10
+ # if the population is none to optimum can be found
11
+ if pop is None or len(pop) == 0:
12
+ return None
13
+
14
+ # first only choose feasible solutions
15
+ ret = pop[pop.get("feas")]
16
+
17
+ # if at least one feasible solution was found
18
+ if len(ret) > 0:
19
+
20
+ # then check the objective values
21
+ F = ret.get("F")
22
+
23
+ if F.shape[1] > 1:
24
+ I = NonDominatedSorting().do(F, only_non_dominated_front=True)
25
+ ret = ret[I]
26
+
27
+ else:
28
+ ret = ret[np.argmin(F[:, 0])]
29
+
30
+ # no feasible solution was found
31
+ else:
32
+ # if flag enable report the least infeasible
33
+ if least_infeasible:
34
+ ret = pop[np.argmin(pop.get("CV"))]
35
+ # otherwise just return none
36
+ else:
37
+ ret = None
38
+
39
+ if isinstance(ret, Individual):
40
+ ret = Population().create(ret)
41
+
42
+ return ret
pymoo/util/plotting.py ADDED
@@ -0,0 +1,177 @@
1
+ import matplotlib.pyplot as plt
2
+ import numpy as np
3
+ from matplotlib import animation
4
+
5
+
6
+ def plot(*args, show=True, labels=None, no_fill=False, **kwargs):
7
+ F = args[0]
8
+
9
+ if F.ndim == 1:
10
+ print("Cannot plot a one dimensional array.")
11
+ return
12
+
13
+ n_dim = F.shape[1]
14
+
15
+ if n_dim == 2:
16
+ ret = plot_2d(*args, labels=labels, no_fill=no_fill, **kwargs)
17
+ elif n_dim == 3:
18
+ ret = plot_3d(*args, labels=labels, no_fill=no_fill, **kwargs)
19
+ else:
20
+ print("Cannot plot a %s dimensional array." % n_dim)
21
+ return
22
+
23
+ if labels:
24
+ plt.legend()
25
+
26
+ if show:
27
+ plt.show()
28
+
29
+ return ret
30
+
31
+
32
+ def plot_3d(*args, no_fill=False, labels=None, **kwargs):
33
+ fig = plt.figure()
34
+ ax = fig.add_subplot(111, projection='3d')
35
+
36
+ for i, F in enumerate(args):
37
+
38
+ if no_fill:
39
+ kwargs["s"] = 20
40
+ kwargs["marker"] = '.'
41
+ kwargs["facecolors"] = (0, 0, 0, 0)
42
+ kwargs["edgecolors"] = 'r'
43
+
44
+ if labels:
45
+ ax.scatter(F[:, 0], F[:, 1], F[:, 2], label=labels[i], **kwargs)
46
+ else:
47
+ ax.scatter(F[:, 0], F[:, 1], F[:, 2], **kwargs)
48
+
49
+ return ax
50
+
51
+
52
+ def plot_2d(*args, labels=None, no_fill=False):
53
+ if no_fill:
54
+ kwargs = dict(
55
+ s=20,
56
+ facecolors='none',
57
+ edgecolors='r'
58
+ )
59
+ else:
60
+ kwargs = {}
61
+
62
+ for i, F in enumerate(args):
63
+ if labels:
64
+ plt.scatter(F[:, 0], F[:, 1], label=labels[i], **kwargs)
65
+ else:
66
+ plt.scatter(F[:, 0], F[:, 1], **kwargs)
67
+
68
+
69
+ def animate(path_to_file, H, problem=None, func_iter=None, plot_min=None, plot_max=None):
70
+ if H.ndim != 3 or H.shape[2] != 2:
71
+ print("Can only animate a two dimensional set of arrays.")
72
+ return
73
+
74
+ fig = plt.figure()
75
+ ax = plt.gca()
76
+
77
+ # plot the pareto front if it is known for the problem
78
+ if problem is not None:
79
+ pf = problem.pareto_front()
80
+ plt.scatter(pf[:, 0], pf[:, 1], label='Pareto Front', s=60, facecolors='none', edgecolors='r')
81
+
82
+ # plot the initial population
83
+ _F = H[0, :, :]
84
+ scat = plt.scatter(_F[:, 0], _F[:, 1])
85
+ plt.title("0")
86
+
87
+ if func_iter is not None:
88
+ func_iter(ax, H[0])
89
+
90
+ # the update method
91
+ def update(n):
92
+ _F = H[n, :, :]
93
+ scat.set_offsets(_F)
94
+
95
+ # get the bounds for plotting and add padding
96
+ min = np.min(_F, axis=0) - 0.1
97
+ max = np.max(_F, axis=0) + 0.1
98
+
99
+ # set the scatter object with padding
100
+ ax.set_xlim(min[0], max[0])
101
+ ax.set_ylim(min[1], max[1])
102
+
103
+ if func_iter is not None:
104
+ func_iter(ax, H[n])
105
+
106
+ plt.title(n)
107
+
108
+ # create the animation
109
+ ani = animation.FuncAnimation(fig, update, frames=H.shape[0])
110
+
111
+ # write the file
112
+ Writer = animation.writers['ffmpeg']
113
+ writer = Writer(fps=6, bitrate=1800)
114
+ ani.save(path_to_file, writer=writer)
115
+
116
+ print("Saving: ", path_to_file)
117
+
118
+
119
+ def plot_problem_surface(problem, n_samples, plot_type="wireframe", cmap="summer", show=True, return_figure=False):
120
+ try:
121
+ import matplotlib.pyplot as plt
122
+ from mpl_toolkits.mplot3d import Axes3D
123
+ except:
124
+ raise Exception("Please install 'matplotlib' to use the plotting functionality.")
125
+
126
+ fig = plt.figure()
127
+
128
+ if problem.n_var == 1 and problem.n_obj == 1:
129
+
130
+ X = np.linspace(problem.xl[0], problem.xu[0], num=n_samples)[:, None]
131
+ Y = problem.evaluate(X, return_values_of=["F"])
132
+ ax = plt.plot(X, Y)
133
+
134
+ elif problem.n_var == 2 and problem.n_obj == 1:
135
+
136
+ X_range = np.linspace(problem.xl[0], problem.xu[0], num=n_samples)
137
+ Y_range = np.linspace(problem.xl[1], problem.xu[1], num=n_samples)
138
+ X, Y = np.meshgrid(X_range, Y_range)
139
+
140
+ A = np.zeros((n_samples * n_samples, 2))
141
+ counter = 0
142
+ for i, x in enumerate(X_range):
143
+ for j, y in enumerate(Y_range):
144
+ A[counter, 0] = x
145
+ A[counter, 1] = y
146
+ counter += 1
147
+
148
+ F = np.reshape(problem.evaluate(A, return_values_of=["F"]), (n_samples, n_samples))
149
+
150
+ # Plot the surface.
151
+ if plot_type == "wireframe":
152
+ ax = fig.add_subplot(111, projection='3d')
153
+ ax.plot_wireframe(X, Y, F)
154
+ elif plot_type == "contour":
155
+ CS = plt.contour(X, Y, F)
156
+ plt.clabel(CS, inline=1, fontsize=10)
157
+ elif plot_type == "wireframe+contour":
158
+ ax = fig.add_subplot(111, projection="3d")
159
+ ax.plot_surface(X, Y, F, cmap=cmap, rstride=1, cstride=1)
160
+ ax.contour(X, Y, F, 10, linestyles="solid", offset=-1)
161
+ ax.set_xlabel("$x_1$")
162
+ ax.set_ylabel("$x_2$")
163
+ ax.set_zlabel("$f(x)$")
164
+ ax.view_init(45, 45)
165
+ else:
166
+ raise Exception("Unknown plotting method.")
167
+
168
+
169
+ else:
170
+ raise Exception("Can only plot single with less than two variables and one objective.")
171
+
172
+ if show:
173
+ plt.tight_layout()
174
+ plt.show()
175
+
176
+ if return_figure:
177
+ return fig, ax
@@ -0,0 +1,89 @@
1
+ import numpy as np
2
+
3
+ def calc_pcd(X, n_remove=0):
4
+
5
+ N = X.shape[0]
6
+ M = X.shape[1]
7
+
8
+ if n_remove <= (N - M):
9
+ if n_remove < 0:
10
+ n_remove = 0
11
+ else:
12
+ pass
13
+ else:
14
+ n_remove = N - M
15
+
16
+ extremes_min = np.argmin(X, axis=0)
17
+ extremes_max = np.argmax(X, axis=0)
18
+
19
+ min_vals = np.min(X, axis=0)
20
+ max_vals = np.max(X, axis=0)
21
+
22
+ extremes = np.concatenate((extremes_min, extremes_max))
23
+
24
+ X = (X - min_vals) / (max_vals - min_vals)
25
+
26
+ H = np.arange(N)
27
+ d = np.full(N, np.inf)
28
+
29
+ I = np.argsort(X, axis=0, kind='mergesort')
30
+
31
+ # sort the objective space values for the whole matrix
32
+ _X = X[I, np.arange(M)]
33
+
34
+ # calculate the distance from each point to the last and next
35
+ dist = np.row_stack([_X, np.full(M, np.inf)]) - np.row_stack([np.full(M, -np.inf), _X])
36
+
37
+ # prepare the distance to last and next vectors
38
+ dist_to_last, dist_to_next = dist, np.copy(dist)
39
+ dist_to_last, dist_to_next = dist_to_last[:-1], dist_to_next[1:]
40
+
41
+ # if we divide by zero because all values in one columns are equal replace by none
42
+ dist_to_last[np.isnan(dist_to_last)] = 0.0
43
+ dist_to_next[np.isnan(dist_to_next)] = 0.0
44
+
45
+ # sum up the distance to next and last and norm by objectives - also reorder from sorted list
46
+ J = np.argsort(I, axis=0)
47
+ _d = np.sum(dist_to_last[J, np.arange(M)] + dist_to_next[J, np.arange(M)], axis=1)
48
+ d[H] = _d
49
+ d[extremes] = np.inf
50
+
51
+ n_removed = 0
52
+
53
+ #While n_remove not acheived
54
+ while n_removed < (n_remove - 1):
55
+
56
+ #Obtain element to drop
57
+ _d = d[H]
58
+ _k = np.argmin(_d)
59
+ k = H[_k]
60
+
61
+ H = H[H != k]
62
+
63
+ #Update index
64
+ n_removed = n_removed + 1
65
+
66
+ I = np.argsort(X[H].copy(), axis=0, kind='mergesort')
67
+
68
+ # sort the objective space values for the whole matrix
69
+ _X = X[H].copy()[I, np.arange(M)]
70
+
71
+ # calculate the distance from each point to the last and next
72
+ dist = np.row_stack([_X, np.full(M, np.inf)]) - np.row_stack([np.full(M, -np.inf), _X])
73
+
74
+ # prepare the distance to last and next vectors
75
+ dist_to_last, dist_to_next = dist, np.copy(dist)
76
+ dist_to_last, dist_to_next = dist_to_last[:-1], dist_to_next[1:]
77
+
78
+ # if we divide by zero because all values in one columns are equal replace by none
79
+ dist_to_last[np.isnan(dist_to_last)] = 0.0
80
+ dist_to_next[np.isnan(dist_to_next)] = 0.0
81
+
82
+ # sum up the distance to next and last and norm by objectives - also reorder from sorted list
83
+ J = np.argsort(I, axis=0)
84
+ _d = np.sum(dist_to_last[J, np.arange(M)] + dist_to_next[J, np.arange(M)], axis=1)
85
+ d[H] = _d
86
+ d[extremes] = np.inf
87
+
88
+ return d
89
+
@@ -0,0 +1,60 @@
1
+ import numpy as np
2
+
3
+ from pymoo.util.misc import swap
4
+
5
+
6
+ def randomized_argsort(A, method="numpy", order='ascending'):
7
+ if method == "numpy":
8
+ P = np.random.permutation(len(A))
9
+ I = np.argsort(A[P], kind='quicksort')
10
+ I = P[I]
11
+
12
+ elif method == "quicksort":
13
+ I = quicksort(A)
14
+
15
+ else:
16
+ raise Exception("Randomized sort method not known.")
17
+
18
+ if order == 'ascending':
19
+ return I
20
+ elif order == 'descending':
21
+ return np.flip(I, axis=0)
22
+ else:
23
+ raise Exception("Unknown sorting order: ascending or descending.")
24
+
25
+
26
+ def quicksort(A):
27
+ I = np.arange(len(A))
28
+ _quicksort(A, I, 0, len(A) - 1)
29
+ return I
30
+
31
+
32
+ def _quicksort(A, I, left, right):
33
+ if left < right:
34
+
35
+ index = np.random.randint(left, right + 1)
36
+ swap(I, right, index)
37
+
38
+ pivot = A[I[right]]
39
+
40
+ i = left - 1
41
+
42
+ for j in range(left, right):
43
+
44
+ if A[I[j]] <= pivot:
45
+ i += 1
46
+ swap(I, i, j)
47
+
48
+ index = i + 1
49
+ swap(I, right, index)
50
+
51
+ _quicksort(A, I, left, index - 1)
52
+ _quicksort(A, I, index + 1, right)
53
+
54
+
55
+ if __name__ == '__main__':
56
+ a = np.array([5, 9, 10, 0, 0, 0, 100, -2])
57
+
58
+ for i in range(200):
59
+ I = randomized_argsort(a, method="numpy")
60
+ print(I)
@@ -0,0 +1,24 @@
1
+ from pymoo.util.ref_dirs.energy import RieszEnergyReferenceDirectionFactory
2
+ from pymoo.util.ref_dirs.energy_layer import LayerwiseRieszEnergyReferenceDirectionFactory
3
+ from pymoo.util.ref_dirs.reduction import ReductionBasedReferenceDirectionFactory
4
+ from pymoo.util.ref_dirs.incremental import IncrementalReferenceDirectionFactory
5
+ from pymoo.util.reference_direction import MultiLayerReferenceDirectionFactory
6
+
7
+
8
+ def get_reference_directions(name, *args, **kwargs):
9
+ from pymoo.util.reference_direction import UniformReferenceDirectionFactory
10
+
11
+ REF = {
12
+ "uniform": UniformReferenceDirectionFactory,
13
+ "das-dennis": UniformReferenceDirectionFactory,
14
+ "energy": RieszEnergyReferenceDirectionFactory,
15
+ "multi-layer": MultiLayerReferenceDirectionFactory,
16
+ "layer-energy": LayerwiseRieszEnergyReferenceDirectionFactory,
17
+ "reduction": ReductionBasedReferenceDirectionFactory,
18
+ "incremental": IncrementalReferenceDirectionFactory,
19
+ }
20
+
21
+ if name not in REF:
22
+ raise Exception("Reference directions factory not found.")
23
+
24
+ return REF[name](*args, **kwargs)()