spotoptim 2.1.1__tar.gz → 3.0.0__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.
- {spotoptim-2.1.1 → spotoptim-3.0.0}/PKG-INFO +6 -7
- {spotoptim-2.1.1 → spotoptim-3.0.0}/pyproject.toml +6 -8
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/SpotOptim.py +61 -8
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/optimizer/acquisition.py +33 -5
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/surrogate/kernels.py +3 -18
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/surrogate/kriging.py +0 -7
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/utils/transform.py +2 -1
- {spotoptim-2.1.1 → spotoptim-3.0.0}/README.md +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/__init__.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/core/__init__.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/core/data.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/core/experiment.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/core/protocol.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/core/storage.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/data/__init__.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/data/base.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/data/diabetes.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/datasets/__init__.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/datasets/py.typed +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/datasets/test01.csv +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/datasets/test02.csv +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/datasets/test11.csv +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/eda/__init__.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/eda/plots.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/factor_analyzer/__init__.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/factor_analyzer/confirmatory_factor_analyzer.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/factor_analyzer/factor_analyzer.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/factor_analyzer/factor_analyzer_rotator.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/factor_analyzer/factor_analyzer_utils.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/function/__init__.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/function/cd_data.csv +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/function/forr08a.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/function/mo.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/function/remote.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/function/so.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/function/torch_objective.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/hyperparameters/__init__.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/hyperparameters/parameters.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/hyperparameters/repr_helpers.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/inspection/__init__.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/inspection/importance.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/inspection/predictions.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/mo/__init__.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/mo/mo_mm.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/mo/pareto.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/nn/__init__.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/nn/linear_regressor.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/nn/mlp.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/optimizer/__init__.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/optimizer/schedule_free.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/optimizer/wrapper.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/plot/__init__.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/plot/contour.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/plot/mo.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/plot/visualization.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/py.typed +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/reporting/__init__.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/reporting/analysis.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/reporting/results.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/sampling/__init__.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/sampling/design.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/sampling/effects.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/sampling/lhs.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/sampling/mm.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/surrogate/__init__.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/surrogate/mlp_surrogate.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/surrogate/nystroem.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/surrogate/pipeline.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/surrogate/simple_kriging.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/tricands/__init__.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/tricands/tricands.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/utils/__init__.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/utils/boundaries.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/utils/convert.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/utils/dimreduction.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/utils/eval.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/utils/file.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/utils/mapping.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/utils/ocba.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/utils/pca.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/utils/scaler.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/utils/serialization.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/utils/stats.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/utils/tensorboard.py +0 -0
- {spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/utils/variables.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: spotoptim
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0
|
|
4
4
|
Summary: Sequential Parameter Optimization Toolbox
|
|
5
5
|
Author: bartzbeielstein
|
|
6
6
|
Author-email: bartzbeielstein <32470350+bartzbeielstein@users.noreply.github.com>
|
|
@@ -8,11 +8,11 @@ License: AGPL-3.0-or-later
|
|
|
8
8
|
Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
|
|
9
9
|
Classifier: Programming Language :: Python :: 3.13
|
|
10
10
|
Classifier: Programming Language :: Python :: 3.14
|
|
11
|
-
Requires-Dist: numpy>=
|
|
12
|
-
Requires-Dist: scipy>=1.
|
|
13
|
-
Requires-Dist: scikit-learn>=1.
|
|
14
|
-
Requires-Dist: pandas>=
|
|
15
|
-
Requires-Dist: tabulate>=0.
|
|
11
|
+
Requires-Dist: numpy>=2.4
|
|
12
|
+
Requires-Dist: scipy>=1.18
|
|
13
|
+
Requires-Dist: scikit-learn>=1.8
|
|
14
|
+
Requires-Dist: pandas>=3.0
|
|
15
|
+
Requires-Dist: tabulate>=0.10
|
|
16
16
|
Requires-Dist: dill>=0.4.1
|
|
17
17
|
Requires-Dist: spotoptim[torch,viz,stats,remote] ; extra == 'all'
|
|
18
18
|
Requires-Dist: pytest>=7.4.0 ; extra == 'dev'
|
|
@@ -22,7 +22,6 @@ Requires-Dist: pytest-timeout>=2.3.0 ; extra == 'dev'
|
|
|
22
22
|
Requires-Dist: black>=24.1.0 ; extra == 'dev'
|
|
23
23
|
Requires-Dist: isort>=5.13.0 ; extra == 'dev'
|
|
24
24
|
Requires-Dist: ruff>=0.3.0 ; extra == 'dev'
|
|
25
|
-
Requires-Dist: safety>=3.0.0 ; extra == 'dev'
|
|
26
25
|
Requires-Dist: bandit>=1.8.0 ; extra == 'dev'
|
|
27
26
|
Requires-Dist: pre-commit>=3.7.0 ; extra == 'dev'
|
|
28
27
|
Requires-Dist: ty>=0.0.29 ; extra == 'dev'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "spotoptim"
|
|
3
|
-
version = "
|
|
3
|
+
version = "3.0.0"
|
|
4
4
|
description = "Sequential Parameter Optimization Toolbox"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "AGPL-3.0-or-later" }
|
|
@@ -14,11 +14,11 @@ authors = [
|
|
|
14
14
|
]
|
|
15
15
|
requires-python = ">=3.13"
|
|
16
16
|
dependencies = [
|
|
17
|
-
"numpy>=
|
|
18
|
-
"scipy>=1.
|
|
19
|
-
"scikit-learn>=1.
|
|
20
|
-
"pandas>=
|
|
21
|
-
"tabulate>=0.
|
|
17
|
+
"numpy>=2.4",
|
|
18
|
+
"scipy>=1.18",
|
|
19
|
+
"scikit-learn>=1.8",
|
|
20
|
+
"pandas>=3.0",
|
|
21
|
+
"tabulate>=0.10",
|
|
22
22
|
"dill>=0.4.1",
|
|
23
23
|
]
|
|
24
24
|
|
|
@@ -35,7 +35,6 @@ dev = [
|
|
|
35
35
|
"black>=24.1.0",
|
|
36
36
|
"isort>=5.13.0",
|
|
37
37
|
"ruff>=0.3.0",
|
|
38
|
-
"safety>=3.0.0",
|
|
39
38
|
"bandit>=1.8.0",
|
|
40
39
|
"pre-commit>=3.7.0",
|
|
41
40
|
"ty>=0.0.29",
|
|
@@ -67,7 +66,6 @@ dev = [
|
|
|
67
66
|
"black>=24.1.0",
|
|
68
67
|
"isort>=5.13.0",
|
|
69
68
|
"ruff>=0.3.0",
|
|
70
|
-
"safety>=3.0.0",
|
|
71
69
|
"bandit>=1.8.0",
|
|
72
70
|
"pre-commit>=3.7.0",
|
|
73
71
|
"ty>=0.0.29",
|
|
@@ -278,7 +278,13 @@ class SpotOptim(BaseEstimator):
|
|
|
278
278
|
For example, max_iter=30 with n_initial=10 will perform 10 initial evaluations plus
|
|
279
279
|
20 sequential optimization iterations. Defaults to 20.
|
|
280
280
|
n_initial (int, optional):
|
|
281
|
-
Number of initial design points. Defaults to 10.
|
|
281
|
+
Number of initial design points. Defaults to 10. A ``UserWarning`` is
|
|
282
|
+
raised when ``n_initial < 2 * n_dim``: a cold-start design that small
|
|
283
|
+
tends to under-sample the search space and gives the surrogate too
|
|
284
|
+
little signal to model dimension interactions. The warning is
|
|
285
|
+
guidance only (existing scripts with a deliberately small
|
|
286
|
+
``n_initial`` keep working unchanged); consider
|
|
287
|
+
``n_initial=max(10, 2 * n_dim)`` for cold starts.
|
|
282
288
|
surrogate (object, optional):
|
|
283
289
|
Surrogate model with scikit-learn interface (fit/predict methods).
|
|
284
290
|
If None, uses a Gaussian Process Regressor with Matern kernel. Default configuration::
|
|
@@ -874,6 +880,26 @@ class SpotOptim(BaseEstimator):
|
|
|
874
880
|
# Derived attribute dimension n_dim
|
|
875
881
|
self.n_dim = len(self.bounds)
|
|
876
882
|
|
|
883
|
+
# Guidance for cold-start designs (ADR 2026-07-05, decision 4): a
|
|
884
|
+
# design with n_initial < 2*n_dim tends to under-sample the search
|
|
885
|
+
# space, giving the surrogate too little signal to model dimension
|
|
886
|
+
# interactions. Warning-only — existing small-budget scripts keep
|
|
887
|
+
# working unchanged. Nested catch_warnings + "always" mirrors
|
|
888
|
+
# _validate_factor_surrogate_compat: makes the warning visible even
|
|
889
|
+
# under the default warnings_filter="ignore".
|
|
890
|
+
if self.n_initial < 2 * self.n_dim:
|
|
891
|
+
with warnings.catch_warnings():
|
|
892
|
+
warnings.simplefilter("always")
|
|
893
|
+
warnings.warn(
|
|
894
|
+
f"n_initial ({self.n_initial}) is below 2 * n_dim "
|
|
895
|
+
f"({2 * self.n_dim}) for a {self.n_dim}-dimensional problem. "
|
|
896
|
+
f"Cold-start designs this small may under-sample the search "
|
|
897
|
+
f"space; consider n_initial=max(10, 2 * n_dim) = "
|
|
898
|
+
f"{max(10, 2 * self.n_dim)}.",
|
|
899
|
+
UserWarning,
|
|
900
|
+
stacklevel=2,
|
|
901
|
+
)
|
|
902
|
+
|
|
877
903
|
# Default variable types
|
|
878
904
|
if self.var_type is None:
|
|
879
905
|
self.var_type = self.detect_var_type()
|
|
@@ -2503,6 +2529,8 @@ class SpotOptim(BaseEstimator):
|
|
|
2503
2529
|
* message: termination message indicating reason for stopping, including statistics (function value, iterations, evaluations)
|
|
2504
2530
|
* X: all evaluated points in Natural Space
|
|
2505
2531
|
* y: all function values
|
|
2532
|
+
* x_encoded: best point in full-dimension natural-NUMERIC encoding (factor dimensions as integer level indices) — the representation restart injection and ``validate_x0`` consume
|
|
2533
|
+
* X_encoded: all evaluated points in the same numeric encoding (numeric dtype even when factor dimensions map to string labels in ``X``)
|
|
2506
2534
|
|
|
2507
2535
|
Examples:
|
|
2508
2536
|
```{python}
|
|
@@ -2615,9 +2643,16 @@ class SpotOptim(BaseEstimator):
|
|
|
2615
2643
|
|
|
2616
2644
|
if self.restart_inject_best:
|
|
2617
2645
|
# Inject the current global best into the next run's initial design.
|
|
2618
|
-
#
|
|
2619
|
-
#
|
|
2620
|
-
|
|
2646
|
+
# Use the pre-string-map numeric encoding (x_encoded) when available:
|
|
2647
|
+
# best_res.x has factor dims mapped to string labels, which
|
|
2648
|
+
# validate_x0's `low <= val <= high` bounds check cannot compare
|
|
2649
|
+
# (UFuncTypeError). x_encoded carries the same full-dim natural-scale
|
|
2650
|
+
# point with factor dims still as integer codes.
|
|
2651
|
+
# validate_x0 converts to internal scale so the injected point can be
|
|
2652
|
+
# mixed with LHS samples.
|
|
2653
|
+
self.x0 = self.validate_x0(
|
|
2654
|
+
getattr(best_res, "x_encoded", best_res.x)
|
|
2655
|
+
)
|
|
2621
2656
|
# Keep current_X0 unset so the initial design is rebuilt around the injected x0.
|
|
2622
2657
|
current_X0 = None
|
|
2623
2658
|
|
|
@@ -2641,8 +2676,13 @@ class SpotOptim(BaseEstimator):
|
|
|
2641
2676
|
# Find best result based on 'fun'
|
|
2642
2677
|
best_result = min(self.restarts_results_, key=lambda r: r.fun)
|
|
2643
2678
|
|
|
2644
|
-
# Merge results from all restart runs
|
|
2645
|
-
|
|
2679
|
+
# Merge results from all restart runs. Use the numeric encoding
|
|
2680
|
+
# (X_encoded) rather than the string-mapped X: on a factor problem the
|
|
2681
|
+
# latter has object dtype, which would leave self.X_ non-numeric after
|
|
2682
|
+
# a restart and break the post-restart surrogate fit.
|
|
2683
|
+
X_all_list = [
|
|
2684
|
+
getattr(res, "X_encoded", res.X) for res in self.restarts_results_
|
|
2685
|
+
]
|
|
2646
2686
|
y_all_list = [res.y for res in self.restarts_results_]
|
|
2647
2687
|
|
|
2648
2688
|
# Concatenate all evaluations
|
|
@@ -2653,8 +2693,9 @@ class SpotOptim(BaseEstimator):
|
|
|
2653
2693
|
# Aggregated iterations (sum of all runs)
|
|
2654
2694
|
self.n_iter_ = sum(getattr(res, "nit", 0) for res in self.restarts_results_)
|
|
2655
2695
|
|
|
2656
|
-
# Update best solution found
|
|
2657
|
-
|
|
2696
|
+
# Update best solution found. Same numeric-encoding rationale as X_
|
|
2697
|
+
# above, for cross-path (x0 injection vs. best_x_) consistency.
|
|
2698
|
+
self.best_x_ = getattr(best_result, "x_encoded", best_result.x)
|
|
2658
2699
|
self.best_y_ = best_result.fun
|
|
2659
2700
|
|
|
2660
2701
|
# If the patience-based early-stopping rule fired, rewrite the result
|
|
@@ -3563,6 +3604,14 @@ class SpotOptim(BaseEstimator):
|
|
|
3563
3604
|
message=status_message,
|
|
3564
3605
|
X=X_result,
|
|
3565
3606
|
y=self.y_,
|
|
3607
|
+
# Pre-string-map numeric form of x/X (full-dim, natural
|
|
3608
|
+
# scale, with factor dims as integer codes rather than
|
|
3609
|
+
# string labels). optimize()'s restart-inject path and the
|
|
3610
|
+
# cross-restart X_ merge use these instead of x/X, so a
|
|
3611
|
+
# factor problem's restart never feeds a string into
|
|
3612
|
+
# validate_x0()/the surrogate (UFuncTypeError).
|
|
3613
|
+
x_encoded=best_x_full,
|
|
3614
|
+
X_encoded=X_full,
|
|
3566
3615
|
)
|
|
3567
3616
|
return "RESTART", res
|
|
3568
3617
|
|
|
@@ -3621,6 +3670,10 @@ class SpotOptim(BaseEstimator):
|
|
|
3621
3670
|
message=message,
|
|
3622
3671
|
X=X_result,
|
|
3623
3672
|
y=self.y_,
|
|
3673
|
+
# See the RESTART branch above: pre-string-map numeric x/X, used
|
|
3674
|
+
# by optimize()'s restart-inject path and cross-restart X_ merge.
|
|
3675
|
+
x_encoded=best_x_full,
|
|
3676
|
+
X_encoded=X_full,
|
|
3624
3677
|
)
|
|
3625
3678
|
|
|
3626
3679
|
def determine_termination(self, timeout_start: float) -> str:
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
+
import warnings
|
|
10
|
+
|
|
9
11
|
from typing import TYPE_CHECKING, List, Optional, Tuple
|
|
10
12
|
|
|
11
13
|
import numpy as np
|
|
@@ -43,8 +45,17 @@ def optimize_acquisition_tricands(optimizer: SpotOptimProtocol) -> np.ndarray:
|
|
|
43
45
|
# Generate candidates
|
|
44
46
|
nmax = max(100 * optimizer.n_dim, optimizer.acquisition_fun_return_size * 50)
|
|
45
47
|
|
|
46
|
-
#
|
|
47
|
-
|
|
48
|
+
# optimizer.lower/upper are TRANSFORMED-scale bounds, so X_ (natural scale)
|
|
49
|
+
# must be transformed first before normalizing against them — otherwise any
|
|
50
|
+
# log10/sqrt/... dim lands far outside [0, 1] and tricands() raises "X
|
|
51
|
+
# outside of lower/upper bounds" (mirrors try_optimizer_candidates, which
|
|
52
|
+
# already calls optimizer.transform_X before comparing against bounds).
|
|
53
|
+
X_internal = optimizer.transform_X(optimizer.X_)
|
|
54
|
+
span = optimizer.upper - optimizer.lower
|
|
55
|
+
|
|
56
|
+
# Normalize to [0, 1] relative to the transformed bounds, clipping away any
|
|
57
|
+
# residual floating-point overshoot at the box edges.
|
|
58
|
+
X_norm = np.clip((X_internal - optimizer.lower) / span, 0.0, 1.0)
|
|
48
59
|
|
|
49
60
|
# Generate candidates in [0, 1] space
|
|
50
61
|
X_cands_norm = tricands(
|
|
@@ -55,8 +66,10 @@ def optimize_acquisition_tricands(optimizer: SpotOptimProtocol) -> np.ndarray:
|
|
|
55
66
|
fringe=optimizer.tricands_fringe,
|
|
56
67
|
)
|
|
57
68
|
|
|
58
|
-
# Denormalize candidates back to
|
|
59
|
-
X_cands =
|
|
69
|
+
# Denormalize candidates back to transformed space, clipping into bounds.
|
|
70
|
+
X_cands = np.clip(
|
|
71
|
+
X_cands_norm * span + optimizer.lower, optimizer.lower, optimizer.upper
|
|
72
|
+
)
|
|
60
73
|
|
|
61
74
|
# Evaluate acquisition function on all candidates
|
|
62
75
|
acq_values = optimizer._acquisition_function(X_cands.T)
|
|
@@ -374,7 +387,22 @@ def try_optimizer_candidates(
|
|
|
374
387
|
if current_batch is None:
|
|
375
388
|
current_batch = []
|
|
376
389
|
|
|
377
|
-
|
|
390
|
+
try:
|
|
391
|
+
x_next_candidates = optimizer.optimize_acquisition_func()
|
|
392
|
+
except Exception as err:
|
|
393
|
+
# Any acquisition-optimizer failure (e.g. an out-of-bounds tricands
|
|
394
|
+
# candidate on a mixed-scale problem, or a restart-injected factor
|
|
395
|
+
# string reaching a numeric optimizer) degrades to an empty candidate
|
|
396
|
+
# set here, so suggest_next_infill_point() falls through to the
|
|
397
|
+
# existing acquisition_failure_strategy fallback instead of aborting
|
|
398
|
+
# optimize() entirely.
|
|
399
|
+
warnings.warn(
|
|
400
|
+
f"Acquisition optimizer failed ({err}); falling back to the "
|
|
401
|
+
f"{optimizer.acquisition_failure_strategy!r} infill strategy.",
|
|
402
|
+
RuntimeWarning,
|
|
403
|
+
stacklevel=2,
|
|
404
|
+
)
|
|
405
|
+
return []
|
|
378
406
|
|
|
379
407
|
# Ensure iterable of 1D arrays
|
|
380
408
|
if x_next_candidates.ndim == 1:
|
|
@@ -75,7 +75,6 @@ class SpotOptimKernel(Kernel):
|
|
|
75
75
|
Note: In standard Kriging usage, this corresponds to `10^theta_log`.
|
|
76
76
|
This kernel expects the LINEAR scale theta values (weights), not log.
|
|
77
77
|
var_type (list of str): List of variable types, e.g. ['float', 'int', 'factor'].
|
|
78
|
-
p_val (float, optional): Power parameter for ordered distance. Defaults to 2.0.
|
|
79
78
|
metric_factorial (str, optional): Metric for factor distance (passed to cdist/pdist).
|
|
80
79
|
Defaults to 'hamming'. Hamming is a true nominal (order-agnostic) metric;
|
|
81
80
|
canberra distance on integer level indices is order-dependent and singles out
|
|
@@ -86,12 +85,10 @@ class SpotOptimKernel(Kernel):
|
|
|
86
85
|
self,
|
|
87
86
|
theta,
|
|
88
87
|
var_type,
|
|
89
|
-
p_val=2.0,
|
|
90
88
|
metric_factorial="hamming",
|
|
91
89
|
):
|
|
92
90
|
self.theta = np.asanyarray(theta)
|
|
93
91
|
self.var_type = var_type
|
|
94
|
-
self.p_val = p_val
|
|
95
92
|
self.metric_factorial = metric_factorial
|
|
96
93
|
|
|
97
94
|
# Precompute masks
|
|
@@ -166,21 +163,9 @@ class SpotOptimKernel(Kernel):
|
|
|
166
163
|
)
|
|
167
164
|
D += D_factor
|
|
168
165
|
|
|
169
|
-
# Final exponential (Gaussian correlation)
|
|
170
|
-
#
|
|
171
|
-
|
|
172
|
-
# If p != 2, the 'sqeuclidean' above was mathematically sum w * (diff^2).
|
|
173
|
-
# If we strictly want sum w * |diff|^p, we can't use 'sqeuclidean' directly if p != 2.
|
|
174
|
-
# But standard implementation often assumes p=2 for efficiency.
|
|
175
|
-
# Kriging code shows:
|
|
176
|
-
# pdist(..., metric="sqeuclidean", ...)
|
|
177
|
-
# Psi = np.exp(-Psi)
|
|
178
|
-
# This implies p=2 is hardcoded effectively in 'sqeuclidean' metric usage in Kriging code provided earlier.
|
|
179
|
-
# The parameter p_val seems unused in the `build_correlation_matrix` snippet I read earlier
|
|
180
|
-
# (which used `sqeuclidean`).
|
|
181
|
-
# I will stick to what the code did: sqeuclidean -> exp(-D).
|
|
182
|
-
pass
|
|
183
|
-
|
|
166
|
+
# Final exponential (Gaussian correlation). The Gaussian correlation
|
|
167
|
+
# power is fixed at 2: D_ordered is computed via the 'sqeuclidean'
|
|
168
|
+
# metric above (sum w * diff^2), so Psi = exp(-D) is exact.
|
|
184
169
|
return np.exp(-D)
|
|
185
170
|
|
|
186
171
|
def diag(self, X):
|
|
@@ -71,8 +71,6 @@ class Kriging(BaseEstimator, RegressorMixin):
|
|
|
71
71
|
min_theta (float, optional): Minimum log10(theta) bound. Defaults to -3.0.
|
|
72
72
|
max_theta (float, optional): Maximum log10(theta) bound. Defaults to 2.0.
|
|
73
73
|
theta_init_zero (bool, optional): Initialize theta to zero. Defaults to False.
|
|
74
|
-
p_val (float, optional): Power parameter for correlation (fixed at 2.0 for Gaussian).
|
|
75
|
-
Defaults to 2.0.
|
|
76
74
|
n_p (int, optional): Number of p parameters (currently not optimized). Defaults to 1.
|
|
77
75
|
optim_p (bool, optional): Optimize p parameters (currently not supported). Defaults to False.
|
|
78
76
|
min_Lambda (float, optional): Minimum log10(Lambda) bound. Defaults to -9.0.
|
|
@@ -160,7 +158,6 @@ class Kriging(BaseEstimator, RegressorMixin):
|
|
|
160
158
|
min_theta: float = -3.0,
|
|
161
159
|
max_theta: float = 2.0,
|
|
162
160
|
theta_init_zero: bool = False,
|
|
163
|
-
p_val: float = 2.0,
|
|
164
161
|
n_p: int = 1,
|
|
165
162
|
optim_p: bool = False,
|
|
166
163
|
min_Lambda: float = -9.0,
|
|
@@ -188,7 +185,6 @@ class Kriging(BaseEstimator, RegressorMixin):
|
|
|
188
185
|
self.max_Lambda = max_Lambda
|
|
189
186
|
self.n_theta = n_theta
|
|
190
187
|
self.isotropic = isotropic
|
|
191
|
-
self.p_val = p_val
|
|
192
188
|
self.n_p = n_p
|
|
193
189
|
self.optim_p = optim_p
|
|
194
190
|
self.theta_init_zero = theta_init_zero
|
|
@@ -393,7 +389,6 @@ class Kriging(BaseEstimator, RegressorMixin):
|
|
|
393
389
|
kernel = SpotOptimKernel(
|
|
394
390
|
theta=theta10,
|
|
395
391
|
var_type=self.var_type,
|
|
396
|
-
p_val=self.p_val,
|
|
397
392
|
metric_factorial=self.metric_factorial,
|
|
398
393
|
)
|
|
399
394
|
|
|
@@ -506,7 +501,6 @@ class Kriging(BaseEstimator, RegressorMixin):
|
|
|
506
501
|
kernel = SpotOptimKernel(
|
|
507
502
|
theta=theta10,
|
|
508
503
|
var_type=self.var_type,
|
|
509
|
-
p_val=self.p_val,
|
|
510
504
|
metric_factorial=self.metric_factorial,
|
|
511
505
|
)
|
|
512
506
|
|
|
@@ -614,7 +608,6 @@ class Kriging(BaseEstimator, RegressorMixin):
|
|
|
614
608
|
"min_theta": self.min_theta,
|
|
615
609
|
"max_theta": self.max_theta,
|
|
616
610
|
"theta_init_zero": self.theta_init_zero,
|
|
617
|
-
"p_val": self.p_val,
|
|
618
611
|
"n_p": self.n_p,
|
|
619
612
|
"optim_p": self.optim_p,
|
|
620
613
|
"min_Lambda": self.min_Lambda,
|
|
@@ -114,7 +114,8 @@ def inverse_transform_value(x: float, trans: Optional[str]) -> float:
|
|
|
114
114
|
elif trans == "square":
|
|
115
115
|
return np.sqrt(x)
|
|
116
116
|
elif trans == "cube":
|
|
117
|
-
|
|
117
|
+
# np.cbrt handles negative inputs; np.power(x, 1/3) returns NaN there.
|
|
118
|
+
return np.cbrt(x)
|
|
118
119
|
elif trans == "inv" or trans == "reciprocal":
|
|
119
120
|
return 1.0 / x
|
|
120
121
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/factor_analyzer/confirmatory_factor_analyzer.py
RENAMED
|
File without changes
|
|
File without changes
|
{spotoptim-2.1.1 → spotoptim-3.0.0}/src/spotoptim/factor_analyzer/factor_analyzer_rotator.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|