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
pymoo/util/misc.py ADDED
@@ -0,0 +1,447 @@
1
+ from collections import OrderedDict
2
+ from itertools import combinations
3
+
4
+ import numpy as np
5
+
6
+ from pymoo.core.population import Population
7
+ from pymoo.core.sampling import Sampling
8
+ from pymoo.util import default_random_state
9
+
10
+
11
+ def parameter_less(F, CV, fmax=None, inplace=False):
12
+ assert len(F) == len(CV)
13
+
14
+ if not inplace:
15
+ F = np.copy(F)
16
+
17
+ if fmax is None:
18
+ fmax = np.max(F)
19
+
20
+ param_less = fmax + CV
21
+
22
+ infeas = (CV > 0).flatten()
23
+ F[infeas] = param_less[infeas]
24
+
25
+ return F
26
+
27
+
28
+ def swap(M, a, b):
29
+ tmp = M[a]
30
+ M[a] = M[b]
31
+ M[b] = tmp
32
+
33
+
34
+ # repairs a numpy array to be in bounds
35
+ def repair(X, xl, xu):
36
+ larger_than_xu = X[0, :] > xu
37
+ X[0, larger_than_xu] = xu[larger_than_xu]
38
+
39
+ smaller_than_xl = X[0, :] < xl
40
+ X[0, smaller_than_xl] = xl[smaller_than_xl]
41
+
42
+ return X
43
+
44
+
45
+ def unique_rows(a):
46
+ a = np.ascontiguousarray(a)
47
+ unique_a = np.unique(a.view([('', a.dtype)] * a.shape[1]))
48
+ return unique_a.view(a.dtype).reshape((unique_a.shape[0], a.shape[1]))
49
+
50
+
51
+ def parameter_less_constraints(F, CV, F_max=None):
52
+ if F_max is None:
53
+ F_max = np.max(F)
54
+ has_constraint_violation = CV > 0
55
+ F[has_constraint_violation] = CV[has_constraint_violation] + F_max
56
+ return F
57
+
58
+
59
+ @default_random_state
60
+ def random_permutations(n, l, concat=True, random_state=None):
61
+ P = []
62
+ for i in range(n):
63
+ P.append(random_state.permutation(l))
64
+ if concat:
65
+ P = np.concatenate(P)
66
+ return P
67
+
68
+
69
+ def get_duplicates(M):
70
+ res = []
71
+ I = np.lexsort([M[:, i] for i in reversed(range(0, M.shape[1]))])
72
+ S = M[I, :]
73
+
74
+ i = 0
75
+
76
+ while i < S.shape[0] - 1:
77
+ l = []
78
+ while np.all(S[i, :] == S[i + 1, :]):
79
+ l.append(I[i])
80
+ i += 1
81
+ if len(l) > 0:
82
+ l.append(I[i])
83
+ res.append(l)
84
+ i += 1
85
+
86
+ return res
87
+
88
+
89
+ # -----------------------------------------------
90
+ # Euclidean Distance
91
+ # -----------------------------------------------
92
+
93
+ def func_euclidean_distance(a, b):
94
+ return np.sqrt(((a - b) ** 2).sum(axis=1))
95
+
96
+
97
+ def func_norm_euclidean_distance(xl, xu):
98
+ return lambda a, b: np.sqrt((((a - b) / (xu - xl)) ** 2).sum(axis=1))
99
+
100
+
101
+ def norm_eucl_dist_by_bounds(A, B, xl, xu, **kwargs):
102
+ return vectorized_cdist(A, B, func_dist=func_norm_euclidean_distance(xl, xu), **kwargs)
103
+
104
+
105
+ def norm_eucl_dist(problem, A, B, **kwargs):
106
+ return norm_eucl_dist_by_bounds(A, B, *problem.bounds(), **kwargs)
107
+
108
+
109
+ # -----------------------------------------------
110
+ # Manhatten Distance
111
+ # -----------------------------------------------
112
+
113
+ def func_manhatten_distance(a, b):
114
+ return np.abs(a - b).sum(axis=1)
115
+
116
+
117
+ def func_norm_manhatten_distance(xl, xu):
118
+ return lambda a, b: np.abs((a - b) / (xu - xl)).sum(axis=1)
119
+
120
+
121
+ def norm_manhatten_dist_by_bounds(A, B, xl, xu, **kwargs):
122
+ return vectorized_cdist(A, B, func_dist=func_norm_manhatten_distance(xl, xu), **kwargs)
123
+
124
+
125
+ def norm_manhatten_dist(problem, A, B, **kwargs):
126
+ return norm_manhatten_dist_by_bounds(A, B, *problem.bounds(), **kwargs)
127
+
128
+
129
+ # -----------------------------------------------
130
+ # Tchebychev Distance
131
+ # -----------------------------------------------
132
+
133
+
134
+ def func_tchebychev_distance(a, b):
135
+ return np.abs(a - b).max(axis=1)
136
+
137
+
138
+ def func_norm_tchebychev_distance(xl, xu):
139
+ return lambda a, b: np.abs((a - b) / (xu - xl)).max(axis=1)
140
+
141
+
142
+ def norm_tchebychev_dist_by_bounds(A, B, xl, xu, **kwargs):
143
+ return vectorized_cdist(A, B, func_dist=func_norm_tchebychev_distance(xl, xu), **kwargs)
144
+
145
+
146
+ def norm_tchebychev_dist(problem, A, B, **kwargs):
147
+ return norm_tchebychev_dist_by_bounds(A, B, *problem.bounds(), **kwargs)
148
+
149
+
150
+ # -----------------------------------------------
151
+ # Others
152
+ # -----------------------------------------------
153
+
154
+
155
+ def cdist(A, B, **kwargs):
156
+ from scipy.spatial import distance
157
+ return distance.cdist(A.astype(float), B.astype(float), **kwargs)
158
+
159
+
160
+ def vectorized_cdist(A, B, func_dist=func_euclidean_distance, fill_diag_with_inf=False, **kwargs) -> object:
161
+ assert A.ndim <= 2 and B.ndim <= 2
162
+
163
+ A, only_row = at_least_2d_array(A, extend_as="row", return_if_reshaped=True)
164
+ B, only_column = at_least_2d_array(B, extend_as="row", return_if_reshaped=True)
165
+
166
+ u = np.repeat(A, B.shape[0], axis=0)
167
+ v = np.tile(B, (A.shape[0], 1))
168
+
169
+ D = func_dist(u, v, **kwargs)
170
+ M = np.reshape(D, (A.shape[0], B.shape[0]))
171
+
172
+ if fill_diag_with_inf:
173
+ np.fill_diagonal(M, np.inf)
174
+
175
+ if only_row and only_column:
176
+ M = M[0, 0]
177
+ elif only_row:
178
+ M = M[0]
179
+ elif only_column:
180
+ M = M[:, [0]]
181
+
182
+ return M
183
+
184
+
185
+ def covert_to_type(problem, X):
186
+ if problem.vtype == float:
187
+ return X.astype(np.double)
188
+ elif problem.vtype == int:
189
+ return np.round(X).astype(int)
190
+ elif problem.vtype == bool:
191
+ return X < (problem.xu - problem.xl) / 2
192
+
193
+
194
+ def find_duplicates(X, epsilon=1e-16):
195
+ # calculate the distance matrix from each point to another
196
+ D = cdist(X, X)
197
+
198
+ # set the diagonal to infinity
199
+ D[np.triu_indices(len(X))] = np.inf
200
+
201
+ # set as duplicate if a point is really close to this one
202
+ is_duplicate = np.any(D <= epsilon, axis=1)
203
+
204
+ return is_duplicate
205
+
206
+
207
+ def at_least_2d(*args, **kwargs):
208
+ ret = tuple([at_least_2d_array(arg, **kwargs) for arg in args])
209
+ if len(ret) == 1:
210
+ ret = ret[0]
211
+ return ret
212
+
213
+
214
+ def at_least_2d_array(x, extend_as="row", return_if_reshaped=False):
215
+ if x is None:
216
+ return x
217
+ elif not isinstance(x, np.ndarray):
218
+ x = np.array([x])
219
+
220
+ has_been_reshaped = False
221
+
222
+ if x.ndim == 1:
223
+ if extend_as.startswith("r"):
224
+ x = x[None, :]
225
+ elif extend_as.startswith("c"):
226
+ x = x[:, None]
227
+ else:
228
+ raise Exception("The option `extend_as` should be either `row` or `column`.")
229
+
230
+ has_been_reshaped = True
231
+
232
+ if return_if_reshaped:
233
+ return x, has_been_reshaped
234
+ else:
235
+ return x
236
+
237
+
238
+ def to_1d_array_if_possible(x):
239
+ if not isinstance(x, np.ndarray):
240
+ x = np.array([x])
241
+
242
+ if x.ndim == 2:
243
+ if x.shape[0] == 1 or x.shape[1] == 1:
244
+ x = x.flatten()
245
+
246
+ return x
247
+
248
+
249
+ def stack(*args, flatten=True):
250
+ if not flatten:
251
+ ps = np.concatenate([e[None, ...] for e in args])
252
+ else:
253
+ ps = np.vstack(args)
254
+ return ps
255
+
256
+
257
+ def all_except(x, *args):
258
+ if len(args) == 0:
259
+ return x
260
+ else:
261
+ H = set(args) if len(args) > 5 else args
262
+ I = [k for k in range(len(x)) if k not in H]
263
+ return x[I]
264
+
265
+
266
+ def all_combinations(A, B):
267
+ u = np.repeat(A, B.shape[0], axis=0)
268
+ v = np.tile(B, A.shape[0])
269
+ return np.column_stack([u, v])
270
+
271
+
272
+ def pop_from_sampling(problem, sampling, n_initial_samples, pop=None):
273
+ # the population type can be different - (different type of individuals)
274
+ if pop is None:
275
+ pop = Population()
276
+
277
+ # provide a whole population object - (individuals might be already evaluated)
278
+ if isinstance(sampling, Population):
279
+ pop = sampling
280
+
281
+ else:
282
+ # if just an X array create a pop
283
+ if isinstance(sampling, np.ndarray):
284
+ pop = pop.new("X", sampling)
285
+
286
+ elif isinstance(sampling, Sampling):
287
+ # use the sampling
288
+ pop = sampling.do(problem, n_initial_samples, pop=pop)
289
+
290
+ else:
291
+ return None
292
+
293
+ return pop
294
+
295
+
296
+ def evaluate_if_not_done_yet(evaluator, problem, pop, algorithm=None):
297
+ I = np.where(pop.get("F") == None)[0]
298
+ if len(I) > 0:
299
+ pop[I] = evaluator.process(problem, pop[I], algorithm=algorithm)
300
+
301
+
302
+ def set_if_none(kwargs, str, val):
303
+ if str not in kwargs:
304
+ kwargs[str] = val
305
+
306
+
307
+ def set_if_none_from_tuples(kwargs, *args):
308
+ for key, val in args:
309
+ if key not in kwargs:
310
+ kwargs[key] = val
311
+
312
+
313
+
314
+ def distance_of_closest_points_to_others(X):
315
+ D = vectorized_cdist(X, X)
316
+ np.fill_diagonal(D, np.inf)
317
+ return D.argmin(axis=1), D.min(axis=1)
318
+
319
+
320
+ def time_to_int(t):
321
+ vals = [int(e) for e in t.split(":")][::-1]
322
+ s = vals[0]
323
+ if len(vals) > 1:
324
+ s += 60 * vals[1]
325
+ if len(vals) > 2:
326
+ s += 3600 * vals[2]
327
+ return s
328
+
329
+
330
+ def powerset(iterable):
331
+ for n in range(len(iterable) + 1):
332
+ yield from combinations(iterable, n)
333
+
334
+
335
+ def intersect(a, b):
336
+ H = set()
337
+ for entry in b:
338
+ H.add(entry)
339
+
340
+ ret = []
341
+ for entry in a:
342
+ if entry in H:
343
+ ret.append(entry)
344
+
345
+ return ret
346
+
347
+
348
+ def has_feasible(pop):
349
+ return np.any(pop.get("FEAS"))
350
+
351
+
352
+ def to_numpy(a):
353
+ return np.array(a)
354
+
355
+
356
+ def termination_from_tuple(termination):
357
+ from pymoo.core.termination import Termination
358
+
359
+ # get the termination if provided as a tuple - create an object
360
+ if termination is not None and not isinstance(termination, Termination):
361
+ from pymoo.termination import get_termination
362
+ if isinstance(termination, str):
363
+ termination = get_termination(termination)
364
+ else:
365
+ termination = get_termination(*termination)
366
+
367
+ return termination
368
+
369
+
370
+ def unique_and_all_indices(arr):
371
+ sort_indexes = np.argsort(arr)
372
+ arr = np.asarray(arr)[sort_indexes]
373
+ vals, first_indexes, inverse, counts = np.unique(arr,
374
+ return_index=True, return_inverse=True, return_counts=True)
375
+ indexes = np.split(sort_indexes, first_indexes[1:])
376
+ for x in indexes:
377
+ x.sort()
378
+ return vals, indexes
379
+
380
+
381
+ def from_dict(D, *keys):
382
+ return [D.get(k) for k in keys]
383
+
384
+
385
+ def list_of_dicts_unique(l, k):
386
+ return list(OrderedDict([(e[k], None) for e in l]).keys())
387
+
388
+
389
+ def list_of_dicts_filter(l, *pairs):
390
+ return [e for e in l if all(e[k] == v for (k, v) in pairs)]
391
+
392
+
393
+ def logical_op(func, a, b, *args):
394
+ ret = func(a, b)
395
+ for c in args:
396
+ ret = func(ret, c)
397
+ return ret
398
+
399
+
400
+ def replace_nan_by(x, val, inplace=False):
401
+ is_nan = np.isnan(x)
402
+ if np.sum(is_nan) > 0:
403
+ if not inplace:
404
+ x = x.copy()
405
+ x[is_nan] = val
406
+ return x
407
+
408
+
409
+ def set_defaults(kwargs, defaults, overwrite=False, func_get=lambda x: x):
410
+ for k, v in defaults.items():
411
+ if overwrite or k not in kwargs:
412
+ kwargs[k] = func_get(v)
413
+
414
+
415
+ def filter_params(params, prefix, delete_prefix=True):
416
+ ret = {}
417
+ for k, v in params.items():
418
+ if k.startswith(prefix):
419
+ if delete_prefix:
420
+ k = k[len(prefix):]
421
+ ret[k] = v
422
+ return ret
423
+
424
+
425
+ def where_is_what(x):
426
+ H = {}
427
+ for k, e in enumerate(x):
428
+ if e not in H:
429
+ H[e] = []
430
+ H[e].append(k)
431
+ return H
432
+
433
+
434
+ def crossover_mask(X, M):
435
+ # convert input to output by flatting along the first axis
436
+ _X = np.copy(X)
437
+ _X[0][M] = X[1][M]
438
+ _X[1][M] = X[0][M]
439
+ return _X
440
+
441
+
442
+ @default_random_state
443
+ def row_at_least_once_true(M, random_state=None):
444
+ _, d = M.shape
445
+ for k in np.where(~np.any(M, axis=1))[0]:
446
+ M[k, random_state.integers(d)] = True
447
+ return M
File without changes
@@ -0,0 +1,159 @@
1
+ """Module which implements Dominance Degree Approaches for Non-dominated Sorting.
2
+
3
+ For the original work see:
4
+ DDA-NS https://ieeexplore.ieee.org/document/7469397
5
+ DDA-ENS https://ieeexplore.ieee.org/document/9282978
6
+
7
+ Adapted from https://github.com/rsenwar/Non-Dominated-Sorting-Algorithms/tree/master
8
+ """
9
+
10
+
11
+ from typing import Literal, List
12
+ import numpy as np
13
+
14
+
15
+ def construct_comp_matrix(vec: np.ndarray, sorted_idx: np.ndarray) -> np.ndarray:
16
+ """
17
+ const_comp_mat construct the comparison matrix from a row-vector vec.
18
+
19
+ Parameters
20
+ ----------
21
+ vec : np.ndarray
22
+ The vector of scores for the population on a single objective
23
+ sorted_idx : np.ndarray
24
+ The indices which would sort `vec`
25
+
26
+ Returns
27
+ -------
28
+ np.ndarray
29
+ The comparison matrix indicating whether each member in the population dominates the other member for the
30
+ objective in `vec`
31
+ """
32
+ n = vec.shape[0]
33
+ c = np.zeros(shape=(n, n), dtype=np.int32)
34
+
35
+ # the elements of the b(0)-th row in C are all set to 1
36
+ c[sorted_idx[0], :] = 1
37
+
38
+ for i in range(1, n):
39
+ if vec[sorted_idx[i]] == vec[sorted_idx[i - 1]]:
40
+ # the rows in C corresponding to the same elements in w are identical
41
+ c[sorted_idx[i]] = c[sorted_idx[i - 1]]
42
+ else:
43
+ c[sorted_idx[i], sorted_idx[i:]] = 1
44
+
45
+ return c
46
+
47
+
48
+ def construct_domination_matrix(f_scores: np.ndarray, **kwargs) -> np.ndarray:
49
+ """
50
+ construct_domination_matrix calculates the dominance degree matrix for a set of vectors.
51
+
52
+ The dominance degree indicate the degree of dominance of a solution, which is the number of
53
+ objectives for which it is the dominating solution.
54
+
55
+ Parameters
56
+ ----------
57
+ f_scores : np.ndarray
58
+ an N x M matrix of N (population size) objective function values for M objectives
59
+ """
60
+ d = np.zeros((f_scores.shape[0], f_scores.shape[0]), dtype=np.int32)
61
+ b = np.apply_over_axes(np.argsort, f_scores, axes=0)
62
+ for vec, srt in zip(f_scores.T, b.T):
63
+ d += construct_comp_matrix(vec, srt)
64
+ d = np.where(
65
+ np.logical_and(d == f_scores.shape[-1], d.T == f_scores.shape[-1]), 0, d
66
+ )
67
+ return d
68
+
69
+
70
+ def dda_ns(f_scores: np.ndarray, **kwargs) -> List[List[int]]:
71
+ """
72
+ dda_ns runs the DDA-NS algorithm.
73
+
74
+ Parameters
75
+ ----------
76
+ f_scores : np.ndarray
77
+ an N x M matrix of N (population size) objective function values for M objectives
78
+
79
+ Returns
80
+ -------
81
+ List[List[int]]
82
+ A list of members of each Pareto front. The index in the outer most list corresponds to the level in the Pareto front
83
+ while the value in the inner-most list is the id of the member of the population belonging to that front.
84
+ """
85
+ d_mx = construct_domination_matrix(f_scores)
86
+ max_d = np.empty((f_scores.shape[0],), dtype=np.int32)
87
+
88
+ fronts = []
89
+ count = 0
90
+ while count < f_scores.shape[0]:
91
+ # Max(D) is the row vector containing the maximum elements from each column of D
92
+ np.max(d_mx, out=max_d, axis=0)
93
+ front = [i for i, m_d in enumerate(max_d) if 0 <= m_d < f_scores.shape[-1]]
94
+ count += len(front)
95
+ d_mx[front] = -1
96
+ d_mx[:, front] = -1
97
+ fronts.append(front)
98
+
99
+ return fronts
100
+
101
+
102
+ def dda_ens(f_scores: np.ndarray, **kwargs) -> List[List[int]]:
103
+ """
104
+ dda_ens runs the DDA-ENS (efficient DDA) algorithm
105
+
106
+ Parameters
107
+ ----------
108
+ f_scores : np.ndarray
109
+ The N x M matrix of N (population size) objective function values for M objectives
110
+
111
+ Returns
112
+ -------
113
+ List[List[int]]
114
+ an N x M matrix of N (population size) objective function values for M objectives
115
+ """
116
+ d_mx = construct_domination_matrix(f_scores)
117
+
118
+ fronts: List[List[int]] = []
119
+ for s in np.lexsort(f_scores.T):
120
+ isinserted = False
121
+ for fk in fronts:
122
+ if not (d_mx[fk, s] == f_scores.shape[1]).any():
123
+ fk.append(s)
124
+ isinserted = True
125
+ break
126
+ if not isinserted:
127
+ fronts.append([s])
128
+ return fronts
129
+
130
+
131
+ def dominance_degree_non_dominated_sort(
132
+ f_scores: np.ndarray, strategy: Literal["efficient", "fast"] = "efficient"
133
+ ) -> List[List[int]]:
134
+ """
135
+ dominance_degree_non_dominated_sort performs the non-dominating sort with the specified algorithm
136
+
137
+ Parameters
138
+ ----------
139
+ f_scores : np.ndarray
140
+ The N x M matrix of N (population size) objective function values for M objectives
141
+ strategy : Literal["efficient", "fast"], optional
142
+ The dominance degree algorithm to use, by default "efficient"
143
+
144
+ Returns
145
+ -------
146
+ List[List[int]]
147
+ A list of members of each Pareto front. The index in the outer most list corresponds to the level in the Pareto front
148
+ while the value in the inner-most list is the id of the member of the population belonging to that front.
149
+
150
+ Raises
151
+ ------
152
+ ValueError
153
+ If an invalid strategy is specified
154
+ """
155
+ if strategy == "efficient":
156
+ return dda_ens(f_scores)
157
+ if strategy == "fast":
158
+ return dda_ns(f_scores)
159
+ raise ValueError("Invalid search strategy")