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,317 @@
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.vstack([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, random_state=None):
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
+ .do(random_state=random_state)
161
+
162
+ elif self.sampling == "construction":
163
+ X = ConstructionBasedReferenceDirectionFactory(self.n_dim,
164
+ self.n_points) \
165
+ .do(random_state=random_state)
166
+ else:
167
+ raise Exception("Unknown sampling method. Either reduction or construction.")
168
+
169
+ X = self._solve(X, freeze_edges=self.freeze_edges)
170
+
171
+ if self.ref_points is not None:
172
+ X, R = self.calc_ref_points(X, self.ref_points)
173
+
174
+ if self.return_as_tuple:
175
+ return X, R
176
+ else:
177
+ return np.vstack([X, R])
178
+
179
+ return X
180
+
181
+ def calc_ref_points(self, X, ref_points):
182
+ n_points = len(X)
183
+
184
+ # the center needed for translations
185
+ centroid = np.full((1, self.n_dim), 1 / self.n_dim)
186
+
187
+ R = []
188
+
189
+ # for each reference point provided by the user
190
+ for entry in ref_points:
191
+ ref_point, n_points_of_ref = entry.get("coordinates"), entry.get("n_points")
192
+ scale, volume = entry.get("scale"), entry.get("volume")
193
+
194
+ if scale is None:
195
+ if volume is None:
196
+ raise Exception("Either define scale or volume!")
197
+ else:
198
+ scale = volume ** (self.n_dim - 1)
199
+
200
+ # retrieve all points to consider
201
+ _X = np.vstack([X] + R)
202
+
203
+ # translate X to make the simplex to fill the unit
204
+ v = centroid - ref_point
205
+ X_t = _X + v
206
+ X_t = scale_reference_directions(X_t, 1 / scale)
207
+
208
+ # find the indices of points which are used as edges
209
+ I = np.where(np.any(X_t < 1e-5, axis=1))[0]
210
+
211
+ # create new points in the simplex where reference directions are supposed to be optimized
212
+ _n_points = n_points_of_ref + (n_points - len(I))
213
+ _R = ReductionBasedReferenceDirectionFactory(self.n_dim, n_points=_n_points, kmeans=True,
214
+ lexsort=False).do()
215
+
216
+ # detect the edges and just optimize them and shrink later
217
+ outer = np.any(_R == 0, axis=1)
218
+ inner = ~outer
219
+
220
+ # rescale the reference directions to be not too close to existing points
221
+ _R = scale_reference_directions(_R, 0.9)
222
+
223
+ # optimize just the edges
224
+ _R[outer] = self._solve(_R[outer], F=np.vstack([X_t[I], _R[inner]]), freeze_edges=False)
225
+
226
+ # no set the reference point and freeze it
227
+ # closest_to_centroid = cdist(centroid, _R).argmin()
228
+ # outer[closest_to_centroid] = True
229
+ # inner[closest_to_centroid] = False
230
+ # _R[closest_to_centroid] = centroid
231
+
232
+ # now when translated the reference point becomes the centroid - fix that point to be included
233
+ _R[inner] = self._solve(_R[inner], F=np.vstack([X_t[I], _R[outer]]), freeze_edges=False)
234
+
235
+ # rescale and translate them back
236
+ _R_t = scale_reference_directions(_R, scale)
237
+ _R_t = _R_t - v
238
+
239
+ # if any point is out of bounds - volume was too large
240
+ if not np.all(_R_t >= 0):
241
+
242
+ # get the corner points if not transformed
243
+ V = (np.eye(self.n_dim) - centroid)
244
+
245
+ # get the corner points of the ref dir simplex
246
+ P = ref_point + scale * V
247
+ E = centroid + scale * V
248
+
249
+ # project because at least is out of points
250
+ P_proj = project_onto_unit_simplex_recursive(np.copy(P))
251
+
252
+ for i in range(len(P)):
253
+
254
+ if not np.all(P[i] == P_proj[i]):
255
+ _R_t = scale_reference_directions(_R, scale)
256
+ _R_t = _R_t - (E[i] - P_proj[i])
257
+
258
+ if np.all(_R_t >= 0):
259
+ break
260
+
261
+ n_points += n_points_of_ref
262
+ R.append(_R_t)
263
+
264
+ # filter out points from to be removed from the original array
265
+ X = X[[i for i in I if i < len(X)]]
266
+
267
+ R = np.vstack(R)
268
+
269
+ return X, R
270
+
271
+
272
+ # ---------------------------------------------------------------------------------------------------------
273
+ # Energy Functions
274
+ # ---------------------------------------------------------------------------------------------------------
275
+
276
+
277
+ def squared_dist(A, B):
278
+ return ((A[:, None] - B[None, :]) ** 2).sum(axis=2)
279
+
280
+
281
+ def calc_potential_energy(A, d):
282
+ i, j = triu_indices(len(A), 1)
283
+ D = sqrt(squared_dist(A, A)[i, j])
284
+ energy = log((1 / D ** d).mean())
285
+ return energy
286
+
287
+
288
+ def calc_potential_energy_with_grad(x, d, return_mutual_dist=False):
289
+ diff = (x[:, None] - x[None, :])
290
+ # calculate the squared euclidean from each point to another
291
+ dist = np.sqrt((diff ** 2).sum(axis=2))
292
+
293
+ # make sure the distance to itself does not count
294
+ np.fill_diagonal(dist, np.inf)
295
+
296
+ # epsilon which is the smallest distance possible to avoid an overflow during gradient calculation
297
+ eps = 10 ** (-320 / (d + 2))
298
+ b = dist < eps
299
+ dist[b] = eps
300
+
301
+ # select only upper triangular matrix to have each mutual distance once
302
+ mutual_dist = dist[np.triu_indices(len(x), 1)]
303
+
304
+ # calculate the energy by summing up the squared distances
305
+ energy = (1 / mutual_dist ** d).sum()
306
+ log_energy = - np.log(len(mutual_dist)) + np.log(energy)
307
+
308
+ # calculate the gradient
309
+ grad = (-d * diff) / (dist ** (d + 2))[..., None]
310
+ grad = np.sum(grad, axis=1)
311
+ grad /= energy
312
+
313
+ ret = [log_energy, grad]
314
+ if return_mutual_dist:
315
+ ret.append(mutual_dist)
316
+
317
+ 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, **kwargs):
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.vstack(_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,64 @@
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, random_state=None):
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
+ random_state=random_state,
61
+ verbose=True)
62
+
63
+ ref_dirs = problem.get_points(res.X)
64
+ return ref_dirs
@@ -0,0 +1,69 @@
1
+ import numpy as np
2
+
3
+ from pymoo.util.reference_direction import ReferenceDirectionFactory
4
+
5
+
6
+ def check_n_points(n_points, n_dim):
7
+ """
8
+ Returns n_partitions or a numeric value associated with the exception message.
9
+ """
10
+
11
+ if n_dim == 1:
12
+ return [0]
13
+
14
+ I = n_dim * np.eye(n_dim)
15
+ W = np.zeros((1, n_dim))
16
+ edgeW = W
17
+ i = 0
18
+
19
+ while len(W) < n_points:
20
+ edgeW = np.tile(edgeW, (n_dim, 1)) + np.repeat(I, edgeW.shape[0], axis=0)
21
+ edgeW = np.unique(edgeW, axis=0)
22
+ edgeW = edgeW [np.any(edgeW == 0, axis=1)]
23
+ W = np.vstack((W + 1, edgeW))
24
+ i += 1
25
+
26
+ if len(W) == n_points:
27
+ return [i]
28
+
29
+ return [len(W) - len(edgeW), i - 1, len(W), i]
30
+
31
+
32
+ def incremental_lattice(n_partitions, n_dim):
33
+ I = n_dim * np.eye(n_dim)
34
+ W = np.zeros((1, n_dim))
35
+ edgeW = W
36
+
37
+ for _ in range(n_partitions):
38
+ edgeW = np.tile(edgeW, (n_dim, 1)) + np.repeat(I, edgeW.shape[0], axis=0)
39
+ edgeW = np.unique(edgeW, axis=0)
40
+ edgeW = edgeW [np.any(edgeW == 0, axis=1)]
41
+ W = np.vstack((W + 1, edgeW))
42
+
43
+ return W / (n_dim * n_partitions)
44
+
45
+ class IncrementalReferenceDirectionFactory(ReferenceDirectionFactory):
46
+
47
+ def __init__(self, n_dim, scaling=None, n_points=None, n_partitions=None, **kwargs) -> None:
48
+ super().__init__(n_dim, scaling=scaling, **kwargs)
49
+
50
+ if n_points is not None:
51
+ results = check_n_points(n_points, n_dim)
52
+
53
+ # the number of points are not matching to any partition number
54
+ if len(results) > 1:
55
+ raise Exception("The number of points (n_points = %s) can not be created uniformly.\n"
56
+ "Either choose n_points = %s (n_partitions = %s) or "
57
+ "n_points = %s (n_partitions = %s)." %
58
+ (n_points, results[0], results[1], results[2], results[3]))
59
+
60
+ self.n_partitions = results[0]
61
+
62
+ elif n_partitions is not None:
63
+ self.n_partitions = n_partitions
64
+
65
+ else:
66
+ raise Exception("Either provide number of partitions or number of points.")
67
+
68
+ def _do(self, **kwargs):
69
+ return incremental_lattice(self.n_partitions, self.n_dim)
@@ -0,0 +1,128 @@
1
+ import numpy as np
2
+
3
+
4
+ def project_onto(y, p, n):
5
+ """
6
+
7
+ Project a point onto a plane.
8
+
9
+ Parameters
10
+ ----------
11
+ y : The point that should be project
12
+ p : A point which lies on the plane
13
+ n : The normal vector of the plane
14
+
15
+ Returns
16
+ -------
17
+
18
+ proj_y : The projection onto the plane
19
+
20
+ """
21
+
22
+ is_1d = False
23
+ if len(y.shape) == 1:
24
+ is_1d = True
25
+ y = np.atleast_2d(y)
26
+
27
+ # make sure the plane vector is normalized
28
+ n = n / np.linalg.norm(n)
29
+
30
+ proj_y = y - n[None, :] * ((y - p) @ n)[:, None]
31
+
32
+ if is_1d:
33
+ proj_y = proj_y[0]
34
+
35
+ return proj_y
36
+
37
+
38
+ def project_onto_sum_equals_one_plane(y):
39
+ n_dim = y.shape[-1]
40
+ return project_onto(y, np.eye(n_dim)[0], np.ones(n_dim))
41
+
42
+
43
+ def project_onto_sum_equals_zero_plane(y):
44
+ n_dim = y.shape[-1]
45
+ return project_onto(y, np.zeros(n_dim), np.ones(n_dim))
46
+
47
+
48
+ def project_onto_unit_simplex(X):
49
+ n_points, n_dim = X.shape
50
+
51
+ # a boolean mask of violating values - less than 0
52
+ I = X < 0
53
+
54
+ # get all the points which are out of bounds and need to be fixed
55
+ out_of_unit_simplex = np.where(I.sum(axis=1) > 0)[0]
56
+
57
+ # now check for each point if it is still in bound
58
+ for j in out_of_unit_simplex:
59
+
60
+ # indices where the last point was already out of bounds
61
+ subspace = np.logical_not(I[j])
62
+
63
+ # project the bounds back onto the simplex in the subspace
64
+ proj = np.zeros(n_dim)
65
+ proj[subspace] = project_onto_sum_equals_one_plane(X[j][subspace])
66
+
67
+ # set the result to the corresponding value
68
+ X[j] = proj
69
+
70
+ test1 = matrix_project_onto_sum_equals_one_plane(X[j][subspace])
71
+ test2 = project_onto_sum_equals_one_plane(X[j][subspace])
72
+
73
+ if not np.allclose(test1, test2):
74
+ print("test")
75
+
76
+ if np.any(X[j] < 0):
77
+ print("test")
78
+
79
+
80
+ def project_onto_unit_simplex_recursive(X):
81
+ # get all the points which are out of bounds and need to be fixed
82
+ out_of_unit_simplex = np.where(np.any(X < 0, axis=1))[0]
83
+
84
+ # now check for each point if it is still in bound
85
+ for j in out_of_unit_simplex:
86
+
87
+ while True:
88
+ X[j, X[j] < 0] = 0
89
+
90
+ # indices where the last point was already out of bounds
91
+ subspace = X[j] > 0
92
+
93
+ # project the bounds back onto the simplex in the subspace
94
+ X[j, subspace] = project_onto_sum_equals_one_plane(X[j][subspace])
95
+
96
+ if np.all(X[j] >= 0):
97
+ break
98
+
99
+ return X
100
+
101
+
102
+ def matrix_project_onto_sum_equals_one_plane(next):
103
+ n_dim = len(next)
104
+ P, S = np.eye(n_dim)[0], next
105
+
106
+ # create for each subspace dimension a point on the hyperplane
107
+ points = P + np.eye(n_dim)[1:]
108
+ points /= points.sum(axis=1)[:, None]
109
+
110
+ v = points - P
111
+ s = S - P
112
+
113
+ # solve a system of linear equations to project the point
114
+ A = np.zeros((n_dim - 1, n_dim - 1))
115
+ for i in range(n_dim - 1):
116
+ for j in range(n_dim - 1):
117
+ A[i, j] = np.dot(v[i], v[j])
118
+
119
+ b = np.zeros(n_dim - 1)
120
+ for i in range(n_dim - 1):
121
+ b[i] = np.dot(s, v[i])
122
+
123
+ x = np.linalg.solve(A, b)
124
+
125
+ # finally calculate the projection onto the plane
126
+ proj = (P + x @ v)
127
+
128
+ return proj