xopt 2.2.2__tar.gz → 2.2.3__tar.gz
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.
- {xopt-2.2.2/xopt.egg-info → xopt-2.2.3}/PKG-INFO +1 -1
- {xopt-2.2.2 → xopt-2.2.3}/requirements.txt +1 -1
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/bayesian/test_bayesian_generator.py +9 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/bayesian/test_utils.py +1 -1
- {xopt-2.2.2 → xopt-2.2.3}/tests/test_evaluator.py +28 -1
- {xopt-2.2.2 → xopt-2.2.3}/tests/test_vocs.py +16 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/_version.py +3 -3
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/bayesian_exploration.py +0 -7
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/bayesian_generator.py +17 -3
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/expected_improvement.py +1 -2
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/mggpo.py +1 -1
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/mobo.py +1 -1
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/objectives.py +7 -21
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/upper_confidence_bound.py +1 -3
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/utils.py +20 -7
- xopt-2.2.3/xopt/generators/bayesian/visualize.py +1091 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/utils.py +5 -1
- {xopt-2.2.2 → xopt-2.2.3}/xopt/vocs.py +8 -0
- {xopt-2.2.2 → xopt-2.2.3/xopt.egg-info}/PKG-INFO +1 -1
- {xopt-2.2.2 → xopt-2.2.3}/xopt.egg-info/requires.txt +1 -1
- xopt-2.2.2/xopt/generators/bayesian/visualize.py +0 -417
- {xopt-2.2.2 → xopt-2.2.3}/LICENSE +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/MANIFEST.in +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/README.md +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/benchmarks/__init__.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/benchmarks/test_mo.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/setup.cfg +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/setup.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/__init__.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/__init__.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/bayesian/__init__.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/bayesian/test_bax.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/bayesian/test_bayesian_exploration.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/bayesian/test_constraints.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/bayesian/test_custom_model.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/bayesian/test_expected_improvement.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/bayesian/test_hessian_kernel.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/bayesian/test_high_level.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/bayesian/test_mggpo.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/bayesian/test_mobo.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/bayesian/test_model_constructor.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/bayesian/test_multi_fidelity.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/bayesian/test_time_dependent_bo.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/bayesian/test_turbo.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/bayesian/test_upper_confidence_bound.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/test_extremum_seeking.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/test_latin_hypercube.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/test_neldermead.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/test_random.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/generators/test_rcds.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/test_generator.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/test_io.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/test_mpi.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/test_numerical_optimizer.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/test_perf.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/test_pydantic.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/test_utils.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/tests/test_xopt.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/versioneer.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/__init__.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/asynchronous.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/base.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/errors.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/evaluator.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generator.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/__init__.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/__init__.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/base_model.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/bax/__init__.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/bax/acquisition.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/bax/algorithms.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/bax_generator.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/custom_botorch/__init__.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/custom_botorch/constrained_acquisition.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/custom_botorch/hessian_kernel.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/custom_botorch/heteroskedastic.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/custom_botorch/identity.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/custom_botorch/log_acquisition_function.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/custom_botorch/multi_fidelity.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/custom_botorch/proximal.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/models/__init__.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/models/prior_mean.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/models/standard.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/models/time_dependent.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/multi_fidelity.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/time_dependent.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/bayesian/turbo.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/es/__init__.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/es/extremumseeking.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/ga/__init__.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/ga/cnsga.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/ga/deap_creator.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/ga/deap_fitness_with_constraints.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/ga/fitness_with_constraints.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/random.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/rcds/__init__.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/rcds/rcds.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/scipy/__init__.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/scipy/latin_hypercube.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/scipy/neldermead.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/generators/utils.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/log.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/mpi/__init__.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/mpi/run.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/numerical_optimizer.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/pydantic.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/resources/__init__.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/resources/benchmarking.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/resources/test_functions/__init__.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/resources/test_functions/ackley_20.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/resources/test_functions/modified_tnk.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/resources/test_functions/multi_objective.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/resources/test_functions/problem.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/resources/test_functions/rosenbrock.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/resources/test_functions/sinusoid_1d.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/resources/test_functions/sphere_100.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/resources/test_functions/sphere_20.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/resources/test_functions/sphere_50.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/resources/test_functions/tnk.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt/resources/testing.py +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt.egg-info/SOURCES.txt +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt.egg-info/dependency_links.txt +0 -0
- {xopt-2.2.2 → xopt-2.2.3}/xopt.egg-info/top_level.txt +0 -0
|
@@ -239,3 +239,12 @@ class TestBayesianGenerator(TestCase):
|
|
|
239
239
|
model.models[0].input_transform.bounds,
|
|
240
240
|
torch.tensor(((0, 0), (1, 10))).double(),
|
|
241
241
|
)
|
|
242
|
+
|
|
243
|
+
# test bad fixed feature name
|
|
244
|
+
gen = BayesianGenerator(vocs=TEST_VOCS_BASE)
|
|
245
|
+
gen.fixed_features = {"bad_name": 3.0}
|
|
246
|
+
data = deepcopy(TEST_VOCS_DATA)
|
|
247
|
+
gen.add_data(data)
|
|
248
|
+
|
|
249
|
+
with pytest.raises(KeyError):
|
|
250
|
+
gen.train_model()
|
|
@@ -10,7 +10,7 @@ class TestUtils:
|
|
|
10
10
|
def test_mobo_objective(self):
|
|
11
11
|
test_vocs_copy = deepcopy(TEST_VOCS_BASE)
|
|
12
12
|
test_vocs_copy.objectives["y2"] = "MAXIMIZE"
|
|
13
|
-
obj = create_mobo_objective(test_vocs_copy
|
|
13
|
+
obj = create_mobo_objective(test_vocs_copy)
|
|
14
14
|
|
|
15
15
|
# test large sample shape
|
|
16
16
|
test_samples = torch.randn(3, 4, 5, 3).double()
|
|
@@ -3,7 +3,8 @@ from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
import pandas as pd
|
|
5
5
|
|
|
6
|
-
from xopt import Evaluator
|
|
6
|
+
from xopt import Evaluator, Xopt
|
|
7
|
+
from xopt.generators import RandomGenerator
|
|
7
8
|
from xopt.vocs import VOCS
|
|
8
9
|
|
|
9
10
|
|
|
@@ -135,3 +136,29 @@ class TestEvaluator:
|
|
|
135
136
|
executor = ProcessPoolExecutor(max_workers=MAX_WORKERS)
|
|
136
137
|
ev = Evaluator(function=self.f, executor=executor, max_workers=MAX_WORKERS)
|
|
137
138
|
ev.evaluate_data(in10)
|
|
139
|
+
|
|
140
|
+
def test_evaluate_return_types(self):
|
|
141
|
+
def a(input):
|
|
142
|
+
return {"f": 1.0}
|
|
143
|
+
|
|
144
|
+
def b(input):
|
|
145
|
+
return {"f": [1.0]}
|
|
146
|
+
|
|
147
|
+
def c(input):
|
|
148
|
+
return {"f": np.array(1.0)}
|
|
149
|
+
|
|
150
|
+
def d(input):
|
|
151
|
+
return {"f": [1.0, 1.0]}
|
|
152
|
+
|
|
153
|
+
def e(input):
|
|
154
|
+
return {"f": np.ones(3)}
|
|
155
|
+
|
|
156
|
+
vocs = VOCS(variables={"x": [0, 1]}, objectives={"f": "MINIMIZE"})
|
|
157
|
+
|
|
158
|
+
for func in [a, b, c, d, e]:
|
|
159
|
+
evaluator = Evaluator(function=func)
|
|
160
|
+
generator = RandomGenerator(vocs=vocs)
|
|
161
|
+
|
|
162
|
+
X = Xopt(evaluator=evaluator, generator=generator, vocs=vocs)
|
|
163
|
+
|
|
164
|
+
X.random_evaluate(5)
|
|
@@ -27,6 +27,14 @@ class TestVOCS(object):
|
|
|
27
27
|
variables={"x": [0, 1]},
|
|
28
28
|
)
|
|
29
29
|
|
|
30
|
+
def test_output_names(self):
|
|
31
|
+
test_vocs = VOCS(
|
|
32
|
+
variables={"x": [0, 1]},
|
|
33
|
+
objectives={"y1": "MINIMIZE"},
|
|
34
|
+
constraints={"c1": ["GREATER_THAN", 0], "c2": ["LESS_THAN", 0]},
|
|
35
|
+
)
|
|
36
|
+
assert test_vocs.output_names == ["y1", "c1", "c2"]
|
|
37
|
+
|
|
30
38
|
def test_constraint_specification(self):
|
|
31
39
|
good_constraint_list = [
|
|
32
40
|
["LESS_THAN", 0],
|
|
@@ -234,6 +242,14 @@ class TestVOCS(object):
|
|
|
234
242
|
assert idx == 1
|
|
235
243
|
assert val == 0.1
|
|
236
244
|
|
|
245
|
+
# test error handling
|
|
246
|
+
with pytest.raises(RuntimeError):
|
|
247
|
+
vocs.select_best(pd.DataFrame())
|
|
248
|
+
|
|
249
|
+
vocs.constraints = {"c1": ["GREATER_THAN", 10.5]}
|
|
250
|
+
with pytest.raises(RuntimeError):
|
|
251
|
+
vocs.select_best(pd.DataFrame())
|
|
252
|
+
|
|
237
253
|
@pytest.mark.filterwarnings("ignore: All-NaN axis encountered")
|
|
238
254
|
def test_cumulative_optimum(self):
|
|
239
255
|
vocs = deepcopy(TEST_VOCS_BASE)
|
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2024-
|
|
11
|
+
"date": "2024-05-07T12:53:58-0400",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "2.2.
|
|
14
|
+
"full-revisionid": "2a01895f05a19d2a26b527c4c47baaf099cd0110",
|
|
15
|
+
"version": "2.2.3"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -13,7 +13,6 @@ from xopt.generators.bayesian.bayesian_generator import (
|
|
|
13
13
|
BayesianGenerator,
|
|
14
14
|
formatted_base_docstring,
|
|
15
15
|
)
|
|
16
|
-
from xopt.generators.bayesian.objectives import create_exploration_objective
|
|
17
16
|
|
|
18
17
|
|
|
19
18
|
class BayesianExplorationGenerator(BayesianGenerator):
|
|
@@ -38,12 +37,6 @@ class BayesianExplorationGenerator(BayesianGenerator):
|
|
|
38
37
|
|
|
39
38
|
return qPV
|
|
40
39
|
|
|
41
|
-
def _get_objective(self):
|
|
42
|
-
"""return exploration objective, which only captures the output of the first
|
|
43
|
-
model output"""
|
|
44
|
-
|
|
45
|
-
return create_exploration_objective(self.vocs, self._tkwargs)
|
|
46
|
-
|
|
47
40
|
|
|
48
41
|
class qPosteriorVariance(MCAcquisitionFunction):
|
|
49
42
|
def __init__(
|
|
@@ -375,6 +375,11 @@ class BayesianGenerator(Generator, ABC):
|
|
|
375
375
|
# get bounds for each fixed_feature (vocs bounds take precedent)
|
|
376
376
|
for key in self.fixed_features:
|
|
377
377
|
if key not in variable_bounds:
|
|
378
|
+
if key not in data:
|
|
379
|
+
raise KeyError(
|
|
380
|
+
"generator data needs to contain fixed feature "
|
|
381
|
+
f"column name `{key}`"
|
|
382
|
+
)
|
|
378
383
|
f_data = data[key]
|
|
379
384
|
bounds = [f_data.min(), f_data.max()]
|
|
380
385
|
if bounds[1] - bounds[0] < 1e-8:
|
|
@@ -545,11 +550,20 @@ class BayesianGenerator(Generator, ABC):
|
|
|
545
550
|
pass
|
|
546
551
|
|
|
547
552
|
def _get_objective(self):
|
|
548
|
-
"""
|
|
553
|
+
"""
|
|
554
|
+
return default objective (scalar objective) determined by vocs
|
|
555
|
+
|
|
556
|
+
If objectives are specified the returned function will weight model
|
|
557
|
+
by +/- 1.0 according to MAXIMIZE/MINIMIZE keys in vocs.
|
|
558
|
+
|
|
559
|
+
If no objectives are specified, the returned function will weight observable
|
|
560
|
+
models by +1.0. This is used in Bayesian exploration.
|
|
561
|
+
|
|
562
|
+
"""
|
|
549
563
|
return create_mc_objective(self.vocs, self._tkwargs)
|
|
550
564
|
|
|
551
565
|
def _get_constraint_callables(self):
|
|
552
|
-
"""return
|
|
566
|
+
"""return constratint callable determined by vocs"""
|
|
553
567
|
constraint_callables = create_constraint_callables(self.vocs)
|
|
554
568
|
if len(constraint_callables) == 0:
|
|
555
569
|
constraint_callables = None
|
|
@@ -755,7 +769,7 @@ class MultiObjectiveBayesianGenerator(BayesianGenerator, ABC):
|
|
|
755
769
|
|
|
756
770
|
n_objectives = self.vocs.n_objectives
|
|
757
771
|
weights = torch.zeros(n_objectives)
|
|
758
|
-
weights = set_botorch_weights(
|
|
772
|
+
weights = set_botorch_weights(self.vocs).to(**self._tkwargs)
|
|
759
773
|
objective_data = objective_data * weights
|
|
760
774
|
|
|
761
775
|
# compute hypervolume
|
|
@@ -36,8 +36,7 @@ class ExpectedImprovementGenerator(BayesianGenerator):
|
|
|
36
36
|
)
|
|
37
37
|
else:
|
|
38
38
|
# analytic acquisition function for single candidate generation
|
|
39
|
-
weights =
|
|
40
|
-
weights = set_botorch_weights(weights, self.vocs)
|
|
39
|
+
weights = set_botorch_weights(self.vocs).to(**self._tkwargs)
|
|
41
40
|
posterior_transform = ScalarizedPosteriorTransform(weights)
|
|
42
41
|
acq = ExpectedImprovement(
|
|
43
42
|
model, best_f=best_f, posterior_transform=posterior_transform
|
|
@@ -61,7 +61,7 @@ class MGGPOGenerator(MultiObjectiveBayesianGenerator):
|
|
|
61
61
|
return acq
|
|
62
62
|
|
|
63
63
|
def _get_objective(self):
|
|
64
|
-
return create_mobo_objective(self.vocs
|
|
64
|
+
return create_mobo_objective(self.vocs)
|
|
65
65
|
|
|
66
66
|
def _get_acquisition(self, model):
|
|
67
67
|
# get reference point from data
|
|
@@ -15,7 +15,7 @@ class MOBOGenerator(MultiObjectiveBayesianGenerator):
|
|
|
15
15
|
Hypervolume Improvement acquisition function"""
|
|
16
16
|
|
|
17
17
|
def _get_objective(self):
|
|
18
|
-
return create_mobo_objective(self.vocs
|
|
18
|
+
return create_mobo_objective(self.vocs)
|
|
19
19
|
|
|
20
20
|
def get_acquisition(self, model):
|
|
21
21
|
"""
|
|
@@ -41,7 +41,7 @@ def constraint_function(Z, vocs, name):
|
|
|
41
41
|
|
|
42
42
|
def create_constraint_callables(vocs):
|
|
43
43
|
if vocs.constraints is not None:
|
|
44
|
-
constraint_names =
|
|
44
|
+
constraint_names = vocs.constraint_names
|
|
45
45
|
constraint_callables = []
|
|
46
46
|
for name in constraint_names:
|
|
47
47
|
constraint_callables += [
|
|
@@ -62,10 +62,7 @@ def create_mc_objective(vocs, tkwargs):
|
|
|
62
62
|
create the objective object
|
|
63
63
|
|
|
64
64
|
"""
|
|
65
|
-
|
|
66
|
-
weights = torch.zeros(n_outputs).to(**tkwargs)
|
|
67
|
-
|
|
68
|
-
weights = set_botorch_weights(weights, vocs)
|
|
65
|
+
weights = set_botorch_weights(vocs)
|
|
69
66
|
|
|
70
67
|
def obj_callable(Z, X=None):
|
|
71
68
|
return torch.matmul(Z, weights.reshape(-1, 1)).squeeze(-1)
|
|
@@ -73,26 +70,15 @@ def create_mc_objective(vocs, tkwargs):
|
|
|
73
70
|
return GenericMCObjective(obj_callable)
|
|
74
71
|
|
|
75
72
|
|
|
76
|
-
def
|
|
77
|
-
n_outputs = vocs.n_outputs
|
|
78
|
-
weights = torch.zeros(n_outputs).to(**tkwargs)
|
|
79
|
-
weights[0] = 1.0
|
|
80
|
-
|
|
81
|
-
def obj_callable(Z, X=None):
|
|
82
|
-
return torch.matmul(Z, weights.reshape(-1, 1)).squeeze(-1)
|
|
83
|
-
|
|
84
|
-
return GenericMCObjective(obj_callable)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
def create_mobo_objective(vocs, tkwargs):
|
|
73
|
+
def create_mobo_objective(vocs):
|
|
88
74
|
"""
|
|
89
75
|
botorch assumes maximization so we need to negate any objectives that have
|
|
90
76
|
minimize keyword and zero out anything that is a constraint
|
|
91
77
|
"""
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
weights = set_botorch_weights(
|
|
78
|
+
output_names = vocs.output_names
|
|
79
|
+
objective_indicies = [output_names.index(name) for name in vocs.objectives]
|
|
80
|
+
weights = set_botorch_weights(vocs)[objective_indicies]
|
|
95
81
|
|
|
96
82
|
return WeightedMCMultiOutputObjective(
|
|
97
|
-
weights, outcomes=
|
|
83
|
+
weights, outcomes=objective_indicies, num_outcomes=vocs.n_objectives
|
|
98
84
|
)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import warnings
|
|
2
2
|
|
|
3
|
-
import torch
|
|
4
3
|
from botorch.acquisition import (
|
|
5
4
|
qUpperConfidenceBound,
|
|
6
5
|
ScalarizedPosteriorTransform,
|
|
@@ -62,8 +61,7 @@ beta : float, default 2.0
|
|
|
62
61
|
)
|
|
63
62
|
else:
|
|
64
63
|
# analytic acquisition function for single candidate generation
|
|
65
|
-
weights =
|
|
66
|
-
weights = set_botorch_weights(weights, self.vocs)
|
|
64
|
+
weights = set_botorch_weights(self.vocs)
|
|
67
65
|
posterior_transform = ScalarizedPosteriorTransform(weights)
|
|
68
66
|
acq = UpperConfidenceBound(
|
|
69
67
|
model, beta=self.beta, posterior_transform=posterior_transform
|
|
@@ -65,13 +65,26 @@ def get_training_data(
|
|
|
65
65
|
return train_X, train_Y, train_Yvar
|
|
66
66
|
|
|
67
67
|
|
|
68
|
-
def set_botorch_weights(
|
|
69
|
-
"""set weights to multiply xopt objectives for botorch objectives"""
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
68
|
+
def set_botorch_weights(vocs: VOCS):
|
|
69
|
+
"""set weights to multiply xopt objectives or observables for botorch objectives"""
|
|
70
|
+
output_names = vocs.output_names
|
|
71
|
+
|
|
72
|
+
weights = torch.zeros(len(output_names), dtype=torch.double)
|
|
73
|
+
|
|
74
|
+
if vocs.n_objectives > 0:
|
|
75
|
+
# if objectives exist this is an optimization problem
|
|
76
|
+
# set weights according to the index of the models -- corresponds to the
|
|
77
|
+
# ordering of output names
|
|
78
|
+
for objective_name in vocs.objective_names:
|
|
79
|
+
if vocs.objectives[objective_name] == "MINIMIZE":
|
|
80
|
+
weights[output_names.index(objective_name)] = -1.0
|
|
81
|
+
elif vocs.objectives[objective_name] == "MAXIMIZE":
|
|
82
|
+
weights[output_names.index(objective_name)] = 1.0
|
|
83
|
+
if vocs.n_objectives == 0:
|
|
84
|
+
# if no objectives exist this may be an exploration problem, weight each
|
|
85
|
+
# observable by 1.0
|
|
86
|
+
for observable_name in vocs.observables:
|
|
87
|
+
weights[output_names.index(observable_name)] = 1.0
|
|
75
88
|
|
|
76
89
|
return weights
|
|
77
90
|
|