Skip to content

Commit 722baa3

Browse files
SamuelGabrielfacebook-github-bot
authored andcommitted
Add better Error for initializers on intra-point constraints (#2775)
Summary: Pull Request resolved: #2775 I have added the wanted exception. Reviewed By: esantorella Differential Revision: D71204155 fbshipit-source-id: dfe5ff0820bffbf69b4ac5c3e453daf1a20f1fdd
1 parent 44b6400 commit 722baa3

File tree

2 files changed

+96
-30
lines changed

2 files changed

+96
-30
lines changed

botorch/optim/initializers.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,21 @@ def gen_one_shot_kg_initial_conditions(
541541
)
542542
q_aug = acq_function.get_augmented_q_batch_size(q=q)
543543

544+
# Check for inter-point (in)equality constraints
545+
for constraints, type_of_constraints in [
546+
(inequality_constraints, "inequality"),
547+
(equality_constraints, "equality"),
548+
]:
549+
if constraints is not None and len(constraints) > 0:
550+
for indices, _, _ in constraints:
551+
if len(indices.shape) > 1:
552+
raise NotImplementedError(
553+
"Indices must be one-dimensional "
554+
"in gen_one_shot_kg_initial_conditions. "
555+
f"Received indices {indices} "
556+
f"for {type_of_constraints} constrained."
557+
)
558+
544559
# TODO: Avoid unnecessary computation by not generating all candidates
545560
ics = gen_batch_initial_conditions(
546561
acq_function=acq_function,
@@ -636,10 +651,12 @@ def gen_one_shot_hvkg_initial_conditions(
636651
restarts and raw samples for solving the posterior objective
637652
maximization problem, respectively) and `eta` (temperature parameter
638653
for sampling heuristic from posterior objective maximizers).
639-
inequality constraints: A list of tuples (indices, coefficients, rhs),
654+
inequality constraints: Optionally, list of tuples (indices, coefficients, rhs),
640655
with each tuple encoding an inequality constraint of the form
641-
`\sum_i (X[indices[i]] * coefficients[i]) >= rhs`.
642-
equality constraints: A list of tuples (indices, coefficients, rhs),
656+
`\sum_i (X[indices[i]] * coefficients[i]) >= rhs`. Each
657+
tensor of indices must be one-dimensional, since inter-point
658+
constraints are not supported here.
659+
equality constraints: Optionally, a list of tuples (indices, coefficients, rhs),
643660
with each tuple encoding an inequality constraint of the form
644661
`\sum_i (X[indices[i]] * coefficients[i]) = rhs`.
645662

test/optim/test_initializers.py

Lines changed: 76 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,40 +1046,89 @@ def test_gen_one_shot_kg_initial_conditions(self):
10461046
raw_samples=raw_samples,
10471047
options={"frac_random": 2.0},
10481048
)
1049+
1050+
forbidden_indices = torch.tensor([[0, 1], [0, 1]])
1051+
for constraint_type in [
1052+
"inequality_constraints",
1053+
"equality_constraints",
1054+
]:
1055+
constraint_kwarg = {
1056+
constraint_type: [
1057+
(
1058+
forbidden_indices,
1059+
torch.ones(2).to(mean),
1060+
0.5,
1061+
)
1062+
]
1063+
}
1064+
with self.subTest(
1065+
f"intra-point {constraint_type} not supported"
1066+
), self.assertRaisesRegex(
1067+
NotImplementedError,
1068+
"Indices must be one-dimensional "
1069+
"in gen_one_shot_kg_initial_conditions. "
1070+
"Received indices",
1071+
):
1072+
gen_one_shot_kg_initial_conditions(
1073+
acq_function=mock_kg,
1074+
bounds=bounds,
1075+
q=1,
1076+
num_restarts=num_restarts,
1077+
raw_samples=raw_samples,
1078+
**constraint_kwarg,
1079+
)
1080+
10491081
# test generation logic
10501082
q = 2
10511083
mock_random_ics = torch.rand(num_restarts, q + num_fantasies, 2)
10521084
mock_fantasy_cands = torch.ones(20, 1, 2)
10531085
mock_fantasy_vals = torch.randn(20)
1054-
with ExitStack() as es:
1055-
mock_gbics = es.enter_context(
1056-
mock.patch(
1057-
"botorch.optim.initializers.gen_batch_initial_conditions",
1058-
return_value=mock_random_ics,
1059-
)
1060-
)
1061-
mock_optacqf = es.enter_context(
1062-
mock.patch(
1063-
"botorch.optim.optimize.optimize_acqf",
1064-
return_value=(mock_fantasy_cands, mock_fantasy_vals),
1086+
for constraint_kwargs in [
1087+
{},
1088+
{
1089+
"inequality_constraints": [
1090+
(torch.tensor([0, 1]), torch.ones(2).to(mean), 0.5)
1091+
]
1092+
}, # test that no error is raised
1093+
{
1094+
"equality_constraints": [
1095+
(torch.tensor([0, 1]), torch.ones(2).to(mean), 0.5)
1096+
]
1097+
# test that no error is raised
1098+
},
1099+
]:
1100+
with ExitStack() as es:
1101+
mock_gbics = es.enter_context(
1102+
mock.patch(
1103+
"botorch.optim.initializers.gen_batch_initial_conditions",
1104+
return_value=mock_random_ics,
1105+
)
10651106
)
1066-
)
1067-
ics = gen_one_shot_kg_initial_conditions(
1068-
acq_function=mock_kg,
1069-
bounds=bounds,
1070-
q=q,
1071-
num_restarts=num_restarts,
1072-
raw_samples=raw_samples,
1073-
)
1074-
mock_gbics.assert_called_once()
1075-
mock_optacqf.assert_called_once()
1076-
n_value = int((1 - 0.1) * num_fantasies)
1077-
self.assertTrue(
1078-
torch.equal(
1079-
ics[..., :-n_value, :], mock_random_ics[..., :-n_value, :]
1107+
mock_optacqf = es.enter_context(
1108+
mock.patch(
1109+
"botorch.optim.optimize.optimize_acqf",
1110+
return_value=(mock_fantasy_cands, mock_fantasy_vals),
1111+
)
10801112
)
1081-
)
1082-
self.assertTrue(torch.all(ics[..., -n_value:, :] == 1))
1113+
with self.subTest(f"Main test with {constraint_kwargs}"):
1114+
ics = gen_one_shot_kg_initial_conditions(
1115+
acq_function=mock_kg,
1116+
bounds=bounds,
1117+
q=q,
1118+
num_restarts=num_restarts,
1119+
raw_samples=raw_samples,
1120+
**constraint_kwargs,
1121+
)
1122+
mock_gbics.assert_called_once()
1123+
mock_optacqf.assert_called_once()
1124+
n_value = int((1 - 0.1) * num_fantasies)
1125+
self.assertTrue(
1126+
torch.equal(
1127+
ics[..., :-n_value, :],
1128+
mock_random_ics[..., :-n_value, :],
1129+
)
1130+
)
1131+
self.assertTrue(torch.all(ics[..., -n_value:, :] == 1))
10831132

10841133

10851134
class TestGenOneShotHVKGInitialConditions(BotorchTestCase):

0 commit comments

Comments
 (0)