xopt 2.2.0__tar.gz → 2.2.2__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.
Files changed (122) hide show
  1. {xopt-2.2.0/xopt.egg-info → xopt-2.2.2}/PKG-INFO +1 -1
  2. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/bayesian/test_bax.py +33 -8
  3. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/bayesian/test_bayesian_exploration.py +10 -0
  4. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/bayesian/test_model_constructor.py +34 -0
  5. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/test_neldermead.py +2 -2
  6. {xopt-2.2.0 → xopt-2.2.2}/tests/test_vocs.py +34 -7
  7. {xopt-2.2.0 → xopt-2.2.2}/tests/test_xopt.py +2 -2
  8. {xopt-2.2.0 → xopt-2.2.2}/xopt/_version.py +3 -3
  9. {xopt-2.2.0 → xopt-2.2.2}/xopt/asynchronous.py +6 -1
  10. {xopt-2.2.0 → xopt-2.2.2}/xopt/base.py +12 -4
  11. {xopt-2.2.0 → xopt-2.2.2}/xopt/evaluator.py +3 -1
  12. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/bax/acquisition.py +6 -3
  13. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/bax/algorithms.py +1 -1
  14. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/bax_generator.py +9 -2
  15. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/bayesian_exploration.py +8 -4
  16. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/custom_botorch/constrained_acquisition.py +4 -3
  17. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/custom_botorch/heteroskedastic.py +2 -1
  18. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/custom_botorch/identity.py +5 -2
  19. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/custom_botorch/proximal.py +8 -4
  20. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/models/prior_mean.py +2 -1
  21. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/models/standard.py +39 -12
  22. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/multi_fidelity.py +1 -1
  23. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/objectives.py +2 -2
  24. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/turbo.py +2 -2
  25. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/visualize.py +43 -17
  26. {xopt-2.2.0 → xopt-2.2.2}/xopt/pydantic.py +4 -2
  27. xopt-2.2.2/xopt/resources/test_functions/sphere_100.py +13 -0
  28. xopt-2.2.2/xopt/resources/test_functions/sphere_50.py +13 -0
  29. {xopt-2.2.0 → xopt-2.2.2}/xopt/resources/testing.py +7 -2
  30. {xopt-2.2.0 → xopt-2.2.2}/xopt/vocs.py +131 -60
  31. {xopt-2.2.0 → xopt-2.2.2/xopt.egg-info}/PKG-INFO +1 -1
  32. {xopt-2.2.0 → xopt-2.2.2}/xopt.egg-info/SOURCES.txt +2 -0
  33. {xopt-2.2.0 → xopt-2.2.2}/LICENSE +0 -0
  34. {xopt-2.2.0 → xopt-2.2.2}/MANIFEST.in +0 -0
  35. {xopt-2.2.0 → xopt-2.2.2}/README.md +0 -0
  36. {xopt-2.2.0 → xopt-2.2.2}/benchmarks/__init__.py +0 -0
  37. {xopt-2.2.0 → xopt-2.2.2}/benchmarks/test_mo.py +0 -0
  38. {xopt-2.2.0 → xopt-2.2.2}/requirements.txt +0 -0
  39. {xopt-2.2.0 → xopt-2.2.2}/setup.cfg +0 -0
  40. {xopt-2.2.0 → xopt-2.2.2}/setup.py +0 -0
  41. {xopt-2.2.0 → xopt-2.2.2}/tests/__init__.py +0 -0
  42. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/__init__.py +0 -0
  43. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/bayesian/__init__.py +0 -0
  44. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/bayesian/test_bayesian_generator.py +0 -0
  45. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/bayesian/test_constraints.py +0 -0
  46. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/bayesian/test_custom_model.py +0 -0
  47. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/bayesian/test_expected_improvement.py +0 -0
  48. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/bayesian/test_hessian_kernel.py +0 -0
  49. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/bayesian/test_high_level.py +0 -0
  50. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/bayesian/test_mggpo.py +0 -0
  51. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/bayesian/test_mobo.py +0 -0
  52. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/bayesian/test_multi_fidelity.py +0 -0
  53. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/bayesian/test_time_dependent_bo.py +0 -0
  54. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/bayesian/test_turbo.py +0 -0
  55. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/bayesian/test_upper_confidence_bound.py +0 -0
  56. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/bayesian/test_utils.py +0 -0
  57. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/test_extremum_seeking.py +0 -0
  58. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/test_latin_hypercube.py +0 -0
  59. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/test_random.py +0 -0
  60. {xopt-2.2.0 → xopt-2.2.2}/tests/generators/test_rcds.py +0 -0
  61. {xopt-2.2.0 → xopt-2.2.2}/tests/test_evaluator.py +0 -0
  62. {xopt-2.2.0 → xopt-2.2.2}/tests/test_generator.py +0 -0
  63. {xopt-2.2.0 → xopt-2.2.2}/tests/test_io.py +0 -0
  64. {xopt-2.2.0 → xopt-2.2.2}/tests/test_mpi.py +0 -0
  65. {xopt-2.2.0 → xopt-2.2.2}/tests/test_numerical_optimizer.py +0 -0
  66. {xopt-2.2.0 → xopt-2.2.2}/tests/test_perf.py +0 -0
  67. {xopt-2.2.0 → xopt-2.2.2}/tests/test_pydantic.py +0 -0
  68. {xopt-2.2.0 → xopt-2.2.2}/tests/test_utils.py +0 -0
  69. {xopt-2.2.0 → xopt-2.2.2}/versioneer.py +0 -0
  70. {xopt-2.2.0 → xopt-2.2.2}/xopt/__init__.py +0 -0
  71. {xopt-2.2.0 → xopt-2.2.2}/xopt/errors.py +0 -0
  72. {xopt-2.2.0 → xopt-2.2.2}/xopt/generator.py +0 -0
  73. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/__init__.py +0 -0
  74. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/__init__.py +0 -0
  75. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/base_model.py +0 -0
  76. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/bax/__init__.py +0 -0
  77. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/bayesian_generator.py +0 -0
  78. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/custom_botorch/__init__.py +0 -0
  79. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/custom_botorch/hessian_kernel.py +0 -0
  80. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/custom_botorch/log_acquisition_function.py +0 -0
  81. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/custom_botorch/multi_fidelity.py +0 -0
  82. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/expected_improvement.py +0 -0
  83. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/mggpo.py +0 -0
  84. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/mobo.py +0 -0
  85. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/models/__init__.py +0 -0
  86. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/models/time_dependent.py +0 -0
  87. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/time_dependent.py +0 -0
  88. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/upper_confidence_bound.py +0 -0
  89. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/bayesian/utils.py +0 -0
  90. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/es/__init__.py +0 -0
  91. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/es/extremumseeking.py +0 -0
  92. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/ga/__init__.py +0 -0
  93. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/ga/cnsga.py +0 -0
  94. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/ga/deap_creator.py +0 -0
  95. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/ga/deap_fitness_with_constraints.py +0 -0
  96. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/ga/fitness_with_constraints.py +0 -0
  97. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/random.py +0 -0
  98. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/rcds/__init__.py +0 -0
  99. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/rcds/rcds.py +0 -0
  100. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/scipy/__init__.py +0 -0
  101. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/scipy/latin_hypercube.py +0 -0
  102. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/scipy/neldermead.py +0 -0
  103. {xopt-2.2.0 → xopt-2.2.2}/xopt/generators/utils.py +0 -0
  104. {xopt-2.2.0 → xopt-2.2.2}/xopt/log.py +0 -0
  105. {xopt-2.2.0 → xopt-2.2.2}/xopt/mpi/__init__.py +0 -0
  106. {xopt-2.2.0 → xopt-2.2.2}/xopt/mpi/run.py +0 -0
  107. {xopt-2.2.0 → xopt-2.2.2}/xopt/numerical_optimizer.py +0 -0
  108. {xopt-2.2.0 → xopt-2.2.2}/xopt/resources/__init__.py +0 -0
  109. {xopt-2.2.0 → xopt-2.2.2}/xopt/resources/benchmarking.py +0 -0
  110. {xopt-2.2.0 → xopt-2.2.2}/xopt/resources/test_functions/__init__.py +0 -0
  111. {xopt-2.2.0 → xopt-2.2.2}/xopt/resources/test_functions/ackley_20.py +0 -0
  112. {xopt-2.2.0 → xopt-2.2.2}/xopt/resources/test_functions/modified_tnk.py +0 -0
  113. {xopt-2.2.0 → xopt-2.2.2}/xopt/resources/test_functions/multi_objective.py +0 -0
  114. {xopt-2.2.0 → xopt-2.2.2}/xopt/resources/test_functions/problem.py +0 -0
  115. {xopt-2.2.0 → xopt-2.2.2}/xopt/resources/test_functions/rosenbrock.py +0 -0
  116. {xopt-2.2.0 → xopt-2.2.2}/xopt/resources/test_functions/sinusoid_1d.py +0 -0
  117. {xopt-2.2.0 → xopt-2.2.2}/xopt/resources/test_functions/sphere_20.py +0 -0
  118. {xopt-2.2.0 → xopt-2.2.2}/xopt/resources/test_functions/tnk.py +0 -0
  119. {xopt-2.2.0 → xopt-2.2.2}/xopt/utils.py +0 -0
  120. {xopt-2.2.0 → xopt-2.2.2}/xopt.egg-info/dependency_links.txt +0 -0
  121. {xopt-2.2.0 → xopt-2.2.2}/xopt.egg-info/requires.txt +0 -0
  122. {xopt-2.2.0 → xopt-2.2.2}/xopt.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: xopt
3
- Version: 2.2.0
3
+ Version: 2.2.2
4
4
  Home-page: https://github.com/ChristopherMayes/xopt
5
5
  Requires-Python: >=3.9
6
6
  Description-Content-Type: text/markdown
@@ -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=deepcopy(TEST_VOCS_BASE),
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=TEST_VOCS_BASE,
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=TEST_VOCS_BASE,
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=TEST_VOCS_BASE)
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
- gen = BaxGenerator(
171
- vocs=TEST_VOCS_BASE, algorithm=alg, algorithm_results_file="test"
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=TEST_VOCS_BASE)
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)
@@ -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
@@ -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,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,28 @@ class TestVOCS(object):
26
27
  variables={"x": [0, 1]},
27
28
  )
28
29
 
30
+ def test_constraint_specification(self):
31
+ good_constraint_list = [
32
+ ["LESS_THAN", 0],
33
+ ["GREATER_THAN", 0],
34
+ ["less_than", 0],
35
+ ["greater_than", 0],
36
+ ]
37
+
38
+ for ele in good_constraint_list:
39
+ VOCS(variables={"x": [0, 1]}, constraints={"c": ele})
40
+
41
+ bad_constraint_list = [
42
+ ["LESS_THAN"],
43
+ ["GREATER_TAN", 0],
44
+ [0, "less_than"],
45
+ ["greater_than", "ahc"],
46
+ ]
47
+
48
+ for ele in bad_constraint_list:
49
+ with pytest.raises(ValidationError):
50
+ VOCS(variables={"x": [0, 1]}, constraints={"c": ele})
51
+
29
52
  def test_from_yaml(self):
30
53
  Y = """
31
54
  variables:
@@ -63,7 +86,11 @@ class TestVOCS(object):
63
86
  data = pd.DataFrame(vocs.random_inputs(n_samples))
64
87
  assert data.shape == (n_samples, vocs.n_inputs)
65
88
 
66
- TEST_VOCS_BASE.random_inputs(5, include_constants=False)
89
+ test_inputs = TEST_VOCS_BASE.random_inputs(5, include_constants=False)
90
+ assert len(test_inputs) == 5
91
+
92
+ test_inputs = TEST_VOCS_BASE.random_inputs()
93
+ assert isinstance(test_inputs[0]["x1"], float)
67
94
 
68
95
  def test_serialization(self):
69
96
  vocs = deepcopy(TEST_VOCS_BASE)
@@ -149,7 +176,7 @@ class TestVOCS(object):
149
176
  vocs.convert_dataframe_to_inputs(test_data)
150
177
 
151
178
  res = vocs.convert_dataframe_to_inputs(test_data[vocs.variable_names])
152
- assert "cnt1" in res
179
+ assert "constant1" in res
153
180
 
154
181
  def test_validate_input_data(self):
155
182
  test_vocs = deepcopy(TEST_VOCS_BASE)
@@ -181,29 +208,29 @@ class TestVOCS(object):
181
208
 
182
209
  # test maximization
183
210
  vocs.objectives[vocs.objective_names[0]] = "MAXIMIZE"
184
- idx, val = vocs.select_best(test_data)
211
+ idx, val, _ = vocs.select_best(test_data)
185
212
  assert idx == [2]
186
213
  assert val == [1.0]
187
214
 
188
215
  vocs.constraints = {}
189
- idx, val = vocs.select_best(test_data)
216
+ idx, val, _ = vocs.select_best(test_data)
190
217
  assert idx == [3]
191
218
  assert val == [1.5]
192
219
 
193
220
  # test returning multiple best values -- sorted by best value
194
- idx, val = vocs.select_best(test_data, 2)
221
+ idx, val, _ = vocs.select_best(test_data, 2)
195
222
  assert np.allclose(idx, np.array([3, 2]))
196
223
  assert np.allclose(val, np.array([1.5, 1.0]))
197
224
 
198
225
  # test minimization
199
226
  vocs.objectives[vocs.objective_names[0]] = "MINIMIZE"
200
227
  vocs.constraints = {"c1": ["GREATER_THAN", 0.5]}
201
- idx, val = vocs.select_best(test_data)
228
+ idx, val, _ = vocs.select_best(test_data)
202
229
  assert idx == [0]
203
230
  assert val == [0.5]
204
231
 
205
232
  vocs.constraints = {}
206
- idx, val = vocs.select_best(test_data)
233
+ idx, val, _ = vocs.select_best(test_data)
207
234
  assert idx == 1
208
235
  assert val == 0.1
209
236
 
@@ -208,7 +208,7 @@ class TestXopt:
208
208
  xopt = Xopt(generator=generator, evaluator=evaluator, vocs=test_vocs)
209
209
 
210
210
  test_vocs.variables = {"x2": [0, 1]}
211
- test_vocs.constants = {"x1": 2.0}
211
+ test_vocs.constants["x1"] = 2.0
212
212
 
213
213
  out = xopt.evaluate({"x2": 0.2})
214
214
  assert isinstance(out, dict)
@@ -259,7 +259,7 @@ class TestXopt:
259
259
  val = str(xopt)
260
260
  assert "Data size: 2" in val
261
261
  assert (
262
- "vocs:\n constants:\n cnt1: 1.0\n constraints:\n c1:\n - "
262
+ "vocs:\n constants:\n constant1: 1.0\n constraints:\n c1:\n - "
263
263
  "GREATER_THAN\n - 0.5\n objectives:\n" in val
264
264
  )
265
265
 
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2024-01-31T21:53:10-0600",
11
+ "date": "2024-04-15T14:51:35-0400",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "6cb0704de59be6542d9889f1f931e2d29a4a2512",
15
- "version": "2.2.0"
14
+ "full-revisionid": "a613b00abdb1ff1809a10b82096947803834cec5",
15
+ "version": "2.2.2"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -31,7 +31,8 @@ class AsynchronousXopt(Xopt):
31
31
  """
32
32
  Submit data to evaluator and return futures indexed to internal futures list.
33
33
 
34
- Args:
34
+ Parameters
35
+ ----------
35
36
  input_data: dataframe containing input data
36
37
 
37
38
  """
@@ -69,6 +70,10 @@ class AsynchronousXopt(Xopt):
69
70
  """
70
71
  input_data = pd.DataFrame(input_data, copy=True) # copy for reindexing
71
72
 
73
+ # add constants to input data
74
+ for name, value in self.vocs.constants.items():
75
+ input_data[name] = value
76
+
72
77
  # Reindex input dataframe
73
78
  input_data.index = np.arange(
74
79
  self._ix_last + 1, self._ix_last + 1 + len(input_data)
@@ -405,7 +405,12 @@ class Xopt(XoptBaseModel):
405
405
  else:
406
406
  return new_data
407
407
 
408
- def random_evaluate(self, n_samples=1, seed=None, **kwargs):
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
- **kwargs
423
- Additional keyword arguments for generating random inputs.
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(n_samples, seed=seed, **kwargs)
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
- Args:
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
- Args:
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
- model_names_ordered: List[str] = Field(
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.model_names_ordered
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(
@@ -25,7 +25,7 @@ class BayesianExplorationGenerator(BayesianGenerator):
25
25
  @field_validator("vocs", mode="after")
26
26
  def validate_vocs(cls, v, info: ValidationInfo):
27
27
  if v.n_objectives != 0:
28
- raise ValueError("this generator only supports zero objectives only")
28
+ raise ValueError("this generator only supports observables")
29
29
  return v
30
30
 
31
31
  def _get_acquisition(self, model):
@@ -55,7 +55,8 @@ class qPosteriorVariance(MCAcquisitionFunction):
55
55
  X_pending: Optional[Tensor] = None,
56
56
  ) -> None:
57
57
  r"""q-Upper Confidence Bound.
58
- Args:
58
+ Parameters
59
+ ----------
59
60
  model: A fitted model.
60
61
  sampler: The sampler used to draw base samples. Defaults to
61
62
  `SobolQMCNormalSampler(num_samples=512, collapse_batch_dims=True)`
@@ -79,10 +80,13 @@ class qPosteriorVariance(MCAcquisitionFunction):
79
80
  @t_batch_mode_transform()
80
81
  def forward(self, X: Tensor) -> Tensor:
81
82
  r"""Evaluate qUpperConfidenceBound on the candidate set `X`.
82
- Args:
83
+ Parameters
84
+ ----------
83
85
  X: A `batch_sahpe x q x d`-dim Tensor of t-batches with `q` `d`-dim design
84
86
  points each.
85
- Returns:
87
+
88
+ Returns
89
+ -------
86
90
  A `batch_shape'`-dim Tensor of Upper Confidence Bound values at the given
87
91
  design points `X`, where `batch_shape'` is the broadcasted batch shape of
88
92
  model and input `X`.
@@ -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(X.shape[:-1])
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
- Args:
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
- Args:
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
@@ -11,10 +11,13 @@ class Identity(AcquisitionFunction):
11
11
  @t_batch_mode_transform()
12
12
  def forward(self, X: Tensor) -> Tensor:
13
13
  r"""Evaluate qUpperConfidenceBound on the candidate set `X`.
14
- Args:
14
+ Parameters
15
+ ----------
15
16
  X: A `batch_sahpe x q x d`-dim Tensor of t-batches with `q` `d`-dim design
16
17
  points each.
17
- Returns:
18
+
19
+ Returns
20
+ -------
18
21
  A `batch_shape'`-dim Tensor of Upper Confidence Bound values at the given
19
22
  design points `X`, where `batch_shape'` is the broadcasted batch shape of
20
23
  model and input `X`.
@@ -55,7 +55,8 @@ class ProximalAcquisitionFunction(AcquisitionFunction):
55
55
  r"""Derived Acquisition Function weighted by proximity to recently
56
56
  observed point.
57
57
 
58
- Args:
58
+ Parameters
59
+ ----------
59
60
  acq_function: The base acquisition function, operating on input tensors
60
61
  of feature dimension `d`.
61
62
  proximal_weights: A `d` dim tensor used to bias locality
@@ -89,10 +90,12 @@ class ProximalAcquisitionFunction(AcquisitionFunction):
89
90
  def forward(self, X: Tensor) -> Tensor:
90
91
  r"""Evaluate base acquisition function with proximal weighting.
91
92
 
92
- Args:
93
+ Parameters
94
+ ----------
93
95
  X: Input tensor of feature dimension `d` .
94
96
 
95
- Returns:
97
+ Returns
98
+ -------
96
99
  Base acquisition function evaluated on tensor `X` multiplied by proximal
97
100
  weighting.
98
101
  """
@@ -143,7 +146,8 @@ def _validate_model(model: Model, proximal_weights: Tensor) -> None:
143
146
  Perform vaidation checks on model used in base acquisition function to make sure
144
147
  it is compatible with proximal weighting.
145
148
 
146
- Args:
149
+ Parameters
150
+ ----------
147
151
  model: Model associated with base acquisition function to be validated.
148
152
  proximal_weights: A `d` dim tensor used to bias locality
149
153
  along each axis.
@@ -14,7 +14,8 @@ class CustomMean(Mean):
14
14
  ):
15
15
  """Custom prior mean for a GP based on an arbitrary model.
16
16
 
17
- Args:
17
+ Parameters
18
+ ----------
18
19
  model: Representation of the model.
19
20
  input_transformer: Module used to transform inputs in the GP.
20
21
  outcome_transformer: Module used to transform outcomes in the GP.