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,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
@@ -0,0 +1,63 @@
1
+ import numpy as np
2
+
3
+ from pymoo.util.misc import swap
4
+ from pymoo.util import default_random_state
5
+
6
+
7
+ @default_random_state
8
+ def randomized_argsort(A, method="numpy", order='ascending', random_state=None):
9
+ if method == "numpy":
10
+ P = random_state.permutation(len(A))
11
+ I = np.argsort(A[P], kind='quicksort')
12
+ I = P[I]
13
+
14
+ elif method == "quicksort":
15
+ I = quicksort(A)
16
+
17
+ else:
18
+ raise Exception("Randomized sort method not known.")
19
+
20
+ if order == 'ascending':
21
+ return I
22
+ elif order == 'descending':
23
+ return np.flip(I, axis=0)
24
+ else:
25
+ raise Exception("Unknown sorting order: ascending or descending.")
26
+
27
+
28
+ @default_random_state
29
+ def quicksort(A, random_state=None):
30
+ I = np.arange(len(A))
31
+ _quicksort(A, I, 0, len(A) - 1, random_state=random_state)
32
+ return I
33
+
34
+
35
+ def _quicksort(A, I, left, right, random_state):
36
+ if left < right:
37
+
38
+ index = random_state.integers(left, right + 1)
39
+ swap(I, right, index)
40
+
41
+ pivot = A[I[right]]
42
+
43
+ i = left - 1
44
+
45
+ for j in range(left, right):
46
+
47
+ if A[I[j]] <= pivot:
48
+ i += 1
49
+ swap(I, i, j)
50
+
51
+ index = i + 1
52
+ swap(I, right, index)
53
+
54
+ _quicksort(A, I, left, index - 1, random_state)
55
+ _quicksort(A, I, index + 1, right, random_state)
56
+
57
+
58
+ if __name__ == '__main__':
59
+ a = np.array([5, 9, 10, 0, 0, 0, 100, -2])
60
+
61
+ for i in range(200):
62
+ I = randomized_argsort(a, method="numpy")
63
+ 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)()
@@ -0,0 +1,89 @@
1
+ import numpy as np
2
+
3
+ from pymoo.util.misc import vectorized_cdist
4
+ from pymoo.util.ref_dirs.misc import project_onto_sum_equals_zero_plane, project_onto_unit_simplex_recursive
5
+ from pymoo.util.ref_dirs.optimizer import Adam
6
+ from pymoo.util.reference_direction import ReferenceDirectionFactory, map_onto_unit_simplex
7
+
8
+
9
+ def calc_dist_to_others(x, X):
10
+ return - np.sqrt(((x - X) ** 2).sum(axis=1)).min()
11
+
12
+
13
+ def calc_dist_to_others_with_gradient(x, X):
14
+ diff = (x - X)
15
+ D = np.sqrt((diff ** 2).sum(axis=1))
16
+
17
+ k = D.argmin()
18
+
19
+ obj = - D.min()
20
+ grad = - diff[k] / D[k]
21
+
22
+ return obj, grad
23
+
24
+
25
+ class ConstructionBasedReferenceDirectionFactory(ReferenceDirectionFactory):
26
+
27
+ def __init__(self,
28
+ n_dim,
29
+ n_points,
30
+ n_samples=100,
31
+ gradient_descent=True,
32
+ verbose=False,
33
+ **kwargs):
34
+
35
+ super().__init__(n_dim, **kwargs)
36
+ self.n_points = n_points
37
+ self.gradient_descent = gradient_descent
38
+ self.n_samples = n_samples
39
+ self.verbose = verbose
40
+ self.X = None
41
+
42
+ def _do(self, random_state=None, **kwargs):
43
+
44
+ self.random_state = random_state
45
+ self.X = np.eye(self.n_dim)
46
+
47
+ while len(self.X) < self.n_points:
48
+ x = self.next()
49
+ self.X = np.vstack([self.X, x])
50
+
51
+ if self.verbose:
52
+ print(len(self.X), "x", x)
53
+
54
+ return self.X
55
+
56
+ def next(self):
57
+
58
+ x = self.random_state.random((self.n_samples, self.n_dim))
59
+ x = map_onto_unit_simplex(x, "kraemer")
60
+ x = x[vectorized_cdist(x, self.X).min(axis=1).argmax()]
61
+
62
+ if self.gradient_descent:
63
+
64
+ optimizer = Adam(precision=1e-4)
65
+
66
+ # for each iteration of gradient descent
67
+ for i in range(1000):
68
+
69
+ # calculate the function value and the gradient
70
+ # auto_obj, auto_grad = value_and_grad(calc_dist_to_others)(x, self.X)
71
+ _obj, _grad = calc_dist_to_others_with_gradient(x, self.X)
72
+
73
+ # project the gradient to have a sum of zero - guarantees to stay on the simplex
74
+ proj_grad = project_onto_sum_equals_zero_plane(_grad)
75
+
76
+ # apply a step of gradient descent by subtracting the projected gradient with a learning rate
77
+ x = optimizer.next(x, proj_grad)
78
+
79
+ # project the out of bounds points back onto the unit simplex
80
+ project_onto_unit_simplex_recursive(x[None, :])
81
+
82
+ # because of floating point issues make sure it is on the unit simplex
83
+ x /= x.sum()
84
+
85
+ # if there was only a little movement during the last iteration -> terminate
86
+ if optimizer.has_converged:
87
+ break
88
+
89
+ return x
@@ -0,0 +1,52 @@
1
+ import numpy as np
2
+ from scipy import special
3
+
4
+
5
+ class DasDennis:
6
+
7
+ def __init__(self, n_partitions, n_dim, scaling=None):
8
+ super().__init__()
9
+ self.n_partitions = n_partitions
10
+ self.n_dim = n_dim
11
+ self.scaling = scaling
12
+
13
+ self.stack = []
14
+ self.stack.append(([], self.n_partitions))
15
+
16
+ def number_of_points(self):
17
+ return int(special.binom(self.n_dim + self.n_partitions - 1, self.n_partitions))
18
+
19
+ def next(self, n_points=None):
20
+ ret = []
21
+ self.traverse(lambda p: ret.append(p), n_points)
22
+ return np.array(ret)
23
+
24
+ def has_next(self):
25
+ return len(self.stack) > 0
26
+
27
+ def traverse(self, func, n_points=None):
28
+
29
+ if self.n_partitions == 0:
30
+ return np.full((1, self.n_dim), 1 / self.n_dim)
31
+
32
+ counter = 0
33
+
34
+ while (n_points is None or counter < n_points) and len(self.stack) > 0:
35
+
36
+ point, beta = self.stack.pop()
37
+
38
+ if len(point) + 1 == self.n_dim:
39
+ point.append(beta / (1.0 * self.n_partitions))
40
+
41
+ if self.scaling is not None:
42
+ point = [p * self.scaling + ((1 - self.scaling) / len(point)) for p in point]
43
+
44
+ func(point)
45
+ counter += 1
46
+ else:
47
+ for i in range(beta + 1):
48
+ _point = list(point)
49
+ _point.append(1.0 * i / (1.0 * self.n_partitions))
50
+ self.stack.append((_point, beta - i))
51
+
52
+ return counter