pymoo 0.6.1.5.dev0__cp39-cp39-musllinux_1_2_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 (330) 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-39-x86_64-linux-gnu.so +0 -0
  91. pymoo/cython/calc_perpendicular_distance.pyx +67 -0
  92. pymoo/cython/decomposition.cpython-39-x86_64-linux-gnu.so +0 -0
  93. pymoo/cython/decomposition.pyx +165 -0
  94. pymoo/cython/hv.cpython-39-x86_64-linux-gnu.so +0 -0
  95. pymoo/cython/hv.pyx +18 -0
  96. pymoo/cython/info.cpython-39-x86_64-linux-gnu.so +0 -0
  97. pymoo/cython/info.pyx +5 -0
  98. pymoo/cython/mnn.cpython-39-x86_64-linux-gnu.so +0 -0
  99. pymoo/cython/mnn.pyx +273 -0
  100. pymoo/cython/non_dominated_sorting.cpython-39-x86_64-linux-gnu.so +0 -0
  101. pymoo/cython/non_dominated_sorting.pyx +645 -0
  102. pymoo/cython/pruning_cd.cpython-39-x86_64-linux-gnu.so +0 -0
  103. pymoo/cython/pruning_cd.pyx +197 -0
  104. pymoo/cython/stochastic_ranking.cpython-39-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 +330 -0
  326. pymoo-0.6.1.5.dev0.dist-info/WHEEL +5 -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
  329. pymoo.libs/libgcc_s-2298274a.so.1 +0 -0
  330. pymoo.libs/libstdc++-08d5c7eb.so.6.0.33 +0 -0
@@ -0,0 +1,51 @@
1
+ from functools import partial
2
+
3
+ from jax.config import config
4
+
5
+ config.update("jax_enable_x64", True)
6
+
7
+ import pymoo.gradient.toolbox as anp
8
+ import numpy as np
9
+ from jax import vjp
10
+ from jax import vmap
11
+ from jax._src.api import _jacrev_unravel, _std_basis
12
+ from jax.tree_util import (tree_map)
13
+
14
+
15
+ def jax_elementwise_value_and_grad(f, x):
16
+ out, pullback = vjp(f, x)
17
+ u = _std_basis(out)
18
+ jac, = vmap(pullback, in_axes=0)(u)
19
+
20
+ grad = tree_map(partial(_jacrev_unravel, out), x, jac)
21
+
22
+ return out, grad
23
+
24
+
25
+ def jax_vectorized_value_and_grad(f, x):
26
+ out, pullback = vjp(f, x)
27
+
28
+ ncols = sum([v.shape[1] for v in out.values()])
29
+
30
+ u = dict()
31
+ cols = dict()
32
+ cnt = 0
33
+ for k, v in out.items():
34
+ if k not in cols:
35
+ cols[k] = []
36
+
37
+ n, m = v.shape
38
+ a = np.zeros((ncols, n, m))
39
+ for i in range(m):
40
+ cols[k].append(cnt)
41
+ a[cnt, :, i] = 1.0
42
+ cnt += 1
43
+
44
+ u[k] = anp.array(a)
45
+
46
+ jac, = vmap(pullback, in_axes=0)(u)
47
+ jac = np.array(jac)
48
+
49
+ grad = {k: np.swapaxes(jac[I], 0, 1) for k, I in cols.items()}
50
+
51
+ return out, grad
@@ -0,0 +1,6 @@
1
+ import importlib
2
+ import sys
3
+
4
+ from pymoo.gradient import TOOLBOX
5
+
6
+ sys.modules[__name__] = importlib.import_module(TOOLBOX)
File without changes
@@ -0,0 +1,55 @@
1
+ import numpy as np
2
+
3
+ from pymoo.core.indicator import Indicator
4
+ from pymoo.util.misc import vectorized_cdist, at_least_2d_array
5
+
6
+
7
+ def euclidean_distance(a, b, norm=None):
8
+ return np.sqrt((((a - b) / norm) ** 2).sum(axis=1))
9
+
10
+
11
+ def modified_distance(z, a, norm=None):
12
+ d = a - z
13
+ d[d < 0] = 0
14
+ d = d / norm
15
+ return np.sqrt((d ** 2).sum(axis=1))
16
+
17
+
18
+ def derive_ideal_and_nadir_from_pf(pf, ideal=None, nadir=None):
19
+
20
+ # try to derive ideal and nadir if not already set and pf provided
21
+ if pf is not None:
22
+ if ideal is None:
23
+ ideal = np.min(pf, axis=0)
24
+ if nadir is None:
25
+ nadir = np.max(pf, axis=0)
26
+
27
+ return ideal, nadir
28
+
29
+
30
+ class DistanceIndicator(Indicator):
31
+
32
+ def __init__(self, pf, dist_func, axis, zero_to_one=False, ideal=None, nadir=None, norm_by_dist=False, **kwargs):
33
+
34
+ # the pareto front if necessary to calculate the indicator
35
+ pf = at_least_2d_array(pf, extend_as="row")
36
+ ideal, nadir = derive_ideal_and_nadir_from_pf(pf, ideal=ideal, nadir=nadir)
37
+
38
+ super().__init__(zero_to_one=zero_to_one, ideal=ideal, nadir=nadir, **kwargs)
39
+ self.dist_func = dist_func
40
+ self.axis = axis
41
+ self.norm_by_dist = norm_by_dist
42
+ self.pf = self.normalization.forward(pf)
43
+
44
+ def _do(self, F):
45
+
46
+ # a factor to normalize the distances by (1.0 disables that by default)
47
+ norm = 1.0
48
+
49
+ # if zero_to_one is disabled this can be used to normalize the distance calculation itself
50
+ if self.norm_by_dist:
51
+ assert self.ideal is not None and self.nadir is not None, "If norm_by_dist is enabled ideal and nadir must be set!"
52
+ norm = self.nadir - self.ideal
53
+
54
+ D = vectorized_cdist(self.pf, F, func_dist=self.dist_func, norm=norm)
55
+ return np.mean(np.min(D, axis=self.axis))
pymoo/indicators/gd.py ADDED
@@ -0,0 +1,7 @@
1
+ from pymoo.indicators.distance_indicator import DistanceIndicator, euclidean_distance
2
+
3
+
4
+ class GD(DistanceIndicator):
5
+
6
+ def __init__(self, pf, **kwargs):
7
+ super().__init__(pf, euclidean_distance, 0, **kwargs)
@@ -0,0 +1,7 @@
1
+ from pymoo.indicators.distance_indicator import DistanceIndicator, modified_distance
2
+
3
+
4
+ class GDPlus(DistanceIndicator):
5
+
6
+ def __init__(self, pf, **kwargs):
7
+ super().__init__(pf, modified_distance, 0, **kwargs)
@@ -0,0 +1,63 @@
1
+ import numpy as np
2
+
3
+ from pymoo.core.indicator import Indicator
4
+ from pymoo.indicators.distance_indicator import derive_ideal_and_nadir_from_pf
5
+ from pymoo.util.misc import at_least_2d_array
6
+ from pymoo.util.nds.non_dominated_sorting import NonDominatedSorting
7
+ from pymoo.vendor.hv import HyperVolume as _HyperVolume
8
+
9
+
10
+ class Hypervolume(Indicator):
11
+
12
+ def __init__(self, ref_point=None, pf=None, nds=True, norm_ref_point=True, ideal=None, nadir=None, **kwargs):
13
+
14
+ pf = at_least_2d_array(pf, extend_as="row")
15
+ ideal, nadir = derive_ideal_and_nadir_from_pf(pf, ideal=ideal, nadir=nadir)
16
+
17
+ super().__init__(ideal=ideal, nadir=nadir, **kwargs)
18
+ # self.normalization = ZeroToOneNormalization(ideal, nadir)
19
+
20
+ # whether the input should be checked for domination or not
21
+ self.nds = nds
22
+
23
+ # the reference point that shall be used - either derived from pf or provided
24
+ ref_point = ref_point
25
+ if ref_point is None:
26
+ if pf is not None:
27
+ ref_point = pf.max(axis=0)
28
+
29
+ # we also have to normalize the reference point to have the same scales
30
+ if norm_ref_point:
31
+ ref_point = self.normalization.forward(ref_point)
32
+
33
+ self.ref_point = ref_point
34
+ assert self.ref_point is not None, "For Hypervolume a reference point needs to be provided!"
35
+
36
+ def _do(self, F):
37
+ if self.nds:
38
+ non_dom = NonDominatedSorting().do(F, only_non_dominated_front=True)
39
+ F = np.copy(F[non_dom, :])
40
+
41
+ # calculate the hypervolume using a vendor library
42
+ hv = _HyperVolume(self.ref_point)
43
+ val = hv.compute(F)
44
+ return val
45
+
46
+
47
+ class HV(Hypervolume):
48
+ pass
49
+
50
+
51
+ def hvc_looped(ref_point, F, func):
52
+ hv = func(ref_point, F)
53
+
54
+ hvc = []
55
+
56
+ for k in range(len(F)):
57
+ v = np.full(len(F), True)
58
+ v[k] = False
59
+ _hv = func(ref_point, F[v])
60
+ hvc.append(hv - _hv)
61
+
62
+ hvc = np.array(hvc)
63
+ return hvc
@@ -0,0 +1,71 @@
1
+ import numpy as np
2
+
3
+ from pymoo.indicators.hv import hvc_looped
4
+ from pymoo.util.function_loader import load_function
5
+
6
+
7
+ def hv_exact(ref_point, F):
8
+ func = load_function("hv")
9
+ hv = func(ref_point, F)
10
+ return hv
11
+
12
+
13
+ def hvc_exact_loopwise(ref_point, F):
14
+ return hvc_looped(ref_point, F, hv_exact)
15
+
16
+
17
+ class DynamicHypervolume:
18
+
19
+ def __init__(self, ref_point, F=None, func_hv=None, func_hvc=None) -> None:
20
+ super().__init__()
21
+ self.ref_point = ref_point
22
+
23
+ self.func_hv = func_hv
24
+ self.func_hvc = func_hvc
25
+
26
+ self.n_dim = len(ref_point)
27
+ self.F = np.zeros((0, self.n_dim))
28
+
29
+ self.hv = 0.0
30
+ self.hvc = np.zeros(0)
31
+
32
+ if F is not None:
33
+ self.add(F)
34
+
35
+ def add(self, F):
36
+ assert len(F.shape) == 2, "The points to add must be a two-dimensional array."
37
+ assert F.shape[1] == self.n_dim, "The dimensions of the ref_point and points to add must be equal"
38
+ self.F = np.row_stack([self.F, F])
39
+ self.hv, self.hvc = self.calc()
40
+ return self
41
+
42
+ def delete(self, k):
43
+ assert k < len(self.F)
44
+ self.F = np.delete(self.F, k, axis=0)
45
+ self.hv, self.hvc = self.calc()
46
+ return self
47
+
48
+ def calc(self):
49
+ return self._calc(self.ref_point, self.F)
50
+
51
+ # if len(self.F) == 0:
52
+ # return 0.0, np.zeros(0)
53
+ # else:
54
+ # return self._calc(self.ref_point, self.F)
55
+
56
+ def _calc(self, ref_point, F):
57
+ hv = None
58
+ if self.func_hv is not None:
59
+ hv = self.func_hv(ref_point, F)
60
+
61
+ hvc = None
62
+ if self.func_hvc is not None:
63
+ hvc = self.func_hvc(ref_point, F)
64
+
65
+ return hv, hvc
66
+
67
+
68
+ class ExactHypervolume(DynamicHypervolume):
69
+
70
+ def __init__(self, ref_point, func_hv=hv_exact, func_hvc=hvc_exact_loopwise, **kwargs) -> None:
71
+ super().__init__(ref_point, func_hv=func_hv, func_hvc=func_hvc, **kwargs)
@@ -0,0 +1,102 @@
1
+ import numpy as np
2
+
3
+ from pymoo.indicators.hv.exact import ExactHypervolume
4
+
5
+
6
+ def hvc_2d_slow(ref_point, F):
7
+ n = len(F)
8
+
9
+ I = np.lexsort((-F[:, 1], F[:, 0]))
10
+
11
+ V = np.row_stack([ref_point, F[I], ref_point])
12
+
13
+ hvi = np.zeros(n)
14
+
15
+ for k in range(1, n + 1):
16
+ height = V[k - 1, 1] - V[k, 1]
17
+ width = V[k + 1, 0] - V[k, 0]
18
+
19
+ hvi[I[k - 1]] = width * height
20
+
21
+ return np.array(hvi)
22
+
23
+
24
+ def hvc_2d_fast(ref_point, F_sorted, left=None, right=None):
25
+ if left is None:
26
+ left = [F_sorted[0, 0], ref_point[1]]
27
+
28
+ if right is None:
29
+ right = [ref_point[0], F_sorted[-1, 1]]
30
+
31
+ V = np.row_stack([left, F_sorted, right])
32
+ height = (V[:-1, 1] - V[1:, 1])[:-1]
33
+ width = (V[1:, 0] - V[:-1, 0])[1:]
34
+
35
+ hvc = height * width
36
+ return hvc
37
+
38
+
39
+ def hv_2d_fast(ref_point, F_sorted):
40
+ V = np.row_stack([ref_point, F_sorted])
41
+ height = (V[:-1, 1] - V[1:, 1])
42
+ width = ref_point[0] - V[1:, 0]
43
+ return (height * width).sum()
44
+
45
+
46
+ class ExactHypervolume2D(ExactHypervolume):
47
+
48
+ def __init__(self, ref_point, **kwargs) -> None:
49
+ assert len(ref_point) == 2, "This hypervolume calculation only works in 2 dimensions."
50
+ super().__init__(ref_point, func_hv=hv_2d_fast, func_hvc=hvc_2d_fast, **kwargs)
51
+ self.S = None
52
+ self.I = None
53
+
54
+ def _calc(self, ref_point, F):
55
+ if len(F) == 0:
56
+ self.I, self.S = [], []
57
+ return 0.0, np.zeros(0)
58
+
59
+ F = np.minimum(self.ref_point, self.F)
60
+ I = np.lexsort((-F[:, 1], F[:, 0]))
61
+ S = np.argsort(I)
62
+
63
+ hv, hvc = super()._calc(ref_point, F[I])
64
+ hvc = hvc[S]
65
+ self.I, self.S = I, S
66
+
67
+ return hv, hvc
68
+
69
+ # this very efficiently just recomputes hvc of the points necessary
70
+ # however has not shown to be much faster because of reindexing
71
+ # def delete(self, k):
72
+ # assert k < len(self.F)
73
+ #
74
+ # F, I, S, hv, hvc = self.F, self.I, self.S, self.hv, self.hvc
75
+ #
76
+ # hv -= hvc[k]
77
+ #
78
+ # i = S[k]
79
+ #
80
+ # S = np.delete(S, k, axis=0)
81
+ # S[S > i] -= 1
82
+ #
83
+ # I = np.delete(I, i, axis=0)
84
+ # I[I > k] -= 1
85
+ #
86
+ # F = np.delete(F, k, axis=0)
87
+ # hvc = np.delete(self.hvc, k, axis=0)
88
+ #
89
+ # v = [I[i] if 0 <= i < len(I) else None for i in np.arange(i-2, i+2)]
90
+ # left, middle, right = v[0], v[1:-1], v[-1]
91
+ #
92
+ # middle = [e for e in middle if e is not None]
93
+ #
94
+ # if len(middle) > 0:
95
+ #
96
+ # hvc[middle] = hvc_2d_fast(self.ref_point,
97
+ # F[middle],
98
+ # left=F[left] if left is not None else None,
99
+ # right=F[right] if right is not None else None,
100
+ # )
101
+ #
102
+ # self.F, self.I, self.S, self.hv, self.hvc = F, I, S, hv, hvc
@@ -0,0 +1,74 @@
1
+ import numpy as np
2
+
3
+ from pymoo.indicators.hv.exact import DynamicHypervolume
4
+
5
+
6
+ def alpha(N, k):
7
+ alpha = np.zeros(N+1)
8
+
9
+ for i in range(1, N + 1):
10
+ alpha[i] = np.prod([(k - j) / (N - j) for j in range(1, i)]) / i
11
+
12
+ return alpha
13
+
14
+
15
+ def hv_monte_carlo(dom, V, n_dom=None):
16
+ N, n_samples = dom.shape
17
+ if n_dom is None:
18
+ n_dom = dom.sum(axis=0)
19
+
20
+ a = alpha(N, N)
21
+ hv = sum([a[n_dom[dom[i]]].sum() for i in range(N)]) / n_samples * V
22
+ return hv
23
+
24
+
25
+ def hvc_monte_carlo(dom, V, n_dom=None, k=1):
26
+ N, n_samples = dom.shape
27
+ if n_dom is None:
28
+ n_dom = dom.sum(axis=0)
29
+
30
+ a = alpha(N, k)
31
+ hvc = np.array([(a[n_dom[dom[i]]].sum() / n_samples * V).sum() for i in range(N)])
32
+ return hvc
33
+
34
+
35
+ class ApproximateMonteCarloHypervolume(DynamicHypervolume):
36
+
37
+ def __init__(self, ref_point, n_samples=10000, n_exclusive=1, **kwargs) -> None:
38
+ self.n_samples = n_samples
39
+ self.n_exclusive = n_exclusive
40
+
41
+ self.V = None
42
+ self.dom = None
43
+
44
+ super().__init__(ref_point, **kwargs)
45
+
46
+ def _calc(self, ref_point, F):
47
+ (N, M) = F.shape
48
+
49
+ ideal = F.min(axis=0)
50
+ V = np.prod(ref_point - ideal)
51
+
52
+ S = np.random.uniform(low=ideal, high=ref_point, size=(self.n_samples, M))
53
+
54
+ dom = np.array([np.all(F[i] <= S, axis=1) for i in range(N)])
55
+
56
+ n_dom = dom.sum(axis=0)
57
+ hv = hv_monte_carlo(dom, V, n_dom=n_dom)
58
+ hvc = hvc_monte_carlo(dom, V, n_dom=n_dom, k=self.n_exclusive)
59
+
60
+ self.V = V
61
+ self.dom = dom
62
+
63
+ return hv, hvc
64
+
65
+ def delete(self, k):
66
+ self.F = np.delete(self.F, k, axis=0)
67
+ self.dom = np.delete(self.dom, k, axis=0)
68
+
69
+ self.hv -= self.hvc[k]
70
+
71
+ V, dom = self.V, self.dom
72
+ n_dom = dom.sum(axis=0)
73
+ self.hvc = hvc_monte_carlo(dom, V, n_dom=n_dom, k=self.n_exclusive)
74
+
@@ -0,0 +1,7 @@
1
+ from pymoo.indicators.distance_indicator import DistanceIndicator, euclidean_distance
2
+
3
+
4
+ class IGD(DistanceIndicator):
5
+
6
+ def __init__(self, pf, **kwargs):
7
+ super().__init__(pf, euclidean_distance, 1, **kwargs)
@@ -0,0 +1,7 @@
1
+ from pymoo.indicators.distance_indicator import DistanceIndicator, modified_distance
2
+
3
+
4
+ class IGDPlus(DistanceIndicator):
5
+
6
+ def __init__(self, pf, **kwargs):
7
+ super().__init__(pf, modified_distance, 1, **kwargs)
@@ -0,0 +1,151 @@
1
+ import numpy as np
2
+
3
+ from pymoo.core.individual import calc_cv
4
+
5
+
6
+ class KKTPM:
7
+
8
+ def calc(self, X, problem, ideal=None, utopian_eps=1e-4, rho=1e-3):
9
+ """
10
+
11
+ Returns the Karush-Kuhn-Tucker Approximate Measure.
12
+
13
+ Parameters
14
+ ----------
15
+ X : np.array
16
+
17
+ problem : pymoo.core.problem
18
+ ideal : np.array
19
+ The ideal point if not in the problem defined or intentionally overwritten.
20
+ utopian_eps : float
21
+ The epsilon used for decrease the ideal point to get the utopian point.
22
+ rho : float
23
+ Since augmented achievement scalarization function is used the F for all other weights
24
+ - here rho - needs to be defined.
25
+
26
+ Returns
27
+ -------
28
+
29
+ """
30
+
31
+ # the final result to be returned
32
+ kktpm = np.full((X.shape[0], 1), np.inf)
33
+ fval = np.full((X.shape[0], 1), np.inf)
34
+
35
+ # set the ideal point for normalization
36
+ z = ideal
37
+
38
+ # if not provided take the one defined in the problem
39
+ if z is None:
40
+ z = problem.ideal_point()
41
+ z -= utopian_eps
42
+
43
+ # for convenience get the counts directly
44
+ n_solutions, n_var, n_obj, n_ieq_constr = X.shape[0], problem.n_var, problem.n_obj, problem.n_ieq_constr
45
+
46
+ F, G, dF, dG = problem.evaluate(X, return_values_of=["F", "G", "dF", "dG"])
47
+ CV = calc_cv(G=G)
48
+
49
+ # loop through each solution to be considered
50
+ for i in range(n_solutions):
51
+
52
+ # get the corresponding values for this solution
53
+ x, f, cv, df = X[i, :], F[i, :], CV[i], dF[i, :].swapaxes(1, 0)
54
+ if n_ieq_constr > 0:
55
+ g, dg = G[i, :], dG[i].T
56
+
57
+ # if the solution that is provided is infeasible
58
+ if cv > 0:
59
+ _kktpm = 1 + cv
60
+ _fval = None
61
+
62
+ else:
63
+
64
+ w = np.sqrt(np.sum(np.power(f - z, 2))) / (f - z)
65
+ a_m = (df * w + (rho * np.sum(df * w, axis=1))[:, None]).T
66
+
67
+ A = np.ones((problem.n_obj, problem.n_obj)) + a_m @ a_m.T
68
+ b = np.ones(problem.n_obj)
69
+
70
+ if n_ieq_constr > 0:
71
+ # a_j is just the transpose of the differential of constraints
72
+ a_j = dg.T
73
+
74
+ # part of the matrix for additional constraints
75
+ gsq = np.zeros((n_ieq_constr, n_ieq_constr))
76
+ np.fill_diagonal(gsq, g * g)
77
+
78
+ # now add the constraints to the optimization problem
79
+ A = np.vstack([np.hstack([A, a_m @ a_j.T]), np.hstack([a_j @ a_m.T, a_j @ a_j.T + gsq])])
80
+ b = np.hstack([b, np.zeros(n_ieq_constr)])
81
+
82
+ method = "qr"
83
+ u = solve(A, b, method=method)
84
+
85
+ # until all the lagrange multiplier are positive
86
+ while np.any(u < 0):
87
+
88
+ # go through one by one
89
+ for j in range(len(u)):
90
+
91
+ # if a lagrange multiplier is negative - we need to fix it
92
+ if u[j] < 0:
93
+ # modify the optimization problem
94
+ A[j, :], A[:, j], A[j, j] = 0, 0, 1
95
+ b[j] = 0
96
+
97
+ # resolve the problem and redefine u. for sure all preview u[j] are positive now
98
+ u = solve(A, b, method=method)
99
+
100
+ # split up the lagrange multiplier for objective and not
101
+ u_m, u_j = u[:n_obj], u[n_obj:]
102
+
103
+ if n_ieq_constr > 0:
104
+ _kktpm = (1 - np.sum(u_m)) ** 2 + np.sum((np.vstack([a_m, a_j]).T @ u) ** 2)
105
+ _fval = _kktpm + np.sum((u_j * g.T) ** 2)
106
+ else:
107
+ _kktpm = (1 - np.sum(u_m)) ** 2 + np.sum((a_m.T @ u) ** 2)
108
+ _fval = _kktpm
109
+
110
+ ujgj = -g @ u_j
111
+ if np.sum(u_m) + ujgj * (1 + ujgj) > 1:
112
+ adjusted_kktpm = - (u_j @ g.T)
113
+ projected_kktpm = (_kktpm * g @ g.T - g @ u_j) / (1 + g @ g.T)
114
+ _kktpm = (_kktpm + adjusted_kktpm + projected_kktpm) / 3
115
+
116
+ # assign to the values to be returned
117
+ kktpm[i] = _kktpm
118
+ fval[i] = _fval
119
+
120
+ return kktpm[:, 0]
121
+
122
+
123
+ def solve(A, b, method="elim"):
124
+ if method == "elim":
125
+ return np.linalg.solve(A, b)
126
+
127
+ elif method == "qr":
128
+ Q, R = np.linalg.qr(A)
129
+ y = np.dot(Q.T, b)
130
+ return np.linalg.solve(R, y)
131
+
132
+ elif method == "svd":
133
+ U, s, V = np.linalg.svd(A) # SVD decomposition of A
134
+ A_inv = np.dot(np.dot(V.T, np.linalg.inv(np.diag(s))), U.T)
135
+ return A_inv @ b
136
+
137
+
138
+ if __name__ == '__main__':
139
+ from pymoo.problems import get_problem
140
+ from pymoo.gradient.automatic import AutomaticDifferentiation
141
+
142
+ from pymoo.constraints.from_bounds import ConstraintsFromBounds
143
+ problem = ConstraintsFromBounds(AutomaticDifferentiation(get_problem("zdt2", n_var=30)))
144
+
145
+ # X = (0.5 * np.ones(10))[None, :]
146
+ X = np.array(
147
+ [0.394876, 0.963263, 0.173956, 0.126330, 0.135079, 0.505662, 0.021525, 0.947970, 0.827115, 0.015019, 0.176196,
148
+ 0.332064, 0.130997, 0.809491, 0.344737, 0.940107, 0.582014, 0.878832, 0.844734, 0.905392, 0.459880, 0.546347,
149
+ 0.798604, 0.285719, 0.490254, 0.599110, 0.015533, 0.593481, 0.433676, 0.807361])
150
+
151
+ print(KKTPM().calc(X[None, :], problem))
@@ -0,0 +1,55 @@
1
+ import numpy as np
2
+
3
+ from pymoo.core.callback import Callback
4
+ from pymoo.indicators.igd import IGD
5
+
6
+
7
+ class MIGD(Callback):
8
+
9
+ def __init__(self, reevaluate=True) -> None:
10
+ """
11
+ Mean Inverted Generational Distance (MIGD)
12
+
13
+ For dynamic optimization problems the performance metric needs to involve the IGD value over time as the
14
+ problem is changing. Thus, the performance needs to be evaluated in each iteration for which
15
+ defining a callback is ideal.
16
+
17
+ """
18
+
19
+ super().__init__()
20
+
21
+ # whether the MIGD should be based on reevaluated solutions
22
+ self.reevaluate = reevaluate
23
+
24
+ # the list where each of the recordings are stored: timesteps and igd
25
+ self.records = []
26
+
27
+ def update(self, algorithm, **kwargs):
28
+
29
+ # the problem to be solved
30
+ problem = algorithm.problem
31
+ assert problem.n_constr == 0, "The current implementation only works for unconstrained problems!"
32
+
33
+ # the current time
34
+ t = problem.time
35
+
36
+ # the current pareto-front of the problem (at the specific time step)
37
+ pf = problem.pareto_front()
38
+
39
+ # the current population of the algorithm
40
+ pop = algorithm.pop
41
+
42
+ # if the callback should reevaluate to match the current time step and avoid deprecated values
43
+ if self.reevaluate:
44
+ X = pop.get("X")
45
+ F = problem.evaluate(X, return_values_of=["F"])
46
+ else:
47
+ F = pop.get("F")
48
+
49
+ # calculate the current igd values
50
+ igd = IGD(pf).do(F)
51
+
52
+ self.records.append((t, igd))
53
+
54
+ def value(self):
55
+ return np.array([igd for _, igd in self.records]).mean()