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