9
9
from typing import Callable , Dict , Iterable , Optional , Tuple , Union
10
10
11
11
from gpytorch .models import ExactGP
12
+ from parameterspace import ParameterSpace
12
13
13
14
from blackboxopt .base import (
14
15
Objective ,
44
45
) from e
45
46
46
47
48
+ def _get_numerical_points_from_discrete_space (space : ParameterSpace ) -> np .ndarray :
49
+ """Retrieve all points from a discrete space in the numerical representation"""
50
+ points_along_dimensions = []
51
+ for parameter_name in space .get_parameter_names ():
52
+ parameter = space .get_parameter_by_name (parameter_name )[
53
+ "parameter"
54
+ ] # type:ignore
55
+ if isinstance (parameter , ps .IntegerParameter ):
56
+ bounds = (parameter .bounds [0 ], parameter .bounds [1 ] + 1 )
57
+ points_along_dimensions .append (
58
+ [parameter .val2num (v ) for v in range (* bounds )]
59
+ )
60
+ elif isinstance (parameter , ps .OrdinalParameter ) or isinstance (
61
+ parameter , ps .CategoricalParameter
62
+ ):
63
+ points_along_dimensions .append (
64
+ [parameter .val2num (v ) for v in parameter .values ]
65
+ )
66
+ else :
67
+ raise ValueError (
68
+ f"Only discrete parameters are allowed but got { parameter } "
69
+ )
70
+ points = np .meshgrid (* points_along_dimensions )
71
+ points = [p .reshape ((p .size , 1 )) for p in points ]
72
+ return np .concatenate (points , axis = - 1 )
73
+
74
+
47
75
def _acquisition_function_optimizer_factory (
48
76
search_space : ps .ParameterSpace ,
49
77
af_opt_kwargs : Optional [dict ],
@@ -52,7 +80,10 @@ def _acquisition_function_optimizer_factory(
52
80
"""Prepare either BoTorch's `optimize_acqf_discrete` or `optimize_acqf` depending
53
81
on whether the search space is fully discrete or not and set required defaults if
54
82
not overridden by `af_opt_kwargs`. If any of the af optimizer specific required
55
- kwargs are set, this overrides the automatic discrete space detection.
83
+ kwargs are set, this overrides the automatic discrete space detection. In case an
84
+ exclusively discrete space is detected and `num_random_choices` is not specified
85
+ in `af_opt_kwargs`, the discrete acquisition function optimizer is using all
86
+ possible combinations in the discrete space.
56
87
57
88
Args:
58
89
search_space: Search space used for optimization.
@@ -76,6 +107,7 @@ def _acquisition_function_optimizer_factory(
76
107
or "raw_samples" in kwargs
77
108
or space_has_continuous_parameters
78
109
):
110
+ # continuous AF optimization
79
111
return functools .partial (
80
112
optimize_acqf ,
81
113
q = 1 ,
@@ -86,12 +118,20 @@ def _acquisition_function_optimizer_factory(
86
118
** kwargs ,
87
119
)
88
120
89
- choices = torch .Tensor (
90
- [
91
- search_space .to_numerical (search_space .sample ())
92
- for _ in range (kwargs .pop ("num_random_choices" , 5_000 ))
93
- ]
94
- ).to (dtype = torch_dtype )
121
+ if "num_random_choices" not in kwargs and not space_has_continuous_parameters :
122
+ # Optimize over the entire discrete search space, if the number of random
123
+ # choices is not specified
124
+ choices = torch .from_numpy (
125
+ _get_numerical_points_from_discrete_space (search_space )
126
+ ).to (torch_dtype )
127
+ else :
128
+ # Optimize over the desired number of samples from the discrete search space
129
+ choices = torch .Tensor (
130
+ [
131
+ search_space .to_numerical (search_space .sample ())
132
+ for _ in range (kwargs ["num_random_choices" ])
133
+ ]
134
+ ).to (dtype = torch_dtype )
95
135
return functools .partial (optimize_acqf_discrete , q = 1 , choices = choices , ** kwargs )
96
136
97
137
0 commit comments