ennbo 0.1.0__py3-none-any.whl → 0.1.7__py3-none-any.whl

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 (123) hide show
  1. enn/__init__.py +25 -13
  2. enn/benchmarks/__init__.py +3 -0
  3. enn/benchmarks/ackley.py +5 -0
  4. enn/benchmarks/ackley_class.py +17 -0
  5. enn/benchmarks/ackley_core.py +12 -0
  6. enn/benchmarks/double_ackley.py +24 -0
  7. enn/enn/candidates.py +14 -0
  8. enn/enn/conditional_posterior_draw_internals.py +15 -0
  9. enn/enn/draw_internals.py +15 -0
  10. enn/enn/enn.py +16 -229
  11. enn/enn/enn_class.py +423 -0
  12. enn/enn/enn_conditional.py +325 -0
  13. enn/enn/enn_fit.py +77 -76
  14. enn/enn/enn_hash.py +79 -0
  15. enn/enn/enn_index.py +92 -0
  16. enn/enn/enn_like_protocol.py +35 -0
  17. enn/enn/enn_normal.py +3 -3
  18. enn/enn/enn_params.py +3 -9
  19. enn/enn/enn_params_class.py +24 -0
  20. enn/enn/enn_util.py +79 -37
  21. enn/enn/neighbor_data.py +14 -0
  22. enn/enn/neighbors.py +14 -0
  23. enn/enn/posterior_flags.py +8 -0
  24. enn/enn/weighted_stats.py +14 -0
  25. enn/turbo/components/__init__.py +41 -0
  26. enn/turbo/components/acquisition.py +13 -0
  27. enn/turbo/components/acquisition_optimizer_protocol.py +19 -0
  28. enn/turbo/components/builder.py +22 -0
  29. enn/turbo/components/chebyshev_incumbent_selector.py +76 -0
  30. enn/turbo/components/enn_surrogate.py +115 -0
  31. enn/turbo/components/gp_surrogate.py +144 -0
  32. enn/turbo/components/hnr_acq_optimizer.py +83 -0
  33. enn/turbo/components/incumbent_selector.py +11 -0
  34. enn/turbo/components/incumbent_selector_protocol.py +16 -0
  35. enn/turbo/components/no_incumbent_selector.py +21 -0
  36. enn/turbo/components/no_surrogate.py +49 -0
  37. enn/turbo/components/pareto_acq_optimizer.py +49 -0
  38. enn/turbo/components/posterior_result.py +12 -0
  39. enn/turbo/components/protocols.py +13 -0
  40. enn/turbo/components/random_acq_optimizer.py +21 -0
  41. enn/turbo/components/scalar_incumbent_selector.py +39 -0
  42. enn/turbo/components/surrogate_protocol.py +32 -0
  43. enn/turbo/components/surrogate_result.py +12 -0
  44. enn/turbo/components/surrogates.py +5 -0
  45. enn/turbo/components/thompson_acq_optimizer.py +49 -0
  46. enn/turbo/components/trust_region_protocol.py +24 -0
  47. enn/turbo/components/ucb_acq_optimizer.py +49 -0
  48. enn/turbo/config/__init__.py +87 -0
  49. enn/turbo/config/acq_type.py +8 -0
  50. enn/turbo/config/acquisition.py +26 -0
  51. enn/turbo/config/base.py +4 -0
  52. enn/turbo/config/candidate_gen_config.py +49 -0
  53. enn/turbo/config/candidate_rv.py +7 -0
  54. enn/turbo/config/draw_acquisition_config.py +14 -0
  55. enn/turbo/config/enn_index_driver.py +6 -0
  56. enn/turbo/config/enn_surrogate_config.py +42 -0
  57. enn/turbo/config/enums.py +7 -0
  58. enn/turbo/config/factory.py +118 -0
  59. enn/turbo/config/gp_surrogate_config.py +14 -0
  60. enn/turbo/config/hnr_optimizer_config.py +7 -0
  61. enn/turbo/config/init_config.py +17 -0
  62. enn/turbo/config/init_strategies/__init__.py +9 -0
  63. enn/turbo/config/init_strategies/hybrid_init.py +23 -0
  64. enn/turbo/config/init_strategies/init_strategy.py +19 -0
  65. enn/turbo/config/init_strategies/lhd_only_init.py +24 -0
  66. enn/turbo/config/morbo_tr_config.py +82 -0
  67. enn/turbo/config/nds_optimizer_config.py +7 -0
  68. enn/turbo/config/no_surrogate_config.py +14 -0
  69. enn/turbo/config/no_tr_config.py +31 -0
  70. enn/turbo/config/optimizer_config.py +72 -0
  71. enn/turbo/config/pareto_acquisition_config.py +14 -0
  72. enn/turbo/config/raasp_driver.py +6 -0
  73. enn/turbo/config/raasp_optimizer_config.py +7 -0
  74. enn/turbo/config/random_acquisition_config.py +14 -0
  75. enn/turbo/config/rescalarize.py +7 -0
  76. enn/turbo/config/surrogate.py +12 -0
  77. enn/turbo/config/trust_region.py +34 -0
  78. enn/turbo/config/turbo_tr_config.py +71 -0
  79. enn/turbo/config/ucb_acquisition_config.py +14 -0
  80. enn/turbo/config/validation.py +45 -0
  81. enn/turbo/hypervolume.py +30 -0
  82. enn/turbo/impl_helpers.py +68 -0
  83. enn/turbo/morbo_trust_region.py +250 -0
  84. enn/turbo/no_trust_region.py +58 -0
  85. enn/turbo/optimizer.py +300 -0
  86. enn/turbo/optimizer_config.py +8 -0
  87. enn/turbo/proposal.py +46 -39
  88. enn/turbo/sampling.py +21 -0
  89. enn/turbo/strategies/__init__.py +9 -0
  90. enn/turbo/strategies/lhd_only_strategy.py +36 -0
  91. enn/turbo/strategies/optimization_strategy.py +19 -0
  92. enn/turbo/strategies/turbo_hybrid_strategy.py +124 -0
  93. enn/turbo/tr_helpers.py +202 -0
  94. enn/turbo/turbo_gp.py +9 -2
  95. enn/turbo/turbo_gp_base.py +0 -1
  96. enn/turbo/turbo_gp_fit.py +187 -0
  97. enn/turbo/turbo_gp_noisy.py +0 -1
  98. enn/turbo/turbo_optimizer_utils.py +98 -0
  99. enn/turbo/turbo_trust_region.py +129 -63
  100. enn/turbo/turbo_utils.py +144 -117
  101. enn/turbo/types/__init__.py +7 -0
  102. enn/turbo/types/appendable_array.py +85 -0
  103. enn/turbo/types/gp_data_prep.py +13 -0
  104. enn/turbo/types/gp_fit_result.py +11 -0
  105. enn/turbo/types/obs_lists.py +10 -0
  106. enn/turbo/types/prepare_ask_result.py +14 -0
  107. enn/turbo/types/tell_inputs.py +14 -0
  108. {ennbo-0.1.0.dist-info → ennbo-0.1.7.dist-info}/METADATA +22 -14
  109. ennbo-0.1.7.dist-info/RECORD +111 -0
  110. enn/enn/__init__.py +0 -4
  111. enn/turbo/__init__.py +0 -11
  112. enn/turbo/base_turbo_impl.py +0 -98
  113. enn/turbo/lhd_only_impl.py +0 -42
  114. enn/turbo/turbo_config.py +0 -28
  115. enn/turbo/turbo_enn_impl.py +0 -176
  116. enn/turbo/turbo_mode.py +0 -10
  117. enn/turbo/turbo_mode_impl.py +0 -67
  118. enn/turbo/turbo_one_impl.py +0 -163
  119. enn/turbo/turbo_optimizer.py +0 -337
  120. enn/turbo/turbo_zero_impl.py +0 -24
  121. ennbo-0.1.0.dist-info/RECORD +0 -27
  122. {ennbo-0.1.0.dist-info → ennbo-0.1.7.dist-info}/WHEEL +0 -0
  123. {ennbo-0.1.0.dist-info → ennbo-0.1.7.dist-info}/licenses/LICENSE +0 -0
@@ -1,176 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import TYPE_CHECKING, Any, Callable
4
-
5
- if TYPE_CHECKING:
6
- import numpy as np
7
- from numpy.random import Generator
8
-
9
- from .base_turbo_impl import BaseTurboImpl
10
- from .turbo_config import TurboConfig
11
-
12
-
13
- class TurboENNImpl(BaseTurboImpl):
14
- def __init__(self, config: TurboConfig) -> None:
15
- super().__init__(config)
16
- self._enn: Any | None = None
17
- self._fitted_params: Any | None = None
18
- self._fitted_n_obs: int = 0
19
-
20
- def get_x_center(
21
- self,
22
- x_obs_list: list,
23
- y_obs_list: list,
24
- rng: Generator,
25
- ) -> np.ndarray | None:
26
- import numpy as np
27
-
28
- from .turbo_utils import argmax_random_tie
29
-
30
- if len(y_obs_list) == 0:
31
- return None
32
- if self._enn is None or self._fitted_params is None:
33
- return super().get_x_center(x_obs_list, y_obs_list, rng)
34
- if self._fitted_n_obs != len(x_obs_list):
35
- raise RuntimeError(
36
- f"ENN fitted on {self._fitted_n_obs} obs but get_x_center called with {len(x_obs_list)}"
37
- )
38
-
39
- y_array = np.asarray(y_obs_list, dtype=float)
40
- x_array = np.asarray(x_obs_list, dtype=float)
41
-
42
- k = self._config.k if self._config.k is not None else 10
43
- num_top = min(k, len(y_array))
44
- top_indices = np.argpartition(-y_array, num_top - 1)[:num_top]
45
-
46
- x_top = x_array[top_indices]
47
- posterior = self._enn.posterior(x_top, params=self._fitted_params)
48
- mu = posterior.mu[:, 0]
49
-
50
- best_idx_in_top = argmax_random_tie(mu, rng=rng)
51
- return x_top[best_idx_in_top]
52
-
53
- def needs_tr_list(self) -> bool:
54
- return True
55
-
56
- def handle_restart(
57
- self,
58
- x_obs_list: list,
59
- y_obs_list: list,
60
- yvar_obs_list: list,
61
- init_idx: int,
62
- num_init: int,
63
- ) -> tuple[bool, int]:
64
- x_obs_list.clear()
65
- y_obs_list.clear()
66
- yvar_obs_list.clear()
67
- return True, 0
68
-
69
- def prepare_ask(
70
- self,
71
- x_obs_list: list,
72
- y_obs_list: list,
73
- yvar_obs_list: list,
74
- num_dim: int,
75
- gp_num_steps: int,
76
- rng: Any | None = None,
77
- ) -> tuple[Any, float | None, float | None, np.ndarray | None]:
78
- from .proposal import mk_enn
79
-
80
- k = self._config.k if self._config.k is not None else 10
81
- self._enn, self._fitted_params = mk_enn(
82
- x_obs_list,
83
- y_obs_list,
84
- yvar_obs_list=yvar_obs_list,
85
- k=k,
86
- num_fit_samples=self._config.num_fit_samples,
87
- num_fit_candidates=self._config.num_fit_candidates,
88
- rng=rng,
89
- params_warm_start=self._fitted_params,
90
- )
91
- self._fitted_n_obs = len(x_obs_list)
92
- return None, None, None, None
93
-
94
- def select_candidates(
95
- self,
96
- x_cand: np.ndarray,
97
- num_arms: int,
98
- num_dim: int,
99
- rng: Generator,
100
- fallback_fn: Callable[[np.ndarray, int], np.ndarray],
101
- from_unit_fn: Callable[[np.ndarray], np.ndarray],
102
- ) -> np.ndarray:
103
- import numpy as np
104
-
105
- from enn.enn.enn_params import ENNParams
106
-
107
- acq_type = self._config.acq_type
108
- k = self._config.k
109
- var_scale = self._config.var_scale
110
-
111
- if self._enn is None:
112
- return fallback_fn(x_cand, num_arms)
113
-
114
- if self._fitted_params is not None:
115
- params = self._fitted_params
116
- else:
117
- k_val = k if k is not None else 10
118
- params = ENNParams(
119
- k=k_val, epi_var_scale=var_scale, ale_homoscedastic_scale=0.0
120
- )
121
-
122
- posterior = self._enn.posterior(x_cand, params=params)
123
- mu = posterior.mu[:, 0]
124
- se = posterior.se[:, 0]
125
-
126
- if acq_type == "pareto":
127
- from enn.enn.enn_util import arms_from_pareto_fronts
128
-
129
- x_arms = arms_from_pareto_fronts(x_cand, mu, se, num_arms, rng)
130
- elif acq_type == "ucb":
131
- scores = mu + se
132
- shuffled_indices = rng.permutation(len(scores))
133
- shuffled_scores = scores[shuffled_indices]
134
- top_k_in_shuffled = np.argpartition(-shuffled_scores, num_arms - 1)[
135
- :num_arms
136
- ]
137
- idx = shuffled_indices[top_k_in_shuffled]
138
- x_arms = x_cand[idx]
139
- elif acq_type == "thompson":
140
- samples = posterior.sample(num_samples=1, rng=rng)
141
- scores = samples[:, 0, 0]
142
- shuffled_indices = rng.permutation(len(scores))
143
- shuffled_scores = scores[shuffled_indices]
144
- top_k_in_shuffled = np.argpartition(-shuffled_scores, num_arms - 1)[
145
- :num_arms
146
- ]
147
- idx = shuffled_indices[top_k_in_shuffled]
148
- x_arms = x_cand[idx]
149
- else:
150
- raise ValueError(f"Unknown acq_type: {acq_type}")
151
-
152
- return from_unit_fn(x_arms)
153
-
154
- def estimate_y(self, x_unit: np.ndarray, y_observed: np.ndarray) -> np.ndarray:
155
- if self._enn is None or self._fitted_params is None:
156
- return y_observed
157
- posterior = self._enn.posterior(x_unit, params=self._fitted_params)
158
- return posterior.mu[:, 0]
159
-
160
- def get_mu_sigma(self, x_unit: np.ndarray) -> tuple[np.ndarray, np.ndarray] | None:
161
- if self._enn is None:
162
- return None
163
- k = self._config.k if self._config.k is not None else 10
164
- from enn.enn.enn_params import ENNParams
165
-
166
- params = (
167
- self._fitted_params
168
- if self._fitted_params is not None
169
- else ENNParams(
170
- k=k, epi_var_scale=self._config.var_scale, ale_homoscedastic_scale=0.0
171
- )
172
- )
173
- posterior = self._enn.posterior(x_unit, params=params, observation_noise=False)
174
- mu = posterior.mu[:, 0]
175
- sigma = posterior.se[:, 0]
176
- return mu, sigma
enn/turbo/turbo_mode.py DELETED
@@ -1,10 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from enum import Enum, auto
4
-
5
-
6
- class TurboMode(Enum):
7
- TURBO_ONE = auto()
8
- TURBO_ZERO = auto()
9
- TURBO_ENN = auto()
10
- LHD_ONLY = auto()
@@ -1,67 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import TYPE_CHECKING, Any, Callable, Protocol
4
-
5
- if TYPE_CHECKING:
6
- import numpy as np
7
- from numpy.random import Generator
8
-
9
-
10
- class TurboModeImpl(Protocol):
11
- def get_x_center(
12
- self,
13
- x_obs_list: list,
14
- y_obs_list: list,
15
- rng: Generator,
16
- ) -> np.ndarray | None: ...
17
-
18
- def needs_tr_list(self) -> bool: ...
19
-
20
- def create_trust_region(self, num_dim: int, num_arms: int) -> Any: ...
21
-
22
- def try_early_ask(
23
- self,
24
- num_arms: int,
25
- x_obs_list: list,
26
- draw_initial_fn: Callable[[int], np.ndarray],
27
- get_init_lhd_points_fn: Callable[[int], np.ndarray | None],
28
- ) -> np.ndarray | None: ...
29
-
30
- def handle_restart(
31
- self,
32
- x_obs_list: list,
33
- y_obs_list: list,
34
- yvar_obs_list: list,
35
- init_idx: int,
36
- num_init: int,
37
- ) -> tuple[bool, int]: ...
38
-
39
- def prepare_ask(
40
- self,
41
- x_obs_list: list,
42
- y_obs_list: list,
43
- yvar_obs_list: list,
44
- num_dim: int,
45
- gp_num_steps: int,
46
- rng: Generator | Any | None = None,
47
- ) -> tuple[Any, float | None, float | None, np.ndarray | None]: ...
48
-
49
- def select_candidates(
50
- self,
51
- x_cand: np.ndarray,
52
- num_arms: int,
53
- num_dim: int,
54
- rng: Generator,
55
- fallback_fn: Callable[[np.ndarray, int], np.ndarray],
56
- from_unit_fn: Callable[[np.ndarray], np.ndarray],
57
- ) -> np.ndarray: ...
58
-
59
- def update_trust_region(
60
- self,
61
- tr_state: Any,
62
- y_obs_list: list,
63
- x_center: np.ndarray | None = None,
64
- k: int | None = None,
65
- ) -> None: ...
66
-
67
- def estimate_y(self, x_unit: np.ndarray, y_observed: np.ndarray) -> np.ndarray: ...
@@ -1,163 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import TYPE_CHECKING, Any, Callable
4
-
5
- if TYPE_CHECKING:
6
- import numpy as np
7
- from numpy.random import Generator
8
-
9
- from .base_turbo_impl import BaseTurboImpl
10
- from .turbo_config import TurboConfig
11
- from .turbo_utils import gp_thompson_sample
12
-
13
-
14
- class TurboOneImpl(BaseTurboImpl):
15
- def __init__(self, config: TurboConfig) -> None:
16
- super().__init__(config)
17
- self._gp_model: Any | None = None
18
- self._gp_y_mean: float = 0.0
19
- self._gp_y_std: float = 1.0
20
- self._fitted_n_obs: int = 0
21
-
22
- def get_x_center(
23
- self,
24
- x_obs_list: list,
25
- y_obs_list: list,
26
- rng: Generator,
27
- ) -> np.ndarray | None:
28
- import numpy as np
29
- import torch
30
-
31
- from .turbo_utils import argmax_random_tie
32
-
33
- if len(y_obs_list) == 0:
34
- return None
35
- if self._gp_model is None:
36
- return super().get_x_center(x_obs_list, y_obs_list, rng)
37
- if self._fitted_n_obs != len(x_obs_list):
38
- raise RuntimeError(
39
- f"GP fitted on {self._fitted_n_obs} obs but get_x_center called with {len(x_obs_list)}"
40
- )
41
-
42
- x_array = np.asarray(x_obs_list, dtype=float)
43
- x_torch = torch.as_tensor(x_array, dtype=torch.float64)
44
- with torch.no_grad():
45
- posterior = self._gp_model.posterior(x_torch)
46
- mu = posterior.mean.cpu().numpy().ravel()
47
-
48
- best_idx = argmax_random_tie(mu, rng=rng)
49
- return x_array[best_idx]
50
-
51
- def needs_tr_list(self) -> bool:
52
- return True
53
-
54
- def try_early_ask(
55
- self,
56
- num_arms: int,
57
- x_obs_list: list,
58
- draw_initial_fn: Callable[[int], np.ndarray],
59
- get_init_lhd_points_fn: Callable[[int], np.ndarray | None],
60
- ) -> np.ndarray | None:
61
- if len(x_obs_list) == 0:
62
- return get_init_lhd_points_fn(num_arms)
63
- return None
64
-
65
- def handle_restart(
66
- self,
67
- x_obs_list: list,
68
- y_obs_list: list,
69
- yvar_obs_list: list,
70
- init_idx: int,
71
- num_init: int,
72
- ) -> tuple[bool, int]:
73
- x_obs_list.clear()
74
- y_obs_list.clear()
75
- yvar_obs_list.clear()
76
- return True, 0
77
-
78
- def prepare_ask(
79
- self,
80
- x_obs_list: list,
81
- y_obs_list: list,
82
- yvar_obs_list: list,
83
- num_dim: int,
84
- gp_num_steps: int,
85
- rng: Any | None = None,
86
- ) -> tuple[Any, float | None, float | None, np.ndarray | None]:
87
- import numpy as np
88
-
89
- from .turbo_utils import fit_gp
90
-
91
- if len(x_obs_list) == 0:
92
- return None, None, None, None
93
- self._gp_model, _likelihood, gp_y_mean_fitted, gp_y_std_fitted = fit_gp(
94
- x_obs_list,
95
- y_obs_list,
96
- num_dim,
97
- yvar_obs_list=yvar_obs_list if yvar_obs_list else None,
98
- num_steps=gp_num_steps,
99
- )
100
- self._fitted_n_obs = len(x_obs_list)
101
- if gp_y_mean_fitted is not None:
102
- self._gp_y_mean = gp_y_mean_fitted
103
- if gp_y_std_fitted is not None:
104
- self._gp_y_std = gp_y_std_fitted
105
- weights = None
106
- if self._gp_model is not None:
107
- weights = (
108
- self._gp_model.covar_module.base_kernel.lengthscale.cpu()
109
- .detach()
110
- .numpy()
111
- .ravel()
112
- )
113
- # First line helps stabilize second line.
114
- weights = weights / weights.mean()
115
- weights = weights / np.prod(np.power(weights, 1.0 / len(weights)))
116
- return self._gp_model, gp_y_mean_fitted, gp_y_std_fitted, weights
117
-
118
- def select_candidates(
119
- self,
120
- x_cand: np.ndarray,
121
- num_arms: int,
122
- num_dim: int,
123
- rng: Generator,
124
- fallback_fn: Callable[[np.ndarray, int], np.ndarray],
125
- from_unit_fn: Callable[[np.ndarray], np.ndarray],
126
- ) -> np.ndarray:
127
- if self._gp_model is None:
128
- return fallback_fn(x_cand, num_arms)
129
-
130
- idx = gp_thompson_sample(
131
- self._gp_model,
132
- x_cand,
133
- num_arms,
134
- rng,
135
- self._gp_y_mean,
136
- self._gp_y_std,
137
- )
138
- return from_unit_fn(x_cand[idx])
139
-
140
- def estimate_y(self, x_unit: np.ndarray, y_observed: np.ndarray) -> np.ndarray:
141
- import torch
142
-
143
- if self._gp_model is None:
144
- return y_observed
145
- x_torch = torch.as_tensor(x_unit, dtype=torch.float64)
146
- with torch.no_grad():
147
- posterior = self._gp_model.posterior(x_torch)
148
- mu = posterior.mean.cpu().numpy().ravel()
149
- return self._gp_y_mean + self._gp_y_std * mu
150
-
151
- def get_mu_sigma(self, x_unit: np.ndarray) -> tuple[np.ndarray, np.ndarray] | None:
152
- import torch
153
-
154
- if self._gp_model is None:
155
- return None
156
- x_torch = torch.as_tensor(x_unit, dtype=torch.float64)
157
- with torch.no_grad():
158
- posterior = self._gp_model.posterior(x_torch)
159
- mu_std = posterior.mean.cpu().numpy().ravel()
160
- sigma_std = posterior.variance.cpu().numpy().ravel() ** 0.5
161
- mu = self._gp_y_mean + self._gp_y_std * mu_std
162
- sigma = self._gp_y_std * sigma_std
163
- return mu, sigma