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.
- 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 +110 -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 +91 -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/cmopso.py +239 -0
- pymoo/algorithms/moo/ctaea.py +305 -0
- pymoo/algorithms/moo/dnsga2.py +80 -0
- pymoo/algorithms/moo/kgb.py +450 -0
- pymoo/algorithms/moo/moead.py +183 -0
- pymoo/algorithms/moo/mopso_cd.py +309 -0
- pymoo/algorithms/moo/nsga2.py +113 -0
- pymoo/algorithms/moo/nsga3.py +361 -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 +196 -0
- pymoo/algorithms/moo/spea2.py +191 -0
- pymoo/algorithms/moo/unsga3.py +49 -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 +162 -0
- pymoo/algorithms/soo/nonconvex/cmaes.py +556 -0
- pymoo/algorithms/soo/nonconvex/de.py +283 -0
- pymoo/algorithms/soo/nonconvex/direct.py +148 -0
- pymoo/algorithms/soo/nonconvex/es.py +213 -0
- pymoo/algorithms/soo/nonconvex/g3pcx.py +94 -0
- pymoo/algorithms/soo/nonconvex/ga.py +95 -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/nrbo.py +191 -0
- pymoo/algorithms/soo/nonconvex/optuna.py +80 -0
- pymoo/algorithms/soo/nonconvex/pattern.py +185 -0
- pymoo/algorithms/soo/nonconvex/pso.py +337 -0
- pymoo/algorithms/soo/nonconvex/pso_ep.py +307 -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/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 +66 -0
- pymoo/constraints/as_obj.py +56 -0
- pymoo/constraints/as_penalty.py +41 -0
- pymoo/constraints/eps.py +34 -0
- pymoo/constraints/from_bounds.py +36 -0
- pymoo/core/__init__.py +0 -0
- pymoo/core/algorithm.py +408 -0
- pymoo/core/callback.py +38 -0
- pymoo/core/crossover.py +79 -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 +65 -0
- pymoo/core/initialization.py +44 -0
- pymoo/core/mating.py +39 -0
- pymoo/core/meta.py +21 -0
- pymoo/core/mixed.py +164 -0
- pymoo/core/mutation.py +44 -0
- pymoo/core/operator.py +46 -0
- pymoo/core/parameters.py +134 -0
- pymoo/core/plot.py +208 -0
- pymoo/core/population.py +180 -0
- pymoo/core/problem.py +373 -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 +45 -0
- pymoo/core/selection.py +61 -0
- pymoo/core/solution.py +10 -0
- pymoo/core/survival.py +107 -0
- pymoo/core/termination.py +70 -0
- pymoo/core/variable.py +415 -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/functions/__init__.py +135 -0
- pymoo/functions/compiled/__init__.py +0 -0
- pymoo/functions/compiled/calc_perpendicular_distance.cpp +27464 -0
- pymoo/functions/compiled/calc_perpendicular_distance.cpython-312-darwin.so +0 -0
- pymoo/functions/compiled/decomposition.cpp +28853 -0
- pymoo/functions/compiled/decomposition.cpython-312-darwin.so +0 -0
- pymoo/functions/compiled/info.cpp +7058 -0
- pymoo/functions/compiled/info.cpython-312-darwin.so +0 -0
- pymoo/functions/compiled/mnn.cpp +30095 -0
- pymoo/functions/compiled/mnn.cpython-312-darwin.so +0 -0
- pymoo/functions/compiled/non_dominated_sorting.cpp +35692 -0
- pymoo/functions/compiled/non_dominated_sorting.cpython-312-darwin.so +0 -0
- pymoo/functions/compiled/pruning_cd.cpp +29248 -0
- pymoo/functions/compiled/pruning_cd.cpython-312-darwin.so +0 -0
- pymoo/functions/compiled/stochastic_ranking.cpp +28042 -0
- pymoo/functions/compiled/stochastic_ranking.cpython-312-darwin.so +0 -0
- pymoo/functions/standard/__init__.py +1 -0
- pymoo/functions/standard/calc_perpendicular_distance.py +20 -0
- pymoo/functions/standard/decomposition.py +18 -0
- pymoo/functions/standard/hv.py +5 -0
- pymoo/functions/standard/mnn.py +78 -0
- pymoo/functions/standard/non_dominated_sorting.py +474 -0
- pymoo/functions/standard/pruning_cd.py +93 -0
- pymoo/functions/standard/stochastic_ranking.py +42 -0
- pymoo/gradient/__init__.py +24 -0
- pymoo/gradient/automatic.py +85 -0
- pymoo/gradient/grad_autograd.py +105 -0
- pymoo/gradient/grad_complex.py +35 -0
- pymoo/gradient/grad_jax.py +51 -0
- pymoo/gradient/numpy.py +22 -0
- pymoo/gradient/toolbox/__init__.py +19 -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 +59 -0
- pymoo/indicators/hv/approximate.py +105 -0
- pymoo/indicators/hv/exact.py +68 -0
- pymoo/indicators/hv/exact_2d.py +102 -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 +190 -0
- pymoo/operators/crossover/__init__.py +0 -0
- pymoo/operators/crossover/binx.py +47 -0
- pymoo/operators/crossover/dex.py +125 -0
- pymoo/operators/crossover/erx.py +164 -0
- pymoo/operators/crossover/expx.py +53 -0
- pymoo/operators/crossover/hux.py +37 -0
- pymoo/operators/crossover/nox.py +25 -0
- pymoo/operators/crossover/ox.py +88 -0
- pymoo/operators/crossover/pcx.py +84 -0
- pymoo/operators/crossover/pntx.py +49 -0
- pymoo/operators/crossover/sbx.py +137 -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 +60 -0
- pymoo/operators/mutation/inversion.py +42 -0
- pymoo/operators/mutation/nom.py +7 -0
- pymoo/operators/mutation/pm.py +96 -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 +97 -0
- pymoo/operators/repair/inverse_penalty.py +91 -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 +76 -0
- pymoo/operators/sampling/rnd.py +52 -0
- pymoo/operators/selection/__init__.py +0 -0
- pymoo/operators/selection/rnd.py +75 -0
- pymoo/operators/selection/tournament.py +78 -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 +212 -0
- pymoo/operators/survival/rank_and_crowding/metrics.py +208 -0
- pymoo/optimize.py +72 -0
- pymoo/parallelization/__init__.py +15 -0
- pymoo/parallelization/dask.py +25 -0
- pymoo/parallelization/joblib.py +28 -0
- pymoo/parallelization/ray.py +31 -0
- pymoo/parallelization/starmap.py +24 -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 +451 -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 +553 -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 +113 -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 +49 -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 +33 -0
- pymoo/util/archive.py +152 -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 +100 -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/hv.py +21 -0
- pymoo/util/matlab_engine.py +39 -0
- pymoo/util/misc.py +447 -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/find_non_dominated.py +54 -0
- pymoo/util/nds/naive_non_dominated_sort.py +36 -0
- pymoo/util/nds/non_dominated_sorting.py +94 -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/randomized_argsort.py +63 -0
- pymoo/util/ref_dirs/__init__.py +24 -0
- pymoo/util/ref_dirs/construction.py +89 -0
- pymoo/util/ref_dirs/das_dennis.py +52 -0
- pymoo/util/ref_dirs/energy.py +317 -0
- pymoo/util/ref_dirs/energy_layer.py +119 -0
- pymoo/util/ref_dirs/genetic_algorithm.py +64 -0
- pymoo/util/ref_dirs/incremental.py +69 -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 +258 -0
- pymoo/util/remote.py +55 -0
- pymoo/util/roulette.py +29 -0
- pymoo/util/running_metric.py +128 -0
- pymoo/util/sliding_window.py +25 -0
- pymoo/util/value_functions.py +720 -0
- pymoo/util/vectors.py +40 -0
- pymoo/util/vf_dominator.py +102 -0
- pymoo/vendor/__init__.py +0 -0
- pymoo/vendor/cec2018.py +398 -0
- pymoo/vendor/gta.py +617 -0
- pymoo/vendor/vendor_cmaes.py +421 -0
- pymoo/vendor/vendor_coco.py +81 -0
- pymoo/vendor/vendor_scipy.py +232 -0
- pymoo/version.py +1 -0
- pymoo/visualization/__init__.py +21 -0
- pymoo/visualization/app/__init__.py +0 -0
- pymoo/visualization/app/pso.py +61 -0
- pymoo/visualization/fitness_landscape.py +128 -0
- pymoo/visualization/heatmap.py +123 -0
- pymoo/visualization/matplotlib.py +61 -0
- pymoo/visualization/pcp.py +121 -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 +296 -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.6.dist-info/METADATA +209 -0
- pymoo-0.6.1.6.dist-info/RECORD +337 -0
- pymoo-0.6.1.6.dist-info/WHEEL +6 -0
- pymoo-0.6.1.6.dist-info/licenses/LICENSE +191 -0
- pymoo-0.6.1.6.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import math
|
|
2
|
+
from abc import abstractmethod
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from pymoo.core.duplicate import NoDuplicateElimination
|
|
7
|
+
from pymoo.core.individual import Individual
|
|
8
|
+
from pymoo.core.infill import InfillCriterion
|
|
9
|
+
from pymoo.core.mixed import MixedVariableMating
|
|
10
|
+
from pymoo.core.parameters import get_params, flatten
|
|
11
|
+
from pymoo.core.problem import Problem
|
|
12
|
+
from pymoo.core.variable import Choice, Real, Integer, Binary
|
|
13
|
+
from pymoo.operators.crossover.sbx import SBX
|
|
14
|
+
from pymoo.operators.crossover.ux import UX
|
|
15
|
+
from pymoo.operators.mutation.bitflip import BFM
|
|
16
|
+
from pymoo.operators.mutation.pm import PM
|
|
17
|
+
from pymoo.operators.mutation.rm import ChoiceRandomMutation
|
|
18
|
+
from pymoo.operators.repair.rounding import RoundingRepair
|
|
19
|
+
from pymoo.operators.selection.tournament import TournamentSelection, compare
|
|
20
|
+
from pymoo.util import default_random_state
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ParameterControl:
|
|
24
|
+
|
|
25
|
+
def __init__(self, obj) -> None:
|
|
26
|
+
super().__init__()
|
|
27
|
+
|
|
28
|
+
self.data = None
|
|
29
|
+
|
|
30
|
+
params = flatten({"ParameterControl": get_params(obj)})
|
|
31
|
+
self.params = params
|
|
32
|
+
|
|
33
|
+
# print("PARAMETER CONTROL:", list(self.params))
|
|
34
|
+
|
|
35
|
+
@default_random_state
|
|
36
|
+
def do(self, N, set_to_params=True, random_state=None):
|
|
37
|
+
vals = self._do(N, random_state=random_state)
|
|
38
|
+
if set_to_params:
|
|
39
|
+
if vals is not None:
|
|
40
|
+
for k, v in vals.items():
|
|
41
|
+
self.params[k].set(v)
|
|
42
|
+
return vals
|
|
43
|
+
|
|
44
|
+
@abstractmethod
|
|
45
|
+
def _do(self, N, random_state=None):
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
def tell(self, **kwargs):
|
|
49
|
+
self.data = dict(kwargs)
|
|
50
|
+
|
|
51
|
+
def advance(self, infills=None):
|
|
52
|
+
for k, v in self.params.items():
|
|
53
|
+
assert len(v.get()) == len(
|
|
54
|
+
infills), "Make sure that the infills and parameters asked for have the same size."
|
|
55
|
+
infills.set(k, v.get())
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class NoParameterControl(ParameterControl):
|
|
59
|
+
|
|
60
|
+
def __init__(self, _) -> None:
|
|
61
|
+
super().__init__(None)
|
|
62
|
+
|
|
63
|
+
def _do(self, N, random_state=None):
|
|
64
|
+
return {}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class RandomParameterControl(ParameterControl):
|
|
68
|
+
|
|
69
|
+
def _do(self, N, random_state=None):
|
|
70
|
+
return {key: value.sample(N, random_state=random_state) for key, value in self.params.items()}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class EvolutionaryParameterControl(ParameterControl):
|
|
74
|
+
|
|
75
|
+
def __init__(self, obj) -> None:
|
|
76
|
+
super().__init__(obj)
|
|
77
|
+
self.eps = 0.05
|
|
78
|
+
|
|
79
|
+
def _do(self, N, random_state=None):
|
|
80
|
+
params = self.params
|
|
81
|
+
pop = self.data.get("pop")
|
|
82
|
+
|
|
83
|
+
# make sure that for each parameter a value exists - if not simply set it randomly
|
|
84
|
+
for name, param in params.items():
|
|
85
|
+
is_none = np.where(pop.get(name) == None)[0]
|
|
86
|
+
if len(is_none) > 0:
|
|
87
|
+
pop[is_none].set(name, param.sample(len(is_none), random_state=random_state))
|
|
88
|
+
|
|
89
|
+
selection = AgeBasedTournamentSelection()
|
|
90
|
+
|
|
91
|
+
crossover = {
|
|
92
|
+
Binary: UX(),
|
|
93
|
+
Real: SBX(),
|
|
94
|
+
Integer: SBX(vtype=float, repair=RoundingRepair()),
|
|
95
|
+
Choice: UX(),
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
mutation = {
|
|
99
|
+
Binary: BFM(),
|
|
100
|
+
Real: PM(),
|
|
101
|
+
Integer: PM(vtype=float, repair=RoundingRepair()),
|
|
102
|
+
Choice: ChoiceRandomMutation(),
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
mating = MixedVariableMating(
|
|
106
|
+
crossover=crossover,
|
|
107
|
+
mutation=mutation,
|
|
108
|
+
eliminate_duplicates=NoDuplicateElimination()
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
problem = Problem(vars=params)
|
|
112
|
+
|
|
113
|
+
parents = selection(problem, pop, N, n_parents=2, random_state=random_state)
|
|
114
|
+
parents = [[Individual(X={key: parent.get(key) for key in params}) for parent in mating] for mating in parents]
|
|
115
|
+
|
|
116
|
+
off = mating(problem, parents, N, parents=True, random_state=random_state)
|
|
117
|
+
|
|
118
|
+
Xp = off.get("X")
|
|
119
|
+
ret = {param: np.array([Xp[i][param] for i in range(len(Xp))]) for param in params}
|
|
120
|
+
|
|
121
|
+
return ret
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class AgeBasedTournamentSelection(TournamentSelection):
|
|
125
|
+
|
|
126
|
+
def __init__(self, pressure=2):
|
|
127
|
+
super().__init__(age_binary_tournament, pressure)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def age_binary_tournament(pop, P, **kwargs):
|
|
131
|
+
n_tournaments, n_parents = P.shape
|
|
132
|
+
|
|
133
|
+
if n_parents != 2:
|
|
134
|
+
raise ValueError("Only implemented for binary tournament!")
|
|
135
|
+
|
|
136
|
+
S = np.full(n_tournaments, np.nan)
|
|
137
|
+
random_state = kwargs.get('random_state', None)
|
|
138
|
+
|
|
139
|
+
for i in range(n_tournaments):
|
|
140
|
+
a, b = P[i, 0], P[i, 1]
|
|
141
|
+
a_gen, b_gen = pop[a].get("n_gen"), pop[b].get("n_gen")
|
|
142
|
+
S[i] = compare(a, a_gen, b, b_gen, method='larger_is_better', return_random_if_equal=True, random_state=random_state)
|
|
143
|
+
|
|
144
|
+
return S[:, None].astype(int, copy=False)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class ParameterControlMating(InfillCriterion):
|
|
148
|
+
|
|
149
|
+
def __init__(self,
|
|
150
|
+
selection,
|
|
151
|
+
crossover,
|
|
152
|
+
mutation,
|
|
153
|
+
control=NoParameterControl,
|
|
154
|
+
**kwargs):
|
|
155
|
+
super().__init__(**kwargs)
|
|
156
|
+
self.selection = selection
|
|
157
|
+
self.crossover = crossover
|
|
158
|
+
self.mutation = mutation
|
|
159
|
+
self.control = control(self)
|
|
160
|
+
|
|
161
|
+
def _do(self, problem, pop, n_offsprings, parents=None, **kwargs):
|
|
162
|
+
|
|
163
|
+
# how many parents need to be select for the mating - depending on number of offsprings remaining
|
|
164
|
+
n_matings = math.ceil(n_offsprings / self.crossover.n_offsprings)
|
|
165
|
+
|
|
166
|
+
# do the parameter control for the mating
|
|
167
|
+
control = self.control
|
|
168
|
+
control.tell(pop=pop)
|
|
169
|
+
control.do(n_matings)
|
|
170
|
+
|
|
171
|
+
# if the parents for the mating are not provided directly - usually selection will be used
|
|
172
|
+
if parents is None:
|
|
173
|
+
|
|
174
|
+
# select the parents for the mating - just an index array
|
|
175
|
+
parents = self.selection.do(problem, pop, n_matings, n_parents=self.crossover.n_parents, **kwargs)
|
|
176
|
+
|
|
177
|
+
# do the crossover using the parents index and the population - additional data provided if necessary
|
|
178
|
+
off = self.crossover(problem, parents, **kwargs)
|
|
179
|
+
|
|
180
|
+
# now we have to consider during parameter control that a crossover can produce multiple offsprings
|
|
181
|
+
for name, param in control.params.items():
|
|
182
|
+
param.set(np.repeat(param.get(), self.crossover.n_offsprings))
|
|
183
|
+
|
|
184
|
+
# do the mutation on the offsprings created through crossover
|
|
185
|
+
off = self.mutation(problem, off, **kwargs)
|
|
186
|
+
|
|
187
|
+
# finally attach the parameters back to the offsprings
|
|
188
|
+
control.advance(off)
|
|
189
|
+
|
|
190
|
+
return off
|
|
File without changes
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pymoo.core.crossover import Crossover
|
|
4
|
+
from pymoo.core.variable import Real, get
|
|
5
|
+
from pymoo.util import default_random_state
|
|
6
|
+
from pymoo.util.misc import row_at_least_once_true
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@default_random_state
|
|
10
|
+
def mut_binomial(n, m, prob, at_least_once=True, random_state=None):
|
|
11
|
+
prob = np.ones(n) * prob
|
|
12
|
+
M = random_state.random((n, m)) < prob[:, None]
|
|
13
|
+
|
|
14
|
+
if at_least_once:
|
|
15
|
+
M = row_at_least_once_true(M, random_state=random_state)
|
|
16
|
+
|
|
17
|
+
return M
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class BinomialCrossover(Crossover):
|
|
21
|
+
|
|
22
|
+
def __init__(self, bias=0.5, n_offsprings=2, **kwargs):
|
|
23
|
+
super().__init__(2, n_offsprings, **kwargs)
|
|
24
|
+
self.bias = Real(bias, bounds=(0.1, 0.9), strict=(0.0, 1.0))
|
|
25
|
+
|
|
26
|
+
def _do(self, problem, X, *args, random_state=None, **kwargs):
|
|
27
|
+
_, n_matings, n_var = X.shape
|
|
28
|
+
|
|
29
|
+
bias = get(self.bias, size=n_matings)
|
|
30
|
+
M = mut_binomial(n_matings, n_var, bias, at_least_once=True, random_state=random_state)
|
|
31
|
+
|
|
32
|
+
if self.n_offsprings == 1:
|
|
33
|
+
Xp = X[0].copy()
|
|
34
|
+
Xp[~M] = X[1][~M]
|
|
35
|
+
Xp = Xp[None, ...]
|
|
36
|
+
elif self.n_offsprings == 2:
|
|
37
|
+
Xp = np.copy(X)
|
|
38
|
+
Xp[0][~M] = X[1][~M]
|
|
39
|
+
Xp[1][~M] = X[0][~M]
|
|
40
|
+
else:
|
|
41
|
+
raise Exception
|
|
42
|
+
|
|
43
|
+
return Xp
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class BX(BinomialCrossover):
|
|
47
|
+
pass
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pymoo.core.crossover import Crossover
|
|
4
|
+
from pymoo.core.population import Population
|
|
5
|
+
from pymoo.operators.crossover.binx import mut_binomial
|
|
6
|
+
from pymoo.operators.crossover.expx import mut_exp
|
|
7
|
+
from pymoo.operators.repair.bounds_repair import is_out_of_bounds_by_problem, repair_random_init
|
|
8
|
+
from pymoo.util import default_random_state
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@default_random_state
|
|
12
|
+
def de_differential(X, F, dither=None, jitter=True, gamma=0.0001, return_differentials=False, random_state=None):
|
|
13
|
+
n_parents, n_matings, n_var = X.shape
|
|
14
|
+
assert n_parents % 2 == 1, "For the differential an odd number of values need to be provided"
|
|
15
|
+
|
|
16
|
+
# make sure F is a one-dimensional vector
|
|
17
|
+
F = np.ones(n_matings) * F
|
|
18
|
+
|
|
19
|
+
# build the pairs for the differentials
|
|
20
|
+
pairs = (np.arange(n_parents - 1) + 1).reshape(-1, 2)
|
|
21
|
+
|
|
22
|
+
# the differentials from each pair subtraction
|
|
23
|
+
diffs = np.zeros((n_matings, n_var))
|
|
24
|
+
|
|
25
|
+
# for each difference
|
|
26
|
+
for i, j in pairs:
|
|
27
|
+
|
|
28
|
+
if dither == "vector":
|
|
29
|
+
F = (F + random_state.random(n_matings) * (1 - F))
|
|
30
|
+
elif dither == "scalar":
|
|
31
|
+
F = F + random_state.random() * (1 - F)
|
|
32
|
+
|
|
33
|
+
# http://www.cs.ndsu.nodak.edu/~siludwig/Publish/papers/SSCI20141.pdf
|
|
34
|
+
if jitter:
|
|
35
|
+
F = (F * (1 + gamma * (random_state.random(n_matings) - 0.5)))
|
|
36
|
+
|
|
37
|
+
# an add the difference to the first vector
|
|
38
|
+
diffs += F[:, None] * (X[i] - X[j])
|
|
39
|
+
|
|
40
|
+
# now add the differentials to the first parent
|
|
41
|
+
Xp = X[0] + diffs
|
|
42
|
+
|
|
43
|
+
if return_differentials:
|
|
44
|
+
return Xp, diffs
|
|
45
|
+
else:
|
|
46
|
+
return Xp
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class DEX(Crossover):
|
|
50
|
+
|
|
51
|
+
def __init__(self,
|
|
52
|
+
F=None,
|
|
53
|
+
CR=0.7,
|
|
54
|
+
variant="bin",
|
|
55
|
+
dither=None,
|
|
56
|
+
jitter=False,
|
|
57
|
+
n_diffs=1,
|
|
58
|
+
n_iter=1,
|
|
59
|
+
at_least_once=True,
|
|
60
|
+
**kwargs):
|
|
61
|
+
|
|
62
|
+
super().__init__(1 + 2 * n_diffs, 1, **kwargs)
|
|
63
|
+
self.n_diffs = n_diffs
|
|
64
|
+
self.F = F
|
|
65
|
+
self.CR = CR
|
|
66
|
+
self.variant = variant
|
|
67
|
+
self.at_least_once = at_least_once
|
|
68
|
+
self.dither = dither
|
|
69
|
+
self.jitter = jitter
|
|
70
|
+
self.n_iter = n_iter
|
|
71
|
+
|
|
72
|
+
def do(self, problem, pop, parents=None, *args, random_state, **kwargs):
|
|
73
|
+
|
|
74
|
+
# if a parents with array with mating indices is provided -> transform the input first
|
|
75
|
+
if parents is not None:
|
|
76
|
+
pop = [pop[mating] for mating in parents]
|
|
77
|
+
|
|
78
|
+
# get the actual values from each of the parents
|
|
79
|
+
X = np.swapaxes(np.array([[parent.get("X") for parent in mating] for mating in pop]), 0, 1).copy()
|
|
80
|
+
|
|
81
|
+
n_parents, n_matings, n_var = X.shape
|
|
82
|
+
|
|
83
|
+
# a mask over matings that need to be repeated
|
|
84
|
+
m = np.arange(n_matings)
|
|
85
|
+
|
|
86
|
+
# if the user provides directly an F value to use
|
|
87
|
+
F = self.F if self.F is not None else rnd_F(m, random_state=random_state)
|
|
88
|
+
|
|
89
|
+
# prepare the out to be set
|
|
90
|
+
Xp = de_differential(X[:, m], F, random_state=random_state)
|
|
91
|
+
|
|
92
|
+
# if the problem has boundaries to be considered
|
|
93
|
+
if problem.has_bounds():
|
|
94
|
+
|
|
95
|
+
for k in range(self.n_iter):
|
|
96
|
+
# find the individuals which are still infeasible
|
|
97
|
+
m = is_out_of_bounds_by_problem(problem, Xp)
|
|
98
|
+
|
|
99
|
+
F = rnd_F(m, random_state=random_state)
|
|
100
|
+
|
|
101
|
+
# actually execute the differential equation
|
|
102
|
+
Xp[m] = de_differential(X[:, m], F, random_state=random_state)
|
|
103
|
+
|
|
104
|
+
# if still infeasible do a random initialization
|
|
105
|
+
Xp = repair_random_init(Xp, X[0], *problem.bounds())
|
|
106
|
+
|
|
107
|
+
if self.variant == "bin":
|
|
108
|
+
M = mut_binomial(n_matings, n_var, self.CR, at_least_once=self.at_least_once, random_state=random_state)
|
|
109
|
+
elif self.variant == "exp":
|
|
110
|
+
M = mut_exp(n_matings, n_var, self.CR, at_least_once=self.at_least_once, random_state=random_state)
|
|
111
|
+
else:
|
|
112
|
+
raise Exception(f"Unknown variant: {self.variant}")
|
|
113
|
+
|
|
114
|
+
# take the first parents (this is already a copy)
|
|
115
|
+
X = X[0]
|
|
116
|
+
|
|
117
|
+
# set the corresponding values from the donor vector
|
|
118
|
+
X[M] = Xp[M]
|
|
119
|
+
|
|
120
|
+
return Population.new("X", X)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@default_random_state
|
|
124
|
+
def rnd_F(m, random_state=None):
|
|
125
|
+
return 0.5 * (1 + random_state.uniform(size=len(m)))
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pymoo.core.crossover import Crossover
|
|
4
|
+
from pymoo.util import default_random_state
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def remove_from_adj_list(H, val):
|
|
8
|
+
for e in list(H[val]):
|
|
9
|
+
H[e].remove(val)
|
|
10
|
+
del H[val]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def has_duplicates(x):
|
|
14
|
+
H = set()
|
|
15
|
+
for v in x:
|
|
16
|
+
if v in H:
|
|
17
|
+
return True
|
|
18
|
+
H.add(v)
|
|
19
|
+
return False
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@default_random_state
|
|
23
|
+
def erx(a, b, random_state=None):
|
|
24
|
+
"""
|
|
25
|
+
http://www.rubicite.com/Tutorials/GeneticAlgorithms/CrossoverOperators/EdgeRecombinationCrossoverOperator.aspx
|
|
26
|
+
|
|
27
|
+
Algorithm Pseudo Code:
|
|
28
|
+
|
|
29
|
+
1. X = the first node from a random parent.
|
|
30
|
+
|
|
31
|
+
2. While the CHILD chromo isn't full, Loop:
|
|
32
|
+
- Append X to CHILD
|
|
33
|
+
- Remove X from Neighbor Lists
|
|
34
|
+
|
|
35
|
+
if X's neighbor list is empty:
|
|
36
|
+
- Xp = random node not already in CHILD
|
|
37
|
+
else
|
|
38
|
+
- Determine neighbor of X that has fewest neighbors
|
|
39
|
+
- If there is a tie, randomly choose 1
|
|
40
|
+
- Xp = chosen node
|
|
41
|
+
X = Xp
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
assert len(a) == len(b)
|
|
45
|
+
|
|
46
|
+
# calculate the edge matrix considering both permutation
|
|
47
|
+
H = calc_adjency_matrix(a)
|
|
48
|
+
H = calc_adjency_matrix(b, H=H)
|
|
49
|
+
|
|
50
|
+
# randomly select the first node
|
|
51
|
+
_next = random_state.choice(list(H.keys()))
|
|
52
|
+
|
|
53
|
+
y = []
|
|
54
|
+
while True:
|
|
55
|
+
|
|
56
|
+
# append to the child
|
|
57
|
+
y.append(_next)
|
|
58
|
+
|
|
59
|
+
# break if the child was successfully created.
|
|
60
|
+
if len(y) == len(a):
|
|
61
|
+
break
|
|
62
|
+
|
|
63
|
+
# get the neighbors to consider and remove them from the lists
|
|
64
|
+
neighbors = list(H[_next])
|
|
65
|
+
remove_from_adj_list(H, _next)
|
|
66
|
+
|
|
67
|
+
# if the current node does not have any neighbors
|
|
68
|
+
if len(neighbors) == 0:
|
|
69
|
+
_next = random_state.choice(list(H.keys()))
|
|
70
|
+
|
|
71
|
+
# otherwise search in the neighbors for a node with the fewest neighbors
|
|
72
|
+
else:
|
|
73
|
+
# search for the one with minimum neighbors
|
|
74
|
+
n_neighbors = [len(H[e]) for e in neighbors]
|
|
75
|
+
min_n_neighbors = min(n_neighbors)
|
|
76
|
+
_next = [neighbors[k] for k in range(len(neighbors)) if n_neighbors[k] == min_n_neighbors]
|
|
77
|
+
|
|
78
|
+
# break the tie if they might have the same number of neighbors
|
|
79
|
+
_next = random_state.choice(_next)
|
|
80
|
+
|
|
81
|
+
return y
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class EdgeRecombinationCrossover(Crossover):
|
|
85
|
+
|
|
86
|
+
def __init__(self, **kwargs):
|
|
87
|
+
super().__init__(2, 1, **kwargs)
|
|
88
|
+
|
|
89
|
+
def _do(self, problem, X, random_state=None, **kwargs):
|
|
90
|
+
_, n_matings, n_var = X.shape
|
|
91
|
+
Y = np.full((self.n_offsprings, n_matings, n_var), -1, dtype=int)
|
|
92
|
+
|
|
93
|
+
for i in range(n_matings):
|
|
94
|
+
a, b = X[:, i, :]
|
|
95
|
+
Y[0, i, :] = erx(a, b, random_state=random_state)
|
|
96
|
+
|
|
97
|
+
return Y
|
|
98
|
+
|
|
99
|
+
class ERX(EdgeRecombinationCrossover):
|
|
100
|
+
pass
|
|
101
|
+
|
|
102
|
+
def number_to_letter(n):
|
|
103
|
+
return chr(ord('@') + n)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def numbers_to_letters(numbers):
|
|
107
|
+
return [number_to_letter(n) for n in numbers]
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def letter_to_number(char):
|
|
111
|
+
return ord(char.lower()) - 96
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def letters_to_numbers(letters):
|
|
115
|
+
return np.array([letter_to_number(char) for char in letters])
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def calc_adjency_matrix(x, H=None):
|
|
119
|
+
H = {} if H is None else H
|
|
120
|
+
|
|
121
|
+
for k in range(len(x)):
|
|
122
|
+
prev = (k - 1) % len(x)
|
|
123
|
+
succ = (k + 1) % len(x)
|
|
124
|
+
|
|
125
|
+
if x[k] not in H:
|
|
126
|
+
H[x[k]] = set()
|
|
127
|
+
H[x[k]].update([x[prev], x[succ]])
|
|
128
|
+
|
|
129
|
+
return H
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
if __name__ == "__main__":
|
|
133
|
+
a = ['A', 'B', 'F', 'E', 'D', 'G', 'C']
|
|
134
|
+
b = ['G', 'F', 'A', 'B', 'C', 'D', 'E']
|
|
135
|
+
|
|
136
|
+
"""
|
|
137
|
+
A: B C F
|
|
138
|
+
B: A F C
|
|
139
|
+
C: A G B D
|
|
140
|
+
D: E G C E
|
|
141
|
+
E: F D G
|
|
142
|
+
F: B E G A
|
|
143
|
+
G: D C E F
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
H = calc_adjency_matrix(a)
|
|
147
|
+
H = calc_adjency_matrix(b, H=H)
|
|
148
|
+
|
|
149
|
+
assert len(H["A"]) == 3
|
|
150
|
+
assert 'B' in H["A"] and 'C' in H["A"] and 'F' in H["A"]
|
|
151
|
+
assert len(H["B"]) == 3
|
|
152
|
+
assert 'A' in H["B"] and 'F' in H["B"] and 'C' in H["B"]
|
|
153
|
+
assert len(H["C"]) == 4
|
|
154
|
+
assert 'A' in H["C"] and 'G' in H["C"] and 'B' in H["C"] and 'D' in H["C"]
|
|
155
|
+
assert len(H["D"]) == 3
|
|
156
|
+
assert 'E' in H["D"] and 'G' in H["D"] and 'C' in H["D"]
|
|
157
|
+
assert len(H["E"]) == 3
|
|
158
|
+
assert 'F' in H["E"] and 'D' in H["E"] and 'G' in H["E"]
|
|
159
|
+
assert len(H["F"]) == 4
|
|
160
|
+
assert 'B' in H["F"] and 'E' in H["F"] and 'G' in H["F"] and 'A' in H["F"]
|
|
161
|
+
assert len(H["G"]) == 4
|
|
162
|
+
assert 'D' in H["G"] and 'E' in H["G"] and 'E' in H["G"] and 'F' in H["G"]
|
|
163
|
+
|
|
164
|
+
c = erx(a, b)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pymoo.core.crossover import Crossover
|
|
4
|
+
from pymoo.core.variable import get, Real
|
|
5
|
+
from pymoo.util import default_random_state
|
|
6
|
+
from pymoo.util.misc import crossover_mask, row_at_least_once_true
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@default_random_state
|
|
10
|
+
def mut_exp(n_matings, n_var, prob, at_least_once=True, random_state=None):
|
|
11
|
+
assert len(prob) == n_matings
|
|
12
|
+
|
|
13
|
+
# the mask do to the crossover
|
|
14
|
+
M = np.full((n_matings, n_var), False)
|
|
15
|
+
|
|
16
|
+
# start point of crossover
|
|
17
|
+
s = random_state.integers(0, n_var, size=n_matings)
|
|
18
|
+
|
|
19
|
+
# create for each individual the crossover range
|
|
20
|
+
for i in range(n_matings):
|
|
21
|
+
|
|
22
|
+
# the actual index where we start
|
|
23
|
+
start = s[i]
|
|
24
|
+
for j in range(n_var):
|
|
25
|
+
|
|
26
|
+
# the current position where we are pointing to
|
|
27
|
+
current = (start + j) % n_var
|
|
28
|
+
|
|
29
|
+
# replace only if random value keeps being smaller than CR
|
|
30
|
+
if random_state.random() <= prob[i]:
|
|
31
|
+
M[i, current] = True
|
|
32
|
+
else:
|
|
33
|
+
break
|
|
34
|
+
|
|
35
|
+
if at_least_once:
|
|
36
|
+
M = row_at_least_once_true(M, random_state=random_state)
|
|
37
|
+
|
|
38
|
+
return M
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class ExponentialCrossover(Crossover):
|
|
42
|
+
|
|
43
|
+
def __init__(self, prob_exp=0.75, **kwargs):
|
|
44
|
+
super().__init__(2, 2, **kwargs)
|
|
45
|
+
self.prob_exp = Real(prob_exp, bounds=(0.5, 0.9), strict=(0.0, 1.0))
|
|
46
|
+
|
|
47
|
+
def _do(self, _, X, random_state=None, **kwargs):
|
|
48
|
+
_, n_matings, n_var = X.shape
|
|
49
|
+
prob_exp = get(self.prob_exp, size=n_matings)
|
|
50
|
+
|
|
51
|
+
M = mut_exp(n_matings, n_var, prob_exp, at_least_once=True, random_state=random_state)
|
|
52
|
+
_X = crossover_mask(X, M)
|
|
53
|
+
return _X
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from pymoo.core.crossover import Crossover
|
|
6
|
+
from pymoo.util.misc import crossover_mask
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class HalfUniformCrossover(Crossover):
|
|
10
|
+
|
|
11
|
+
def __init__(self, prob_hux=0.5, **kwargs):
|
|
12
|
+
super().__init__(2, 2, **kwargs)
|
|
13
|
+
self.prob_hux = prob_hux
|
|
14
|
+
|
|
15
|
+
def _do(self, _, X, random_state=None, **kwargs):
|
|
16
|
+
_, n_matings, n_var = X.shape
|
|
17
|
+
|
|
18
|
+
# the mask do to the crossover
|
|
19
|
+
M = np.full((n_matings, n_var), False)
|
|
20
|
+
|
|
21
|
+
not_equal = X[0] != X[1]
|
|
22
|
+
|
|
23
|
+
# create for each individual the crossover range
|
|
24
|
+
for i in range(n_matings):
|
|
25
|
+
I = np.where(not_equal[i])[0]
|
|
26
|
+
|
|
27
|
+
n = math.ceil(len(I) / 2)
|
|
28
|
+
if n > 0:
|
|
29
|
+
_I = I[random_state.permutation(len(I))[:n]]
|
|
30
|
+
M[i, _I] = True
|
|
31
|
+
|
|
32
|
+
_X = crossover_mask(X, M)
|
|
33
|
+
return _X
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class HUX(HalfUniformCrossover):
|
|
37
|
+
pass
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from pymoo.core.crossover import Crossover
|
|
2
|
+
from pymoo.core.population import Population
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class NoCrossover(Crossover):
|
|
6
|
+
def __init__(self, *, n_parents=1, n_offsprings=None, prob=0.0, **kwargs):
|
|
7
|
+
if n_offsprings is None:
|
|
8
|
+
n_offsprings = n_parents
|
|
9
|
+
super().__init__(n_parents, n_offsprings, prob, **kwargs)
|
|
10
|
+
|
|
11
|
+
def do(self, problem, pop, *args, random_state, **kwargs):
|
|
12
|
+
offsprings = []
|
|
13
|
+
for parents in pop:
|
|
14
|
+
if self.n_offsprings < self.n_parents:
|
|
15
|
+
# Select without replacement
|
|
16
|
+
offsprings.extend(random_state.choice(parents, size=self.n_offsprings, replace=False))
|
|
17
|
+
elif self.n_offsprings == self.n_parents:
|
|
18
|
+
# Return all parents as-is
|
|
19
|
+
offsprings.extend(parents)
|
|
20
|
+
else:
|
|
21
|
+
# Keep each parent at least once, then fill randomly
|
|
22
|
+
offsprings.extend(parents)
|
|
23
|
+
extra = self.n_offsprings - self.n_parents
|
|
24
|
+
offsprings.extend(random_state.choice(parents, size=extra, replace=True))
|
|
25
|
+
return Population.create(*offsprings)
|