pymoo 0.6.1.5.dev0__cp311-cp311-musllinux_1_2_x86_64.whl

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

Potentially problematic release.


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

Files changed (330) hide show
  1. pymoo/__init__.py +3 -0
  2. pymoo/algorithms/__init__.py +0 -0
  3. pymoo/algorithms/base/__init__.py +0 -0
  4. pymoo/algorithms/base/bracket.py +38 -0
  5. pymoo/algorithms/base/genetic.py +109 -0
  6. pymoo/algorithms/base/line.py +62 -0
  7. pymoo/algorithms/base/local.py +39 -0
  8. pymoo/algorithms/base/meta.py +79 -0
  9. pymoo/algorithms/hyperparameters.py +89 -0
  10. pymoo/algorithms/moo/__init__.py +0 -0
  11. pymoo/algorithms/moo/age.py +310 -0
  12. pymoo/algorithms/moo/age2.py +194 -0
  13. pymoo/algorithms/moo/ctaea.py +298 -0
  14. pymoo/algorithms/moo/dnsga2.py +76 -0
  15. pymoo/algorithms/moo/kgb.py +446 -0
  16. pymoo/algorithms/moo/moead.py +183 -0
  17. pymoo/algorithms/moo/nsga2.py +113 -0
  18. pymoo/algorithms/moo/nsga3.py +358 -0
  19. pymoo/algorithms/moo/pinsga2.py +370 -0
  20. pymoo/algorithms/moo/rnsga2.py +188 -0
  21. pymoo/algorithms/moo/rnsga3.py +246 -0
  22. pymoo/algorithms/moo/rvea.py +214 -0
  23. pymoo/algorithms/moo/sms.py +195 -0
  24. pymoo/algorithms/moo/spea2.py +190 -0
  25. pymoo/algorithms/moo/unsga3.py +47 -0
  26. pymoo/algorithms/soo/__init__.py +0 -0
  27. pymoo/algorithms/soo/convex/__init__.py +0 -0
  28. pymoo/algorithms/soo/nonconvex/__init__.py +0 -0
  29. pymoo/algorithms/soo/nonconvex/brkga.py +161 -0
  30. pymoo/algorithms/soo/nonconvex/cmaes.py +554 -0
  31. pymoo/algorithms/soo/nonconvex/de.py +279 -0
  32. pymoo/algorithms/soo/nonconvex/direct.py +149 -0
  33. pymoo/algorithms/soo/nonconvex/es.py +203 -0
  34. pymoo/algorithms/soo/nonconvex/g3pcx.py +94 -0
  35. pymoo/algorithms/soo/nonconvex/ga.py +93 -0
  36. pymoo/algorithms/soo/nonconvex/ga_niching.py +223 -0
  37. pymoo/algorithms/soo/nonconvex/isres.py +74 -0
  38. pymoo/algorithms/soo/nonconvex/nelder.py +251 -0
  39. pymoo/algorithms/soo/nonconvex/optuna.py +80 -0
  40. pymoo/algorithms/soo/nonconvex/pattern.py +183 -0
  41. pymoo/algorithms/soo/nonconvex/pso.py +399 -0
  42. pymoo/algorithms/soo/nonconvex/pso_ep.py +297 -0
  43. pymoo/algorithms/soo/nonconvex/random_search.py +25 -0
  44. pymoo/algorithms/soo/nonconvex/sres.py +56 -0
  45. pymoo/algorithms/soo/univariate/__init__.py +0 -0
  46. pymoo/algorithms/soo/univariate/backtracking.py +59 -0
  47. pymoo/algorithms/soo/univariate/exp.py +46 -0
  48. pymoo/algorithms/soo/univariate/golden.py +65 -0
  49. pymoo/algorithms/soo/univariate/quadr_interp.py +81 -0
  50. pymoo/algorithms/soo/univariate/wolfe.py +163 -0
  51. pymoo/config.py +33 -0
  52. pymoo/constraints/__init__.py +3 -0
  53. pymoo/constraints/adaptive.py +62 -0
  54. pymoo/constraints/as_obj.py +56 -0
  55. pymoo/constraints/as_penalty.py +41 -0
  56. pymoo/constraints/eps.py +26 -0
  57. pymoo/constraints/from_bounds.py +36 -0
  58. pymoo/core/__init__.py +0 -0
  59. pymoo/core/algorithm.py +394 -0
  60. pymoo/core/callback.py +38 -0
  61. pymoo/core/crossover.py +77 -0
  62. pymoo/core/decision_making.py +102 -0
  63. pymoo/core/decomposition.py +76 -0
  64. pymoo/core/duplicate.py +163 -0
  65. pymoo/core/evaluator.py +116 -0
  66. pymoo/core/indicator.py +34 -0
  67. pymoo/core/individual.py +784 -0
  68. pymoo/core/infill.py +64 -0
  69. pymoo/core/initialization.py +42 -0
  70. pymoo/core/mating.py +39 -0
  71. pymoo/core/meta.py +21 -0
  72. pymoo/core/mixed.py +165 -0
  73. pymoo/core/mutation.py +44 -0
  74. pymoo/core/operator.py +40 -0
  75. pymoo/core/parameters.py +134 -0
  76. pymoo/core/plot.py +210 -0
  77. pymoo/core/population.py +180 -0
  78. pymoo/core/problem.py +460 -0
  79. pymoo/core/recorder.py +99 -0
  80. pymoo/core/repair.py +23 -0
  81. pymoo/core/replacement.py +96 -0
  82. pymoo/core/result.py +52 -0
  83. pymoo/core/sampling.py +43 -0
  84. pymoo/core/selection.py +61 -0
  85. pymoo/core/solution.py +10 -0
  86. pymoo/core/survival.py +103 -0
  87. pymoo/core/termination.py +70 -0
  88. pymoo/core/variable.py +399 -0
  89. pymoo/cython/__init__.py +0 -0
  90. pymoo/cython/calc_perpendicular_distance.cpython-311-x86_64-linux-musl.so +0 -0
  91. pymoo/cython/calc_perpendicular_distance.pyx +67 -0
  92. pymoo/cython/decomposition.cpython-311-x86_64-linux-musl.so +0 -0
  93. pymoo/cython/decomposition.pyx +165 -0
  94. pymoo/cython/hv.cpython-311-x86_64-linux-musl.so +0 -0
  95. pymoo/cython/hv.pyx +18 -0
  96. pymoo/cython/info.cpython-311-x86_64-linux-musl.so +0 -0
  97. pymoo/cython/info.pyx +5 -0
  98. pymoo/cython/mnn.cpython-311-x86_64-linux-musl.so +0 -0
  99. pymoo/cython/mnn.pyx +273 -0
  100. pymoo/cython/non_dominated_sorting.cpython-311-x86_64-linux-musl.so +0 -0
  101. pymoo/cython/non_dominated_sorting.pyx +645 -0
  102. pymoo/cython/pruning_cd.cpython-311-x86_64-linux-musl.so +0 -0
  103. pymoo/cython/pruning_cd.pyx +197 -0
  104. pymoo/cython/stochastic_ranking.cpython-311-x86_64-linux-musl.so +0 -0
  105. pymoo/cython/stochastic_ranking.pyx +49 -0
  106. pymoo/cython/utils.pxd +129 -0
  107. pymoo/cython/vendor/__init__.py +0 -0
  108. pymoo/cython/vendor/hypervolume.cpp +1621 -0
  109. pymoo/cython/vendor/hypervolume.h +63 -0
  110. pymoo/decomposition/__init__.py +0 -0
  111. pymoo/decomposition/aasf.py +24 -0
  112. pymoo/decomposition/asf.py +10 -0
  113. pymoo/decomposition/pbi.py +13 -0
  114. pymoo/decomposition/perp_dist.py +13 -0
  115. pymoo/decomposition/tchebicheff.py +11 -0
  116. pymoo/decomposition/util.py +13 -0
  117. pymoo/decomposition/weighted_sum.py +8 -0
  118. pymoo/docs.py +187 -0
  119. pymoo/experimental/__init__.py +0 -0
  120. pymoo/experimental/algorithms/__init__.py +0 -0
  121. pymoo/experimental/algorithms/gde3.py +57 -0
  122. pymoo/gradient/__init__.py +21 -0
  123. pymoo/gradient/automatic.py +57 -0
  124. pymoo/gradient/grad_autograd.py +105 -0
  125. pymoo/gradient/grad_complex.py +35 -0
  126. pymoo/gradient/grad_jax.py +51 -0
  127. pymoo/gradient/toolbox/__init__.py +6 -0
  128. pymoo/indicators/__init__.py +0 -0
  129. pymoo/indicators/distance_indicator.py +55 -0
  130. pymoo/indicators/gd.py +7 -0
  131. pymoo/indicators/gd_plus.py +7 -0
  132. pymoo/indicators/hv/__init__.py +63 -0
  133. pymoo/indicators/hv/exact.py +71 -0
  134. pymoo/indicators/hv/exact_2d.py +102 -0
  135. pymoo/indicators/hv/monte_carlo.py +74 -0
  136. pymoo/indicators/igd.py +7 -0
  137. pymoo/indicators/igd_plus.py +7 -0
  138. pymoo/indicators/kktpm.py +151 -0
  139. pymoo/indicators/migd.py +55 -0
  140. pymoo/indicators/rmetric.py +203 -0
  141. pymoo/indicators/spacing.py +52 -0
  142. pymoo/mcdm/__init__.py +0 -0
  143. pymoo/mcdm/compromise_programming.py +19 -0
  144. pymoo/mcdm/high_tradeoff.py +40 -0
  145. pymoo/mcdm/pseudo_weights.py +32 -0
  146. pymoo/operators/__init__.py +0 -0
  147. pymoo/operators/control.py +187 -0
  148. pymoo/operators/crossover/__init__.py +0 -0
  149. pymoo/operators/crossover/binx.py +45 -0
  150. pymoo/operators/crossover/dex.py +122 -0
  151. pymoo/operators/crossover/erx.py +162 -0
  152. pymoo/operators/crossover/expx.py +51 -0
  153. pymoo/operators/crossover/hux.py +37 -0
  154. pymoo/operators/crossover/nox.py +13 -0
  155. pymoo/operators/crossover/ox.py +84 -0
  156. pymoo/operators/crossover/pcx.py +82 -0
  157. pymoo/operators/crossover/pntx.py +49 -0
  158. pymoo/operators/crossover/sbx.py +125 -0
  159. pymoo/operators/crossover/spx.py +5 -0
  160. pymoo/operators/crossover/ux.py +20 -0
  161. pymoo/operators/mutation/__init__.py +0 -0
  162. pymoo/operators/mutation/bitflip.py +17 -0
  163. pymoo/operators/mutation/gauss.py +58 -0
  164. pymoo/operators/mutation/inversion.py +42 -0
  165. pymoo/operators/mutation/nom.py +7 -0
  166. pymoo/operators/mutation/pm.py +94 -0
  167. pymoo/operators/mutation/rm.py +23 -0
  168. pymoo/operators/repair/__init__.py +0 -0
  169. pymoo/operators/repair/bounce_back.py +32 -0
  170. pymoo/operators/repair/bounds_repair.py +95 -0
  171. pymoo/operators/repair/inverse_penalty.py +89 -0
  172. pymoo/operators/repair/rounding.py +18 -0
  173. pymoo/operators/repair/to_bound.py +31 -0
  174. pymoo/operators/repair/vtype.py +11 -0
  175. pymoo/operators/sampling/__init__.py +0 -0
  176. pymoo/operators/sampling/lhs.py +73 -0
  177. pymoo/operators/sampling/rnd.py +50 -0
  178. pymoo/operators/selection/__init__.py +0 -0
  179. pymoo/operators/selection/rnd.py +72 -0
  180. pymoo/operators/selection/tournament.py +76 -0
  181. pymoo/operators/survival/__init__.py +0 -0
  182. pymoo/operators/survival/rank_and_crowding/__init__.py +1 -0
  183. pymoo/operators/survival/rank_and_crowding/classes.py +209 -0
  184. pymoo/operators/survival/rank_and_crowding/metrics.py +208 -0
  185. pymoo/optimize.py +72 -0
  186. pymoo/problems/__init__.py +157 -0
  187. pymoo/problems/dyn.py +47 -0
  188. pymoo/problems/dynamic/__init__.py +0 -0
  189. pymoo/problems/dynamic/cec2015.py +108 -0
  190. pymoo/problems/dynamic/df.py +452 -0
  191. pymoo/problems/dynamic/misc.py +167 -0
  192. pymoo/problems/functional.py +48 -0
  193. pymoo/problems/many/__init__.py +5 -0
  194. pymoo/problems/many/cdtlz.py +159 -0
  195. pymoo/problems/many/dcdtlz.py +88 -0
  196. pymoo/problems/many/dtlz.py +264 -0
  197. pymoo/problems/many/wfg.py +550 -0
  198. pymoo/problems/multi/__init__.py +14 -0
  199. pymoo/problems/multi/bnh.py +34 -0
  200. pymoo/problems/multi/carside.py +48 -0
  201. pymoo/problems/multi/clutch.py +104 -0
  202. pymoo/problems/multi/csi.py +55 -0
  203. pymoo/problems/multi/ctp.py +198 -0
  204. pymoo/problems/multi/dascmop.py +213 -0
  205. pymoo/problems/multi/kursawe.py +25 -0
  206. pymoo/problems/multi/modact.py +68 -0
  207. pymoo/problems/multi/mw.py +400 -0
  208. pymoo/problems/multi/omnitest.py +48 -0
  209. pymoo/problems/multi/osy.py +32 -0
  210. pymoo/problems/multi/srn.py +28 -0
  211. pymoo/problems/multi/sympart.py +94 -0
  212. pymoo/problems/multi/tnk.py +24 -0
  213. pymoo/problems/multi/truss2d.py +83 -0
  214. pymoo/problems/multi/welded_beam.py +41 -0
  215. pymoo/problems/multi/wrm.py +36 -0
  216. pymoo/problems/multi/zdt.py +151 -0
  217. pymoo/problems/multi_to_single.py +22 -0
  218. pymoo/problems/single/__init__.py +12 -0
  219. pymoo/problems/single/ackley.py +24 -0
  220. pymoo/problems/single/cantilevered_beam.py +34 -0
  221. pymoo/problems/single/flowshop_scheduling.py +112 -0
  222. pymoo/problems/single/g.py +874 -0
  223. pymoo/problems/single/griewank.py +18 -0
  224. pymoo/problems/single/himmelblau.py +15 -0
  225. pymoo/problems/single/knapsack.py +48 -0
  226. pymoo/problems/single/mopta08.py +26 -0
  227. pymoo/problems/single/multimodal.py +20 -0
  228. pymoo/problems/single/pressure_vessel.py +30 -0
  229. pymoo/problems/single/rastrigin.py +20 -0
  230. pymoo/problems/single/rosenbrock.py +22 -0
  231. pymoo/problems/single/schwefel.py +18 -0
  232. pymoo/problems/single/simple.py +13 -0
  233. pymoo/problems/single/sphere.py +19 -0
  234. pymoo/problems/single/traveling_salesman.py +79 -0
  235. pymoo/problems/single/zakharov.py +19 -0
  236. pymoo/problems/static.py +14 -0
  237. pymoo/problems/util.py +42 -0
  238. pymoo/problems/zero_to_one.py +27 -0
  239. pymoo/termination/__init__.py +23 -0
  240. pymoo/termination/collection.py +12 -0
  241. pymoo/termination/cv.py +48 -0
  242. pymoo/termination/default.py +45 -0
  243. pymoo/termination/delta.py +64 -0
  244. pymoo/termination/fmin.py +16 -0
  245. pymoo/termination/ftol.py +144 -0
  246. pymoo/termination/indicator.py +49 -0
  247. pymoo/termination/max_eval.py +14 -0
  248. pymoo/termination/max_gen.py +15 -0
  249. pymoo/termination/max_time.py +20 -0
  250. pymoo/termination/robust.py +34 -0
  251. pymoo/termination/xtol.py +33 -0
  252. pymoo/util/__init__.py +0 -0
  253. pymoo/util/archive.py +150 -0
  254. pymoo/util/cache.py +29 -0
  255. pymoo/util/clearing.py +82 -0
  256. pymoo/util/display/__init__.py +0 -0
  257. pymoo/util/display/column.py +52 -0
  258. pymoo/util/display/display.py +34 -0
  259. pymoo/util/display/multi.py +96 -0
  260. pymoo/util/display/output.py +53 -0
  261. pymoo/util/display/progress.py +54 -0
  262. pymoo/util/display/single.py +67 -0
  263. pymoo/util/dominator.py +67 -0
  264. pymoo/util/function_loader.py +129 -0
  265. pymoo/util/hv.py +23 -0
  266. pymoo/util/matlab_engine.py +39 -0
  267. pymoo/util/misc.py +460 -0
  268. pymoo/util/mnn.py +70 -0
  269. pymoo/util/nds/__init__.py +0 -0
  270. pymoo/util/nds/dominance_degree_non_dominated_sort.py +159 -0
  271. pymoo/util/nds/efficient_non_dominated_sort.py +152 -0
  272. pymoo/util/nds/fast_non_dominated_sort.py +70 -0
  273. pymoo/util/nds/naive_non_dominated_sort.py +36 -0
  274. pymoo/util/nds/non_dominated_sorting.py +67 -0
  275. pymoo/util/nds/tree_based_non_dominated_sort.py +133 -0
  276. pymoo/util/normalization.py +312 -0
  277. pymoo/util/optimum.py +42 -0
  278. pymoo/util/plotting.py +177 -0
  279. pymoo/util/pruning_cd.py +89 -0
  280. pymoo/util/randomized_argsort.py +60 -0
  281. pymoo/util/ref_dirs/__init__.py +24 -0
  282. pymoo/util/ref_dirs/construction.py +88 -0
  283. pymoo/util/ref_dirs/das_dennis.py +52 -0
  284. pymoo/util/ref_dirs/energy.py +319 -0
  285. pymoo/util/ref_dirs/energy_layer.py +119 -0
  286. pymoo/util/ref_dirs/genetic_algorithm.py +63 -0
  287. pymoo/util/ref_dirs/incremental.py +68 -0
  288. pymoo/util/ref_dirs/misc.py +128 -0
  289. pymoo/util/ref_dirs/optimizer.py +59 -0
  290. pymoo/util/ref_dirs/performance.py +162 -0
  291. pymoo/util/ref_dirs/reduction.py +85 -0
  292. pymoo/util/ref_dirs/sample_and_map.py +24 -0
  293. pymoo/util/reference_direction.py +260 -0
  294. pymoo/util/remote.py +55 -0
  295. pymoo/util/roulette.py +27 -0
  296. pymoo/util/running_metric.py +128 -0
  297. pymoo/util/sliding_window.py +25 -0
  298. pymoo/util/stochastic_ranking.py +32 -0
  299. pymoo/util/value_functions.py +719 -0
  300. pymoo/util/vectors.py +40 -0
  301. pymoo/util/vf_dominator.py +99 -0
  302. pymoo/vendor/__init__.py +0 -0
  303. pymoo/vendor/cec2018.py +398 -0
  304. pymoo/vendor/gta.py +617 -0
  305. pymoo/vendor/hv.py +267 -0
  306. pymoo/vendor/vendor_cmaes.py +412 -0
  307. pymoo/vendor/vendor_coco.py +81 -0
  308. pymoo/vendor/vendor_scipy.py +232 -0
  309. pymoo/version.py +1 -0
  310. pymoo/visualization/__init__.py +8 -0
  311. pymoo/visualization/fitness_landscape.py +127 -0
  312. pymoo/visualization/heatmap.py +123 -0
  313. pymoo/visualization/pcp.py +120 -0
  314. pymoo/visualization/petal.py +91 -0
  315. pymoo/visualization/radar.py +108 -0
  316. pymoo/visualization/radviz.py +68 -0
  317. pymoo/visualization/scatter.py +150 -0
  318. pymoo/visualization/star_coordinate.py +75 -0
  319. pymoo/visualization/util.py +123 -0
  320. pymoo/visualization/video/__init__.py +0 -0
  321. pymoo/visualization/video/callback_video.py +82 -0
  322. pymoo/visualization/video/one_var_one_obj.py +57 -0
  323. pymoo/visualization/video/two_var_one_obj.py +62 -0
  324. pymoo-0.6.1.5.dev0.dist-info/METADATA +187 -0
  325. pymoo-0.6.1.5.dev0.dist-info/RECORD +330 -0
  326. pymoo-0.6.1.5.dev0.dist-info/WHEEL +5 -0
  327. pymoo-0.6.1.5.dev0.dist-info/licenses/LICENSE +191 -0
  328. pymoo-0.6.1.5.dev0.dist-info/top_level.txt +1 -0
  329. pymoo.libs/libgcc_s-2298274a.so.1 +0 -0
  330. pymoo.libs/libstdc++-08d5c7eb.so.6.0.33 +0 -0
pymoo/core/problem.py ADDED
@@ -0,0 +1,460 @@
1
+ from abc import abstractmethod
2
+
3
+ import numpy as np
4
+
5
+ import pymoo.gradient.toolbox as anp
6
+ from pymoo.util.cache import Cache
7
+ from pymoo.util.misc import at_least_2d_array
8
+
9
+ try:
10
+ import ray
11
+ except ImportError:
12
+ ray = None
13
+
14
+
15
+ class ElementwiseEvaluationFunction:
16
+
17
+ def __init__(self, problem, args, kwargs) -> None:
18
+ super().__init__()
19
+ self.problem = problem
20
+ self.args = args
21
+ self.kwargs = kwargs
22
+
23
+ def __call__(self, x):
24
+ out = dict()
25
+ self.problem._evaluate(x, out, *self.args, **self.kwargs)
26
+ return out
27
+
28
+
29
+ class LoopedElementwiseEvaluation:
30
+
31
+ def __call__(self, f, X):
32
+ return [f(x) for x in X]
33
+
34
+
35
+ class StarmapParallelization:
36
+
37
+ def __init__(self, starmap) -> None:
38
+ super().__init__()
39
+ self.starmap = starmap
40
+
41
+ def __call__(self, f, X):
42
+ return list(self.starmap(f, [[x] for x in X]))
43
+
44
+ def __getstate__(self):
45
+ state = self.__dict__.copy()
46
+ state.pop("starmap", None)
47
+ return state
48
+
49
+
50
+ class DaskParallelization:
51
+
52
+ def __init__(self, client) -> None:
53
+ super().__init__()
54
+ self.client = client
55
+
56
+ def __call__(self, f, X):
57
+ jobs = [self.client.submit(f, x) for x in X]
58
+ return [job.result() for job in jobs]
59
+
60
+ def __getstate__(self):
61
+ state = self.__dict__.copy()
62
+ state.pop("client", None)
63
+ return state
64
+
65
+
66
+ class JoblibParallelization:
67
+
68
+ def __init__(self, aJoblibParallel, aJoblibDelayed, *args, **kwargs) -> None:
69
+ super().__init__()
70
+ self.parallel = aJoblibParallel
71
+ self.delayed = aJoblibDelayed
72
+
73
+ def __call__(self, f, X):
74
+ return self.parallel(self.delayed(f)(x) for x in X)
75
+
76
+ def __getstate__(self):
77
+ state = self.__dict__.copy()
78
+ state.pop("parallel", None)
79
+ state.pop("delayed", None)
80
+ return state
81
+
82
+
83
+ class RayParallelization:
84
+ """Use Ray as backend to parallelize problem evaluation.
85
+
86
+ Ray is an open-source unified framework for scaling AI and Python applicaitons.
87
+ Read more here: https://docs.ray.io.
88
+
89
+ You will need to install Ray to use this.
90
+ """
91
+ def __init__(self, job_resources: dict = {'num_cpus': 1}) -> None:
92
+ """
93
+ Parameters
94
+ ----------
95
+ job_resources: A resource in Ray is a key-value pair where the key denotes a
96
+ resource name and the value is a float quantity. Ray has native support for CPU,
97
+ GPU, and memory resource types; `'num_cpus'`, `'num_gpus'`, and `'memory'`.
98
+ Read more here:
99
+ https://docs.ray.io/en/latest/ray-core/scheduling/resources.html.
100
+ """
101
+ assert ray is not None, (
102
+ "Ray must be installed! "
103
+ "You can install Ray with the command: "
104
+ '`pip install -U "ray[default]"`'
105
+ )
106
+ super().__init__()
107
+ self.job_resources = job_resources
108
+
109
+ def __call__(self, f, X):
110
+ runnable = ray.remote(f.__call__.__func__)
111
+ runnable = runnable.options(**self.job_resources)
112
+ futures = [runnable.remote(f, x) for x in X]
113
+ return ray.get(futures)
114
+
115
+ def __getstate__(self):
116
+ state = self.__dict__.copy()
117
+ return state
118
+
119
+
120
+ class Problem:
121
+ def __init__(self,
122
+ n_var=-1,
123
+ n_obj=1,
124
+ n_ieq_constr=0,
125
+ n_eq_constr=0,
126
+ xl=None,
127
+ xu=None,
128
+ vtype=None,
129
+ vars=None,
130
+ elementwise=False,
131
+ elementwise_func=ElementwiseEvaluationFunction,
132
+ elementwise_runner=LoopedElementwiseEvaluation(),
133
+ requires_kwargs=False,
134
+ replace_nan_values_by=None,
135
+ exclude_from_serialization=None,
136
+ callback=None,
137
+ strict=True,
138
+ **kwargs):
139
+
140
+ """
141
+
142
+ Parameters
143
+ ----------
144
+ n_var : int
145
+ Number of Variables
146
+
147
+ n_obj : int
148
+ Number of Objectives
149
+
150
+ n_ieq_constr : int
151
+ Number of Inequality Constraints
152
+
153
+ n_eq_constr : int
154
+ Number of Equality Constraints
155
+
156
+ xl : np.array, float, int
157
+ Lower bounds for the variables. if integer all lower bounds are equal.
158
+
159
+ xu : np.array, float, int
160
+ Upper bounds for the variable. if integer all upper bounds are equal.
161
+
162
+ vtype : type
163
+ The variable type. So far, just used as a type hint.
164
+
165
+ """
166
+
167
+ # number of variable
168
+ self.n_var = n_var
169
+
170
+ # number of objectives
171
+ self.n_obj = n_obj
172
+
173
+ # number of inequality constraints
174
+ self.n_ieq_constr = n_ieq_constr if "n_constr" not in kwargs else max(n_ieq_constr, kwargs["n_constr"])
175
+
176
+ # number of equality constraints
177
+ self.n_eq_constr = n_eq_constr
178
+
179
+ # type of the variable to be evaluated
180
+ self.data = dict(**kwargs)
181
+
182
+ # the lower bounds, make sure it is a numpy array with the length of n_var
183
+ self.xl, self.xu = xl, xu
184
+
185
+ # a callback function to be called after every evaluation
186
+ self.callback = callback
187
+
188
+ # if the variables are provided in their explicit form
189
+ if vars is not None:
190
+ self.vars = vars
191
+ self.n_var = len(vars)
192
+
193
+ if self.xl is None:
194
+ self.xl = {name: var.lb if hasattr(var, "lb") else None for name, var in vars.items()}
195
+ if self.xu is None:
196
+ self.xu = {name: var.ub if hasattr(var, "ub") else None for name, var in vars.items()}
197
+
198
+ # the variable type (only as a type hint at this point)
199
+ self.vtype = vtype
200
+
201
+ # the functions used if elementwise is enabled
202
+ self.elementwise = elementwise
203
+ self.elementwise_func = elementwise_func
204
+ self.elementwise_runner = elementwise_runner
205
+
206
+ # whether evaluation requires kwargs (passing them can cause overhead in parallelization)
207
+ self.requires_kwargs = requires_kwargs
208
+
209
+ # whether the shapes are checked strictly
210
+ self.strict = strict
211
+
212
+ # if it is a problem with an actual number of variables - make sure xl and xu are numpy arrays
213
+ if n_var > 0:
214
+
215
+ if self.xl is not None:
216
+ if not isinstance(self.xl, np.ndarray):
217
+ self.xl = np.ones(n_var) * xl
218
+ self.xl = self.xl.astype(float)
219
+
220
+ if self.xu is not None:
221
+ if not isinstance(self.xu, np.ndarray):
222
+ self.xu = np.ones(n_var) * xu
223
+ self.xu = self.xu.astype(float)
224
+
225
+ # this defines if NaN values should be replaced or not
226
+ self.replace_nan_values_by = replace_nan_values_by
227
+
228
+ # attribute which are excluded from being serialized
229
+ self.exclude_from_serialization = exclude_from_serialization
230
+
231
+ def evaluate(self,
232
+ X,
233
+ *args,
234
+ return_values_of=None,
235
+ return_as_dictionary=False,
236
+ **kwargs):
237
+
238
+ # if the problem does not require any kwargs they are re-initialized
239
+ if not self.requires_kwargs:
240
+ kwargs = dict()
241
+
242
+ if return_values_of is None:
243
+ return_values_of = ["F"]
244
+ if self.n_ieq_constr > 0:
245
+ return_values_of.append("G")
246
+ if self.n_eq_constr > 0:
247
+ return_values_of.append("H")
248
+
249
+ # make sure the array is at least 2d. store if reshaping was necessary
250
+ if isinstance(X, np.ndarray) and X.dtype != object:
251
+ X, only_single_value = at_least_2d_array(X, extend_as="row", return_if_reshaped=True)
252
+ assert X.shape[1] == self.n_var, f'Input dimension {X.shape[1]} are not equal to n_var {self.n_var}!'
253
+ else:
254
+ only_single_value = not (isinstance(X, list) or isinstance(X, np.ndarray))
255
+
256
+ # this is where the actual evaluation takes place
257
+ _out = self.do(X, return_values_of, *args, **kwargs)
258
+
259
+ out = {}
260
+ for k, v in _out.items():
261
+
262
+ # copy it to a numpy array (it might be one of jax at this point)
263
+ v = np.array(v)
264
+
265
+ # in case the input had only one dimension, then remove always the first dimension from each output
266
+ if only_single_value:
267
+ v = v[0]
268
+
269
+ # if the NaN values should be replaced
270
+ if self.replace_nan_values_by is not None:
271
+ v[np.isnan(v)] = self.replace_nan_values_by
272
+
273
+ try:
274
+ out[k] = v.astype(np.float64)
275
+ except:
276
+ out[k] = v
277
+
278
+ if self.callback is not None:
279
+ self.callback(X, out)
280
+
281
+ # now depending on what should be returned prepare the output
282
+ if return_as_dictionary:
283
+ return out
284
+
285
+ if len(return_values_of) == 1:
286
+ return out[return_values_of[0]]
287
+ else:
288
+ return tuple([out[e] for e in return_values_of])
289
+
290
+ def do(self, X, return_values_of, *args, **kwargs):
291
+
292
+ # create an empty dictionary
293
+ out = {name: None for name in return_values_of}
294
+
295
+ # do the function evaluation
296
+ if self.elementwise:
297
+ self._evaluate_elementwise(X, out, *args, **kwargs)
298
+ else:
299
+ self._evaluate_vectorized(X, out, *args, **kwargs)
300
+
301
+ # finally format the output dictionary
302
+ out = self._format_dict(out, len(X), return_values_of)
303
+
304
+ return out
305
+
306
+ def _evaluate_vectorized(self, X, out, *args, **kwargs):
307
+ self._evaluate(X, out, *args, **kwargs)
308
+
309
+ def _evaluate_elementwise(self, X, out, *args, **kwargs):
310
+
311
+ # create the function that evaluates a single individual
312
+ f = self.elementwise_func(self, args, kwargs)
313
+
314
+ # execute the runner
315
+ elems = self.elementwise_runner(f, X)
316
+
317
+ # for each evaluation call
318
+ for elem in elems:
319
+
320
+ # for each key stored for this evaluation
321
+ for k, v in elem.items():
322
+
323
+ # if the element does not exist in out yet -> create it
324
+ if out.get(k, None) is None:
325
+ out[k] = []
326
+
327
+ out[k].append(v)
328
+
329
+ # convert to arrays (the none check is important because otherwise an empty array is initialized)
330
+ for k in out:
331
+ if out[k] is not None:
332
+ out[k] = anp.array(out[k])
333
+
334
+ def _format_dict(self, out, N, return_values_of):
335
+
336
+ # get the default output shape for the default values
337
+ shape = default_shape(self, N)
338
+
339
+ # finally the array to be returned
340
+ ret = {}
341
+
342
+ # for all values that have been set in the user implemented function
343
+ for name, v in out.items():
344
+
345
+ # only if they have truly been set
346
+ if v is not None:
347
+
348
+ # if there is a shape to be expected
349
+ if name in shape:
350
+
351
+ if isinstance(v, list):
352
+ v = anp.column_stack(v)
353
+
354
+ try:
355
+ v = v.reshape(shape[name])
356
+ except Exception as e:
357
+ raise Exception(
358
+ f"Problem Error: {name} can not be set, expected shape {shape[name]} but provided {v.shape}",
359
+ e)
360
+
361
+ ret[name] = v
362
+
363
+ # if some values that are necessary have not been set
364
+ for name in return_values_of:
365
+ if name not in ret:
366
+ s = shape.get(name, N)
367
+ ret[name] = np.full(s, np.inf)
368
+
369
+ return ret
370
+
371
+ @Cache
372
+ def nadir_point(self, *args, **kwargs):
373
+ pf = self.pareto_front(*args, **kwargs)
374
+ if pf is not None:
375
+ return np.max(pf, axis=0)
376
+
377
+ @Cache
378
+ def ideal_point(self, *args, **kwargs):
379
+ pf = self.pareto_front(*args, **kwargs)
380
+ if pf is not None:
381
+ return np.min(pf, axis=0)
382
+
383
+ @Cache
384
+ def pareto_front(self, *args, **kwargs):
385
+ pf = self._calc_pareto_front(*args, **kwargs)
386
+ pf = at_least_2d_array(pf, extend_as='r')
387
+ if pf is not None and pf.shape[1] == 2:
388
+ pf = pf[np.argsort(pf[:, 0])]
389
+ return pf
390
+
391
+ @Cache
392
+ def pareto_set(self, *args, **kwargs):
393
+ ps = self._calc_pareto_set(*args, **kwargs)
394
+ ps = at_least_2d_array(ps, extend_as='r')
395
+ return ps
396
+
397
+ @property
398
+ def n_constr(self):
399
+ return self.n_ieq_constr + self.n_eq_constr
400
+
401
+ @abstractmethod
402
+ def _evaluate(self, x, out, *args, **kwargs):
403
+ pass
404
+
405
+ def has_bounds(self):
406
+ return self.xl is not None and self.xu is not None
407
+
408
+ def has_constraints(self):
409
+ return self.n_constr > 0
410
+
411
+ def bounds(self):
412
+ return self.xl, self.xu
413
+
414
+ def name(self):
415
+ return self.__class__.__name__
416
+
417
+ def _calc_pareto_front(self, *args, **kwargs):
418
+ pass
419
+
420
+ def _calc_pareto_set(self, *args, **kwargs):
421
+ pass
422
+
423
+ def __str__(self):
424
+ s = "# name: %s\n" % self.name()
425
+ s += "# n_var: %s\n" % self.n_var
426
+ s += "# n_obj: %s\n" % self.n_obj
427
+ s += "# n_ieq_constr: %s\n" % self.n_ieq_constr
428
+ s += "# n_eq_constr: %s\n" % self.n_eq_constr
429
+ return s
430
+
431
+ def __getstate__(self):
432
+ if self.exclude_from_serialization is not None:
433
+ state = self.__dict__.copy()
434
+
435
+ # exclude objects which should not be stored
436
+ for key in self.exclude_from_serialization:
437
+ state[key] = None
438
+
439
+ return state
440
+ else:
441
+ return self.__dict__
442
+
443
+
444
+ class ElementwiseProblem(Problem):
445
+
446
+ def __init__(self, elementwise=True, **kwargs):
447
+ super().__init__(elementwise=elementwise, **kwargs)
448
+
449
+
450
+ def default_shape(problem, n):
451
+ n_var = problem.n_var
452
+ DEFAULTS = dict(
453
+ F=(n, problem.n_obj),
454
+ G=(n, problem.n_ieq_constr),
455
+ H=(n, problem.n_eq_constr),
456
+ dF=(n, problem.n_obj, n_var),
457
+ dG=(n, problem.n_ieq_constr, n_var),
458
+ dH=(n, problem.n_eq_constr, n_var),
459
+ )
460
+ return DEFAULTS
pymoo/core/recorder.py ADDED
@@ -0,0 +1,99 @@
1
+ from abc import abstractmethod
2
+
3
+ import numpy as np
4
+
5
+ from pymoo.core.callback import Callback
6
+ from pymoo.indicators.igd import IGD
7
+ from pymoo.indicators.igd_plus import IGDPlus
8
+
9
+
10
+ class Recorder(Callback):
11
+
12
+ def __init__(self, nth_evals=None) -> None:
13
+ super().__init__()
14
+ self.data = []
15
+ self.nth_evals = nth_evals
16
+ self.rec_n_evals = 0
17
+
18
+ def notify(self, algorithm, **kwargs):
19
+
20
+ if self.nth_evals is None:
21
+ self.data.append(self.save(algorithm))
22
+
23
+ else:
24
+ n_evals = algorithm.evaluator.n_eval
25
+
26
+ if n_evals >= self.rec_n_evals:
27
+ self.data.append(self.save(algorithm))
28
+ self.rec_n_evals = (1 + (n_evals // self.nth_evals)) * self.nth_evals
29
+
30
+ @abstractmethod
31
+ def save(self, algorithm):
32
+ pass
33
+
34
+ def get(self, *args, as_array=True):
35
+ ret = []
36
+ for arg in args:
37
+ e = [entry.get(arg) for entry in self.data]
38
+ if as_array:
39
+ e = np.array(e)
40
+ ret.append(e)
41
+ return tuple(ret)
42
+
43
+
44
+ class DefaultSingleObjectiveRecorder(Recorder):
45
+
46
+ def save(self, algorithm):
47
+ n_evals = algorithm.evaluator.n_eval
48
+
49
+ opt = algorithm.opt
50
+ _feas, _cv, _f = opt.get("feas", "cv", "f")
51
+
52
+ cv = _cv.min()
53
+
54
+ if np.any(_feas):
55
+ f = _f[_feas].min()
56
+ else:
57
+ f = np.inf
58
+
59
+ fgap = np.inf
60
+ try:
61
+ pf = algorithm.problem.pareto_front()
62
+ except:
63
+ pf = None
64
+
65
+ if pf is not None:
66
+ fgap = f - pf.min()
67
+
68
+ return dict(n_evals=n_evals, cv=cv, f=f, fgap=fgap)
69
+
70
+
71
+ class DefaultMultiObjectiveRecorder(Recorder):
72
+
73
+ def save(self, algorithm):
74
+
75
+ igd, igd_plus = np.inf, np.inf
76
+
77
+ opt = algorithm.opt
78
+
79
+ # get all optimal solutions that are feasible
80
+ feas_opt = opt[opt.get("feas")]
81
+
82
+ if len(feas_opt) > 0:
83
+
84
+ try:
85
+ pf = algorithm.problem.pareto_front()
86
+ except:
87
+ pf = None
88
+
89
+ if pf is not None:
90
+ F = feas_opt.get("F")
91
+ igd = IGD(pf=pf, zero_to_one=True).do(F)
92
+ igd_plus = IGDPlus(pf=pf, zero_to_one=True).do(F)
93
+
94
+ return {
95
+ "n_evals": algorithm.evaluator.n_eval,
96
+ "cv": opt.get("cv").min(),
97
+ "igd": igd,
98
+ "igd+": igd_plus,
99
+ }
pymoo/core/repair.py ADDED
@@ -0,0 +1,23 @@
1
+ import numpy as np
2
+
3
+ from pymoo.core.operator import Operator
4
+
5
+
6
+ class Repair(Operator):
7
+
8
+ def do(self, problem, pop, **kwargs):
9
+ X = np.array([ind.X for ind in pop])
10
+ if self.vtype is not None:
11
+ X = X.astype(self.vtype)
12
+
13
+ Xp = self._do(problem, X, **kwargs)
14
+
15
+ pop.set("X", Xp)
16
+ return pop
17
+
18
+ def _do(self, problem, X, **kwargs):
19
+ return X
20
+
21
+
22
+ class NoRepair(Repair):
23
+ pass
@@ -0,0 +1,96 @@
1
+ import numpy as np
2
+
3
+ from pymoo.core.duplicate import DefaultDuplicateElimination
4
+ from pymoo.core.individual import Individual
5
+ from pymoo.core.population import Population
6
+ from pymoo.core.survival import Survival
7
+
8
+
9
+ def is_better(_new, _old, eps=0.0):
10
+ both_infeasible = not _old.feas and not _new.feas
11
+ both_feasible = _old.feas and _new.feas
12
+
13
+ if both_infeasible and _old.CV[0] - _new.CV[0] > eps:
14
+ return True
15
+ elif not _old.FEAS and _new.FEAS:
16
+ return True
17
+ elif both_feasible and _old.F[0] - _new.F[0] > eps:
18
+ return True
19
+
20
+ return False
21
+
22
+
23
+ class ReplacementSurvival(Survival):
24
+
25
+ def do(self, problem, pop, off, return_indices=False, inplace=False, **kwargs):
26
+
27
+ # this makes it usable as a traditional survival
28
+ if isinstance(off, int):
29
+ k = off
30
+ off = pop[k:]
31
+ pop = pop[:k]
32
+
33
+ # if the offsprings are simply empty don't do anything
34
+ if len(off) == 0:
35
+ return pop
36
+
37
+ assert len(pop) == len(off), "For the replacement pop and off must have the same number of individuals."
38
+
39
+ pop = Population.create(pop) if isinstance(pop, Individual) else pop
40
+ off = Population.create(off) if isinstance(off, Individual) else off
41
+
42
+ I = self._do(problem, pop, off, **kwargs)
43
+
44
+ if return_indices:
45
+ return I
46
+ else:
47
+ if not inplace:
48
+ pop = pop.copy()
49
+ pop[I] = off[I]
50
+ return pop
51
+
52
+ def _do(self, problem, pop, off, **kwargs):
53
+ pass
54
+
55
+
56
+ class ImprovementReplacement(ReplacementSurvival):
57
+
58
+ def _do(self, problem, pop, off, **kwargs):
59
+
60
+ ret = np.full((len(pop), 1), False)
61
+
62
+ pop_F, pop_CV, pop_feas = pop.get("F", "CV", "FEAS")
63
+ off_F, off_CV, off_feas = off.get("F", "CV", "FEAS")
64
+
65
+ if problem.has_constraints() > 0:
66
+
67
+ # 1) Both infeasible and constraints have been improved
68
+ ret[(~pop_feas & ~off_feas) & (off_CV < pop_CV)] = True
69
+
70
+ # 2) A solution became feasible
71
+ ret[~pop_feas & off_feas] = True
72
+
73
+ # 3) Both feasible but objective space value has improved
74
+ ret[(pop_feas & off_feas) & (off_F < pop_F)] = True
75
+
76
+ else:
77
+ ret[off_F < pop_F] = True
78
+
79
+ # never allow duplicates to become part of the population when replacement is used
80
+ _, _, is_duplicate = DefaultDuplicateElimination(epsilon=0.0).do(off, pop, return_indices=True)
81
+ ret[is_duplicate] = False
82
+
83
+ return ret[:, 0]
84
+
85
+
86
+ def parameter_less(f, cv):
87
+ v = np.copy(f)
88
+ infeas = cv > 0
89
+ v[infeas] = f.max() + cv[infeas]
90
+ return v
91
+
92
+
93
+ def hierarchical_sort(f, cv=None):
94
+ if cv is not None:
95
+ f = parameter_less(f, cv)
96
+ return np.argsort(f)