Skip to content

Commit 77a2867

Browse files
David Erikssonfacebook-github-bot
David Eriksson
authored andcommitted
LABS test function (#2832)
Summary: Pull Request resolved: #2832 Moves the LABS problems to OSS BoTorch. Reviewed By: saitcakmak Differential Revision: D72390996 fbshipit-source-id: b17e346e6a39c1c42005c8ef2478905cf4c4786f
1 parent de51252 commit 77a2867

File tree

2 files changed

+90
-4
lines changed

2 files changed

+90
-4
lines changed

botorch/test_functions/synthetic.py

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
algorithms through the use of dominance-based tournament selection.
2323
Advanced Engineering Informatics, 16(3):193–203, 2002.
2424
25+
.. [Gramacy2016]
26+
R. Gramacy, G. Gray, S. Le Digabel, H. Lee, P. Ranjan, G. Wells & S. Wild.
27+
Modeling an Augmented Lagrangian for Blackbox Constrained Optimization,
28+
Technometrics, 2016.
29+
2530
.. [Hedar2006derivfree]
2631
A.-R. Hedar and M. Fukushima. Derivative-free filter simulated annealing
2732
method for constrained continuous global optimization. Journal of Global
@@ -43,10 +48,9 @@
4348
Particle Swarm and the Differential Evolution Methods (May 1, 2007).
4449
Available at SSRN: https://ssrn.com/abstract=983836.
4550
46-
.. [Gramacy2016]
47-
R. Gramacy, G. Gray, S. Le Digabel, H. Lee, P. Ranjan, G. Wells & S. Wild.
48-
Modeling an Augmented Lagrangian for Blackbox Constrained Optimization,
49-
Technometrics, 2016.
51+
.. [Packebusch2016]
52+
T. Packebusch, S. Mertens. Low autocorrelation binary sequences. Journal of
53+
Physics A: Mathematical and Theoretical 49.16 (2016).
5054
"""
5155

5256
from __future__ import annotations
@@ -917,6 +921,68 @@ def _evaluate_true(self, X: Tensor) -> Tensor:
917921
return self._ackley.evaluate_true((X - self.x_opt).abs())
918922

919923

924+
class Labs(SyntheticTestFunction):
925+
r"""Low Auto-correlation Binary Sequences (LABS) problem.
926+
927+
This input space is binary and the goal is to maximize the Merit factor.
928+
[Packebusch2016]_ provides optimal values and optimizers attained through
929+
brute-force for dim <= 66. We include these for dim = 10, 20, 30, 40, 50, 60.
930+
"""
931+
932+
_check_grad_at_opt = False
933+
934+
def __init__(
935+
self,
936+
dim: int = 30,
937+
noise_std: float | None = None,
938+
negate: bool = False,
939+
dtype: torch.dtype = torch.double,
940+
) -> None:
941+
r"""
942+
Args:
943+
dim: The (input) dimension.
944+
noise_std: Standard deviation of the observation noise.
945+
negate: If True, negate the function.
946+
bounds: Custom bounds for the function specified as (lower, upper) pairs.
947+
dtype: The dtype that is used for the bounds of the function.
948+
"""
949+
self.dim = dim
950+
self.discrete_inds = list(range(dim))
951+
bounds = [(0.0, 1.0) for _ in range(dim)]
952+
optvals = {10: 3.846, 20: 7.692, 30: 7.627, 40: 7.407, 50: 8.170, 60: 8.257}
953+
optimizers = {
954+
10: "42211",
955+
20: "5113112321",
956+
30: "551212111113231",
957+
40: "44412112131121313131",
958+
50: "215131311224112241141142",
959+
60: "761112141111131124211322211222",
960+
}
961+
self._optimal_value = optvals.get(self.dim)
962+
_optimizers = optimizers.get(self.dim)
963+
if _optimizers is not None:
964+
_optimizers = self._optimizer_from_binary_seq(_optimizers)
965+
self._optimizers = _optimizers
966+
super().__init__(noise_std=noise_std, negate=negate, bounds=bounds, dtype=dtype)
967+
968+
def _optimizer_from_binary_seq(self, seq: str) -> list[tuple[float]]:
969+
"""Converts a binary sequence into a an array."""
970+
arr, val = [], 0
971+
for s in seq:
972+
arr += [val for _ in range(int(s))]
973+
val = 1 - val # alternate between 0 and 1
974+
return [tuple(arr)]
975+
976+
def _evaluate_true(self, X: Tensor) -> Tensor:
977+
X = 2 * X - 1 # Map from {0, 1}^d to {-1, 1}^d
978+
energy = torch.zeros(X.shape[:-1], dtype=X.dtype, device=X.device)
979+
for k in range(1, self.dim):
980+
energy += (
981+
(X[..., 0 : self.dim - k] * X[..., k : self.dim]).sum(dim=-1).pow(2)
982+
)
983+
return (self.dim**2) / (2.0 * energy)
984+
985+
920986
# ------------ Constrained synthetic test functions ----------- #
921987

922988

test/test_functions/test_synthetic.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
Hartmann,
2525
HolderTable,
2626
KeaneBumpFunction,
27+
Labs,
2728
Levy,
2829
Michalewicz,
2930
Powell,
@@ -330,6 +331,25 @@ class TestThreeHumpCamel(
330331
]
331332

332333

334+
class TestLabs(
335+
BotorchTestCase, BaseTestProblemTestCaseMixIn, SyntheticTestFunctionTestCaseMixin
336+
):
337+
functions = [
338+
Labs(),
339+
Labs(negate=True),
340+
Labs(noise_std=0.1),
341+
]
342+
343+
def test_labs_optimizers(self):
344+
for dim in [10, 20, 30, 40, 50, 60]:
345+
labs = Labs(dim=dim)
346+
self.assertAllClose(
347+
labs.optimal_value,
348+
labs.evaluate_true(labs.optimizers).item(),
349+
atol=1e-2,
350+
)
351+
352+
333353
class TestAckleyMixed(
334354
BotorchTestCase, BaseTestProblemTestCaseMixIn, SyntheticTestFunctionTestCaseMixin
335355
):

0 commit comments

Comments
 (0)