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.
Files changed (52) hide show
  1. polystep/__init__.py +176 -0
  2. polystep/_compiled.py +334 -0
  3. polystep/_step_blockwise.py +994 -0
  4. polystep/_step_momentum.py +128 -0
  5. polystep/_step_monolithic.py +1070 -0
  6. polystep/adaptive_subspace.py +762 -0
  7. polystep/api.py +307 -0
  8. polystep/ask_tell.py +164 -0
  9. polystep/benchmarks/__init__.py +62 -0
  10. polystep/benchmarks/baselines.py +604 -0
  11. polystep/benchmarks/rl/__init__.py +13 -0
  12. polystep/benchmarks/rl/cartpole.py +260 -0
  13. polystep/benchmarks/rl/gym_evaluator.py +304 -0
  14. polystep/benchmarks/rl/metrics.py +53 -0
  15. polystep/benchmarks/rl/policies.py +133 -0
  16. polystep/benchmarks/utils.py +1262 -0
  17. polystep/blockwise.py +549 -0
  18. polystep/cma.py +400 -0
  19. polystep/cma_subspace.py +404 -0
  20. polystep/cost_nn.py +633 -0
  21. polystep/costs.py +86 -0
  22. polystep/dynamics.py +138 -0
  23. polystep/epsilon.py +217 -0
  24. polystep/geometry.py +410 -0
  25. polystep/hybrid_subspace.py +1335 -0
  26. polystep/layers/__init__.py +16 -0
  27. polystep/layers/attention.py +243 -0
  28. polystep/layers/rnn.py +276 -0
  29. polystep/objectives/__init__.py +25 -0
  30. polystep/objectives/base.py +77 -0
  31. polystep/objectives/synthetic.py +232 -0
  32. polystep/optimizer.py +1405 -0
  33. polystep/projection/__init__.py +5 -0
  34. polystep/projection/sparse.py +291 -0
  35. polystep/py.typed +0 -0
  36. polystep/quadratic_model.py +285 -0
  37. polystep/solver.py +654 -0
  38. polystep/solvers/__init__.py +34 -0
  39. polystep/solvers/_prelude.py +129 -0
  40. polystep/solvers/base.py +77 -0
  41. polystep/solvers/greedy.py +159 -0
  42. polystep/solvers/kl_softmax.py +200 -0
  43. polystep/solvers/sinkhorn.py +522 -0
  44. polystep/solvers/softmax.py +151 -0
  45. polystep/solvers/tempered_softmax.py +97 -0
  46. polystep/subspace.py +694 -0
  47. polystep/transform.py +365 -0
  48. polystep-0.7.0.dist-info/METADATA +285 -0
  49. polystep-0.7.0.dist-info/RECORD +52 -0
  50. polystep-0.7.0.dist-info/WHEEL +5 -0
  51. polystep-0.7.0.dist-info/licenses/LICENSE +191 -0
  52. 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)