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

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

Potentially problematic release.


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

Files changed (328) hide show
  1. pymoo/__init__.py +3 -0
  2. pymoo/algorithms/__init__.py +0 -0
  3. pymoo/algorithms/base/__init__.py +0 -0
  4. pymoo/algorithms/base/bracket.py +38 -0
  5. pymoo/algorithms/base/genetic.py +109 -0
  6. pymoo/algorithms/base/line.py +62 -0
  7. pymoo/algorithms/base/local.py +39 -0
  8. pymoo/algorithms/base/meta.py +79 -0
  9. pymoo/algorithms/hyperparameters.py +89 -0
  10. pymoo/algorithms/moo/__init__.py +0 -0
  11. pymoo/algorithms/moo/age.py +310 -0
  12. pymoo/algorithms/moo/age2.py +194 -0
  13. pymoo/algorithms/moo/ctaea.py +298 -0
  14. pymoo/algorithms/moo/dnsga2.py +76 -0
  15. pymoo/algorithms/moo/kgb.py +446 -0
  16. pymoo/algorithms/moo/moead.py +183 -0
  17. pymoo/algorithms/moo/nsga2.py +113 -0
  18. pymoo/algorithms/moo/nsga3.py +358 -0
  19. pymoo/algorithms/moo/pinsga2.py +370 -0
  20. pymoo/algorithms/moo/rnsga2.py +188 -0
  21. pymoo/algorithms/moo/rnsga3.py +246 -0
  22. pymoo/algorithms/moo/rvea.py +214 -0
  23. pymoo/algorithms/moo/sms.py +195 -0
  24. pymoo/algorithms/moo/spea2.py +190 -0
  25. pymoo/algorithms/moo/unsga3.py +47 -0
  26. pymoo/algorithms/soo/__init__.py +0 -0
  27. pymoo/algorithms/soo/convex/__init__.py +0 -0
  28. pymoo/algorithms/soo/nonconvex/__init__.py +0 -0
  29. pymoo/algorithms/soo/nonconvex/brkga.py +161 -0
  30. pymoo/algorithms/soo/nonconvex/cmaes.py +554 -0
  31. pymoo/algorithms/soo/nonconvex/de.py +279 -0
  32. pymoo/algorithms/soo/nonconvex/direct.py +149 -0
  33. pymoo/algorithms/soo/nonconvex/es.py +203 -0
  34. pymoo/algorithms/soo/nonconvex/g3pcx.py +94 -0
  35. pymoo/algorithms/soo/nonconvex/ga.py +93 -0
  36. pymoo/algorithms/soo/nonconvex/ga_niching.py +223 -0
  37. pymoo/algorithms/soo/nonconvex/isres.py +74 -0
  38. pymoo/algorithms/soo/nonconvex/nelder.py +251 -0
  39. pymoo/algorithms/soo/nonconvex/optuna.py +80 -0
  40. pymoo/algorithms/soo/nonconvex/pattern.py +183 -0
  41. pymoo/algorithms/soo/nonconvex/pso.py +399 -0
  42. pymoo/algorithms/soo/nonconvex/pso_ep.py +297 -0
  43. pymoo/algorithms/soo/nonconvex/random_search.py +25 -0
  44. pymoo/algorithms/soo/nonconvex/sres.py +56 -0
  45. pymoo/algorithms/soo/univariate/__init__.py +0 -0
  46. pymoo/algorithms/soo/univariate/backtracking.py +59 -0
  47. pymoo/algorithms/soo/univariate/exp.py +46 -0
  48. pymoo/algorithms/soo/univariate/golden.py +65 -0
  49. pymoo/algorithms/soo/univariate/quadr_interp.py +81 -0
  50. pymoo/algorithms/soo/univariate/wolfe.py +163 -0
  51. pymoo/config.py +33 -0
  52. pymoo/constraints/__init__.py +3 -0
  53. pymoo/constraints/adaptive.py +62 -0
  54. pymoo/constraints/as_obj.py +56 -0
  55. pymoo/constraints/as_penalty.py +41 -0
  56. pymoo/constraints/eps.py +26 -0
  57. pymoo/constraints/from_bounds.py +36 -0
  58. pymoo/core/__init__.py +0 -0
  59. pymoo/core/algorithm.py +394 -0
  60. pymoo/core/callback.py +38 -0
  61. pymoo/core/crossover.py +77 -0
  62. pymoo/core/decision_making.py +102 -0
  63. pymoo/core/decomposition.py +76 -0
  64. pymoo/core/duplicate.py +163 -0
  65. pymoo/core/evaluator.py +116 -0
  66. pymoo/core/indicator.py +34 -0
  67. pymoo/core/individual.py +784 -0
  68. pymoo/core/infill.py +64 -0
  69. pymoo/core/initialization.py +42 -0
  70. pymoo/core/mating.py +39 -0
  71. pymoo/core/meta.py +21 -0
  72. pymoo/core/mixed.py +165 -0
  73. pymoo/core/mutation.py +44 -0
  74. pymoo/core/operator.py +40 -0
  75. pymoo/core/parameters.py +134 -0
  76. pymoo/core/plot.py +210 -0
  77. pymoo/core/population.py +180 -0
  78. pymoo/core/problem.py +460 -0
  79. pymoo/core/recorder.py +99 -0
  80. pymoo/core/repair.py +23 -0
  81. pymoo/core/replacement.py +96 -0
  82. pymoo/core/result.py +52 -0
  83. pymoo/core/sampling.py +43 -0
  84. pymoo/core/selection.py +61 -0
  85. pymoo/core/solution.py +10 -0
  86. pymoo/core/survival.py +103 -0
  87. pymoo/core/termination.py +70 -0
  88. pymoo/core/variable.py +399 -0
  89. pymoo/cython/__init__.py +0 -0
  90. pymoo/cython/calc_perpendicular_distance.cpython-312-x86_64-linux-gnu.so +0 -0
  91. pymoo/cython/calc_perpendicular_distance.pyx +67 -0
  92. pymoo/cython/decomposition.cpython-312-x86_64-linux-gnu.so +0 -0
  93. pymoo/cython/decomposition.pyx +165 -0
  94. pymoo/cython/hv.cpython-312-x86_64-linux-gnu.so +0 -0
  95. pymoo/cython/hv.pyx +18 -0
  96. pymoo/cython/info.cpython-312-x86_64-linux-gnu.so +0 -0
  97. pymoo/cython/info.pyx +5 -0
  98. pymoo/cython/mnn.cpython-312-x86_64-linux-gnu.so +0 -0
  99. pymoo/cython/mnn.pyx +273 -0
  100. pymoo/cython/non_dominated_sorting.cpython-312-x86_64-linux-gnu.so +0 -0
  101. pymoo/cython/non_dominated_sorting.pyx +645 -0
  102. pymoo/cython/pruning_cd.cpython-312-x86_64-linux-gnu.so +0 -0
  103. pymoo/cython/pruning_cd.pyx +197 -0
  104. pymoo/cython/stochastic_ranking.cpython-312-x86_64-linux-gnu.so +0 -0
  105. pymoo/cython/stochastic_ranking.pyx +49 -0
  106. pymoo/cython/utils.pxd +129 -0
  107. pymoo/cython/vendor/__init__.py +0 -0
  108. pymoo/cython/vendor/hypervolume.cpp +1621 -0
  109. pymoo/cython/vendor/hypervolume.h +63 -0
  110. pymoo/decomposition/__init__.py +0 -0
  111. pymoo/decomposition/aasf.py +24 -0
  112. pymoo/decomposition/asf.py +10 -0
  113. pymoo/decomposition/pbi.py +13 -0
  114. pymoo/decomposition/perp_dist.py +13 -0
  115. pymoo/decomposition/tchebicheff.py +11 -0
  116. pymoo/decomposition/util.py +13 -0
  117. pymoo/decomposition/weighted_sum.py +8 -0
  118. pymoo/docs.py +187 -0
  119. pymoo/experimental/__init__.py +0 -0
  120. pymoo/experimental/algorithms/__init__.py +0 -0
  121. pymoo/experimental/algorithms/gde3.py +57 -0
  122. pymoo/gradient/__init__.py +21 -0
  123. pymoo/gradient/automatic.py +57 -0
  124. pymoo/gradient/grad_autograd.py +105 -0
  125. pymoo/gradient/grad_complex.py +35 -0
  126. pymoo/gradient/grad_jax.py +51 -0
  127. pymoo/gradient/toolbox/__init__.py +6 -0
  128. pymoo/indicators/__init__.py +0 -0
  129. pymoo/indicators/distance_indicator.py +55 -0
  130. pymoo/indicators/gd.py +7 -0
  131. pymoo/indicators/gd_plus.py +7 -0
  132. pymoo/indicators/hv/__init__.py +63 -0
  133. pymoo/indicators/hv/exact.py +71 -0
  134. pymoo/indicators/hv/exact_2d.py +102 -0
  135. pymoo/indicators/hv/monte_carlo.py +74 -0
  136. pymoo/indicators/igd.py +7 -0
  137. pymoo/indicators/igd_plus.py +7 -0
  138. pymoo/indicators/kktpm.py +151 -0
  139. pymoo/indicators/migd.py +55 -0
  140. pymoo/indicators/rmetric.py +203 -0
  141. pymoo/indicators/spacing.py +52 -0
  142. pymoo/mcdm/__init__.py +0 -0
  143. pymoo/mcdm/compromise_programming.py +19 -0
  144. pymoo/mcdm/high_tradeoff.py +40 -0
  145. pymoo/mcdm/pseudo_weights.py +32 -0
  146. pymoo/operators/__init__.py +0 -0
  147. pymoo/operators/control.py +187 -0
  148. pymoo/operators/crossover/__init__.py +0 -0
  149. pymoo/operators/crossover/binx.py +45 -0
  150. pymoo/operators/crossover/dex.py +122 -0
  151. pymoo/operators/crossover/erx.py +162 -0
  152. pymoo/operators/crossover/expx.py +51 -0
  153. pymoo/operators/crossover/hux.py +37 -0
  154. pymoo/operators/crossover/nox.py +13 -0
  155. pymoo/operators/crossover/ox.py +84 -0
  156. pymoo/operators/crossover/pcx.py +82 -0
  157. pymoo/operators/crossover/pntx.py +49 -0
  158. pymoo/operators/crossover/sbx.py +125 -0
  159. pymoo/operators/crossover/spx.py +5 -0
  160. pymoo/operators/crossover/ux.py +20 -0
  161. pymoo/operators/mutation/__init__.py +0 -0
  162. pymoo/operators/mutation/bitflip.py +17 -0
  163. pymoo/operators/mutation/gauss.py +58 -0
  164. pymoo/operators/mutation/inversion.py +42 -0
  165. pymoo/operators/mutation/nom.py +7 -0
  166. pymoo/operators/mutation/pm.py +94 -0
  167. pymoo/operators/mutation/rm.py +23 -0
  168. pymoo/operators/repair/__init__.py +0 -0
  169. pymoo/operators/repair/bounce_back.py +32 -0
  170. pymoo/operators/repair/bounds_repair.py +95 -0
  171. pymoo/operators/repair/inverse_penalty.py +89 -0
  172. pymoo/operators/repair/rounding.py +18 -0
  173. pymoo/operators/repair/to_bound.py +31 -0
  174. pymoo/operators/repair/vtype.py +11 -0
  175. pymoo/operators/sampling/__init__.py +0 -0
  176. pymoo/operators/sampling/lhs.py +73 -0
  177. pymoo/operators/sampling/rnd.py +50 -0
  178. pymoo/operators/selection/__init__.py +0 -0
  179. pymoo/operators/selection/rnd.py +72 -0
  180. pymoo/operators/selection/tournament.py +76 -0
  181. pymoo/operators/survival/__init__.py +0 -0
  182. pymoo/operators/survival/rank_and_crowding/__init__.py +1 -0
  183. pymoo/operators/survival/rank_and_crowding/classes.py +209 -0
  184. pymoo/operators/survival/rank_and_crowding/metrics.py +208 -0
  185. pymoo/optimize.py +72 -0
  186. pymoo/problems/__init__.py +157 -0
  187. pymoo/problems/dyn.py +47 -0
  188. pymoo/problems/dynamic/__init__.py +0 -0
  189. pymoo/problems/dynamic/cec2015.py +108 -0
  190. pymoo/problems/dynamic/df.py +452 -0
  191. pymoo/problems/dynamic/misc.py +167 -0
  192. pymoo/problems/functional.py +48 -0
  193. pymoo/problems/many/__init__.py +5 -0
  194. pymoo/problems/many/cdtlz.py +159 -0
  195. pymoo/problems/many/dcdtlz.py +88 -0
  196. pymoo/problems/many/dtlz.py +264 -0
  197. pymoo/problems/many/wfg.py +550 -0
  198. pymoo/problems/multi/__init__.py +14 -0
  199. pymoo/problems/multi/bnh.py +34 -0
  200. pymoo/problems/multi/carside.py +48 -0
  201. pymoo/problems/multi/clutch.py +104 -0
  202. pymoo/problems/multi/csi.py +55 -0
  203. pymoo/problems/multi/ctp.py +198 -0
  204. pymoo/problems/multi/dascmop.py +213 -0
  205. pymoo/problems/multi/kursawe.py +25 -0
  206. pymoo/problems/multi/modact.py +68 -0
  207. pymoo/problems/multi/mw.py +400 -0
  208. pymoo/problems/multi/omnitest.py +48 -0
  209. pymoo/problems/multi/osy.py +32 -0
  210. pymoo/problems/multi/srn.py +28 -0
  211. pymoo/problems/multi/sympart.py +94 -0
  212. pymoo/problems/multi/tnk.py +24 -0
  213. pymoo/problems/multi/truss2d.py +83 -0
  214. pymoo/problems/multi/welded_beam.py +41 -0
  215. pymoo/problems/multi/wrm.py +36 -0
  216. pymoo/problems/multi/zdt.py +151 -0
  217. pymoo/problems/multi_to_single.py +22 -0
  218. pymoo/problems/single/__init__.py +12 -0
  219. pymoo/problems/single/ackley.py +24 -0
  220. pymoo/problems/single/cantilevered_beam.py +34 -0
  221. pymoo/problems/single/flowshop_scheduling.py +112 -0
  222. pymoo/problems/single/g.py +874 -0
  223. pymoo/problems/single/griewank.py +18 -0
  224. pymoo/problems/single/himmelblau.py +15 -0
  225. pymoo/problems/single/knapsack.py +48 -0
  226. pymoo/problems/single/mopta08.py +26 -0
  227. pymoo/problems/single/multimodal.py +20 -0
  228. pymoo/problems/single/pressure_vessel.py +30 -0
  229. pymoo/problems/single/rastrigin.py +20 -0
  230. pymoo/problems/single/rosenbrock.py +22 -0
  231. pymoo/problems/single/schwefel.py +18 -0
  232. pymoo/problems/single/simple.py +13 -0
  233. pymoo/problems/single/sphere.py +19 -0
  234. pymoo/problems/single/traveling_salesman.py +79 -0
  235. pymoo/problems/single/zakharov.py +19 -0
  236. pymoo/problems/static.py +14 -0
  237. pymoo/problems/util.py +42 -0
  238. pymoo/problems/zero_to_one.py +27 -0
  239. pymoo/termination/__init__.py +23 -0
  240. pymoo/termination/collection.py +12 -0
  241. pymoo/termination/cv.py +48 -0
  242. pymoo/termination/default.py +45 -0
  243. pymoo/termination/delta.py +64 -0
  244. pymoo/termination/fmin.py +16 -0
  245. pymoo/termination/ftol.py +144 -0
  246. pymoo/termination/indicator.py +49 -0
  247. pymoo/termination/max_eval.py +14 -0
  248. pymoo/termination/max_gen.py +15 -0
  249. pymoo/termination/max_time.py +20 -0
  250. pymoo/termination/robust.py +34 -0
  251. pymoo/termination/xtol.py +33 -0
  252. pymoo/util/__init__.py +0 -0
  253. pymoo/util/archive.py +150 -0
  254. pymoo/util/cache.py +29 -0
  255. pymoo/util/clearing.py +82 -0
  256. pymoo/util/display/__init__.py +0 -0
  257. pymoo/util/display/column.py +52 -0
  258. pymoo/util/display/display.py +34 -0
  259. pymoo/util/display/multi.py +96 -0
  260. pymoo/util/display/output.py +53 -0
  261. pymoo/util/display/progress.py +54 -0
  262. pymoo/util/display/single.py +67 -0
  263. pymoo/util/dominator.py +67 -0
  264. pymoo/util/function_loader.py +129 -0
  265. pymoo/util/hv.py +23 -0
  266. pymoo/util/matlab_engine.py +39 -0
  267. pymoo/util/misc.py +460 -0
  268. pymoo/util/mnn.py +70 -0
  269. pymoo/util/nds/__init__.py +0 -0
  270. pymoo/util/nds/dominance_degree_non_dominated_sort.py +159 -0
  271. pymoo/util/nds/efficient_non_dominated_sort.py +152 -0
  272. pymoo/util/nds/fast_non_dominated_sort.py +70 -0
  273. pymoo/util/nds/naive_non_dominated_sort.py +36 -0
  274. pymoo/util/nds/non_dominated_sorting.py +67 -0
  275. pymoo/util/nds/tree_based_non_dominated_sort.py +133 -0
  276. pymoo/util/normalization.py +312 -0
  277. pymoo/util/optimum.py +42 -0
  278. pymoo/util/plotting.py +177 -0
  279. pymoo/util/pruning_cd.py +89 -0
  280. pymoo/util/randomized_argsort.py +60 -0
  281. pymoo/util/ref_dirs/__init__.py +24 -0
  282. pymoo/util/ref_dirs/construction.py +88 -0
  283. pymoo/util/ref_dirs/das_dennis.py +52 -0
  284. pymoo/util/ref_dirs/energy.py +319 -0
  285. pymoo/util/ref_dirs/energy_layer.py +119 -0
  286. pymoo/util/ref_dirs/genetic_algorithm.py +63 -0
  287. pymoo/util/ref_dirs/incremental.py +68 -0
  288. pymoo/util/ref_dirs/misc.py +128 -0
  289. pymoo/util/ref_dirs/optimizer.py +59 -0
  290. pymoo/util/ref_dirs/performance.py +162 -0
  291. pymoo/util/ref_dirs/reduction.py +85 -0
  292. pymoo/util/ref_dirs/sample_and_map.py +24 -0
  293. pymoo/util/reference_direction.py +260 -0
  294. pymoo/util/remote.py +55 -0
  295. pymoo/util/roulette.py +27 -0
  296. pymoo/util/running_metric.py +128 -0
  297. pymoo/util/sliding_window.py +25 -0
  298. pymoo/util/stochastic_ranking.py +32 -0
  299. pymoo/util/value_functions.py +719 -0
  300. pymoo/util/vectors.py +40 -0
  301. pymoo/util/vf_dominator.py +99 -0
  302. pymoo/vendor/__init__.py +0 -0
  303. pymoo/vendor/cec2018.py +398 -0
  304. pymoo/vendor/gta.py +617 -0
  305. pymoo/vendor/hv.py +267 -0
  306. pymoo/vendor/vendor_cmaes.py +412 -0
  307. pymoo/vendor/vendor_coco.py +81 -0
  308. pymoo/vendor/vendor_scipy.py +232 -0
  309. pymoo/version.py +1 -0
  310. pymoo/visualization/__init__.py +8 -0
  311. pymoo/visualization/fitness_landscape.py +127 -0
  312. pymoo/visualization/heatmap.py +123 -0
  313. pymoo/visualization/pcp.py +120 -0
  314. pymoo/visualization/petal.py +91 -0
  315. pymoo/visualization/radar.py +108 -0
  316. pymoo/visualization/radviz.py +68 -0
  317. pymoo/visualization/scatter.py +150 -0
  318. pymoo/visualization/star_coordinate.py +75 -0
  319. pymoo/visualization/util.py +123 -0
  320. pymoo/visualization/video/__init__.py +0 -0
  321. pymoo/visualization/video/callback_video.py +82 -0
  322. pymoo/visualization/video/one_var_one_obj.py +57 -0
  323. pymoo/visualization/video/two_var_one_obj.py +62 -0
  324. pymoo-0.6.1.5.dev0.dist-info/METADATA +187 -0
  325. pymoo-0.6.1.5.dev0.dist-info/RECORD +328 -0
  326. pymoo-0.6.1.5.dev0.dist-info/WHEEL +6 -0
  327. pymoo-0.6.1.5.dev0.dist-info/licenses/LICENSE +191 -0
  328. pymoo-0.6.1.5.dev0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,88 @@
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):
43
+
44
+ self.X = np.eye(self.n_dim)
45
+
46
+ while len(self.X) < self.n_points:
47
+ x = self.next()
48
+ self.X = np.row_stack([self.X, x])
49
+
50
+ if self.verbose:
51
+ print(len(self.X), "x", x)
52
+
53
+ return self.X
54
+
55
+ def next(self):
56
+
57
+ x = np.random.random((self.n_samples, self.n_dim))
58
+ x = map_onto_unit_simplex(x, "kraemer")
59
+ x = x[vectorized_cdist(x, self.X).min(axis=1).argmax()]
60
+
61
+ if self.gradient_descent:
62
+
63
+ optimizer = Adam(precision=1e-4)
64
+
65
+ # for each iteration of gradient descent
66
+ for i in range(1000):
67
+
68
+ # calculate the function value and the gradient
69
+ # auto_obj, auto_grad = value_and_grad(calc_dist_to_others)(x, self.X)
70
+ _obj, _grad = calc_dist_to_others_with_gradient(x, self.X)
71
+
72
+ # project the gradient to have a sum of zero - guarantees to stay on the simplex
73
+ proj_grad = project_onto_sum_equals_zero_plane(_grad)
74
+
75
+ # apply a step of gradient descent by subtracting the projected gradient with a learning rate
76
+ x = optimizer.next(x, proj_grad)
77
+
78
+ # project the out of bounds points back onto the unit simplex
79
+ project_onto_unit_simplex_recursive(x[None, :])
80
+
81
+ # because of floating point issues make sure it is on the unit simplex
82
+ x /= x.sum()
83
+
84
+ # if there was only a little movement during the last iteration -> terminate
85
+ if optimizer.has_converged:
86
+ break
87
+
88
+ 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
@@ -0,0 +1,319 @@
1
+ import numpy as np
2
+
3
+ from pymoo.gradient.grad_autograd import triu_indices, sqrt, log
4
+ from pymoo.util.ref_dirs.construction import ConstructionBasedReferenceDirectionFactory
5
+ from pymoo.util.ref_dirs.misc import project_onto_sum_equals_zero_plane, project_onto_unit_simplex_recursive
6
+ from pymoo.util.ref_dirs.optimizer import Adam
7
+ from pymoo.util.ref_dirs.reduction import ReductionBasedReferenceDirectionFactory
8
+ from pymoo.util.reference_direction import ReferenceDirectionFactory, scale_reference_directions
9
+
10
+
11
+ class RieszEnergyReferenceDirectionFactory(ReferenceDirectionFactory):
12
+
13
+ def __init__(self,
14
+ n_dim,
15
+ n_points,
16
+ ref_points=None,
17
+ return_as_tuple=False,
18
+ n_max_iter=1000,
19
+ n_until_optimizer_reset=30,
20
+ sampling="reduction",
21
+ norm_gradients=True,
22
+ verify_gradient=False,
23
+ freeze_edges=False,
24
+ precision=1e-5,
25
+ restarts=True,
26
+ X=None,
27
+ d=None,
28
+ callback=None,
29
+ **kwargs):
30
+
31
+ super().__init__(n_dim, **kwargs)
32
+
33
+ self.n_points = n_points
34
+ self.n_max_iter = n_max_iter
35
+ self.n_max_not_improved = n_until_optimizer_reset
36
+ self.return_as_tuple = return_as_tuple
37
+ self.sampling = sampling
38
+ self.X = X
39
+ self.ref_points = ref_points
40
+ self.precision = precision
41
+ self.verify_gradient = verify_gradient
42
+ self.norm_gradients = norm_gradients
43
+ self.freeze_edges = freeze_edges
44
+ self.d = d
45
+ self.callback = callback
46
+ self.restarts = restarts
47
+
48
+ # experiments have shown that dimensions squared is good value to choose here
49
+ if self.d is None:
50
+ self.d = n_dim * 2
51
+
52
+ def _step(self, optimizer, X, freeze=None):
53
+ free = np.logical_not(freeze)
54
+
55
+ obj, grad, mutual_dist = calc_potential_energy_with_grad(X, self.d, return_mutual_dist=True)
56
+ # obj, grad = value_and_grad(calc_potential_energy)(X, self.d)
57
+
58
+ if self.verify_gradient:
59
+ from autograd import value_and_grad
60
+ obj, grad = calc_potential_energy_with_grad(X, self.d)
61
+ _obj, _grad = value_and_grad(calc_potential_energy)(X, self.d)
62
+ if np.abs(grad - _grad).mean() > 1e-5:
63
+ print("GRADIENT IMPLEMENTATION IS INCORRECT!")
64
+
65
+ # set the gradients for frozen points to zero - make them not to move
66
+ if freeze is not None:
67
+ grad[freeze] = 0
68
+
69
+ # project the gradient to have a sum of zero - guarantees to stay on the simplex
70
+ proj_grad = project_onto_sum_equals_zero_plane(grad)
71
+
72
+ # normalize the gradients by the largest gradient norm
73
+ if self.norm_gradients:
74
+ norm = np.linalg.norm(proj_grad, axis=1)
75
+ proj_grad = (proj_grad / max(norm.max(), 1e-24))
76
+
77
+ # apply a step of gradient descent by subtracting the projected gradient with a learning rate
78
+ X = optimizer.next(X, proj_grad)
79
+
80
+ # project the out of bounds points back onto the unit simplex
81
+ X[free] = project_onto_unit_simplex_recursive(X[free])
82
+
83
+ # because of floating point issues make sure it is on the unit simplex
84
+ X /= X.sum(axis=1)[:, None]
85
+
86
+ return X, obj
87
+
88
+ def _solve(self, X, F=None, freeze_edges=True):
89
+ n_points = len(X)
90
+ ret, obj = X, np.inf
91
+ n_not_improved = 0
92
+
93
+ # get the edge mask
94
+ if freeze_edges:
95
+ freeze = np.any(X < 1e-16, axis=1)
96
+ else:
97
+ freeze = np.full(len(X), False)
98
+
99
+ # if additional points to be frozen are provided - add them to the X and mark them as frozen
100
+ if F is not None:
101
+ X = np.row_stack([X, F])
102
+ freeze = np.concatenate([freeze, np.full(len(F), True)])
103
+
104
+ # if all points are frozen - simply return it
105
+ if np.all(freeze):
106
+ return X
107
+
108
+ # initialize the optimizer for the run
109
+ self.optimizer = Adam(alpha=0.005)
110
+
111
+ if self.callback is not None:
112
+ self.callback(self, X)
113
+
114
+ # for each iteration of gradient descent
115
+ for i in range(self.n_max_iter):
116
+
117
+ # execute one optimization step
118
+ _X, _obj = self._step(self.optimizer, X, freeze=freeze)
119
+
120
+ # if it is the current best solution -> store it
121
+ if _obj < obj:
122
+ ret, obj, n_not_improved = _X, _obj, 0
123
+ else:
124
+ n_not_improved += 1
125
+
126
+ # evaluate how much the points have moved
127
+ delta = np.sqrt((_X[:n_points] - X[:n_points]) ** 2).mean(axis=1).mean()
128
+
129
+ if self.verbose:
130
+ print(i, "objective", _obj, "delta", delta)
131
+
132
+ # if there was only a little delta during the last iteration -> terminate
133
+ if delta < self.precision or np.isnan(_obj):
134
+ break
135
+
136
+ # reset the optimizer if the objective value has not improved x iterations
137
+ if self.restarts and n_not_improved > self.n_max_not_improved:
138
+ self.optimizer = Adam(alpha=self.optimizer.alpha / 2)
139
+ _X = ret
140
+ n_not_improved = 0
141
+
142
+ # otherwise use the new points for the next iteration
143
+ X = _X
144
+
145
+ if self.callback is not None:
146
+ self.callback(self, X)
147
+
148
+ return ret[:n_points]
149
+
150
+ def _do(self):
151
+ X = self.X
152
+
153
+ # if no initial points are provided by the user
154
+ if X is None:
155
+ if self.sampling == "reduction":
156
+ X = ReductionBasedReferenceDirectionFactory(self.n_dim,
157
+ self.n_points,
158
+ kmeans=True,
159
+ lexsort=False,
160
+ seed=self.seed) \
161
+ .do()
162
+
163
+ elif self.sampling == "construction":
164
+ X = ConstructionBasedReferenceDirectionFactory(self.n_dim,
165
+ self.n_points,
166
+ seed=self.seed) \
167
+ .do()
168
+ else:
169
+ raise Exception("Unknown sampling method. Either reduction or construction.")
170
+
171
+ X = self._solve(X, freeze_edges=self.freeze_edges)
172
+
173
+ if self.ref_points is not None:
174
+ X, R = self.calc_ref_points(X, self.ref_points)
175
+
176
+ if self.return_as_tuple:
177
+ return X, R
178
+ else:
179
+ return np.row_stack([X, R])
180
+
181
+ return X
182
+
183
+ def calc_ref_points(self, X, ref_points):
184
+ n_points = len(X)
185
+
186
+ # the center needed for translations
187
+ centroid = np.full((1, self.n_dim), 1 / self.n_dim)
188
+
189
+ R = []
190
+
191
+ # for each reference point provided by the user
192
+ for entry in ref_points:
193
+ ref_point, n_points_of_ref = entry.get("coordinates"), entry.get("n_points")
194
+ scale, volume = entry.get("scale"), entry.get("volume")
195
+
196
+ if scale is None:
197
+ if volume is None:
198
+ raise Exception("Either define scale or volume!")
199
+ else:
200
+ scale = volume ** (self.n_dim - 1)
201
+
202
+ # retrieve all points to consider
203
+ _X = np.row_stack([X] + R)
204
+
205
+ # translate X to make the simplex to fill the unit
206
+ v = centroid - ref_point
207
+ X_t = _X + v
208
+ X_t = scale_reference_directions(X_t, 1 / scale)
209
+
210
+ # find the indices of points which are used as edges
211
+ I = np.where(np.any(X_t < 1e-5, axis=1))[0]
212
+
213
+ # create new points in the simplex where reference directions are supposed to be optimized
214
+ _n_points = n_points_of_ref + (n_points - len(I))
215
+ _R = ReductionBasedReferenceDirectionFactory(self.n_dim, n_points=_n_points, kmeans=True,
216
+ lexsort=False).do()
217
+
218
+ # detect the edges and just optimize them and shrink later
219
+ outer = np.any(_R == 0, axis=1)
220
+ inner = ~outer
221
+
222
+ # rescale the reference directions to be not too close to existing points
223
+ _R = scale_reference_directions(_R, 0.9)
224
+
225
+ # optimize just the edges
226
+ _R[outer] = self._solve(_R[outer], F=np.row_stack([X_t[I], _R[inner]]), freeze_edges=False)
227
+
228
+ # no set the reference point and freeze it
229
+ # closest_to_centroid = cdist(centroid, _R).argmin()
230
+ # outer[closest_to_centroid] = True
231
+ # inner[closest_to_centroid] = False
232
+ # _R[closest_to_centroid] = centroid
233
+
234
+ # now when translated the reference point becomes the centroid - fix that point to be included
235
+ _R[inner] = self._solve(_R[inner], F=np.row_stack([X_t[I], _R[outer]]), freeze_edges=False)
236
+
237
+ # rescale and translate them back
238
+ _R_t = scale_reference_directions(_R, scale)
239
+ _R_t = _R_t - v
240
+
241
+ # if any point is out of bounds - volume was too large
242
+ if not np.all(_R_t >= 0):
243
+
244
+ # get the corner points if not transformed
245
+ V = (np.eye(self.n_dim) - centroid)
246
+
247
+ # get the corner points of the ref dir simplex
248
+ P = ref_point + scale * V
249
+ E = centroid + scale * V
250
+
251
+ # project because at least is out of points
252
+ P_proj = project_onto_unit_simplex_recursive(np.copy(P))
253
+
254
+ for i in range(len(P)):
255
+
256
+ if not np.all(P[i] == P_proj[i]):
257
+ _R_t = scale_reference_directions(_R, scale)
258
+ _R_t = _R_t - (E[i] - P_proj[i])
259
+
260
+ if np.all(_R_t >= 0):
261
+ break
262
+
263
+ n_points += n_points_of_ref
264
+ R.append(_R_t)
265
+
266
+ # filter out points from to be removed from the original array
267
+ X = X[[i for i in I if i < len(X)]]
268
+
269
+ R = np.row_stack(R)
270
+
271
+ return X, R
272
+
273
+
274
+ # ---------------------------------------------------------------------------------------------------------
275
+ # Energy Functions
276
+ # ---------------------------------------------------------------------------------------------------------
277
+
278
+
279
+ def squared_dist(A, B):
280
+ return ((A[:, None] - B[None, :]) ** 2).sum(axis=2)
281
+
282
+
283
+ def calc_potential_energy(A, d):
284
+ i, j = triu_indices(len(A), 1)
285
+ D = sqrt(squared_dist(A, A)[i, j])
286
+ energy = log((1 / D ** d).mean())
287
+ return energy
288
+
289
+
290
+ def calc_potential_energy_with_grad(x, d, return_mutual_dist=False):
291
+ diff = (x[:, None] - x[None, :])
292
+ # calculate the squared euclidean from each point to another
293
+ dist = np.sqrt((diff ** 2).sum(axis=2))
294
+
295
+ # make sure the distance to itself does not count
296
+ np.fill_diagonal(dist, np.inf)
297
+
298
+ # epsilon which is the smallest distance possible to avoid an overflow during gradient calculation
299
+ eps = 10 ** (-320 / (d + 2))
300
+ b = dist < eps
301
+ dist[b] = eps
302
+
303
+ # select only upper triangular matrix to have each mutual distance once
304
+ mutual_dist = dist[np.triu_indices(len(x), 1)]
305
+
306
+ # calculate the energy by summing up the squared distances
307
+ energy = (1 / mutual_dist ** d).sum()
308
+ log_energy = - np.log(len(mutual_dist)) + np.log(energy)
309
+
310
+ # calculate the gradient
311
+ grad = (-d * diff) / (dist ** (d + 2))[..., None]
312
+ grad = np.sum(grad, axis=1)
313
+ grad /= energy
314
+
315
+ ret = [log_energy, grad]
316
+ if return_mutual_dist:
317
+ ret.append(mutual_dist)
318
+
319
+ return tuple(ret)
@@ -0,0 +1,119 @@
1
+
2
+
3
+ import numpy as np
4
+
5
+ from pymoo.gradient.grad_autograd import value_and_grad, triu_indices, row_stack
6
+ from pymoo.util.normalization import normalize
7
+ from pymoo.util.ref_dirs.energy import squared_dist
8
+ from pymoo.util.ref_dirs.optimizer import Adam
9
+ from pymoo.util.reference_direction import ReferenceDirectionFactory, scale_reference_directions
10
+
11
+
12
+ class LayerwiseRieszEnergyReferenceDirectionFactory(ReferenceDirectionFactory):
13
+
14
+ def __init__(self,
15
+ n_dim,
16
+ partitions,
17
+ return_as_tuple=False,
18
+ n_max_iter=1000,
19
+ verbose=False,
20
+ X=None,
21
+ **kwargs):
22
+
23
+ super().__init__(n_dim, **kwargs)
24
+ self.scalings = None
25
+ self.n_max_iter = n_max_iter
26
+ self.verbose = verbose
27
+ self.return_as_tuple = return_as_tuple
28
+ self.X = X
29
+ self.partitions = partitions
30
+
31
+ def _step(self, optimizer, X, scalings):
32
+ obj, grad = value_and_grad(calc_potential_energy)(scalings, X)
33
+ scalings = optimizer.next(scalings, np.array(grad))
34
+ scalings = normalize(scalings, xl=0, xu=scalings.max())
35
+ return scalings, obj
36
+
37
+ def _solve(self, X, scalings):
38
+
39
+ # initialize the optimizer for the run
40
+ optimizer = Adam()
41
+
42
+ # for each iteration of gradient descent
43
+ for i in range(self.n_max_iter):
44
+
45
+ # execute one optimization step
46
+ _scalings, _obj = self._step(optimizer, X, scalings)
47
+
48
+ # evaluate how much the points have moved
49
+ delta = np.abs(_scalings - scalings).sum()
50
+
51
+ if self.verbose:
52
+ print(i, "objective", _obj, "delta", delta)
53
+
54
+ # if there was only a little delta during the last iteration -> terminate
55
+ if delta < 1e-5:
56
+ scalings = _scalings
57
+ break
58
+
59
+ # otherwise use the new points for the next iteration
60
+ scalings = _scalings
61
+
62
+ self.scalings = scalings
63
+ return get_points(X, scalings)
64
+
65
+ def do(self):
66
+
67
+ X = []
68
+ scalings = []
69
+
70
+ for k, p in enumerate(self.partitions):
71
+
72
+ if p > 1:
73
+ val = np.linspace(0, 1, p + 1)[1:-1]
74
+ _X = []
75
+ for i in range(self.n_dim):
76
+ for j in range(i + 1, self.n_dim):
77
+ x = np.zeros((len(val), self.n_dim))
78
+ x[:, i] = val
79
+ x[:, j] = 1 - val
80
+ _X.append(x)
81
+
82
+ X.append(np.row_stack(_X + [np.eye(self.n_dim)]))
83
+
84
+ elif p == 1:
85
+ X.append(np.eye(self.n_dim))
86
+ else:
87
+ X.append(np.full(self.n_dim, 1 / self.n_dim)[None, :])
88
+
89
+ scalings.append(1 - k / len(self.partitions))
90
+
91
+ scalings = np.array(scalings)
92
+ X = self._solve(X, scalings)
93
+
94
+ return X
95
+
96
+
97
+ # ---------------------------------------------------------------------------------------------------------
98
+ # Energy Functions
99
+ # ---------------------------------------------------------------------------------------------------------
100
+
101
+
102
+ def get_points(X, scalings):
103
+ vals = []
104
+ for i in range(len(X)):
105
+ vals.append(scale_reference_directions(X[i], scalings[i]))
106
+ X = row_stack(vals)
107
+ return X
108
+
109
+
110
+ def calc_potential_energy(scalings, X):
111
+ X = get_points(X, scalings)
112
+
113
+ i, j = triu_indices(len(X), 1)
114
+ D = squared_dist(X, X)[i, j]
115
+
116
+ if np.any(D < 1e-12):
117
+ return np.nan, np.nan
118
+
119
+ return (1 / D).mean()
@@ -0,0 +1,63 @@
1
+ from pymoo.algorithms.soo.nonconvex.ga import GA
2
+ from pymoo.core.problem import Problem
3
+ from pymoo.optimize import minimize
4
+ from pymoo.util.reference_direction import get_partition_closest_to_points, ReferenceDirectionFactory
5
+
6
+
7
+ class ReferenceDirectionGA(ReferenceDirectionFactory):
8
+
9
+ def __init__(self,
10
+ n_dim,
11
+ n_points,
12
+ fun,
13
+ pop_size=20,
14
+ n_gen=200,
15
+ verbose=False,
16
+ **kwargs):
17
+
18
+ super().__init__(n_dim, **kwargs)
19
+
20
+ self.n_points = n_points
21
+ self.pop_size = pop_size
22
+ self.n_gen = n_gen
23
+
24
+ self.fun = fun
25
+ self.verbose = verbose
26
+
27
+ def _do(self):
28
+ pop_size, n_gen = self.pop_size, self.n_gen
29
+ n_points, n_dim, = self.n_points, self.n_dim
30
+ fun = self.fun
31
+
32
+ class MyProblem(Problem):
33
+
34
+ def __init__(self):
35
+ self.n_points = n_points
36
+ self.n_dim = n_dim
37
+ self.n_partitions = get_partition_closest_to_points(n_points, n_dim)
38
+
39
+ super().__init__(n_var=n_points * n_dim,
40
+ n_obj=1,
41
+ xl=0.0,
42
+ xu=1.0,
43
+ elementwise_evaluation=True)
44
+
45
+ def get_points(self, x):
46
+ _x = x.reshape((self.n_points, self.n_dim)) ** 2
47
+ _x = _x / _x.sum(axis=1)[:, None]
48
+ return _x
49
+
50
+ def _evaluate(self, x, out, *args, **kwargs):
51
+ out["F"] = fun(self.get_points(x))
52
+
53
+ problem = MyProblem()
54
+
55
+ algorithm = GA(pop_size=pop_size, eliminate_duplicates=True)
56
+
57
+ res = minimize(problem,
58
+ algorithm,
59
+ termination=('n_gen', n_gen),
60
+ verbose=True)
61
+
62
+ ref_dirs = problem.get_points(res.X)
63
+ return ref_dirs