polystep 0.7.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.
- polystep/__init__.py +176 -0
- polystep/_compiled.py +334 -0
- polystep/_step_blockwise.py +994 -0
- polystep/_step_momentum.py +128 -0
- polystep/_step_monolithic.py +1070 -0
- polystep/adaptive_subspace.py +762 -0
- polystep/api.py +307 -0
- polystep/ask_tell.py +164 -0
- polystep/benchmarks/__init__.py +62 -0
- polystep/benchmarks/baselines.py +604 -0
- polystep/benchmarks/rl/__init__.py +13 -0
- polystep/benchmarks/rl/cartpole.py +260 -0
- polystep/benchmarks/rl/gym_evaluator.py +304 -0
- polystep/benchmarks/rl/metrics.py +53 -0
- polystep/benchmarks/rl/policies.py +133 -0
- polystep/benchmarks/utils.py +1262 -0
- polystep/blockwise.py +549 -0
- polystep/cma.py +400 -0
- polystep/cma_subspace.py +404 -0
- polystep/cost_nn.py +633 -0
- polystep/costs.py +86 -0
- polystep/dynamics.py +138 -0
- polystep/epsilon.py +217 -0
- polystep/geometry.py +410 -0
- polystep/hybrid_subspace.py +1335 -0
- polystep/layers/__init__.py +16 -0
- polystep/layers/attention.py +243 -0
- polystep/layers/rnn.py +276 -0
- polystep/objectives/__init__.py +25 -0
- polystep/objectives/base.py +77 -0
- polystep/objectives/synthetic.py +232 -0
- polystep/optimizer.py +1405 -0
- polystep/projection/__init__.py +5 -0
- polystep/projection/sparse.py +291 -0
- polystep/py.typed +0 -0
- polystep/quadratic_model.py +285 -0
- polystep/solver.py +654 -0
- polystep/solvers/__init__.py +34 -0
- polystep/solvers/_prelude.py +129 -0
- polystep/solvers/base.py +77 -0
- polystep/solvers/greedy.py +159 -0
- polystep/solvers/kl_softmax.py +200 -0
- polystep/solvers/sinkhorn.py +522 -0
- polystep/solvers/softmax.py +151 -0
- polystep/solvers/tempered_softmax.py +97 -0
- polystep/subspace.py +694 -0
- polystep/transform.py +365 -0
- polystep-0.7.0.dist-info/METADATA +285 -0
- polystep-0.7.0.dist-info/RECORD +52 -0
- polystep-0.7.0.dist-info/WHEEL +5 -0
- polystep-0.7.0.dist-info/licenses/LICENSE +191 -0
- polystep-0.7.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"""Synthetic test functions for benchmarking optimization algorithms."""
|
|
2
|
+
|
|
3
|
+
import math
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
import torch
|
|
7
|
+
|
|
8
|
+
from .base import ObjectiveFn
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Ackley(ObjectiveFn):
|
|
12
|
+
"""Ackley test function.
|
|
13
|
+
|
|
14
|
+
f(x) = -a*exp(-b*sqrt(1/d * sum(x_i^2))) - exp(1/d * sum(cos(c*x_i))) + a + e
|
|
15
|
+
|
|
16
|
+
Global minimum at x = 0 with f(x) = 0.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
dim: int = 2,
|
|
22
|
+
a: float = 20.0,
|
|
23
|
+
b: float = 0.2,
|
|
24
|
+
c: float = 2 * math.pi,
|
|
25
|
+
noise_std: Optional[float] = None,
|
|
26
|
+
negate: bool = False,
|
|
27
|
+
bounds: Optional[torch.Tensor] = None,
|
|
28
|
+
):
|
|
29
|
+
if bounds is None:
|
|
30
|
+
bounds = torch.tensor([[-6.0, 6.0]] * dim)
|
|
31
|
+
optimizers = torch.zeros(1, dim)
|
|
32
|
+
super().__init__(
|
|
33
|
+
dim=dim, bounds=bounds, optimizers=optimizers, optimal_value=0.0, noise_std=noise_std, negate=negate
|
|
34
|
+
)
|
|
35
|
+
self.a = a
|
|
36
|
+
self.b = b
|
|
37
|
+
self.c = c
|
|
38
|
+
|
|
39
|
+
def evaluate(self, X: torch.Tensor) -> torch.Tensor:
|
|
40
|
+
a, b, c = self.a, self.b, self.c
|
|
41
|
+
part1 = -a * torch.exp(-b / math.sqrt(self.dim) * torch.linalg.norm(X, dim=-1))
|
|
42
|
+
part2 = -torch.exp(torch.mean(torch.cos(c * X), dim=-1))
|
|
43
|
+
return part1 + part2 + a + math.e
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class Rosenbrock(ObjectiveFn):
|
|
47
|
+
"""Rosenbrock (banana) function. Global minimum at x = (1,...,1) with f(x) = 0."""
|
|
48
|
+
|
|
49
|
+
def __init__(
|
|
50
|
+
self,
|
|
51
|
+
dim: int = 2,
|
|
52
|
+
noise_std: Optional[float] = None,
|
|
53
|
+
negate: bool = False,
|
|
54
|
+
bounds: Optional[torch.Tensor] = None,
|
|
55
|
+
):
|
|
56
|
+
if bounds is None:
|
|
57
|
+
bounds = torch.tensor([[-5.0, 5.0]] * dim)
|
|
58
|
+
optimizers = torch.ones(1, dim)
|
|
59
|
+
super().__init__(
|
|
60
|
+
dim=dim, bounds=bounds, optimizers=optimizers, optimal_value=0.0, noise_std=noise_std, negate=negate
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def evaluate(self, X: torch.Tensor) -> torch.Tensor:
|
|
64
|
+
return torch.sum(
|
|
65
|
+
100.0 * (X[..., 1:] - X[..., :-1] ** 2) ** 2 + (X[..., :-1] - 1) ** 2,
|
|
66
|
+
dim=-1,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class Rastrigin(ObjectiveFn):
|
|
71
|
+
"""Rastrigin function. Global minimum at x = 0 with f(x) = 0."""
|
|
72
|
+
|
|
73
|
+
def __init__(
|
|
74
|
+
self,
|
|
75
|
+
dim: int = 2,
|
|
76
|
+
noise_std: Optional[float] = None,
|
|
77
|
+
negate: bool = False,
|
|
78
|
+
bounds: Optional[torch.Tensor] = None,
|
|
79
|
+
):
|
|
80
|
+
if bounds is None:
|
|
81
|
+
bounds = torch.tensor([[-5.12, 5.12]] * dim)
|
|
82
|
+
optimizers = torch.zeros(1, dim)
|
|
83
|
+
super().__init__(
|
|
84
|
+
dim=dim, bounds=bounds, optimizers=optimizers, optimal_value=0.0, noise_std=noise_std, negate=negate
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
def evaluate(self, X: torch.Tensor) -> torch.Tensor:
|
|
88
|
+
return 10.0 * self.dim + torch.sum(
|
|
89
|
+
X**2 - 10.0 * torch.cos(2.0 * math.pi * X),
|
|
90
|
+
dim=-1,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class StyblinskiTang(ObjectiveFn):
|
|
95
|
+
"""Styblinski-Tang function. Global minimum at x = -2.903534 per dim."""
|
|
96
|
+
|
|
97
|
+
def __init__(
|
|
98
|
+
self,
|
|
99
|
+
dim: int = 2,
|
|
100
|
+
noise_std: Optional[float] = None,
|
|
101
|
+
negate: bool = False,
|
|
102
|
+
bounds: Optional[torch.Tensor] = None,
|
|
103
|
+
):
|
|
104
|
+
if bounds is None:
|
|
105
|
+
bounds = torch.tensor([[-5.0, 5.0]] * dim)
|
|
106
|
+
optimizers = torch.full((1, dim), -2.903534)
|
|
107
|
+
optimal_value = -39.166166 * dim
|
|
108
|
+
super().__init__(
|
|
109
|
+
dim=dim,
|
|
110
|
+
bounds=bounds,
|
|
111
|
+
optimizers=optimizers,
|
|
112
|
+
optimal_value=optimal_value,
|
|
113
|
+
noise_std=noise_std,
|
|
114
|
+
negate=negate,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
def evaluate(self, X: torch.Tensor) -> torch.Tensor:
|
|
118
|
+
return 0.5 * (X**4 - 16 * X**2 + 5 * X).sum(dim=-1)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class Levy(ObjectiveFn):
|
|
122
|
+
"""Levy function. Global minimum at x = (1,...,1) with f(x) = 0."""
|
|
123
|
+
|
|
124
|
+
def __init__(
|
|
125
|
+
self,
|
|
126
|
+
dim: int = 2,
|
|
127
|
+
noise_std: Optional[float] = None,
|
|
128
|
+
negate: bool = False,
|
|
129
|
+
bounds: Optional[torch.Tensor] = None,
|
|
130
|
+
):
|
|
131
|
+
if bounds is None:
|
|
132
|
+
bounds = torch.tensor([[-10.0, 10.0]] * dim)
|
|
133
|
+
optimizers = torch.ones(1, dim)
|
|
134
|
+
super().__init__(
|
|
135
|
+
dim=dim, bounds=bounds, optimizers=optimizers, optimal_value=0.0, noise_std=noise_std, negate=negate
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
def evaluate(self, X: torch.Tensor) -> torch.Tensor:
|
|
139
|
+
w = 1.0 + (X - 1.0) / 4.0
|
|
140
|
+
part1 = torch.sin(math.pi * w[..., 0]) ** 2
|
|
141
|
+
part2 = torch.sum(
|
|
142
|
+
(w[..., :-1] - 1.0) ** 2 * (1.0 + 10.0 * torch.sin(math.pi * w[..., :-1] + 1.0) ** 2),
|
|
143
|
+
dim=-1,
|
|
144
|
+
)
|
|
145
|
+
part3 = (w[..., -1] - 1.0) ** 2 * (1.0 + torch.sin(2.0 * math.pi * w[..., -1]) ** 2)
|
|
146
|
+
return part1 + part2 + part3
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class Griewank(ObjectiveFn):
|
|
150
|
+
"""Griewank function. Global minimum at x = 0 with f(x) = 0."""
|
|
151
|
+
|
|
152
|
+
def __init__(
|
|
153
|
+
self,
|
|
154
|
+
dim: int = 2,
|
|
155
|
+
noise_std: Optional[float] = None,
|
|
156
|
+
negate: bool = False,
|
|
157
|
+
bounds: Optional[torch.Tensor] = None,
|
|
158
|
+
):
|
|
159
|
+
if bounds is None:
|
|
160
|
+
bounds = torch.tensor([[-600.0, 600.0]] * dim)
|
|
161
|
+
optimizers = torch.zeros(1, dim)
|
|
162
|
+
super().__init__(
|
|
163
|
+
dim=dim, bounds=bounds, optimizers=optimizers, optimal_value=0.0, noise_std=noise_std, negate=negate
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
def evaluate(self, X: torch.Tensor) -> torch.Tensor:
|
|
167
|
+
part1 = torch.sum(X**2 / 4000.0, dim=-1)
|
|
168
|
+
i = torch.arange(1, self.dim + 1, device=X.device, dtype=X.dtype)
|
|
169
|
+
part2 = -torch.prod(torch.cos(X / torch.sqrt(i)), dim=-1)
|
|
170
|
+
return part1 + part2 + 1.0
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class Beale(ObjectiveFn):
|
|
174
|
+
"""Beale function (2D). Global minimum at (3, 0.5) with f(x) = 0."""
|
|
175
|
+
|
|
176
|
+
def __init__(self, noise_std: Optional[float] = None, negate: bool = False, bounds: Optional[torch.Tensor] = None):
|
|
177
|
+
if bounds is None:
|
|
178
|
+
bounds = torch.tensor([[-4.5, 4.5], [-4.5, 4.5]])
|
|
179
|
+
optimizers = torch.tensor([[3.0, 0.5]])
|
|
180
|
+
super().__init__(
|
|
181
|
+
dim=2, bounds=bounds, optimizers=optimizers, optimal_value=0.0, noise_std=noise_std, negate=negate
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
def evaluate(self, X: torch.Tensor) -> torch.Tensor:
|
|
185
|
+
x1, x2 = X[..., 0], X[..., 1]
|
|
186
|
+
part1 = (1.5 - x1 + x1 * x2) ** 2
|
|
187
|
+
part2 = (2.25 - x1 + x1 * x2**2) ** 2
|
|
188
|
+
part3 = (2.625 - x1 + x1 * x2**3) ** 2
|
|
189
|
+
return part1 + part2 + part3
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class Branin(ObjectiveFn):
|
|
193
|
+
"""Branin function (2D). Global minimum ~0.397887."""
|
|
194
|
+
|
|
195
|
+
def __init__(self, noise_std: Optional[float] = None, negate: bool = False, bounds: Optional[torch.Tensor] = None):
|
|
196
|
+
if bounds is None:
|
|
197
|
+
bounds = torch.tensor([[-5.0, 10.0], [0.0, 15.0]])
|
|
198
|
+
optimizers = torch.tensor([[-math.pi, 12.275], [math.pi, 2.275], [9.42478, 2.475]])
|
|
199
|
+
super().__init__(
|
|
200
|
+
dim=2, bounds=bounds, optimizers=optimizers, optimal_value=0.397887, noise_std=noise_std, negate=negate
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
def evaluate(self, X: torch.Tensor) -> torch.Tensor:
|
|
204
|
+
t1 = X[..., 1] - 5.1 / (4 * math.pi**2) * X[..., 0] ** 2 + 5 / math.pi * X[..., 0] - 6
|
|
205
|
+
t2 = 10 * (1 - 1 / (8 * math.pi)) * torch.cos(X[..., 0])
|
|
206
|
+
return t1**2 + t2 + 10
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class Sphere(ObjectiveFn):
|
|
210
|
+
"""Sphere function. Global minimum at x = 0 with f(x) = 0.
|
|
211
|
+
|
|
212
|
+
f(x) = sum(x_i^2)
|
|
213
|
+
|
|
214
|
+
The simplest convex test function, useful as a baseline.
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
def __init__(
|
|
218
|
+
self,
|
|
219
|
+
dim: int = 2,
|
|
220
|
+
noise_std: Optional[float] = None,
|
|
221
|
+
negate: bool = False,
|
|
222
|
+
bounds: Optional[torch.Tensor] = None,
|
|
223
|
+
):
|
|
224
|
+
if bounds is None:
|
|
225
|
+
bounds = torch.tensor([[-5.12, 5.12]] * dim)
|
|
226
|
+
optimizers = torch.zeros(1, dim)
|
|
227
|
+
super().__init__(
|
|
228
|
+
dim=dim, bounds=bounds, optimizers=optimizers, optimal_value=0.0, noise_std=noise_std, negate=negate
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
def evaluate(self, X: torch.Tensor) -> torch.Tensor:
|
|
232
|
+
return torch.sum(X**2, dim=-1)
|