pymoo 0.6.1.5.dev0__cp310-cp310-macosx_11_0_arm64.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.
- pymoo/__init__.py +3 -0
- pymoo/algorithms/__init__.py +0 -0
- pymoo/algorithms/base/__init__.py +0 -0
- pymoo/algorithms/base/bracket.py +38 -0
- pymoo/algorithms/base/genetic.py +109 -0
- pymoo/algorithms/base/line.py +62 -0
- pymoo/algorithms/base/local.py +39 -0
- pymoo/algorithms/base/meta.py +79 -0
- pymoo/algorithms/hyperparameters.py +89 -0
- pymoo/algorithms/moo/__init__.py +0 -0
- pymoo/algorithms/moo/age.py +310 -0
- pymoo/algorithms/moo/age2.py +194 -0
- pymoo/algorithms/moo/ctaea.py +298 -0
- pymoo/algorithms/moo/dnsga2.py +76 -0
- pymoo/algorithms/moo/kgb.py +446 -0
- pymoo/algorithms/moo/moead.py +183 -0
- pymoo/algorithms/moo/nsga2.py +113 -0
- pymoo/algorithms/moo/nsga3.py +358 -0
- pymoo/algorithms/moo/pinsga2.py +370 -0
- pymoo/algorithms/moo/rnsga2.py +188 -0
- pymoo/algorithms/moo/rnsga3.py +246 -0
- pymoo/algorithms/moo/rvea.py +214 -0
- pymoo/algorithms/moo/sms.py +195 -0
- pymoo/algorithms/moo/spea2.py +190 -0
- pymoo/algorithms/moo/unsga3.py +47 -0
- pymoo/algorithms/soo/__init__.py +0 -0
- pymoo/algorithms/soo/convex/__init__.py +0 -0
- pymoo/algorithms/soo/nonconvex/__init__.py +0 -0
- pymoo/algorithms/soo/nonconvex/brkga.py +161 -0
- pymoo/algorithms/soo/nonconvex/cmaes.py +554 -0
- pymoo/algorithms/soo/nonconvex/de.py +279 -0
- pymoo/algorithms/soo/nonconvex/direct.py +149 -0
- pymoo/algorithms/soo/nonconvex/es.py +203 -0
- pymoo/algorithms/soo/nonconvex/g3pcx.py +94 -0
- pymoo/algorithms/soo/nonconvex/ga.py +93 -0
- pymoo/algorithms/soo/nonconvex/ga_niching.py +223 -0
- pymoo/algorithms/soo/nonconvex/isres.py +74 -0
- pymoo/algorithms/soo/nonconvex/nelder.py +251 -0
- pymoo/algorithms/soo/nonconvex/optuna.py +80 -0
- pymoo/algorithms/soo/nonconvex/pattern.py +183 -0
- pymoo/algorithms/soo/nonconvex/pso.py +399 -0
- pymoo/algorithms/soo/nonconvex/pso_ep.py +297 -0
- pymoo/algorithms/soo/nonconvex/random_search.py +25 -0
- pymoo/algorithms/soo/nonconvex/sres.py +56 -0
- pymoo/algorithms/soo/univariate/__init__.py +0 -0
- pymoo/algorithms/soo/univariate/backtracking.py +59 -0
- pymoo/algorithms/soo/univariate/exp.py +46 -0
- pymoo/algorithms/soo/univariate/golden.py +65 -0
- pymoo/algorithms/soo/univariate/quadr_interp.py +81 -0
- pymoo/algorithms/soo/univariate/wolfe.py +163 -0
- pymoo/config.py +33 -0
- pymoo/constraints/__init__.py +3 -0
- pymoo/constraints/adaptive.py +62 -0
- pymoo/constraints/as_obj.py +56 -0
- pymoo/constraints/as_penalty.py +41 -0
- pymoo/constraints/eps.py +26 -0
- pymoo/constraints/from_bounds.py +36 -0
- pymoo/core/__init__.py +0 -0
- pymoo/core/algorithm.py +394 -0
- pymoo/core/callback.py +38 -0
- pymoo/core/crossover.py +77 -0
- pymoo/core/decision_making.py +102 -0
- pymoo/core/decomposition.py +76 -0
- pymoo/core/duplicate.py +163 -0
- pymoo/core/evaluator.py +116 -0
- pymoo/core/indicator.py +34 -0
- pymoo/core/individual.py +784 -0
- pymoo/core/infill.py +64 -0
- pymoo/core/initialization.py +42 -0
- pymoo/core/mating.py +39 -0
- pymoo/core/meta.py +21 -0
- pymoo/core/mixed.py +165 -0
- pymoo/core/mutation.py +44 -0
- pymoo/core/operator.py +40 -0
- pymoo/core/parameters.py +134 -0
- pymoo/core/plot.py +210 -0
- pymoo/core/population.py +180 -0
- pymoo/core/problem.py +460 -0
- pymoo/core/recorder.py +99 -0
- pymoo/core/repair.py +23 -0
- pymoo/core/replacement.py +96 -0
- pymoo/core/result.py +52 -0
- pymoo/core/sampling.py +43 -0
- pymoo/core/selection.py +61 -0
- pymoo/core/solution.py +10 -0
- pymoo/core/survival.py +103 -0
- pymoo/core/termination.py +70 -0
- pymoo/core/variable.py +399 -0
- pymoo/cython/__init__.py +0 -0
- pymoo/cython/calc_perpendicular_distance.cpython-310-darwin.so +0 -0
- pymoo/cython/calc_perpendicular_distance.pyx +67 -0
- pymoo/cython/decomposition.cpython-310-darwin.so +0 -0
- pymoo/cython/decomposition.pyx +165 -0
- pymoo/cython/hv.cpython-310-darwin.so +0 -0
- pymoo/cython/hv.pyx +18 -0
- pymoo/cython/info.cpython-310-darwin.so +0 -0
- pymoo/cython/info.pyx +5 -0
- pymoo/cython/mnn.cpython-310-darwin.so +0 -0
- pymoo/cython/mnn.pyx +273 -0
- pymoo/cython/non_dominated_sorting.cpython-310-darwin.so +0 -0
- pymoo/cython/non_dominated_sorting.pyx +645 -0
- pymoo/cython/pruning_cd.cpython-310-darwin.so +0 -0
- pymoo/cython/pruning_cd.pyx +197 -0
- pymoo/cython/stochastic_ranking.cpython-310-darwin.so +0 -0
- pymoo/cython/stochastic_ranking.pyx +49 -0
- pymoo/cython/utils.pxd +129 -0
- pymoo/cython/vendor/__init__.py +0 -0
- pymoo/cython/vendor/hypervolume.cpp +1621 -0
- pymoo/cython/vendor/hypervolume.h +63 -0
- pymoo/decomposition/__init__.py +0 -0
- pymoo/decomposition/aasf.py +24 -0
- pymoo/decomposition/asf.py +10 -0
- pymoo/decomposition/pbi.py +13 -0
- pymoo/decomposition/perp_dist.py +13 -0
- pymoo/decomposition/tchebicheff.py +11 -0
- pymoo/decomposition/util.py +13 -0
- pymoo/decomposition/weighted_sum.py +8 -0
- pymoo/docs.py +187 -0
- pymoo/experimental/__init__.py +0 -0
- pymoo/experimental/algorithms/__init__.py +0 -0
- pymoo/experimental/algorithms/gde3.py +57 -0
- pymoo/gradient/__init__.py +21 -0
- pymoo/gradient/automatic.py +57 -0
- pymoo/gradient/grad_autograd.py +105 -0
- pymoo/gradient/grad_complex.py +35 -0
- pymoo/gradient/grad_jax.py +51 -0
- pymoo/gradient/toolbox/__init__.py +6 -0
- pymoo/indicators/__init__.py +0 -0
- pymoo/indicators/distance_indicator.py +55 -0
- pymoo/indicators/gd.py +7 -0
- pymoo/indicators/gd_plus.py +7 -0
- pymoo/indicators/hv/__init__.py +63 -0
- pymoo/indicators/hv/exact.py +71 -0
- pymoo/indicators/hv/exact_2d.py +102 -0
- pymoo/indicators/hv/monte_carlo.py +74 -0
- pymoo/indicators/igd.py +7 -0
- pymoo/indicators/igd_plus.py +7 -0
- pymoo/indicators/kktpm.py +151 -0
- pymoo/indicators/migd.py +55 -0
- pymoo/indicators/rmetric.py +203 -0
- pymoo/indicators/spacing.py +52 -0
- pymoo/mcdm/__init__.py +0 -0
- pymoo/mcdm/compromise_programming.py +19 -0
- pymoo/mcdm/high_tradeoff.py +40 -0
- pymoo/mcdm/pseudo_weights.py +32 -0
- pymoo/operators/__init__.py +0 -0
- pymoo/operators/control.py +187 -0
- pymoo/operators/crossover/__init__.py +0 -0
- pymoo/operators/crossover/binx.py +45 -0
- pymoo/operators/crossover/dex.py +122 -0
- pymoo/operators/crossover/erx.py +162 -0
- pymoo/operators/crossover/expx.py +51 -0
- pymoo/operators/crossover/hux.py +37 -0
- pymoo/operators/crossover/nox.py +13 -0
- pymoo/operators/crossover/ox.py +84 -0
- pymoo/operators/crossover/pcx.py +82 -0
- pymoo/operators/crossover/pntx.py +49 -0
- pymoo/operators/crossover/sbx.py +125 -0
- pymoo/operators/crossover/spx.py +5 -0
- pymoo/operators/crossover/ux.py +20 -0
- pymoo/operators/mutation/__init__.py +0 -0
- pymoo/operators/mutation/bitflip.py +17 -0
- pymoo/operators/mutation/gauss.py +58 -0
- pymoo/operators/mutation/inversion.py +42 -0
- pymoo/operators/mutation/nom.py +7 -0
- pymoo/operators/mutation/pm.py +94 -0
- pymoo/operators/mutation/rm.py +23 -0
- pymoo/operators/repair/__init__.py +0 -0
- pymoo/operators/repair/bounce_back.py +32 -0
- pymoo/operators/repair/bounds_repair.py +95 -0
- pymoo/operators/repair/inverse_penalty.py +89 -0
- pymoo/operators/repair/rounding.py +18 -0
- pymoo/operators/repair/to_bound.py +31 -0
- pymoo/operators/repair/vtype.py +11 -0
- pymoo/operators/sampling/__init__.py +0 -0
- pymoo/operators/sampling/lhs.py +73 -0
- pymoo/operators/sampling/rnd.py +50 -0
- pymoo/operators/selection/__init__.py +0 -0
- pymoo/operators/selection/rnd.py +72 -0
- pymoo/operators/selection/tournament.py +76 -0
- pymoo/operators/survival/__init__.py +0 -0
- pymoo/operators/survival/rank_and_crowding/__init__.py +1 -0
- pymoo/operators/survival/rank_and_crowding/classes.py +209 -0
- pymoo/operators/survival/rank_and_crowding/metrics.py +208 -0
- pymoo/optimize.py +72 -0
- pymoo/problems/__init__.py +157 -0
- pymoo/problems/dyn.py +47 -0
- pymoo/problems/dynamic/__init__.py +0 -0
- pymoo/problems/dynamic/cec2015.py +108 -0
- pymoo/problems/dynamic/df.py +452 -0
- pymoo/problems/dynamic/misc.py +167 -0
- pymoo/problems/functional.py +48 -0
- pymoo/problems/many/__init__.py +5 -0
- pymoo/problems/many/cdtlz.py +159 -0
- pymoo/problems/many/dcdtlz.py +88 -0
- pymoo/problems/many/dtlz.py +264 -0
- pymoo/problems/many/wfg.py +550 -0
- pymoo/problems/multi/__init__.py +14 -0
- pymoo/problems/multi/bnh.py +34 -0
- pymoo/problems/multi/carside.py +48 -0
- pymoo/problems/multi/clutch.py +104 -0
- pymoo/problems/multi/csi.py +55 -0
- pymoo/problems/multi/ctp.py +198 -0
- pymoo/problems/multi/dascmop.py +213 -0
- pymoo/problems/multi/kursawe.py +25 -0
- pymoo/problems/multi/modact.py +68 -0
- pymoo/problems/multi/mw.py +400 -0
- pymoo/problems/multi/omnitest.py +48 -0
- pymoo/problems/multi/osy.py +32 -0
- pymoo/problems/multi/srn.py +28 -0
- pymoo/problems/multi/sympart.py +94 -0
- pymoo/problems/multi/tnk.py +24 -0
- pymoo/problems/multi/truss2d.py +83 -0
- pymoo/problems/multi/welded_beam.py +41 -0
- pymoo/problems/multi/wrm.py +36 -0
- pymoo/problems/multi/zdt.py +151 -0
- pymoo/problems/multi_to_single.py +22 -0
- pymoo/problems/single/__init__.py +12 -0
- pymoo/problems/single/ackley.py +24 -0
- pymoo/problems/single/cantilevered_beam.py +34 -0
- pymoo/problems/single/flowshop_scheduling.py +112 -0
- pymoo/problems/single/g.py +874 -0
- pymoo/problems/single/griewank.py +18 -0
- pymoo/problems/single/himmelblau.py +15 -0
- pymoo/problems/single/knapsack.py +48 -0
- pymoo/problems/single/mopta08.py +26 -0
- pymoo/problems/single/multimodal.py +20 -0
- pymoo/problems/single/pressure_vessel.py +30 -0
- pymoo/problems/single/rastrigin.py +20 -0
- pymoo/problems/single/rosenbrock.py +22 -0
- pymoo/problems/single/schwefel.py +18 -0
- pymoo/problems/single/simple.py +13 -0
- pymoo/problems/single/sphere.py +19 -0
- pymoo/problems/single/traveling_salesman.py +79 -0
- pymoo/problems/single/zakharov.py +19 -0
- pymoo/problems/static.py +14 -0
- pymoo/problems/util.py +42 -0
- pymoo/problems/zero_to_one.py +27 -0
- pymoo/termination/__init__.py +23 -0
- pymoo/termination/collection.py +12 -0
- pymoo/termination/cv.py +48 -0
- pymoo/termination/default.py +45 -0
- pymoo/termination/delta.py +64 -0
- pymoo/termination/fmin.py +16 -0
- pymoo/termination/ftol.py +144 -0
- pymoo/termination/indicator.py +49 -0
- pymoo/termination/max_eval.py +14 -0
- pymoo/termination/max_gen.py +15 -0
- pymoo/termination/max_time.py +20 -0
- pymoo/termination/robust.py +34 -0
- pymoo/termination/xtol.py +33 -0
- pymoo/util/__init__.py +0 -0
- pymoo/util/archive.py +150 -0
- pymoo/util/cache.py +29 -0
- pymoo/util/clearing.py +82 -0
- pymoo/util/display/__init__.py +0 -0
- pymoo/util/display/column.py +52 -0
- pymoo/util/display/display.py +34 -0
- pymoo/util/display/multi.py +96 -0
- pymoo/util/display/output.py +53 -0
- pymoo/util/display/progress.py +54 -0
- pymoo/util/display/single.py +67 -0
- pymoo/util/dominator.py +67 -0
- pymoo/util/function_loader.py +129 -0
- pymoo/util/hv.py +23 -0
- pymoo/util/matlab_engine.py +39 -0
- pymoo/util/misc.py +460 -0
- pymoo/util/mnn.py +70 -0
- pymoo/util/nds/__init__.py +0 -0
- pymoo/util/nds/dominance_degree_non_dominated_sort.py +159 -0
- pymoo/util/nds/efficient_non_dominated_sort.py +152 -0
- pymoo/util/nds/fast_non_dominated_sort.py +70 -0
- pymoo/util/nds/naive_non_dominated_sort.py +36 -0
- pymoo/util/nds/non_dominated_sorting.py +67 -0
- pymoo/util/nds/tree_based_non_dominated_sort.py +133 -0
- pymoo/util/normalization.py +312 -0
- pymoo/util/optimum.py +42 -0
- pymoo/util/plotting.py +177 -0
- pymoo/util/pruning_cd.py +89 -0
- pymoo/util/randomized_argsort.py +60 -0
- pymoo/util/ref_dirs/__init__.py +24 -0
- pymoo/util/ref_dirs/construction.py +88 -0
- pymoo/util/ref_dirs/das_dennis.py +52 -0
- pymoo/util/ref_dirs/energy.py +319 -0
- pymoo/util/ref_dirs/energy_layer.py +119 -0
- pymoo/util/ref_dirs/genetic_algorithm.py +63 -0
- pymoo/util/ref_dirs/incremental.py +68 -0
- pymoo/util/ref_dirs/misc.py +128 -0
- pymoo/util/ref_dirs/optimizer.py +59 -0
- pymoo/util/ref_dirs/performance.py +162 -0
- pymoo/util/ref_dirs/reduction.py +85 -0
- pymoo/util/ref_dirs/sample_and_map.py +24 -0
- pymoo/util/reference_direction.py +260 -0
- pymoo/util/remote.py +55 -0
- pymoo/util/roulette.py +27 -0
- pymoo/util/running_metric.py +128 -0
- pymoo/util/sliding_window.py +25 -0
- pymoo/util/stochastic_ranking.py +32 -0
- pymoo/util/value_functions.py +719 -0
- pymoo/util/vectors.py +40 -0
- pymoo/util/vf_dominator.py +99 -0
- pymoo/vendor/__init__.py +0 -0
- pymoo/vendor/cec2018.py +398 -0
- pymoo/vendor/gta.py +617 -0
- pymoo/vendor/hv.py +267 -0
- pymoo/vendor/vendor_cmaes.py +412 -0
- pymoo/vendor/vendor_coco.py +81 -0
- pymoo/vendor/vendor_scipy.py +232 -0
- pymoo/version.py +1 -0
- pymoo/visualization/__init__.py +8 -0
- pymoo/visualization/fitness_landscape.py +127 -0
- pymoo/visualization/heatmap.py +123 -0
- pymoo/visualization/pcp.py +120 -0
- pymoo/visualization/petal.py +91 -0
- pymoo/visualization/radar.py +108 -0
- pymoo/visualization/radviz.py +68 -0
- pymoo/visualization/scatter.py +150 -0
- pymoo/visualization/star_coordinate.py +75 -0
- pymoo/visualization/util.py +123 -0
- pymoo/visualization/video/__init__.py +0 -0
- pymoo/visualization/video/callback_video.py +82 -0
- pymoo/visualization/video/one_var_one_obj.py +57 -0
- pymoo/visualization/video/two_var_one_obj.py +62 -0
- pymoo-0.6.1.5.dev0.dist-info/METADATA +187 -0
- pymoo-0.6.1.5.dev0.dist-info/RECORD +328 -0
- pymoo-0.6.1.5.dev0.dist-info/WHEEL +6 -0
- pymoo-0.6.1.5.dev0.dist-info/licenses/LICENSE +191 -0
- pymoo-0.6.1.5.dev0.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,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__)
|