evograd-diff 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.
- evograd/__init__.py +67 -0
- evograd/algorithms/__init__.py +138 -0
- evograd/algorithms/cmaes.py +1365 -0
- evograd/algorithms/de.py +895 -0
- evograd/algorithms/ga.py +532 -0
- evograd/algorithms/pso.py +648 -0
- evograd/algorithms/shade.py +1165 -0
- evograd/benchmarks/functions/__init__.py +229 -0
- evograd/benchmarks/functions/base.py +217 -0
- evograd/benchmarks/functions/cec2017/__init__.py +250 -0
- evograd/benchmarks/functions/cec2017/basic.py +413 -0
- evograd/benchmarks/functions/cec2017/composition.py +580 -0
- evograd/benchmarks/functions/cec2017/data.pkl +0 -0
- evograd/benchmarks/functions/cec2017/data.py +350 -0
- evograd/benchmarks/functions/cec2017/hybrid.py +406 -0
- evograd/benchmarks/functions/cec2017/simple.py +326 -0
- evograd/benchmarks/functions/classical.py +649 -0
- evograd/benchmarks/functions/smoothed_funnel.py +476 -0
- evograd/benchmarks/functions/transforms.py +463 -0
- evograd/benchmarks/run_benchmark_functions.py +1208 -0
- evograd/core/__init__.py +73 -0
- evograd/core/algorithm.py +778 -0
- evograd/core/maximize.py +269 -0
- evograd/core/minimize.py +740 -0
- evograd/core/problem.py +444 -0
- evograd/core/result.py +571 -0
- evograd/core/termination.py +602 -0
- evograd/operators/__init__.py +178 -0
- evograd/operators/crossover.py +1117 -0
- evograd/operators/mutation.py +1098 -0
- evograd/operators/relaxations.py +175 -0
- evograd/operators/repair.py +601 -0
- evograd/operators/sampling.py +577 -0
- evograd/operators/selection.py +981 -0
- evograd/operators/survival.py +1000 -0
- evograd/tests/__init__.py +11 -0
- evograd/tests/run_all.py +78 -0
- evograd/tests/test_core.py +528 -0
- evograd/tests/test_ga.py +572 -0
- evograd/tests/test_operators.py +662 -0
- evograd/tests/test_per_individual.py +326 -0
- evograd/tests/test_utils.py +328 -0
- evograd/utils/__init__.py +97 -0
- evograd/utils/callbacks.py +926 -0
- evograd/utils/device.py +502 -0
- evograd/utils/duplicates.py +421 -0
- evograd_diff-0.1.0.dist-info/METADATA +439 -0
- evograd_diff-0.1.0.dist-info/RECORD +50 -0
- evograd_diff-0.1.0.dist-info/WHEEL +4 -0
- evograd_diff-0.1.0.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CEC 2017 Composition Functions (F21-F30).
|
|
3
|
+
|
|
4
|
+
Composition functions are weighted combinations of multiple basic or hybrid
|
|
5
|
+
functions, each with different shifts and rotations.
|
|
6
|
+
|
|
7
|
+
Reference: CEC 2017 Competition on Real-Parameter Single Objective Optimization
|
|
8
|
+
|
|
9
|
+
F21: Composition Function 1 (N=3)
|
|
10
|
+
F22: Composition Function 2 (N=3)
|
|
11
|
+
F23: Composition Function 3 (N=4)
|
|
12
|
+
F24: Composition Function 4 (N=4)
|
|
13
|
+
F25: Composition Function 5 (N=5)
|
|
14
|
+
F26: Composition Function 6 (N=5)
|
|
15
|
+
F27: Composition Function 7 (N=6)
|
|
16
|
+
F28: Composition Function 8 (N=6)
|
|
17
|
+
F29: Composition Function 9 (N=3) - Hybrid composition
|
|
18
|
+
F30: Composition Function 10 (N=3) - Hybrid composition
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from typing import List, Optional, Tuple, Callable
|
|
22
|
+
|
|
23
|
+
import torch
|
|
24
|
+
from torch import Tensor
|
|
25
|
+
|
|
26
|
+
from ..base import BenchmarkFunction
|
|
27
|
+
from . import basic
|
|
28
|
+
from . import data as cec_data
|
|
29
|
+
from . import hybrid as hybrid_module
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class CEC2017CompositionFunction(BenchmarkFunction):
|
|
33
|
+
"""Base class for CEC 2017 composition functions."""
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
func_num: int,
|
|
38
|
+
n_var: int = 10,
|
|
39
|
+
n_components: int = 3,
|
|
40
|
+
rotations: Optional[List[Tensor]] = None,
|
|
41
|
+
shifts: Optional[List[Tensor]] = None,
|
|
42
|
+
seed: Optional[int] = None,
|
|
43
|
+
):
|
|
44
|
+
"""
|
|
45
|
+
Initialize CEC 2017 composition function.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
func_num: Function number (21-30).
|
|
49
|
+
n_var: Number of variables.
|
|
50
|
+
n_components: Number of component functions.
|
|
51
|
+
rotations: Optional list of rotation matrices.
|
|
52
|
+
shifts: Optional list of shift vectors.
|
|
53
|
+
seed: Random seed for generating transforms if not provided.
|
|
54
|
+
"""
|
|
55
|
+
super().__init__(n_var=n_var, xl=-100.0, xu=100.0)
|
|
56
|
+
|
|
57
|
+
self.func_num = func_num
|
|
58
|
+
self.bias = func_num * 100.0
|
|
59
|
+
self.n_components = n_components
|
|
60
|
+
|
|
61
|
+
# Load or generate transforms for each component
|
|
62
|
+
if rotations is not None:
|
|
63
|
+
self.rotations = rotations
|
|
64
|
+
else:
|
|
65
|
+
self.rotations = [
|
|
66
|
+
cec_data.get_rotation_cf(func_num, i, n_var, seed=seed)
|
|
67
|
+
for i in range(n_components)
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
if shifts is not None:
|
|
71
|
+
self.shifts = shifts
|
|
72
|
+
else:
|
|
73
|
+
self.shifts = [
|
|
74
|
+
cec_data.get_shift_cf(func_num, i, n_var, seed=seed)
|
|
75
|
+
for i in range(n_components)
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
def default_bounds(self) -> Tuple[float, float]:
|
|
79
|
+
return (-100.0, 100.0)
|
|
80
|
+
|
|
81
|
+
def _calc_weights(self, x: Tensor, sigmas: Tensor) -> Tensor:
|
|
82
|
+
"""
|
|
83
|
+
Calculate composition weights based on distance from each shift.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
x: Input tensor of shape [..., n_var].
|
|
87
|
+
sigmas: Sigma values for each component of shape [n_components].
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
Weights of shape [..., n_components].
|
|
91
|
+
"""
|
|
92
|
+
batch_shape = x.shape[:-1]
|
|
93
|
+
nx = x.shape[-1]
|
|
94
|
+
n = self.n_components
|
|
95
|
+
|
|
96
|
+
weights = torch.zeros(*batch_shape, n, device=x.device, dtype=x.dtype)
|
|
97
|
+
|
|
98
|
+
for i in range(n):
|
|
99
|
+
shift = self.shifts[i].to(x.device, x.dtype)
|
|
100
|
+
x_shifted = x - shift
|
|
101
|
+
|
|
102
|
+
# Squared distance
|
|
103
|
+
w = (x_shifted ** 2).sum(dim=-1)
|
|
104
|
+
|
|
105
|
+
# Non-zero mask
|
|
106
|
+
nz_mask = w != 0
|
|
107
|
+
|
|
108
|
+
# Calculate weight: (1/sqrt(w)) * exp(-w / (2*nx*sigma^2))
|
|
109
|
+
sigma = sigmas[i]
|
|
110
|
+
weights[..., i] = torch.where(
|
|
111
|
+
nz_mask,
|
|
112
|
+
(1.0 / torch.sqrt(w + 1e-10)) * torch.exp(-w / (2.0 * nx * sigma * sigma)),
|
|
113
|
+
torch.tensor(float('inf'), device=x.device, dtype=x.dtype),
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# Normalize weights
|
|
117
|
+
w_sum = weights.sum(dim=-1, keepdim=True)
|
|
118
|
+
nz_sum_mask = w_sum != 0
|
|
119
|
+
weights = torch.where(
|
|
120
|
+
nz_sum_mask.expand_as(weights),
|
|
121
|
+
weights / (w_sum + 1e-10),
|
|
122
|
+
torch.full_like(weights, 1.0 / n),
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
return weights
|
|
126
|
+
|
|
127
|
+
def _evaluate_composition(
|
|
128
|
+
self,
|
|
129
|
+
x: Tensor,
|
|
130
|
+
funcs: List[Callable],
|
|
131
|
+
sigmas: Tensor,
|
|
132
|
+
lambdas: Tensor,
|
|
133
|
+
biases: Tensor,
|
|
134
|
+
) -> Tensor:
|
|
135
|
+
"""
|
|
136
|
+
Evaluate composition function.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
x: Input tensor of shape [..., n_var].
|
|
140
|
+
funcs: List of basic functions.
|
|
141
|
+
sigmas: Sigma values for weight calculation.
|
|
142
|
+
lambdas: Scaling factors for each component.
|
|
143
|
+
biases: Bias values for each component.
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
Function values.
|
|
147
|
+
"""
|
|
148
|
+
batch_shape = x.shape[:-1]
|
|
149
|
+
nx = x.shape[-1]
|
|
150
|
+
n = len(funcs)
|
|
151
|
+
|
|
152
|
+
# Move tensors to correct device
|
|
153
|
+
sigmas = sigmas.to(x.device, x.dtype)
|
|
154
|
+
lambdas = lambdas.to(x.device, x.dtype)
|
|
155
|
+
biases = biases.to(x.device, x.dtype)
|
|
156
|
+
|
|
157
|
+
# Calculate weights
|
|
158
|
+
weights = self._calc_weights(x, sigmas)
|
|
159
|
+
|
|
160
|
+
# Evaluate each component
|
|
161
|
+
vals = torch.zeros(*batch_shape, n, device=x.device, dtype=x.dtype)
|
|
162
|
+
|
|
163
|
+
for i in range(n):
|
|
164
|
+
shift = self.shifts[i].to(x.device, x.dtype)
|
|
165
|
+
rotation = self.rotations[i].to(x.device, x.dtype)
|
|
166
|
+
|
|
167
|
+
# Transform: R @ (x - shift)
|
|
168
|
+
z = cec_data.shift_rotate(x, shift, rotation)
|
|
169
|
+
|
|
170
|
+
# Evaluate function
|
|
171
|
+
vals[..., i] = funcs[i](z)
|
|
172
|
+
|
|
173
|
+
# Weighted sum: sum(w * (lambda * f + bias))
|
|
174
|
+
result = (weights * (lambdas * vals + biases)).sum(dim=-1)
|
|
175
|
+
|
|
176
|
+
return result + self.bias
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class CEC2017_F21(CEC2017CompositionFunction):
|
|
180
|
+
"""
|
|
181
|
+
F21: Composition Function 1 (N=3)
|
|
182
|
+
|
|
183
|
+
Components: Rosenbrock, High Conditioned Elliptic, Rastrigin
|
|
184
|
+
|
|
185
|
+
Optimal value: F21* = 2100
|
|
186
|
+
"""
|
|
187
|
+
name = "cec2017_f21"
|
|
188
|
+
optimal_value = 2100.0
|
|
189
|
+
|
|
190
|
+
def __init__(self, n_var: int = 10, **kwargs):
|
|
191
|
+
super().__init__(func_num=21, n_var=n_var, n_components=3, **kwargs)
|
|
192
|
+
|
|
193
|
+
self.funcs = [
|
|
194
|
+
basic.rosenbrock,
|
|
195
|
+
basic.high_conditioned_elliptic,
|
|
196
|
+
basic.rastrigin,
|
|
197
|
+
]
|
|
198
|
+
self.sigmas = torch.tensor([10.0, 20.0, 30.0])
|
|
199
|
+
self.lambdas = torch.tensor([1.0, 1e-6, 1.0])
|
|
200
|
+
self.biases_comp = torch.tensor([0.0, 100.0, 200.0])
|
|
201
|
+
|
|
202
|
+
def __call__(self, x: Tensor) -> Tensor:
|
|
203
|
+
return self._evaluate_composition(
|
|
204
|
+
x, self.funcs, self.sigmas, self.lambdas, self.biases_comp
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class CEC2017_F22(CEC2017CompositionFunction):
|
|
209
|
+
"""
|
|
210
|
+
F22: Composition Function 2 (N=3)
|
|
211
|
+
|
|
212
|
+
Components: Rastrigin, Griewank, Modified Schwefel
|
|
213
|
+
|
|
214
|
+
Optimal value: F22* = 2200
|
|
215
|
+
"""
|
|
216
|
+
name = "cec2017_f22"
|
|
217
|
+
optimal_value = 2200.0
|
|
218
|
+
|
|
219
|
+
def __init__(self, n_var: int = 10, **kwargs):
|
|
220
|
+
super().__init__(func_num=22, n_var=n_var, n_components=3, **kwargs)
|
|
221
|
+
|
|
222
|
+
self.funcs = [
|
|
223
|
+
basic.rastrigin,
|
|
224
|
+
basic.griewank,
|
|
225
|
+
basic.modified_schwefel,
|
|
226
|
+
]
|
|
227
|
+
self.sigmas = torch.tensor([10.0, 20.0, 30.0])
|
|
228
|
+
self.lambdas = torch.tensor([1.0, 10.0, 1.0])
|
|
229
|
+
self.biases_comp = torch.tensor([0.0, 100.0, 200.0])
|
|
230
|
+
|
|
231
|
+
def __call__(self, x: Tensor) -> Tensor:
|
|
232
|
+
return self._evaluate_composition(
|
|
233
|
+
x, self.funcs, self.sigmas, self.lambdas, self.biases_comp
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
class CEC2017_F23(CEC2017CompositionFunction):
|
|
238
|
+
"""
|
|
239
|
+
F23: Composition Function 3 (N=4)
|
|
240
|
+
|
|
241
|
+
Components: Rosenbrock, Ackley, Modified Schwefel, Rastrigin
|
|
242
|
+
|
|
243
|
+
Optimal value: F23* = 2300
|
|
244
|
+
"""
|
|
245
|
+
name = "cec2017_f23"
|
|
246
|
+
optimal_value = 2300.0
|
|
247
|
+
|
|
248
|
+
def __init__(self, n_var: int = 10, **kwargs):
|
|
249
|
+
super().__init__(func_num=23, n_var=n_var, n_components=4, **kwargs)
|
|
250
|
+
|
|
251
|
+
self.funcs = [
|
|
252
|
+
basic.rosenbrock,
|
|
253
|
+
basic.ackley,
|
|
254
|
+
basic.modified_schwefel,
|
|
255
|
+
basic.rastrigin,
|
|
256
|
+
]
|
|
257
|
+
self.sigmas = torch.tensor([10.0, 20.0, 30.0, 40.0])
|
|
258
|
+
self.lambdas = torch.tensor([1.0, 10.0, 1.0, 1.0])
|
|
259
|
+
self.biases_comp = torch.tensor([0.0, 100.0, 200.0, 300.0])
|
|
260
|
+
|
|
261
|
+
def __call__(self, x: Tensor) -> Tensor:
|
|
262
|
+
return self._evaluate_composition(
|
|
263
|
+
x, self.funcs, self.sigmas, self.lambdas, self.biases_comp
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
class CEC2017_F24(CEC2017CompositionFunction):
|
|
268
|
+
"""
|
|
269
|
+
F24: Composition Function 4 (N=4)
|
|
270
|
+
|
|
271
|
+
Components: Ackley, High Conditioned Elliptic, Griewank, Rastrigin
|
|
272
|
+
|
|
273
|
+
Optimal value: F24* = 2400
|
|
274
|
+
"""
|
|
275
|
+
name = "cec2017_f24"
|
|
276
|
+
optimal_value = 2400.0
|
|
277
|
+
|
|
278
|
+
def __init__(self, n_var: int = 10, **kwargs):
|
|
279
|
+
super().__init__(func_num=24, n_var=n_var, n_components=4, **kwargs)
|
|
280
|
+
|
|
281
|
+
self.funcs = [
|
|
282
|
+
basic.ackley,
|
|
283
|
+
basic.high_conditioned_elliptic,
|
|
284
|
+
basic.griewank,
|
|
285
|
+
basic.rastrigin,
|
|
286
|
+
]
|
|
287
|
+
self.sigmas = torch.tensor([10.0, 20.0, 30.0, 40.0])
|
|
288
|
+
self.lambdas = torch.tensor([1.0, 1e-6, 10.0, 1.0])
|
|
289
|
+
self.biases_comp = torch.tensor([0.0, 100.0, 200.0, 300.0])
|
|
290
|
+
|
|
291
|
+
def __call__(self, x: Tensor) -> Tensor:
|
|
292
|
+
return self._evaluate_composition(
|
|
293
|
+
x, self.funcs, self.sigmas, self.lambdas, self.biases_comp
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
class CEC2017_F25(CEC2017CompositionFunction):
|
|
298
|
+
"""
|
|
299
|
+
F25: Composition Function 5 (N=5)
|
|
300
|
+
|
|
301
|
+
Components: Rastrigin, Happy Cat, Ackley, Discus, Rosenbrock
|
|
302
|
+
|
|
303
|
+
Optimal value: F25* = 2500
|
|
304
|
+
"""
|
|
305
|
+
name = "cec2017_f25"
|
|
306
|
+
optimal_value = 2500.0
|
|
307
|
+
|
|
308
|
+
def __init__(self, n_var: int = 10, **kwargs):
|
|
309
|
+
super().__init__(func_num=25, n_var=n_var, n_components=5, **kwargs)
|
|
310
|
+
|
|
311
|
+
self.funcs = [
|
|
312
|
+
basic.rastrigin,
|
|
313
|
+
basic.happy_cat,
|
|
314
|
+
basic.ackley,
|
|
315
|
+
basic.discus,
|
|
316
|
+
basic.rosenbrock,
|
|
317
|
+
]
|
|
318
|
+
self.sigmas = torch.tensor([10.0, 20.0, 30.0, 40.0, 50.0])
|
|
319
|
+
self.lambdas = torch.tensor([10.0, 1.0, 10.0, 1e-6, 1.0])
|
|
320
|
+
self.biases_comp = torch.tensor([0.0, 100.0, 200.0, 300.0, 400.0])
|
|
321
|
+
|
|
322
|
+
def __call__(self, x: Tensor) -> Tensor:
|
|
323
|
+
return self._evaluate_composition(
|
|
324
|
+
x, self.funcs, self.sigmas, self.lambdas, self.biases_comp
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
class CEC2017_F26(CEC2017CompositionFunction):
|
|
329
|
+
"""
|
|
330
|
+
F26: Composition Function 6 (N=5)
|
|
331
|
+
|
|
332
|
+
Components: Expanded Schaffer's F6, Modified Schwefel, Griewank,
|
|
333
|
+
Rosenbrock, Rastrigin
|
|
334
|
+
|
|
335
|
+
Optimal value: F26* = 2600
|
|
336
|
+
"""
|
|
337
|
+
name = "cec2017_f26"
|
|
338
|
+
optimal_value = 2600.0
|
|
339
|
+
|
|
340
|
+
def __init__(self, n_var: int = 10, **kwargs):
|
|
341
|
+
super().__init__(func_num=26, n_var=n_var, n_components=5, **kwargs)
|
|
342
|
+
|
|
343
|
+
self.funcs = [
|
|
344
|
+
basic.expanded_schaffers_f6,
|
|
345
|
+
basic.modified_schwefel,
|
|
346
|
+
basic.griewank,
|
|
347
|
+
basic.rosenbrock,
|
|
348
|
+
basic.rastrigin,
|
|
349
|
+
]
|
|
350
|
+
self.sigmas = torch.tensor([10.0, 20.0, 20.0, 30.0, 40.0])
|
|
351
|
+
# Note: Using lambdas from the actual code, not the problem definitions
|
|
352
|
+
self.lambdas = torch.tensor([5e-4, 1.0, 10.0, 1.0, 10.0])
|
|
353
|
+
self.biases_comp = torch.tensor([0.0, 100.0, 200.0, 300.0, 400.0])
|
|
354
|
+
|
|
355
|
+
def __call__(self, x: Tensor) -> Tensor:
|
|
356
|
+
return self._evaluate_composition(
|
|
357
|
+
x, self.funcs, self.sigmas, self.lambdas, self.biases_comp
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
class CEC2017_F27(CEC2017CompositionFunction):
|
|
362
|
+
"""
|
|
363
|
+
F27: Composition Function 7 (N=6)
|
|
364
|
+
|
|
365
|
+
Components: HGBat, Rastrigin, Modified Schwefel, Bent Cigar,
|
|
366
|
+
High Conditioned Elliptic, Expanded Schaffer's F6
|
|
367
|
+
|
|
368
|
+
Optimal value: F27* = 2700
|
|
369
|
+
"""
|
|
370
|
+
name = "cec2017_f27"
|
|
371
|
+
optimal_value = 2700.0
|
|
372
|
+
|
|
373
|
+
def __init__(self, n_var: int = 10, **kwargs):
|
|
374
|
+
super().__init__(func_num=27, n_var=n_var, n_components=6, **kwargs)
|
|
375
|
+
|
|
376
|
+
self.funcs = [
|
|
377
|
+
basic.h_g_bat,
|
|
378
|
+
basic.rastrigin,
|
|
379
|
+
basic.modified_schwefel,
|
|
380
|
+
basic.bent_cigar,
|
|
381
|
+
basic.high_conditioned_elliptic,
|
|
382
|
+
basic.expanded_schaffers_f6,
|
|
383
|
+
]
|
|
384
|
+
self.sigmas = torch.tensor([10.0, 20.0, 30.0, 40.0, 50.0, 60.0])
|
|
385
|
+
self.lambdas = torch.tensor([10.0, 10.0, 2.5, 1e-26, 1e-6, 5e-4])
|
|
386
|
+
self.biases_comp = torch.tensor([0.0, 100.0, 200.0, 300.0, 400.0, 500.0])
|
|
387
|
+
|
|
388
|
+
def __call__(self, x: Tensor) -> Tensor:
|
|
389
|
+
return self._evaluate_composition(
|
|
390
|
+
x, self.funcs, self.sigmas, self.lambdas, self.biases_comp
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
class CEC2017_F28(CEC2017CompositionFunction):
|
|
395
|
+
"""
|
|
396
|
+
F28: Composition Function 8 (N=6)
|
|
397
|
+
|
|
398
|
+
Components: Ackley, Griewank, Discus, Rosenbrock, Happy Cat,
|
|
399
|
+
Expanded Schaffer's F6
|
|
400
|
+
|
|
401
|
+
Optimal value: F28* = 2800
|
|
402
|
+
"""
|
|
403
|
+
name = "cec2017_f28"
|
|
404
|
+
optimal_value = 2800.0
|
|
405
|
+
|
|
406
|
+
def __init__(self, n_var: int = 10, **kwargs):
|
|
407
|
+
super().__init__(func_num=28, n_var=n_var, n_components=6, **kwargs)
|
|
408
|
+
|
|
409
|
+
self.funcs = [
|
|
410
|
+
basic.ackley,
|
|
411
|
+
basic.griewank,
|
|
412
|
+
basic.discus,
|
|
413
|
+
basic.rosenbrock,
|
|
414
|
+
basic.happy_cat,
|
|
415
|
+
basic.expanded_schaffers_f6,
|
|
416
|
+
]
|
|
417
|
+
self.sigmas = torch.tensor([10.0, 20.0, 30.0, 40.0, 50.0, 60.0])
|
|
418
|
+
self.lambdas = torch.tensor([10.0, 10.0, 1e-6, 1.0, 1.0, 5e-4])
|
|
419
|
+
self.biases_comp = torch.tensor([0.0, 100.0, 200.0, 300.0, 400.0, 500.0])
|
|
420
|
+
|
|
421
|
+
def __call__(self, x: Tensor) -> Tensor:
|
|
422
|
+
return self._evaluate_composition(
|
|
423
|
+
x, self.funcs, self.sigmas, self.lambdas, self.biases_comp
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
class CEC2017_F29(CEC2017CompositionFunction):
|
|
428
|
+
"""
|
|
429
|
+
F29: Composition Function 9 (N=3) - Hybrid Composition
|
|
430
|
+
|
|
431
|
+
Components: Hybrid F15, Hybrid F16, Hybrid F17
|
|
432
|
+
|
|
433
|
+
Optimal value: F29* = 2900
|
|
434
|
+
"""
|
|
435
|
+
name = "cec2017_f29"
|
|
436
|
+
optimal_value = 2900.0
|
|
437
|
+
|
|
438
|
+
def __init__(self, n_var: int = 10, **kwargs):
|
|
439
|
+
seed = kwargs.get('seed', None)
|
|
440
|
+
super().__init__(func_num=29, n_var=n_var, n_components=3, **kwargs)
|
|
441
|
+
|
|
442
|
+
# Load shuffles for each component
|
|
443
|
+
self.shuffles = [
|
|
444
|
+
cec_data.get_shuffle_cf(29, i, n_var, seed=seed)
|
|
445
|
+
for i in range(3)
|
|
446
|
+
]
|
|
447
|
+
|
|
448
|
+
self.sigmas = torch.tensor([10.0, 30.0, 50.0])
|
|
449
|
+
self.biases_comp = torch.tensor([0.0, 100.0, 200.0])
|
|
450
|
+
# Offsets to subtract F* added at the end of hybrid functions
|
|
451
|
+
self.offsets = torch.tensor([1500.0, 1600.0, 1700.0])
|
|
452
|
+
|
|
453
|
+
def __call__(self, x: Tensor) -> Tensor:
|
|
454
|
+
batch_shape = x.shape[:-1]
|
|
455
|
+
nx = x.shape[-1]
|
|
456
|
+
n = 3
|
|
457
|
+
|
|
458
|
+
sigmas = self.sigmas.to(x.device, x.dtype)
|
|
459
|
+
biases = self.biases_comp.to(x.device, x.dtype)
|
|
460
|
+
offsets = self.offsets.to(x.device, x.dtype)
|
|
461
|
+
|
|
462
|
+
# Calculate weights
|
|
463
|
+
weights = self._calc_weights(x, sigmas)
|
|
464
|
+
|
|
465
|
+
# Evaluate each hybrid function
|
|
466
|
+
vals = torch.zeros(*batch_shape, n, device=x.device, dtype=x.dtype)
|
|
467
|
+
|
|
468
|
+
hybrid_classes = [
|
|
469
|
+
hybrid_module.CEC2017_F15,
|
|
470
|
+
hybrid_module.CEC2017_F16,
|
|
471
|
+
hybrid_module.CEC2017_F17,
|
|
472
|
+
]
|
|
473
|
+
|
|
474
|
+
for i in range(n):
|
|
475
|
+
# Create hybrid function with composition's rotation, shift, shuffle
|
|
476
|
+
hybrid_func = hybrid_classes[i](
|
|
477
|
+
n_var=nx,
|
|
478
|
+
rotation=self.rotations[i],
|
|
479
|
+
shift=self.shifts[i],
|
|
480
|
+
shuffle=self.shuffles[i],
|
|
481
|
+
)
|
|
482
|
+
vals[..., i] = hybrid_func(x) - offsets[i]
|
|
483
|
+
|
|
484
|
+
# Weighted sum
|
|
485
|
+
result = (weights * (vals + biases)).sum(dim=-1)
|
|
486
|
+
|
|
487
|
+
return result + self.bias
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
class CEC2017_F30(CEC2017CompositionFunction):
|
|
491
|
+
"""
|
|
492
|
+
F30: Composition Function 10 (N=3) - Hybrid Composition
|
|
493
|
+
|
|
494
|
+
Components: Hybrid F15, Hybrid F18, Hybrid F19
|
|
495
|
+
|
|
496
|
+
Optimal value: F30* = 3000
|
|
497
|
+
"""
|
|
498
|
+
name = "cec2017_f30"
|
|
499
|
+
optimal_value = 3000.0
|
|
500
|
+
|
|
501
|
+
def __init__(self, n_var: int = 10, **kwargs):
|
|
502
|
+
seed = kwargs.get('seed', None)
|
|
503
|
+
super().__init__(func_num=30, n_var=n_var, n_components=3, **kwargs)
|
|
504
|
+
|
|
505
|
+
# Load shuffles for each component
|
|
506
|
+
self.shuffles = [
|
|
507
|
+
cec_data.get_shuffle_cf(30, i, n_var, seed=seed)
|
|
508
|
+
for i in range(3)
|
|
509
|
+
]
|
|
510
|
+
|
|
511
|
+
self.sigmas = torch.tensor([10.0, 30.0, 50.0])
|
|
512
|
+
self.biases_comp = torch.tensor([0.0, 100.0, 200.0])
|
|
513
|
+
self.offsets = torch.tensor([1500.0, 1800.0, 1900.0])
|
|
514
|
+
|
|
515
|
+
def __call__(self, x: Tensor) -> Tensor:
|
|
516
|
+
batch_shape = x.shape[:-1]
|
|
517
|
+
nx = x.shape[-1]
|
|
518
|
+
n = 3
|
|
519
|
+
|
|
520
|
+
sigmas = self.sigmas.to(x.device, x.dtype)
|
|
521
|
+
biases = self.biases_comp.to(x.device, x.dtype)
|
|
522
|
+
offsets = self.offsets.to(x.device, x.dtype)
|
|
523
|
+
|
|
524
|
+
# Calculate weights
|
|
525
|
+
weights = self._calc_weights(x, sigmas)
|
|
526
|
+
|
|
527
|
+
# Evaluate each hybrid function
|
|
528
|
+
vals = torch.zeros(*batch_shape, n, device=x.device, dtype=x.dtype)
|
|
529
|
+
|
|
530
|
+
hybrid_classes = [
|
|
531
|
+
hybrid_module.CEC2017_F15,
|
|
532
|
+
hybrid_module.CEC2017_F18,
|
|
533
|
+
hybrid_module.CEC2017_F19,
|
|
534
|
+
]
|
|
535
|
+
|
|
536
|
+
for i in range(n):
|
|
537
|
+
hybrid_func = hybrid_classes[i](
|
|
538
|
+
n_var=nx,
|
|
539
|
+
rotation=self.rotations[i],
|
|
540
|
+
shift=self.shifts[i],
|
|
541
|
+
shuffle=self.shuffles[i],
|
|
542
|
+
)
|
|
543
|
+
vals[..., i] = hybrid_func(x) - offsets[i]
|
|
544
|
+
|
|
545
|
+
# Weighted sum
|
|
546
|
+
result = (weights * (vals + biases)).sum(dim=-1)
|
|
547
|
+
|
|
548
|
+
return result + self.bias
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
# =============================================================================
|
|
552
|
+
# FUNCTION REGISTRY
|
|
553
|
+
# =============================================================================
|
|
554
|
+
|
|
555
|
+
COMPOSITION_FUNCTIONS = {
|
|
556
|
+
"cec2017_f21": CEC2017_F21,
|
|
557
|
+
"cec2017_f22": CEC2017_F22,
|
|
558
|
+
"cec2017_f23": CEC2017_F23,
|
|
559
|
+
"cec2017_f24": CEC2017_F24,
|
|
560
|
+
"cec2017_f25": CEC2017_F25,
|
|
561
|
+
"cec2017_f26": CEC2017_F26,
|
|
562
|
+
"cec2017_f27": CEC2017_F27,
|
|
563
|
+
"cec2017_f28": CEC2017_F28,
|
|
564
|
+
"cec2017_f29": CEC2017_F29,
|
|
565
|
+
"cec2017_f30": CEC2017_F30,
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
# List for iteration
|
|
569
|
+
all_functions = [
|
|
570
|
+
CEC2017_F21,
|
|
571
|
+
CEC2017_F22,
|
|
572
|
+
CEC2017_F23,
|
|
573
|
+
CEC2017_F24,
|
|
574
|
+
CEC2017_F25,
|
|
575
|
+
CEC2017_F26,
|
|
576
|
+
CEC2017_F27,
|
|
577
|
+
CEC2017_F28,
|
|
578
|
+
CEC2017_F29,
|
|
579
|
+
CEC2017_F30,
|
|
580
|
+
]
|
|
Binary file
|