pymoo 0.6.1.2__cp39-cp39-macosx_10_9_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.

Potentially problematic release.


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

Files changed (316) 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 +304 -0
  12. pymoo/algorithms/moo/age2.py +164 -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 +117 -0
  18. pymoo/algorithms/moo/nsga3.py +358 -0
  19. pymoo/algorithms/moo/rnsga2.py +188 -0
  20. pymoo/algorithms/moo/rnsga3.py +246 -0
  21. pymoo/algorithms/moo/rvea.py +214 -0
  22. pymoo/algorithms/moo/sms.py +195 -0
  23. pymoo/algorithms/moo/spea2.py +190 -0
  24. pymoo/algorithms/moo/unsga3.py +47 -0
  25. pymoo/algorithms/soo/__init__.py +0 -0
  26. pymoo/algorithms/soo/convex/__init__.py +0 -0
  27. pymoo/algorithms/soo/nonconvex/__init__.py +0 -0
  28. pymoo/algorithms/soo/nonconvex/brkga.py +161 -0
  29. pymoo/algorithms/soo/nonconvex/cmaes.py +554 -0
  30. pymoo/algorithms/soo/nonconvex/de.py +279 -0
  31. pymoo/algorithms/soo/nonconvex/direct.py +149 -0
  32. pymoo/algorithms/soo/nonconvex/es.py +202 -0
  33. pymoo/algorithms/soo/nonconvex/g3pcx.py +94 -0
  34. pymoo/algorithms/soo/nonconvex/ga.py +93 -0
  35. pymoo/algorithms/soo/nonconvex/ga_niching.py +223 -0
  36. pymoo/algorithms/soo/nonconvex/isres.py +74 -0
  37. pymoo/algorithms/soo/nonconvex/nelder.py +251 -0
  38. pymoo/algorithms/soo/nonconvex/optuna.py +80 -0
  39. pymoo/algorithms/soo/nonconvex/pattern.py +183 -0
  40. pymoo/algorithms/soo/nonconvex/pso.py +399 -0
  41. pymoo/algorithms/soo/nonconvex/pso_ep.py +297 -0
  42. pymoo/algorithms/soo/nonconvex/random_search.py +25 -0
  43. pymoo/algorithms/soo/nonconvex/sres.py +56 -0
  44. pymoo/algorithms/soo/univariate/__init__.py +0 -0
  45. pymoo/algorithms/soo/univariate/backtracking.py +59 -0
  46. pymoo/algorithms/soo/univariate/exp.py +46 -0
  47. pymoo/algorithms/soo/univariate/golden.py +65 -0
  48. pymoo/algorithms/soo/univariate/quadr_interp.py +81 -0
  49. pymoo/algorithms/soo/univariate/wolfe.py +163 -0
  50. pymoo/config.py +33 -0
  51. pymoo/constraints/__init__.py +3 -0
  52. pymoo/constraints/adaptive.py +62 -0
  53. pymoo/constraints/as_obj.py +56 -0
  54. pymoo/constraints/as_penalty.py +41 -0
  55. pymoo/constraints/eps.py +26 -0
  56. pymoo/constraints/from_bounds.py +36 -0
  57. pymoo/core/__init__.py +0 -0
  58. pymoo/core/algorithm.py +394 -0
  59. pymoo/core/callback.py +38 -0
  60. pymoo/core/crossover.py +77 -0
  61. pymoo/core/decision_making.py +102 -0
  62. pymoo/core/decomposition.py +76 -0
  63. pymoo/core/duplicate.py +163 -0
  64. pymoo/core/evaluator.py +116 -0
  65. pymoo/core/indicator.py +34 -0
  66. pymoo/core/individual.py +783 -0
  67. pymoo/core/infill.py +64 -0
  68. pymoo/core/initialization.py +42 -0
  69. pymoo/core/mating.py +39 -0
  70. pymoo/core/meta.py +21 -0
  71. pymoo/core/mixed.py +165 -0
  72. pymoo/core/mutation.py +44 -0
  73. pymoo/core/operator.py +40 -0
  74. pymoo/core/parameters.py +134 -0
  75. pymoo/core/plot.py +210 -0
  76. pymoo/core/population.py +180 -0
  77. pymoo/core/problem.py +460 -0
  78. pymoo/core/recorder.py +99 -0
  79. pymoo/core/repair.py +23 -0
  80. pymoo/core/replacement.py +96 -0
  81. pymoo/core/result.py +52 -0
  82. pymoo/core/sampling.py +43 -0
  83. pymoo/core/selection.py +61 -0
  84. pymoo/core/solution.py +10 -0
  85. pymoo/core/survival.py +103 -0
  86. pymoo/core/termination.py +70 -0
  87. pymoo/core/variable.py +399 -0
  88. pymoo/cython/__init__.py +0 -0
  89. pymoo/cython/calc_perpendicular_distance.cpython-39-darwin.so +0 -0
  90. pymoo/cython/decomposition.cpython-39-darwin.so +0 -0
  91. pymoo/cython/hv.cpython-39-darwin.so +0 -0
  92. pymoo/cython/info.cpython-39-darwin.so +0 -0
  93. pymoo/cython/mnn.cpython-39-darwin.so +0 -0
  94. pymoo/cython/non_dominated_sorting.cpython-39-darwin.so +0 -0
  95. pymoo/cython/pruning_cd.cpython-39-darwin.so +0 -0
  96. pymoo/cython/stochastic_ranking.cpython-39-darwin.so +0 -0
  97. pymoo/cython/utils.pxd +129 -0
  98. pymoo/cython/vendor/__init__.py +0 -0
  99. pymoo/cython/vendor/hypervolume.h +63 -0
  100. pymoo/decomposition/__init__.py +0 -0
  101. pymoo/decomposition/aasf.py +24 -0
  102. pymoo/decomposition/asf.py +10 -0
  103. pymoo/decomposition/pbi.py +13 -0
  104. pymoo/decomposition/perp_dist.py +13 -0
  105. pymoo/decomposition/tchebicheff.py +11 -0
  106. pymoo/decomposition/util.py +13 -0
  107. pymoo/decomposition/weighted_sum.py +8 -0
  108. pymoo/docs.py +187 -0
  109. pymoo/experimental/__init__.py +0 -0
  110. pymoo/experimental/algorithms/__init__.py +0 -0
  111. pymoo/experimental/algorithms/gde3.py +57 -0
  112. pymoo/gradient/__init__.py +21 -0
  113. pymoo/gradient/automatic.py +57 -0
  114. pymoo/gradient/grad_autograd.py +105 -0
  115. pymoo/gradient/grad_complex.py +35 -0
  116. pymoo/gradient/grad_jax.py +51 -0
  117. pymoo/gradient/toolbox/__init__.py +6 -0
  118. pymoo/indicators/__init__.py +0 -0
  119. pymoo/indicators/distance_indicator.py +55 -0
  120. pymoo/indicators/gd.py +7 -0
  121. pymoo/indicators/gd_plus.py +7 -0
  122. pymoo/indicators/hv/__init__.py +63 -0
  123. pymoo/indicators/hv/exact.py +71 -0
  124. pymoo/indicators/hv/exact_2d.py +102 -0
  125. pymoo/indicators/hv/monte_carlo.py +74 -0
  126. pymoo/indicators/igd.py +7 -0
  127. pymoo/indicators/igd_plus.py +7 -0
  128. pymoo/indicators/kktpm.py +151 -0
  129. pymoo/indicators/migd.py +55 -0
  130. pymoo/indicators/rmetric.py +203 -0
  131. pymoo/indicators/spacing.py +52 -0
  132. pymoo/mcdm/__init__.py +0 -0
  133. pymoo/mcdm/compromise_programming.py +19 -0
  134. pymoo/mcdm/high_tradeoff.py +40 -0
  135. pymoo/mcdm/pseudo_weights.py +32 -0
  136. pymoo/operators/__init__.py +0 -0
  137. pymoo/operators/control.py +187 -0
  138. pymoo/operators/crossover/__init__.py +0 -0
  139. pymoo/operators/crossover/binx.py +45 -0
  140. pymoo/operators/crossover/dex.py +122 -0
  141. pymoo/operators/crossover/erx.py +162 -0
  142. pymoo/operators/crossover/expx.py +51 -0
  143. pymoo/operators/crossover/hux.py +37 -0
  144. pymoo/operators/crossover/nox.py +13 -0
  145. pymoo/operators/crossover/ox.py +84 -0
  146. pymoo/operators/crossover/pcx.py +82 -0
  147. pymoo/operators/crossover/pntx.py +49 -0
  148. pymoo/operators/crossover/sbx.py +125 -0
  149. pymoo/operators/crossover/spx.py +5 -0
  150. pymoo/operators/crossover/ux.py +20 -0
  151. pymoo/operators/mutation/__init__.py +0 -0
  152. pymoo/operators/mutation/bitflip.py +17 -0
  153. pymoo/operators/mutation/gauss.py +58 -0
  154. pymoo/operators/mutation/inversion.py +42 -0
  155. pymoo/operators/mutation/nom.py +7 -0
  156. pymoo/operators/mutation/pm.py +94 -0
  157. pymoo/operators/mutation/rm.py +23 -0
  158. pymoo/operators/repair/__init__.py +0 -0
  159. pymoo/operators/repair/bounce_back.py +32 -0
  160. pymoo/operators/repair/bounds_repair.py +95 -0
  161. pymoo/operators/repair/inverse_penalty.py +89 -0
  162. pymoo/operators/repair/rounding.py +18 -0
  163. pymoo/operators/repair/to_bound.py +31 -0
  164. pymoo/operators/repair/vtype.py +11 -0
  165. pymoo/operators/sampling/__init__.py +0 -0
  166. pymoo/operators/sampling/lhs.py +73 -0
  167. pymoo/operators/sampling/rnd.py +50 -0
  168. pymoo/operators/selection/__init__.py +0 -0
  169. pymoo/operators/selection/rnd.py +72 -0
  170. pymoo/operators/selection/tournament.py +76 -0
  171. pymoo/operators/survival/__init__.py +0 -0
  172. pymoo/operators/survival/rank_and_crowding/__init__.py +1 -0
  173. pymoo/operators/survival/rank_and_crowding/classes.py +209 -0
  174. pymoo/operators/survival/rank_and_crowding/metrics.py +208 -0
  175. pymoo/optimize.py +72 -0
  176. pymoo/problems/__init__.py +157 -0
  177. pymoo/problems/dyn.py +47 -0
  178. pymoo/problems/dynamic/__init__.py +0 -0
  179. pymoo/problems/dynamic/cec2015.py +108 -0
  180. pymoo/problems/dynamic/df.py +452 -0
  181. pymoo/problems/dynamic/misc.py +167 -0
  182. pymoo/problems/functional.py +48 -0
  183. pymoo/problems/many/__init__.py +5 -0
  184. pymoo/problems/many/cdtlz.py +159 -0
  185. pymoo/problems/many/dcdtlz.py +88 -0
  186. pymoo/problems/many/dtlz.py +264 -0
  187. pymoo/problems/many/wfg.py +550 -0
  188. pymoo/problems/multi/__init__.py +14 -0
  189. pymoo/problems/multi/bnh.py +34 -0
  190. pymoo/problems/multi/carside.py +48 -0
  191. pymoo/problems/multi/clutch.py +104 -0
  192. pymoo/problems/multi/csi.py +55 -0
  193. pymoo/problems/multi/ctp.py +198 -0
  194. pymoo/problems/multi/dascmop.py +213 -0
  195. pymoo/problems/multi/kursawe.py +25 -0
  196. pymoo/problems/multi/modact.py +68 -0
  197. pymoo/problems/multi/mw.py +400 -0
  198. pymoo/problems/multi/omnitest.py +48 -0
  199. pymoo/problems/multi/osy.py +32 -0
  200. pymoo/problems/multi/srn.py +28 -0
  201. pymoo/problems/multi/sympart.py +94 -0
  202. pymoo/problems/multi/tnk.py +24 -0
  203. pymoo/problems/multi/truss2d.py +83 -0
  204. pymoo/problems/multi/welded_beam.py +41 -0
  205. pymoo/problems/multi/wrm.py +36 -0
  206. pymoo/problems/multi/zdt.py +151 -0
  207. pymoo/problems/multi_to_single.py +22 -0
  208. pymoo/problems/single/__init__.py +12 -0
  209. pymoo/problems/single/ackley.py +24 -0
  210. pymoo/problems/single/cantilevered_beam.py +34 -0
  211. pymoo/problems/single/flowshop_scheduling.py +112 -0
  212. pymoo/problems/single/g.py +874 -0
  213. pymoo/problems/single/griewank.py +18 -0
  214. pymoo/problems/single/himmelblau.py +15 -0
  215. pymoo/problems/single/knapsack.py +48 -0
  216. pymoo/problems/single/mopta08.py +26 -0
  217. pymoo/problems/single/multimodal.py +20 -0
  218. pymoo/problems/single/pressure_vessel.py +30 -0
  219. pymoo/problems/single/rastrigin.py +20 -0
  220. pymoo/problems/single/rosenbrock.py +22 -0
  221. pymoo/problems/single/schwefel.py +18 -0
  222. pymoo/problems/single/simple.py +13 -0
  223. pymoo/problems/single/sphere.py +19 -0
  224. pymoo/problems/single/traveling_salesman.py +79 -0
  225. pymoo/problems/single/zakharov.py +19 -0
  226. pymoo/problems/static.py +14 -0
  227. pymoo/problems/util.py +42 -0
  228. pymoo/problems/zero_to_one.py +27 -0
  229. pymoo/termination/__init__.py +23 -0
  230. pymoo/termination/collection.py +12 -0
  231. pymoo/termination/cv.py +48 -0
  232. pymoo/termination/default.py +45 -0
  233. pymoo/termination/delta.py +64 -0
  234. pymoo/termination/fmin.py +16 -0
  235. pymoo/termination/ftol.py +144 -0
  236. pymoo/termination/indicator.py +49 -0
  237. pymoo/termination/max_eval.py +14 -0
  238. pymoo/termination/max_gen.py +15 -0
  239. pymoo/termination/max_time.py +20 -0
  240. pymoo/termination/robust.py +34 -0
  241. pymoo/termination/xtol.py +33 -0
  242. pymoo/util/__init__.py +0 -0
  243. pymoo/util/archive.py +150 -0
  244. pymoo/util/cache.py +29 -0
  245. pymoo/util/clearing.py +82 -0
  246. pymoo/util/display/__init__.py +0 -0
  247. pymoo/util/display/column.py +52 -0
  248. pymoo/util/display/display.py +34 -0
  249. pymoo/util/display/multi.py +96 -0
  250. pymoo/util/display/output.py +53 -0
  251. pymoo/util/display/progress.py +54 -0
  252. pymoo/util/display/single.py +67 -0
  253. pymoo/util/dominator.py +67 -0
  254. pymoo/util/function_loader.py +129 -0
  255. pymoo/util/hv.py +23 -0
  256. pymoo/util/matlab_engine.py +39 -0
  257. pymoo/util/misc.py +460 -0
  258. pymoo/util/mnn.py +70 -0
  259. pymoo/util/nds/__init__.py +0 -0
  260. pymoo/util/nds/dominance_degree_non_dominated_sort.py +159 -0
  261. pymoo/util/nds/efficient_non_dominated_sort.py +152 -0
  262. pymoo/util/nds/fast_non_dominated_sort.py +68 -0
  263. pymoo/util/nds/naive_non_dominated_sort.py +36 -0
  264. pymoo/util/nds/non_dominated_sorting.py +67 -0
  265. pymoo/util/nds/tree_based_non_dominated_sort.py +133 -0
  266. pymoo/util/normalization.py +315 -0
  267. pymoo/util/optimum.py +42 -0
  268. pymoo/util/plotting.py +177 -0
  269. pymoo/util/pruning_cd.py +89 -0
  270. pymoo/util/randomized_argsort.py +60 -0
  271. pymoo/util/ref_dirs/__init__.py +24 -0
  272. pymoo/util/ref_dirs/construction.py +88 -0
  273. pymoo/util/ref_dirs/das_dennis.py +52 -0
  274. pymoo/util/ref_dirs/energy.py +317 -0
  275. pymoo/util/ref_dirs/energy_layer.py +119 -0
  276. pymoo/util/ref_dirs/genetic_algorithm.py +63 -0
  277. pymoo/util/ref_dirs/incremental.py +68 -0
  278. pymoo/util/ref_dirs/misc.py +128 -0
  279. pymoo/util/ref_dirs/optimizer.py +59 -0
  280. pymoo/util/ref_dirs/performance.py +162 -0
  281. pymoo/util/ref_dirs/reduction.py +85 -0
  282. pymoo/util/ref_dirs/sample_and_map.py +24 -0
  283. pymoo/util/reference_direction.py +259 -0
  284. pymoo/util/remote.py +55 -0
  285. pymoo/util/roulette.py +27 -0
  286. pymoo/util/running_metric.py +128 -0
  287. pymoo/util/sliding_window.py +25 -0
  288. pymoo/util/stochastic_ranking.py +32 -0
  289. pymoo/util/vectors.py +40 -0
  290. pymoo/vendor/__init__.py +0 -0
  291. pymoo/vendor/cec2018.py +398 -0
  292. pymoo/vendor/gta.py +617 -0
  293. pymoo/vendor/hv.py +267 -0
  294. pymoo/vendor/vendor_cmaes.py +412 -0
  295. pymoo/vendor/vendor_coco.py +81 -0
  296. pymoo/vendor/vendor_scipy.py +232 -0
  297. pymoo/version.py +1 -0
  298. pymoo/visualization/__init__.py +8 -0
  299. pymoo/visualization/fitness_landscape.py +127 -0
  300. pymoo/visualization/heatmap.py +123 -0
  301. pymoo/visualization/pcp.py +120 -0
  302. pymoo/visualization/petal.py +91 -0
  303. pymoo/visualization/radar.py +108 -0
  304. pymoo/visualization/radviz.py +68 -0
  305. pymoo/visualization/scatter.py +150 -0
  306. pymoo/visualization/star_coordinate.py +75 -0
  307. pymoo/visualization/util.py +123 -0
  308. pymoo/visualization/video/__init__.py +0 -0
  309. pymoo/visualization/video/callback_video.py +82 -0
  310. pymoo/visualization/video/one_var_one_obj.py +57 -0
  311. pymoo/visualization/video/two_var_one_obj.py +62 -0
  312. pymoo-0.6.1.2.dist-info/LICENSE +191 -0
  313. pymoo-0.6.1.2.dist-info/METADATA +190 -0
  314. pymoo-0.6.1.2.dist-info/RECORD +316 -0
  315. pymoo-0.6.1.2.dist-info/WHEEL +5 -0
  316. pymoo-0.6.1.2.dist-info/top_level.txt +1 -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,202 @@
1
+ import numpy as np
2
+
3
+ from pymoo.algorithms.base.genetic import GeneticAlgorithm
4
+ from pymoo.algorithms.soo.nonconvex.ga import FitnessSurvival
5
+ from pymoo.core.population import Population
6
+ from pymoo.docs import parse_doc_string
7
+ from pymoo.operators.sampling.rnd import FloatRandomSampling
8
+ from pymoo.termination.default import DefaultSingleObjectiveTermination
9
+ from pymoo.util.display.single import SingleObjectiveOutput
10
+ from pymoo.util.optimum import filter_optimum
11
+
12
+
13
+ class ES(GeneticAlgorithm):
14
+
15
+ def __init__(self,
16
+ n_offsprings=200,
17
+ pop_size=None,
18
+ rule=1.0 / 7.0,
19
+ phi=1.0,
20
+ gamma=0.85,
21
+ sampling=FloatRandomSampling(),
22
+ survival=FitnessSurvival(),
23
+ output=SingleObjectiveOutput(),
24
+ **kwargs):
25
+
26
+ """
27
+ Evolutionary Strategy (ES)
28
+
29
+ Parameters
30
+ ----------
31
+ n_offsprings : int
32
+ The number of individuals created in each iteration.
33
+ pop_size : int
34
+ The number of individuals which are surviving from the offspring population (non-elitist)
35
+ rule : float
36
+ The rule (ratio) of individuals surviving. This automatically either calculated `n_offsprings` or `pop_size`.
37
+ phi : float
38
+ Expected rate of convergence (usually 1.0).
39
+ gamma : float
40
+ If not `None`, some individuals are created using the differentials with this as a length scale.
41
+ sampling : object
42
+ The sampling method for creating the initial population.
43
+ """
44
+
45
+ if pop_size is None and n_offsprings is not None:
46
+ pop_size = int(np.math.ceil(n_offsprings * rule))
47
+ elif n_offsprings is None and pop_size is not None:
48
+ n_offsprings = int(np.math.floor(pop_size / rule))
49
+
50
+ assert pop_size is not None and n_offsprings is not None, "You have to at least provivde pop_size of n_offsprings."
51
+ assert n_offsprings >= 2 * pop_size, "The number of offsprings should be at least double the population size."
52
+
53
+ super().__init__(pop_size=pop_size,
54
+ n_offsprings=n_offsprings,
55
+ sampling=sampling,
56
+ survival=survival,
57
+ output=output,
58
+ advance_after_initial_infill=True,
59
+ **kwargs)
60
+
61
+ self.termination = DefaultSingleObjectiveTermination()
62
+ self.phi = phi
63
+ self.gamma = gamma
64
+
65
+ self.tau, self.taup, self.sigma_max = None, None, None
66
+
67
+ def _setup(self, problem, **kwargs):
68
+ n = problem.n_var
69
+ self.taup = self.phi / ((2 * n) ** 0.5)
70
+ self.tau = self.phi / ((2 * (n ** 0.5)) ** 0.5)
71
+
72
+ xl, xu = self.problem.bounds()
73
+ self.sigma_max = (xu - xl) / (self.problem.n_var ** 0.5)
74
+
75
+ def _initialize_advance(self, infills=None, **kwargs):
76
+ super()._initialize_advance(infills=infills, **kwargs)
77
+
78
+ # initialize all individuals with the maximum sigma value
79
+ infills.set("sigma", [self.sigma_max] * len(infills))
80
+
81
+ def _infill(self):
82
+ pop, mu, _lambda = self.pop, self.pop_size, self.n_offsprings
83
+ xl, xu = self.problem.bounds()
84
+ X, sigma = pop.get("X", "sigma")
85
+
86
+ # cycle through the elites individuals for create the solutions
87
+ I = np.arange(_lambda) % mu
88
+
89
+ # transform X and sigma to the shape of number of offsprings
90
+ X, sigma = X[I], sigma[I]
91
+
92
+ # get the sigma only of the elites to be used
93
+ sigmap = es_intermediate_recomb(sigma)
94
+
95
+ # calculate the new sigma based on tau and tau prime
96
+ sigmap = np.minimum(self.sigma_max, es_sigma(sigmap, self.tau, self.taup))
97
+
98
+ # execute the evolutionary strategy to calculate the offspring solutions
99
+ Xp = X + sigmap * np.random.normal(size=sigmap.shape)
100
+
101
+ # if gamma is not none do the differential variation overwrite Xp and sigmap for the first mu-1 individuals
102
+ if self.gamma is not None:
103
+ Xp[:mu - 1] = X[:mu - 1] + self.gamma * (X[0] - X[1:mu])
104
+ sigmap[:mu - 1] = sigma[:mu - 1]
105
+
106
+ # if we have bounds to consider -> repair the individuals which are out of bounds
107
+ if self.problem.has_bounds():
108
+ Xp = es_mut_repair(Xp, X, sigmap, xl, xu, 10)
109
+
110
+ # create the population to proceed further
111
+ off = Population.new(X=Xp, sigma=sigmap)
112
+
113
+ return off
114
+
115
+ def _advance(self, infills=None, **kwargs):
116
+
117
+ # if not all solutions suggested by infill() are evaluated we create a more semi (mu+lambda) algorithm
118
+ if len(infills) < self.pop_size:
119
+ infills = Population.merge(infills, self.pop)
120
+
121
+ self.pop = self.survival.do(self.problem, infills, n_survive=self.pop_size)
122
+
123
+ def _set_optimum(self):
124
+ pop = self.pop if self.opt is None else Population.merge(self.opt, self.pop)
125
+ self.opt = filter_optimum(pop, least_infeasible=True)
126
+
127
+
128
+ def es_sigma(sigma, tau, taup):
129
+ _lambda, _n = sigma.shape
130
+ return sigma * np.exp(taup * np.random.normal(size=(_lambda, 1)) + tau * np.random.normal(size=(_lambda, _n)))
131
+
132
+
133
+ def es_intermediate_recomb(sigma):
134
+ _lambda, _n = sigma.shape
135
+ sigma_hat = np.zeros_like(sigma)
136
+
137
+ for i in range(_lambda):
138
+ for j in range(_n):
139
+ k = np.random.randint(_lambda)
140
+ sigma_hat[i, j] = (sigma[i, j] + sigma[k, j]) / 2.0
141
+
142
+ return sigma_hat
143
+
144
+
145
+ def es_mut_repair(Xp, X, sigma, xl, xu, n_trials):
146
+ # reshape xl and xu to be the same shape as the input
147
+ XL = xl[None, :].repeat(len(Xp), axis=0)
148
+ XU = xu[None, :].repeat(len(Xp), axis=0)
149
+
150
+ all_in_bounds = False
151
+
152
+ # for the given number of trials
153
+ for k in range(n_trials):
154
+
155
+ # find all indices which are out of bounds
156
+ i, j = np.where(np.logical_or(Xp < XL, Xp > XU))
157
+
158
+ if len(i) == 0:
159
+ all_in_bounds = True
160
+ break
161
+ else:
162
+ # do the mutation again vectored for all values not in bound
163
+ Xp[i, j] = X[i, j] + sigma[i, j] * np.random.normal(size=len(i))
164
+
165
+ # if there are still solutions which boundaries are violated, set them to the original X
166
+ if not all_in_bounds:
167
+ i, j = np.where(np.logical_or(Xp < XL, Xp > XU))
168
+ Xp[i, j] = X[i, j]
169
+
170
+ return Xp
171
+
172
+
173
+ def es_mut_loop(X, sigmap, xl, xu, n_trials=10):
174
+ _lambda, _n = sigmap.shape
175
+
176
+ # X prime which will be returned by the algorithm (set the default value to the same as parent)
177
+ Xp = np.zeros_like(sigmap)
178
+
179
+ # for each of the new offsprings
180
+ for i in range(_lambda):
181
+
182
+ # for each variable of it
183
+ for j in range(_n):
184
+
185
+ # by default just copy the value if no value is in bounds this will stay
186
+ Xp[i, j] = X[i, j]
187
+
188
+ # try to set the value a few time and be done if in bounds
189
+ for _ in range(n_trials):
190
+
191
+ # calculate the mutated value
192
+ x = X[i, j] + sigmap[i, j] * np.random.normal()
193
+
194
+ # if it is inside the bounds accept it - otherwise try again
195
+ if xl[j] <= x <= xu[j]:
196
+ Xp[i, j] = x
197
+ break
198
+
199
+ return Xp
200
+
201
+
202
+ parse_doc_string(ES.__init__)