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/core/problem.py ADDED
@@ -0,0 +1,373 @@
1
+ from __future__ import annotations
2
+
3
+ from abc import abstractmethod
4
+
5
+ import numpy as np
6
+
7
+ import pymoo.gradient.toolbox as anp
8
+ from pymoo.util.cache import Cache
9
+ from pymoo.util.misc import at_least_2d_array
10
+
11
+
12
+ class LoopedElementwiseEvaluation:
13
+ """Default sequential evaluation for elementwise problems."""
14
+
15
+ def __call__(self, f, X):
16
+ return [f(x) for x in X]
17
+
18
+
19
+ class ElementwiseEvaluationFunction:
20
+
21
+ def __init__(self, problem, args, kwargs) -> None:
22
+ super().__init__()
23
+ self.problem = problem
24
+ self.args = args
25
+ self.kwargs = kwargs
26
+
27
+ def __call__(self, x):
28
+ out = dict()
29
+ self.problem._evaluate(x, out, *self.args, **self.kwargs)
30
+ return out
31
+
32
+
33
+ class Problem:
34
+ def __init__(self,
35
+ n_var=-1,
36
+ n_obj=1,
37
+ n_ieq_constr=0,
38
+ n_eq_constr=0,
39
+ xl=None,
40
+ xu=None,
41
+ vtype=None,
42
+ vars=None,
43
+ elementwise=False,
44
+ elementwise_func=ElementwiseEvaluationFunction,
45
+ elementwise_runner=LoopedElementwiseEvaluation(),
46
+ requires_kwargs=False,
47
+ replace_nan_values_by=None,
48
+ exclude_from_serialization=None,
49
+ callback=None,
50
+ strict=True,
51
+ **kwargs):
52
+
53
+ """
54
+
55
+ Parameters
56
+ ----------
57
+ n_var : int
58
+ Number of Variables
59
+
60
+ n_obj : int
61
+ Number of Objectives
62
+
63
+ n_ieq_constr : int
64
+ Number of Inequality Constraints
65
+
66
+ n_eq_constr : int
67
+ Number of Equality Constraints
68
+
69
+ xl : np.array, float, int
70
+ Lower bounds for the variables. if integer all lower bounds are equal.
71
+
72
+ xu : np.array, float, int
73
+ Upper bounds for the variable. if integer all upper bounds are equal.
74
+
75
+ vtype : type
76
+ The variable type. So far, just used as a type hint.
77
+
78
+ """
79
+
80
+ # number of variable
81
+ self.n_var = n_var
82
+
83
+ # number of objectives
84
+ self.n_obj = n_obj
85
+
86
+ # number of inequality constraints
87
+ self.n_ieq_constr = n_ieq_constr if "n_constr" not in kwargs else max(n_ieq_constr, kwargs["n_constr"])
88
+
89
+ # number of equality constraints
90
+ self.n_eq_constr = n_eq_constr
91
+
92
+ # type of the variable to be evaluated
93
+ self.data = dict(**kwargs)
94
+
95
+ # the lower bounds, make sure it is a numpy array with the length of n_var
96
+ self.xl, self.xu = xl, xu
97
+
98
+ # a callback function to be called after every evaluation
99
+ self.callback = callback
100
+
101
+ # if the variables are provided in their explicit form
102
+ if vars is not None:
103
+ self.vars = vars
104
+ self.n_var = len(vars)
105
+
106
+ if self.xl is None:
107
+ self.xl = {name: var.lb if hasattr(var, "lb") else None for name, var in vars.items()}
108
+ if self.xu is None:
109
+ self.xu = {name: var.ub if hasattr(var, "ub") else None for name, var in vars.items()}
110
+
111
+ # the variable type (only as a type hint at this point)
112
+ self.vtype = vtype
113
+
114
+ # the functions used if elementwise is enabled
115
+ self.elementwise = elementwise
116
+ self.elementwise_func = elementwise_func
117
+ self.elementwise_runner = elementwise_runner
118
+
119
+ # whether evaluation requires kwargs (passing them can cause overhead in parallelization)
120
+ self.requires_kwargs = requires_kwargs
121
+
122
+ # whether the shapes are checked strictly
123
+ self.strict = strict
124
+
125
+ # if it is a problem with an actual number of variables - make sure xl and xu are numpy arrays
126
+ if n_var > 0:
127
+
128
+ if self.xl is not None:
129
+ if not isinstance(self.xl, np.ndarray):
130
+ self.xl = np.ones(n_var) * xl
131
+ self.xl = self.xl.astype(float)
132
+
133
+ if self.xu is not None:
134
+ if not isinstance(self.xu, np.ndarray):
135
+ self.xu = np.ones(n_var) * xu
136
+ self.xu = self.xu.astype(float)
137
+
138
+ # this defines if NaN values should be replaced or not
139
+ self.replace_nan_values_by = replace_nan_values_by
140
+
141
+ # attribute which are excluded from being serialized
142
+ self.exclude_from_serialization = exclude_from_serialization
143
+
144
+ def evaluate(self,
145
+ X,
146
+ *args,
147
+ return_values_of=None,
148
+ return_as_dictionary=False,
149
+ **kwargs):
150
+
151
+ # if the problem does not require any kwargs they are re-initialized
152
+ if not self.requires_kwargs:
153
+ kwargs = dict()
154
+
155
+ if return_values_of is None:
156
+ return_values_of = ["F"]
157
+ if self.n_ieq_constr > 0:
158
+ return_values_of.append("G")
159
+ if self.n_eq_constr > 0:
160
+ return_values_of.append("H")
161
+
162
+ # make sure the array is at least 2d. store if reshaping was necessary
163
+ if isinstance(X, np.ndarray) and X.dtype != object:
164
+ X, only_single_value = at_least_2d_array(X, extend_as="row", return_if_reshaped=True)
165
+ assert X.shape[1] == self.n_var, f'Input dimension {X.shape[1]} are not equal to n_var {self.n_var}!'
166
+ else:
167
+ only_single_value = not (isinstance(X, list) or isinstance(X, np.ndarray))
168
+
169
+ # this is where the actual evaluation takes place
170
+ _out = self.do(X, return_values_of, *args, **kwargs)
171
+
172
+ out = {}
173
+ for k, v in _out.items():
174
+
175
+ # copy it to a numpy array (it might be one of jax at this point)
176
+ v = np.array(v)
177
+
178
+ # in case the input had only one dimension, then remove always the first dimension from each output
179
+ if only_single_value:
180
+ v = v[0]
181
+
182
+ # if the NaN values should be replaced
183
+ if self.replace_nan_values_by is not None:
184
+ v[np.isnan(v)] = self.replace_nan_values_by
185
+
186
+ try:
187
+ out[k] = v.astype(np.float64)
188
+ except:
189
+ out[k] = v
190
+
191
+ if self.callback is not None:
192
+ self.callback(X, out)
193
+
194
+ # now depending on what should be returned prepare the output
195
+ if return_as_dictionary:
196
+ return out
197
+
198
+ if len(return_values_of) == 1:
199
+ return out[return_values_of[0]]
200
+ else:
201
+ return tuple([out[e] for e in return_values_of])
202
+
203
+ def do(self, X, return_values_of, *args, **kwargs):
204
+
205
+ # create an empty dictionary
206
+ out = {name: None for name in return_values_of}
207
+
208
+ # do the function evaluation
209
+ if self.elementwise:
210
+ self._evaluate_elementwise(X, out, *args, **kwargs)
211
+ else:
212
+ self._evaluate_vectorized(X, out, *args, **kwargs)
213
+
214
+ # finally format the output dictionary
215
+ out = self._format_dict(out, len(X), return_values_of)
216
+
217
+ return out
218
+
219
+ def _evaluate_vectorized(self, X, out, *args, **kwargs):
220
+ self._evaluate(X, out, *args, **kwargs)
221
+
222
+ def _evaluate_elementwise(self, X, out, *args, **kwargs):
223
+
224
+ # create the function that evaluates a single individual
225
+ f = self.elementwise_func(self, args, kwargs)
226
+
227
+ # execute the runner
228
+ elems = self.elementwise_runner(f, X)
229
+
230
+ # for each evaluation call
231
+ for elem in elems:
232
+
233
+ # for each key stored for this evaluation
234
+ for k, v in elem.items():
235
+
236
+ # if the element does not exist in out yet -> create it
237
+ if out.get(k, None) is None:
238
+ out[k] = []
239
+
240
+ out[k].append(v)
241
+
242
+ # convert to arrays (the none check is important because otherwise an empty array is initialized)
243
+ for k in out:
244
+ if out[k] is not None:
245
+ out[k] = anp.array(out[k])
246
+
247
+ def _format_dict(self, out, N, return_values_of):
248
+
249
+ # get the default output shape for the default values
250
+ shape = default_shape(self, N)
251
+
252
+ # finally the array to be returned
253
+ ret = {}
254
+
255
+ # for all values that have been set in the user implemented function
256
+ for name, v in out.items():
257
+
258
+ # only if they have truly been set
259
+ if v is not None:
260
+
261
+ # if there is a shape to be expected
262
+ if name in shape:
263
+
264
+ if isinstance(v, list):
265
+ v = anp.column_stack(v)
266
+
267
+ try:
268
+ v = v.reshape(shape[name])
269
+ except Exception as e:
270
+ raise Exception(
271
+ f"Problem Error: {name} can not be set, expected shape {shape[name]} but provided {v.shape}",
272
+ e)
273
+
274
+ ret[name] = v
275
+
276
+ # if some values that are necessary have not been set
277
+ for name in return_values_of:
278
+ if name not in ret:
279
+ s = shape.get(name, N)
280
+ ret[name] = np.full(s, np.inf)
281
+
282
+ return ret
283
+
284
+ @Cache
285
+ def nadir_point(self, *args, **kwargs):
286
+ pf = self.pareto_front(*args, **kwargs)
287
+ if pf is not None:
288
+ return np.max(pf, axis=0)
289
+
290
+ @Cache
291
+ def ideal_point(self, *args, **kwargs):
292
+ pf = self.pareto_front(*args, **kwargs)
293
+ if pf is not None:
294
+ return np.min(pf, axis=0)
295
+
296
+ @Cache
297
+ def pareto_front(self, *args, **kwargs):
298
+ pf = self._calc_pareto_front(*args, **kwargs)
299
+ pf = at_least_2d_array(pf, extend_as='r')
300
+ if pf is not None and pf.shape[1] == 2:
301
+ pf = pf[np.argsort(pf[:, 0])]
302
+ return pf
303
+
304
+ @Cache
305
+ def pareto_set(self, *args, **kwargs):
306
+ ps = self._calc_pareto_set(*args, **kwargs)
307
+ ps = at_least_2d_array(ps, extend_as='r')
308
+ return ps
309
+
310
+ @property
311
+ def n_constr(self):
312
+ return self.n_ieq_constr + self.n_eq_constr
313
+
314
+ @abstractmethod
315
+ def _evaluate(self, x, out, *args, **kwargs):
316
+ pass
317
+
318
+ def has_bounds(self):
319
+ return self.xl is not None and self.xu is not None
320
+
321
+ def has_constraints(self):
322
+ return self.n_constr > 0
323
+
324
+ def bounds(self):
325
+ return self.xl, self.xu
326
+
327
+ def name(self):
328
+ return self.__class__.__name__
329
+
330
+ def _calc_pareto_front(self, *args, **kwargs):
331
+ pass
332
+
333
+ def _calc_pareto_set(self, *args, **kwargs):
334
+ pass
335
+
336
+ def __str__(self):
337
+ s = "# name: %s\n" % self.name()
338
+ s += "# n_var: %s\n" % self.n_var
339
+ s += "# n_obj: %s\n" % self.n_obj
340
+ s += "# n_ieq_constr: %s\n" % self.n_ieq_constr
341
+ s += "# n_eq_constr: %s\n" % self.n_eq_constr
342
+ return s
343
+
344
+ def __getstate__(self):
345
+ if self.exclude_from_serialization is not None:
346
+ state = self.__dict__.copy()
347
+
348
+ # exclude objects which should not be stored
349
+ for key in self.exclude_from_serialization:
350
+ state[key] = None
351
+
352
+ return state
353
+ else:
354
+ return self.__dict__
355
+
356
+
357
+ class ElementwiseProblem(Problem):
358
+
359
+ def __init__(self, elementwise=True, **kwargs):
360
+ super().__init__(elementwise=elementwise, **kwargs)
361
+
362
+
363
+ def default_shape(problem, n):
364
+ n_var = problem.n_var
365
+ DEFAULTS = dict(
366
+ F=(n, problem.n_obj),
367
+ G=(n, problem.n_ieq_constr),
368
+ H=(n, problem.n_eq_constr),
369
+ dF=(n, problem.n_obj, n_var),
370
+ dG=(n, problem.n_ieq_constr, n_var),
371
+ dH=(n, problem.n_eq_constr, n_var),
372
+ )
373
+ 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)
pymoo/core/result.py ADDED
@@ -0,0 +1,52 @@
1
+ class Result:
2
+ """
3
+ The resulting object of an optimization run.
4
+ """
5
+
6
+ def __init__(self) -> None:
7
+ super().__init__()
8
+
9
+ self.opt = None
10
+ self.success = None
11
+ self.message = None
12
+
13
+ # ! other attributes to be set as well
14
+
15
+ # the problem that was solved
16
+ self.problem = None
17
+
18
+ # the archive stored during the run
19
+ self.archive = None
20
+
21
+ # the optimal solution for that problem
22
+ self.pf = None
23
+
24
+ # the algorithm that was used for optimization
25
+ self.algorithm = None
26
+
27
+ # the final population if it applies
28
+ self.pop = None
29
+
30
+ # directly the values of opt
31
+ self.X, self.F, self.CV, self.G, self.H = None, None, None, None, None
32
+
33
+ # all the timings that are stored of the run
34
+ self.start_time, self.end_time, self.exec_time = None, None, None
35
+
36
+ # the history of the optimization run is they were saved
37
+ self.history = []
38
+
39
+ # data stored within the algorithm
40
+ self.data = None
41
+
42
+ @property
43
+ def cv(self):
44
+ return self.CV[0]
45
+
46
+ @property
47
+ def f(self):
48
+ return self.F[0]
49
+
50
+ @property
51
+ def feas(self):
52
+ return self.cv <= 0
pymoo/core/sampling.py ADDED
@@ -0,0 +1,45 @@
1
+ from abc import abstractmethod
2
+
3
+ from pymoo.core.operator import Operator
4
+ from pymoo.core.population import Population
5
+ from pymoo.util import default_random_state
6
+
7
+
8
+ class Sampling(Operator):
9
+
10
+ def __init__(self) -> None:
11
+ """
12
+ This abstract class represents any sampling strategy that can be used to create an initial population or
13
+ an initial search point.
14
+ """
15
+ super().__init__()
16
+
17
+ @default_random_state
18
+ def do(self, problem, n_samples, *args, random_state=None, **kwargs):
19
+ """
20
+ Sample new points with problem information if necessary.
21
+
22
+ Parameters
23
+ ----------
24
+
25
+ problem : :class:`~pymoo.core.problem.Problem`
26
+ The problem to which points should be sampled. (lower and upper bounds, discrete, binary, ...)
27
+
28
+ n_samples : int
29
+ Number of samples
30
+
31
+ Returns
32
+ -------
33
+ pop : Population
34
+ The output population after sampling
35
+
36
+ """
37
+ val = self._do(problem, n_samples, *args, random_state=random_state, **kwargs)
38
+ return Population.new("X", val)
39
+
40
+ @abstractmethod
41
+ def _do(self, problem, n_samples, *args, random_state=None, **kwargs):
42
+ pass
43
+
44
+
45
+