pymoo 0.6.1.6__cp312-cp312-macosx_10_13_universal2.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (337) hide show
  1. pymoo/__init__.py +3 -0
  2. pymoo/algorithms/__init__.py +0 -0
  3. pymoo/algorithms/base/__init__.py +0 -0
  4. pymoo/algorithms/base/bracket.py +38 -0
  5. pymoo/algorithms/base/genetic.py +110 -0
  6. pymoo/algorithms/base/line.py +62 -0
  7. pymoo/algorithms/base/local.py +39 -0
  8. pymoo/algorithms/base/meta.py +79 -0
  9. pymoo/algorithms/hyperparameters.py +91 -0
  10. pymoo/algorithms/moo/__init__.py +0 -0
  11. pymoo/algorithms/moo/age.py +310 -0
  12. pymoo/algorithms/moo/age2.py +194 -0
  13. pymoo/algorithms/moo/cmopso.py +239 -0
  14. pymoo/algorithms/moo/ctaea.py +305 -0
  15. pymoo/algorithms/moo/dnsga2.py +80 -0
  16. pymoo/algorithms/moo/kgb.py +450 -0
  17. pymoo/algorithms/moo/moead.py +183 -0
  18. pymoo/algorithms/moo/mopso_cd.py +309 -0
  19. pymoo/algorithms/moo/nsga2.py +113 -0
  20. pymoo/algorithms/moo/nsga3.py +361 -0
  21. pymoo/algorithms/moo/pinsga2.py +370 -0
  22. pymoo/algorithms/moo/rnsga2.py +188 -0
  23. pymoo/algorithms/moo/rnsga3.py +246 -0
  24. pymoo/algorithms/moo/rvea.py +214 -0
  25. pymoo/algorithms/moo/sms.py +196 -0
  26. pymoo/algorithms/moo/spea2.py +191 -0
  27. pymoo/algorithms/moo/unsga3.py +49 -0
  28. pymoo/algorithms/soo/__init__.py +0 -0
  29. pymoo/algorithms/soo/convex/__init__.py +0 -0
  30. pymoo/algorithms/soo/nonconvex/__init__.py +0 -0
  31. pymoo/algorithms/soo/nonconvex/brkga.py +162 -0
  32. pymoo/algorithms/soo/nonconvex/cmaes.py +556 -0
  33. pymoo/algorithms/soo/nonconvex/de.py +283 -0
  34. pymoo/algorithms/soo/nonconvex/direct.py +148 -0
  35. pymoo/algorithms/soo/nonconvex/es.py +213 -0
  36. pymoo/algorithms/soo/nonconvex/g3pcx.py +94 -0
  37. pymoo/algorithms/soo/nonconvex/ga.py +95 -0
  38. pymoo/algorithms/soo/nonconvex/ga_niching.py +223 -0
  39. pymoo/algorithms/soo/nonconvex/isres.py +74 -0
  40. pymoo/algorithms/soo/nonconvex/nelder.py +251 -0
  41. pymoo/algorithms/soo/nonconvex/nrbo.py +191 -0
  42. pymoo/algorithms/soo/nonconvex/optuna.py +80 -0
  43. pymoo/algorithms/soo/nonconvex/pattern.py +185 -0
  44. pymoo/algorithms/soo/nonconvex/pso.py +337 -0
  45. pymoo/algorithms/soo/nonconvex/pso_ep.py +307 -0
  46. pymoo/algorithms/soo/nonconvex/random_search.py +25 -0
  47. pymoo/algorithms/soo/nonconvex/sres.py +56 -0
  48. pymoo/algorithms/soo/univariate/__init__.py +0 -0
  49. pymoo/algorithms/soo/univariate/exp.py +46 -0
  50. pymoo/algorithms/soo/univariate/golden.py +65 -0
  51. pymoo/algorithms/soo/univariate/quadr_interp.py +81 -0
  52. pymoo/algorithms/soo/univariate/wolfe.py +163 -0
  53. pymoo/config.py +33 -0
  54. pymoo/constraints/__init__.py +3 -0
  55. pymoo/constraints/adaptive.py +66 -0
  56. pymoo/constraints/as_obj.py +56 -0
  57. pymoo/constraints/as_penalty.py +41 -0
  58. pymoo/constraints/eps.py +34 -0
  59. pymoo/constraints/from_bounds.py +36 -0
  60. pymoo/core/__init__.py +0 -0
  61. pymoo/core/algorithm.py +408 -0
  62. pymoo/core/callback.py +38 -0
  63. pymoo/core/crossover.py +79 -0
  64. pymoo/core/decision_making.py +102 -0
  65. pymoo/core/decomposition.py +76 -0
  66. pymoo/core/duplicate.py +163 -0
  67. pymoo/core/evaluator.py +116 -0
  68. pymoo/core/indicator.py +34 -0
  69. pymoo/core/individual.py +784 -0
  70. pymoo/core/infill.py +65 -0
  71. pymoo/core/initialization.py +44 -0
  72. pymoo/core/mating.py +39 -0
  73. pymoo/core/meta.py +21 -0
  74. pymoo/core/mixed.py +164 -0
  75. pymoo/core/mutation.py +44 -0
  76. pymoo/core/operator.py +46 -0
  77. pymoo/core/parameters.py +134 -0
  78. pymoo/core/plot.py +208 -0
  79. pymoo/core/population.py +180 -0
  80. pymoo/core/problem.py +373 -0
  81. pymoo/core/recorder.py +99 -0
  82. pymoo/core/repair.py +23 -0
  83. pymoo/core/replacement.py +96 -0
  84. pymoo/core/result.py +52 -0
  85. pymoo/core/sampling.py +45 -0
  86. pymoo/core/selection.py +61 -0
  87. pymoo/core/solution.py +10 -0
  88. pymoo/core/survival.py +107 -0
  89. pymoo/core/termination.py +70 -0
  90. pymoo/core/variable.py +415 -0
  91. pymoo/decomposition/__init__.py +0 -0
  92. pymoo/decomposition/aasf.py +24 -0
  93. pymoo/decomposition/asf.py +10 -0
  94. pymoo/decomposition/pbi.py +13 -0
  95. pymoo/decomposition/perp_dist.py +13 -0
  96. pymoo/decomposition/tchebicheff.py +11 -0
  97. pymoo/decomposition/util.py +13 -0
  98. pymoo/decomposition/weighted_sum.py +8 -0
  99. pymoo/docs.py +187 -0
  100. pymoo/experimental/__init__.py +0 -0
  101. pymoo/experimental/algorithms/__init__.py +0 -0
  102. pymoo/experimental/algorithms/gde3.py +57 -0
  103. pymoo/functions/__init__.py +135 -0
  104. pymoo/functions/compiled/__init__.py +0 -0
  105. pymoo/functions/compiled/calc_perpendicular_distance.cpp +27464 -0
  106. pymoo/functions/compiled/calc_perpendicular_distance.cpython-312-darwin.so +0 -0
  107. pymoo/functions/compiled/decomposition.cpp +28853 -0
  108. pymoo/functions/compiled/decomposition.cpython-312-darwin.so +0 -0
  109. pymoo/functions/compiled/info.cpp +7058 -0
  110. pymoo/functions/compiled/info.cpython-312-darwin.so +0 -0
  111. pymoo/functions/compiled/mnn.cpp +30095 -0
  112. pymoo/functions/compiled/mnn.cpython-312-darwin.so +0 -0
  113. pymoo/functions/compiled/non_dominated_sorting.cpp +35692 -0
  114. pymoo/functions/compiled/non_dominated_sorting.cpython-312-darwin.so +0 -0
  115. pymoo/functions/compiled/pruning_cd.cpp +29248 -0
  116. pymoo/functions/compiled/pruning_cd.cpython-312-darwin.so +0 -0
  117. pymoo/functions/compiled/stochastic_ranking.cpp +28042 -0
  118. pymoo/functions/compiled/stochastic_ranking.cpython-312-darwin.so +0 -0
  119. pymoo/functions/standard/__init__.py +1 -0
  120. pymoo/functions/standard/calc_perpendicular_distance.py +20 -0
  121. pymoo/functions/standard/decomposition.py +18 -0
  122. pymoo/functions/standard/hv.py +5 -0
  123. pymoo/functions/standard/mnn.py +78 -0
  124. pymoo/functions/standard/non_dominated_sorting.py +474 -0
  125. pymoo/functions/standard/pruning_cd.py +93 -0
  126. pymoo/functions/standard/stochastic_ranking.py +42 -0
  127. pymoo/gradient/__init__.py +24 -0
  128. pymoo/gradient/automatic.py +85 -0
  129. pymoo/gradient/grad_autograd.py +105 -0
  130. pymoo/gradient/grad_complex.py +35 -0
  131. pymoo/gradient/grad_jax.py +51 -0
  132. pymoo/gradient/numpy.py +22 -0
  133. pymoo/gradient/toolbox/__init__.py +19 -0
  134. pymoo/indicators/__init__.py +0 -0
  135. pymoo/indicators/distance_indicator.py +55 -0
  136. pymoo/indicators/gd.py +7 -0
  137. pymoo/indicators/gd_plus.py +7 -0
  138. pymoo/indicators/hv/__init__.py +59 -0
  139. pymoo/indicators/hv/approximate.py +105 -0
  140. pymoo/indicators/hv/exact.py +68 -0
  141. pymoo/indicators/hv/exact_2d.py +102 -0
  142. pymoo/indicators/igd.py +7 -0
  143. pymoo/indicators/igd_plus.py +7 -0
  144. pymoo/indicators/kktpm.py +151 -0
  145. pymoo/indicators/migd.py +55 -0
  146. pymoo/indicators/rmetric.py +203 -0
  147. pymoo/indicators/spacing.py +52 -0
  148. pymoo/mcdm/__init__.py +0 -0
  149. pymoo/mcdm/compromise_programming.py +19 -0
  150. pymoo/mcdm/high_tradeoff.py +40 -0
  151. pymoo/mcdm/pseudo_weights.py +32 -0
  152. pymoo/operators/__init__.py +0 -0
  153. pymoo/operators/control.py +190 -0
  154. pymoo/operators/crossover/__init__.py +0 -0
  155. pymoo/operators/crossover/binx.py +47 -0
  156. pymoo/operators/crossover/dex.py +125 -0
  157. pymoo/operators/crossover/erx.py +164 -0
  158. pymoo/operators/crossover/expx.py +53 -0
  159. pymoo/operators/crossover/hux.py +37 -0
  160. pymoo/operators/crossover/nox.py +25 -0
  161. pymoo/operators/crossover/ox.py +88 -0
  162. pymoo/operators/crossover/pcx.py +84 -0
  163. pymoo/operators/crossover/pntx.py +49 -0
  164. pymoo/operators/crossover/sbx.py +137 -0
  165. pymoo/operators/crossover/spx.py +5 -0
  166. pymoo/operators/crossover/ux.py +20 -0
  167. pymoo/operators/mutation/__init__.py +0 -0
  168. pymoo/operators/mutation/bitflip.py +17 -0
  169. pymoo/operators/mutation/gauss.py +60 -0
  170. pymoo/operators/mutation/inversion.py +42 -0
  171. pymoo/operators/mutation/nom.py +7 -0
  172. pymoo/operators/mutation/pm.py +96 -0
  173. pymoo/operators/mutation/rm.py +23 -0
  174. pymoo/operators/repair/__init__.py +0 -0
  175. pymoo/operators/repair/bounce_back.py +32 -0
  176. pymoo/operators/repair/bounds_repair.py +97 -0
  177. pymoo/operators/repair/inverse_penalty.py +91 -0
  178. pymoo/operators/repair/rounding.py +18 -0
  179. pymoo/operators/repair/to_bound.py +31 -0
  180. pymoo/operators/repair/vtype.py +11 -0
  181. pymoo/operators/sampling/__init__.py +0 -0
  182. pymoo/operators/sampling/lhs.py +76 -0
  183. pymoo/operators/sampling/rnd.py +52 -0
  184. pymoo/operators/selection/__init__.py +0 -0
  185. pymoo/operators/selection/rnd.py +75 -0
  186. pymoo/operators/selection/tournament.py +78 -0
  187. pymoo/operators/survival/__init__.py +0 -0
  188. pymoo/operators/survival/rank_and_crowding/__init__.py +1 -0
  189. pymoo/operators/survival/rank_and_crowding/classes.py +212 -0
  190. pymoo/operators/survival/rank_and_crowding/metrics.py +208 -0
  191. pymoo/optimize.py +72 -0
  192. pymoo/parallelization/__init__.py +15 -0
  193. pymoo/parallelization/dask.py +25 -0
  194. pymoo/parallelization/joblib.py +28 -0
  195. pymoo/parallelization/ray.py +31 -0
  196. pymoo/parallelization/starmap.py +24 -0
  197. pymoo/problems/__init__.py +157 -0
  198. pymoo/problems/dyn.py +47 -0
  199. pymoo/problems/dynamic/__init__.py +0 -0
  200. pymoo/problems/dynamic/cec2015.py +108 -0
  201. pymoo/problems/dynamic/df.py +451 -0
  202. pymoo/problems/dynamic/misc.py +167 -0
  203. pymoo/problems/functional.py +48 -0
  204. pymoo/problems/many/__init__.py +5 -0
  205. pymoo/problems/many/cdtlz.py +159 -0
  206. pymoo/problems/many/dcdtlz.py +88 -0
  207. pymoo/problems/many/dtlz.py +264 -0
  208. pymoo/problems/many/wfg.py +553 -0
  209. pymoo/problems/multi/__init__.py +14 -0
  210. pymoo/problems/multi/bnh.py +34 -0
  211. pymoo/problems/multi/carside.py +48 -0
  212. pymoo/problems/multi/clutch.py +104 -0
  213. pymoo/problems/multi/csi.py +55 -0
  214. pymoo/problems/multi/ctp.py +198 -0
  215. pymoo/problems/multi/dascmop.py +213 -0
  216. pymoo/problems/multi/kursawe.py +25 -0
  217. pymoo/problems/multi/modact.py +68 -0
  218. pymoo/problems/multi/mw.py +400 -0
  219. pymoo/problems/multi/omnitest.py +48 -0
  220. pymoo/problems/multi/osy.py +32 -0
  221. pymoo/problems/multi/srn.py +28 -0
  222. pymoo/problems/multi/sympart.py +94 -0
  223. pymoo/problems/multi/tnk.py +24 -0
  224. pymoo/problems/multi/truss2d.py +83 -0
  225. pymoo/problems/multi/welded_beam.py +41 -0
  226. pymoo/problems/multi/wrm.py +36 -0
  227. pymoo/problems/multi/zdt.py +151 -0
  228. pymoo/problems/multi_to_single.py +22 -0
  229. pymoo/problems/single/__init__.py +12 -0
  230. pymoo/problems/single/ackley.py +24 -0
  231. pymoo/problems/single/cantilevered_beam.py +34 -0
  232. pymoo/problems/single/flowshop_scheduling.py +113 -0
  233. pymoo/problems/single/g.py +874 -0
  234. pymoo/problems/single/griewank.py +18 -0
  235. pymoo/problems/single/himmelblau.py +15 -0
  236. pymoo/problems/single/knapsack.py +49 -0
  237. pymoo/problems/single/mopta08.py +26 -0
  238. pymoo/problems/single/multimodal.py +20 -0
  239. pymoo/problems/single/pressure_vessel.py +30 -0
  240. pymoo/problems/single/rastrigin.py +20 -0
  241. pymoo/problems/single/rosenbrock.py +22 -0
  242. pymoo/problems/single/schwefel.py +18 -0
  243. pymoo/problems/single/simple.py +13 -0
  244. pymoo/problems/single/sphere.py +19 -0
  245. pymoo/problems/single/traveling_salesman.py +79 -0
  246. pymoo/problems/single/zakharov.py +19 -0
  247. pymoo/problems/static.py +14 -0
  248. pymoo/problems/util.py +42 -0
  249. pymoo/problems/zero_to_one.py +27 -0
  250. pymoo/termination/__init__.py +23 -0
  251. pymoo/termination/collection.py +12 -0
  252. pymoo/termination/cv.py +48 -0
  253. pymoo/termination/default.py +45 -0
  254. pymoo/termination/delta.py +64 -0
  255. pymoo/termination/fmin.py +16 -0
  256. pymoo/termination/ftol.py +144 -0
  257. pymoo/termination/indicator.py +49 -0
  258. pymoo/termination/max_eval.py +14 -0
  259. pymoo/termination/max_gen.py +15 -0
  260. pymoo/termination/max_time.py +20 -0
  261. pymoo/termination/robust.py +34 -0
  262. pymoo/termination/xtol.py +33 -0
  263. pymoo/util/__init__.py +33 -0
  264. pymoo/util/archive.py +152 -0
  265. pymoo/util/cache.py +29 -0
  266. pymoo/util/clearing.py +82 -0
  267. pymoo/util/display/__init__.py +0 -0
  268. pymoo/util/display/column.py +52 -0
  269. pymoo/util/display/display.py +34 -0
  270. pymoo/util/display/multi.py +100 -0
  271. pymoo/util/display/output.py +53 -0
  272. pymoo/util/display/progress.py +54 -0
  273. pymoo/util/display/single.py +67 -0
  274. pymoo/util/dominator.py +67 -0
  275. pymoo/util/hv.py +21 -0
  276. pymoo/util/matlab_engine.py +39 -0
  277. pymoo/util/misc.py +447 -0
  278. pymoo/util/nds/__init__.py +0 -0
  279. pymoo/util/nds/dominance_degree_non_dominated_sort.py +159 -0
  280. pymoo/util/nds/efficient_non_dominated_sort.py +152 -0
  281. pymoo/util/nds/fast_non_dominated_sort.py +70 -0
  282. pymoo/util/nds/find_non_dominated.py +54 -0
  283. pymoo/util/nds/naive_non_dominated_sort.py +36 -0
  284. pymoo/util/nds/non_dominated_sorting.py +94 -0
  285. pymoo/util/nds/tree_based_non_dominated_sort.py +133 -0
  286. pymoo/util/normalization.py +312 -0
  287. pymoo/util/optimum.py +42 -0
  288. pymoo/util/randomized_argsort.py +63 -0
  289. pymoo/util/ref_dirs/__init__.py +24 -0
  290. pymoo/util/ref_dirs/construction.py +89 -0
  291. pymoo/util/ref_dirs/das_dennis.py +52 -0
  292. pymoo/util/ref_dirs/energy.py +317 -0
  293. pymoo/util/ref_dirs/energy_layer.py +119 -0
  294. pymoo/util/ref_dirs/genetic_algorithm.py +64 -0
  295. pymoo/util/ref_dirs/incremental.py +69 -0
  296. pymoo/util/ref_dirs/misc.py +128 -0
  297. pymoo/util/ref_dirs/optimizer.py +59 -0
  298. pymoo/util/ref_dirs/performance.py +162 -0
  299. pymoo/util/ref_dirs/reduction.py +85 -0
  300. pymoo/util/ref_dirs/sample_and_map.py +24 -0
  301. pymoo/util/reference_direction.py +258 -0
  302. pymoo/util/remote.py +55 -0
  303. pymoo/util/roulette.py +29 -0
  304. pymoo/util/running_metric.py +128 -0
  305. pymoo/util/sliding_window.py +25 -0
  306. pymoo/util/value_functions.py +720 -0
  307. pymoo/util/vectors.py +40 -0
  308. pymoo/util/vf_dominator.py +102 -0
  309. pymoo/vendor/__init__.py +0 -0
  310. pymoo/vendor/cec2018.py +398 -0
  311. pymoo/vendor/gta.py +617 -0
  312. pymoo/vendor/vendor_cmaes.py +421 -0
  313. pymoo/vendor/vendor_coco.py +81 -0
  314. pymoo/vendor/vendor_scipy.py +232 -0
  315. pymoo/version.py +1 -0
  316. pymoo/visualization/__init__.py +21 -0
  317. pymoo/visualization/app/__init__.py +0 -0
  318. pymoo/visualization/app/pso.py +61 -0
  319. pymoo/visualization/fitness_landscape.py +128 -0
  320. pymoo/visualization/heatmap.py +123 -0
  321. pymoo/visualization/matplotlib.py +61 -0
  322. pymoo/visualization/pcp.py +121 -0
  323. pymoo/visualization/petal.py +91 -0
  324. pymoo/visualization/radar.py +108 -0
  325. pymoo/visualization/radviz.py +68 -0
  326. pymoo/visualization/scatter.py +150 -0
  327. pymoo/visualization/star_coordinate.py +75 -0
  328. pymoo/visualization/util.py +296 -0
  329. pymoo/visualization/video/__init__.py +0 -0
  330. pymoo/visualization/video/callback_video.py +82 -0
  331. pymoo/visualization/video/one_var_one_obj.py +57 -0
  332. pymoo/visualization/video/two_var_one_obj.py +62 -0
  333. pymoo-0.6.1.6.dist-info/METADATA +209 -0
  334. pymoo-0.6.1.6.dist-info/RECORD +337 -0
  335. pymoo-0.6.1.6.dist-info/WHEEL +6 -0
  336. pymoo-0.6.1.6.dist-info/licenses/LICENSE +191 -0
  337. pymoo-0.6.1.6.dist-info/top_level.txt +1 -0
@@ -0,0 +1,408 @@
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.meta import Meta
9
+ from pymoo.core.population import Population
10
+ from pymoo.core.result import Result
11
+ from pymoo.functions import FunctionLoader
12
+ from pymoo.termination.default import DefaultMultiObjectiveTermination, DefaultSingleObjectiveTermination
13
+ from pymoo.util.display.display import Display
14
+ from pymoo.util.misc import termination_from_tuple
15
+ from pymoo.util.optimum import filter_optimum
16
+
17
+
18
+ class Algorithm:
19
+
20
+ def __init__(self,
21
+ termination=None,
22
+ output=None,
23
+ display=None,
24
+ callback=None,
25
+ archive=None,
26
+ return_least_infeasible=False,
27
+ save_history=False,
28
+ verbose=False,
29
+ seed=None,
30
+ evaluator=None,
31
+ **kwargs):
32
+
33
+ super().__init__()
34
+
35
+ # prints the compile warning if enabled
36
+ FunctionLoader.get_instance()
37
+
38
+ # the problem to be solved (will be set later on)
39
+ self.problem = None
40
+
41
+ # the termination criterion to be used by the algorithm - might be specific for an algorithm
42
+ self.termination = termination
43
+
44
+ # the text that should be printed during the algorithm run
45
+ self.output = output
46
+
47
+ # an archive kept during algorithm execution (not always the same as optimum)
48
+ self.archive = archive
49
+
50
+ # the form of display shown during algorithm execution
51
+ self.display = display
52
+
53
+ # callback to be executed each generation
54
+ if callback is None:
55
+ callback = Callback()
56
+ self.callback = callback
57
+
58
+ # whether the algorithm should finally return the least infeasible solution if no feasible found
59
+ self.return_least_infeasible = return_least_infeasible
60
+
61
+ # whether the history should be saved or not
62
+ self.save_history = save_history
63
+
64
+ # whether the algorithm should print output in this run or not
65
+ self.verbose = verbose
66
+
67
+ # the random seed that was used
68
+ self.seed = seed
69
+ self.random_state = None
70
+
71
+ # the function evaluator object (can be used to inject code)
72
+ if evaluator is None:
73
+ evaluator = Evaluator()
74
+ self.evaluator = evaluator
75
+
76
+ # the history object which contains the list
77
+ self.history = list()
78
+
79
+ # the current solutions stored - here considered as population
80
+ self.pop = None
81
+
82
+ # a placeholder object for implementation to store solutions in each iteration
83
+ self.off = None
84
+
85
+ # the optimum found by the algorithm
86
+ self.opt = None
87
+
88
+ # the current number of generation or iteration
89
+ self.n_iter = None
90
+
91
+ # can be used to store additional data in submodules
92
+ self.data = {}
93
+
94
+ # if the initialized method has been called before or not
95
+ self.is_initialized = False
96
+
97
+ # the time when the algorithm has been setup for the first time
98
+ self.start_time = None
99
+
100
+ def setup(self, problem, verbose=False, progress=False, **kwargs):
101
+
102
+ # the problem to be solved by the algorithm
103
+ self.problem = problem
104
+
105
+ # clone the output object if it exists to avoid state pollution between runs
106
+ if self.output is not None:
107
+ self.output = copy.deepcopy(self.output)
108
+
109
+ # set all the provided options to this method
110
+ for key, value in kwargs.items():
111
+ self.__dict__[key] = value
112
+
113
+ # set random state
114
+ self.random_state = np.random.default_rng(self.seed)
115
+
116
+ # make sure that some type of termination criterion is set
117
+ if self.termination is None:
118
+ self.termination = default_termination(problem)
119
+ else:
120
+ self.termination = termination_from_tuple(self.termination)
121
+
122
+ # set up the display during the algorithm execution
123
+ if self.display is None:
124
+ self.display = Display(self.output, verbose=verbose, progress=progress)
125
+
126
+ # finally call the function that can be overwritten by the actual algorithm
127
+ self._setup(problem, **kwargs)
128
+
129
+ return self
130
+
131
+ def run(self):
132
+ while self.has_next():
133
+ self.next()
134
+ return self.result()
135
+
136
+ def has_next(self):
137
+ return not self.termination.has_terminated()
138
+
139
+ def finalize(self):
140
+
141
+ # finalize the display output in the end of the run
142
+ self.display.finalize()
143
+
144
+ return self._finalize()
145
+
146
+ def next(self):
147
+
148
+ # get the infill solutions
149
+ infills = self.infill()
150
+
151
+ # call the advance with them after evaluation
152
+ if infills is not None:
153
+ self.evaluator.eval(self.problem, infills, algorithm=self)
154
+ self.advance(infills=infills)
155
+
156
+ # if the algorithm does not follow the infill-advance scheme just call advance
157
+ else:
158
+ self.advance()
159
+
160
+ def _initialize(self):
161
+
162
+ # the time starts whenever this method is called
163
+ self.start_time = time.time()
164
+
165
+ # set the attribute for the optimization method to start
166
+ self.n_iter = 1
167
+ self.pop = Population.empty()
168
+ self.opt = None
169
+
170
+ def infill(self):
171
+ if self.problem is None:
172
+ raise Exception("Please call `setup(problem)` before calling next().")
173
+
174
+ # the first time next is called simply initial the algorithm - makes the interface cleaner
175
+ if not self.is_initialized:
176
+
177
+ # hook mostly used by the class to happen before even to initialize
178
+ self._initialize()
179
+
180
+ # execute the initialization infill of the algorithm
181
+ infills = self._initialize_infill()
182
+
183
+ else:
184
+ # request the infill solutions if the algorithm has implemented it
185
+ infills = self._infill()
186
+
187
+ # set the current generation to the offsprings
188
+ if infills is not None:
189
+ infills.set("n_gen", self.n_iter)
190
+ infills.set("n_iter", self.n_iter)
191
+
192
+ return infills
193
+
194
+ def advance(self, infills=None, **kwargs):
195
+
196
+ # if infills have been provided set them as offsprings and feed them into advance
197
+ self.off = infills
198
+
199
+ # if the algorithm has not been already initialized
200
+ if not self.is_initialized:
201
+
202
+ # set the generation counter to 1
203
+ self.n_iter = 1
204
+
205
+ # assign the population to the algorithm
206
+ self.pop = infills
207
+
208
+ # do what is necessary after the initialization
209
+ self._initialize_advance(infills=infills, **kwargs)
210
+
211
+ # set this algorithm to be initialized
212
+ self.is_initialized = True
213
+
214
+ # always advance to the next iteration after initialization
215
+ self._post_advance()
216
+
217
+ else:
218
+
219
+ # call the implementation of the advance method - if the infill is not None
220
+ val = self._advance(infills=infills, **kwargs)
221
+
222
+ # always advance to the next iteration - except if the algorithm returns False
223
+ if val is None or val:
224
+ self._post_advance()
225
+
226
+ # if the algorithm has terminated, then do the finalization steps and return the result
227
+ if self.termination.has_terminated():
228
+ self.finalize()
229
+ ret = self.result()
230
+
231
+ # otherwise just increase the iteration counter for the next step and return the current optimum
232
+ else:
233
+ ret = self.opt
234
+
235
+ # add the infill solutions to an archive
236
+ if self.archive is not None and infills is not None:
237
+ self.archive = self.archive.add(infills)
238
+
239
+ return ret
240
+
241
+ def result(self):
242
+ res = Result()
243
+
244
+ # store the time when the algorithm as finished
245
+ res.start_time = self.start_time
246
+ res.end_time = time.time()
247
+ res.exec_time = res.end_time - res.start_time
248
+
249
+ res.pop = self.pop
250
+ res.archive = self.archive
251
+ res.data = self.data
252
+
253
+ # get the optimal solution found
254
+ opt = self.opt
255
+ if opt is None or len(opt) == 0:
256
+ opt = None
257
+
258
+ # if no feasible solution has been found
259
+ elif not np.any(opt.get("FEAS")):
260
+ if self.return_least_infeasible:
261
+ opt = filter_optimum(opt, least_infeasible=True)
262
+ else:
263
+ opt = None
264
+ res.opt = opt
265
+
266
+ # if optimum is set to none to not report anything
267
+ if res.opt is None:
268
+ X, F, CV, G, H = None, None, None, None, None
269
+
270
+ # otherwise get the values from the population
271
+ else:
272
+ X, F, CV, G, H = self.opt.get("X", "F", "CV", "G", "H")
273
+
274
+ # if single-objective problem and only one solution was found - create a 1d array
275
+ if self.problem.n_obj == 1 and len(X) == 1:
276
+ X, F, CV, G, H = X[0], F[0], CV[0], G[0], H[0]
277
+
278
+ # set all the individual values
279
+ res.X, res.F, res.CV, res.G, res.H = X, F, CV, G, H
280
+
281
+ # create the result object
282
+ res.problem = self.problem
283
+ res.history = self.history
284
+
285
+ return res
286
+
287
+ def ask(self):
288
+ return self.infill()
289
+
290
+ def tell(self, *args, **kwargs):
291
+ return self.advance(*args, **kwargs)
292
+
293
+ def _set_optimum(self):
294
+ self.opt = filter_optimum(self.pop, least_infeasible=True)
295
+
296
+ def _post_advance(self):
297
+
298
+ # update the current optimum of the algorithm
299
+ self._set_optimum()
300
+
301
+ # update the current termination condition of the algorithm
302
+ self.termination.update(self)
303
+
304
+ # display the output if defined by the algorithm
305
+ self.display(self)
306
+
307
+ if self.save_history:
308
+ _hist, _callback, _display = self.history, self.callback, self.display
309
+
310
+ self.history, self.callback, self.display = None, None, None
311
+ obj = copy.deepcopy(self)
312
+
313
+ self.history, self.callback, self.display = _hist, _callback, _display
314
+ self.history.append(obj)
315
+
316
+ # if a callback function is provided it is called after each iteration
317
+ self.callback(self)
318
+
319
+ self.n_iter += 1
320
+
321
+ # =========================================================================================================
322
+ # TO BE OVERWRITTEN
323
+ # =========================================================================================================
324
+
325
+ def _setup(self, problem, **kwargs):
326
+ pass
327
+
328
+ def _initialize_infill(self):
329
+ pass
330
+
331
+ def _initialize_advance(self, infills=None, **kwargs):
332
+ pass
333
+
334
+ def _infill(self):
335
+ pass
336
+
337
+ def _advance(self, infills=None, **kwargs):
338
+ pass
339
+
340
+ def _finalize(self):
341
+ pass
342
+
343
+ # =========================================================================================================
344
+ # CONVENIENCE
345
+ # =========================================================================================================
346
+
347
+ @property
348
+ def n_gen(self):
349
+ return self.n_iter
350
+
351
+ @n_gen.setter
352
+ def n_gen(self, value):
353
+ self.n_iter = value
354
+
355
+
356
+ class LoopwiseAlgorithm(Algorithm):
357
+
358
+ def __init__(self, **kwargs):
359
+ super().__init__(**kwargs)
360
+ self.generator = None
361
+ self.state = None
362
+
363
+ def _next(self):
364
+ pass
365
+
366
+ def _infill(self):
367
+ if self.state is None:
368
+ self._advance()
369
+ return self.state
370
+
371
+ def _advance(self, infills=None, **kwargs):
372
+ if self.generator is None:
373
+ self.generator = self._next()
374
+ try:
375
+ self.state = self.generator.send(infills)
376
+ except StopIteration:
377
+ self.generator = None
378
+ self.state = None
379
+ return True
380
+
381
+ return False
382
+
383
+
384
+ def default_termination(problem):
385
+ if problem.n_obj > 1:
386
+ termination = DefaultMultiObjectiveTermination()
387
+ else:
388
+ termination = DefaultSingleObjectiveTermination()
389
+ return termination
390
+
391
+
392
+ class MetaAlgorithm(Meta):
393
+ """
394
+ An algorithm wrapper that combines Algorithm's functionality with Meta's delegation behavior.
395
+ Uses Meta to provide transparent proxying with the ability to override specific methods.
396
+ """
397
+
398
+ def __init__(self, algorithm, copy=True, **kwargs):
399
+ # If the algorithm is already a Meta object, don't copy to avoid deepcopy issues with nested proxies
400
+ if isinstance(algorithm, Meta):
401
+ copy = False
402
+
403
+ # Initialize Meta
404
+ super().__init__(algorithm, copy=copy)
405
+
406
+ # Pass any additional kwargs to the wrapped algorithm if needed
407
+ for key, value in kwargs.items():
408
+ setattr(self, key, value)
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,79 @@
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
+ from pymoo.util import default_random_state
7
+
8
+
9
+ class Crossover(Operator):
10
+
11
+ def __init__(self,
12
+ n_parents,
13
+ n_offsprings,
14
+ prob=0.9,
15
+ **kwargs):
16
+ super().__init__(**kwargs)
17
+ self.n_parents = n_parents
18
+ self.n_offsprings = n_offsprings
19
+ self.prob = Real(prob, bounds=(0.5, 1.0), strict=(0.0, 1.0))
20
+
21
+ @default_random_state
22
+ def do(self, problem, pop, parents=None, *args, random_state=None, **kwargs):
23
+
24
+ # if a parents with array with mating indices is provided -> transform the input first
25
+ if parents is not None:
26
+ pop = [pop[mating] for mating in parents]
27
+
28
+ # get the dimensions necessary to create in and output
29
+ n_parents, n_offsprings = self.n_parents, self.n_offsprings
30
+ n_matings, n_var = len(pop), problem.n_var
31
+
32
+ # get the actual values from each of the parents
33
+ X = np.swapaxes(np.array([[parent.get("X") for parent in mating] for mating in pop]), 0, 1)
34
+ if self.vtype is not None:
35
+ X = X.astype(self.vtype)
36
+
37
+ # the array where the offsprings will be stored to
38
+ Xp = np.empty(shape=(n_offsprings, n_matings, n_var), dtype=X.dtype)
39
+
40
+ # the probability of executing the crossover
41
+ prob = get(self.prob, size=n_matings)
42
+
43
+ # a boolean mask when crossover is actually executed
44
+ cross = random_state.random(n_matings) < prob
45
+
46
+ # the design space from the parents used for the crossover
47
+ if np.any(cross):
48
+
49
+ # we can not prefilter for cross first, because there might be other variables using the same shape as X
50
+ Q = self._do(problem, X, *args, random_state=random_state, **kwargs)
51
+ assert Q.shape == (n_offsprings, n_matings, problem.n_var), "Shape is incorrect of crossover impl."
52
+ Xp[:, cross] = Q[:, cross]
53
+
54
+ # now set the parents whenever NO crossover has been applied
55
+ for k in np.flatnonzero(~cross):
56
+ if n_offsprings < n_parents:
57
+ s = random_state.choice(np.arange(self.n_parents), size=n_offsprings, replace=False)
58
+ elif n_offsprings == n_parents:
59
+ s = np.arange(n_parents)
60
+ else:
61
+ s = []
62
+ while len(s) < n_offsprings:
63
+ s.extend(random_state.permutation(n_parents))
64
+ s = s[:n_offsprings]
65
+
66
+ Xp[:, k] = np.copy(X[s, k])
67
+
68
+ # flatten the array to become a 2d-array
69
+ Xp = Xp.reshape(-1, X.shape[-1])
70
+
71
+ # create a population object
72
+ off = Population.new("X", Xp)
73
+
74
+ return off
75
+
76
+ def _do(self, problem, X, *args, random_state=None, **kwargs):
77
+ pass
78
+
79
+
@@ -0,0 +1,102 @@
1
+ import numpy as np
2
+ from scipy.spatial.ckdtree import cKDTree
3
+
4
+ from pymoo.core.indicator import Indicator
5
+
6
+
7
+ class DecisionMaking(Indicator):
8
+
9
+ def __init__(self, **kwargs) -> None:
10
+ super().__init__(**kwargs)
11
+ self.default_if_empty = None
12
+
13
+ def _do(self, F, *args, **kwargs):
14
+ pass
15
+
16
+
17
+ class NeighborFinder:
18
+
19
+ def __init__(self, N,
20
+ epsilon=0.125,
21
+ n_neighbors=None,
22
+ n_min_neigbors=None,
23
+ consider_2d=True):
24
+
25
+ super().__init__()
26
+ self.N = N
27
+ self.consider_2d = consider_2d
28
+
29
+ _, n_dim = N.shape
30
+
31
+ # at least find min(dimensionality times two neighbors, number PO solutions - 1) - if enabled
32
+ if n_min_neigbors == "auto":
33
+ self.n_min_neigbors = min(2 * n_dim, _ - 1)
34
+
35
+ # disable the minimum neighbor variable
36
+ else:
37
+ self.n_min_neigbors = np.inf
38
+
39
+ # either choose epsilon
40
+ self.epsilon = epsilon
41
+
42
+ # if none choose the number of neighbors
43
+ self.n_neighbors = n_neighbors
44
+
45
+ if self.N.shape[1] == 1:
46
+ raise Exception("At least 2 objectives must be provided.")
47
+
48
+ elif self.consider_2d and self.N.shape[1] == 2:
49
+ self.min, self.max = N.min(), N.max()
50
+ self.rank = np.argsort(N[:, 0])
51
+ self.pos_in_rank = np.argsort(self.rank)
52
+
53
+ else:
54
+ self.tree = cKDTree(N)
55
+
56
+ def find(self, i):
57
+
58
+ if self.consider_2d and self.N.shape[1] == 2:
59
+ neighbours = []
60
+
61
+ pos = self.pos_in_rank[i]
62
+ if pos > 0:
63
+ neighbours.append(self.rank[pos - 1])
64
+ if pos < len(self.N) - 1:
65
+ neighbours.append(self.rank[pos + 1])
66
+
67
+ else:
68
+
69
+ # for each neighbour in a specific radius of that solution
70
+ if self.epsilon is not None:
71
+ neighbours = self.tree.query_ball_point([self.N[i]], self.epsilon).tolist()[0]
72
+ elif self.n_neighbors is not None:
73
+ neighbours = self.tree.query([self.N[i]], k=self.n_neighbors + 1)[1].tolist()[0]
74
+ else:
75
+ raise Exception("Either define epsilon or number of neighbors.")
76
+
77
+ # in case n_min_neigbors is enabled
78
+ if len(neighbours) < self.n_min_neigbors:
79
+ neighbours = self.tree.query([self.N[i]], k=self.n_min_neigbors + 1)[1].tolist()[0]
80
+
81
+ return neighbours
82
+
83
+
84
+ def find_outliers_upper_tail(mu):
85
+
86
+ # remove values that are nan
87
+ I = np.where(np.logical_and(np.logical_not(np.isnan(mu)), np.logical_not(np.isinf(mu))))[0]
88
+ mu = mu[I]
89
+
90
+ # calculate mean and sigma
91
+ mean, sigma = mu.mean(), mu.std()
92
+
93
+ # calculate the deviation in terms of sigma
94
+ deviation = (mu - mean) / sigma
95
+
96
+ # 2 * sigma is considered as an outlier
97
+ S = I[np.where(deviation >= 2)[0]]
98
+
99
+ if len(S) == 0 and deviation.max() > 1:
100
+ S = I[[np.argmax(mu)]]
101
+
102
+ return S if len(S) > 0 else None
@@ -0,0 +1,76 @@
1
+ import numpy as np
2
+
3
+ from pymoo.util.misc import at_least_2d_array, to_1d_array_if_possible
4
+
5
+
6
+ class Decomposition:
7
+
8
+ def __init__(self, eps=0.0, _type="auto", **kwargs) -> None:
9
+ super().__init__()
10
+ self.eps = eps
11
+ self._type = _type
12
+ self.ideal_point, self.utopian_point, self.nadir_point = None, None, None
13
+
14
+ def __call__(self, *args, **kwargs):
15
+ return self.do(*args, **kwargs)
16
+
17
+ def do(self,
18
+ F,
19
+ weights,
20
+ _type="auto",
21
+ ideal_point=None,
22
+ utopian_point=None,
23
+ nadir_point=None,
24
+ **kwargs):
25
+
26
+ _F, _weights = to_1d_array_if_possible(F), to_1d_array_if_possible(weights)
27
+
28
+ if _type == "auto":
29
+ if _F.ndim == 1 and _weights.ndim > 1:
30
+ _type = "one_to_many"
31
+ elif _F.ndim > 1 and _weights.ndim == 1:
32
+ _type = "many_to_one"
33
+ elif _F.ndim == 2 and _weights.ndim == 2 and _F.shape[0] == _weights.shape[0]:
34
+ _type = "one_to_one"
35
+ else:
36
+ _type = "many_to_many"
37
+
38
+ # make both at least 2d arrays
39
+ F, weights = at_least_2d_array(F), at_least_2d_array(weights)
40
+
41
+ # get the number of points and weights
42
+ n_points, n_weights = F.shape[0], weights.shape[0]
43
+
44
+ self.ideal_point = ideal_point
45
+ if self.ideal_point is None:
46
+ self.ideal_point = np.zeros(F.shape[1])
47
+
48
+ self.utopian_point = utopian_point
49
+ if self.utopian_point is None:
50
+ self.utopian_point = self.ideal_point - self.eps
51
+
52
+ # set the nadir point by default to value or default
53
+ self.nadir_point = nadir_point
54
+ if self.nadir_point is None:
55
+ self.nadir_point = self.utopian_point + np.ones(F.shape[1])
56
+
57
+ if _type == "one_to_one":
58
+ D = self._do(F, weights=weights, **kwargs).flatten()
59
+
60
+ elif _type == "one_to_many":
61
+ F = np.repeat(F, n_weights, axis=0)
62
+ D = self._do(F, weights=weights, **kwargs).flatten()
63
+
64
+ elif _type == "many_to_one":
65
+ weights = np.repeat(weights, n_points, axis=0)
66
+ D = self._do(F, weights=weights, **kwargs).flatten()
67
+
68
+ elif _type == "many_to_many":
69
+ F = np.repeat(F, n_weights, axis=0)
70
+ weights = np.tile(weights, (n_points, 1))
71
+ D = self._do(F, weights=weights, **kwargs).reshape(n_points, n_weights)
72
+
73
+ else:
74
+ raise Exception("Unknown type for decomposition: %s" % _type)
75
+
76
+ return D