pymoo 0.6.1.5.dev0__cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

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

Potentially problematic release.


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

Files changed (328) hide show
  1. pymoo/__init__.py +3 -0
  2. pymoo/algorithms/__init__.py +0 -0
  3. pymoo/algorithms/base/__init__.py +0 -0
  4. pymoo/algorithms/base/bracket.py +38 -0
  5. pymoo/algorithms/base/genetic.py +109 -0
  6. pymoo/algorithms/base/line.py +62 -0
  7. pymoo/algorithms/base/local.py +39 -0
  8. pymoo/algorithms/base/meta.py +79 -0
  9. pymoo/algorithms/hyperparameters.py +89 -0
  10. pymoo/algorithms/moo/__init__.py +0 -0
  11. pymoo/algorithms/moo/age.py +310 -0
  12. pymoo/algorithms/moo/age2.py +194 -0
  13. pymoo/algorithms/moo/ctaea.py +298 -0
  14. pymoo/algorithms/moo/dnsga2.py +76 -0
  15. pymoo/algorithms/moo/kgb.py +446 -0
  16. pymoo/algorithms/moo/moead.py +183 -0
  17. pymoo/algorithms/moo/nsga2.py +113 -0
  18. pymoo/algorithms/moo/nsga3.py +358 -0
  19. pymoo/algorithms/moo/pinsga2.py +370 -0
  20. pymoo/algorithms/moo/rnsga2.py +188 -0
  21. pymoo/algorithms/moo/rnsga3.py +246 -0
  22. pymoo/algorithms/moo/rvea.py +214 -0
  23. pymoo/algorithms/moo/sms.py +195 -0
  24. pymoo/algorithms/moo/spea2.py +190 -0
  25. pymoo/algorithms/moo/unsga3.py +47 -0
  26. pymoo/algorithms/soo/__init__.py +0 -0
  27. pymoo/algorithms/soo/convex/__init__.py +0 -0
  28. pymoo/algorithms/soo/nonconvex/__init__.py +0 -0
  29. pymoo/algorithms/soo/nonconvex/brkga.py +161 -0
  30. pymoo/algorithms/soo/nonconvex/cmaes.py +554 -0
  31. pymoo/algorithms/soo/nonconvex/de.py +279 -0
  32. pymoo/algorithms/soo/nonconvex/direct.py +149 -0
  33. pymoo/algorithms/soo/nonconvex/es.py +203 -0
  34. pymoo/algorithms/soo/nonconvex/g3pcx.py +94 -0
  35. pymoo/algorithms/soo/nonconvex/ga.py +93 -0
  36. pymoo/algorithms/soo/nonconvex/ga_niching.py +223 -0
  37. pymoo/algorithms/soo/nonconvex/isres.py +74 -0
  38. pymoo/algorithms/soo/nonconvex/nelder.py +251 -0
  39. pymoo/algorithms/soo/nonconvex/optuna.py +80 -0
  40. pymoo/algorithms/soo/nonconvex/pattern.py +183 -0
  41. pymoo/algorithms/soo/nonconvex/pso.py +399 -0
  42. pymoo/algorithms/soo/nonconvex/pso_ep.py +297 -0
  43. pymoo/algorithms/soo/nonconvex/random_search.py +25 -0
  44. pymoo/algorithms/soo/nonconvex/sres.py +56 -0
  45. pymoo/algorithms/soo/univariate/__init__.py +0 -0
  46. pymoo/algorithms/soo/univariate/backtracking.py +59 -0
  47. pymoo/algorithms/soo/univariate/exp.py +46 -0
  48. pymoo/algorithms/soo/univariate/golden.py +65 -0
  49. pymoo/algorithms/soo/univariate/quadr_interp.py +81 -0
  50. pymoo/algorithms/soo/univariate/wolfe.py +163 -0
  51. pymoo/config.py +33 -0
  52. pymoo/constraints/__init__.py +3 -0
  53. pymoo/constraints/adaptive.py +62 -0
  54. pymoo/constraints/as_obj.py +56 -0
  55. pymoo/constraints/as_penalty.py +41 -0
  56. pymoo/constraints/eps.py +26 -0
  57. pymoo/constraints/from_bounds.py +36 -0
  58. pymoo/core/__init__.py +0 -0
  59. pymoo/core/algorithm.py +394 -0
  60. pymoo/core/callback.py +38 -0
  61. pymoo/core/crossover.py +77 -0
  62. pymoo/core/decision_making.py +102 -0
  63. pymoo/core/decomposition.py +76 -0
  64. pymoo/core/duplicate.py +163 -0
  65. pymoo/core/evaluator.py +116 -0
  66. pymoo/core/indicator.py +34 -0
  67. pymoo/core/individual.py +784 -0
  68. pymoo/core/infill.py +64 -0
  69. pymoo/core/initialization.py +42 -0
  70. pymoo/core/mating.py +39 -0
  71. pymoo/core/meta.py +21 -0
  72. pymoo/core/mixed.py +165 -0
  73. pymoo/core/mutation.py +44 -0
  74. pymoo/core/operator.py +40 -0
  75. pymoo/core/parameters.py +134 -0
  76. pymoo/core/plot.py +210 -0
  77. pymoo/core/population.py +180 -0
  78. pymoo/core/problem.py +460 -0
  79. pymoo/core/recorder.py +99 -0
  80. pymoo/core/repair.py +23 -0
  81. pymoo/core/replacement.py +96 -0
  82. pymoo/core/result.py +52 -0
  83. pymoo/core/sampling.py +43 -0
  84. pymoo/core/selection.py +61 -0
  85. pymoo/core/solution.py +10 -0
  86. pymoo/core/survival.py +103 -0
  87. pymoo/core/termination.py +70 -0
  88. pymoo/core/variable.py +399 -0
  89. pymoo/cython/__init__.py +0 -0
  90. pymoo/cython/calc_perpendicular_distance.cpython-313-x86_64-linux-gnu.so +0 -0
  91. pymoo/cython/calc_perpendicular_distance.pyx +67 -0
  92. pymoo/cython/decomposition.cpython-313-x86_64-linux-gnu.so +0 -0
  93. pymoo/cython/decomposition.pyx +165 -0
  94. pymoo/cython/hv.cpython-313-x86_64-linux-gnu.so +0 -0
  95. pymoo/cython/hv.pyx +18 -0
  96. pymoo/cython/info.cpython-313-x86_64-linux-gnu.so +0 -0
  97. pymoo/cython/info.pyx +5 -0
  98. pymoo/cython/mnn.cpython-313-x86_64-linux-gnu.so +0 -0
  99. pymoo/cython/mnn.pyx +273 -0
  100. pymoo/cython/non_dominated_sorting.cpython-313-x86_64-linux-gnu.so +0 -0
  101. pymoo/cython/non_dominated_sorting.pyx +645 -0
  102. pymoo/cython/pruning_cd.cpython-313-x86_64-linux-gnu.so +0 -0
  103. pymoo/cython/pruning_cd.pyx +197 -0
  104. pymoo/cython/stochastic_ranking.cpython-313-x86_64-linux-gnu.so +0 -0
  105. pymoo/cython/stochastic_ranking.pyx +49 -0
  106. pymoo/cython/utils.pxd +129 -0
  107. pymoo/cython/vendor/__init__.py +0 -0
  108. pymoo/cython/vendor/hypervolume.cpp +1621 -0
  109. pymoo/cython/vendor/hypervolume.h +63 -0
  110. pymoo/decomposition/__init__.py +0 -0
  111. pymoo/decomposition/aasf.py +24 -0
  112. pymoo/decomposition/asf.py +10 -0
  113. pymoo/decomposition/pbi.py +13 -0
  114. pymoo/decomposition/perp_dist.py +13 -0
  115. pymoo/decomposition/tchebicheff.py +11 -0
  116. pymoo/decomposition/util.py +13 -0
  117. pymoo/decomposition/weighted_sum.py +8 -0
  118. pymoo/docs.py +187 -0
  119. pymoo/experimental/__init__.py +0 -0
  120. pymoo/experimental/algorithms/__init__.py +0 -0
  121. pymoo/experimental/algorithms/gde3.py +57 -0
  122. pymoo/gradient/__init__.py +21 -0
  123. pymoo/gradient/automatic.py +57 -0
  124. pymoo/gradient/grad_autograd.py +105 -0
  125. pymoo/gradient/grad_complex.py +35 -0
  126. pymoo/gradient/grad_jax.py +51 -0
  127. pymoo/gradient/toolbox/__init__.py +6 -0
  128. pymoo/indicators/__init__.py +0 -0
  129. pymoo/indicators/distance_indicator.py +55 -0
  130. pymoo/indicators/gd.py +7 -0
  131. pymoo/indicators/gd_plus.py +7 -0
  132. pymoo/indicators/hv/__init__.py +63 -0
  133. pymoo/indicators/hv/exact.py +71 -0
  134. pymoo/indicators/hv/exact_2d.py +102 -0
  135. pymoo/indicators/hv/monte_carlo.py +74 -0
  136. pymoo/indicators/igd.py +7 -0
  137. pymoo/indicators/igd_plus.py +7 -0
  138. pymoo/indicators/kktpm.py +151 -0
  139. pymoo/indicators/migd.py +55 -0
  140. pymoo/indicators/rmetric.py +203 -0
  141. pymoo/indicators/spacing.py +52 -0
  142. pymoo/mcdm/__init__.py +0 -0
  143. pymoo/mcdm/compromise_programming.py +19 -0
  144. pymoo/mcdm/high_tradeoff.py +40 -0
  145. pymoo/mcdm/pseudo_weights.py +32 -0
  146. pymoo/operators/__init__.py +0 -0
  147. pymoo/operators/control.py +187 -0
  148. pymoo/operators/crossover/__init__.py +0 -0
  149. pymoo/operators/crossover/binx.py +45 -0
  150. pymoo/operators/crossover/dex.py +122 -0
  151. pymoo/operators/crossover/erx.py +162 -0
  152. pymoo/operators/crossover/expx.py +51 -0
  153. pymoo/operators/crossover/hux.py +37 -0
  154. pymoo/operators/crossover/nox.py +13 -0
  155. pymoo/operators/crossover/ox.py +84 -0
  156. pymoo/operators/crossover/pcx.py +82 -0
  157. pymoo/operators/crossover/pntx.py +49 -0
  158. pymoo/operators/crossover/sbx.py +125 -0
  159. pymoo/operators/crossover/spx.py +5 -0
  160. pymoo/operators/crossover/ux.py +20 -0
  161. pymoo/operators/mutation/__init__.py +0 -0
  162. pymoo/operators/mutation/bitflip.py +17 -0
  163. pymoo/operators/mutation/gauss.py +58 -0
  164. pymoo/operators/mutation/inversion.py +42 -0
  165. pymoo/operators/mutation/nom.py +7 -0
  166. pymoo/operators/mutation/pm.py +94 -0
  167. pymoo/operators/mutation/rm.py +23 -0
  168. pymoo/operators/repair/__init__.py +0 -0
  169. pymoo/operators/repair/bounce_back.py +32 -0
  170. pymoo/operators/repair/bounds_repair.py +95 -0
  171. pymoo/operators/repair/inverse_penalty.py +89 -0
  172. pymoo/operators/repair/rounding.py +18 -0
  173. pymoo/operators/repair/to_bound.py +31 -0
  174. pymoo/operators/repair/vtype.py +11 -0
  175. pymoo/operators/sampling/__init__.py +0 -0
  176. pymoo/operators/sampling/lhs.py +73 -0
  177. pymoo/operators/sampling/rnd.py +50 -0
  178. pymoo/operators/selection/__init__.py +0 -0
  179. pymoo/operators/selection/rnd.py +72 -0
  180. pymoo/operators/selection/tournament.py +76 -0
  181. pymoo/operators/survival/__init__.py +0 -0
  182. pymoo/operators/survival/rank_and_crowding/__init__.py +1 -0
  183. pymoo/operators/survival/rank_and_crowding/classes.py +209 -0
  184. pymoo/operators/survival/rank_and_crowding/metrics.py +208 -0
  185. pymoo/optimize.py +72 -0
  186. pymoo/problems/__init__.py +157 -0
  187. pymoo/problems/dyn.py +47 -0
  188. pymoo/problems/dynamic/__init__.py +0 -0
  189. pymoo/problems/dynamic/cec2015.py +108 -0
  190. pymoo/problems/dynamic/df.py +452 -0
  191. pymoo/problems/dynamic/misc.py +167 -0
  192. pymoo/problems/functional.py +48 -0
  193. pymoo/problems/many/__init__.py +5 -0
  194. pymoo/problems/many/cdtlz.py +159 -0
  195. pymoo/problems/many/dcdtlz.py +88 -0
  196. pymoo/problems/many/dtlz.py +264 -0
  197. pymoo/problems/many/wfg.py +550 -0
  198. pymoo/problems/multi/__init__.py +14 -0
  199. pymoo/problems/multi/bnh.py +34 -0
  200. pymoo/problems/multi/carside.py +48 -0
  201. pymoo/problems/multi/clutch.py +104 -0
  202. pymoo/problems/multi/csi.py +55 -0
  203. pymoo/problems/multi/ctp.py +198 -0
  204. pymoo/problems/multi/dascmop.py +213 -0
  205. pymoo/problems/multi/kursawe.py +25 -0
  206. pymoo/problems/multi/modact.py +68 -0
  207. pymoo/problems/multi/mw.py +400 -0
  208. pymoo/problems/multi/omnitest.py +48 -0
  209. pymoo/problems/multi/osy.py +32 -0
  210. pymoo/problems/multi/srn.py +28 -0
  211. pymoo/problems/multi/sympart.py +94 -0
  212. pymoo/problems/multi/tnk.py +24 -0
  213. pymoo/problems/multi/truss2d.py +83 -0
  214. pymoo/problems/multi/welded_beam.py +41 -0
  215. pymoo/problems/multi/wrm.py +36 -0
  216. pymoo/problems/multi/zdt.py +151 -0
  217. pymoo/problems/multi_to_single.py +22 -0
  218. pymoo/problems/single/__init__.py +12 -0
  219. pymoo/problems/single/ackley.py +24 -0
  220. pymoo/problems/single/cantilevered_beam.py +34 -0
  221. pymoo/problems/single/flowshop_scheduling.py +112 -0
  222. pymoo/problems/single/g.py +874 -0
  223. pymoo/problems/single/griewank.py +18 -0
  224. pymoo/problems/single/himmelblau.py +15 -0
  225. pymoo/problems/single/knapsack.py +48 -0
  226. pymoo/problems/single/mopta08.py +26 -0
  227. pymoo/problems/single/multimodal.py +20 -0
  228. pymoo/problems/single/pressure_vessel.py +30 -0
  229. pymoo/problems/single/rastrigin.py +20 -0
  230. pymoo/problems/single/rosenbrock.py +22 -0
  231. pymoo/problems/single/schwefel.py +18 -0
  232. pymoo/problems/single/simple.py +13 -0
  233. pymoo/problems/single/sphere.py +19 -0
  234. pymoo/problems/single/traveling_salesman.py +79 -0
  235. pymoo/problems/single/zakharov.py +19 -0
  236. pymoo/problems/static.py +14 -0
  237. pymoo/problems/util.py +42 -0
  238. pymoo/problems/zero_to_one.py +27 -0
  239. pymoo/termination/__init__.py +23 -0
  240. pymoo/termination/collection.py +12 -0
  241. pymoo/termination/cv.py +48 -0
  242. pymoo/termination/default.py +45 -0
  243. pymoo/termination/delta.py +64 -0
  244. pymoo/termination/fmin.py +16 -0
  245. pymoo/termination/ftol.py +144 -0
  246. pymoo/termination/indicator.py +49 -0
  247. pymoo/termination/max_eval.py +14 -0
  248. pymoo/termination/max_gen.py +15 -0
  249. pymoo/termination/max_time.py +20 -0
  250. pymoo/termination/robust.py +34 -0
  251. pymoo/termination/xtol.py +33 -0
  252. pymoo/util/__init__.py +0 -0
  253. pymoo/util/archive.py +150 -0
  254. pymoo/util/cache.py +29 -0
  255. pymoo/util/clearing.py +82 -0
  256. pymoo/util/display/__init__.py +0 -0
  257. pymoo/util/display/column.py +52 -0
  258. pymoo/util/display/display.py +34 -0
  259. pymoo/util/display/multi.py +96 -0
  260. pymoo/util/display/output.py +53 -0
  261. pymoo/util/display/progress.py +54 -0
  262. pymoo/util/display/single.py +67 -0
  263. pymoo/util/dominator.py +67 -0
  264. pymoo/util/function_loader.py +129 -0
  265. pymoo/util/hv.py +23 -0
  266. pymoo/util/matlab_engine.py +39 -0
  267. pymoo/util/misc.py +460 -0
  268. pymoo/util/mnn.py +70 -0
  269. pymoo/util/nds/__init__.py +0 -0
  270. pymoo/util/nds/dominance_degree_non_dominated_sort.py +159 -0
  271. pymoo/util/nds/efficient_non_dominated_sort.py +152 -0
  272. pymoo/util/nds/fast_non_dominated_sort.py +70 -0
  273. pymoo/util/nds/naive_non_dominated_sort.py +36 -0
  274. pymoo/util/nds/non_dominated_sorting.py +67 -0
  275. pymoo/util/nds/tree_based_non_dominated_sort.py +133 -0
  276. pymoo/util/normalization.py +312 -0
  277. pymoo/util/optimum.py +42 -0
  278. pymoo/util/plotting.py +177 -0
  279. pymoo/util/pruning_cd.py +89 -0
  280. pymoo/util/randomized_argsort.py +60 -0
  281. pymoo/util/ref_dirs/__init__.py +24 -0
  282. pymoo/util/ref_dirs/construction.py +88 -0
  283. pymoo/util/ref_dirs/das_dennis.py +52 -0
  284. pymoo/util/ref_dirs/energy.py +319 -0
  285. pymoo/util/ref_dirs/energy_layer.py +119 -0
  286. pymoo/util/ref_dirs/genetic_algorithm.py +63 -0
  287. pymoo/util/ref_dirs/incremental.py +68 -0
  288. pymoo/util/ref_dirs/misc.py +128 -0
  289. pymoo/util/ref_dirs/optimizer.py +59 -0
  290. pymoo/util/ref_dirs/performance.py +162 -0
  291. pymoo/util/ref_dirs/reduction.py +85 -0
  292. pymoo/util/ref_dirs/sample_and_map.py +24 -0
  293. pymoo/util/reference_direction.py +260 -0
  294. pymoo/util/remote.py +55 -0
  295. pymoo/util/roulette.py +27 -0
  296. pymoo/util/running_metric.py +128 -0
  297. pymoo/util/sliding_window.py +25 -0
  298. pymoo/util/stochastic_ranking.py +32 -0
  299. pymoo/util/value_functions.py +719 -0
  300. pymoo/util/vectors.py +40 -0
  301. pymoo/util/vf_dominator.py +99 -0
  302. pymoo/vendor/__init__.py +0 -0
  303. pymoo/vendor/cec2018.py +398 -0
  304. pymoo/vendor/gta.py +617 -0
  305. pymoo/vendor/hv.py +267 -0
  306. pymoo/vendor/vendor_cmaes.py +412 -0
  307. pymoo/vendor/vendor_coco.py +81 -0
  308. pymoo/vendor/vendor_scipy.py +232 -0
  309. pymoo/version.py +1 -0
  310. pymoo/visualization/__init__.py +8 -0
  311. pymoo/visualization/fitness_landscape.py +127 -0
  312. pymoo/visualization/heatmap.py +123 -0
  313. pymoo/visualization/pcp.py +120 -0
  314. pymoo/visualization/petal.py +91 -0
  315. pymoo/visualization/radar.py +108 -0
  316. pymoo/visualization/radviz.py +68 -0
  317. pymoo/visualization/scatter.py +150 -0
  318. pymoo/visualization/star_coordinate.py +75 -0
  319. pymoo/visualization/util.py +123 -0
  320. pymoo/visualization/video/__init__.py +0 -0
  321. pymoo/visualization/video/callback_video.py +82 -0
  322. pymoo/visualization/video/one_var_one_obj.py +57 -0
  323. pymoo/visualization/video/two_var_one_obj.py +62 -0
  324. pymoo-0.6.1.5.dev0.dist-info/METADATA +187 -0
  325. pymoo-0.6.1.5.dev0.dist-info/RECORD +328 -0
  326. pymoo-0.6.1.5.dev0.dist-info/WHEEL +6 -0
  327. pymoo-0.6.1.5.dev0.dist-info/licenses/LICENSE +191 -0
  328. pymoo-0.6.1.5.dev0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,41 @@
1
+ from pymoo.core.individual import calc_cv
2
+ from pymoo.core.meta import Meta
3
+ from pymoo.core.problem import Problem
4
+ from pymoo.util.misc import from_dict
5
+
6
+ import numpy as np
7
+
8
+
9
+ class ConstraintsAsPenalty(Meta, Problem):
10
+
11
+ def __init__(self,
12
+ problem,
13
+ penalty: float = 0.1):
14
+ super().__init__(problem)
15
+
16
+ # the amount of penalty to add for this type
17
+ self.penalty = penalty
18
+
19
+ # set ieq and eq to zero (because it became now a penalty)
20
+ self.n_ieq_constr = 0
21
+ self.n_eq_constr = 0
22
+
23
+ def do(self, X, return_values_of, *args, **kwargs):
24
+ out = self.__object__.do(X, return_values_of, *args, **kwargs)
25
+
26
+ # get at the values from the output
27
+ F, G, H = from_dict(out, "F", "G", "H")
28
+
29
+ # store a backup of the values in out
30
+ out["__F__"], out["__G__"], out["__H__"] = F, G, H
31
+
32
+ # calculate the total constraint violation (here normalization shall be already included)
33
+ CV = calc_cv(G=G, H=H)
34
+
35
+ # set the penalized objective values
36
+ out["F"] = F + self.penalty * np.reshape(CV, F.shape)
37
+
38
+ del out["G"]
39
+ del out["H"]
40
+
41
+ return out
@@ -0,0 +1,26 @@
1
+ import numpy as np
2
+
3
+ from pymoo.constraints.adaptive import AdaptiveConstraintHandling
4
+
5
+
6
+ class AdaptiveEpsilonConstraintHandling(AdaptiveConstraintHandling):
7
+
8
+ def __init__(self, algorithm, perc_eps_until=0.5):
9
+ super().__init__(algorithm)
10
+ self.perc_eps_until = perc_eps_until
11
+ self.max_cv = None
12
+
13
+ def _adapt_constraint_handling(self, config, **kwargs):
14
+ t = self.termination.perc
15
+ alpha = np.maximum(0.0, 1 - 1 / self.perc_eps_until * t)
16
+ eps = alpha * self.max_cv
17
+
18
+ config["cv_eps"] = eps
19
+
20
+ def _initialize_advance(self, infills=None, **kwargs):
21
+
22
+ # get the average constraint violation in the current generation
23
+ cv = infills.get("cv")
24
+ self.max_cv = np.mean(cv)
25
+
26
+ return super()._initialize_advance(infills, **kwargs)
@@ -0,0 +1,36 @@
1
+ import numpy as np
2
+
3
+ import pymoo.gradient.toolbox as anp
4
+
5
+ from pymoo.core.meta import Meta
6
+ from pymoo.core.problem import Problem
7
+
8
+
9
+ class ConstraintsFromBounds(Meta, Problem):
10
+
11
+ def __init__(self, problem, remove_bonds=False):
12
+ super().__init__(problem)
13
+ self.n_ieq_constr += 2 * self.n_var
14
+
15
+ if remove_bonds:
16
+ self.xl, self.xu = None, None
17
+
18
+ def do(self, X, return_values_of, *args, **kwargs):
19
+
20
+ out = self.__object__.do(X, return_values_of, *args, **kwargs)
21
+
22
+ # get the boundaries for normalization
23
+ xl, xu = self.bounds()
24
+
25
+ # add the boundary constraint if enabled
26
+ _G = anp.column_stack([xl - X, X - xu])
27
+
28
+ out["G"] = anp.column_stack([out["G"], _G])
29
+
30
+ if "dG" in out:
31
+ _dG = np.zeros((len(X), 2 * self.n_var, self.n_var))
32
+ _dG[:, :self.n_var, :] = - np.eye(self.n_var)
33
+ _dG[:, self.n_var:, :] = np.eye(self.n_var)
34
+ out["dG"] = np.column_stack([out["dG"], _dG])
35
+
36
+ return out
pymoo/core/__init__.py ADDED
File without changes
@@ -0,0 +1,394 @@
1
+ import copy
2
+ import time
3
+
4
+ import numpy as np
5
+
6
+ from pymoo.core.callback import Callback
7
+ from pymoo.core.evaluator import Evaluator
8
+ from pymoo.core.population import Population
9
+ from pymoo.core.result import Result
10
+ from pymoo.termination.default import DefaultMultiObjectiveTermination, DefaultSingleObjectiveTermination
11
+ from pymoo.util.display.display import Display
12
+ from pymoo.util.function_loader import FunctionLoader
13
+ from pymoo.util.misc import termination_from_tuple
14
+ from pymoo.util.optimum import filter_optimum
15
+
16
+
17
+ class Algorithm:
18
+
19
+ def __init__(self,
20
+ termination=None,
21
+ output=None,
22
+ display=None,
23
+ callback=None,
24
+ archive=None,
25
+ return_least_infeasible=False,
26
+ save_history=False,
27
+ verbose=False,
28
+ seed=None,
29
+ evaluator=None,
30
+ **kwargs):
31
+
32
+ super().__init__()
33
+
34
+ # prints the compile warning if enabled
35
+ FunctionLoader.get_instance()
36
+
37
+ # the problem to be solved (will be set later on)
38
+ self.problem = None
39
+
40
+ # the termination criterion to be used by the algorithm - might be specific for an algorithm
41
+ self.termination = termination
42
+
43
+ # the text that should be printed during the algorithm run
44
+ self.output = output
45
+
46
+ # an archive kept during algorithm execution (not always the same as optimum)
47
+ self.archive = archive
48
+
49
+ # the form of display shown during algorithm execution
50
+ self.display = display
51
+
52
+ # callback to be executed each generation
53
+ if callback is None:
54
+ callback = Callback()
55
+ self.callback = callback
56
+
57
+ # whether the algorithm should finally return the least infeasible solution if no feasible found
58
+ self.return_least_infeasible = return_least_infeasible
59
+
60
+ # whether the history should be saved or not
61
+ self.save_history = save_history
62
+
63
+ # whether the algorithm should print output in this run or not
64
+ self.verbose = verbose
65
+
66
+ # the random seed that was used
67
+ self.seed = seed
68
+
69
+ # the function evaluator object (can be used to inject code)
70
+ if evaluator is None:
71
+ evaluator = Evaluator()
72
+ self.evaluator = evaluator
73
+
74
+ # the history object which contains the list
75
+ self.history = list()
76
+
77
+ # the current solutions stored - here considered as population
78
+ self.pop = None
79
+
80
+ # a placeholder object for implementation to store solutions in each iteration
81
+ self.off = None
82
+
83
+ # the optimum found by the algorithm
84
+ self.opt = None
85
+
86
+ # the current number of generation or iteration
87
+ self.n_iter = None
88
+
89
+ # can be used to store additional data in submodules
90
+ self.data = {}
91
+
92
+ # if the initialized method has been called before or not
93
+ self.is_initialized = False
94
+
95
+ # the time when the algorithm has been setup for the first time
96
+ self.start_time = None
97
+
98
+ def setup(self, problem, **kwargs):
99
+
100
+ # the problem to be solved by the algorithm
101
+ self.problem = problem
102
+
103
+ # set all the provided options to this method
104
+ for key, value in kwargs.items():
105
+ self.__dict__[key] = value
106
+
107
+ # if seed is a boolean and true, then randomly set a seed (useful to reproduce runs)
108
+ seed = self.seed
109
+ if isinstance(seed, bool) and seed:
110
+ seed = np.random.randint(0, 10000000)
111
+ self.seed = seed
112
+
113
+ # if a seed is set, then use it to call the random number generators
114
+ if seed is not None:
115
+ import random
116
+ random.seed(seed)
117
+ np.random.seed(seed)
118
+
119
+ # make sure that some type of termination criterion is set
120
+ if self.termination is None:
121
+ self.termination = default_termination(problem)
122
+ else:
123
+ self.termination = termination_from_tuple(self.termination)
124
+
125
+ # set up the display during the algorithm execution
126
+ if self.display is None:
127
+ verbose = kwargs.get("verbose", False)
128
+ progress = kwargs.get("progress", False)
129
+ self.display = Display(self.output, verbose=verbose, progress=progress)
130
+
131
+ # finally call the function that can be overwritten by the actual algorithm
132
+ self._setup(problem, **kwargs)
133
+
134
+ return self
135
+
136
+ def run(self):
137
+ while self.has_next():
138
+ self.next()
139
+ return self.result()
140
+
141
+ def has_next(self):
142
+ return not self.termination.has_terminated()
143
+
144
+ def finalize(self):
145
+
146
+ # finalize the display output in the end of the run
147
+ self.display.finalize()
148
+
149
+ return self._finalize()
150
+
151
+ def next(self):
152
+
153
+ # get the infill solutions
154
+ infills = self.infill()
155
+
156
+ # call the advance with them after evaluation
157
+ if infills is not None:
158
+ self.evaluator.eval(self.problem, infills, algorithm=self)
159
+ self.advance(infills=infills)
160
+
161
+ # if the algorithm does not follow the infill-advance scheme just call advance
162
+ else:
163
+ self.advance()
164
+
165
+ def _initialize(self):
166
+
167
+ # the time starts whenever this method is called
168
+ self.start_time = time.time()
169
+
170
+ # set the attribute for the optimization method to start
171
+ self.n_iter = 1
172
+ self.pop = Population.empty()
173
+ self.opt = None
174
+
175
+ def infill(self):
176
+ if self.problem is None:
177
+ raise Exception("Please call `setup(problem)` before calling next().")
178
+
179
+ # the first time next is called simply initial the algorithm - makes the interface cleaner
180
+ if not self.is_initialized:
181
+
182
+ # hook mostly used by the class to happen before even to initialize
183
+ self._initialize()
184
+
185
+ # execute the initialization infill of the algorithm
186
+ infills = self._initialize_infill()
187
+
188
+ else:
189
+ # request the infill solutions if the algorithm has implemented it
190
+ infills = self._infill()
191
+
192
+ # set the current generation to the offsprings
193
+ if infills is not None:
194
+ infills.set("n_gen", self.n_iter)
195
+ infills.set("n_iter", self.n_iter)
196
+
197
+ return infills
198
+
199
+ def advance(self, infills=None, **kwargs):
200
+
201
+ # if infills have been provided set them as offsprings and feed them into advance
202
+ self.off = infills
203
+
204
+ # if the algorithm has not been already initialized
205
+ if not self.is_initialized:
206
+
207
+ # set the generation counter to 1
208
+ self.n_iter = 1
209
+
210
+ # assign the population to the algorithm
211
+ self.pop = infills
212
+
213
+ # do what is necessary after the initialization
214
+ self._initialize_advance(infills=infills, **kwargs)
215
+
216
+ # set this algorithm to be initialized
217
+ self.is_initialized = True
218
+
219
+ # always advance to the next iteration after initialization
220
+ self._post_advance()
221
+
222
+ else:
223
+
224
+ # call the implementation of the advance method - if the infill is not None
225
+ val = self._advance(infills=infills, **kwargs)
226
+
227
+ # always advance to the next iteration - except if the algorithm returns False
228
+ if val is None or val:
229
+ self._post_advance()
230
+
231
+ # if the algorithm has terminated, then do the finalization steps and return the result
232
+ if self.termination.has_terminated():
233
+ self.finalize()
234
+ ret = self.result()
235
+
236
+ # otherwise just increase the iteration counter for the next step and return the current optimum
237
+ else:
238
+ ret = self.opt
239
+
240
+ # add the infill solutions to an archive
241
+ if self.archive is not None and infills is not None:
242
+ self.archive = self.archive.add(infills)
243
+
244
+ return ret
245
+
246
+ def result(self):
247
+ res = Result()
248
+
249
+ # store the time when the algorithm as finished
250
+ res.start_time = self.start_time
251
+ res.end_time = time.time()
252
+ res.exec_time = res.end_time - res.start_time
253
+
254
+ res.pop = self.pop
255
+ res.archive = self.archive
256
+ res.data = self.data
257
+
258
+ # get the optimal solution found
259
+ opt = self.opt
260
+ if opt is None or len(opt) == 0:
261
+ opt = None
262
+
263
+ # if no feasible solution has been found
264
+ elif not np.any(opt.get("FEAS")):
265
+ if self.return_least_infeasible:
266
+ opt = filter_optimum(opt, least_infeasible=True)
267
+ else:
268
+ opt = None
269
+ res.opt = opt
270
+
271
+ # if optimum is set to none to not report anything
272
+ if res.opt is None:
273
+ X, F, CV, G, H = None, None, None, None, None
274
+
275
+ # otherwise get the values from the population
276
+ else:
277
+ X, F, CV, G, H = self.opt.get("X", "F", "CV", "G", "H")
278
+
279
+ # if single-objective problem and only one solution was found - create a 1d array
280
+ if self.problem.n_obj == 1 and len(X) == 1:
281
+ X, F, CV, G, H = X[0], F[0], CV[0], G[0], H[0]
282
+
283
+ # set all the individual values
284
+ res.X, res.F, res.CV, res.G, res.H = X, F, CV, G, H
285
+
286
+ # create the result object
287
+ res.problem = self.problem
288
+ res.history = self.history
289
+
290
+ return res
291
+
292
+ def ask(self):
293
+ return self.infill()
294
+
295
+ def tell(self, *args, **kwargs):
296
+ return self.advance(*args, **kwargs)
297
+
298
+ def _set_optimum(self):
299
+ self.opt = filter_optimum(self.pop, least_infeasible=True)
300
+
301
+ def _post_advance(self):
302
+
303
+ # update the current optimum of the algorithm
304
+ self._set_optimum()
305
+
306
+ # update the current termination condition of the algorithm
307
+ self.termination.update(self)
308
+
309
+ # display the output if defined by the algorithm
310
+ self.display(self)
311
+
312
+ # if a callback function is provided it is called after each iteration
313
+ self.callback(self)
314
+
315
+ if self.save_history:
316
+ _hist, _callback, _display = self.history, self.callback, self.display
317
+
318
+ self.history, self.callback, self.display = None, None, None
319
+ obj = copy.deepcopy(self)
320
+
321
+ self.history, self.callback, self.display = _hist, _callback, _display
322
+ self.history.append(obj)
323
+
324
+ self.n_iter += 1
325
+
326
+ # =========================================================================================================
327
+ # TO BE OVERWRITTEN
328
+ # =========================================================================================================
329
+
330
+ def _setup(self, problem, **kwargs):
331
+ pass
332
+
333
+ def _initialize_infill(self):
334
+ pass
335
+
336
+ def _initialize_advance(self, infills=None, **kwargs):
337
+ pass
338
+
339
+ def _infill(self):
340
+ pass
341
+
342
+ def _advance(self, infills=None, **kwargs):
343
+ pass
344
+
345
+ def _finalize(self):
346
+ pass
347
+
348
+ # =========================================================================================================
349
+ # CONVENIENCE
350
+ # =========================================================================================================
351
+
352
+ @property
353
+ def n_gen(self):
354
+ return self.n_iter
355
+
356
+ @n_gen.setter
357
+ def n_gen(self, value):
358
+ self.n_iter = value
359
+
360
+
361
+ class LoopwiseAlgorithm(Algorithm):
362
+
363
+ def __init__(self, **kwargs):
364
+ super().__init__(**kwargs)
365
+ self.generator = None
366
+ self.state = None
367
+
368
+ def _next(self):
369
+ pass
370
+
371
+ def _infill(self):
372
+ if self.state is None:
373
+ self._advance()
374
+ return self.state
375
+
376
+ def _advance(self, infills=None, **kwargs):
377
+ if self.generator is None:
378
+ self.generator = self._next()
379
+ try:
380
+ self.state = self.generator.send(infills)
381
+ except StopIteration:
382
+ self.generator = None
383
+ self.state = None
384
+ return True
385
+
386
+ return False
387
+
388
+
389
+ def default_termination(problem):
390
+ if problem.n_obj > 1:
391
+ termination = DefaultMultiObjectiveTermination()
392
+ else:
393
+ termination = DefaultSingleObjectiveTermination()
394
+ return termination
pymoo/core/callback.py ADDED
@@ -0,0 +1,38 @@
1
+ class Callback:
2
+
3
+ def __init__(self) -> None:
4
+ super().__init__()
5
+ self.data = {}
6
+ self.is_initialized = False
7
+
8
+ def initialize(self, algorithm):
9
+ pass
10
+
11
+ def notify(self, algorithm):
12
+ pass
13
+
14
+ def update(self, algorithm):
15
+ return self._update(algorithm)
16
+
17
+ def _update(self, algorithm):
18
+ pass
19
+
20
+ def __call__(self, algorithm):
21
+
22
+ if not self.is_initialized:
23
+ self.initialize(algorithm)
24
+ self.is_initialized = True
25
+
26
+ self.notify(algorithm)
27
+ self.update(algorithm)
28
+
29
+
30
+ class CallbackCollection(Callback):
31
+
32
+ def __init__(self, *args) -> None:
33
+ super().__init__()
34
+ self.callbacks = args
35
+
36
+ def update(self, algorithm):
37
+ [callback.update(algorithm) for callback in self.callbacks]
38
+
@@ -0,0 +1,77 @@
1
+ import numpy as np
2
+
3
+ from pymoo.core.operator import Operator
4
+ from pymoo.core.population import Population
5
+ from pymoo.core.variable import Real, get
6
+
7
+
8
+ class Crossover(Operator):
9
+
10
+ def __init__(self,
11
+ n_parents,
12
+ n_offsprings,
13
+ prob=0.9,
14
+ **kwargs):
15
+ super().__init__(**kwargs)
16
+ self.n_parents = n_parents
17
+ self.n_offsprings = n_offsprings
18
+ self.prob = Real(prob, bounds=(0.5, 1.0), strict=(0.0, 1.0))
19
+
20
+ def do(self, problem, pop, parents=None, **kwargs):
21
+
22
+ # if a parents with array with mating indices is provided -> transform the input first
23
+ if parents is not None:
24
+ pop = [pop[mating] for mating in parents]
25
+
26
+ # get the dimensions necessary to create in and output
27
+ n_parents, n_offsprings = self.n_parents, self.n_offsprings
28
+ n_matings, n_var = len(pop), problem.n_var
29
+
30
+ # get the actual values from each of the parents
31
+ X = np.swapaxes(np.array([[parent.get("X") for parent in mating] for mating in pop]), 0, 1)
32
+ if self.vtype is not None:
33
+ X = X.astype(self.vtype)
34
+
35
+ # the array where the offsprings will be stored to
36
+ Xp = np.empty(shape=(n_offsprings, n_matings, n_var), dtype=X.dtype)
37
+
38
+ # the probability of executing the crossover
39
+ prob = get(self.prob, size=n_matings)
40
+
41
+ # a boolean mask when crossover is actually executed
42
+ cross = np.random.random(n_matings) < prob
43
+
44
+ # the design space from the parents used for the crossover
45
+ if np.any(cross):
46
+
47
+ # we can not prefilter for cross first, because there might be other variables using the same shape as X
48
+ Q = self._do(problem, X, **kwargs)
49
+ assert Q.shape == (n_offsprings, n_matings, problem.n_var), "Shape is incorrect of crossover impl."
50
+ Xp[:, cross] = Q[:, cross]
51
+
52
+ # now set the parents whenever NO crossover has been applied
53
+ for k in np.flatnonzero(~cross):
54
+ if n_offsprings < n_parents:
55
+ s = np.random.choice(np.arange(self.n_parents), size=n_offsprings, replace=False)
56
+ elif n_offsprings == n_parents:
57
+ s = np.arange(n_parents)
58
+ else:
59
+ s = []
60
+ while len(s) < n_offsprings:
61
+ s.extend(np.random.permutation(n_parents))
62
+ s = s[:n_offsprings]
63
+
64
+ Xp[:, k] = np.copy(X[s, k])
65
+
66
+ # flatten the array to become a 2d-array
67
+ Xp = Xp.reshape(-1, X.shape[-1])
68
+
69
+ # create a population object
70
+ off = Population.new("X", Xp)
71
+
72
+ return off
73
+
74
+ def _do(self, problem, X, **kwargs):
75
+ pass
76
+
77
+