pymoo 0.6.1.5.dev0__cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pymoo might be problematic. Click here for more details.
- 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-313-x86_64-linux-gnu.so +0 -0
- pymoo/cython/calc_perpendicular_distance.pyx +67 -0
- pymoo/cython/decomposition.cpython-313-x86_64-linux-gnu.so +0 -0
- pymoo/cython/decomposition.pyx +165 -0
- pymoo/cython/hv.cpython-313-x86_64-linux-gnu.so +0 -0
- pymoo/cython/hv.pyx +18 -0
- pymoo/cython/info.cpython-313-x86_64-linux-gnu.so +0 -0
- pymoo/cython/info.pyx +5 -0
- pymoo/cython/mnn.cpython-313-x86_64-linux-gnu.so +0 -0
- pymoo/cython/mnn.pyx +273 -0
- pymoo/cython/non_dominated_sorting.cpython-313-x86_64-linux-gnu.so +0 -0
- pymoo/cython/non_dominated_sorting.pyx +645 -0
- pymoo/cython/pruning_cd.cpython-313-x86_64-linux-gnu.so +0 -0
- pymoo/cython/pruning_cd.pyx +197 -0
- pymoo/cython/stochastic_ranking.cpython-313-x86_64-linux-gnu.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,88 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pymoo.util.misc import vectorized_cdist
|
|
4
|
+
from pymoo.util.ref_dirs.misc import project_onto_sum_equals_zero_plane, project_onto_unit_simplex_recursive
|
|
5
|
+
from pymoo.util.ref_dirs.optimizer import Adam
|
|
6
|
+
from pymoo.util.reference_direction import ReferenceDirectionFactory, map_onto_unit_simplex
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def calc_dist_to_others(x, X):
|
|
10
|
+
return - np.sqrt(((x - X) ** 2).sum(axis=1)).min()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def calc_dist_to_others_with_gradient(x, X):
|
|
14
|
+
diff = (x - X)
|
|
15
|
+
D = np.sqrt((diff ** 2).sum(axis=1))
|
|
16
|
+
|
|
17
|
+
k = D.argmin()
|
|
18
|
+
|
|
19
|
+
obj = - D.min()
|
|
20
|
+
grad = - diff[k] / D[k]
|
|
21
|
+
|
|
22
|
+
return obj, grad
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ConstructionBasedReferenceDirectionFactory(ReferenceDirectionFactory):
|
|
26
|
+
|
|
27
|
+
def __init__(self,
|
|
28
|
+
n_dim,
|
|
29
|
+
n_points,
|
|
30
|
+
n_samples=100,
|
|
31
|
+
gradient_descent=True,
|
|
32
|
+
verbose=False,
|
|
33
|
+
**kwargs):
|
|
34
|
+
|
|
35
|
+
super().__init__(n_dim, **kwargs)
|
|
36
|
+
self.n_points = n_points
|
|
37
|
+
self.gradient_descent = gradient_descent
|
|
38
|
+
self.n_samples = n_samples
|
|
39
|
+
self.verbose = verbose
|
|
40
|
+
self.X = None
|
|
41
|
+
|
|
42
|
+
def _do(self):
|
|
43
|
+
|
|
44
|
+
self.X = np.eye(self.n_dim)
|
|
45
|
+
|
|
46
|
+
while len(self.X) < self.n_points:
|
|
47
|
+
x = self.next()
|
|
48
|
+
self.X = np.row_stack([self.X, x])
|
|
49
|
+
|
|
50
|
+
if self.verbose:
|
|
51
|
+
print(len(self.X), "x", x)
|
|
52
|
+
|
|
53
|
+
return self.X
|
|
54
|
+
|
|
55
|
+
def next(self):
|
|
56
|
+
|
|
57
|
+
x = np.random.random((self.n_samples, self.n_dim))
|
|
58
|
+
x = map_onto_unit_simplex(x, "kraemer")
|
|
59
|
+
x = x[vectorized_cdist(x, self.X).min(axis=1).argmax()]
|
|
60
|
+
|
|
61
|
+
if self.gradient_descent:
|
|
62
|
+
|
|
63
|
+
optimizer = Adam(precision=1e-4)
|
|
64
|
+
|
|
65
|
+
# for each iteration of gradient descent
|
|
66
|
+
for i in range(1000):
|
|
67
|
+
|
|
68
|
+
# calculate the function value and the gradient
|
|
69
|
+
# auto_obj, auto_grad = value_and_grad(calc_dist_to_others)(x, self.X)
|
|
70
|
+
_obj, _grad = calc_dist_to_others_with_gradient(x, self.X)
|
|
71
|
+
|
|
72
|
+
# project the gradient to have a sum of zero - guarantees to stay on the simplex
|
|
73
|
+
proj_grad = project_onto_sum_equals_zero_plane(_grad)
|
|
74
|
+
|
|
75
|
+
# apply a step of gradient descent by subtracting the projected gradient with a learning rate
|
|
76
|
+
x = optimizer.next(x, proj_grad)
|
|
77
|
+
|
|
78
|
+
# project the out of bounds points back onto the unit simplex
|
|
79
|
+
project_onto_unit_simplex_recursive(x[None, :])
|
|
80
|
+
|
|
81
|
+
# because of floating point issues make sure it is on the unit simplex
|
|
82
|
+
x /= x.sum()
|
|
83
|
+
|
|
84
|
+
# if there was only a little movement during the last iteration -> terminate
|
|
85
|
+
if optimizer.has_converged:
|
|
86
|
+
break
|
|
87
|
+
|
|
88
|
+
return x
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from scipy import special
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class DasDennis:
|
|
6
|
+
|
|
7
|
+
def __init__(self, n_partitions, n_dim, scaling=None):
|
|
8
|
+
super().__init__()
|
|
9
|
+
self.n_partitions = n_partitions
|
|
10
|
+
self.n_dim = n_dim
|
|
11
|
+
self.scaling = scaling
|
|
12
|
+
|
|
13
|
+
self.stack = []
|
|
14
|
+
self.stack.append(([], self.n_partitions))
|
|
15
|
+
|
|
16
|
+
def number_of_points(self):
|
|
17
|
+
return int(special.binom(self.n_dim + self.n_partitions - 1, self.n_partitions))
|
|
18
|
+
|
|
19
|
+
def next(self, n_points=None):
|
|
20
|
+
ret = []
|
|
21
|
+
self.traverse(lambda p: ret.append(p), n_points)
|
|
22
|
+
return np.array(ret)
|
|
23
|
+
|
|
24
|
+
def has_next(self):
|
|
25
|
+
return len(self.stack) > 0
|
|
26
|
+
|
|
27
|
+
def traverse(self, func, n_points=None):
|
|
28
|
+
|
|
29
|
+
if self.n_partitions == 0:
|
|
30
|
+
return np.full((1, self.n_dim), 1 / self.n_dim)
|
|
31
|
+
|
|
32
|
+
counter = 0
|
|
33
|
+
|
|
34
|
+
while (n_points is None or counter < n_points) and len(self.stack) > 0:
|
|
35
|
+
|
|
36
|
+
point, beta = self.stack.pop()
|
|
37
|
+
|
|
38
|
+
if len(point) + 1 == self.n_dim:
|
|
39
|
+
point.append(beta / (1.0 * self.n_partitions))
|
|
40
|
+
|
|
41
|
+
if self.scaling is not None:
|
|
42
|
+
point = [p * self.scaling + ((1 - self.scaling) / len(point)) for p in point]
|
|
43
|
+
|
|
44
|
+
func(point)
|
|
45
|
+
counter += 1
|
|
46
|
+
else:
|
|
47
|
+
for i in range(beta + 1):
|
|
48
|
+
_point = list(point)
|
|
49
|
+
_point.append(1.0 * i / (1.0 * self.n_partitions))
|
|
50
|
+
self.stack.append((_point, beta - i))
|
|
51
|
+
|
|
52
|
+
return counter
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pymoo.gradient.grad_autograd import triu_indices, sqrt, log
|
|
4
|
+
from pymoo.util.ref_dirs.construction import ConstructionBasedReferenceDirectionFactory
|
|
5
|
+
from pymoo.util.ref_dirs.misc import project_onto_sum_equals_zero_plane, project_onto_unit_simplex_recursive
|
|
6
|
+
from pymoo.util.ref_dirs.optimizer import Adam
|
|
7
|
+
from pymoo.util.ref_dirs.reduction import ReductionBasedReferenceDirectionFactory
|
|
8
|
+
from pymoo.util.reference_direction import ReferenceDirectionFactory, scale_reference_directions
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class RieszEnergyReferenceDirectionFactory(ReferenceDirectionFactory):
|
|
12
|
+
|
|
13
|
+
def __init__(self,
|
|
14
|
+
n_dim,
|
|
15
|
+
n_points,
|
|
16
|
+
ref_points=None,
|
|
17
|
+
return_as_tuple=False,
|
|
18
|
+
n_max_iter=1000,
|
|
19
|
+
n_until_optimizer_reset=30,
|
|
20
|
+
sampling="reduction",
|
|
21
|
+
norm_gradients=True,
|
|
22
|
+
verify_gradient=False,
|
|
23
|
+
freeze_edges=False,
|
|
24
|
+
precision=1e-5,
|
|
25
|
+
restarts=True,
|
|
26
|
+
X=None,
|
|
27
|
+
d=None,
|
|
28
|
+
callback=None,
|
|
29
|
+
**kwargs):
|
|
30
|
+
|
|
31
|
+
super().__init__(n_dim, **kwargs)
|
|
32
|
+
|
|
33
|
+
self.n_points = n_points
|
|
34
|
+
self.n_max_iter = n_max_iter
|
|
35
|
+
self.n_max_not_improved = n_until_optimizer_reset
|
|
36
|
+
self.return_as_tuple = return_as_tuple
|
|
37
|
+
self.sampling = sampling
|
|
38
|
+
self.X = X
|
|
39
|
+
self.ref_points = ref_points
|
|
40
|
+
self.precision = precision
|
|
41
|
+
self.verify_gradient = verify_gradient
|
|
42
|
+
self.norm_gradients = norm_gradients
|
|
43
|
+
self.freeze_edges = freeze_edges
|
|
44
|
+
self.d = d
|
|
45
|
+
self.callback = callback
|
|
46
|
+
self.restarts = restarts
|
|
47
|
+
|
|
48
|
+
# experiments have shown that dimensions squared is good value to choose here
|
|
49
|
+
if self.d is None:
|
|
50
|
+
self.d = n_dim * 2
|
|
51
|
+
|
|
52
|
+
def _step(self, optimizer, X, freeze=None):
|
|
53
|
+
free = np.logical_not(freeze)
|
|
54
|
+
|
|
55
|
+
obj, grad, mutual_dist = calc_potential_energy_with_grad(X, self.d, return_mutual_dist=True)
|
|
56
|
+
# obj, grad = value_and_grad(calc_potential_energy)(X, self.d)
|
|
57
|
+
|
|
58
|
+
if self.verify_gradient:
|
|
59
|
+
from autograd import value_and_grad
|
|
60
|
+
obj, grad = calc_potential_energy_with_grad(X, self.d)
|
|
61
|
+
_obj, _grad = value_and_grad(calc_potential_energy)(X, self.d)
|
|
62
|
+
if np.abs(grad - _grad).mean() > 1e-5:
|
|
63
|
+
print("GRADIENT IMPLEMENTATION IS INCORRECT!")
|
|
64
|
+
|
|
65
|
+
# set the gradients for frozen points to zero - make them not to move
|
|
66
|
+
if freeze is not None:
|
|
67
|
+
grad[freeze] = 0
|
|
68
|
+
|
|
69
|
+
# project the gradient to have a sum of zero - guarantees to stay on the simplex
|
|
70
|
+
proj_grad = project_onto_sum_equals_zero_plane(grad)
|
|
71
|
+
|
|
72
|
+
# normalize the gradients by the largest gradient norm
|
|
73
|
+
if self.norm_gradients:
|
|
74
|
+
norm = np.linalg.norm(proj_grad, axis=1)
|
|
75
|
+
proj_grad = (proj_grad / max(norm.max(), 1e-24))
|
|
76
|
+
|
|
77
|
+
# apply a step of gradient descent by subtracting the projected gradient with a learning rate
|
|
78
|
+
X = optimizer.next(X, proj_grad)
|
|
79
|
+
|
|
80
|
+
# project the out of bounds points back onto the unit simplex
|
|
81
|
+
X[free] = project_onto_unit_simplex_recursive(X[free])
|
|
82
|
+
|
|
83
|
+
# because of floating point issues make sure it is on the unit simplex
|
|
84
|
+
X /= X.sum(axis=1)[:, None]
|
|
85
|
+
|
|
86
|
+
return X, obj
|
|
87
|
+
|
|
88
|
+
def _solve(self, X, F=None, freeze_edges=True):
|
|
89
|
+
n_points = len(X)
|
|
90
|
+
ret, obj = X, np.inf
|
|
91
|
+
n_not_improved = 0
|
|
92
|
+
|
|
93
|
+
# get the edge mask
|
|
94
|
+
if freeze_edges:
|
|
95
|
+
freeze = np.any(X < 1e-16, axis=1)
|
|
96
|
+
else:
|
|
97
|
+
freeze = np.full(len(X), False)
|
|
98
|
+
|
|
99
|
+
# if additional points to be frozen are provided - add them to the X and mark them as frozen
|
|
100
|
+
if F is not None:
|
|
101
|
+
X = np.row_stack([X, F])
|
|
102
|
+
freeze = np.concatenate([freeze, np.full(len(F), True)])
|
|
103
|
+
|
|
104
|
+
# if all points are frozen - simply return it
|
|
105
|
+
if np.all(freeze):
|
|
106
|
+
return X
|
|
107
|
+
|
|
108
|
+
# initialize the optimizer for the run
|
|
109
|
+
self.optimizer = Adam(alpha=0.005)
|
|
110
|
+
|
|
111
|
+
if self.callback is not None:
|
|
112
|
+
self.callback(self, X)
|
|
113
|
+
|
|
114
|
+
# for each iteration of gradient descent
|
|
115
|
+
for i in range(self.n_max_iter):
|
|
116
|
+
|
|
117
|
+
# execute one optimization step
|
|
118
|
+
_X, _obj = self._step(self.optimizer, X, freeze=freeze)
|
|
119
|
+
|
|
120
|
+
# if it is the current best solution -> store it
|
|
121
|
+
if _obj < obj:
|
|
122
|
+
ret, obj, n_not_improved = _X, _obj, 0
|
|
123
|
+
else:
|
|
124
|
+
n_not_improved += 1
|
|
125
|
+
|
|
126
|
+
# evaluate how much the points have moved
|
|
127
|
+
delta = np.sqrt((_X[:n_points] - X[:n_points]) ** 2).mean(axis=1).mean()
|
|
128
|
+
|
|
129
|
+
if self.verbose:
|
|
130
|
+
print(i, "objective", _obj, "delta", delta)
|
|
131
|
+
|
|
132
|
+
# if there was only a little delta during the last iteration -> terminate
|
|
133
|
+
if delta < self.precision or np.isnan(_obj):
|
|
134
|
+
break
|
|
135
|
+
|
|
136
|
+
# reset the optimizer if the objective value has not improved x iterations
|
|
137
|
+
if self.restarts and n_not_improved > self.n_max_not_improved:
|
|
138
|
+
self.optimizer = Adam(alpha=self.optimizer.alpha / 2)
|
|
139
|
+
_X = ret
|
|
140
|
+
n_not_improved = 0
|
|
141
|
+
|
|
142
|
+
# otherwise use the new points for the next iteration
|
|
143
|
+
X = _X
|
|
144
|
+
|
|
145
|
+
if self.callback is not None:
|
|
146
|
+
self.callback(self, X)
|
|
147
|
+
|
|
148
|
+
return ret[:n_points]
|
|
149
|
+
|
|
150
|
+
def _do(self):
|
|
151
|
+
X = self.X
|
|
152
|
+
|
|
153
|
+
# if no initial points are provided by the user
|
|
154
|
+
if X is None:
|
|
155
|
+
if self.sampling == "reduction":
|
|
156
|
+
X = ReductionBasedReferenceDirectionFactory(self.n_dim,
|
|
157
|
+
self.n_points,
|
|
158
|
+
kmeans=True,
|
|
159
|
+
lexsort=False,
|
|
160
|
+
seed=self.seed) \
|
|
161
|
+
.do()
|
|
162
|
+
|
|
163
|
+
elif self.sampling == "construction":
|
|
164
|
+
X = ConstructionBasedReferenceDirectionFactory(self.n_dim,
|
|
165
|
+
self.n_points,
|
|
166
|
+
seed=self.seed) \
|
|
167
|
+
.do()
|
|
168
|
+
else:
|
|
169
|
+
raise Exception("Unknown sampling method. Either reduction or construction.")
|
|
170
|
+
|
|
171
|
+
X = self._solve(X, freeze_edges=self.freeze_edges)
|
|
172
|
+
|
|
173
|
+
if self.ref_points is not None:
|
|
174
|
+
X, R = self.calc_ref_points(X, self.ref_points)
|
|
175
|
+
|
|
176
|
+
if self.return_as_tuple:
|
|
177
|
+
return X, R
|
|
178
|
+
else:
|
|
179
|
+
return np.row_stack([X, R])
|
|
180
|
+
|
|
181
|
+
return X
|
|
182
|
+
|
|
183
|
+
def calc_ref_points(self, X, ref_points):
|
|
184
|
+
n_points = len(X)
|
|
185
|
+
|
|
186
|
+
# the center needed for translations
|
|
187
|
+
centroid = np.full((1, self.n_dim), 1 / self.n_dim)
|
|
188
|
+
|
|
189
|
+
R = []
|
|
190
|
+
|
|
191
|
+
# for each reference point provided by the user
|
|
192
|
+
for entry in ref_points:
|
|
193
|
+
ref_point, n_points_of_ref = entry.get("coordinates"), entry.get("n_points")
|
|
194
|
+
scale, volume = entry.get("scale"), entry.get("volume")
|
|
195
|
+
|
|
196
|
+
if scale is None:
|
|
197
|
+
if volume is None:
|
|
198
|
+
raise Exception("Either define scale or volume!")
|
|
199
|
+
else:
|
|
200
|
+
scale = volume ** (self.n_dim - 1)
|
|
201
|
+
|
|
202
|
+
# retrieve all points to consider
|
|
203
|
+
_X = np.row_stack([X] + R)
|
|
204
|
+
|
|
205
|
+
# translate X to make the simplex to fill the unit
|
|
206
|
+
v = centroid - ref_point
|
|
207
|
+
X_t = _X + v
|
|
208
|
+
X_t = scale_reference_directions(X_t, 1 / scale)
|
|
209
|
+
|
|
210
|
+
# find the indices of points which are used as edges
|
|
211
|
+
I = np.where(np.any(X_t < 1e-5, axis=1))[0]
|
|
212
|
+
|
|
213
|
+
# create new points in the simplex where reference directions are supposed to be optimized
|
|
214
|
+
_n_points = n_points_of_ref + (n_points - len(I))
|
|
215
|
+
_R = ReductionBasedReferenceDirectionFactory(self.n_dim, n_points=_n_points, kmeans=True,
|
|
216
|
+
lexsort=False).do()
|
|
217
|
+
|
|
218
|
+
# detect the edges and just optimize them and shrink later
|
|
219
|
+
outer = np.any(_R == 0, axis=1)
|
|
220
|
+
inner = ~outer
|
|
221
|
+
|
|
222
|
+
# rescale the reference directions to be not too close to existing points
|
|
223
|
+
_R = scale_reference_directions(_R, 0.9)
|
|
224
|
+
|
|
225
|
+
# optimize just the edges
|
|
226
|
+
_R[outer] = self._solve(_R[outer], F=np.row_stack([X_t[I], _R[inner]]), freeze_edges=False)
|
|
227
|
+
|
|
228
|
+
# no set the reference point and freeze it
|
|
229
|
+
# closest_to_centroid = cdist(centroid, _R).argmin()
|
|
230
|
+
# outer[closest_to_centroid] = True
|
|
231
|
+
# inner[closest_to_centroid] = False
|
|
232
|
+
# _R[closest_to_centroid] = centroid
|
|
233
|
+
|
|
234
|
+
# now when translated the reference point becomes the centroid - fix that point to be included
|
|
235
|
+
_R[inner] = self._solve(_R[inner], F=np.row_stack([X_t[I], _R[outer]]), freeze_edges=False)
|
|
236
|
+
|
|
237
|
+
# rescale and translate them back
|
|
238
|
+
_R_t = scale_reference_directions(_R, scale)
|
|
239
|
+
_R_t = _R_t - v
|
|
240
|
+
|
|
241
|
+
# if any point is out of bounds - volume was too large
|
|
242
|
+
if not np.all(_R_t >= 0):
|
|
243
|
+
|
|
244
|
+
# get the corner points if not transformed
|
|
245
|
+
V = (np.eye(self.n_dim) - centroid)
|
|
246
|
+
|
|
247
|
+
# get the corner points of the ref dir simplex
|
|
248
|
+
P = ref_point + scale * V
|
|
249
|
+
E = centroid + scale * V
|
|
250
|
+
|
|
251
|
+
# project because at least is out of points
|
|
252
|
+
P_proj = project_onto_unit_simplex_recursive(np.copy(P))
|
|
253
|
+
|
|
254
|
+
for i in range(len(P)):
|
|
255
|
+
|
|
256
|
+
if not np.all(P[i] == P_proj[i]):
|
|
257
|
+
_R_t = scale_reference_directions(_R, scale)
|
|
258
|
+
_R_t = _R_t - (E[i] - P_proj[i])
|
|
259
|
+
|
|
260
|
+
if np.all(_R_t >= 0):
|
|
261
|
+
break
|
|
262
|
+
|
|
263
|
+
n_points += n_points_of_ref
|
|
264
|
+
R.append(_R_t)
|
|
265
|
+
|
|
266
|
+
# filter out points from to be removed from the original array
|
|
267
|
+
X = X[[i for i in I if i < len(X)]]
|
|
268
|
+
|
|
269
|
+
R = np.row_stack(R)
|
|
270
|
+
|
|
271
|
+
return X, R
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
275
|
+
# Energy Functions
|
|
276
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def squared_dist(A, B):
|
|
280
|
+
return ((A[:, None] - B[None, :]) ** 2).sum(axis=2)
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def calc_potential_energy(A, d):
|
|
284
|
+
i, j = triu_indices(len(A), 1)
|
|
285
|
+
D = sqrt(squared_dist(A, A)[i, j])
|
|
286
|
+
energy = log((1 / D ** d).mean())
|
|
287
|
+
return energy
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def calc_potential_energy_with_grad(x, d, return_mutual_dist=False):
|
|
291
|
+
diff = (x[:, None] - x[None, :])
|
|
292
|
+
# calculate the squared euclidean from each point to another
|
|
293
|
+
dist = np.sqrt((diff ** 2).sum(axis=2))
|
|
294
|
+
|
|
295
|
+
# make sure the distance to itself does not count
|
|
296
|
+
np.fill_diagonal(dist, np.inf)
|
|
297
|
+
|
|
298
|
+
# epsilon which is the smallest distance possible to avoid an overflow during gradient calculation
|
|
299
|
+
eps = 10 ** (-320 / (d + 2))
|
|
300
|
+
b = dist < eps
|
|
301
|
+
dist[b] = eps
|
|
302
|
+
|
|
303
|
+
# select only upper triangular matrix to have each mutual distance once
|
|
304
|
+
mutual_dist = dist[np.triu_indices(len(x), 1)]
|
|
305
|
+
|
|
306
|
+
# calculate the energy by summing up the squared distances
|
|
307
|
+
energy = (1 / mutual_dist ** d).sum()
|
|
308
|
+
log_energy = - np.log(len(mutual_dist)) + np.log(energy)
|
|
309
|
+
|
|
310
|
+
# calculate the gradient
|
|
311
|
+
grad = (-d * diff) / (dist ** (d + 2))[..., None]
|
|
312
|
+
grad = np.sum(grad, axis=1)
|
|
313
|
+
grad /= energy
|
|
314
|
+
|
|
315
|
+
ret = [log_energy, grad]
|
|
316
|
+
if return_mutual_dist:
|
|
317
|
+
ret.append(mutual_dist)
|
|
318
|
+
|
|
319
|
+
return tuple(ret)
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from pymoo.gradient.grad_autograd import value_and_grad, triu_indices, row_stack
|
|
6
|
+
from pymoo.util.normalization import normalize
|
|
7
|
+
from pymoo.util.ref_dirs.energy import squared_dist
|
|
8
|
+
from pymoo.util.ref_dirs.optimizer import Adam
|
|
9
|
+
from pymoo.util.reference_direction import ReferenceDirectionFactory, scale_reference_directions
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class LayerwiseRieszEnergyReferenceDirectionFactory(ReferenceDirectionFactory):
|
|
13
|
+
|
|
14
|
+
def __init__(self,
|
|
15
|
+
n_dim,
|
|
16
|
+
partitions,
|
|
17
|
+
return_as_tuple=False,
|
|
18
|
+
n_max_iter=1000,
|
|
19
|
+
verbose=False,
|
|
20
|
+
X=None,
|
|
21
|
+
**kwargs):
|
|
22
|
+
|
|
23
|
+
super().__init__(n_dim, **kwargs)
|
|
24
|
+
self.scalings = None
|
|
25
|
+
self.n_max_iter = n_max_iter
|
|
26
|
+
self.verbose = verbose
|
|
27
|
+
self.return_as_tuple = return_as_tuple
|
|
28
|
+
self.X = X
|
|
29
|
+
self.partitions = partitions
|
|
30
|
+
|
|
31
|
+
def _step(self, optimizer, X, scalings):
|
|
32
|
+
obj, grad = value_and_grad(calc_potential_energy)(scalings, X)
|
|
33
|
+
scalings = optimizer.next(scalings, np.array(grad))
|
|
34
|
+
scalings = normalize(scalings, xl=0, xu=scalings.max())
|
|
35
|
+
return scalings, obj
|
|
36
|
+
|
|
37
|
+
def _solve(self, X, scalings):
|
|
38
|
+
|
|
39
|
+
# initialize the optimizer for the run
|
|
40
|
+
optimizer = Adam()
|
|
41
|
+
|
|
42
|
+
# for each iteration of gradient descent
|
|
43
|
+
for i in range(self.n_max_iter):
|
|
44
|
+
|
|
45
|
+
# execute one optimization step
|
|
46
|
+
_scalings, _obj = self._step(optimizer, X, scalings)
|
|
47
|
+
|
|
48
|
+
# evaluate how much the points have moved
|
|
49
|
+
delta = np.abs(_scalings - scalings).sum()
|
|
50
|
+
|
|
51
|
+
if self.verbose:
|
|
52
|
+
print(i, "objective", _obj, "delta", delta)
|
|
53
|
+
|
|
54
|
+
# if there was only a little delta during the last iteration -> terminate
|
|
55
|
+
if delta < 1e-5:
|
|
56
|
+
scalings = _scalings
|
|
57
|
+
break
|
|
58
|
+
|
|
59
|
+
# otherwise use the new points for the next iteration
|
|
60
|
+
scalings = _scalings
|
|
61
|
+
|
|
62
|
+
self.scalings = scalings
|
|
63
|
+
return get_points(X, scalings)
|
|
64
|
+
|
|
65
|
+
def do(self):
|
|
66
|
+
|
|
67
|
+
X = []
|
|
68
|
+
scalings = []
|
|
69
|
+
|
|
70
|
+
for k, p in enumerate(self.partitions):
|
|
71
|
+
|
|
72
|
+
if p > 1:
|
|
73
|
+
val = np.linspace(0, 1, p + 1)[1:-1]
|
|
74
|
+
_X = []
|
|
75
|
+
for i in range(self.n_dim):
|
|
76
|
+
for j in range(i + 1, self.n_dim):
|
|
77
|
+
x = np.zeros((len(val), self.n_dim))
|
|
78
|
+
x[:, i] = val
|
|
79
|
+
x[:, j] = 1 - val
|
|
80
|
+
_X.append(x)
|
|
81
|
+
|
|
82
|
+
X.append(np.row_stack(_X + [np.eye(self.n_dim)]))
|
|
83
|
+
|
|
84
|
+
elif p == 1:
|
|
85
|
+
X.append(np.eye(self.n_dim))
|
|
86
|
+
else:
|
|
87
|
+
X.append(np.full(self.n_dim, 1 / self.n_dim)[None, :])
|
|
88
|
+
|
|
89
|
+
scalings.append(1 - k / len(self.partitions))
|
|
90
|
+
|
|
91
|
+
scalings = np.array(scalings)
|
|
92
|
+
X = self._solve(X, scalings)
|
|
93
|
+
|
|
94
|
+
return X
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
98
|
+
# Energy Functions
|
|
99
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def get_points(X, scalings):
|
|
103
|
+
vals = []
|
|
104
|
+
for i in range(len(X)):
|
|
105
|
+
vals.append(scale_reference_directions(X[i], scalings[i]))
|
|
106
|
+
X = row_stack(vals)
|
|
107
|
+
return X
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def calc_potential_energy(scalings, X):
|
|
111
|
+
X = get_points(X, scalings)
|
|
112
|
+
|
|
113
|
+
i, j = triu_indices(len(X), 1)
|
|
114
|
+
D = squared_dist(X, X)[i, j]
|
|
115
|
+
|
|
116
|
+
if np.any(D < 1e-12):
|
|
117
|
+
return np.nan, np.nan
|
|
118
|
+
|
|
119
|
+
return (1 / D).mean()
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from pymoo.algorithms.soo.nonconvex.ga import GA
|
|
2
|
+
from pymoo.core.problem import Problem
|
|
3
|
+
from pymoo.optimize import minimize
|
|
4
|
+
from pymoo.util.reference_direction import get_partition_closest_to_points, ReferenceDirectionFactory
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ReferenceDirectionGA(ReferenceDirectionFactory):
|
|
8
|
+
|
|
9
|
+
def __init__(self,
|
|
10
|
+
n_dim,
|
|
11
|
+
n_points,
|
|
12
|
+
fun,
|
|
13
|
+
pop_size=20,
|
|
14
|
+
n_gen=200,
|
|
15
|
+
verbose=False,
|
|
16
|
+
**kwargs):
|
|
17
|
+
|
|
18
|
+
super().__init__(n_dim, **kwargs)
|
|
19
|
+
|
|
20
|
+
self.n_points = n_points
|
|
21
|
+
self.pop_size = pop_size
|
|
22
|
+
self.n_gen = n_gen
|
|
23
|
+
|
|
24
|
+
self.fun = fun
|
|
25
|
+
self.verbose = verbose
|
|
26
|
+
|
|
27
|
+
def _do(self):
|
|
28
|
+
pop_size, n_gen = self.pop_size, self.n_gen
|
|
29
|
+
n_points, n_dim, = self.n_points, self.n_dim
|
|
30
|
+
fun = self.fun
|
|
31
|
+
|
|
32
|
+
class MyProblem(Problem):
|
|
33
|
+
|
|
34
|
+
def __init__(self):
|
|
35
|
+
self.n_points = n_points
|
|
36
|
+
self.n_dim = n_dim
|
|
37
|
+
self.n_partitions = get_partition_closest_to_points(n_points, n_dim)
|
|
38
|
+
|
|
39
|
+
super().__init__(n_var=n_points * n_dim,
|
|
40
|
+
n_obj=1,
|
|
41
|
+
xl=0.0,
|
|
42
|
+
xu=1.0,
|
|
43
|
+
elementwise_evaluation=True)
|
|
44
|
+
|
|
45
|
+
def get_points(self, x):
|
|
46
|
+
_x = x.reshape((self.n_points, self.n_dim)) ** 2
|
|
47
|
+
_x = _x / _x.sum(axis=1)[:, None]
|
|
48
|
+
return _x
|
|
49
|
+
|
|
50
|
+
def _evaluate(self, x, out, *args, **kwargs):
|
|
51
|
+
out["F"] = fun(self.get_points(x))
|
|
52
|
+
|
|
53
|
+
problem = MyProblem()
|
|
54
|
+
|
|
55
|
+
algorithm = GA(pop_size=pop_size, eliminate_duplicates=True)
|
|
56
|
+
|
|
57
|
+
res = minimize(problem,
|
|
58
|
+
algorithm,
|
|
59
|
+
termination=('n_gen', n_gen),
|
|
60
|
+
verbose=True)
|
|
61
|
+
|
|
62
|
+
ref_dirs = problem.get_points(res.X)
|
|
63
|
+
return ref_dirs
|