pymoo 0.6.1.5.dev0__cp39-cp39-musllinux_1_2_x86_64.whl

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

Potentially problematic release.


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

Files changed (330) hide show
  1. pymoo/__init__.py +3 -0
  2. pymoo/algorithms/__init__.py +0 -0
  3. pymoo/algorithms/base/__init__.py +0 -0
  4. pymoo/algorithms/base/bracket.py +38 -0
  5. pymoo/algorithms/base/genetic.py +109 -0
  6. pymoo/algorithms/base/line.py +62 -0
  7. pymoo/algorithms/base/local.py +39 -0
  8. pymoo/algorithms/base/meta.py +79 -0
  9. pymoo/algorithms/hyperparameters.py +89 -0
  10. pymoo/algorithms/moo/__init__.py +0 -0
  11. pymoo/algorithms/moo/age.py +310 -0
  12. pymoo/algorithms/moo/age2.py +194 -0
  13. pymoo/algorithms/moo/ctaea.py +298 -0
  14. pymoo/algorithms/moo/dnsga2.py +76 -0
  15. pymoo/algorithms/moo/kgb.py +446 -0
  16. pymoo/algorithms/moo/moead.py +183 -0
  17. pymoo/algorithms/moo/nsga2.py +113 -0
  18. pymoo/algorithms/moo/nsga3.py +358 -0
  19. pymoo/algorithms/moo/pinsga2.py +370 -0
  20. pymoo/algorithms/moo/rnsga2.py +188 -0
  21. pymoo/algorithms/moo/rnsga3.py +246 -0
  22. pymoo/algorithms/moo/rvea.py +214 -0
  23. pymoo/algorithms/moo/sms.py +195 -0
  24. pymoo/algorithms/moo/spea2.py +190 -0
  25. pymoo/algorithms/moo/unsga3.py +47 -0
  26. pymoo/algorithms/soo/__init__.py +0 -0
  27. pymoo/algorithms/soo/convex/__init__.py +0 -0
  28. pymoo/algorithms/soo/nonconvex/__init__.py +0 -0
  29. pymoo/algorithms/soo/nonconvex/brkga.py +161 -0
  30. pymoo/algorithms/soo/nonconvex/cmaes.py +554 -0
  31. pymoo/algorithms/soo/nonconvex/de.py +279 -0
  32. pymoo/algorithms/soo/nonconvex/direct.py +149 -0
  33. pymoo/algorithms/soo/nonconvex/es.py +203 -0
  34. pymoo/algorithms/soo/nonconvex/g3pcx.py +94 -0
  35. pymoo/algorithms/soo/nonconvex/ga.py +93 -0
  36. pymoo/algorithms/soo/nonconvex/ga_niching.py +223 -0
  37. pymoo/algorithms/soo/nonconvex/isres.py +74 -0
  38. pymoo/algorithms/soo/nonconvex/nelder.py +251 -0
  39. pymoo/algorithms/soo/nonconvex/optuna.py +80 -0
  40. pymoo/algorithms/soo/nonconvex/pattern.py +183 -0
  41. pymoo/algorithms/soo/nonconvex/pso.py +399 -0
  42. pymoo/algorithms/soo/nonconvex/pso_ep.py +297 -0
  43. pymoo/algorithms/soo/nonconvex/random_search.py +25 -0
  44. pymoo/algorithms/soo/nonconvex/sres.py +56 -0
  45. pymoo/algorithms/soo/univariate/__init__.py +0 -0
  46. pymoo/algorithms/soo/univariate/backtracking.py +59 -0
  47. pymoo/algorithms/soo/univariate/exp.py +46 -0
  48. pymoo/algorithms/soo/univariate/golden.py +65 -0
  49. pymoo/algorithms/soo/univariate/quadr_interp.py +81 -0
  50. pymoo/algorithms/soo/univariate/wolfe.py +163 -0
  51. pymoo/config.py +33 -0
  52. pymoo/constraints/__init__.py +3 -0
  53. pymoo/constraints/adaptive.py +62 -0
  54. pymoo/constraints/as_obj.py +56 -0
  55. pymoo/constraints/as_penalty.py +41 -0
  56. pymoo/constraints/eps.py +26 -0
  57. pymoo/constraints/from_bounds.py +36 -0
  58. pymoo/core/__init__.py +0 -0
  59. pymoo/core/algorithm.py +394 -0
  60. pymoo/core/callback.py +38 -0
  61. pymoo/core/crossover.py +77 -0
  62. pymoo/core/decision_making.py +102 -0
  63. pymoo/core/decomposition.py +76 -0
  64. pymoo/core/duplicate.py +163 -0
  65. pymoo/core/evaluator.py +116 -0
  66. pymoo/core/indicator.py +34 -0
  67. pymoo/core/individual.py +784 -0
  68. pymoo/core/infill.py +64 -0
  69. pymoo/core/initialization.py +42 -0
  70. pymoo/core/mating.py +39 -0
  71. pymoo/core/meta.py +21 -0
  72. pymoo/core/mixed.py +165 -0
  73. pymoo/core/mutation.py +44 -0
  74. pymoo/core/operator.py +40 -0
  75. pymoo/core/parameters.py +134 -0
  76. pymoo/core/plot.py +210 -0
  77. pymoo/core/population.py +180 -0
  78. pymoo/core/problem.py +460 -0
  79. pymoo/core/recorder.py +99 -0
  80. pymoo/core/repair.py +23 -0
  81. pymoo/core/replacement.py +96 -0
  82. pymoo/core/result.py +52 -0
  83. pymoo/core/sampling.py +43 -0
  84. pymoo/core/selection.py +61 -0
  85. pymoo/core/solution.py +10 -0
  86. pymoo/core/survival.py +103 -0
  87. pymoo/core/termination.py +70 -0
  88. pymoo/core/variable.py +399 -0
  89. pymoo/cython/__init__.py +0 -0
  90. pymoo/cython/calc_perpendicular_distance.cpython-39-x86_64-linux-gnu.so +0 -0
  91. pymoo/cython/calc_perpendicular_distance.pyx +67 -0
  92. pymoo/cython/decomposition.cpython-39-x86_64-linux-gnu.so +0 -0
  93. pymoo/cython/decomposition.pyx +165 -0
  94. pymoo/cython/hv.cpython-39-x86_64-linux-gnu.so +0 -0
  95. pymoo/cython/hv.pyx +18 -0
  96. pymoo/cython/info.cpython-39-x86_64-linux-gnu.so +0 -0
  97. pymoo/cython/info.pyx +5 -0
  98. pymoo/cython/mnn.cpython-39-x86_64-linux-gnu.so +0 -0
  99. pymoo/cython/mnn.pyx +273 -0
  100. pymoo/cython/non_dominated_sorting.cpython-39-x86_64-linux-gnu.so +0 -0
  101. pymoo/cython/non_dominated_sorting.pyx +645 -0
  102. pymoo/cython/pruning_cd.cpython-39-x86_64-linux-gnu.so +0 -0
  103. pymoo/cython/pruning_cd.pyx +197 -0
  104. pymoo/cython/stochastic_ranking.cpython-39-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 +330 -0
  326. pymoo-0.6.1.5.dev0.dist-info/WHEEL +5 -0
  327. pymoo-0.6.1.5.dev0.dist-info/licenses/LICENSE +191 -0
  328. pymoo-0.6.1.5.dev0.dist-info/top_level.txt +1 -0
  329. pymoo.libs/libgcc_s-2298274a.so.1 +0 -0
  330. pymoo.libs/libstdc++-08d5c7eb.so.6.0.33 +0 -0
@@ -0,0 +1,279 @@
1
+ """
2
+
3
+ Differential Evolution (DE)
4
+
5
+ -------------------------------- Description -------------------------------
6
+
7
+
8
+
9
+ -------------------------------- References --------------------------------
10
+
11
+ [1] J. Blank and K. Deb, pymoo: Multi-Objective Optimization in Python, in IEEE Access,
12
+ vol. 8, pp. 89497-89509, 2020, DOI: 10.1109/ACCESS.2020.2990567
13
+
14
+ -------------------------------- License -----------------------------------
15
+
16
+
17
+ ----------------------------------------------------------------------------
18
+ """
19
+
20
+ import numpy as np
21
+
22
+ from pymoo.algorithms.base.genetic import GeneticAlgorithm
23
+ from pymoo.algorithms.soo.nonconvex.ga import FitnessSurvival
24
+ from pymoo.core.infill import InfillCriterion
25
+ from pymoo.core.population import Population
26
+ from pymoo.core.replacement import ImprovementReplacement
27
+ from pymoo.core.variable import Choice, get
28
+ from pymoo.core.variable import Real
29
+ from pymoo.docs import parse_doc_string
30
+ from pymoo.operators.control import EvolutionaryParameterControl, NoParameterControl
31
+ from pymoo.operators.crossover.binx import mut_binomial
32
+ from pymoo.operators.crossover.expx import mut_exp
33
+ from pymoo.operators.mutation.pm import PM
34
+ from pymoo.operators.repair.bounds_repair import repair_random_init
35
+ from pymoo.operators.sampling.rnd import FloatRandomSampling
36
+ from pymoo.operators.selection.rnd import fast_fill_random
37
+ from pymoo.termination.default import DefaultSingleObjectiveTermination
38
+ from pymoo.util.display.single import SingleObjectiveOutput
39
+ from pymoo.util.misc import where_is_what
40
+
41
+
42
+ # =========================================================================================================
43
+ # Crossover
44
+ # =========================================================================================================
45
+
46
+ def de_differential(X, F, jitter, alpha=0.001):
47
+ n_parents, n_matings, n_var = X.shape
48
+ assert n_parents % 2 == 1, "For the differential an odd number of values need to be provided"
49
+
50
+ # the differentials from each pair
51
+ delta = np.zeros((n_matings, n_var))
52
+
53
+ # for each difference of the differences
54
+ for i in range(1, n_parents, 2):
55
+ # create the weight vectors with jitter to give some variation
56
+ _F = F[:, None].repeat(n_var, axis=1)
57
+ _F[jitter] *= (1 + alpha * (np.random.random((jitter.sum(), n_var)) - 0.5))
58
+
59
+ # add the difference to the vector
60
+ delta += _F * (X[i] - X[i + 1])
61
+
62
+ # now add the differentials to the first parent
63
+ Xp = X[0] + delta
64
+
65
+ return Xp
66
+
67
+
68
+ # =========================================================================================================
69
+ # Variant
70
+ # =========================================================================================================
71
+
72
+ class Variant(InfillCriterion):
73
+
74
+ def __init__(self,
75
+ selection="best",
76
+ n_diffs=1,
77
+ F=0.5,
78
+ crossover="bin",
79
+ CR=0.2,
80
+ jitter=False,
81
+ prob_mut=0.1,
82
+ control=EvolutionaryParameterControl,
83
+ **kwargs):
84
+
85
+ super().__init__(**kwargs)
86
+ self.selection = Choice(selection, options=["rand", "best"], all=["rand", "best", "target-to-best"])
87
+ self.n_diffs = Choice(n_diffs, options=[1], all=[1, 2])
88
+ self.F = Real(F, bounds=(0.4, 0.7), strict=(0.0, None))
89
+ self.crossover = Choice(crossover, ["bin"], all=["bin", "exp", "hypercube", "line"])
90
+ self.CR = Real(CR, bounds=(0.2, 0.8), strict=(0.0, 1.0))
91
+ self.jitter = Choice(jitter, options=[False], all=[True, False])
92
+
93
+ self.mutation = PM(at_least_once=True)
94
+ self.mutation.eta = 20
95
+ self.mutation.prob = prob_mut
96
+
97
+ self.control = control(self)
98
+
99
+ def do(self, problem, pop, n_offsprings, algorithm=None, **kwargs):
100
+ control = self.control
101
+
102
+ # let the parameter control now some information
103
+ control.tell(pop=pop)
104
+
105
+ # set the controlled parameter for the desired number of offsprings
106
+ control.do(n_offsprings)
107
+
108
+ # find the different groups of selection schemes and order them by category
109
+ sel, n_diffs = get(self.selection, self.n_diffs, size=n_offsprings)
110
+ H = where_is_what(zip(sel, n_diffs))
111
+
112
+ # get the parameters used for reproduction during the crossover
113
+ F, CR, jitter = get(self.F, self.CR, self.jitter, size=n_offsprings)
114
+
115
+ # the `target` vectors which will be recombined
116
+ X = pop.get("X")
117
+
118
+ # the `donor` vector which will be obtained through the differential equation
119
+ donor = np.full((n_offsprings, problem.n_var), np.nan)
120
+
121
+ # for each type defined by the type and number of differentials
122
+ for (sel_type, n_diffs), targets in H.items():
123
+
124
+ # the number of offsprings created in this run
125
+ n_matings, n_parents = len(targets), 1 + 2 * n_diffs
126
+
127
+ # create the parents array
128
+ P = np.full([n_matings, n_parents], -1)
129
+
130
+ itself = np.array(targets)[:, None]
131
+
132
+ best = lambda: np.random.choice(np.where(pop.get("rank") == 0)[0], replace=True, size=n_matings)
133
+
134
+ if sel_type == "rand":
135
+ fast_fill_random(P, len(pop), columns=range(n_parents), Xp=itself)
136
+ elif sel_type == "best":
137
+ P[:, 0] = best()
138
+ fast_fill_random(P, len(pop), columns=range(1, n_parents), Xp=itself)
139
+ elif sel_type == "target-to-best":
140
+ P[:, 0] = targets
141
+ P[:, 1] = best()
142
+ fast_fill_random(P, len(pop), columns=range(2, n_parents), Xp=itself)
143
+ else:
144
+ raise Exception("Unknown selection method.")
145
+
146
+ # get the values of the parents in the design space
147
+ XX = np.swapaxes(X[P], 0, 1)
148
+
149
+ # do the differential crossover to create the donor vector
150
+ Xp = de_differential(XX, F[targets], jitter[targets])
151
+
152
+ # make sure everything stays in bounds
153
+ if problem.has_bounds():
154
+ Xp = repair_random_init(Xp, XX[0], *problem.bounds())
155
+
156
+ # set the donors (the one we have created in this step)
157
+ donor[targets] = Xp
158
+
159
+ # the `trial` created by by recombining target and donor
160
+ trial = np.full((n_offsprings, problem.n_var), np.nan)
161
+
162
+ crossover = get(self.crossover, size=n_offsprings)
163
+ for name, K in where_is_what(crossover).items():
164
+
165
+ _target = X[K]
166
+ _donor = donor[K]
167
+ _CR = CR[K]
168
+
169
+ if name == "bin":
170
+ M = mut_binomial(len(K), problem.n_var, _CR, at_least_once=True)
171
+ _trial = np.copy(_target)
172
+ _trial[M] = _donor[M]
173
+ elif name == "exp":
174
+ M = mut_exp(n_offsprings, problem.n_var, _CR, at_least_once=True)
175
+ _trial = np.copy(_target)
176
+ _trial[M] = _donor[M]
177
+ elif name == "line":
178
+ w = np.random.random((len(K), 1)) * _CR[:, None]
179
+ _trial = _target + w * (_donor - _target)
180
+ elif name == "hypercube":
181
+ w = np.random.random((len(K), _target.shape[1])) * _CR[:, None]
182
+ _trial = _target + w * (_donor - _target)
183
+ else:
184
+ raise Exception(f"Unknown crossover variant: {name}")
185
+
186
+ trial[K] = _trial
187
+
188
+ # create the population
189
+ off = Population.new(X=trial)
190
+
191
+ # do the mutation which helps to add some more diversity
192
+ off = self.mutation(problem, off)
193
+
194
+ # repair the individuals if necessary - disabled if repair is NoRepair
195
+ off = self.repair(problem, off, **kwargs)
196
+
197
+ # advance the parameter control by attaching them to the offsprings
198
+ control.advance(off)
199
+
200
+ return off
201
+
202
+
203
+ # =========================================================================================================
204
+ # Implementation
205
+ # =========================================================================================================
206
+
207
+
208
+ class DE(GeneticAlgorithm):
209
+
210
+ def __init__(self,
211
+ pop_size=100,
212
+ n_offsprings=None,
213
+ sampling=FloatRandomSampling(),
214
+ variant="DE/best/1/bin",
215
+ output=SingleObjectiveOutput(),
216
+ **kwargs
217
+ ):
218
+
219
+ if variant is None:
220
+ if "control" not in kwargs:
221
+ kwargs["control"] = NoParameterControl
222
+ variant = Variant(**kwargs)
223
+
224
+ elif isinstance(variant, str):
225
+ try:
226
+ _, selection, n_diffs, crossover = variant.split("/")
227
+ if "control" not in kwargs:
228
+ kwargs["control"] = NoParameterControl
229
+ variant = Variant(selection=selection, n_diffs=int(n_diffs), crossover=crossover, **kwargs)
230
+ except:
231
+ raise Exception("Please provide a valid variant: DE/<selection>/<n_diffs>/<crossover>")
232
+
233
+ super().__init__(pop_size=pop_size,
234
+ n_offsprings=n_offsprings,
235
+ sampling=sampling,
236
+ mating=variant,
237
+ survival=None,
238
+ output=output,
239
+ eliminate_duplicates=False,
240
+ **kwargs)
241
+
242
+ self.termination = DefaultSingleObjectiveTermination()
243
+
244
+ def _initialize_advance(self, infills=None, **kwargs):
245
+ FitnessSurvival().do(self.problem, self.pop, return_indices=True)
246
+
247
+ def _infill(self):
248
+ infills = self.mating.do(self.problem, self.pop, self.n_offsprings, algorithm=self)
249
+
250
+ # tag each individual with an index - if a steady state version is executed
251
+ index = np.arange(len(infills))
252
+
253
+ # if number of offsprings is set lower than pop_size - randomly select
254
+ if self.n_offsprings < self.pop_size:
255
+ index = np.random.permutation(len(infills))[:self.n_offsprings]
256
+ infills = infills[index]
257
+
258
+ infills.set("index", index)
259
+
260
+ return infills
261
+
262
+ def _advance(self, infills=None, **kwargs):
263
+ assert infills is not None, "This algorithms uses the AskAndTell interface thus infills must to be provided."
264
+
265
+ # get the indices where each offspring is originating from
266
+ I = infills.get("index")
267
+
268
+ # replace the individuals with the corresponding parents from the mating
269
+ self.pop[I] = ImprovementReplacement().do(self.problem, self.pop[I], infills)
270
+
271
+ # update the information regarding the current population
272
+ FitnessSurvival().do(self.problem, self.pop, return_indices=True)
273
+
274
+ def _set_optimum(self, **kwargs):
275
+ k = self.pop.get("rank") == 0
276
+ self.opt = self.pop[k]
277
+
278
+
279
+ parse_doc_string(DE.__init__)
@@ -0,0 +1,149 @@
1
+ import numpy as np
2
+
3
+ from pymoo.algorithms.base.local import LocalSearch
4
+ from pymoo.algorithms.moo.nsga2 import RankAndCrowdingSurvival
5
+ from pymoo.core.individual import Individual
6
+ from pymoo.core.population import Population
7
+ from pymoo.util.display.single import SingleObjectiveOutput
8
+
9
+ from pymoo.util.nds.non_dominated_sorting import NonDominatedSorting
10
+ from pymoo.util.normalization import normalize, denormalize
11
+
12
+
13
+ def norm_bounds(pop, problem):
14
+ nxl = normalize(pop.get("xl"), problem.xl, problem.xu)
15
+ nxu = normalize(pop.get("xu"), problem.xl, problem.xu)
16
+ return nxl, nxu
17
+
18
+
19
+ def update_bounds(ind, xl, xu, k, delta):
20
+ _xl = np.copy(xl)
21
+ _xl[k] = ind.X[k] - delta
22
+ ind.set("xl", _xl)
23
+
24
+ _xu = np.copy(xu)
25
+ _xu[k] = ind.X[k] + delta
26
+ ind.set("xu", _xu)
27
+
28
+
29
+ class DIRECT(LocalSearch):
30
+
31
+ def __init__(self,
32
+ eps=1e-2,
33
+ penalty=0.1,
34
+ n_max_candidates=10,
35
+ n_max_archive=400,
36
+ archive_reduct=0.66,
37
+ output=SingleObjectiveOutput(),
38
+ **kwargs):
39
+ super().__init__(output=output, **kwargs)
40
+ self.eps = eps
41
+ self.penalty = penalty
42
+ self.n_max_candidates = n_max_candidates
43
+ self.n_max_archive = n_max_archive
44
+ self.archive_reduct = archive_reduct
45
+
46
+ def _setup(self, problem, **kwargs):
47
+
48
+ xl, xu = problem.bounds()
49
+ X = denormalize(0.5 * np.ones(problem.n_var), xl, xu)
50
+
51
+ x0 = Individual(X=X)
52
+ x0.set("xl", xl)
53
+ x0.set("xu", xu)
54
+ x0.set("depth", 0)
55
+
56
+ self.x0 = x0
57
+
58
+ def _initialize_infill(self, **kwargs):
59
+ return Population.create(self.x0)
60
+
61
+ def _potential_optimal(self):
62
+ pop = self.pop
63
+
64
+ if len(pop) == 1:
65
+ return pop
66
+
67
+ # get the intervals of each individual
68
+ _F, _CV, xl, xu = pop.get("F", "CV", "xl", "xu")
69
+ nF = normalize(_F)
70
+ F = nF + self.penalty * _CV
71
+
72
+ # get the length of the interval of each solution
73
+ nxl, nxu = norm_bounds(pop, self.problem)
74
+ length = (nxu - nxl) / 2
75
+ val = length.mean(axis=1)
76
+
77
+ # (a) non-dominated set with respect to interval
78
+ obj = np.column_stack([-val, F])
79
+
80
+ # an unlimited archive size can cause issues - thus truncate if necessary
81
+ if len(pop) > self.n_max_archive:
82
+ # find the rank of each individual
83
+ _, rank = NonDominatedSorting().do(obj, return_rank=True)
84
+
85
+ # calculate the number of solutions after truncation and filter the best ones out
86
+ n_truncated = int(self.archive_reduct * self.n_max_archive)
87
+ I = np.argsort(rank)[:n_truncated]
88
+
89
+ # also update all the utility variables defined so far to match the truncation
90
+ pop, F, nxl, nxu, length, val, obj = pop[I], F[I], nxl[I], nxu[I], length[I], val[I], obj[I]
91
+ self.pop = pop
92
+
93
+ I = NonDominatedSorting().do(obj, only_non_dominated_front=True)
94
+ candidates, F, xl, xu, val = pop[I], F[I], xl[I], xu[I], val[I]
95
+
96
+ # if all candidates are expanded in each iteration this can cause issues - here use crowding distance to decide
97
+ if len(candidates) == 1:
98
+ return candidates
99
+ else:
100
+ if len(candidates) > self.n_max_candidates:
101
+ candidates = RankAndCrowdingSurvival().do(self.problem, pop, n_survive=self.n_max_candidates)
102
+
103
+ return candidates
104
+
105
+ def _infill(self):
106
+
107
+ # the offspring population to finally evaluate and attach to the population
108
+ infills = Population()
109
+
110
+ # find the potential optimal solution in the current population
111
+ potential_optimal = self._potential_optimal()
112
+
113
+ # for each of those solutions execute the division move
114
+ for current in potential_optimal:
115
+
116
+ # find the largest dimension the solution has not been evaluated yet
117
+ nxl, nxu = norm_bounds(current, self.problem)
118
+ k = np.argmax(nxu - nxl)
119
+
120
+ # the delta value to be used to get left and right - this is one sixth of the range
121
+ xl, xu = current.get("xl"), current.get("xu")
122
+
123
+ delta = (xu[k] - xl[k]) / 6
124
+
125
+ # create the left individual
126
+ left_x = np.copy(current.X)
127
+ left_x[k] = xl[k] + delta
128
+ left = Individual(X=left_x)
129
+
130
+ # create the right individual
131
+ right_x = np.copy(current.X)
132
+ right_x[k] = xu[k] - delta
133
+ right = Individual(X=right_x)
134
+
135
+ # update the boundaries for all the points accordingly
136
+ for ind in [current, left, right]:
137
+ update_bounds(ind, xl, xu, k, delta)
138
+
139
+ # create the offspring population, evaluate and attach to current population
140
+ _infill = Population.create(left, right)
141
+ _infill.set("depth", current.get("depth") + 1)
142
+
143
+ infills = Population.merge(infills, _infill)
144
+
145
+ return infills
146
+
147
+ def _advance(self, infills=None, **kwargs):
148
+ assert infills is not None, "This algorithms uses the AskAndTell interface thus infills must to be provided."
149
+ self.pop = Population.merge(self.pop, infills)
@@ -0,0 +1,203 @@
1
+ import numpy as np
2
+ import math
3
+
4
+ from pymoo.algorithms.base.genetic import GeneticAlgorithm
5
+ from pymoo.algorithms.soo.nonconvex.ga import FitnessSurvival
6
+ from pymoo.core.population import Population
7
+ from pymoo.docs import parse_doc_string
8
+ from pymoo.operators.sampling.rnd import FloatRandomSampling
9
+ from pymoo.termination.default import DefaultSingleObjectiveTermination
10
+ from pymoo.util.display.single import SingleObjectiveOutput
11
+ from pymoo.util.optimum import filter_optimum
12
+
13
+
14
+ class ES(GeneticAlgorithm):
15
+
16
+ def __init__(self,
17
+ n_offsprings=200,
18
+ pop_size=None,
19
+ rule=1.0 / 7.0,
20
+ phi=1.0,
21
+ gamma=0.85,
22
+ sampling=FloatRandomSampling(),
23
+ survival=FitnessSurvival(),
24
+ output=SingleObjectiveOutput(),
25
+ **kwargs):
26
+
27
+ """
28
+ Evolutionary Strategy (ES)
29
+
30
+ Parameters
31
+ ----------
32
+ n_offsprings : int
33
+ The number of individuals created in each iteration.
34
+ pop_size : int
35
+ The number of individuals which are surviving from the offspring population (non-elitist)
36
+ rule : float
37
+ The rule (ratio) of individuals surviving. This automatically either calculated `n_offsprings` or `pop_size`.
38
+ phi : float
39
+ Expected rate of convergence (usually 1.0).
40
+ gamma : float
41
+ If not `None`, some individuals are created using the differentials with this as a length scale.
42
+ sampling : object
43
+ The sampling method for creating the initial population.
44
+ """
45
+
46
+ if pop_size is None and n_offsprings is not None:
47
+ pop_size = int(math.ceil(n_offsprings * rule))
48
+ elif n_offsprings is None and pop_size is not None:
49
+ n_offsprings = int(math.floor(pop_size / rule))
50
+
51
+ assert pop_size is not None and n_offsprings is not None, "You have to at least provivde pop_size of n_offsprings."
52
+ assert n_offsprings >= 2 * pop_size, "The number of offsprings should be at least double the population size."
53
+
54
+ super().__init__(pop_size=pop_size,
55
+ n_offsprings=n_offsprings,
56
+ sampling=sampling,
57
+ survival=survival,
58
+ output=output,
59
+ advance_after_initial_infill=True,
60
+ **kwargs)
61
+
62
+ self.termination = DefaultSingleObjectiveTermination()
63
+ self.phi = phi
64
+ self.gamma = gamma
65
+
66
+ self.tau, self.taup, self.sigma_max = None, None, None
67
+
68
+ def _setup(self, problem, **kwargs):
69
+ n = problem.n_var
70
+ self.taup = self.phi / ((2 * n) ** 0.5)
71
+ self.tau = self.phi / ((2 * (n ** 0.5)) ** 0.5)
72
+
73
+ xl, xu = self.problem.bounds()
74
+ self.sigma_max = (xu - xl) / (self.problem.n_var ** 0.5)
75
+
76
+ def _initialize_advance(self, infills=None, **kwargs):
77
+ super()._initialize_advance(infills=infills, **kwargs)
78
+
79
+ # initialize all individuals with the maximum sigma value
80
+ infills.set("sigma", [self.sigma_max] * len(infills))
81
+
82
+ def _infill(self):
83
+ pop, mu, _lambda = self.pop, self.pop_size, self.n_offsprings
84
+ xl, xu = self.problem.bounds()
85
+ X, sigma = pop.get("X", "sigma")
86
+
87
+ # cycle through the elites individuals for create the solutions
88
+ I = np.arange(_lambda) % mu
89
+
90
+ # transform X and sigma to the shape of number of offsprings
91
+ X, sigma = X[I], sigma[I]
92
+
93
+ # get the sigma only of the elites to be used
94
+ sigmap = es_intermediate_recomb(sigma)
95
+
96
+ # calculate the new sigma based on tau and tau prime
97
+ sigmap = np.minimum(self.sigma_max, es_sigma(sigmap, self.tau, self.taup))
98
+
99
+ # execute the evolutionary strategy to calculate the offspring solutions
100
+ Xp = X + sigmap * np.random.normal(size=sigmap.shape)
101
+
102
+ # if gamma is not none do the differential variation overwrite Xp and sigmap for the first mu-1 individuals
103
+ if self.gamma is not None:
104
+ Xp[:mu - 1] = X[:mu - 1] + self.gamma * (X[0] - X[1:mu])
105
+ sigmap[:mu - 1] = sigma[:mu - 1]
106
+
107
+ # if we have bounds to consider -> repair the individuals which are out of bounds
108
+ if self.problem.has_bounds():
109
+ Xp = es_mut_repair(Xp, X, sigmap, xl, xu, 10)
110
+
111
+ # create the population to proceed further
112
+ off = Population.new(X=Xp, sigma=sigmap)
113
+
114
+ return off
115
+
116
+ def _advance(self, infills=None, **kwargs):
117
+
118
+ # if not all solutions suggested by infill() are evaluated we create a more semi (mu+lambda) algorithm
119
+ if len(infills) < self.pop_size:
120
+ infills = Population.merge(infills, self.pop)
121
+
122
+ self.pop = self.survival.do(self.problem, infills, n_survive=self.pop_size)
123
+
124
+ def _set_optimum(self):
125
+ pop = self.pop if self.opt is None else Population.merge(self.opt, self.pop)
126
+ self.opt = filter_optimum(pop, least_infeasible=True)
127
+
128
+
129
+ def es_sigma(sigma, tau, taup):
130
+ _lambda, _n = sigma.shape
131
+ return sigma * np.exp(taup * np.random.normal(size=(_lambda, 1)) + tau * np.random.normal(size=(_lambda, _n)))
132
+
133
+
134
+ def es_intermediate_recomb(sigma):
135
+ _lambda, _n = sigma.shape
136
+ sigma_hat = np.zeros_like(sigma)
137
+
138
+ for i in range(_lambda):
139
+ for j in range(_n):
140
+ k = np.random.randint(_lambda)
141
+ sigma_hat[i, j] = (sigma[i, j] + sigma[k, j]) / 2.0
142
+
143
+ return sigma_hat
144
+
145
+
146
+ def es_mut_repair(Xp, X, sigma, xl, xu, n_trials):
147
+ # reshape xl and xu to be the same shape as the input
148
+ XL = xl[None, :].repeat(len(Xp), axis=0)
149
+ XU = xu[None, :].repeat(len(Xp), axis=0)
150
+
151
+ all_in_bounds = False
152
+
153
+ # for the given number of trials
154
+ for k in range(n_trials):
155
+
156
+ # find all indices which are out of bounds
157
+ i, j = np.where(np.logical_or(Xp < XL, Xp > XU))
158
+
159
+ if len(i) == 0:
160
+ all_in_bounds = True
161
+ break
162
+ else:
163
+ # do the mutation again vectored for all values not in bound
164
+ Xp[i, j] = X[i, j] + sigma[i, j] * np.random.normal(size=len(i))
165
+
166
+ # if there are still solutions which boundaries are violated, set them to the original X
167
+ if not all_in_bounds:
168
+ i, j = np.where(np.logical_or(Xp < XL, Xp > XU))
169
+ Xp[i, j] = X[i, j]
170
+
171
+ return Xp
172
+
173
+
174
+ def es_mut_loop(X, sigmap, xl, xu, n_trials=10):
175
+ _lambda, _n = sigmap.shape
176
+
177
+ # X prime which will be returned by the algorithm (set the default value to the same as parent)
178
+ Xp = np.zeros_like(sigmap)
179
+
180
+ # for each of the new offsprings
181
+ for i in range(_lambda):
182
+
183
+ # for each variable of it
184
+ for j in range(_n):
185
+
186
+ # by default just copy the value if no value is in bounds this will stay
187
+ Xp[i, j] = X[i, j]
188
+
189
+ # try to set the value a few time and be done if in bounds
190
+ for _ in range(n_trials):
191
+
192
+ # calculate the mutated value
193
+ x = X[i, j] + sigmap[i, j] * np.random.normal()
194
+
195
+ # if it is inside the bounds accept it - otherwise try again
196
+ if xl[j] <= x <= xu[j]:
197
+ Xp[i, j] = x
198
+ break
199
+
200
+ return Xp
201
+
202
+
203
+ parse_doc_string(ES.__init__)