pydmoo 0.0.18__py3-none-any.whl → 0.1.0__py3-none-any.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.
- pydmoo/algorithms/base/__init__.py +20 -0
- pydmoo/algorithms/base/core/__init__.py +0 -0
- pydmoo/algorithms/base/core/algorithm.py +416 -0
- pydmoo/algorithms/base/core/genetic.py +129 -0
- pydmoo/algorithms/base/dmoo/__init__.py +0 -0
- pydmoo/algorithms/base/dmoo/dmoead.py +131 -0
- pydmoo/algorithms/base/dmoo/dmoeadde.py +131 -0
- pydmoo/algorithms/base/dmoo/dmopso.py +0 -0
- pydmoo/algorithms/base/dmoo/dnsga2.py +137 -0
- pydmoo/algorithms/base/moo/__init__.py +0 -0
- pydmoo/algorithms/base/moo/moead.py +199 -0
- pydmoo/algorithms/base/moo/moeadde.py +105 -0
- pydmoo/algorithms/base/moo/mopso.py +0 -0
- pydmoo/algorithms/base/moo/nsga2.py +122 -0
- pydmoo/algorithms/modern/__init__.py +94 -0
- pydmoo/algorithms/modern/moead_imkt.py +161 -0
- pydmoo/algorithms/modern/moead_imkt_igp.py +56 -0
- pydmoo/algorithms/modern/moead_imkt_lstm.py +109 -0
- pydmoo/algorithms/modern/moead_imkt_n.py +117 -0
- pydmoo/algorithms/modern/moead_imkt_n_igp.py +56 -0
- pydmoo/algorithms/modern/moead_imkt_n_lstm.py +111 -0
- pydmoo/algorithms/modern/moead_ktmm.py +112 -0
- pydmoo/algorithms/modern/moeadde_imkt.py +161 -0
- pydmoo/algorithms/modern/moeadde_imkt_clstm.py +223 -0
- pydmoo/algorithms/modern/moeadde_imkt_igp.py +56 -0
- pydmoo/algorithms/modern/moeadde_imkt_lstm.py +212 -0
- pydmoo/algorithms/modern/moeadde_imkt_n.py +117 -0
- pydmoo/algorithms/modern/moeadde_imkt_n_clstm.py +146 -0
- pydmoo/algorithms/modern/moeadde_imkt_n_igp.py +56 -0
- pydmoo/algorithms/modern/moeadde_imkt_n_lstm.py +114 -0
- pydmoo/algorithms/modern/moeadde_ktmm.py +112 -0
- pydmoo/algorithms/modern/nsga2_imkt.py +162 -0
- pydmoo/algorithms/modern/nsga2_imkt_clstm.py +223 -0
- pydmoo/algorithms/modern/nsga2_imkt_igp.py +56 -0
- pydmoo/algorithms/modern/nsga2_imkt_lstm.py +248 -0
- pydmoo/algorithms/modern/nsga2_imkt_n.py +117 -0
- pydmoo/algorithms/modern/nsga2_imkt_n_clstm.py +146 -0
- pydmoo/algorithms/modern/nsga2_imkt_n_igp.py +57 -0
- pydmoo/algorithms/modern/nsga2_imkt_n_lstm.py +154 -0
- pydmoo/algorithms/modern/nsga2_ktmm.py +112 -0
- pydmoo/algorithms/utils/__init__.py +0 -0
- pydmoo/algorithms/utils/utils.py +166 -0
- pydmoo/core/__init__.py +0 -0
- pydmoo/{response → core}/ar_model.py +4 -4
- pydmoo/{response → core}/bounds.py +35 -2
- pydmoo/core/distance.py +45 -0
- pydmoo/core/inverse.py +55 -0
- pydmoo/core/lstm/__init__.py +0 -0
- pydmoo/core/lstm/base.py +291 -0
- pydmoo/core/lstm/lstm.py +491 -0
- pydmoo/core/manifold.py +93 -0
- pydmoo/core/predictions.py +50 -0
- pydmoo/core/sample_gaussian.py +56 -0
- pydmoo/core/sample_uniform.py +63 -0
- pydmoo/{response/tca_model.py → core/transfer.py} +3 -3
- pydmoo/problems/__init__.py +53 -49
- pydmoo/problems/dyn.py +94 -13
- pydmoo/problems/dynamic/cec2015.py +10 -5
- pydmoo/problems/dynamic/df.py +6 -3
- pydmoo/problems/dynamic/gts.py +69 -34
- pydmoo/problems/real_world/__init__.py +0 -0
- pydmoo/problems/real_world/dsrp.py +168 -0
- pydmoo/problems/real_world/dwbdp.py +189 -0
- {pydmoo-0.0.18.dist-info → pydmoo-0.1.0.dist-info}/METADATA +11 -10
- pydmoo-0.1.0.dist-info/RECORD +70 -0
- {pydmoo-0.0.18.dist-info → pydmoo-0.1.0.dist-info}/WHEEL +1 -1
- pydmoo-0.0.18.dist-info/RECORD +0 -15
- /pydmoo/{response → algorithms}/__init__.py +0 -0
- {pydmoo-0.0.18.dist-info → pydmoo-0.1.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from pymoo.core.population import Population
|
|
3
|
+
from pymoo.operators.survival.rank_and_crowding import RankAndCrowding
|
|
4
|
+
|
|
5
|
+
from pydmoo.algorithms.base.dmoo.dmoeadde import DMOEADDE
|
|
6
|
+
from pydmoo.core.sample_gaussian import univariate_gaussian_sample
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class MOEADDEKTMM(DMOEADDE):
|
|
10
|
+
"""Knowledge Transfer with Mixture Model.
|
|
11
|
+
|
|
12
|
+
Zou, J., Hou, Z., Jiang, S., Yang, S., Ruan, G., Xia, Y., and Liu, Y. (2025).
|
|
13
|
+
Knowledge transfer with mixture model in dynamic multi-objective optimization.
|
|
14
|
+
IEEE Transactions on Evolutionary Computation, in press.
|
|
15
|
+
https://doi.org/10.1109/TEVC.2025.3566481
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, **kwargs):
|
|
19
|
+
|
|
20
|
+
super().__init__(**kwargs)
|
|
21
|
+
|
|
22
|
+
self.size_pool = 14 # the size of knowledge pool
|
|
23
|
+
self.denominator = 0.5
|
|
24
|
+
|
|
25
|
+
def _response_change(self):
|
|
26
|
+
pop = self.pop
|
|
27
|
+
X = pop.get("X")
|
|
28
|
+
|
|
29
|
+
# recreate the current population without being evaluated
|
|
30
|
+
pop = Population.new(X=X)
|
|
31
|
+
|
|
32
|
+
# sample self.pop_size solutions in decision space
|
|
33
|
+
samples_old = self.sampling_new_pop()
|
|
34
|
+
|
|
35
|
+
# select self.pop_size/2 individuals with better convergence and diversity
|
|
36
|
+
samples = samples_old[:int(len(samples_old)/2)]
|
|
37
|
+
|
|
38
|
+
# knowledge in decision space
|
|
39
|
+
means_stds_ps, mean, std = self._in_decision_or_objective_space_1d(samples, "decision_space")
|
|
40
|
+
mean_new, std_new = self._select_means_stds(means_stds_ps, mean, std)
|
|
41
|
+
|
|
42
|
+
# sample self.pop_size solutions in decision space
|
|
43
|
+
X = univariate_gaussian_sample(mean_new, std_new, self.pop_size, random_state=self.random_state)
|
|
44
|
+
|
|
45
|
+
# bounds
|
|
46
|
+
if self.problem.has_bounds():
|
|
47
|
+
xl, xu = self.problem.bounds()
|
|
48
|
+
X = np.clip(X, xl, xu) # not provided in the original reference literature
|
|
49
|
+
|
|
50
|
+
# merge
|
|
51
|
+
pop = Population.merge(samples_old, Population.new(X=X))
|
|
52
|
+
|
|
53
|
+
return pop
|
|
54
|
+
|
|
55
|
+
def _in_decision_or_objective_space_1d(self, samples, decision_or_objective="decision_space"):
|
|
56
|
+
# decision space or objective space
|
|
57
|
+
flag = "X" if decision_or_objective == "decision_space" else "F"
|
|
58
|
+
|
|
59
|
+
means_stds = self.data.get("means_stds", [])
|
|
60
|
+
|
|
61
|
+
flag_value = self.opt.get(flag)
|
|
62
|
+
if len(flag_value) <= 1:
|
|
63
|
+
flag_value = self.pop.get(flag)
|
|
64
|
+
flag_value = flag_value[:2]
|
|
65
|
+
|
|
66
|
+
means_stds.append((np.mean(flag_value, axis=0), np.std(flag_value, axis=0), self.n_iter - 1)) # 1-based
|
|
67
|
+
self.data["means_stds"] = means_stds
|
|
68
|
+
|
|
69
|
+
flag_value = samples.get(flag)
|
|
70
|
+
mean, std = np.mean(flag_value, axis=0), np.std(flag_value, axis=0)
|
|
71
|
+
return means_stds, mean, std
|
|
72
|
+
|
|
73
|
+
def sampling_new_pop(self):
|
|
74
|
+
samples = self.initialization.sampling(self.problem, self.pop_size)
|
|
75
|
+
samples = self.evaluator.eval(self.problem, samples)
|
|
76
|
+
|
|
77
|
+
# do a survival to recreate rank and crowding of all individuals
|
|
78
|
+
samples = RankAndCrowding().do(self.problem, samples, n_survive=len(samples))
|
|
79
|
+
return samples
|
|
80
|
+
|
|
81
|
+
def _select_means_stds(self, means_stds, mean_new, std_new):
|
|
82
|
+
# Unpack means and stds
|
|
83
|
+
means = np.array([m[0] for m in means_stds])
|
|
84
|
+
stds = np.array([m[1] for m in means_stds])
|
|
85
|
+
|
|
86
|
+
# Calculate distances
|
|
87
|
+
mean_diffs = means - mean_new
|
|
88
|
+
std_diffs = stds - std_new
|
|
89
|
+
|
|
90
|
+
distances = np.sqrt(np.sum(mean_diffs**2, axis=1) + np.sum(std_diffs**2, axis=1))
|
|
91
|
+
|
|
92
|
+
# Get top K closest
|
|
93
|
+
top_k_idx = np.argsort(distances)[:self.size_pool]
|
|
94
|
+
top_k_dist = distances[top_k_idx]
|
|
95
|
+
top_k_means = means[top_k_idx]
|
|
96
|
+
top_k_stds = stds[top_k_idx]
|
|
97
|
+
|
|
98
|
+
# Update pool
|
|
99
|
+
self._update_means_stds_pool(means_stds, top_k_idx)
|
|
100
|
+
|
|
101
|
+
# Calculate weights
|
|
102
|
+
weights = 1 / (top_k_dist + 1e-8) # Add small epsilon to avoid division by zero
|
|
103
|
+
weights = weights / (np.sum(weights) + self.denominator)
|
|
104
|
+
|
|
105
|
+
# Weighted combination
|
|
106
|
+
mean_new = (1 - np.sum(weights)) * mean_new + np.sum(weights[:, None] * top_k_means, axis=0)
|
|
107
|
+
std_new = (1 - np.sum(weights)) * std_new + np.sum(weights[:, None] * top_k_stds, axis=0)
|
|
108
|
+
return mean_new, std_new
|
|
109
|
+
|
|
110
|
+
def _update_means_stds_pool(self, means_stds, top_k_idx) -> None:
|
|
111
|
+
self.data["means_stds"] = [means_stds[i] for i in top_k_idx]
|
|
112
|
+
return None
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from pymoo.core.population import Population
|
|
3
|
+
from pymoo.operators.survival.rank_and_crowding import RankAndCrowding
|
|
4
|
+
|
|
5
|
+
from pydmoo.algorithms.modern.nsga2_ktmm import NSGA2KTMM
|
|
6
|
+
from pydmoo.core.bounds import clip_and_randomize
|
|
7
|
+
from pydmoo.core.inverse import closed_form_solution
|
|
8
|
+
from pydmoo.core.sample_gaussian import univariate_gaussian_sample
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class NSGA2IMKT(NSGA2KTMM):
|
|
12
|
+
"""Inverse Modeling with Knowledge Transfer.
|
|
13
|
+
|
|
14
|
+
Inverse Modeling for Dynamic Multiobjective Optimization with Knowledge Transfer In objective Space.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, **kwargs):
|
|
18
|
+
super().__init__(**kwargs)
|
|
19
|
+
self.size_pool = 10
|
|
20
|
+
self.denominator = 0.5
|
|
21
|
+
|
|
22
|
+
def _response_change(self):
|
|
23
|
+
"""Inverse Modeling with Knowledge Transfer."""
|
|
24
|
+
pop = self.pop
|
|
25
|
+
X = pop.get("X")
|
|
26
|
+
|
|
27
|
+
# recreate the current population without being evaluated
|
|
28
|
+
pop = Population.new(X=X)
|
|
29
|
+
|
|
30
|
+
# sample self.pop_size individuals in decision space
|
|
31
|
+
samples_old = self.sampling_new_pop()
|
|
32
|
+
|
|
33
|
+
# select self.pop_size/2 individuals with better convergence and diversity
|
|
34
|
+
samples = samples_old[:int(len(samples_old)/2)]
|
|
35
|
+
|
|
36
|
+
# knowledge in objective space
|
|
37
|
+
means_stds, mean, std = self._in_decision_or_objective_space_1d(samples, "objective_space")
|
|
38
|
+
mean_new, std_new = self._select_means_stds(means_stds, mean, std)
|
|
39
|
+
|
|
40
|
+
# sample self.pop_size individuals in objective space
|
|
41
|
+
F = univariate_gaussian_sample(mean_new, std_new, self.pop_size, random_state=self.random_state)
|
|
42
|
+
|
|
43
|
+
# TODO
|
|
44
|
+
# inverse mapping
|
|
45
|
+
# X = FB
|
|
46
|
+
B = closed_form_solution(samples.get("X"), samples.get("F"))
|
|
47
|
+
|
|
48
|
+
# X = FB
|
|
49
|
+
X = np.dot(F, B)
|
|
50
|
+
|
|
51
|
+
# bounds
|
|
52
|
+
if self.problem.has_bounds():
|
|
53
|
+
xl, xu = self.problem.bounds()
|
|
54
|
+
X = clip_and_randomize(X, xl, xu, random_state=self.random_state)
|
|
55
|
+
|
|
56
|
+
# merge
|
|
57
|
+
pop = Population.merge(samples_old, Population.new(X=X))
|
|
58
|
+
|
|
59
|
+
return pop
|
|
60
|
+
|
|
61
|
+
def sampling_new_pop(self):
|
|
62
|
+
X = self.pop.get("X")
|
|
63
|
+
|
|
64
|
+
if not self.problem.has_constraints():
|
|
65
|
+
|
|
66
|
+
last_X = self.data.get("last_X", [])
|
|
67
|
+
if len(last_X) == 0:
|
|
68
|
+
last_X = X
|
|
69
|
+
self.data["last_X"] = X
|
|
70
|
+
|
|
71
|
+
d = np.mean(X - last_X, axis=0)
|
|
72
|
+
|
|
73
|
+
radius = max(np.linalg.norm(d) / self.problem.n_obj, 0.1)
|
|
74
|
+
|
|
75
|
+
X = X + d + self.random_state.uniform(low=-radius, high=radius, size=X.shape)
|
|
76
|
+
|
|
77
|
+
# bounds
|
|
78
|
+
if self.problem.has_bounds():
|
|
79
|
+
xl, xu = self.problem.bounds()
|
|
80
|
+
X = clip_and_randomize(X, xl, xu, random_state=self.random_state)
|
|
81
|
+
|
|
82
|
+
samples = Population.new(X=X)
|
|
83
|
+
samples = self.evaluator.eval(self.problem, samples)
|
|
84
|
+
|
|
85
|
+
# do a survival to recreate rank and crowding of all individuals
|
|
86
|
+
samples = RankAndCrowding().do(self.problem, samples, n_survive=len(samples))
|
|
87
|
+
return samples
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class NSGA2IMKT0(NSGA2IMKT):
|
|
91
|
+
def __init__(self, **kwargs):
|
|
92
|
+
super().__init__(**kwargs)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class NSGA2IMKT1(NSGA2IMKT):
|
|
96
|
+
def __init__(self, **kwargs):
|
|
97
|
+
super().__init__(**kwargs)
|
|
98
|
+
self.size_pool = 2
|
|
99
|
+
self.denominator = 0.5
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class NSGA2IMKT2(NSGA2IMKT):
|
|
103
|
+
def __init__(self, **kwargs):
|
|
104
|
+
super().__init__(**kwargs)
|
|
105
|
+
self.size_pool = 4
|
|
106
|
+
self.denominator = 0.5
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class NSGA2IMKT3(NSGA2IMKT):
|
|
110
|
+
def __init__(self, **kwargs):
|
|
111
|
+
super().__init__(**kwargs)
|
|
112
|
+
self.size_pool = 6
|
|
113
|
+
self.denominator = 0.5
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class NSGA2IMKT4(NSGA2IMKT):
|
|
117
|
+
def __init__(self, **kwargs):
|
|
118
|
+
super().__init__(**kwargs)
|
|
119
|
+
self.size_pool = 8
|
|
120
|
+
self.denominator = 0.5
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class NSGA2IMKT5(NSGA2IMKT):
|
|
124
|
+
def __init__(self, **kwargs):
|
|
125
|
+
super().__init__(**kwargs)
|
|
126
|
+
self.size_pool = 10
|
|
127
|
+
self.denominator = 0.5
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class NSGA2IMKT6(NSGA2IMKT):
|
|
131
|
+
def __init__(self, **kwargs):
|
|
132
|
+
super().__init__(**kwargs)
|
|
133
|
+
self.size_pool = 12
|
|
134
|
+
self.denominator = 0.5
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class NSGA2IMKT7(NSGA2IMKT):
|
|
138
|
+
def __init__(self, **kwargs):
|
|
139
|
+
super().__init__(**kwargs)
|
|
140
|
+
self.size_pool = 14
|
|
141
|
+
self.denominator = 0.5
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class NSGA2IMKT8(NSGA2IMKT):
|
|
145
|
+
def __init__(self, **kwargs):
|
|
146
|
+
super().__init__(**kwargs)
|
|
147
|
+
self.size_pool = 16
|
|
148
|
+
self.denominator = 0.5
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class NSGA2IMKT9(NSGA2IMKT):
|
|
152
|
+
def __init__(self, **kwargs):
|
|
153
|
+
super().__init__(**kwargs)
|
|
154
|
+
self.size_pool = 18
|
|
155
|
+
self.denominator = 0.5
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class NSGA2IMKT10(NSGA2IMKT):
|
|
159
|
+
def __init__(self, **kwargs):
|
|
160
|
+
super().__init__(**kwargs)
|
|
161
|
+
self.size_pool = 20
|
|
162
|
+
self.denominator = 0.5
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from pymoo.core.population import Population
|
|
3
|
+
from pymoo.operators.survival.rank_and_crowding import RankAndCrowding
|
|
4
|
+
|
|
5
|
+
from pydmoo.algorithms.modern.nsga2_imkt import NSGA2IMKT
|
|
6
|
+
from pydmoo.algorithms.modern.nsga2_imkt_lstm import prepare_data_means_std
|
|
7
|
+
from pydmoo.core.bounds import clip_and_randomize
|
|
8
|
+
from pydmoo.core.inverse import closed_form_solution
|
|
9
|
+
from pydmoo.core.lstm.lstm import LSTMpredictor
|
|
10
|
+
from pydmoo.core.sample_gaussian import univariate_gaussian_sample
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class NSGA2IMcLSTM(NSGA2IMKT):
|
|
14
|
+
def __init__(self, **kwargs):
|
|
15
|
+
super().__init__(**kwargs)
|
|
16
|
+
|
|
17
|
+
self._n_timesteps = 10
|
|
18
|
+
self._sequence_length = 5 # Use 5 historical time steps to predict next step
|
|
19
|
+
self._incremental_learning = False
|
|
20
|
+
|
|
21
|
+
def _setup(self, problem, **kwargs):
|
|
22
|
+
super()._setup(problem, **kwargs)
|
|
23
|
+
|
|
24
|
+
# Must be here
|
|
25
|
+
self._lstm = LSTMpredictor(
|
|
26
|
+
self._sequence_length,
|
|
27
|
+
hidden_dim=64,
|
|
28
|
+
num_layers=1,
|
|
29
|
+
epochs=50,
|
|
30
|
+
batch_size=32,
|
|
31
|
+
lr=0.001,
|
|
32
|
+
device="cpu", # for fair comparison
|
|
33
|
+
patience=5,
|
|
34
|
+
seed=self.seed,
|
|
35
|
+
model_type="lstm",
|
|
36
|
+
incremental_learning=self._incremental_learning,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
def _response_change(self):
|
|
40
|
+
pop = self.pop
|
|
41
|
+
X = pop.get("X")
|
|
42
|
+
|
|
43
|
+
# recreate the current population without being evaluated
|
|
44
|
+
pop = Population.new(X=X)
|
|
45
|
+
|
|
46
|
+
# sample self.pop_size individuals in decision space
|
|
47
|
+
samples_old = self.sampling_new_pop()
|
|
48
|
+
|
|
49
|
+
# select self.pop_size/2 individuals with better convergence and diversity
|
|
50
|
+
samples = samples_old[:int(len(samples_old)/2)]
|
|
51
|
+
|
|
52
|
+
# knowledge in objective space
|
|
53
|
+
means_stds, mean, std = self._in_decision_or_objective_space_1d(samples, "objective_space")
|
|
54
|
+
|
|
55
|
+
# Check if sufficient historical data is available for LSTM prediction
|
|
56
|
+
if len(means_stds) > self._n_timesteps:
|
|
57
|
+
# Update pool
|
|
58
|
+
self.data["means_stds"] = means_stds[self._n_timesteps:]
|
|
59
|
+
|
|
60
|
+
# Prepare time series data from historical means and standard deviations
|
|
61
|
+
time_series_data = prepare_data_means_std(self._n_timesteps, means_stds)
|
|
62
|
+
|
|
63
|
+
# Initialize predictor and generate prediction for next time step
|
|
64
|
+
next_prediction = self._lstm.convert_train_predict(time_series_data)
|
|
65
|
+
|
|
66
|
+
# Convert prediction tensor to numpy array for further processing
|
|
67
|
+
next_prediction = next_prediction.numpy()
|
|
68
|
+
|
|
69
|
+
# Split prediction into mean and standard deviation components
|
|
70
|
+
# First n_obj elements represent mean values, remaining elements represent standard deviations
|
|
71
|
+
mean_new, std_new = next_prediction[:self.problem.n_obj], next_prediction[self.problem.n_obj:]
|
|
72
|
+
std_new = np.abs(std_new)
|
|
73
|
+
|
|
74
|
+
else:
|
|
75
|
+
mean_new, std_new = self._select_means_stds(means_stds, mean, std)
|
|
76
|
+
|
|
77
|
+
# sample self.pop_size individuals in objective space
|
|
78
|
+
F = univariate_gaussian_sample(mean_new, std_new, self.pop_size, random_state=self.random_state)
|
|
79
|
+
|
|
80
|
+
# TODO
|
|
81
|
+
# inverse mapping
|
|
82
|
+
# X = FB
|
|
83
|
+
B = closed_form_solution(samples.get("X"), samples.get("F"))
|
|
84
|
+
|
|
85
|
+
# X = FB
|
|
86
|
+
X = np.dot(F, B)
|
|
87
|
+
|
|
88
|
+
# bounds
|
|
89
|
+
if self.problem.has_bounds():
|
|
90
|
+
xl, xu = self.problem.bounds()
|
|
91
|
+
X = clip_and_randomize(X, xl, xu, random_state=self.random_state)
|
|
92
|
+
|
|
93
|
+
# merge
|
|
94
|
+
pop = Population.merge(samples_old, Population.new(X=X))
|
|
95
|
+
|
|
96
|
+
return pop
|
|
97
|
+
|
|
98
|
+
def sampling_new_pop(self):
|
|
99
|
+
ps = self.opt.get("X")
|
|
100
|
+
X = self.pop.get("X")
|
|
101
|
+
|
|
102
|
+
if not self.problem.has_constraints():
|
|
103
|
+
|
|
104
|
+
last_ps = self.data.get("last_ps", [])
|
|
105
|
+
if len(last_ps) == 0:
|
|
106
|
+
last_ps = ps
|
|
107
|
+
self.data["last_ps"] = ps
|
|
108
|
+
|
|
109
|
+
d = np.mean(ps, axis=0) - np.mean(last_ps, axis=0)
|
|
110
|
+
|
|
111
|
+
radius = max(np.linalg.norm(d) / self.problem.n_obj, 0.1)
|
|
112
|
+
|
|
113
|
+
X = X + d + self.random_state.uniform(low=-radius, high=radius, size=X.shape)
|
|
114
|
+
|
|
115
|
+
# bounds
|
|
116
|
+
if self.problem.has_bounds():
|
|
117
|
+
xl, xu = self.problem.bounds()
|
|
118
|
+
X = clip_and_randomize(X, xl, xu, random_state=self.random_state)
|
|
119
|
+
|
|
120
|
+
samples = Population.new(X=X)
|
|
121
|
+
samples = self.evaluator.eval(self.problem, samples)
|
|
122
|
+
|
|
123
|
+
# do a survival to recreate rank and crowding of all individuals
|
|
124
|
+
samples = RankAndCrowding().do(self.problem, samples, n_survive=len(samples))
|
|
125
|
+
return samples
|
|
126
|
+
|
|
127
|
+
def _select_means_stds(self, means_stds, mean_new, std_new):
|
|
128
|
+
# Unpack means and stds
|
|
129
|
+
means = np.array([m[0] for m in means_stds])
|
|
130
|
+
stds = np.array([m[1] for m in means_stds])
|
|
131
|
+
|
|
132
|
+
# Weighted combination
|
|
133
|
+
mean_new = 0.5 * mean_new + 0.5 * means[-1]
|
|
134
|
+
std_new = 0.5 * std_new + 0.5 * stds[-1]
|
|
135
|
+
return mean_new, std_new
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class NSGA2IMicLSTM(NSGA2IMcLSTM):
|
|
139
|
+
def __init__(self, **kwargs) -> None:
|
|
140
|
+
super().__init__(**kwargs)
|
|
141
|
+
self._n_timesteps = 10
|
|
142
|
+
self._sequence_length = 5 # Use 5 historical time steps to predict next step
|
|
143
|
+
self._incremental_learning = True
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class NSGA2IMicLSTM1003(NSGA2IMcLSTM):
|
|
147
|
+
def __init__(self, **kwargs) -> None:
|
|
148
|
+
super().__init__(**kwargs)
|
|
149
|
+
self._n_timesteps = 10
|
|
150
|
+
self._sequence_length = 3
|
|
151
|
+
self._incremental_learning = True
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class NSGA2IMicLSTM1005(NSGA2IMcLSTM):
|
|
155
|
+
def __init__(self, **kwargs) -> None:
|
|
156
|
+
super().__init__(**kwargs)
|
|
157
|
+
self._n_timesteps = 10
|
|
158
|
+
self._sequence_length = 5
|
|
159
|
+
self._incremental_learning = True
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class NSGA2IMicLSTM1007(NSGA2IMcLSTM):
|
|
163
|
+
def __init__(self, **kwargs) -> None:
|
|
164
|
+
super().__init__(**kwargs)
|
|
165
|
+
self._n_timesteps = 10
|
|
166
|
+
self._sequence_length = 7
|
|
167
|
+
self._incremental_learning = True
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class NSGA2IMicLSTM1009(NSGA2IMcLSTM):
|
|
171
|
+
def __init__(self, **kwargs) -> None:
|
|
172
|
+
super().__init__(**kwargs)
|
|
173
|
+
self._n_timesteps = 10
|
|
174
|
+
self._sequence_length = 9
|
|
175
|
+
self._incremental_learning = True
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class NSGA2IMicLSTM1503(NSGA2IMcLSTM):
|
|
179
|
+
def __init__(self, **kwargs) -> None:
|
|
180
|
+
super().__init__(**kwargs)
|
|
181
|
+
self._n_timesteps = 15
|
|
182
|
+
self._sequence_length = 3
|
|
183
|
+
self._incremental_learning = True
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class NSGA2IMicLSTM1505(NSGA2IMcLSTM):
|
|
187
|
+
def __init__(self, **kwargs) -> None:
|
|
188
|
+
super().__init__(**kwargs)
|
|
189
|
+
self._n_timesteps = 15
|
|
190
|
+
self._sequence_length = 5
|
|
191
|
+
self._incremental_learning = True
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class NSGA2IMicLSTM1507(NSGA2IMcLSTM):
|
|
195
|
+
def __init__(self, **kwargs) -> None:
|
|
196
|
+
super().__init__(**kwargs)
|
|
197
|
+
self._n_timesteps = 15
|
|
198
|
+
self._sequence_length = 7
|
|
199
|
+
self._incremental_learning = True
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class NSGA2IMicLSTM1509(NSGA2IMcLSTM):
|
|
203
|
+
def __init__(self, **kwargs) -> None:
|
|
204
|
+
super().__init__(**kwargs)
|
|
205
|
+
self._n_timesteps = 15
|
|
206
|
+
self._sequence_length = 9
|
|
207
|
+
self._incremental_learning = True
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
class NSGA2IMicLSTM1511(NSGA2IMcLSTM):
|
|
211
|
+
def __init__(self, **kwargs) -> None:
|
|
212
|
+
super().__init__(**kwargs)
|
|
213
|
+
self._n_timesteps = 15
|
|
214
|
+
self._sequence_length = 11
|
|
215
|
+
self._incremental_learning = True
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
class NSGA2IMicLSTM1513(NSGA2IMcLSTM):
|
|
219
|
+
def __init__(self, **kwargs) -> None:
|
|
220
|
+
super().__init__(**kwargs)
|
|
221
|
+
self._n_timesteps = 15
|
|
222
|
+
self._sequence_length = 13
|
|
223
|
+
self._incremental_learning = True
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from pymoo.core.population import Population
|
|
2
|
+
|
|
3
|
+
from pydmoo.algorithms.modern.nsga2_imkt import NSGA2IMKT
|
|
4
|
+
from pydmoo.core.bounds import clip_and_randomize
|
|
5
|
+
from pydmoo.core.predictions import igp_based_predictor
|
|
6
|
+
from pydmoo.core.sample_gaussian import univariate_gaussian_sample
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class NSGA2IMKTIGP(NSGA2IMKT):
|
|
10
|
+
def __init__(self, **kwargs):
|
|
11
|
+
super().__init__(**kwargs)
|
|
12
|
+
self.size_pool = 10
|
|
13
|
+
self.denominator = 0.5
|
|
14
|
+
|
|
15
|
+
self.delta_s = 0.01
|
|
16
|
+
self.sigma_n = 0.01
|
|
17
|
+
self.sigma_n_2 = self.sigma_n ** 2
|
|
18
|
+
|
|
19
|
+
def _response_change(self):
|
|
20
|
+
pop = self.pop
|
|
21
|
+
X = pop.get("X")
|
|
22
|
+
|
|
23
|
+
# recreate the current population without being evaluated
|
|
24
|
+
pop = Population.new(X=X)
|
|
25
|
+
|
|
26
|
+
# sample self.pop_size individuals in decision space
|
|
27
|
+
samples_old = self.sampling_new_pop()
|
|
28
|
+
|
|
29
|
+
# select self.pop_size/2 individuals with better convergence and diversity
|
|
30
|
+
samples = samples_old[:int(len(samples_old)/2)]
|
|
31
|
+
|
|
32
|
+
# knowledge in objective space
|
|
33
|
+
means_stds, mean, std = self._in_decision_or_objective_space_1d(samples, "objective_space")
|
|
34
|
+
mean_new, std_new = self._select_means_stds(means_stds, mean, std)
|
|
35
|
+
|
|
36
|
+
# sample self.pop_size individuals in objective space
|
|
37
|
+
F = univariate_gaussian_sample(mean_new, std_new, self.pop_size, random_state=self.random_state)
|
|
38
|
+
|
|
39
|
+
# TODO
|
|
40
|
+
# inverse mapping
|
|
41
|
+
X = igp_based_predictor(samples.get("X"), samples.get("F"), F, self.sigma_n_2)
|
|
42
|
+
|
|
43
|
+
# bounds
|
|
44
|
+
if self.problem.has_bounds():
|
|
45
|
+
xl, xu = self.problem.bounds()
|
|
46
|
+
X = clip_and_randomize(X, xl, xu, random_state=self.random_state)
|
|
47
|
+
|
|
48
|
+
# merge
|
|
49
|
+
pop = Population.merge(samples_old, Population.new(X=X))
|
|
50
|
+
|
|
51
|
+
return pop
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class NSGA2IMKTIGP0(NSGA2IMKTIGP):
|
|
55
|
+
def __init__(self, **kwargs):
|
|
56
|
+
super().__init__(**kwargs)
|