xopt 2.2.1__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.1/xopt.egg-info → xopt-2.2.3}/PKG-INFO +1 -1
- {xopt-2.2.1 → xopt-2.2.3}/requirements.txt +1 -1
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/bayesian/test_bax.py +33 -8
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/bayesian/test_bayesian_exploration.py +10 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/bayesian/test_bayesian_generator.py +9 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/bayesian/test_model_constructor.py +34 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/bayesian/test_utils.py +1 -1
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/test_neldermead.py +2 -2
- {xopt-2.2.1 → xopt-2.2.3}/tests/test_evaluator.py +28 -1
- {xopt-2.2.1 → xopt-2.2.3}/tests/test_vocs.py +49 -6
- {xopt-2.2.1 → xopt-2.2.3}/xopt/_version.py +3 -3
- {xopt-2.2.1 → xopt-2.2.3}/xopt/asynchronous.py +2 -1
- {xopt-2.2.1 → xopt-2.2.3}/xopt/base.py +12 -4
- {xopt-2.2.1 → xopt-2.2.3}/xopt/evaluator.py +3 -1
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/bax/acquisition.py +6 -3
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/bax/algorithms.py +1 -1
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/bax_generator.py +9 -2
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/bayesian_exploration.py +8 -11
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/bayesian_generator.py +17 -3
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/custom_botorch/constrained_acquisition.py +4 -3
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/custom_botorch/heteroskedastic.py +2 -1
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/custom_botorch/identity.py +5 -2
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/custom_botorch/proximal.py +8 -4
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/expected_improvement.py +1 -2
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/mggpo.py +1 -1
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/mobo.py +1 -1
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/models/prior_mean.py +2 -1
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/models/standard.py +39 -12
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/multi_fidelity.py +1 -1
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/objectives.py +8 -22
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/turbo.py +2 -2
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/upper_confidence_bound.py +1 -3
- {xopt-2.2.1 → 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.1 → xopt-2.2.3}/xopt/pydantic.py +4 -2
- xopt-2.2.3/xopt/resources/test_functions/sphere_100.py +13 -0
- xopt-2.2.3/xopt/resources/test_functions/sphere_50.py +13 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/utils.py +5 -1
- {xopt-2.2.1 → xopt-2.2.3}/xopt/vocs.py +139 -60
- {xopt-2.2.1 → xopt-2.2.3/xopt.egg-info}/PKG-INFO +1 -1
- {xopt-2.2.1 → xopt-2.2.3}/xopt.egg-info/SOURCES.txt +2 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt.egg-info/requires.txt +1 -1
- xopt-2.2.1/xopt/generators/bayesian/visualize.py +0 -396
- {xopt-2.2.1 → xopt-2.2.3}/LICENSE +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/MANIFEST.in +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/README.md +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/benchmarks/__init__.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/benchmarks/test_mo.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/setup.cfg +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/setup.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/__init__.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/__init__.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/bayesian/__init__.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/bayesian/test_constraints.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/bayesian/test_custom_model.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/bayesian/test_expected_improvement.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/bayesian/test_hessian_kernel.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/bayesian/test_high_level.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/bayesian/test_mggpo.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/bayesian/test_mobo.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/bayesian/test_multi_fidelity.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/bayesian/test_time_dependent_bo.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/bayesian/test_turbo.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/bayesian/test_upper_confidence_bound.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/test_extremum_seeking.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/test_latin_hypercube.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/test_random.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/generators/test_rcds.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/test_generator.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/test_io.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/test_mpi.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/test_numerical_optimizer.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/test_perf.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/test_pydantic.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/test_utils.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/tests/test_xopt.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/versioneer.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/__init__.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/errors.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generator.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/__init__.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/__init__.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/base_model.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/bax/__init__.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/custom_botorch/__init__.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/custom_botorch/hessian_kernel.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/custom_botorch/log_acquisition_function.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/custom_botorch/multi_fidelity.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/models/__init__.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/models/time_dependent.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/time_dependent.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/es/__init__.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/es/extremumseeking.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/ga/__init__.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/ga/cnsga.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/ga/deap_creator.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/ga/deap_fitness_with_constraints.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/ga/fitness_with_constraints.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/random.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/rcds/__init__.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/rcds/rcds.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/scipy/__init__.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/scipy/latin_hypercube.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/scipy/neldermead.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/generators/utils.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/log.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/mpi/__init__.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/mpi/run.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/numerical_optimizer.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/resources/__init__.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/resources/benchmarking.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/resources/test_functions/__init__.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/resources/test_functions/ackley_20.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/resources/test_functions/modified_tnk.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/resources/test_functions/multi_objective.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/resources/test_functions/problem.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/resources/test_functions/rosenbrock.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/resources/test_functions/sinusoid_1d.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/resources/test_functions/sphere_20.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/resources/test_functions/tnk.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt/resources/testing.py +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt.egg-info/dependency_links.txt +0 -0
- {xopt-2.2.1 → xopt-2.2.3}/xopt.egg-info/top_level.txt +0 -0
|
@@ -2,11 +2,15 @@ import pickle
|
|
|
2
2
|
from copy import deepcopy
|
|
3
3
|
from unittest.mock import patch
|
|
4
4
|
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
5
7
|
import torch
|
|
6
8
|
from botorch.models import SingleTaskGP
|
|
7
9
|
from botorch.models.model import ModelList
|
|
8
10
|
from botorch.models.transforms import Normalize, Standardize
|
|
9
11
|
|
|
12
|
+
from pydantic import ValidationError
|
|
13
|
+
|
|
10
14
|
from xopt.base import Xopt
|
|
11
15
|
from xopt.evaluator import Evaluator
|
|
12
16
|
from xopt.generators.bayesian.bax.algorithms import (
|
|
@@ -21,9 +25,12 @@ from xopt.resources.testing import TEST_VOCS_BASE, TEST_VOCS_DATA, xtest_callabl
|
|
|
21
25
|
class TestBaxGenerator:
|
|
22
26
|
@patch.multiple(Algorithm, __abstractmethods__=set())
|
|
23
27
|
def test_init(self):
|
|
28
|
+
test_vocs = deepcopy(TEST_VOCS_BASE)
|
|
29
|
+
test_vocs.objectives = {}
|
|
30
|
+
test_vocs.observables = ["y1"]
|
|
24
31
|
alg = Algorithm()
|
|
25
32
|
bax_gen = BaxGenerator(
|
|
26
|
-
vocs=
|
|
33
|
+
vocs=test_vocs,
|
|
27
34
|
algorithm=alg,
|
|
28
35
|
)
|
|
29
36
|
bax_gen.model_dump()
|
|
@@ -110,6 +117,8 @@ class TestBaxGenerator:
|
|
|
110
117
|
|
|
111
118
|
# test w/o constraints
|
|
112
119
|
test_vocs = deepcopy(TEST_VOCS_BASE)
|
|
120
|
+
test_vocs.objectives = {}
|
|
121
|
+
test_vocs.observables = ["y1"]
|
|
113
122
|
test_vocs.constraints = {}
|
|
114
123
|
gen = BaxGenerator(
|
|
115
124
|
vocs=test_vocs,
|
|
@@ -123,6 +132,8 @@ class TestBaxGenerator:
|
|
|
123
132
|
|
|
124
133
|
# test w/ constraints
|
|
125
134
|
test_vocs = deepcopy(TEST_VOCS_BASE)
|
|
135
|
+
test_vocs.objectives = {}
|
|
136
|
+
test_vocs.observables = ["y1"]
|
|
126
137
|
gen = BaxGenerator(
|
|
127
138
|
vocs=test_vocs,
|
|
128
139
|
algorithm=alg,
|
|
@@ -135,8 +146,11 @@ class TestBaxGenerator:
|
|
|
135
146
|
|
|
136
147
|
def test_cuda(self):
|
|
137
148
|
alg = GridMinimize()
|
|
149
|
+
test_vocs = deepcopy(TEST_VOCS_BASE)
|
|
150
|
+
test_vocs.objectives = {}
|
|
151
|
+
test_vocs.observables = ["y1"]
|
|
138
152
|
gen = BaxGenerator(
|
|
139
|
-
vocs=
|
|
153
|
+
vocs=test_vocs,
|
|
140
154
|
algorithm=alg,
|
|
141
155
|
)
|
|
142
156
|
|
|
@@ -151,13 +165,16 @@ class TestBaxGenerator:
|
|
|
151
165
|
evaluator = Evaluator(function=xtest_callable)
|
|
152
166
|
alg = GridMinimize()
|
|
153
167
|
|
|
168
|
+
test_vocs = deepcopy(TEST_VOCS_BASE)
|
|
169
|
+
test_vocs.objectives = {}
|
|
170
|
+
test_vocs.observables = ["y1"]
|
|
154
171
|
gen = BaxGenerator(
|
|
155
|
-
vocs=
|
|
172
|
+
vocs=test_vocs,
|
|
156
173
|
algorithm=alg,
|
|
157
174
|
)
|
|
158
175
|
gen.numerical_optimizer.n_restarts = 1
|
|
159
176
|
|
|
160
|
-
xopt = Xopt(generator=gen, evaluator=evaluator, vocs=
|
|
177
|
+
xopt = Xopt(generator=gen, evaluator=evaluator, vocs=test_vocs)
|
|
161
178
|
|
|
162
179
|
# initialize with single initial candidate
|
|
163
180
|
xopt.random_evaluate(3)
|
|
@@ -167,12 +184,13 @@ class TestBaxGenerator:
|
|
|
167
184
|
evaluator = Evaluator(function=xtest_callable)
|
|
168
185
|
alg = GridMinimize()
|
|
169
186
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
187
|
+
test_vocs = deepcopy(TEST_VOCS_BASE)
|
|
188
|
+
test_vocs.objectives = {}
|
|
189
|
+
test_vocs.observables = ["y1"]
|
|
190
|
+
gen = BaxGenerator(vocs=test_vocs, algorithm=alg, algorithm_results_file="test")
|
|
173
191
|
gen.numerical_optimizer.n_restarts = 1
|
|
174
192
|
|
|
175
|
-
xopt = Xopt(generator=gen, evaluator=evaluator, vocs=
|
|
193
|
+
xopt = Xopt(generator=gen, evaluator=evaluator, vocs=test_vocs)
|
|
176
194
|
|
|
177
195
|
# initialize with single initial candidate
|
|
178
196
|
xopt.random_evaluate(3)
|
|
@@ -191,3 +209,10 @@ class TestBaxGenerator:
|
|
|
191
209
|
|
|
192
210
|
os.remove("test_1.pkl")
|
|
193
211
|
os.remove("test_2.pkl")
|
|
212
|
+
|
|
213
|
+
def test_vocs_validation(self):
|
|
214
|
+
test_vocs = deepcopy(TEST_VOCS_BASE)
|
|
215
|
+
alg = GridMinimize()
|
|
216
|
+
|
|
217
|
+
with pytest.raises(ValidationError):
|
|
218
|
+
BaxGenerator(vocs=test_vocs, algorithm=alg)
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
from copy import deepcopy
|
|
2
2
|
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from pydantic import ValidationError
|
|
6
|
+
|
|
3
7
|
from xopt.base import Xopt
|
|
4
8
|
from xopt.evaluator import Evaluator
|
|
5
9
|
from xopt.generators.bayesian.bayesian_exploration import BayesianExplorationGenerator
|
|
@@ -76,3 +80,9 @@ class TestBayesianExplorationGenerator:
|
|
|
76
80
|
X.step()
|
|
77
81
|
X.step()
|
|
78
82
|
assert len(X.data) == 20
|
|
83
|
+
|
|
84
|
+
def test_vocs_validation(self):
|
|
85
|
+
test_vocs = deepcopy(TEST_VOCS_BASE)
|
|
86
|
+
|
|
87
|
+
with pytest.raises(ValidationError):
|
|
88
|
+
BayesianExplorationGenerator(vocs=test_vocs)
|
|
@@ -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()
|
|
@@ -13,6 +13,7 @@ from botorch.models.transforms import Normalize, Standardize
|
|
|
13
13
|
from gpytorch import ExactMarginalLogLikelihood
|
|
14
14
|
from gpytorch.kernels import PeriodicKernel, PolynomialKernel, ScaleKernel
|
|
15
15
|
from gpytorch.likelihoods import GaussianLikelihood
|
|
16
|
+
from gpytorch.means import ConstantMean
|
|
16
17
|
from gpytorch.priors import GammaPrior
|
|
17
18
|
from pydantic import ValidationError
|
|
18
19
|
|
|
@@ -437,6 +438,23 @@ class TestModelConstructor:
|
|
|
437
438
|
assert torch.allclose(generated_pred, benchmark_pred, rtol=1e-3)
|
|
438
439
|
assert ~torch.allclose(generated_pred, old_prediction, rtol=1e-3)
|
|
439
440
|
|
|
441
|
+
def test_unused_modules_warning(self):
|
|
442
|
+
test_vocs = deepcopy(TEST_VOCS_BASE)
|
|
443
|
+
test_data = deepcopy(TEST_VOCS_DATA)
|
|
444
|
+
|
|
445
|
+
# test unused covariance or mean module
|
|
446
|
+
kwargs_covar = {"covar_modules": {"faulty_output_name": PeriodicKernel()}}
|
|
447
|
+
kwargs_mean = {"mean_modules": {"faulty_output_name": ConstantMean()}}
|
|
448
|
+
|
|
449
|
+
for kwargs in [kwargs_covar, kwargs_mean]:
|
|
450
|
+
gp_constructor = StandardModelConstructor(**kwargs)
|
|
451
|
+
generator = ExpectedImprovementGenerator(
|
|
452
|
+
vocs=test_vocs, gp_constructor=gp_constructor
|
|
453
|
+
)
|
|
454
|
+
generator.add_data(test_data)
|
|
455
|
+
with pytest.warns(UserWarning):
|
|
456
|
+
_ = generator.train_model()
|
|
457
|
+
|
|
440
458
|
def test_heteroskedastic(self):
|
|
441
459
|
test_data = deepcopy(TEST_VOCS_DATA)
|
|
442
460
|
test_vocs = deepcopy(TEST_VOCS_BASE)
|
|
@@ -487,6 +505,22 @@ class TestModelConstructor:
|
|
|
487
505
|
posterior.variance[..., 0].flatten(), bposterior.variance.flatten()
|
|
488
506
|
)
|
|
489
507
|
|
|
508
|
+
def test_custom_noise_prior(self):
|
|
509
|
+
test_data = deepcopy(TEST_VOCS_DATA)
|
|
510
|
+
test_vocs = deepcopy(TEST_VOCS_BASE)
|
|
511
|
+
|
|
512
|
+
noise_prior = GammaPrior(1.0, 1000.0)
|
|
513
|
+
|
|
514
|
+
gp_constructor = StandardModelConstructor(custom_noise_prior=noise_prior)
|
|
515
|
+
model = gp_constructor.build_model_from_vocs(test_vocs, test_data)
|
|
516
|
+
|
|
517
|
+
# check if created models have the correct noise priors
|
|
518
|
+
assert model.models[0].likelihood.noise_covar.noise_prior.rate == 1000.0
|
|
519
|
+
assert model.models[0].likelihood.noise_covar.noise_prior.concentration == 1.0
|
|
520
|
+
|
|
521
|
+
assert model.models[1].likelihood.noise_covar.noise_prior.rate == 1000.0
|
|
522
|
+
assert model.models[1].likelihood.noise_covar.noise_prior.concentration == 1.0
|
|
523
|
+
|
|
490
524
|
@pytest.fixture(autouse=True)
|
|
491
525
|
def clean_up(self):
|
|
492
526
|
yield
|
|
@@ -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()
|
|
@@ -138,7 +138,7 @@ class TestNelderMeadGenerator:
|
|
|
138
138
|
data = X.vocs.variable_data(X.data).to_numpy()
|
|
139
139
|
assert np.array_equal(data, scipy_data)
|
|
140
140
|
|
|
141
|
-
idx, best = X.vocs.select_best(X.data)
|
|
141
|
+
idx, best, _ = X.vocs.select_best(X.data)
|
|
142
142
|
xbest = X.vocs.variable_data(X.data.loc[idx, :]).to_numpy().flatten()
|
|
143
143
|
assert np.array_equal(
|
|
144
144
|
xbest, result.x
|
|
@@ -216,7 +216,7 @@ class TestNelderMeadGenerator:
|
|
|
216
216
|
assert data.shape == scipy_data.shape
|
|
217
217
|
assert np.allclose(data, scipy_data, rtol=0, atol=1e-10)
|
|
218
218
|
|
|
219
|
-
idx, best = X.vocs.select_best(X.data)
|
|
219
|
+
idx, best, _ = X.vocs.select_best(X.data)
|
|
220
220
|
xbest = X.vocs.variable_data(X.data.loc[idx, :]).to_numpy().flatten()
|
|
221
221
|
assert np.array_equal(
|
|
222
222
|
xbest, result.x
|
|
@@ -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)
|
|
@@ -3,6 +3,7 @@ from copy import deepcopy
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
import pandas as pd
|
|
5
5
|
import pytest
|
|
6
|
+
from pydantic import ValidationError
|
|
6
7
|
|
|
7
8
|
from xopt.resources.testing import TEST_VOCS_BASE, TEST_VOCS_DATA
|
|
8
9
|
from xopt.vocs import ObjectiveEnum, VOCS
|
|
@@ -26,6 +27,36 @@ class TestVOCS(object):
|
|
|
26
27
|
variables={"x": [0, 1]},
|
|
27
28
|
)
|
|
28
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
|
+
|
|
38
|
+
def test_constraint_specification(self):
|
|
39
|
+
good_constraint_list = [
|
|
40
|
+
["LESS_THAN", 0],
|
|
41
|
+
["GREATER_THAN", 0],
|
|
42
|
+
["less_than", 0],
|
|
43
|
+
["greater_than", 0],
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
for ele in good_constraint_list:
|
|
47
|
+
VOCS(variables={"x": [0, 1]}, constraints={"c": ele})
|
|
48
|
+
|
|
49
|
+
bad_constraint_list = [
|
|
50
|
+
["LESS_THAN"],
|
|
51
|
+
["GREATER_TAN", 0],
|
|
52
|
+
[0, "less_than"],
|
|
53
|
+
["greater_than", "ahc"],
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
for ele in bad_constraint_list:
|
|
57
|
+
with pytest.raises(ValidationError):
|
|
58
|
+
VOCS(variables={"x": [0, 1]}, constraints={"c": ele})
|
|
59
|
+
|
|
29
60
|
def test_from_yaml(self):
|
|
30
61
|
Y = """
|
|
31
62
|
variables:
|
|
@@ -63,7 +94,11 @@ class TestVOCS(object):
|
|
|
63
94
|
data = pd.DataFrame(vocs.random_inputs(n_samples))
|
|
64
95
|
assert data.shape == (n_samples, vocs.n_inputs)
|
|
65
96
|
|
|
66
|
-
TEST_VOCS_BASE.random_inputs(5, include_constants=False)
|
|
97
|
+
test_inputs = TEST_VOCS_BASE.random_inputs(5, include_constants=False)
|
|
98
|
+
assert len(test_inputs) == 5
|
|
99
|
+
|
|
100
|
+
test_inputs = TEST_VOCS_BASE.random_inputs()
|
|
101
|
+
assert isinstance(test_inputs[0]["x1"], float)
|
|
67
102
|
|
|
68
103
|
def test_serialization(self):
|
|
69
104
|
vocs = deepcopy(TEST_VOCS_BASE)
|
|
@@ -181,32 +216,40 @@ class TestVOCS(object):
|
|
|
181
216
|
|
|
182
217
|
# test maximization
|
|
183
218
|
vocs.objectives[vocs.objective_names[0]] = "MAXIMIZE"
|
|
184
|
-
idx, val = vocs.select_best(test_data)
|
|
219
|
+
idx, val, _ = vocs.select_best(test_data)
|
|
185
220
|
assert idx == [2]
|
|
186
221
|
assert val == [1.0]
|
|
187
222
|
|
|
188
223
|
vocs.constraints = {}
|
|
189
|
-
idx, val = vocs.select_best(test_data)
|
|
224
|
+
idx, val, _ = vocs.select_best(test_data)
|
|
190
225
|
assert idx == [3]
|
|
191
226
|
assert val == [1.5]
|
|
192
227
|
|
|
193
228
|
# test returning multiple best values -- sorted by best value
|
|
194
|
-
idx, val = vocs.select_best(test_data, 2)
|
|
229
|
+
idx, val, _ = vocs.select_best(test_data, 2)
|
|
195
230
|
assert np.allclose(idx, np.array([3, 2]))
|
|
196
231
|
assert np.allclose(val, np.array([1.5, 1.0]))
|
|
197
232
|
|
|
198
233
|
# test minimization
|
|
199
234
|
vocs.objectives[vocs.objective_names[0]] = "MINIMIZE"
|
|
200
235
|
vocs.constraints = {"c1": ["GREATER_THAN", 0.5]}
|
|
201
|
-
idx, val = vocs.select_best(test_data)
|
|
236
|
+
idx, val, _ = vocs.select_best(test_data)
|
|
202
237
|
assert idx == [0]
|
|
203
238
|
assert val == [0.5]
|
|
204
239
|
|
|
205
240
|
vocs.constraints = {}
|
|
206
|
-
idx, val = vocs.select_best(test_data)
|
|
241
|
+
idx, val, _ = vocs.select_best(test_data)
|
|
207
242
|
assert idx == 1
|
|
208
243
|
assert val == 0.1
|
|
209
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
|
+
|
|
210
253
|
@pytest.mark.filterwarnings("ignore: All-NaN axis encountered")
|
|
211
254
|
def test_cumulative_optimum(self):
|
|
212
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
|
|
|
@@ -405,7 +405,12 @@ class Xopt(XoptBaseModel):
|
|
|
405
405
|
else:
|
|
406
406
|
return new_data
|
|
407
407
|
|
|
408
|
-
def random_evaluate(
|
|
408
|
+
def random_evaluate(
|
|
409
|
+
self,
|
|
410
|
+
n_samples=None,
|
|
411
|
+
seed=None,
|
|
412
|
+
custom_bounds: dict = None,
|
|
413
|
+
):
|
|
409
414
|
"""
|
|
410
415
|
Convenience method to generate random inputs using VOCs and evaluate them.
|
|
411
416
|
|
|
@@ -419,8 +424,9 @@ class Xopt(XoptBaseModel):
|
|
|
419
424
|
The number of random samples to generate.
|
|
420
425
|
seed : int, optional
|
|
421
426
|
The random seed for reproducibility.
|
|
422
|
-
|
|
423
|
-
|
|
427
|
+
custom_bounds : dict, optional
|
|
428
|
+
Dictionary of vocs-like ranges for random sampling
|
|
429
|
+
|
|
424
430
|
|
|
425
431
|
Returns
|
|
426
432
|
-------
|
|
@@ -428,7 +434,9 @@ class Xopt(XoptBaseModel):
|
|
|
428
434
|
The results of the evaluations added to the internal DataFrame.
|
|
429
435
|
|
|
430
436
|
"""
|
|
431
|
-
random_inputs = self.vocs.random_inputs(
|
|
437
|
+
random_inputs = self.vocs.random_inputs(
|
|
438
|
+
n_samples, seed=seed, custom_bounds=custom_bounds, include_constants=True
|
|
439
|
+
)
|
|
432
440
|
result = self.evaluate_data(random_inputs)
|
|
433
441
|
return result
|
|
434
442
|
|
|
@@ -37,7 +37,9 @@ class Evaluator(XoptBaseModel):
|
|
|
37
37
|
executor : NormalExecutor
|
|
38
38
|
NormalExecutor or any instantiated Executor object
|
|
39
39
|
vectorized : bool, default=False
|
|
40
|
-
If true,
|
|
40
|
+
If true, lists of evaluation points will be sent to the evaluator
|
|
41
|
+
function to be processed in parallel instead of evaluated seperately via
|
|
42
|
+
mapping.
|
|
41
43
|
"""
|
|
42
44
|
|
|
43
45
|
function: Callable
|
|
@@ -20,7 +20,8 @@ class ModelListExpectedInformationGain(MultiObjectiveAnalyticAcquisitionFunction
|
|
|
20
20
|
>>> EIG = ExpectedInformationGain(model, algo)
|
|
21
21
|
>>> eig = EIG(test_X)
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
24
25
|
model: A fitted independent multi-output (ModelList) model.
|
|
25
26
|
"""
|
|
26
27
|
|
|
@@ -62,13 +63,15 @@ class ModelListExpectedInformationGain(MultiObjectiveAnalyticAcquisitionFunction
|
|
|
62
63
|
def forward(self, X: Tensor) -> Tensor:
|
|
63
64
|
r"""Evaluate Expected Information Gain on the candidate set X.
|
|
64
65
|
|
|
65
|
-
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
66
68
|
X: A `(b1 x ... bk) x 1 x d`-dim batched tensor of `d`-dim design points.
|
|
67
69
|
Expected Information Gain is computed for each point individually,
|
|
68
70
|
i.e., what is considered are the marginal posteriors, not the
|
|
69
71
|
joint.
|
|
70
72
|
|
|
71
|
-
Returns
|
|
73
|
+
Returns
|
|
74
|
+
-------
|
|
72
75
|
A `(b1 x ... bk)`-dim tensor of Expected Information Gain values at the
|
|
73
76
|
given design points `X`.
|
|
74
77
|
"""
|
|
@@ -46,7 +46,7 @@ class GridScanAlgorithm(Algorithm, ABC):
|
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
class GridMinimize(GridScanAlgorithm):
|
|
49
|
-
|
|
49
|
+
observable_names_ordered: List[str] = Field(
|
|
50
50
|
default=["y1"],
|
|
51
51
|
description="names of observable/objective models used in this algorithm",
|
|
52
52
|
)
|
|
@@ -3,7 +3,8 @@ import pickle
|
|
|
3
3
|
from copy import deepcopy
|
|
4
4
|
from typing import Dict
|
|
5
5
|
|
|
6
|
-
from pydantic import Field
|
|
6
|
+
from pydantic import Field, field_validator
|
|
7
|
+
from pydantic_core.core_schema import ValidationInfo
|
|
7
8
|
|
|
8
9
|
from xopt.generators.bayesian.bax.acquisition import ModelListExpectedInformationGain
|
|
9
10
|
from xopt.generators.bayesian.bax.algorithms import Algorithm
|
|
@@ -24,6 +25,12 @@ class BaxGenerator(BayesianGenerator):
|
|
|
24
25
|
|
|
25
26
|
_n_calls: int = 0
|
|
26
27
|
|
|
28
|
+
@field_validator("vocs", mode="after")
|
|
29
|
+
def validate_vocs(cls, v, info: ValidationInfo):
|
|
30
|
+
if v.n_objectives != 0:
|
|
31
|
+
raise ValueError("this generator only supports observables")
|
|
32
|
+
return v
|
|
33
|
+
|
|
27
34
|
def generate(self, n_candidates: int) -> list[dict]:
|
|
28
35
|
self._n_calls += 1
|
|
29
36
|
return super().generate(n_candidates)
|
|
@@ -31,7 +38,7 @@ class BaxGenerator(BayesianGenerator):
|
|
|
31
38
|
def _get_acquisition(self, model):
|
|
32
39
|
bax_model_ids = [
|
|
33
40
|
self.vocs.output_names.index(name)
|
|
34
|
-
for name in self.algorithm.
|
|
41
|
+
for name in self.algorithm.observable_names_ordered
|
|
35
42
|
]
|
|
36
43
|
bax_model = model.subset_output(bax_model_ids)
|
|
37
44
|
eig = ModelListExpectedInformationGain(
|
|
@@ -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):
|
|
@@ -25,7 +24,7 @@ class BayesianExplorationGenerator(BayesianGenerator):
|
|
|
25
24
|
@field_validator("vocs", mode="after")
|
|
26
25
|
def validate_vocs(cls, v, info: ValidationInfo):
|
|
27
26
|
if v.n_objectives != 0:
|
|
28
|
-
raise ValueError("this generator only supports
|
|
27
|
+
raise ValueError("this generator only supports observables")
|
|
29
28
|
return v
|
|
30
29
|
|
|
31
30
|
def _get_acquisition(self, model):
|
|
@@ -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__(
|
|
@@ -55,7 +48,8 @@ class qPosteriorVariance(MCAcquisitionFunction):
|
|
|
55
48
|
X_pending: Optional[Tensor] = None,
|
|
56
49
|
) -> None:
|
|
57
50
|
r"""q-Upper Confidence Bound.
|
|
58
|
-
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
59
53
|
model: A fitted model.
|
|
60
54
|
sampler: The sampler used to draw base samples. Defaults to
|
|
61
55
|
`SobolQMCNormalSampler(num_samples=512, collapse_batch_dims=True)`
|
|
@@ -79,10 +73,13 @@ class qPosteriorVariance(MCAcquisitionFunction):
|
|
|
79
73
|
@t_batch_mode_transform()
|
|
80
74
|
def forward(self, X: Tensor) -> Tensor:
|
|
81
75
|
r"""Evaluate qUpperConfidenceBound on the candidate set `X`.
|
|
82
|
-
|
|
76
|
+
Parameters
|
|
77
|
+
----------
|
|
83
78
|
X: A `batch_sahpe x q x d`-dim Tensor of t-batches with `q` `d`-dim design
|
|
84
79
|
points each.
|
|
85
|
-
|
|
80
|
+
|
|
81
|
+
Returns
|
|
82
|
+
-------
|
|
86
83
|
A `batch_shape'`-dim Tensor of Upper Confidence Bound values at the given
|
|
87
84
|
design points `X`, where `batch_shape'` is the broadcasted batch shape of
|
|
88
85
|
model and input `X`.
|
|
@@ -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
|
{xopt-2.2.1 → xopt-2.2.3}/xopt/generators/bayesian/custom_botorch/constrained_acquisition.py
RENAMED
|
@@ -18,8 +18,8 @@ class FeasibilityObjective(GenericMCObjective):
|
|
|
18
18
|
infeasible_cost: float = 0.0,
|
|
19
19
|
eta: float = 1e-3,
|
|
20
20
|
) -> None:
|
|
21
|
-
def ones_callable(X):
|
|
22
|
-
return torch.ones(
|
|
21
|
+
def ones_callable(Z, X=None):
|
|
22
|
+
return torch.ones(Z.shape[:-1])
|
|
23
23
|
|
|
24
24
|
super().__init__(objective=ones_callable)
|
|
25
25
|
self.constraints = constraints
|
|
@@ -29,7 +29,8 @@ class FeasibilityObjective(GenericMCObjective):
|
|
|
29
29
|
def forward(self, samples: Tensor, X: Optional[Tensor] = None) -> Tensor:
|
|
30
30
|
r"""Evaluate the feasibility-weighted objective on the samples.
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
Parameters
|
|
33
|
+
----------
|
|
33
34
|
samples: A `sample_shape x batch_shape x q x m`-dim Tensors of
|
|
34
35
|
samples from a model posterior.
|
|
35
36
|
X: A `batch_shape x q x d`-dim tensor of inputs. Relevant only if
|
|
@@ -38,7 +38,8 @@ class XoptHeteroskedasticSingleTaskGP(BatchedMultiOutputGPyTorchModel, ExactGP):
|
|
|
38
38
|
to specify mean and covariance modules.
|
|
39
39
|
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
Parameters
|
|
42
|
+
----------
|
|
42
43
|
train_X: A `batch_shape x n x d` tensor of training features.
|
|
43
44
|
train_Y: A `batch_shape x n x m` tensor of training observations.
|
|
44
45
|
train_Yvar: A `batch_shape x n x m` tensor of observed measurement
|