Skip to content

Commit 77e6f12

Browse files
vizier-teamcopybara-github
authored andcommitted
Modify the Harmonica algorithm to work with discrete, integer and categorical parameters with two values.
PiperOrigin-RevId: 752735728
1 parent 4d1bd2c commit 77e6f12

File tree

2 files changed

+100
-3
lines changed

2 files changed

+100
-3
lines changed

vizier/_src/algorithms/designers/harmonica.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -272,8 +272,14 @@ def __init__(
272272
f'This designer {self} does not support conditional search.'
273273
)
274274
for p_config in problem_statement.search_space.parameters:
275-
if p_config.external_type != vz.ExternalType.BOOLEAN:
276-
raise ValueError('Only boolean search spaces are supported.')
275+
if p_config.external_type != vz.ExternalType.BOOLEAN and (
276+
p_config.type == vz.ParameterType.DOUBLE
277+
or len(p_config.feasible_values) != 2
278+
):
279+
raise ValueError(
280+
'Only boolean search spaces are supported, bot got parameter'
281+
f' config: f{p_config}'
282+
)
277283

278284
self._problem_statement = problem_statement
279285
self._metric_name = self._problem_statement.metric_information.item().name
@@ -345,5 +351,11 @@ def suggest(
345351

346352
parameters = vz.ParameterDict()
347353
for i, p in enumerate(self._search_space.parameters):
348-
parameters[p.name] = 'True' if x_new[i] == 1.0 else 'False'
354+
if p.external_type == vz.ExternalType.BOOLEAN:
355+
parameters[p.name] = 'True' if x_new[i] == 1.0 else 'False'
356+
else:
357+
parameters[p.name] = (
358+
p.feasible_values[1] if x_new[i] == 1.0 else p.feasible_values[0]
359+
)
360+
349361
return [vz.TrialSuggestion(parameters=parameters)]

vizier/_src/algorithms/designers/harmonica_test.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
from __future__ import annotations
1616

1717
"""Tests for bocs."""
18+
from vizier import pyvizier as vz
1819
from vizier._src.algorithms.designers import harmonica
1920
from vizier._src.algorithms.testing import test_runners
2021
from vizier._src.benchmarks.experimenters import combo_experimenter
22+
from vizier.testing import test_studies
2123

2224
from absl.testing import absltest
2325

@@ -39,6 +41,89 @@ def test_make_suggestions(self):
3941
validate_parameters=True)
4042
self.assertLen(trials, num_trials)
4143

44+
def test_make_suggestions_with_two_values(self):
45+
space = vz.SearchSpace()
46+
root = space.root
47+
root.add_int_param('integer_0', 11, 12)
48+
root.add_discrete_param('discrete_0', feasible_values=[1001, 2034])
49+
root.add_categorical_param('categorical_0', feasible_values=['a', 'b'])
50+
root.add_bool_param('bool_0')
51+
problem_statement = vz.ProblemStatement(space)
52+
problem_statement.metric_information.append(
53+
vz.MetricInformation(
54+
name='main_objective', goal=vz.ObjectiveMetricGoal.MAXIMIZE
55+
)
56+
)
57+
designer = harmonica.HarmonicaDesigner(
58+
problem_statement, num_init_samples=1
59+
)
60+
num_trials = 10
61+
trials = test_runners.run_with_random_metrics(
62+
designer,
63+
problem_statement,
64+
iters=num_trials,
65+
batch_size=1,
66+
verbose=1,
67+
validate_parameters=True,
68+
)
69+
self.assertLen(trials, num_trials)
70+
71+
def test_categorical_search_space_with_more_than_two_values_raises_error(
72+
self,
73+
):
74+
experimenter = combo_experimenter.CentroidExperimenter(centroid_n_choice=3)
75+
with self.assertRaisesRegex(
76+
ValueError, 'Only boolean search spaces are supported'
77+
):
78+
_ = harmonica.HarmonicaDesigner(
79+
experimenter.problem_statement(), num_init_samples=1
80+
)
81+
82+
def test_integer_search_space_with_more_than_two_values_raises_error(
83+
self,
84+
):
85+
space = vz.SearchSpace()
86+
root = space.root
87+
root.add_int_param('integer_0', 11, 13)
88+
problem_statement = vz.ProblemStatement(space)
89+
problem_statement.metric_information.append(
90+
vz.MetricInformation(
91+
name='main_objective', goal=vz.ObjectiveMetricGoal.MAXIMIZE
92+
)
93+
)
94+
with self.assertRaisesRegex(
95+
ValueError, 'Only boolean search spaces are supported'
96+
):
97+
_ = harmonica.HarmonicaDesigner(problem_statement, num_init_samples=1)
98+
99+
def test_discrete_search_space_with_more_than_two_values_raises_error(
100+
self,
101+
):
102+
space = vz.SearchSpace()
103+
root = space.root
104+
root.add_discrete_param('discrete_0', feasible_values=[1001, 2034, 3000])
105+
problem_statement = vz.ProblemStatement(space)
106+
problem_statement.metric_information.append(
107+
vz.MetricInformation(
108+
name='main_objective', goal=vz.ObjectiveMetricGoal.MAXIMIZE
109+
)
110+
)
111+
with self.assertRaisesRegex(
112+
ValueError, 'Only boolean search spaces are supported'
113+
):
114+
_ = harmonica.HarmonicaDesigner(problem_statement, num_init_samples=1)
115+
116+
def test_continuous_search_space_raises_error(self):
117+
with self.assertRaisesRegex(
118+
ValueError, 'Only boolean search spaces are supported'
119+
):
120+
_ = harmonica.HarmonicaDesigner(
121+
vz.ProblemStatement(
122+
test_studies.flat_continuous_space_with_scaling()
123+
),
124+
num_init_samples=1,
125+
)
126+
42127

43128
if __name__ == '__main__':
44129
absltest.main()

0 commit comments

Comments
 (0)