diff --git a/README.md b/README.md index 98d9034..6aeeba3 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ result = optimizer.optimize() - `tolerance_x` (float, optional): Minimum distance between points - `seed` (int, optional): Random seed for reproducibility - `verbose` (bool, default=False): Print progress information -- `max_surrogate_points` (int, optional): Maximum number of points for surrogate fitting (default: None, use all points) +- `max_surrogate_points` (int, optional): Maximum number of points for surrogate fitting (default: 30; set to None to use all points) - `selection_method` (str, default='distant'): Point selection method ('distant' or 'best') **Methods:** diff --git a/_freeze/docs/reference/SpotOptim.SpotOptim/execute-results/html.json b/_freeze/docs/reference/SpotOptim.SpotOptim/execute-results/html.json index c626fd8..79d777a 100644 --- a/_freeze/docs/reference/SpotOptim.SpotOptim/execute-results/html.json +++ b/_freeze/docs/reference/SpotOptim.SpotOptim/execute-results/html.json @@ -1,8 +1,8 @@ { - "hash": "d6d91e86b2c9bc2fca7d9342c08683a1", + "hash": "5c1420b3656e1014432897d340b1b78f", "result": { "engine": "jupyter", - "markdown": "---\ntitle: SpotOptim.SpotOptim\n---\n\n\n\n```python\nSpotOptim.SpotOptim(\n fun,\n bounds=None,\n max_iter=20,\n n_initial=10,\n surrogate=None,\n acquisition='y',\n var_type=None,\n var_name=None,\n var_trans=None,\n tolerance_x=None,\n max_time=np.inf,\n repeats_initial=1,\n repeats_surrogate=1,\n ocba_delta=0,\n tensorboard_log=False,\n tensorboard_path=None,\n tensorboard_clean=False,\n fun_mo2so=None,\n seed=None,\n verbose=False,\n warnings_filter='ignore',\n n_infill_points=1,\n max_surrogate_points=None,\n selection_method='distant',\n acquisition_failure_strategy='random',\n penalty=False,\n penalty_val=None,\n acquisition_fun_return_size=3,\n acquisition_optimizer='differential_evolution',\n restart_after_n=100,\n restart_inject_best=True,\n max_restarts=None,\n x0=None,\n de_x0_prob=0.1,\n tricands_fringe=False,\n prob_de_tricands=0.8,\n window_size=None,\n min_tol_metric='chebyshev',\n prob_surrogate=None,\n acquisition_optimizer_kwargs=None,\n args=(),\n kwargs=None,\n)\n```\n\nSPOT optimizer compatible with scipy.optimize interface.\n\n## Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|------------------------------|-------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------|\n| fun | [callable](`callable`) | Objective function to minimize. Should accept array of shape (n_samples, n_features). | _required_ |\n| bounds | list of tuple | Bounds for each dimension as [(low, high), ...]. | `None` |\n| max_iter | [int](`int`) | Maximum number of total function evaluations (including initial design). For example, max_iter=30 with n_initial=10 will perform 10 initial evaluations plus 20 sequential optimization iterations. Defaults to 20. | `20` |\n| n_initial | [int](`int`) | Number of initial design points. Defaults to 10. | `10` |\n| surrogate | [object](`object`) | Surrogate model with scikit-learn interface (fit/predict methods). If None, uses a Gaussian Process Regressor with Matern kernel. Default configuration:: * `from sklearn.gaussian_process import GaussianProcessRegressor` * `from sklearn.gaussian_process.kernels import Matern, ConstantKernel` * `kernel = ConstantKernel(1.0, (1e-2, 1e12)) * Matern(length_scale=1.0, length_scale_bounds=(1e-4, 1e2), nu=2.5)` * `surrogate = GaussianProcessRegressor(kernel=kernel, n_restarts_optimizer=100)` Alternative surrogates can be provided, including SpotOptim's Kriging model, Random Forests, or any scikit-learn compatible regressor. See Examples section. Defaults to None (uses default Gaussian Process configuration). | `None` |\n| acquisition | [str](`str`) | Acquisition function ('ei', 'y', 'pi'). Defaults to 'y'. | `'y'` |\n| var_type | list of str | Variable types for each dimension. Supported types: * 'float': Python floats, continuous optimization (no rounding) * 'int': Python int, float values will be rounded to integers * 'factor': Unordered categorical data, internally mapped to int values (e.g., \"red\"->0, \"green\"->1, etc.) Defaults to None (which sets all dimensions to 'float'). | `None` |\n| var_name | list of str | Variable names for each dimension. If None, uses default names ['x0', 'x1', 'x2', ...]. Defaults to None. | `None` |\n| tolerance_x | [float](`float`) | Minimum distance between points. Defaults to np.sqrt(np.spacing(1)) | `None` |\n| var_trans | list of str | Variable transformations for each dimension. Supported: It can be one of `id`, `log10`, `log`, `ln`, `sqrt`, `exp`, `square`, `cube`, `inv`, `reciprocal`, or `None`. Also supports dynamic strings like `log(x)`, `sqrt(x)`, `pow(x, p)`. Defaults to None (no transformations). | `None` |\n| max_time | [float](`float`) | Maximum runtime in minutes. If np.inf (default), no time limit. The optimization terminates when either max_iter evaluations are reached OR max_time minutes have elapsed, whichever comes first. Defaults to np.inf. | `np.inf` |\n| repeats_initial | [int](`int`) | Number of times to evaluate each initial design point. Useful for noisy objective functions. If > 1, noise handling is activated and statistics (mean, variance) are tracked. Defaults to 1. | `1` |\n| repeats_surrogate | [int](`int`) | Number of times to evaluate each surrogate-suggested point. Useful for noisy objective functions. If > 1, noise handling is activated and statistics (mean, variance) are tracked. Defaults to 1. | `1` |\n| ocba_delta | [int](`int`) | Number of additional evaluations to allocate using Optimal Computing Budget Allocation (OCBA) when noise handling is active. OCBA determines which existing design points should be re-evaluated to best distinguish between alternatives. Only used when repeats_surrogate > 1 and ocba_delta > 0. Requires at least 3 design points with variance information. Defaults to 0 (no OCBA). | `0` |\n| tensorboard_log | [bool](`bool`) | Enable TensorBoard logging. If True, optimization metrics and hyperparameters are logged to TensorBoard. View logs by running: `tensorboard --logdir=` in a separate terminal. Defaults to False. | `False` |\n| tensorboard_path | [str](`str`) | Path for TensorBoard log files. If None and tensorboard_log is True, creates a default path: runs/spotoptim_YYYYMMDD_HHMMSS. Defaults to None. | `None` |\n| tensorboard_clean | [bool](`bool`) | If True, removes old TensorBoard logs before starting optimization so every run begins with a fresh dashboard. With tensorboard_path set, the configured directory itself is removed (and re-created empty by the writer); without a path, all subdirectories of the default 'runs' folder are removed. Use with caution as this permanently deletes the affected log directories. Defaults to False. | `False` |\n| fun_mo2so | [callable](`callable`) | Function to convert multi-objective values to single-objective. Takes an array of shape (n_samples, n_objectives) and returns array of shape (n_samples,). If None and objective function returns multi-objective values, uses first objective. Defaults to None. | `None` |\n| seed | [int](`int`) | Random seed for reproducibility. Defaults to None. | `None` |\n| verbose | [bool](`bool`) | Print progress information. Defaults to False. | `False` |\n| warnings_filter | [Literal](`typing.Literal`)\\[\\'default\\', \\'error\\', \\'ignore\\'\\] | Filter for warnings. One of \"error\", \"ignore\", \"always\", \"all\", \"default\", \"module\", or \"once\". Defaults to \"ignore\". | `'ignore'` |\n| n_infill_points | [int](`int`) | Number of infill points to suggest at each iteration. Defaults to 1. If > 1, multiple distinct points are proposed using the optimizer and fallback strategies. | `1` |\n| max_surrogate_points | [int](`int`) | Maximum number of points to use for surrogate model fitting. If None, all points are used. If the number of evaluated points exceeds this limit, a subset is selected using the selection method. Defaults to None. | `None` |\n| selection_method | [str](`str`) | Method for selecting points when max_surrogate_points is exceeded. Options: 'distant' (Select points that are distant from each other via K-means clustering) or 'best' (Select all points from the cluster with the best mean objective value). Defaults to 'distant'. | `'distant'` |\n| acquisition_failure_strategy | [str](`str`) | Strategy for handling acquisition function failures. Options: 'random' (space-filling design via Latin Hypercube Sampling) Defaults to 'random'. | `'random'` |\n| penalty | [bool](`bool`) | Whether to use penalty for handling NaN/inf values in objective function evaluations. Defaults to False. | `False` |\n| penalty_val | [float](`float`) | Penalty value to replace NaN/inf values in objective function evaluations. When the objective function returns NaN or inf, these values are replaced with penalty plus a small random noise (sampled from N(0, 0.1)) to avoid identical penalty values. This allows optimization to continue despite occasional function evaluation failures. Defaults to None. | `None` |\n| acquisition_fun_return_size | [int](`int`) | Number of top candidates to return from acquisition function optimization. Defaults to 3. | `3` |\n| acquisition_optimizer | [str](`str`) or [callable](`callable`) | Optimizer to use for maximizing acquisition function. Can be \"differential_evolution\" (default) or any method name supported by scipy.optimize.minimize (e.g., \"Nelder-Mead\", \"L-BFGS-B\"). Can also be a callable with signature compatible with scipy.optimize.minimize (fun, x0, bounds, ...). A specific version is \"de_tricands\", which combines DE with Tricands. It can be parameterized with \"prob_de_tricands\" (probability of using DE). Defaults to \"differential_evolution\". | `'differential_evolution'` |\n| acquisition_optimizer_kwargs | [dict](`dict`) | Kwargs passed to the acquisition function optimizer and GPR surrogate optimizer. Defaults to {'maxiter': 10000, 'gtol': 1e-9}. | `None` |\n| restart_after_n | [int](`int`) | Number of consecutive iterations with zero success rate before triggering a restart. Defaults to 100. | `100` |\n| restart_inject_best | [bool](`bool`) | Whether to inject the best solution found so far as a starting point for the next restart. Defaults to True. | `True` |\n| max_restarts | [Optional](`typing.Optional`)\\[[int](`int`)\\] | Patience-based early-stopping threshold. When set to a non-negative integer ``N``, the optimizer terminates after ``N`` consecutive restarts that fail to improve the best objective value. The returned :class:`scipy.optimize.OptimizeResult` has ``success=True`` and a message of the form ``\"Optimization early stopped: no improvement for N consecutive restarts\"``. This rule complements ``restart_after_n`` and mirrors the ``no_progress_loss`` pattern in Hyperopt and plateau-based stopping in Ray Tune and SMAC. ``None`` (default) disables the rule so the optimizer runs until ``max_iter`` or ``max_time`` is reached. | `None` |\n| x0 | [array](`array`) - [like](`like`) | Starting point for optimization, shape (n_features,). If provided, this point will be evaluated first and included in the initial design. The point should be within the bounds and will be validated before use. Defaults to None (no starting point, uses only LHS design). | `None` |\n| de_x0_prob | [float](`float`) | Probability of using the best point as starting point for differential evolution. Defaults to 0.1. | `0.1` |\n| tricands_fringe | [bool](`bool`) | Whether to use the fringe of the design space for the initial design. Defaults to False. | `False` |\n| prob_de_tricands | [float](`float`) | Probability of using differential evolution as an optimizer on the surrogate model. 1 - prob_de_tricands is the probability of using tricands. Defaults to 0.8. | `0.8` |\n| window_size | [int](`int`) | Window size for success rate calculation. | `None` |\n| min_tol_metric | [str](`str`) | Distance metric used when checking `tolerance_x` for duplicate detection. Default is \"chebyshev\". Supports all metrics from scipy.spatial.distance.cdist, including: * \"chebyshev\": L-infinity distance (hypercube). Default. Matches previous behavior. * \"euclidean\": L2 distance (hypersphere). * \"minkowski\": Lp distance (default p=2). * \"cityblock\": Manhattan/L1 distance. * \"cosine\": Cosine distance. * \"correlation\": Correlation distance. * \"canberra\", \"braycurtis\", \"sqeuclidean\", etc. | `'chebyshev'` |\n\n## Attributes {.doc-section .doc-section-attributes}\n\n| Name | Type | Description |\n|------------------------------|-------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------|\n| X_ | [ndarray](`ndarray`) | All evaluated points, shape (n_samples, n_features). |\n| y_ | [ndarray](`ndarray`) | Function values at X_, shape (n_samples,). For multi-objective problems, these are the converted single-objective values. |\n| y_mo | [ndarray](`ndarray`) or None | Multi-objective function values, shape (n_samples, n_objectives). None for single-objective problems. |\n| best_x_ | [ndarray](`ndarray`) | Best point found, shape (n_features,). |\n| best_y_ | [float](`float`) | Best function value found. |\n| n_iter_ | [int](`int`) | Number of iterations performed. This is not the same as counter. Provided for compatibility with scipy.optimize routines. |\n| counter | [int](`int`) | Total number of function evaluations. |\n| success_rate | [float](`float`) | Rolling success rate over the last window_size evaluations. A success is counted when a new evaluation improves upon the best value found so far. |\n| warnings_filter | [Literal](`typing.Literal`)\\[\\'default\\', \\'error\\', \\'ignore\\'\\] | Filter for warnings during optimization. |\n| max_surrogate_points | [int](`int`) or None | Maximum number of points for surrogate fitting. |\n| selection_method | [str](`str`) | Point selection method. |\n| acquisition_failure_strategy | [str](`str`) | Strategy for handling acquisition failures ('random'). |\n| mean_X | [ndarray](`ndarray`) or None | Aggregated unique design points (if repeats_surrogate > 1). |\n| mean_y | [ndarray](`ndarray`) or None | Mean y values per design point (if repeats_surrogate > 1). |\n| var_y | [ndarray](`ndarray`) or None | Variance of y values per design point (if repeats_surrogate > 1). |\n| min_mean_X | [ndarray](`ndarray`) or None | X value of best mean y (if repeats_surrogate > 1). |\n| min_mean_y | [float](`float`) or None | Best mean y value (if repeats_surrogate > 1). |\n| min_var_y | [float](`float`) or None | Variance of best mean y (if repeats_surrogate > 1). |\n| de_x0_prob | [float](`float`) | Probability of using the best point as starting point for differential evolution. |\n| tricands_fringe | [bool](`bool`) | Whether to use the fringe of the design space for the initial design. |\n| prob_de_tricands | [float](`float`) | Probability of using differential evolution as an optimizer on the surrogate model. |\n\n## Examples {.doc-section .doc-section-examples}\n\n\n::: {#4ecb6548 .cell execution_count=1}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n\ndef objective(X):\n return np.sum(X**2, axis=1)\n\n# Example 1: Basic usage (deterministic function)\nbounds = [(-5, 5), (-5, 5)]\noptimizer = SpotOptim(fun=objective, bounds=bounds, max_iter=10, n_initial=5, verbose=True)\nresult = optimizer.optimize()\nprint(\"Best x:\", result.x)\nprint(\"Best f(x):\", result.fun)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTensorBoard logging disabled\nInitial best: f(x) = 4.636459\nIter 1 | Best: 4.636459 | Curr: 5.315778 | Rate: 0.00 | Evals: 60.0%\nIter 2 | Best: 4.636313 | Rate: 0.50 | Evals: 70.0%\nIter 3 | Best: 4.281456 | Rate: 0.67 | Evals: 80.0%\nIter 4 | Best: 2.711596 | Rate: 0.75 | Evals: 90.0%\nIter 5 | Best: 0.301565 | Rate: 0.80 | Evals: 100.0%\nBest x: [-0.40475083 -0.37113639]\nBest f(x): 0.3015654589641591\n```\n:::\n:::\n\n\n::: {#93ce63d1 .cell execution_count=2}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n\ndef objective(X):\n return np.sum(X**2, axis=1)\n\n# Example 2: With custom variable names\noptimizer = SpotOptim(\n fun=objective,\n bounds=[(-5, 5), (-5, 5)],\n var_name=[\"param1\", \"param2\"],\n max_iter=10,\n n_initial=5\n)\nresult = optimizer.optimize()\n# Ensure we can use custom names in plots\noptimizer.plot_surrogate(show=False)\n```\n\n::: {.cell-output .cell-output-display}\n![](SpotOptim.SpotOptim_files/figure-html/cell-3-output-1.png){width=1125 height=950}\n:::\n:::\n\n\n::: {#acf5b17c .cell execution_count=3}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n\n# Example 3: Noisy function with repeated evaluations\ndef noisy_objective(X):\n base = np.sum(X**2, axis=1)\n noise = np.random.normal(0, 0.1, size=base.shape)\n return base + noise\n\noptimizer = SpotOptim(\n fun=noisy_objective,\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10,\n n_initial=5,\n repeats_initial=1, # Evaluate each initial point once\n repeats_surrogate=2, # Evaluate each new point twice\n seed=42, # For reproducibility\n verbose=True\n)\nresult = optimizer.optimize()\n\n# Access noise statistics\nprint(\"Unique design points:\", optimizer.mean_X.shape[0])\nprint(\"Best mean value:\", optimizer.min_mean_y)\nprint(\"Variance at best point:\", optimizer.min_var_y)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTensorBoard logging disabled\nInitial best: f(x) = 3.403652, mean best: f(x) = 3.403652\nIter 1 | Best: 3.279049 | Rate: 0.50 | Evals: 70.0% | Mean Best: 3.369716\nIter 2 | Best: 3.279049 | Curr: 3.392849 | Rate: 0.25 | Evals: 90.0% | Mean Curr: 3.454694\nIter 3 | Best: 1.563282 | Rate: 0.50 | Evals: 110.0% | Mean Best: 1.613581\nUnique design points: 8\nBest mean value: 1.6135806237005457\nVariance at best point: 0.002529978015323257\n```\n:::\n:::\n\n\n::: {#7f26784f .cell execution_count=4}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n\ndef noisy_objective(X):\n base = np.sum(X**2, axis=1)\n noise = np.random.normal(0, 0.1, size=base.shape)\n return base + noise\n\n# Example 4: Noisy function with OCBA (Optimal Computing Budget Allocation)\noptimizer_ocba = SpotOptim(\n fun=noisy_objective,\n bounds=[(-5, 5), (-5, 5)],\n max_iter=20,\n n_initial=5,\n repeats_initial=2, # Initial repeats\n repeats_surrogate=1, # Surrogate repeats\n ocba_delta=3, # Allocate 3 additional evaluations per iteration\n seed=42,\n verbose=True\n)\nresult = optimizer_ocba.optimize()\n\n# OCBA intelligently re-evaluates promising points to reduce uncertainty\nprint(\"Total evaluations:\", result.nfev)\nprint(\"Unique design points:\", optimizer_ocba.mean_X.shape[0])\nprint(\"Best mean value:\", optimizer_ocba.min_mean_y)\nprint(\"Variance at best point:\", optimizer_ocba.min_var_y)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTensorBoard logging disabled\nInitial best: f(x) = 3.328092, mean best: f(x) = 3.368681\n\nIn get_ocba():\nmeans: [25.90094202 19.61660056 23.96405211 3.36868097 10.79578138]\nvars: [6.73858271e-13 2.56053422e-03 1.00799409e-03 1.64745915e-03\n 1.91555606e-03]\ndelta: 3\nn_designs: 5\nRatios: [3.82210611e-11 2.79305049e-01 6.84325095e-02 9.58065217e-01\n 1.00000000e+00]\nBest: 3, Second best: 4\n OCBA: Adding 3 re-evaluation(s)\nIter 1 | Best: 3.103418 | Rate: 0.75 | Evals: 70.0% | Mean Best: 3.103418\nIter 2 | Best: 3.103418 | Curr: 3.354605 | Rate: 0.60 | Evals: 75.0% | Mean Curr: 3.354605\nIter 3 | Best: 1.613729 | Rate: 0.67 | Evals: 80.0% | Mean Best: 1.613729\nIter 4 | Best: 1.230181 | Rate: 0.71 | Evals: 85.0% | Mean Best: 1.230181\nIter 5 | Best: 0.449320 | Rate: 0.75 | Evals: 90.0% | Mean Best: 0.449320\nIter 6 | Best: 0.367163 | Rate: 0.78 | Evals: 95.0% | Mean Best: 0.367163\nIter 7 | Best: 0.367163 | Curr: 0.518496 | Rate: 0.70 | Evals: 100.0% | Mean Curr: 0.518496\nTotal evaluations: 20\nUnique design points: 12\nBest mean value: 0.3671633104119547\nVariance at best point: 0.0\n```\n:::\n:::\n\n\n::: {#d4b7c883 .cell execution_count=5}\n``` {.python .cell-code}\nimport numpy as np\nimport shutil\nimport os\nfrom spotoptim import SpotOptim\n\ndef objective(X):\n return np.sum(X**2, axis=1)\n\n# Example 5: With TensorBoard logging\ntb_dir = \"runs/my_optimization\"\noptimizer_tb = SpotOptim(\n fun=objective,\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10,\n n_initial=5,\n tensorboard_log=True, # Enable TensorBoard\n tensorboard_path=tb_dir, # Optional custom path\n verbose=True\n)\nresult = optimizer_tb.optimize()\n\n# View logs in browser: tensorboard --logdir=runs/my_optimization\nprint(\"Logs saved to:\", optimizer_tb.tensorboard_path)\n\n# Cleanup log dir\nif os.path.exists(tb_dir):\n shutil.rmtree(tb_dir)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTensorBoard logging enabled: runs/my_optimization\nInitial best: f(x) = 0.412239\nIter 1 | Best: 0.407719 | Rate: 1.00 | Evals: 60.0%\nIter 2 | Best: 0.180004 | Rate: 1.00 | Evals: 70.0%\nIter 3 | Best: 0.023776 | Rate: 1.00 | Evals: 80.0%\nIter 4 | Best: 0.007910 | Rate: 1.00 | Evals: 90.0%\nIter 5 | Best: 0.001229 | Rate: 1.00 | Evals: 100.0%\nTensorBoard writer closed. View logs with: tensorboard --logdir=runs/my_optimization\nLogs saved to: runs/my_optimization\n```\n:::\n:::\n\n\n::: {#25c90219 .cell execution_count=6}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.surrogate import Kriging\n\ndef objective(X):\n return np.sum(X**2, axis=1)\n\n# Example 6: Using SpotOptim's Kriging surrogate\nkriging_model = Kriging(\n noise=1e-10, # Regularization parameter\n kernel='gauss', # Gaussian/RBF kernel\n min_theta=-3.0, # Min log10(theta) bound\n max_theta=2.0, # Max log10(theta) bound\n seed=42\n)\noptimizer_kriging = SpotOptim(\n fun=objective,\n bounds=[(-5, 5), (-5, 5)],\n surrogate=kriging_model,\n max_iter=10,\n n_initial=5,\n seed=42,\n verbose=True\n)\nresult = optimizer_kriging.optimize()\nprint(\"Best solution found:\", result.x)\nprint(\"Best value:\", result.fun)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTensorBoard logging disabled\nInitial best: f(x) = 3.251349\nIter 1 | Best: 3.251349 | Curr: 4.425619 | Rate: 0.00 | Evals: 60.0%\nIter 2 | Best: 1.617693 | Rate: 0.50 | Evals: 70.0%\nIter 3 | Best: 1.617693 | Curr: 18.716279 | Rate: 0.33 | Evals: 80.0%\nIter 4 | Best: 0.839564 | Rate: 0.50 | Evals: 90.0%\nIter 5 | Best: 0.102879 | Rate: 0.60 | Evals: 100.0%\nBest solution found: [0.00128033 0.32074518]\nBest value: 0.10287911055669191\n```\n:::\n:::\n\n\n::: {#0eeb445f .cell execution_count=7}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom sklearn.gaussian_process import GaussianProcessRegressor\nfrom sklearn.gaussian_process.kernels import RBF, ConstantKernel, WhiteKernel\n\ndef objective(X):\n return np.sum(X**2, axis=1)\n\n# Example 7: Using sklearn Gaussian Process with custom kernel\n# Custom kernel: constant * RBF + white noise\ncustom_kernel = ConstantKernel(1.0, (1e-2, 1e2)) * RBF(\n length_scale=1.0, length_scale_bounds=(1e-1, 10.0)\n) + WhiteKernel(noise_level=1e-5, noise_level_bounds=(1e-10, 1e-1))\n\ngp_custom = GaussianProcessRegressor(\n kernel=custom_kernel,\n n_restarts_optimizer=15,\n normalize_y=True,\n random_state=42\n)\n\noptimizer_custom_gp = SpotOptim(\n fun=objective,\n bounds=[(-5, 5), (-5, 5)],\n surrogate=gp_custom,\n max_iter=10,\n n_initial=5,\n seed=42\n)\nresult = optimizer_custom_gp.optimize()\n```\n:::\n\n\n::: {#d0cabd35 .cell execution_count=8}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom sklearn.ensemble import RandomForestRegressor\n\ndef objective(X):\n return np.sum(X**2, axis=1)\n\n# Example 8: Using Random Forest as surrogate\nrf_model = RandomForestRegressor(\n n_estimators=100,\n max_depth=10,\n random_state=42\n)\n\noptimizer_rf = SpotOptim(\n fun=objective,\n bounds=[(-5, 5), (-5, 5)],\n surrogate=rf_model,\n max_iter=10,\n n_initial=5,\n seed=42\n)\nresult = optimizer_rf.optimize()\n\n# Note: Random Forests don't provide uncertainty estimates,\n# so Expected Improvement (EI) may be less effective.\n# Consider using acquisition='y' for pure exploitation.\n```\n:::\n\n\n::: {#9e879121 .cell execution_count=9}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom sklearn.gaussian_process import GaussianProcessRegressor\nfrom sklearn.gaussian_process.kernels import Matern, RationalQuadratic, ConstantKernel, RBF\n\ndef objective(X):\n return np.sum(X**2, axis=1)\n\n# Example 9: Comparing different kernels for Gaussian Process\n# Matern kernel with nu=1.5 (once differentiable)\nkernel_matern15 = ConstantKernel(1.0) * Matern(length_scale=1.0, nu=1.5)\ngp_matern15 = GaussianProcessRegressor(kernel=kernel_matern15, normalize_y=True)\n\n# Matern kernel with nu=2.5 (twice differentiable, DEFAULT)\nkernel_matern25 = ConstantKernel(1.0) * Matern(length_scale=1.0, nu=2.5)\ngp_matern25 = GaussianProcessRegressor(kernel=kernel_matern25, normalize_y=True)\n\n# RBF kernel (infinitely differentiable, smooth)\nkernel_rbf = ConstantKernel(1.0) * RBF(length_scale=1.0)\ngp_rbf = GaussianProcessRegressor(kernel=kernel_rbf, normalize_y=True)\n\n# Rational Quadratic kernel (mixture of RBF kernels)\nkernel_rq = ConstantKernel(1.0) * RationalQuadratic(length_scale=1.0, alpha=1.0)\ngp_rq = GaussianProcessRegressor(kernel=kernel_rq, normalize_y=True)\n\n# Use any of these as surrogate\noptimizer_rbf = SpotOptim(fun=objective, bounds=[(-5, 5), (-5, 5)],\n surrogate=gp_rbf, max_iter=10, n_initial=5)\nresult = optimizer_rbf.optimize()\n```\n:::\n\n\n## Methods\n\n| Name | Description |\n| --- | --- |\n| [aggregate_mean_var](#spotoptim.SpotOptim.SpotOptim.aggregate_mean_var) | Aggregate X and y values to compute mean and variance per group. |\n| [apply_ocba](#spotoptim.SpotOptim.SpotOptim.apply_ocba) | Apply Optimal Computing Budget Allocation for noisy functions. |\n| [apply_penalty_NA](#spotoptim.SpotOptim.SpotOptim.apply_penalty_NA) | Replace NaN and infinite values with penalty plus random noise. |\n| [check_size_initial_design](#spotoptim.SpotOptim.SpotOptim.check_size_initial_design) | Validate that initial design has sufficient points for surrogate fitting. |\n| [curate_initial_design](#spotoptim.SpotOptim.SpotOptim.curate_initial_design) | Remove duplicates and ensure sufficient unique points in initial design. |\n| [detect_var_type](#spotoptim.SpotOptim.SpotOptim.detect_var_type) | Auto-detect variable types based on factor mappings. |\n| [determine_termination](#spotoptim.SpotOptim.SpotOptim.determine_termination) | Determine termination reason for optimization. |\n| [evaluate_function](#spotoptim.SpotOptim.SpotOptim.evaluate_function) | Evaluate objective function at points X. |\n| [execute_optimization_run](#spotoptim.SpotOptim.SpotOptim.execute_optimization_run) | Entry point for a single sequential optimization run. |\n| [fit_scheduler](#spotoptim.SpotOptim.SpotOptim.fit_scheduler) | Fit surrogate model using appropriate data based on noise handling. |\n| [fit_select_best_cluster](#spotoptim.SpotOptim.SpotOptim.fit_select_best_cluster) | Selects all points from the cluster with the smallest mean y value. |\n| [fit_select_distant_points](#spotoptim.SpotOptim.SpotOptim.fit_select_distant_points) | Selects k points that are distant from each other using K-means clustering. |\n| [fit_selection_dispatcher](#spotoptim.SpotOptim.SpotOptim.fit_selection_dispatcher) | Dispatcher for selection methods. |\n| [fit_surrogate](#spotoptim.SpotOptim.SpotOptim.fit_surrogate) | Fit surrogate model to data. |\n| [gen_design_table](#spotoptim.SpotOptim.SpotOptim.gen_design_table) | Generate a table of the design or results. |\n| [generate_initial_design](#spotoptim.SpotOptim.SpotOptim.generate_initial_design) | Generate initial space-filling design using Latin Hypercube Sampling. |\n| [get_best_hyperparameters](#spotoptim.SpotOptim.SpotOptim.get_best_hyperparameters) | Get the best hyperparameter configuration found during optimization. |\n| [get_best_xy_initial_design](#spotoptim.SpotOptim.SpotOptim.get_best_xy_initial_design) | Determine and store the best point from initial design. |\n| [get_design_table](#spotoptim.SpotOptim.SpotOptim.get_design_table) | Get a table string showing the search space design before optimization. |\n| [get_experiment_filename](#spotoptim.SpotOptim.SpotOptim.get_experiment_filename) | Generate experiment filename with '_exp.pkl' suffix. |\n| [get_importance](#spotoptim.SpotOptim.SpotOptim.get_importance) | Calculate variable importance scores. |\n| [get_initial_design](#spotoptim.SpotOptim.SpotOptim.get_initial_design) | Generate or process initial design points. Ensures that design points are in |\n| [get_ocba](#spotoptim.SpotOptim.SpotOptim.get_ocba) | Optimal Computing Budget Allocation (OCBA). |\n| [get_ocba_X](#spotoptim.SpotOptim.SpotOptim.get_ocba_X) | Calculate OCBA allocation and repeat input array X. |\n| [get_pickle_safe_optimizer](#spotoptim.SpotOptim.SpotOptim.get_pickle_safe_optimizer) | Create a pickle-safe copy of the optimizer. |\n| [get_ranks](#spotoptim.SpotOptim.SpotOptim.get_ranks) | Returns ranks of numbers within input array x. |\n| [get_result_filename](#spotoptim.SpotOptim.SpotOptim.get_result_filename) | Generate result filename with '_res.pkl' suffix. |\n| [get_results_table](#spotoptim.SpotOptim.SpotOptim.get_results_table) | Get a comprehensive table string of optimization results. |\n| [get_shape](#spotoptim.SpotOptim.SpotOptim.get_shape) | Get the shape of the objective function output. |\n| [get_stars](#spotoptim.SpotOptim.SpotOptim.get_stars) | Converts a list of values to a list of stars. |\n| [get_success_rate](#spotoptim.SpotOptim.SpotOptim.get_success_rate) | Get the current success rate of the optimization process. |\n| [handle_default_var_trans](#spotoptim.SpotOptim.SpotOptim.handle_default_var_trans) | Handle default variable transformations. Does not perform any transformations, |\n| [init_storage](#spotoptim.SpotOptim.SpotOptim.init_storage) | Initialize storage for optimization. |\n| [init_surrogate](#spotoptim.SpotOptim.SpotOptim.init_surrogate) | Initialize or configure the surrogate model for optimization. Handles three surrogate configurations: |\n| [inverse_transform_X](#spotoptim.SpotOptim.SpotOptim.inverse_transform_X) | Transform parameter array from internal to original scale. |\n| [inverse_transform_value](#spotoptim.SpotOptim.SpotOptim.inverse_transform_value) | Apply inverse transformation to a single float value. |\n| [load_experiment](#spotoptim.SpotOptim.SpotOptim.load_experiment) | Load experiment configuration from a pickle file. |\n| [load_result](#spotoptim.SpotOptim.SpotOptim.load_result) | Load complete optimization results from a pickle file. |\n| [map_to_factor_values](#spotoptim.SpotOptim.SpotOptim.map_to_factor_values) | Map internal integer factor values back to string labels. |\n| [mo2so](#spotoptim.SpotOptim.SpotOptim.mo2so) | Convert multi-objective values to single-objective. |\n| [modify_bounds_based_on_var_type](#spotoptim.SpotOptim.SpotOptim.modify_bounds_based_on_var_type) | Modify bounds based on variable types. |\n| [optimize](#spotoptim.SpotOptim.SpotOptim.optimize) | Run the optimization process. The optimization terminates when either the total function evaluations reach |\n| [optimize_acquisition_func](#spotoptim.SpotOptim.SpotOptim.optimize_acquisition_func) | Optimize the acquisition function to find the next point to evaluate. |\n| [optimize_sequential_run](#spotoptim.SpotOptim.SpotOptim.optimize_sequential_run) | Perform a single sequential optimization run. |\n| [plot_importance](#spotoptim.SpotOptim.SpotOptim.plot_importance) | Plot variable importance. |\n| [plot_important_hyperparameter_contour](#spotoptim.SpotOptim.SpotOptim.plot_important_hyperparameter_contour) | Plot surrogate contours using spotoptim.plot.visualization.plot_important_hyperparameter_contour. |\n| [plot_parameter_scatter](#spotoptim.SpotOptim.SpotOptim.plot_parameter_scatter) | Plot parameter distributions showing relationship between each parameter and objective. |\n| [plot_progress](#spotoptim.SpotOptim.SpotOptim.plot_progress) | Plot optimization progress using spotoptim.plot.visualization.plot_progress. |\n| [plot_surrogate](#spotoptim.SpotOptim.SpotOptim.plot_surrogate) | Plot the surrogate model for two dimensions. |\n| [print_best](#spotoptim.SpotOptim.SpotOptim.print_best) | Print the best solution found during optimization. |\n| [print_results](#spotoptim.SpotOptim.SpotOptim.print_results) | Alias for print(get_results_table()) for compatibility. |\n| [process_factor_bounds](#spotoptim.SpotOptim.SpotOptim.process_factor_bounds) | Process `bounds` to handle factor variables. |\n| [reinitialize_components](#spotoptim.SpotOptim.SpotOptim.reinitialize_components) | Reinitialize components that were excluded during pickling. |\n| [remove_nan](#spotoptim.SpotOptim.SpotOptim.remove_nan) | Remove rows where y contains NaN or inf values. |\n| [repair_natural_X](#spotoptim.SpotOptim.SpotOptim.repair_natural_X) | Enforce integrality and declared bounds in natural (original) space. |\n| [repair_non_numeric](#spotoptim.SpotOptim.SpotOptim.repair_non_numeric) | Round non-numeric values to integers based on variable type. |\n| [rm_initial_design_NA_values](#spotoptim.SpotOptim.SpotOptim.rm_initial_design_NA_values) | Remove NaN/inf values from initial design evaluations. |\n| [save_experiment](#spotoptim.SpotOptim.SpotOptim.save_experiment) | Save experiment configuration to a pickle file. |\n| [save_result](#spotoptim.SpotOptim.SpotOptim.save_result) | Save complete optimization results to a pickle file. |\n| [select_new](#spotoptim.SpotOptim.SpotOptim.select_new) | Select rows from A that are not in X. |\n| [sensitivity_spearman](#spotoptim.SpotOptim.SpotOptim.sensitivity_spearman) | Compute and print Spearman correlation between parameters and objective values. |\n| [set_seed](#spotoptim.SpotOptim.SpotOptim.set_seed) | Set global random seeds for reproducibility. |\n| [setup_dimension_reduction](#spotoptim.SpotOptim.SpotOptim.setup_dimension_reduction) | Set up dimension reduction by identifying fixed dimensions. |\n| [store_mo](#spotoptim.SpotOptim.SpotOptim.store_mo) | Store multi-objective values in self.y_mo. |\n| [suggest_next_infill_point](#spotoptim.SpotOptim.SpotOptim.suggest_next_infill_point) | Suggest next point to evaluate (dispatcher). |\n| [to_all_dim](#spotoptim.SpotOptim.SpotOptim.to_all_dim) | Expand reduced-dimensional points to full-dimensional representation. |\n| [to_red_dim](#spotoptim.SpotOptim.SpotOptim.to_red_dim) | Reduce full-dimensional points to optimization space. |\n| [transform_X](#spotoptim.SpotOptim.SpotOptim.transform_X) | Transform parameter array from original (natural) to internal scale. |\n| [transform_bounds](#spotoptim.SpotOptim.SpotOptim.transform_bounds) | Transform bounds from original to internal scale. |\n| [transform_value](#spotoptim.SpotOptim.SpotOptim.transform_value) | Apply transformation to a single float value. |\n| [update_repeats_infill_points](#spotoptim.SpotOptim.SpotOptim.update_repeats_infill_points) | Repeat infill point for noisy function evaluation. Used in the sequential_loop. |\n| [update_stats](#spotoptim.SpotOptim.SpotOptim.update_stats) | Update optimization statistics. |\n| [update_storage](#spotoptim.SpotOptim.SpotOptim.update_storage) | Update storage (`X_`, `y_`) with new evaluation points. |\n| [update_success_rate](#spotoptim.SpotOptim.SpotOptim.update_success_rate) | Update the rolling success rate of the optimization process. |\n| [validate_x0](#spotoptim.SpotOptim.SpotOptim.validate_x0) | Validate and process starting point x0. Called in `__init__` and `optimize`. |\n\n### aggregate_mean_var { #spotoptim.SpotOptim.SpotOptim.aggregate_mean_var }\n\n```python\nSpotOptim.SpotOptim.aggregate_mean_var(X, y)\n```\n\nAggregate X and y values to compute mean and variance per group.\nFor repeated evaluations at the same design point, this method computes\nthe mean function value and variance (using population variance, ddof=0).\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-----------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Design points, shape (n_samples, n_features). | _required_ |\n| y | [ndarray](`ndarray`) | Function values, shape (n_samples,). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|---------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| tuple | [Tuple](`typing.Tuple`)\\[[np](`numpy`).[ndarray](`numpy.ndarray`), [np](`numpy`).[ndarray](`numpy.ndarray`), [np](`numpy`).[ndarray](`numpy.ndarray`)\\] | A tuple containing: * X_agg (ndarray): Unique design points, shape (n_groups, n_features) * y_mean (ndarray): Mean y values per group, shape (n_groups,) * y_var (ndarray): Variance of y values per group, shape (n_groups,) |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#869ca22e .cell execution_count=10}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n repeats_initial=2)\nX = np.array([[1, 2], [3, 4], [1, 2]])\ny = np.array([1, 2, 3])\nX_agg, y_mean, y_var = opt.aggregate_mean_var(X, y)\nprint(X_agg.shape)\nprint(y_mean)\nprint(y_var)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n(2, 2)\n[2. 2.]\n[1. 0.]\n```\n:::\n:::\n\n\n### apply_ocba { #spotoptim.SpotOptim.SpotOptim.apply_ocba }\n\n```python\nSpotOptim.SpotOptim.apply_ocba()\n```\n\nApply Optimal Computing Budget Allocation for noisy functions.\n\n### apply_penalty_NA { #spotoptim.SpotOptim.SpotOptim.apply_penalty_NA }\n\n```python\nSpotOptim.SpotOptim.apply_penalty_NA(\n y,\n y_history=None,\n penalty_value=None,\n sd=0.1,\n)\n```\n\nReplace NaN and infinite values with penalty plus random noise.\nUsed in the optimize() method after function evaluations.\nThis method follows the approach from spotpython.utils.repair.apply_penalty_NA,\nreplacing NaN/inf values with a penalty value plus random noise to avoid\nidentical penalty values.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|---------------|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|\n| y | [ndarray](`ndarray`) | Array of objective function values to be repaired. | _required_ |\n| y_history | [ndarray](`ndarray`) | Historical objective function values used for computing penalty statistics. If None, uses y itself. Default is None. | `None` |\n| penalty_value | [float](`float`) | Value to replace NaN/inf with. If None, computes penalty as: max(finite_y_history) + 3 * std(finite_y_history). If all values are NaN/inf or only one finite value exists, falls back to self.penalty_val. Default is None. | `None` |\n| sd | [float](`float`) | Standard deviation for normal distributed random noise added to penalty. Default is 0.1. | `0.1` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Array with NaN/inf replaced by penalty_value + random noise (normal distributed with mean 0 and standard deviation sd). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#8cd2b351 .cell execution_count=11}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda X: np.sum(X**2, axis=1), bounds=[(-5, 5)])\ny_hist = np.array([1.0, 2.0, 3.0, 5.0])\ny_new = np.array([4.0, np.nan, np.inf])\ny_clean = opt.apply_penalty_NA(y_new, y_history=y_hist)\nprint(f\"np.all(np.isfinite(y_clean)): {np.all(np.isfinite(y_clean))}\")\nprint(f\"y_clean: {y_clean}\")\n# NaN/inf replaced with worst value from history + 3*std + noise\nprint(f\"y_clean[1] > 5.0: {y_clean[1] > 5.0}\") # Should be larger than max finite value in history\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nnp.all(np.isfinite(y_clean)): True\ny_clean: [4. 9.99213659 9.97045717]\ny_clean[1] > 5.0: True\n```\n:::\n:::\n\n\n### check_size_initial_design { #spotoptim.SpotOptim.SpotOptim.check_size_initial_design }\n\n```python\nSpotOptim.SpotOptim.check_size_initial_design(y0, n_evaluated)\n```\n\nValidate that initial design has sufficient points for surrogate fitting.\n\nChecks if the number of valid initial design points meets the minimum\nrequirement for fitting a surrogate model. The minimum required is the\nsmaller of:\n * (a) typical minimum for surrogate fitting (3 for multi-dimensional, 2 for 1D), or\n * (b) what the user requested (`n_initial`).\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|-------------|----------------------|-------------------------------------------------------------------------------|------------|\n| y0 | [ndarray](`ndarray`) | Function values at initial design points (after filtering), shape (n_valid,). | _required_ |\n| n_evaluated | [int](`int`) | Original number of points evaluated before filtering. | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Raises {.doc-section .doc-section-raises}\n\n| Name | Type | Description |\n|--------|----------------------------|------------------------------------------------------------------|\n| | [ValueError](`ValueError`) | If the number of valid points is less than the minimum required. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#5db0c341 .cell execution_count=12}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\n\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=10\n)\n# Sufficient points - no error\ny0 = np.array([1.0, 2.0, 3.0, 4.0, 5.0])\nopt.check_size_initial_design(y0, n_evaluated=10)\n\n# Insufficient points - raises ValueError\ny0_small = np.array([1.0])\ntry:\n opt.check_size_initial_design(y0_small, n_evaluated=10)\nexcept ValueError as e:\n print(f\"Error: {e}\")\n\n# With verbose output\nopt_verbose = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=10,\n verbose=True\n)\ny0_reduced = np.array([1.0, 2.0, 3.0]) # Less than n_initial but valid\nopt_verbose.check_size_initial_design(y0_reduced, n_evaluated=10)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nError: Insufficient valid initial design points: only 1 finite value(s) out of 10 evaluated. Need at least 3 points to fit surrogate model. Please check your objective function or increase n_initial.\nTensorBoard logging disabled\nNote: Initial design size (3) is smaller than requested (10) due to NaN/inf values\n```\n:::\n:::\n\n\n### curate_initial_design { #spotoptim.SpotOptim.SpotOptim.curate_initial_design }\n\n```python\nSpotOptim.SpotOptim.curate_initial_design(X0)\n```\n\nRemove duplicates and ensure sufficient unique points in initial design.\n\nThis method handles deduplication that can occur after rounding integer/factor\nvariables. If duplicates are found, it generates additional points to reach\nthe target n_initial unique points. Also handles repeating points when\nrepeats_initial > 1.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-------------------------------------------------------------------------|------------|\n| X0 | [ndarray](`ndarray`) | Initial design points in internal scale, shape (n_samples, n_features). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Curated initial design with duplicates removed and repeated if necessary, shape (n_unique * repeats_initial, n_features). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#396570c9 .cell execution_count=13}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\n\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=10,\n var_type=['int', 'int'] # Integer variables may cause duplicates\n)\nX0 = opt.get_initial_design()\nX0_curated = opt.curate_initial_design(X0)\nX0_curated.shape[0] == 10 # Should have n_initial unique points\n```\n\n::: {.cell-output .cell-output-display execution_count=13}\n```\nTrue\n```\n:::\n:::\n\n\n::: {#58cba70c .cell execution_count=14}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\n# With repeats\nopt_repeat = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n repeats_initial=3\n)\nX0 = opt_repeat.get_initial_design()\nX0_curated = opt_repeat.curate_initial_design(X0)\nX0_curated.shape[0] == 15 # 5 unique points * 3 repeats\n```\n\n::: {.cell-output .cell-output-display execution_count=14}\n```\nTrue\n```\n:::\n:::\n\n\n### detect_var_type { #spotoptim.SpotOptim.SpotOptim.detect_var_type }\n\n```python\nSpotOptim.SpotOptim.detect_var_type()\n```\n\nAuto-detect variable types based on factor mappings.\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|----------------|-------------------------------------------------------------------------------------------------------------------------------------------|\n| list | [list](`list`) | List of variable types ('factor' or 'float') for each dimension. Dimensions with factor mappings are assigned 'factor', others 'float'. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#de10719a .cell execution_count=15}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\n\n# Define a simple objective mapping names to values for demonstration\ndef objective(X):\n # X has shape (n_samples, n_dimensions)\n return X[:, 0] + X[:, 1]\n\n# The first dimension has factor levels ('red', 'green', 'blue')\n# The second dimension is continuous bounds (0, 10)\nspot = SpotOptim(fun=objective, bounds=[('red', 'green', 'blue'), (0, 10)])\nprint(spot.detect_var_type())\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n['factor', 'float']\n```\n:::\n:::\n\n\n### determine_termination { #spotoptim.SpotOptim.SpotOptim.determine_termination }\n\n```python\nSpotOptim.SpotOptim.determine_termination(timeout_start)\n```\n\nDetermine termination reason for optimization.\nChecks the termination conditions and returns an appropriate message\nindicating why the optimization stopped. Three possible termination\nconditions are checked in order of priority:\n 1. Maximum number of evaluations reached\n 2. Maximum time limit exceeded\n 3. Successful completion (neither limit reached)\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|---------------|------------------|------------------------------------------------|------------|\n| timeout_start | [float](`float`) | Start time of optimization (from time.time()). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------------|--------------------------------------------|\n| str | [str](`str`) | Message describing the termination reason. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#7147d096 .cell execution_count=16}\n``` {.python .cell-code}\nimport numpy as np\nimport time\nfrom spotoptim import SpotOptim\nopt = SpotOptim(\n fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10,\n max_time=10.0\n)\n# Case 1: Maximum evaluations reached\nopt.y_ = np.zeros(20) # Simulate 20 evaluations\nstart_time = time.time()\nmsg = opt.determine_termination(start_time)\nprint(msg)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nOptimization terminated: maximum evaluations (10) reached\n```\n:::\n:::\n\n\n::: {#c869e676 .cell execution_count=17}\n``` {.python .cell-code}\n# Case 2: Time limit exceeded\nimport numpy as np\nimport time\nfrom spotoptim import SpotOptim\nopt.y_ = np.zeros(10) # Only 10 evaluations\nstart_time = time.time() - 700 # Simulate 11.67 minutes elapsed\nmsg = opt.determine_termination(start_time)\nprint(msg)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nOptimization terminated: maximum evaluations (10) reached\n```\n:::\n:::\n\n\n::: {#c2b6f85a .cell execution_count=18}\n``` {.python .cell-code}\n# Case 3: Successful completion\nimport numpy as np\nimport time\nfrom spotoptim import SpotOptim\nopt.y_ = np.zeros(10) # Under max_iter\nstart_time = time.time() # Just started\nmsg = opt.determine_termination(start_time)\nprint(msg)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nOptimization terminated: maximum evaluations (10) reached\n```\n:::\n:::\n\n\n### evaluate_function { #spotoptim.SpotOptim.SpotOptim.evaluate_function }\n\n```python\nSpotOptim.SpotOptim.evaluate_function(X)\n```\n\nEvaluate objective function at points X.\nUsed in the optimize() method to evaluate the objective function.\n\nInput Space: `X` is expected in Transformed and Mapped Space (Internal scale, Reduced dimensions).\nProcess as follows:\n 1. Expands `X` to Transformed Space (Full dimensions) if dimension reduction is active.\n 2. Inverse transforms `X` to Natural Space (Original scale).\n 3. Evaluates the user function with points in Natural Space.\n\nIf dimension reduction is active, expands `X` to full dimensions before evaluation.\nSupports both single-objective and multi-objective functions. For multi-objective\nfunctions, converts to single-objective using `mo2so` method.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|--------------------------------------------------------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Points to evaluate in Transformed and Mapped Space, shape (n_samples, n_reduced_features). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|--------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Function values, shape (n_samples,). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#5b32bd11 .cell execution_count=19}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n# Single-objective function\nopt_so = SpotOptim(\n fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10,\n n_initial=5\n)\nX = np.array([[1.0, 2.0], [3.0, 4.0]])\ny = opt_so.evaluate_function(X)\nprint(f\"Single-objective output: {y}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nSingle-objective output: [ 5. 25.]\n```\n:::\n:::\n\n\n::: {#974f9fa2 .cell execution_count=20}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n# Multi-objective function (default: use first objective)\nopt_mo = SpotOptim(\n fun=lambda X: np.column_stack([\n np.sum(X**2, axis=1),\n np.sum((X-1)**2, axis=1)\n ]),\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10,\n n_initial=5\n)\ny_mo = opt_mo.evaluate_function(X)\nprint(f\"Multi-objective output (first obj): {y_mo}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nMulti-objective output (first obj): [ 5. 25.]\n```\n:::\n:::\n\n\n### execute_optimization_run { #spotoptim.SpotOptim.SpotOptim.execute_optimization_run }\n\n```python\nSpotOptim.SpotOptim.execute_optimization_run(\n timeout_start,\n X0=None,\n y0_known=None,\n max_iter_override=None,\n)\n```\n\nEntry point for a single sequential optimization run.\nDelegates to optimize_sequential_run with the provided arguments.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|-------------------|---------------------------------------------------------------------------|------------------------------------------------------------------------|------------|\n| timeout_start | [float](`float`) | Start time for timeout. | _required_ |\n| X0 | [Optional](`typing.Optional`)\\[[np](`numpy`).[ndarray](`numpy.ndarray`)\\] | Initial design points in Natural Space, shape (n_initial, n_features). | `None` |\n| y0_known | [Optional](`typing.Optional`)\\[[float](`float`)\\] | Known best value for initial design. | `None` |\n| max_iter_override | [Optional](`typing.Optional`)\\[[int](`int`)\\] | Override for maximum number of iterations. | `None` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------------------------------------------------------------------------------------------|------------------------------------------------------------------------------|\n| | [Tuple](`typing.Tuple`)\\[[str](`str`), [OptimizeResult](`scipy.optimize.OptimizeResult`)\\] | Tuple[str, OptimizeResult]: Tuple containing status and optimization result. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#a9f18325 .cell execution_count=21}\n``` {.python .cell-code}\nimport time\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n max_iter=10,\n seed=0,\n verbose=True\n)\nstatus, result = opt.execute_optimization_run(timeout_start=time.time())\nprint(status)\nprint(result.message.splitlines()[0])\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTensorBoard logging disabled\nInitial best: f(x) = 8.463203\nIter 1 | Best: 8.463203 | Curr: 18.224245 | Rate: 0.00 | Evals: 60.0%\nIter 2 | Best: 8.412459 | Rate: 0.50 | Evals: 70.0%\nIter 3 | Best: 5.623369 | Rate: 0.67 | Evals: 80.0%\nIter 4 | Best: 2.902974 | Rate: 0.75 | Evals: 90.0%\nIter 5 | Best: 0.022050 | Rate: 0.80 | Evals: 100.0%\nFINISHED\nOptimization terminated: maximum evaluations (10) reached\n```\n:::\n:::\n\n\n### fit_scheduler { #spotoptim.SpotOptim.SpotOptim.fit_scheduler }\n\n```python\nSpotOptim.SpotOptim.fit_scheduler()\n```\n\nFit surrogate model using appropriate data based on noise handling.\nThis method selects the appropriate training data for surrogate fitting:\n * For noisy functions (repeats_surrogate > 1): Uses mean_X and mean_y (aggregated values)\n * For deterministic functions: Uses X_ and y_ (all evaluated points)\nThe data is transformed to internal scale before fitting the surrogate.\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n```python\n>>> import numpy as np\n>>> from spotoptim import SpotOptim\n>>> from sklearn.gaussian_process import GaussianProcessRegressor\n>>> # Deterministic function\n>>> def sphere(X):\n... X = np.atleast_2d(X)\n... return np.sum(X**2, axis=1)\n>>> opt = SpotOptim(\n... fun=sphere,\n... bounds=[(-5, 5), (-5, 5)],\n... surrogate=GaussianProcessRegressor(),\n... n_initial=5\n... )\n>>> # Simulate optimization state\n>>> opt.X_ = np.array([[1, 2], [0, 0], [2, 1]])\n>>> opt.y_ = np.array([5.0, 0.0, 5.0])\n>>> opt.fit_scheduler()\n>>> # Surrogate fitted with X_ and y_\n>>>\n>>> # Noisy function\n>>> def sphere(X):\n... X = np.atleast_2d(X)\n... return np.sum(X**2, axis=1)\n>>> opt_noise = SpotOptim(\n... fun=sphere,\n... bounds=[(-5, 5), (-5, 5)],\n... surrogate=GaussianProcessRegressor(),\n... n_initial=5,\n... repeats_initial=3,\n... )\n>>> # Simulate noisy optimization state\n>>> opt_noise.mean_X = np.array([[1, 2], [0, 0]])\n>>> opt_noise.mean_y = np.array([5.0, 0.0])\n>>> opt_noise.fit_scheduler()\n>>> # Surrogate fitted with mean_X and mean_y\n```\n\n### fit_select_best_cluster { #spotoptim.SpotOptim.SpotOptim.fit_select_best_cluster }\n\n```python\nSpotOptim.SpotOptim.fit_select_best_cluster(X, y, k)\n```\n\nSelects all points from the cluster with the smallest mean y value.\nThis method performs K-means clustering and selects all points from the\ncluster whose center corresponds to the best (smallest) mean objective\nfunction value.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-----------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Design points, shape (n_samples, n_features). | _required_ |\n| y | [ndarray](`ndarray`) | Function values at X, shape (n_samples,). | _required_ |\n| k | [int](`int`) | Number of clusters. | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|---------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| tuple | [Tuple](`typing.Tuple`)\\[[np](`numpy`).[ndarray](`numpy.ndarray`), [np](`numpy`).[ndarray](`numpy.ndarray`)\\] | A tuple containing: * selected_X (ndarray): Selected design points from best cluster, shape (m, n_features). * selected_y (ndarray): Function values at selected points, shape (m,). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#c2a13373 .cell execution_count=22}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n max_surrogate_points=5,\n selection_method='best')\nX = np.random.rand(100, 2)\ny = np.random.rand(100)\nX_sel, y_sel = opt.fit_select_best_cluster(X, y, 5)\nprint(f\"X_sel.shape: {X_sel.shape}\")\nprint(f\"y_sel.shape: {y_sel.shape}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nX_sel.shape: (25, 2)\ny_sel.shape: (25,)\n```\n:::\n:::\n\n\n### fit_select_distant_points { #spotoptim.SpotOptim.SpotOptim.fit_select_distant_points }\n\n```python\nSpotOptim.SpotOptim.fit_select_distant_points(X, y, k)\n```\n\nSelects k points that are distant from each other using K-means clustering.\nThis method performs K-means clustering to find k clusters, then selects\nthe point closest to each cluster center. This ensures a space-filling\nsubset of points for surrogate model training.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-----------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Design points, shape (n_samples, n_features). | _required_ |\n| y | [ndarray](`ndarray`) | Function values at X, shape (n_samples,). | _required_ |\n| k | [int](`int`) | Number of points to select. | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|---------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| tuple | [Tuple](`typing.Tuple`)\\[[np](`numpy`).[ndarray](`numpy.ndarray`), [np](`numpy`).[ndarray](`numpy.ndarray`)\\] | A tuple containing: * selected_X (ndarray): Selected design points, shape (k, n_features). * selected_y (ndarray): Function values at selected points, shape (k,). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#0434e10d .cell execution_count=23}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n max_surrogate_points=5)\nX = np.random.rand(100, 2)\ny = np.random.rand(100)\nX_sel, y_sel = opt.fit_select_distant_points(X, y, 5)\nprint(X_sel.shape)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n(5, 2)\n```\n:::\n:::\n\n\n### fit_selection_dispatcher { #spotoptim.SpotOptim.SpotOptim.fit_selection_dispatcher }\n\n```python\nSpotOptim.SpotOptim.fit_selection_dispatcher(X, y)\n```\n\nDispatcher for selection methods.\nDepending on the value of `self.selection_method`, this method calls\nthe appropriate selection function to choose a subset of points for\nsurrogate model training when the total number of points exceeds\n`self.max_surrogate_points`.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-----------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Design points, shape (n_samples, n_features). | _required_ |\n| y | [ndarray](`ndarray`) | Function values at X, shape (n_samples,). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|---------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------|\n| tuple | [Tuple](`typing.Tuple`)\\[[np](`numpy`).[ndarray](`numpy.ndarray`), [np](`numpy`).[ndarray](`numpy.ndarray`)\\] | A tuple containing: * selected_X (ndarray): Selected design points. * selected_y (ndarray): Function values at selected points. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#4930a0f8 .cell execution_count=24}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n max_surrogate_points=5)\nX = np.random.rand(100, 2)\ny = np.random.rand(100)\nX_sel, y_sel = opt.fit_selection_dispatcher(X, y)\nprint(X_sel.shape[0] <= 5)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTrue\n```\n:::\n:::\n\n\n### fit_surrogate { #spotoptim.SpotOptim.SpotOptim.fit_surrogate }\n\n```python\nSpotOptim.SpotOptim.fit_surrogate(X, y)\n```\n\nFit surrogate model to data.\nUsed by fit_scheduler() to fit the surrogate model.\nIf the number of points exceeds `self.max_surrogate_points`,\na subset of points is selected using the selection dispatcher.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-----------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Design points, shape (n_samples, n_features). | _required_ |\n| y | [ndarray](`ndarray`) | Function values at X, shape (n_samples,). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n```python\n>>> import numpy as np\n>>> from spotoptim import SpotOptim\n>>> from sklearn.gaussian_process import GaussianProcessRegressor\n>>> def sphere(X):\n... X = np.atleast_2d(X)\n... return np.sum(X**2, axis=1)\n>>> opt = SpotOptim(fun=sphere,\n... bounds=[(-5, 5), (-5, 5)],\n... max_surrogate_points=10,\n... surrogate=GaussianProcessRegressor())\n>>> X = np.random.rand(50, 2)\n>>> y = np.random.rand(50)\n>>> opt.fit_surrogate(X, y)\n>>> # Surrogate is now fitted\n```\n\n### gen_design_table { #spotoptim.SpotOptim.SpotOptim.gen_design_table }\n\n```python\nSpotOptim.SpotOptim.gen_design_table(precision=4, tablefmt='github')\n```\n\nGenerate a table of the design or results.\nIf optimization has been run (results available), returns the results table.\nOtherwise, returns the design table (search space configuration).\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|-----------|--------------|-----------------------------------------------------------|------------|\n| tablefmt | [str](`str`) | Table format. Defaults to 'github'. | `'github'` |\n| precision | [int](`int`) | Number of decimal places for float values. Defaults to 4. | `4` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------------|-------------------------|\n| str | [str](`str`) | Formatted table string. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#13cc3f91 .cell execution_count=25}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n\ndef sphere(X):\n X = np.atleast_2d(X)\n return np.sum(X**2, axis=1)\n\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-10, 10), (0, 1)],\n var_name=[\"x1\", \"x2\", \"x3\"],\n var_type=[\"float\", \"int\", \"float\"],\n max_iter=10,\n n_initial=5\n)\ntable = opt.gen_design_table()\nprint(table)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n| name | type | lower | upper | default | transform |\n|--------|--------|---------|---------|-----------|-------------|\n| x1 | float | -5 | 5 | 0 | - |\n| x2 | int | -10 | 10 | 0 | - |\n| x3 | float | 0 | 1 | 0.5 | - |\n```\n:::\n:::\n\n\n### generate_initial_design { #spotoptim.SpotOptim.SpotOptim.generate_initial_design }\n\n```python\nSpotOptim.SpotOptim.generate_initial_design()\n```\n\nGenerate initial space-filling design using Latin Hypercube Sampling.\nUsed in the optimize() method to create the initial set of design points.\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|-------------------------------------------------------------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Initial design points, shape (n_initial, n_features). Points are in the intervals defined by `self.bounds`. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#3fccaf4d .cell execution_count=26}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nopt = SpotOptim(fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=3,\n var_type=['float', 'int'],\n var_trans=['log10', None])\nX0 = opt.generate_initial_design()\nprint(X0.shape)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n(3, 2)\n```\n:::\n:::\n\n\n### get_best_hyperparameters { #spotoptim.SpotOptim.SpotOptim.get_best_hyperparameters }\n\n```python\nSpotOptim.SpotOptim.get_best_hyperparameters(as_dict=True)\n```\n\nGet the best hyperparameter configuration found during optimization.\nIf noise handling is active (repeats_initial > 1 or OCBA), this returns the parameter\nconfiguration associated with the best *mean* objective value. Otherwise, it returns\nthe configuration associated with the absolute best observed value.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|---------|----------------|---------------------------------------------------------------------------------------------------------------------------------|-----------|\n| as_dict | [bool](`bool`) | If True, returns a dictionary mapping parameter names to their values. If False, returns the raw numpy array. Defaults to True. | `True` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|---------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------|\n| | [Union](`typing.Union`)\\[[Dict](`typing.Dict`)\\[[str](`str`), [Any](`typing.Any`)\\], [np](`numpy`).[ndarray](`numpy.ndarray`), None\\] | Union[Dict[str, Any], np.ndarray, None]: The best hyperparameter configuration. Returns None if optimization hasn't started (no data). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#fcf39f9b .cell execution_count=27}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\n\nopt = SpotOptim(fun=sphere,\n bounds=[(-5, 5), (0, 10)],\n n_initial=5,\n var_name=[\"x\", \"y\"],\n verbose=True)\nopt.optimize()\nbest_params = opt.get_best_hyperparameters()\nprint(best_params['x']) # Should be close to 0\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTensorBoard logging disabled\nInitial best: f(x) = 21.001919\nIter 1 | Best: 10.937353 | Rate: 1.00 | Evals: 30.0%\nIter 2 | Best: 3.690681 | Rate: 1.00 | Evals: 35.0%\nIter 3 | Best: 0.171879 | Rate: 1.00 | Evals: 40.0%\nIter 4 | Best: 0.112225 | Rate: 1.00 | Evals: 45.0%\nIter 5 | Best: 0.000182 | Rate: 1.00 | Evals: 50.0%\nIter 6 | Best: 0.000001 | Rate: 1.00 | Evals: 55.0%\nIter 7 | Best: 0.000000 | Rate: 1.00 | Evals: 60.0%\nIter 8 | Best: 0.000000 | Rate: 1.00 | Evals: 65.0%\nIter 9 | Best: 0.000000 | Rate: 1.00 | Evals: 70.0%\nIter 10 | Best: 0.000000 | Rate: 1.00 | Evals: 75.0%\nIter 11 | Best: 0.000000 | Rate: 1.00 | Evals: 80.0%\nIter 12 | Best: 0.000000 | Rate: 1.00 | Evals: 85.0%\nIter 13 | Best: 0.000000 | Curr: 0.000000 | Rate: 0.92 | Evals: 90.0%\nIter 14 | Best: 0.000000 | Curr: 0.000000 | Rate: 0.86 | Evals: 95.0%\nIter 15 | Best: 0.000000 | Rate: 0.87 | Evals: 100.0%\n0.0003481606136886121\n```\n:::\n:::\n\n\n### get_best_xy_initial_design { #spotoptim.SpotOptim.SpotOptim.get_best_xy_initial_design }\n\n```python\nSpotOptim.SpotOptim.get_best_xy_initial_design()\n```\n\nDetermine and store the best point from initial design.\nFinds the best (minimum) function value in the initial design,\nstores the corresponding point and value in instance attributes,\nand optionally prints the results if verbose mode is enabled.\nFor noisy functions, also reports the mean best value.\n\n#### Note {.doc-section .doc-section-note}\n\nThis method assumes self.X_ and self.y_ have been initialized\nwith the initial design evaluations.\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#86a8c68b .cell execution_count=28}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n verbose=True\n)\n# Simulate initial design (normally done in optimize())\nopt.X_ = np.array([[1, 2], [0, 0], [2, 1]])\nopt.y_ = np.array([5.0, 0.0, 5.0])\nopt.get_best_xy_initial_design()\nprint(f\"Best x: {opt.best_x_}\")\nprint(f\"Best y: {opt.best_y_}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTensorBoard logging disabled\nInitial best: f(x) = 0.000000\nBest x: [0 0]\nBest y: 0.0\n```\n:::\n:::\n\n\n::: {#4a2675d6 .cell execution_count=29}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import noisy_sphere\n# With noisy function\nopt_noise = SpotOptim(\n fun=noisy_sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n repeats_surrogate=2,\n verbose=True\n)\nopt_noise.X_ = np.array([[1, 2], [0, 0], [2, 1]])\nopt_noise.y_ = np.array([5.0, 0.0, 5.0])\nopt_noise.min_mean_y = 0.5 # Simulated mean best\nopt_noise.get_best_xy_initial_design()\nprint(f\"Best x: {opt_noise.best_x_}\")\nprint(f\"Best y: {opt_noise.best_y_}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTensorBoard logging disabled\nInitial best: f(x) = 0.000000, mean best: f(x) = 0.500000\nBest x: [0 0]\nBest y: 0.0\n```\n:::\n:::\n\n\n### get_design_table { #spotoptim.SpotOptim.SpotOptim.get_design_table }\n\n```python\nSpotOptim.SpotOptim.get_design_table(tablefmt='github', precision=4)\n```\n\nGet a table string showing the search space design before optimization.\nThis method generates a table displaying the variable names, types, bounds,\nand defaults without requiring an optimization run. Useful for inspecting\nand documenting the search space configuration.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|-----------|--------------|-----------------------------------------------------------|------------|\n| tablefmt | [str](`str`) | Table format for tabulate library. Defaults to 'github'. | `'github'` |\n| precision | [int](`int`) | Number of decimal places for float values. Defaults to 4. | `4` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------------|-------------------------|\n| str | [str](`str`) | Formatted table string. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#5b5adedf .cell execution_count=30}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n\ndef sphere(X):\n X = np.atleast_2d(X)\n return np.sum(X**2, axis=1)\n\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-10, 10), (0, 1)],\n var_name=[\"x1\", \"x2\", \"x3\"],\n var_type=[\"float\", \"int\", \"float\"],\n max_iter=10,\n n_initial=5\n)\ntable = opt.get_design_table()\nprint(table)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n| name | type | lower | upper | default | transform |\n|--------|--------|---------|---------|-----------|-------------|\n| x1 | float | -5 | 5 | 0 | - |\n| x2 | int | -10 | 10 | 0 | - |\n| x3 | float | 0 | 1 | 0.5 | - |\n```\n:::\n:::\n\n\n### get_experiment_filename { #spotoptim.SpotOptim.SpotOptim.get_experiment_filename }\n\n```python\nSpotOptim.SpotOptim.get_experiment_filename(prefix)\n```\n\nGenerate experiment filename with '_exp.pkl' suffix.\n\n### get_importance { #spotoptim.SpotOptim.SpotOptim.get_importance }\n\n```python\nSpotOptim.SpotOptim.get_importance()\n```\n\nCalculate variable importance scores.\nImportance is computed as the normalized sensitivity of each parameter\nbased on the variation in objective values across the evaluated points.\nHigher scores indicate parameters that have more influence on the objective.\nThe importance is calculated as:\n 1. For each dimension, compute the correlation between parameter values\n and objective values\n 2. Normalize to percentage scale (0-100)\n 3. Higher values indicate more important parameters\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|-------------------------------------------|------------------------------------------------------------------|\n| | [List](`typing.List`)\\[[float](`float`)\\] | List[float]: Importance scores for each dimension (0-100 scale). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#40ebff5d .cell execution_count=31}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n\ndef test_func(X):\n # x0 has strong effect, x1 has weak effect\n return 10 * X[:, 0]**2 + 0.1 * X[:, 1]**2\n\nopt = SpotOptim(\n fun=test_func,\n bounds=[(-5, 5), (-5, 5)],\n var_name=[\"x0\", \"x1\"],\n max_iter=10,\n n_initial=5,\n seed=42\n)\nresult = opt.optimize()\nimportance = opt.get_importance()\nprint(f\"x0 importance: {importance[0]:.2f}\")\nprint(f\"x1 importance: {importance[1]:.2f}\")\n\n# Use table to display importance\ntable = opt.get_results_table(show_importance=True)\nprint(table)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nx0 importance: 73.24\nx1 importance: 26.76\n| name | type | default | lower | upper | tuned | transform | importance | stars |\n|--------|--------|-----------|---------|---------|---------|-------------|--------------|---------|\n| x0 | float | 0 | -5 | 5 | 0.1701 | - | 73.24 | * |\n| x1 | float | 0 | -5 | 5 | 1.9552 | - | 26.76 | . |\n\nInterpretation: ***: >99%, **: >75%, *: >50%, .: >10%\n```\n:::\n:::\n\n\n### get_initial_design { #spotoptim.SpotOptim.SpotOptim.get_initial_design }\n\n```python\nSpotOptim.SpotOptim.get_initial_design(X0=None)\n```\n\nGenerate or process initial design points. Ensures that design points are in\ninternal (transformed and reduced) scale.\nCalls `generate_initial_design()` if `X0` is None, otherwise processes user-provided `X0`.\nHandles three scenarios:\n * `X0` is None: Generate space-filling design using LHS\n * `X0` is None but starting point(s) `x0` is provided: Generate LHS and include `x0` as first point(s)\n * `X0` is provided: Transform and prepare user-provided initial design\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------|-----------|\n| X0 | [ndarray](`ndarray`) | User-provided initial design points in original scale, shape (n_initial, n_features). If None, generates space-filling design. Defaults to None. | `None` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|-----------------------------------------------------------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Initial design points in internal (transformed and reduced) scale, shape (n_initial, n_features_reduced). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#1842b498 .cell execution_count=32}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nfrom spotoptim.plot.visualization import plot_design_points\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=10\n)\n# Generate default LHS design\nX0 = opt.get_initial_design()\nprint(X0.shape)\nplot_design_points(X0)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n(10, 2)\n```\n:::\n\n::: {.cell-output .cell-output-display}\n![](SpotOptim.SpotOptim_files/figure-html/cell-33-output-2.png){width=565 height=469}\n:::\n\n::: {.cell-output .cell-output-display execution_count=32}\n![](SpotOptim.SpotOptim_files/figure-html/cell-33-output-3.png){width=565 height=469}\n:::\n:::\n\n\n::: {#249d5df2 .cell execution_count=33}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nfrom spotoptim.plot.visualization import plot_design_points\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=10,\n x0=np.array([0, 0]) # Starting point to include in initial design\n)\nX0 = opt.get_initial_design()\nprint(X0.shape)\nplot_design_points(X0)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n(10, 2)\n```\n:::\n\n::: {.cell-output .cell-output-display}\n![](SpotOptim.SpotOptim_files/figure-html/cell-34-output-2.png){width=565 height=469}\n:::\n\n::: {.cell-output .cell-output-display execution_count=33}\n![](SpotOptim.SpotOptim_files/figure-html/cell-34-output-3.png){width=565 height=469}\n:::\n:::\n\n\n### get_ocba { #spotoptim.SpotOptim.SpotOptim.get_ocba }\n\n```python\nSpotOptim.SpotOptim.get_ocba(means, vars, delta, verbose=False)\n```\n\nOptimal Computing Budget Allocation (OCBA).\n\n### get_ocba_X { #spotoptim.SpotOptim.SpotOptim.get_ocba_X }\n\n```python\nSpotOptim.SpotOptim.get_ocba_X(X, means, vars, delta, verbose=False)\n```\n\nCalculate OCBA allocation and repeat input array X.\n\n### get_pickle_safe_optimizer { #spotoptim.SpotOptim.SpotOptim.get_pickle_safe_optimizer }\n\n```python\nSpotOptim.SpotOptim.get_pickle_safe_optimizer(\n unpickleables='file_io',\n verbosity=0,\n)\n```\n\nCreate a pickle-safe copy of the optimizer.\n\n### get_ranks { #spotoptim.SpotOptim.SpotOptim.get_ranks }\n\n```python\nSpotOptim.SpotOptim.get_ranks(x)\n```\n\nReturns ranks of numbers within input array x.\n\n### get_result_filename { #spotoptim.SpotOptim.SpotOptim.get_result_filename }\n\n```python\nSpotOptim.SpotOptim.get_result_filename(prefix)\n```\n\nGenerate result filename with '_res.pkl' suffix.\n\n### get_results_table { #spotoptim.SpotOptim.SpotOptim.get_results_table }\n\n```python\nSpotOptim.SpotOptim.get_results_table(\n tablefmt='github',\n precision=4,\n show_importance=False,\n)\n```\n\nGet a comprehensive table string of optimization results.\nThis method generates a formatted table of the search space configuration,\nbest values found, and optionally variable importance scores.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|-----------------|----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|\n| tablefmt | [str](`str`) | Table format for tabulate library. Options include: 'github', 'grid', 'simple', 'plain', 'html', 'latex', etc. Defaults to 'github'. | `'github'` |\n| precision | [int](`int`) | Number of decimal places for float values. Defaults to 4. | `4` |\n| show_importance | [bool](`bool`) | Whether to include importance scores. Importance is calculated as the normalized standard deviation of each parameter's effect on the objective. Requires multiple evaluations. Defaults to False. | `False` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------------|------------------------------------------------------|\n| str | [str](`str`) | Formatted table string that can be printed or saved. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#3ced231f .cell execution_count=34}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n\n# Example 1: Basic usage after optimization\ndef sphere(X):\n X = np.atleast_2d(X)\n return np.sum(X**2, axis=1)\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5), (-5, 5)],\n var_name=[\"x1\", \"x2\", \"x3\"],\n var_type=[\"float\", \"float\", \"float\"],\n max_iter=10,\n n_initial=5\n)\nresult = opt.optimize()\ntable = opt.get_results_table()\nprint(table)\ntable = opt.get_results_table(show_importance=True)\nprint(table)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n| name | type | default | lower | upper | tuned | transform |\n|--------|--------|-----------|---------|---------|---------|-------------|\n| x1 | float | 0 | -5 | 5 | -0.2921 | - |\n| x2 | float | 0 | -5 | 5 | 0.2695 | - |\n| x3 | float | 0 | -5 | 5 | 0.0753 | - |\n| name | type | default | lower | upper | tuned | transform | importance | stars |\n|--------|--------|-----------|---------|---------|---------|-------------|--------------|---------|\n| x1 | float | 0 | -5 | 5 | -0.2921 | - | 56.84 | * |\n| x2 | float | 0 | -5 | 5 | 0.2695 | - | 18.44 | . |\n| x3 | float | 0 | -5 | 5 | 0.0753 | - | 24.72 | . |\n\nInterpretation: ***: >99%, **: >75%, *: >50%, .: >10%\n```\n:::\n:::\n\n\n### get_shape { #spotoptim.SpotOptim.SpotOptim.get_shape }\n\n```python\nSpotOptim.SpotOptim.get_shape(y)\n```\n\nGet the shape of the objective function output.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-----------------------------------------------------------------------------|------------|\n| y | [ndarray](`ndarray`) | Objective function output, shape (n_samples,) or (n_samples, n_objectives). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|----------------------------------------------------------------------------------------|----------------------------------------------------------------------------|\n| tuple | [Tuple](`typing.Tuple`)\\[[int](`int`), [Optional](`typing.Optional`)\\[[int](`int`)\\]\\] | (n_samples, n_objectives) where n_objectives is None for single-objective. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#0ab2ca1b .cell execution_count=35}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(\n fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10,\n n_initial=5\n)\ny_single = np.array([1.0, 2.0, 3.0])\nn, m = opt.get_shape(y_single)\nprint(f\"n={n}, m={m}\")\ny_multi = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])\nn, m = opt.get_shape(y_multi)\nprint(f\"n={n}, m={m}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nn=3, m=None\nn=3, m=2\n```\n:::\n:::\n\n\n### get_stars { #spotoptim.SpotOptim.SpotOptim.get_stars }\n\n```python\nSpotOptim.SpotOptim.get_stars(input_list)\n```\n\nConverts a list of values to a list of stars.\nUsed to visualize the importance of a variable.\nThresholds: >99: ***, >75: **, >50: *, >10: .\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|------------|----------------|--------------------------------------|------------|\n| input_list | [list](`list`) | A list of importance scores (0-100). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|----------------|-------------------------|\n| list | [list](`list`) | A list of star strings. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#c2fbe63b .cell execution_count=36}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nimport numpy as np\n\ndef test_func(X):\n return 10 * X[:, 0]**2 + 0.1 * X[:, 1]**2\n\nopt = SpotOptim(\n fun=test_func,\n bounds=[(-5, 5), (-5, 5)],\n var_name=[\"x0\", \"x1\"],\n max_iter=10,\n n_initial=5,\n seed=42\n)\nopt.optimize()\nopt.get_stars([100, 75, 50, 10, 0])\n```\n\n::: {.cell-output .cell-output-display execution_count=36}\n```\n['***', '*', '.', '', '']\n```\n:::\n:::\n\n\n### get_success_rate { #spotoptim.SpotOptim.SpotOptim.get_success_rate }\n\n```python\nSpotOptim.SpotOptim.get_success_rate()\n```\n\nGet the current success rate of the optimization process.\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|------------------|---------------------------|\n| float | [float](`float`) | The current success rate. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#e604d927 .cell execution_count=37}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda x: x,\n bounds=[(-5, 5), (-5, 5)])\nprint(opt.get_success_rate())\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n0.0\n```\n:::\n:::\n\n\n### handle_default_var_trans { #spotoptim.SpotOptim.SpotOptim.handle_default_var_trans }\n\n```python\nSpotOptim.SpotOptim.handle_default_var_trans()\n```\n\nHandle default variable transformations. Does not perform any transformations,\nonly sets `var_trans` to a list of `None` values if not specified, or normalizes\ntransformation names by converting `id`, `None`, or `None` to `None`.\nAlso validates that `var_trans` length matches the number of dimensions.\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Raises {.doc-section .doc-section-raises}\n\n| Name | Type | Description |\n|--------|----------------------------|------------------------------------------|\n| | [ValueError](`ValueError`) | If var_trans length doesn't match n_dim. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#e79a4630 .cell execution_count=38}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\n# Default behavior - all None\nspot = SpotOptim(fun=lambda x: x, bounds=[(0, 10), (0, 10)])\nprint(f\"spot.var_trans (should be [None, None]): {spot.var_trans}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nspot.var_trans (should be [None, None]): [None, None]\n```\n:::\n:::\n\n\n::: {#a0373001 .cell execution_count=39}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\n# Normalize transformation names\nspot = SpotOptim(fun=lambda x: x, bounds=[(1, 10), (1, 100)],\n var_trans=['log10', 'id'])\nprint(f\"spot.var_trans (should be ['log10', 'None']): {spot.var_trans}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nspot.var_trans (should be ['log10', 'None']): ['log10', None]\n```\n:::\n:::\n\n\n### init_storage { #spotoptim.SpotOptim.SpotOptim.init_storage }\n\n```python\nSpotOptim.SpotOptim.init_storage(X0, y0)\n```\n\nInitialize storage for optimization.\nSets up the initial data structures needed for optimization tracking:\n * X_: Evaluated design points (in original scale)\n * y_: Function values at evaluated points\n * n_iter_: Iteration counter\nThen updates statistics by calling `update_stats()`.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-------------------------------------------------------------------------|------------|\n| X0 | [ndarray](`ndarray`) | Initial design points in internal scale, shape (n_samples, n_features). | _required_ |\n| y0 | [ndarray](`ndarray`) | Function values at X0, shape (n_samples,). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#696db1ea .cell execution_count=40}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5)\nX0 = np.array([[1, 2], [3, 4], [0, 1]])\ny0 = np.array([5.0, 25.0, 1.0])\nopt.init_storage(X0, y0)\nprint(f\"X_ = {opt.X_}\")\nprint(f\"y_ = {opt.y_}\")\nprint(f\"n_iter_ = {opt.n_iter_}\")\nprint(f\"counter = {opt.counter}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nX_ = [[1. 2.]\n [3. 4.]\n [0. 1.]]\ny_ = [ 5. 25. 1.]\nn_iter_ = 0\ncounter = 0\n```\n:::\n:::\n\n\n### init_surrogate { #spotoptim.SpotOptim.SpotOptim.init_surrogate }\n\n```python\nSpotOptim.SpotOptim.init_surrogate()\n```\n\nInitialize or configure the surrogate model for optimization. Handles three surrogate configurations:\n * List of surrogates: sets up multi-surrogate selection with probability weights and per-surrogate `max_surrogate_points`.\n * None (default): creates a `GaussianProcessRegressor` with a\n `ConstantKernel * Matern(nu=2.5)` kernel, 100 optimizer restarts,\n and `normalize_y=True`.\n * User-provided surrogate: accepted as-is; internal bookkeeping\n attributes (`_max_surrogate_points_list`,\n `_active_max_surrogate_points`) are still initialised.\nAfter this method returns the following attributes are set:\n * `self.surrogate` — the active surrogate model.\n * `self._surrogates_list` — `list | None`.\n * `self._prob_surrogate` — normalised selection probabilities or `None`.\n * `self._max_surrogate_points_list` — per-surrogate point caps or `None`.\n * `self._active_max_surrogate_points` — active cap.\n\n#### Raises {.doc-section .doc-section-raises}\n\n| Name | Type | Description |\n|--------|----------------------------|---------------------------------------------------------------------------------|\n| | [ValueError](`ValueError`) | If the surrogate list is empty. |\n| | [ValueError](`ValueError`) | If 'prob_surrogate' length does not match the surrogate list length. |\n| | [ValueError](`ValueError`) | If 'max_surrogate_points' list length does not match the surrogate list length. |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#4a4f55d1 .cell execution_count=41}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n# Default surrogate (GaussianProcessRegressor)\nopt = SpotOptim(\n fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n)\nprint(type(opt.surrogate).__name__)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nGaussianProcessRegressor\n```\n:::\n:::\n\n\n::: {#47a4a963 .cell execution_count=42}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom sklearn.ensemble import RandomForestRegressor\n# User-provided surrogate\nrf = RandomForestRegressor(n_estimators=50, random_state=42)\nopt = SpotOptim(\n fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n surrogate=rf,\n)\nprint(type(opt.surrogate).__name__)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nRandomForestRegressor\n```\n:::\n:::\n\n\n::: {#a75a4ad9 .cell execution_count=43}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom sklearn.ensemble import RandomForestRegressor\nfrom sklearn.gaussian_process import GaussianProcessRegressor\n# List of surrogates with selection probabilities\nsurrogates = [GaussianProcessRegressor(), RandomForestRegressor()]\nopt = SpotOptim(\n fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n surrogate=surrogates,\n prob_surrogate=[0.7, 0.3],\n)\nprint(opt._prob_surrogate)\nprint([type(s).__name__ for s in opt._surrogates_list])\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[0.7, 0.3]\n['GaussianProcessRegressor', 'RandomForestRegressor']\n```\n:::\n:::\n\n\n### inverse_transform_X { #spotoptim.SpotOptim.SpotOptim.inverse_transform_X }\n\n```python\nSpotOptim.SpotOptim.inverse_transform_X(X)\n```\n\nTransform parameter array from internal to original scale.\nConverts from transformed space (full dimension) to natural space (original).\nDoes NOT handle dimension expansion (un-mapping).\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-----------------------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Array in Transformed Space, shape (n_samples, n_features) | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Array in Natural Space |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#a4ec4965 .cell execution_count=44}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nimport numpy as np\nspot = SpotOptim(fun=sphere, bounds=[(1, 10)], var_trans=['log10'])\nX_trans = np.array([[0], [1], [2]])\nspot.inverse_transform_X(X_trans)\n```\n\n::: {.cell-output .cell-output-display execution_count=44}\n```\narray([[ 1],\n [ 10],\n [100]])\n```\n:::\n:::\n\n\n### inverse_transform_value { #spotoptim.SpotOptim.SpotOptim.inverse_transform_value }\n\n```python\nSpotOptim.SpotOptim.inverse_transform_value(x, trans)\n```\n\nApply inverse transformation to a single float value.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|-----------------------------------------------|----------------------|------------|\n| x | [float](`float`) | Transformed value | _required_ |\n| trans | [Optional](`typing.Optional`)\\[[str](`str`)\\] | Transformation name. | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|------------------|----------------|\n| | [float](`float`) | Original value |\n\n#### Notes {.doc-section .doc-section-notes}\n\nSee also transform_value.\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#b0377034 .cell execution_count=45}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nspot = SpotOptim(fun=sphere, bounds=[(1, 10)])\nspot.inverse_transform_value(10, 'log10')\nspot.inverse_transform_value(100, 'log(x)')\n```\n\n::: {.cell-output .cell-output-display execution_count=45}\n```\nnp.float64(2.6881171418161356e+43)\n```\n:::\n:::\n\n\n### load_experiment { #spotoptim.SpotOptim.SpotOptim.load_experiment }\n\n```python\nSpotOptim.SpotOptim.load_experiment(filename)\n```\n\nLoad experiment configuration from a pickle file.\n\n### load_result { #spotoptim.SpotOptim.SpotOptim.load_result }\n\n```python\nSpotOptim.SpotOptim.load_result(filename)\n```\n\nLoad complete optimization results from a pickle file.\n\n### map_to_factor_values { #spotoptim.SpotOptim.SpotOptim.map_to_factor_values }\n\n```python\nSpotOptim.SpotOptim.map_to_factor_values(X)\n```\n\nMap internal integer factor values back to string labels.\nFor factor variables, converts integer indices back to original string values.\nOther variable types remain unchanged.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-------------------------------------------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Design points with integer values for factors, shape (n_samples, n_features). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|--------------------------------------------------------------------------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Design points with factor integers replaced by string labels. Dtype will be object or string if mixed types are present. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#a337f7c4 .cell execution_count=46}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nimport numpy as np\nspot = SpotOptim(\n fun=sphere,\n bounds=[('red', 'blue'), (0, 10)]\n)\nspot.process_factor_bounds()\nX_int = np.array([[0, 5.0], [1, 8.0]])\nX_str = spot.map_to_factor_values(X_int)\nprint(X_str[0])\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n['red' 5.0]\n```\n:::\n:::\n\n\n### mo2so { #spotoptim.SpotOptim.SpotOptim.mo2so }\n\n```python\nSpotOptim.SpotOptim.mo2so(y_mo)\n```\n\nConvert multi-objective values to single-objective.\nConverts multi-objective values to a single-objective value by applying a user-defined\nfunction from `fun_mo2so`. If no user-defined function is given, the\nvalues in the first objective column are used.\n\nThis method is called after the objective function evaluation. It returns a 1D array\nwith the single-objective values.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|----------------------------------------------------------------------------------------------------------|------------|\n| y_mo | [ndarray](`ndarray`) | If multi-objective, shape (n_samples, n_objectives). If single-objective, shape (n_samples,). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|----------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Single-objective values, shape (n_samples,). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#769f687b .cell execution_count=47}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n\n# Multi-objective function\ndef mo_fun(X):\n return np.column_stack([\n np.sum(X**2, axis=1),\n np.sum((X-1)**2, axis=1)\n ])\n\n# Example 1: Default behavior (use first objective)\nopt1 = SpotOptim(\n fun=mo_fun,\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10,\n n_initial=5\n)\ny_mo = np.array([[1.0, 2.0], [3.0, 4.0]])\ny_so = opt1.mo2so(y_mo)\nprint(f\"Single-objective (default): {y_so}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nSingle-objective (default): [1. 3.]\n```\n:::\n:::\n\n\n::: {#763ab0aa .cell execution_count=48}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n# Example 2: Custom conversion function (sum of objectives)\ndef custom_mo2so(y_mo):\n return y_mo[:, 0] + y_mo[:, 1]\n\nopt2 = SpotOptim(\n fun=mo_fun,\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10,\n n_initial=5,\n fun_mo2so=custom_mo2so\n)\ny_so_custom = opt2.mo2so(y_mo)\nprint(f\"Single-objective (custom): {y_so_custom}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nSingle-objective (custom): [3. 7.]\n```\n:::\n:::\n\n\n### modify_bounds_based_on_var_type { #spotoptim.SpotOptim.SpotOptim.modify_bounds_based_on_var_type }\n\n```python\nSpotOptim.SpotOptim.modify_bounds_based_on_var_type()\n```\n\nModify bounds based on variable types.\nAdjusts bounds for each dimension according to its var_type:\n * 'int': Ensures bounds are integers (ceiling for lower, floor for upper)\n * 'factor': Bounds already set to (0, n_levels-1) by process_factor_bounds\n * 'float': Explicitly converts bounds to float\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Raises {.doc-section .doc-section-raises}\n\n| Name | Type | Description |\n|--------|----------------------------|--------------------------------------------|\n| | [ValueError](`ValueError`) | If an unsupported var_type is encountered. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#e767b87a .cell execution_count=49}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nspot = SpotOptim(fun=lambda x: x, bounds=[(0.5, 10.5)], var_type=['int'])\nprint(spot.bounds)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[(1, 10)]\n```\n:::\n:::\n\n\n::: {#42cb35ba .cell execution_count=50}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nspot = SpotOptim(fun=lambda x: x, bounds=[(0, 10)], var_type=['float'])\nprint(spot.bounds)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[(0.0, 10.0)]\n```\n:::\n:::\n\n\n### optimize { #spotoptim.SpotOptim.SpotOptim.optimize }\n\n```python\nSpotOptim.SpotOptim.optimize(X0=None)\n```\n\nRun the optimization process. The optimization terminates when either the total function evaluations reach\n `max_iter` (including initial design), or the runtime exceeds max_time minutes. Input/Output spaces are\n * Input `X0`: Expected in Natural Space (original scale, physical units).\n * Output `result.x`: Returned in Natural Space.\n * Output `result.X`: Returned in Natural Space.\n * Internal Optimization: Performed in Transformed and Mapped Space.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-----------------------------------------------------------------------------------------------------------------------------------|-----------|\n| X0 | [ndarray](`ndarray`) | Initial design points in Natural Space, shape (n_initial, n_features). If None, generates space-filling design. Defaults to None. | `None` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|----------------|---------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| OptimizeResult | [OptimizeResult](`scipy.optimize.OptimizeResult`) | Optimization result with fields: * x: best point found in Natural Space * fun: best function value * nfev: number of function evaluations (including initial design) * nit: number of sequential optimization iterations (after initial design) * success: whether optimization succeeded * message: termination message indicating reason for stopping, including statistics (function value, iterations, evaluations) * X: all evaluated points in Natural Space * y: all function values |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#36dc8836 .cell execution_count=51}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n max_iter=10,\n seed=0,\n x0=np.array([0.1, -0.1]),\n verbose=True\n)\nresult = opt.optimize()\nprint(result.message.splitlines()[0])\nprint(\"Best point:\", result.x)\nprint(\"Best value:\", result.fun)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nStarting point x0 validated and processed successfully.\n Original scale: [ 0.1 -0.1]\n Internal scale: [ 0.1 -0.1]\nTensorBoard logging disabled\nIncluding 1 starting points from x0 in initial design.\nInitial best: f(x) = 0.020000\nIter 1 | Best: 0.020000 | Curr: 14.707944 | Rate: 0.00 | Evals: 60.0%\nOptimizer candidate 1/3 was duplicate/invalid.\nIter 2 | Best: 0.020000 | Curr: 0.020020 | Rate: 0.00 | Evals: 70.0%\nIter 3 | Best: 0.020000 | Curr: 0.322921 | Rate: 0.00 | Evals: 80.0%\nIter 4 | Best: 0.002244 | Rate: 0.25 | Evals: 90.0%\nIter 5 | Best: 0.002179 | Rate: 0.40 | Evals: 100.0%\nOptimization terminated: maximum evaluations (10) reached\nBest point: [0.04474339 0.01330855]\nBest value: 0.002179088112986503\n```\n:::\n:::\n\n\n### optimize_acquisition_func { #spotoptim.SpotOptim.SpotOptim.optimize_acquisition_func }\n\n```python\nSpotOptim.SpotOptim.optimize_acquisition_func()\n```\n\nOptimize the acquisition function to find the next point to evaluate.\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | The optimized point(s). If acquisition_fun_return_size == 1, returns 1D array of shape (n_features,). If acquisition_fun_return_size > 1, returns 2D array of shape (N, n_features), where N is min(acquisition_fun_return_size, population_size). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#283531fa .cell execution_count=52}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\ndef sphere(X):\n X = np.atleast_2d(X)\n return np.sum(X**2, axis=1)\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n max_iter=10,\n seed=0,\n)\nopt.optimize()\nx_next = opt.suggest_next_infill_point()\nprint(\"Next point to evaluate:\", x_next)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nNext point to evaluate: [[0.14356455 0.03793884]]\n```\n:::\n:::\n\n\n### optimize_sequential_run { #spotoptim.SpotOptim.SpotOptim.optimize_sequential_run }\n\n```python\nSpotOptim.SpotOptim.optimize_sequential_run(\n timeout_start,\n X0=None,\n y0_known=None,\n max_iter_override=None,\n)\n```\n\nPerform a single sequential optimization run.\nCalls _initialize_run, rm_initial_design_NA_values, check_size_initial_design, init_storage, get_best_xy_initial_design, and _run_sequential_loop.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|-------------------|---------------------------------------------------------------------------|------------------------------------------------------------------------|------------|\n| timeout_start | [float](`float`) | Start time for timeout. | _required_ |\n| X0 | [Optional](`typing.Optional`)\\[[np](`numpy`).[ndarray](`numpy.ndarray`)\\] | Initial design points in Natural Space, shape (n_initial, n_features). | `None` |\n| y0_known | [Optional](`typing.Optional`)\\[[float](`float`)\\] | Known best value for initial design. | `None` |\n| max_iter_override | [Optional](`typing.Optional`)\\[[int](`int`)\\] | Override for maximum number of iterations. | `None` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------------------------------------------------------------------------------------------|------------------------------------------------------------------------------|\n| | [Tuple](`typing.Tuple`)\\[[str](`str`), [OptimizeResult](`scipy.optimize.OptimizeResult`)\\] | Tuple[str, OptimizeResult]: Tuple containing status and optimization result. |\n\n#### Raises {.doc-section .doc-section-raises}\n\n| Name | Type | Description |\n|--------|----------------------------|----------------------------------------------------------------------------------------------------------------------------|\n| | [ValueError](`ValueError`) | If the initial design has no valid points after removing NaN/inf values, or if the initial design is too small to proceed. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#6cefd235 .cell execution_count=53}\n``` {.python .cell-code}\nimport time\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nopt = SpotOptim(fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n max_iter=10,\n seed=0,\n verbose=True\n )\nstatus, result = opt.optimize_sequential_run(timeout_start=time.time())\nprint(status)\nprint(result.message.splitlines()[0])\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTensorBoard logging disabled\nInitial best: f(x) = 8.463203\nIter 1 | Best: 8.463203 | Curr: 18.224245 | Rate: 0.00 | Evals: 60.0%\nIter 2 | Best: 8.412459 | Rate: 0.50 | Evals: 70.0%\nIter 3 | Best: 5.623369 | Rate: 0.67 | Evals: 80.0%\nIter 4 | Best: 2.902974 | Rate: 0.75 | Evals: 90.0%\nIter 5 | Best: 0.022050 | Rate: 0.80 | Evals: 100.0%\nFINISHED\nOptimization terminated: maximum evaluations (10) reached\n```\n:::\n:::\n\n\n### plot_importance { #spotoptim.SpotOptim.SpotOptim.plot_importance }\n\n```python\nSpotOptim.SpotOptim.plot_importance(threshold=0.0, figsize=(10, 6))\n```\n\nPlot variable importance.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|-----------|------------------|---------------------------------------------------|-----------|\n| threshold | [float](`float`) | Minimum importance percentage to include in plot. | `0.0` |\n| figsize | [tuple](`tuple`) | Figure size. | `(10, 6)` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#cb7b7f3a .cell execution_count=54}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nimport numpy as np\n\ndef test_func(X):\n return 10 * X[:, 0]**2 + 0.1 * X[:, 1]**2\n\nopt = SpotOptim(\n fun=test_func,\n bounds=[(-5, 5), (-5, 5)],\n var_name=[\"x0\", \"x1\"],\n max_iter=10,\n n_initial=5,\n seed=42\n)\nopt.optimize()\nopt.plot_importance()\n```\n\n::: {.cell-output .cell-output-display}\n![](SpotOptim.SpotOptim_files/figure-html/cell-55-output-1.png){width=789 height=523}\n:::\n:::\n\n\n### plot_important_hyperparameter_contour { #spotoptim.SpotOptim.SpotOptim.plot_important_hyperparameter_contour }\n\n```python\nSpotOptim.SpotOptim.plot_important_hyperparameter_contour(\n max_imp=3,\n show=True,\n alpha=0.8,\n cmap='jet',\n num=100,\n add_points=True,\n grid_visible=True,\n contour_levels=30,\n figsize=(12, 10),\n)\n```\n\nPlot surrogate contours using spotoptim.plot.visualization.plot_important_hyperparameter_contour.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|----------------|------------------|----------------------------------------------------------|------------|\n| max_imp | [int](`int`) | The maximum number of important hyperparameters to plot. | `3` |\n| show | [bool](`bool`) | Whether to show the plot. | `True` |\n| alpha | [float](`float`) | The alpha value for the plot. | `0.8` |\n| cmap | [str](`str`) | The colormap to use. | `'jet'` |\n| num | [int](`int`) | The number of points to use for the plot. | `100` |\n| add_points | [bool](`bool`) | Whether to add points to the plot. | `True` |\n| grid_visible | [bool](`bool`) | Whether to show the grid. | `True` |\n| contour_levels | [int](`int`) | The number of contour levels to use. | `30` |\n| figsize | [tuple](`tuple`) | The size of the plot. | `(12, 10)` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#dd219443 .cell execution_count=55}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nimport numpy as np\n\ndef test_func(X):\n return 10 * X[:, 0]**2 + 0.1 * X[:, 1]**2\n\n# 2-D problem: max_imp must not exceed n_dim (2)\nopt = SpotOptim(\n fun=test_func,\n bounds=[(-5, 5), (-5, 5)],\n var_name=[\"x0\", \"x1\"],\n max_iter=10,\n n_initial=5,\n seed=42\n)\nopt.optimize()\nopt.plot_important_hyperparameter_contour(max_imp=2)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nPlotting surrogate contours for top 2 most important parameters:\n x0: importance = 73.24% (type: float)\n x1: importance = 26.76% (type: float)\n\nGenerating 1 surrogate plots...\n Plotting x0 vs x1\n```\n:::\n\n::: {.cell-output .cell-output-display}\n![](SpotOptim.SpotOptim_files/figure-html/cell-56-output-2.png){width=1113 height=950}\n:::\n:::\n\n\n### plot_parameter_scatter { #spotoptim.SpotOptim.SpotOptim.plot_parameter_scatter }\n\n```python\nSpotOptim.SpotOptim.plot_parameter_scatter(\n result=None,\n show=True,\n figsize=(12, 10),\n ylabel='Objective Value',\n cmap='viridis_r',\n show_correlation=False,\n log_y=False,\n)\n```\n\nPlot parameter distributions showing relationship between each parameter and objective.\nCreates a grid of scatter plots, one for each parameter dimension, showing how\nthe objective function value varies with each parameter. The best configuration\nis marked with a red star. Parameters with log-scale transformations (var_trans)\nare automatically displayed on a log x-axis.\nOptionally displays Spearman correlation coefficients in plot titles for\nsensitivity analysis. For factor (categorical) variables, correlation is not\ncomputed and they are displayed with discrete positions on the x-axis.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|------------------|---------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|---------------------|\n| result | [OptimizeResult](`scipy.optimize.OptimizeResult`) | Optimization result containing best parameters. If None, uses the best found values from self.best_x_ and self.best_y_. | `None` |\n| show | [bool](`bool`) | Whether to display the plot. Defaults to True. | `True` |\n| figsize | [tuple](`tuple`) | Figure size as (width, height). Defaults to (12, 10). | `(12, 10)` |\n| ylabel | [str](`str`) | Label for y-axis. Defaults to \"Objective Value\". | `'Objective Value'` |\n| cmap | [str](`str`) | Colormap for scatter plot. Defaults to \"viridis_r\". | `'viridis_r'` |\n| show_correlation | [bool](`bool`) | Whether to compute and display Spearman correlation coefficients in plot titles. Requires scipy. Defaults to False. | `False` |\n| log_y | [bool](`bool`) | Whether to use logarithmic scale for y-axis. Defaults to False. | `False` |\n\n#### Raises {.doc-section .doc-section-raises}\n\n| Name | Type | Description |\n|--------|----------------------------|---------------------------------------|\n| | [ValueError](`ValueError`) | If no optimization data is available. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#f74f2edd .cell execution_count=56}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\ndef objective(X):\n X = np.atleast_2d(X)\n return np.sum(X**2, axis=1)\nopt = SpotOptim(\n fun=objective,\n bounds=[(-5, 5), (-5, 5), (-5, 5), (-5, 5)],\n var_name=[\"x0\", \"x1\", \"x2\", \"x3\"],\n max_iter=10,\n n_initial=5,\n seed=42\n)\nresult = opt.optimize()\n# Plot parameter distributions\nopt.plot_parameter_scatter(result)\n# Plot with custom settings\nopt.plot_parameter_scatter(result, cmap=\"plasma\", ylabel=\"Error\")\n```\n\n::: {.cell-output .cell-output-display}\n![](SpotOptim.SpotOptim_files/figure-html/cell-57-output-1.png){width=1141 height=949}\n:::\n\n::: {.cell-output .cell-output-display}\n![](SpotOptim.SpotOptim_files/figure-html/cell-57-output-2.png){width=1141 height=949}\n:::\n:::\n\n\n### plot_progress { #spotoptim.SpotOptim.SpotOptim.plot_progress }\n\n```python\nSpotOptim.SpotOptim.plot_progress(\n show=True,\n log_y=False,\n figsize=(10, 6),\n ylabel='Objective Value',\n mo=False,\n)\n```\n\nPlot optimization progress using spotoptim.plot.visualization.plot_progress.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|---------|------------------|----------------------------------------------|---------------------|\n| show | [bool](`bool`) | Whether to show the plot. | `True` |\n| log_y | [bool](`bool`) | Whether to use a logarithmic y-axis. | `False` |\n| figsize | [tuple](`tuple`) | The size of the plot. | `(10, 6)` |\n| ylabel | [str](`str`) | The label for the y-axis. | `'Objective Value'` |\n| mo | [bool](`bool`) | Whether the optimization is multi-objective. | `False` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#481b4482 .cell execution_count=57}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nimport numpy as np\n\ndef test_func(X):\n return 10 * X[:, 0]**2 + 0.1 * X[:, 1]**2\n\nopt = SpotOptim(\n fun=test_func,\n bounds=[(-5, 5), (-5, 5)],\n var_name=[\"x0\", \"x1\"],\n max_iter=10,\n n_initial=5,\n seed=42\n)\nopt.optimize()\nopt.plot_progress()\n```\n\n::: {.cell-output .cell-output-display}\n![](SpotOptim.SpotOptim_files/figure-html/cell-58-output-1.png){width=949 height=565}\n:::\n:::\n\n\n### plot_surrogate { #spotoptim.SpotOptim.SpotOptim.plot_surrogate }\n\n```python\nSpotOptim.SpotOptim.plot_surrogate(\n i=0,\n j=1,\n show=True,\n alpha=0.8,\n var_name=None,\n cmap='jet',\n num=100,\n vmin=None,\n vmax=None,\n add_points=True,\n grid_visible=True,\n contour_levels=30,\n figsize=(12, 10),\n)\n```\n\nPlot the surrogate model for two dimensions.\nDelegates to spotoptim.plot.visualization.plot_surrogate.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|----------------|------------------------------------------------------------------------|-------------------------------------------|------------|\n| i | [int](`int`) | The index of the first dimension. | `0` |\n| j | [int](`int`) | The index of the second dimension. | `1` |\n| show | [bool](`bool`) | Whether to show the plot. | `True` |\n| alpha | [float](`float`) | The alpha value for the plot. | `0.8` |\n| var_name | [Optional](`typing.Optional`)\\[[List](`typing.List`)\\[[str](`str`)\\]\\] | The names of the variables. | `None` |\n| cmap | [str](`str`) | The colormap to use. | `'jet'` |\n| num | [int](`int`) | The number of points to use for the plot. | `100` |\n| vmin | [Optional](`typing.Optional`)\\[[float](`float`)\\] | The minimum value for the plot. | `None` |\n| vmax | [Optional](`typing.Optional`)\\[[float](`float`)\\] | The maximum value for the plot. | `None` |\n| add_points | [bool](`bool`) | Whether to add points to the plot. | `True` |\n| grid_visible | [bool](`bool`) | Whether to show the grid. | `True` |\n| contour_levels | [int](`int`) | The number of contour levels to use. | `30` |\n| figsize | [tuple](`tuple`) | The size of the plot. | `(12, 10)` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#65a5409a .cell execution_count=58}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nimport numpy as np\n\ndef test_func(X):\n return 10 * X[:, 0]**2 + 0.1 * X[:, 1]**2\n\nopt = SpotOptim(\n fun=test_func,\n bounds=[(-5, 5), (-5, 5)],\n var_name=[\"x0\", \"x1\"],\n max_iter=10,\n n_initial=5,\n seed=42\n)\nopt.optimize()\nopt.plot_surrogate()\n```\n\n::: {.cell-output .cell-output-display}\n![](SpotOptim.SpotOptim_files/figure-html/cell-59-output-1.png){width=1113 height=950}\n:::\n:::\n\n\n### print_best { #spotoptim.SpotOptim.SpotOptim.print_best }\n\n```python\nSpotOptim.SpotOptim.print_best(\n result=None,\n transformations=None,\n show_name=True,\n precision=4,\n)\n```\n\nPrint the best solution found during optimization.\nThis method displays the best hyperparameters and objective value in a\nformatted table. It supports custom transformations for parameters\n(e.g., converting log-scale values back to original scale).\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|-----------------|---------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|\n| result | [OptimizeResult](`scipy.optimize.OptimizeResult`) | Optimization result object from optimize(). If None, uses the stored best values from the optimizer. Defaults to None. | `None` |\n| transformations | list of callable | List of transformation functions to apply to each parameter. Each function takes a single value and returns the transformed value. Use None for parameters that don't need transformation. Length must match number of dimensions. Example: [None, None, lambda x: 10**x] to convert the 3rd parameter from log10 scale. Defaults to None. | `None` |\n| show_name | [bool](`bool`) | Whether to display variable names. If False, uses generic names like 'x0', 'x1', etc. Defaults to True. | `True` |\n| precision | [int](`int`) | Number of decimal places for floating point values. Defaults to 4. | `4` |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#d153d144 .cell execution_count=59}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n\ndef sphere(X):\n X = np.atleast_2d(X)\n return np.sum(X**2, axis=1)\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n var_name=[\"x1\", \"x2\"],\n max_iter=10,\n n_initial=5\n)\nresult = opt.optimize()\nopt.print_best(result)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n\nBest Solution Found:\n--------------------------------------------------\n x1: -1.1704\n x2: -0.4434\n Objective Value: 1.5664\n Total Evaluations: 10\n```\n:::\n:::\n\n\n### print_results { #spotoptim.SpotOptim.SpotOptim.print_results }\n\n```python\nSpotOptim.SpotOptim.print_results(*args, **kwargs)\n```\n\nAlias for print(get_results_table()) for compatibility.\nPrints the table.\n\n### process_factor_bounds { #spotoptim.SpotOptim.SpotOptim.process_factor_bounds }\n\n```python\nSpotOptim.SpotOptim.process_factor_bounds()\n```\n\nProcess `bounds` to handle factor variables.\nFor dimensions with tuple bounds (factor variables), creates internal\ninteger mappings and replaces bounds with (0, n_levels-1).\nStores mappings in `self._factor_maps`: {dim_idx: {int_val: str_val}}\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Raises {.doc-section .doc-section-raises}\n\n| Name | Type | Description |\n|--------|----------------------------|------------------------------------|\n| | [ValueError](`ValueError`) | If bounds are invalidly formatted. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#0792bc57 .cell execution_count=60}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nspot = SpotOptim(fun=lambda x: x, bounds=[('red', 'green', 'blue'), (0, 10)])\nspot.process_factor_bounds()\nprint(f\"spot.bounds (should be [(0, 2), (0, 10)]): {spot.bounds}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nspot.bounds (should be [(0, 2), (0, 10)]): [(0, 2), (0, 10)]\n```\n:::\n:::\n\n\n### reinitialize_components { #spotoptim.SpotOptim.SpotOptim.reinitialize_components }\n\n```python\nSpotOptim.SpotOptim.reinitialize_components()\n```\n\nReinitialize components that were excluded during pickling.\n\n### remove_nan { #spotoptim.SpotOptim.SpotOptim.remove_nan }\n\n```python\nSpotOptim.SpotOptim.remove_nan(X, y, stop_on_zero_return=True)\n```\n\nRemove rows where y contains NaN or inf values.\nUsed in the optimize() method after function evaluations.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|---------------------|----------------------|---------------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Design matrix, shape (n_samples, n_features). | _required_ |\n| y | [ndarray](`ndarray`) | Objective values, shape (n_samples,). | _required_ |\n| stop_on_zero_return | [bool](`bool`) | If True, raise error when all values are removed. | `True` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|------------------|-----------------------------------------------|\n| tuple | [tuple](`tuple`) | (X_clean, y_clean) with NaN/inf rows removed. |\n\n#### Raises {.doc-section .doc-section-raises}\n\n| Name | Type | Description |\n|--------|----------------------------|------------------------------------------------------------|\n| | [ValueError](`ValueError`) | If all values are NaN/inf and stop_on_zero_return is True. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#b5e217b7 .cell execution_count=61}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nopt = SpotOptim(fun=sphere, bounds=[(-5, 5)])\nX = np.array([[1, 2], [3, 4], [5, 6]])\ny = np.array([1.0, np.nan, np.inf])\nX_clean, y_clean = opt.remove_nan(X, y, stop_on_zero_return=False)\nprint(\"Clean X:\", X_clean)\nprint(\"Clean y:\", y_clean)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nClean X: [[1 2]]\nClean y: [1.]\n```\n:::\n:::\n\n\n### repair_natural_X { #spotoptim.SpotOptim.SpotOptim.repair_natural_X }\n\n```python\nSpotOptim.SpotOptim.repair_natural_X(X)\n```\n\nEnforce integrality and declared bounds in natural (original) space.\n\nInteger dimensions are rounded to the nearest integer; integer\ndimensions with an active transform are additionally clipped to their\ndeclared natural bounds, because the inverse transform of a continuous\ninternal proposal can land marginally outside them (issue #87). Float\nand factor dimensions pass through unchanged.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|--------------------------------------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Points in natural scale, shape (n_samples, n_features) or (n_features,). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|---------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Repaired copy of ``X`` (same shape as the input). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#c30bfcf9 .cell execution_count=62}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(10, 5000)],\n var_type=['int'],\n var_trans=['log10'])\nX_nat = np.array([[4999.99999], [10.4], [5000.2]])\nprint(opt.repair_natural_X(X_nat))\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[[5000.]\n [ 10.]\n [5000.]]\n```\n:::\n:::\n\n\n### repair_non_numeric { #spotoptim.SpotOptim.SpotOptim.repair_non_numeric }\n\n```python\nSpotOptim.SpotOptim.repair_non_numeric(X, var_type)\n```\n\nRound non-numeric values to integers based on variable type.\nThis method applies rounding to variables that are not continuous:\n * 'float': No rounding (continuous values)\n * 'int': Rounded to integers\n * 'factor': Rounded to integers (representing categorical values)\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|----------|----------------------|------------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | X array with values to potentially round. | _required_ |\n| var_type | list of str | List with type information for each dimension. | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|---------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | X array with non-continuous values rounded to integers. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#97636316 .cell execution_count=63}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n var_type=['int', 'float'])\nX = np.array([[1.2, 2.5], [3.7, 4.1], [5.9, 6.8]])\nX_repaired = opt.repair_non_numeric(X, opt.var_type)\nprint(X_repaired)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[[1. 2.5]\n [4. 4.1]\n [6. 6.8]]\n```\n:::\n:::\n\n\n### rm_initial_design_NA_values { #spotoptim.SpotOptim.SpotOptim.rm_initial_design_NA_values }\n\n```python\nSpotOptim.SpotOptim.rm_initial_design_NA_values(X0, y0)\n```\n\nRemove NaN/inf values from initial design evaluations.\nThis method filters out design points that returned NaN or inf values\nduring initial evaluation. Unlike the sequential optimization phase where\npenalties are applied, initial design points with invalid values are\nsimply removed.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-------------------------------------------------------------------------|------------|\n| X0 | [ndarray](`ndarray`) | Initial design points in internal scale, shape (n_samples, n_features). | _required_ |\n| y0 | [ndarray](`ndarray`) | Function values at X0, shape (n_samples,). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|-----------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| | [Tuple](`typing.Tuple`)\\[[np](`numpy`).[ndarray](`numpy.ndarray`), [np](`numpy`).[ndarray](`numpy.ndarray`), [int](`int`)\\] | Tuple[ndarray, ndarray, int]: Filtered (X0, y0) with only finite values and the original count before filtering. X0 has shape (n_valid, n_features), y0 has shape (n_valid,), and the int is the original size. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#d95a9132 .cell execution_count=64}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=10\n)\nX0 = np.array([[1, 2], [3, 4], [5, 6]])\ny0 = np.array([5.0, np.nan, np.inf])\nX0_clean, y0_clean, n_eval = opt.rm_initial_design_NA_values(X0, y0)\nprint(X0_clean.shape) # (1, 2)\nprint(y0_clean) # array([5.])\nprint(n_eval) # 3\n# All valid values - no filtering\nX0 = np.array([[1, 2], [3, 4]])\ny0 = np.array([5.0, 25.0])\nX0_clean, y0_clean, n_eval = opt.rm_initial_design_NA_values(X0, y0)\nprint(X0_clean.shape) # (2, 2)\nprint(n_eval) # 2\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n(1, 2)\n[5.]\n3\n(2, 2)\n2\n```\n:::\n:::\n\n\n### save_experiment { #spotoptim.SpotOptim.SpotOptim.save_experiment }\n\n```python\nSpotOptim.SpotOptim.save_experiment(\n filename=None,\n prefix='experiment',\n path=None,\n overwrite=True,\n unpickleables='all',\n verbosity=0,\n)\n```\n\nSave experiment configuration to a pickle file.\n\n### save_result { #spotoptim.SpotOptim.SpotOptim.save_result }\n\n```python\nSpotOptim.SpotOptim.save_result(\n filename=None,\n prefix='result',\n path=None,\n overwrite=True,\n verbosity=0,\n)\n```\n\nSave complete optimization results to a pickle file.\n\n### select_new { #spotoptim.SpotOptim.SpotOptim.select_new }\n\n```python\nSpotOptim.SpotOptim.select_new(A, X, tolerance=0)\n```\n\nSelect rows from A that are not in X.\nUsed in suggest_next_infill_point() to avoid duplicate evaluations.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|-----------|----------------------|------------------------------------------------|------------|\n| A | [ndarray](`ndarray`) | Array with new values. | _required_ |\n| X | [ndarray](`ndarray`) | Array with known values. | _required_ |\n| tolerance | [float](`float`) | Tolerance value for comparison. Defaults to 0. | `0` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|---------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|\n| tuple | [Tuple](`typing.Tuple`)\\[[np](`numpy`).[ndarray](`numpy.ndarray`), [np](`numpy`).[ndarray](`numpy.ndarray`)\\] | A tuple containing: * ndarray: Array with unknown (new) values. * ndarray: Array with True if value is new, otherwise False. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#09472aea .cell execution_count=65}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\ndef sphere(X):\n X = np.atleast_2d(X)\n return np.sum(X**2, axis=1)\nopt = SpotOptim(fun=sphere, bounds=[(-5, 5)])\nA = np.array([[1, 2], [3, 4], [5, 6]])\nX = np.array([[3, 4], [7, 8]])\nnew_A, is_new = opt.select_new(A, X)\nprint(\"New A:\", new_A)\nprint(\"Is new:\", is_new)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nNew A: [[1 2]\n [5 6]]\nIs new: [ True False True]\n```\n:::\n:::\n\n\n### sensitivity_spearman { #spotoptim.SpotOptim.SpotOptim.sensitivity_spearman }\n\n```python\nSpotOptim.SpotOptim.sensitivity_spearman()\n```\n\nCompute and print Spearman correlation between parameters and objective values.\nThis method analyzes the sensitivity of the objective function to each\nhyperparameter by computing Spearman rank correlations. For categorical\n(factor) variables, correlation is not computed as they require visual\ninspection instead.\nThe method automatically handles different parameter types:\n * Integer/float parameters: Direct correlation with objective values\n * Log-transformed parameters (log10, log, ln): Correlation in log-space\n * Factor (categorical) parameters: Skipped with informative message\nSignificance levels:\n * ***: p < 0.001 (highly significant)\n * **: p < 0.01 (significant)\n * *: p < 0.05 (marginally significant)\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#45356c33 .cell execution_count=66}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nimport numpy as np\n\ndef test_func(X):\n # x0 has strong effect, x1 has weak effect\n X = np.atleast_2d(X)\n return 10 * X[:, 0]**2 + 0.1 * X[:, 1]**2\n\nopt = SpotOptim(\n fun=test_func,\n bounds=[(-5, 5), (-5, 5)],\n var_name=[\"x0\", \"x1\"],\n max_iter=10,\n n_initial=5,\n seed=42\n)\nopt.optimize()\nopt.sensitivity_spearman()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n\nSensitivity Analysis (Spearman Correlation):\n--------------------------------------------------\n x0 : -0.188 (p=0.603)\n x1 : -0.297 (p=0.405)\n```\n:::\n:::\n\n\n#### Note {.doc-section .doc-section-note}\n\nOnly meaningful after optimize() has been called with sufficient evaluations.\n\n### set_seed { #spotoptim.SpotOptim.SpotOptim.set_seed }\n\n```python\nSpotOptim.SpotOptim.set_seed()\n```\n\nSet global random seeds for reproducibility.\nSets seeds for:\n * random\n * numpy.random\n * torch (cpu and cuda)\nOnly performs actions if self.seed is not None.\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#b6262867 .cell execution_count=67}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nimport numpy as np\nspot = SpotOptim(fun=lambda x: x, bounds=[(0, 1)], seed=42)\nspot.set_seed()\nnp.random.rand() # Should be deterministic\n```\n\n::: {.cell-output .cell-output-display execution_count=67}\n```\n0.3745401188473625\n```\n:::\n:::\n\n\n### setup_dimension_reduction { #spotoptim.SpotOptim.SpotOptim.setup_dimension_reduction }\n\n```python\nSpotOptim.SpotOptim.setup_dimension_reduction()\n```\n\nSet up dimension reduction by identifying fixed dimensions.\nIdentifies dimensions where lower and upper bounds are equal in Transformed Space.\nReduces `self.bounds`, `self.lower`, `self.upper`, etc., to the Mapped Space\n(active variables only).\nThe resulting `self.bounds` defines the Transformed and Mapped Space used\nfor optimization.\nThis method identifies variables that are fixed (constant) and excludes them\nfrom the optimization process. It stores:\n * Original bounds and metadata in `all_*` attributes\n * Boolean mask of fixed dimensions in `ident`\n * Reduced bounds, types, and names for optimization\n * `red_dim` flag indicating if reduction occurred\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#158630f9 .cell execution_count=68}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nspot = SpotOptim(fun=lambda x: x, bounds=[(1, 10), (5, 5), (0, 1)])\nprint(\"Original lower bounds:\", spot.all_lower)\nprint(\"Original upper bounds:\", spot.all_upper)\nprint(\"Fixed dimensions mask:\", spot.ident)\nprint(\"Reduced lower bounds:\", spot.lower)\nprint(\"Reduced upper bounds:\", spot.upper)\nprint(\"Reduced variable names:\", spot.var_name)\nprint(\"Is dimension reduction active?\", spot.red_dim)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nOriginal lower bounds: [1. 5. 0.]\nOriginal upper bounds: [10. 5. 1.]\nFixed dimensions mask: [False True False]\nReduced lower bounds: [1. 0.]\nReduced upper bounds: [10. 1.]\nReduced variable names: ['x0', 'x2']\nIs dimension reduction active? True\n```\n:::\n:::\n\n\n### store_mo { #spotoptim.SpotOptim.SpotOptim.store_mo }\n\n```python\nSpotOptim.SpotOptim.store_mo(y_mo)\n```\n\nStore multi-objective values in self.y_mo.\nIf multi-objective values are present (ndim==2), they are stored in self.y_mo.\nNew values are appended to existing ones. For single-objective problems,\nself.y_mo remains None.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|----------------------------------------------------------------------------------------------------------|------------|\n| y_mo | [ndarray](`ndarray`) | If multi-objective, shape (n_samples, n_objectives). If single-objective, shape (n_samples,). | _required_ |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#e8dd2be1 .cell execution_count=69}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(\n fun=lambda X: np.column_stack([\n np.sum(X**2, axis=1),\n np.sum((X-1)**2, axis=1)\n ]),\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10,\n n_initial=5\n)\ny_mo_1 = np.array([[1.0, 2.0], [3.0, 4.0]])\nopt.store_mo(y_mo_1)\nprint(f\"y_mo after first call: {opt.y_mo}\")\ny_mo_2 = np.array([[5.0, 6.0], [7.0, 8.0]])\nopt.store_mo(y_mo_2)\nprint(f\"y_mo after second call: {opt.y_mo}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\ny_mo after first call: [[1. 2.]\n [3. 4.]]\ny_mo after second call: [[1. 2.]\n [3. 4.]\n [5. 6.]\n [7. 8.]]\n```\n:::\n:::\n\n\n### suggest_next_infill_point { #spotoptim.SpotOptim.SpotOptim.suggest_next_infill_point }\n\n```python\nSpotOptim.SpotOptim.suggest_next_infill_point()\n```\n\nSuggest next point to evaluate (dispatcher).\nUsed in both sequential and parallel optimization loops. This method orchestrates\nthe process of generating candidate points from the acquisition function optimizer,\nhandling any failures in the acquisition process with a fallback strategy, and\nensuring that the returned point(s) are valid and ready for evaluation.\nThe returned point is in the Transformed and Mapped Space (Internal Optimization Space).\nThis means:\n 1. Transformations (e.g., log, sqrt) have been applied.\n 2. Dimension reduction has been applied (fixed variables removed).\nProcess:\n 1. Try candidates from acquisition function optimizer.\n 2. Handle acquisition failure (fallback).\n 3. Return last attempt if all fails.\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|------------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Next point(s) to evaluate in Transformed and Mapped Space. |\n| | [np](`numpy`).[ndarray](`numpy.ndarray`) | Shape is (n_infill_points, n_features). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#dcd65ad6 .cell execution_count=70}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\ndef sphere(X):\n X = np.atleast_2d(X)\n return np.sum(X**2, axis=1)\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n n_infill_points=2\n)\n# Need to initialize optimization state (X_, y_, surrogate)\n# Normally done inside optimize()\nnp.random.seed(0)\nopt.X_ = np.random.rand(10, 2)\nopt.y_ = np.random.rand(10)\nopt.fit_surrogate(opt.X_, opt.y_)\nx_next = opt.suggest_next_infill_point()\nx_next.shape\n```\n\n::: {.cell-output .cell-output-display execution_count=70}\n```\n(2, 2)\n```\n:::\n:::\n\n\n### to_all_dim { #spotoptim.SpotOptim.SpotOptim.to_all_dim }\n\n```python\nSpotOptim.SpotOptim.to_all_dim(X_red)\n```\n\nExpand reduced-dimensional points to full-dimensional representation.\nThis method restores points from the reduced optimization space to the\nfull-dimensional space by inserting fixed values for constant dimensions.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-------------------------------------------------------------|------------|\n| X_red | [ndarray](`ndarray`) | Points in reduced space, shape (n_samples, n_reduced_dims). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|-----------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Points in full space, shape (n_samples, n_original_dims). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#353b240c .cell execution_count=71}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\ndef sphere(X):\n X = np.atleast_2d(X)\n return np.sum(X**2, axis=1)\n# Create problem with one fixed dimension\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (2, 2), (-5, 5)], # x1 is fixed at 2\n max_iter=10,\n n_initial=3\n)\nX_red = np.array([[1.0, 3.0], [2.0, 4.0]]) # Only x0 and x2\nX_full = opt.to_all_dim(X_red)\nprint(X_full.shape)\nprint(X_full[:, 1])\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n(2, 3)\n[2. 2.]\n```\n:::\n:::\n\n\n### to_red_dim { #spotoptim.SpotOptim.SpotOptim.to_red_dim }\n\n```python\nSpotOptim.SpotOptim.to_red_dim(X_full)\n```\n\nReduce full-dimensional points to optimization space.\nThis method removes fixed dimensions from full-dimensional points,\nextracting only the varying dimensions used in optimization.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-----------------------------------------------------------|------------|\n| X_full | [ndarray](`ndarray`) | Points in full space, shape (n_samples, n_original_dims). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|-------------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Points in reduced space, shape (n_samples, n_reduced_dims). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#5aa97d49 .cell execution_count=72}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\ndef sphere(X):\n X = np.atleast_2d(X)\n return np.sum(X**2, axis=1)\n# Create problem with one fixed dimension\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (2, 2), (-5, 5)], # x1 is fixed at 2\n max_iter=10,\n n_initial=3\n)\nX_full = np.array([[1.0, 2.0, 3.0], [4.0, 2.0, 5.0]])\nX_red = opt.to_red_dim(X_full)\nprint(X_red.shape)\nprint(np.array_equal(X_red, np.array([[1.0, 3.0], [4.0, 5.0]])))\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n(2, 2)\nTrue\n```\n:::\n:::\n\n\n### transform_X { #spotoptim.SpotOptim.SpotOptim.transform_X }\n\n```python\nSpotOptim.SpotOptim.transform_X(X)\n```\n\nTransform parameter array from original (natural) to internal scale.\nConverts from natural space (Original) to transformed space (full dimension).\nDoes NOT handle dimension reduction (mapping).\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-------------------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Array in Natural Space, shape (n_samples, n_features) | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|---------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Array in Transformed Space (Full Dimension) |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#ee9877f0 .cell execution_count=73}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nimport numpy as np\nfrom spotoptim.function import sphere\nspot = SpotOptim(fun=sphere, bounds=[(1, 10)], var_trans=['log10'])\nX_orig = np.array([[1], [10], [100]])\nspot.transform_X(X_orig)\n```\n\n::: {.cell-output .cell-output-display execution_count=73}\n```\narray([[0],\n [1],\n [2]])\n```\n:::\n:::\n\n\n### transform_bounds { #spotoptim.SpotOptim.SpotOptim.transform_bounds }\n\n```python\nSpotOptim.SpotOptim.transform_bounds()\n```\n\nTransform bounds from original to internal scale.\nUpdates `self.bounds` (and `self.lower`, `self.upper`) from Natural Space\nto Transformed Space. Calls `transform_value` for each bound and converts\nnumpy types to Python native types (`int` or `float` based on `var_type`).\nHandles also reversed bounds, e.g., as an effect of `reciprocal` transformation.\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Notes {.doc-section .doc-section-notes}\n\nUses settings in `self.var_trans`. It can be one of `id`, `log10`, `log`, `ln`, `sqrt`,\n`exp`, `square`, `cube`, `inv`, `reciprocal`, or `None`. Also supports dynamic\nstrings like `log(x)`, `sqrt(x)`, `pow(x, p)`.\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#40bdd609 .cell execution_count=74}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nimport numpy as np\nspot = SpotOptim(fun=sphere, bounds=[(1, 10), (0.1, 100)])\nspot.var_trans = ['log10', 'sqrt']\nspot.transform_bounds()\nprint(f\"spot.bounds: {spot.bounds}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nspot.bounds: [(0.0, 1.0), (0.31622776601683794, 10.0)]\n```\n:::\n:::\n\n\n### transform_value { #spotoptim.SpotOptim.SpotOptim.transform_value }\n\n```python\nSpotOptim.SpotOptim.transform_value(x, trans)\n```\n\nApply transformation to a single float value.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|-----------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|\n| x | [float](`float`) | Value to transform | _required_ |\n| trans | [Optional](`typing.Optional`)\\[[str](`str`)\\] | Transformation name. Can be one of `id`, `log10`, `log`, `ln`, `sqrt`, `exp`, `square`, `cube`, `inv`, `reciprocal`, or `None`. Also supports dynamic strings like `log(x)`, `sqrt(x)`, `pow(x, p)`. | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|------------------|-------------------|\n| | [float](`float`) | Transformed value |\n\n#### Raises {.doc-section .doc-section-raises}\n\n| Name | Type | Description |\n|--------|----------------------------|--------------------------------------------|\n| | [TypeError](`TypeError`) | If x is not a float. |\n| | [ValueError](`ValueError`) | If an unknown transformation is specified. |\n\n#### Notes {.doc-section .doc-section-notes}\n\nSee also inverse_transform_value.\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#92d4a0ed .cell execution_count=75}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nspot = SpotOptim(fun=sphere, bounds=[(1, 10)])\nspot.transform_value(10, 'log10')\nspot.transform_value(100, 'log(x)')\n```\n\n::: {.cell-output .cell-output-display execution_count=75}\n```\nnp.float64(4.605170185988092)\n```\n:::\n:::\n\n\n### update_repeats_infill_points { #spotoptim.SpotOptim.SpotOptim.update_repeats_infill_points }\n\n```python\nSpotOptim.SpotOptim.update_repeats_infill_points(x_next)\n```\n\nRepeat infill point for noisy function evaluation. Used in the sequential_loop.\nFor noisy objective functions (repeats_surrogate > 1), creates multiple\ncopies of the suggested point for repeated evaluation. Otherwise, returns\nthe point in 2D array format.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|----------------------------------------------|------------|\n| x_next | [ndarray](`ndarray`) | Next point to evaluate, shape (n_features,). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|---------------------------------------------------------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Points to evaluate, shape (repeats_surrogate, n_features) or (1, n_features) if repeats_surrogate == 1. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#c3d09cef .cell execution_count=76}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere, noisy_sphere\n# Without repeats\n\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n repeats_surrogate=1\n)\nx_next = np.array([1.0, 2.0])\nx_repeated = opt.update_repeats_infill_points(x_next)\nprint(x_repeated.shape)\n\n# With repeats for noisy function\nopt_noisy = SpotOptim(\n fun=noisy_sphere,\n bounds=[(-5, 5), (-5, 5)],\n repeats_surrogate=3\n)\nx_next = np.array([1.0, 2.0])\nx_repeated = opt_noisy.update_repeats_infill_points(x_next)\nprint(x_repeated.shape)\n# All three copies should be identical\nnp.all(x_repeated[0] == x_repeated[1])\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n(1, 2)\n(3, 2)\n```\n:::\n\n::: {.cell-output .cell-output-display execution_count=76}\n```\nnp.True_\n```\n:::\n:::\n\n\n### update_stats { #spotoptim.SpotOptim.SpotOptim.update_stats }\n\n```python\nSpotOptim.SpotOptim.update_stats()\n```\n\nUpdate optimization statistics.\nUpdates various statistics related to the optimization progress:\n * `min_y`: Minimum y value found so far\n * `min_X`: X value corresponding to minimum y\n * `counter`: Total number of function evaluations\n\n#### Notes {.doc-section .doc-section-notes}\n\n`success_rate` is updated separately via `update_success_rate()` method, which is called after each batch of function evaluations.\n\nIf \"noise\" is True (`repeats_initial > 1` or `repeats_surrogate > 1`), additionally computes:\n * `mean_X`: Unique design points (aggregated from repeated evaluations)\n * `mean_y`: Mean y values per design point\n * `var_y`: Variance of y values per design point\n * `min_mean_X`: X value of the best mean y value\n * `min_mean_y`: Best mean y value\n * `min_var_y`: Variance of the best mean y value\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#17d91600 .cell execution_count=77}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\n# Without noise\nopt = SpotOptim(fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10, n_initial=5)\nopt.optimize()\nprint(\"SpotOptim stats without noise:\")\nprint(f\"opt.X_: {opt.X_}\")\nprint(f\"opt.y_: {opt.y_}\")\nprint(f\"opt.min_y: {opt.min_y}\")\nprint(f\"opt.min_X: {opt.min_X}\")\nprint(f\"opt.counter: {opt.counter}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nSpotOptim stats without noise:\nopt.X_: [[ 4.31661406 -2.98706752]\n [ 0.28684864 3.92905185]\n [ 1.97317349 -3.70660092]\n [-2.41473188 0.16632017]\n [-4.10634486 1.16610501]\n [ 4.37586785 1.41894113]\n [ 2.8253474 3.87008318]\n [-2.41474188 0.16632604]\n [-2.25660285 0.07542405]\n [-1.72444053 -0.28778632]]\nopt.y_: [27.55572928 15.51973059 17.63230402 5.85859245 18.22186903 21.16161338\n 22.96013178 5.85864268 5.09794521 3.05651611]\nopt.min_y: 3.056516107962276\nopt.min_X: [-1.72444053 -0.28778632]\nopt.counter: 10\n```\n:::\n:::\n\n\n::: {#db82ef81 .cell execution_count=78}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import noisy_sphere\n# With noise\nopt_noise = SpotOptim(fun=noisy_sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n repeats_surrogate=2,\n repeats_initial=2)\nopt_noise.optimize()\nprint(\"SpotOptim stats with noise:\")\nprint(f\"opt_noise.X_: {opt_noise.X_}\")\nprint(f\"opt_noise.y_: {opt_noise.y_}\")\nprint(f\"opt_noise.min_y: {opt_noise.min_y}\")\nprint(f\"opt_noise.min_X: {opt_noise.min_X}\")\nprint(f\"opt_noise.counter: {opt_noise.counter}\")\nprint(f\"opt_noise.mean_X: {opt_noise.mean_X}\")\nprint(f\"opt_noise.mean_y: {opt_noise.mean_y}\")\nprint(f\"opt_noise.var_y: {opt_noise.var_y}\")\nprint(f\"opt_noise.min_mean_X: {opt_noise.min_mean_X}\")\nprint(f\"opt_noise.min_mean_y: {opt_noise.min_mean_y}\")\nprint(f\"opt_noise.min_var_y: {opt_noise.min_var_y}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nSpotOptim stats with noise:\nopt_noise.X_: [[-4.34670042 -4.29344041]\n [-4.34670042 -4.29344041]\n [ 0.59785002 1.78569096]\n [ 0.59785002 1.78569096]\n [ 1.37986219 -1.61587239]\n [ 1.37986219 -1.61587239]\n [ 3.30811094 4.61751022]\n [ 3.30811094 4.61751022]\n [-2.76668523 0.9968025 ]\n [-2.76668523 0.9968025 ]\n [ 0.34674766 1.08969718]\n [ 0.34674766 1.08969718]\n [ 0.29133996 0.60430193]\n [ 0.29133996 0.60430193]\n [ 0.379487 0.07398903]\n [ 0.379487 0.07398903]\n [ 0.24675965 0.11214783]\n [ 0.24675965 0.11214783]\n [ 0.43014284 0.12837287]\n [ 0.43014284 0.12837287]]\nopt_noise.y_: [ 3.72962376e+01 3.72434061e+01 3.44543366e+00 3.71427451e+00\n 4.43583457e+00 4.46190265e+00 3.23015835e+01 3.23947812e+01\n 8.69627390e+00 8.92409790e+00 1.43441505e+00 1.35762371e+00\n 3.91136895e-01 4.05213293e-01 1.04608058e-01 -2.49340162e-02\n 1.58520530e-01 -1.04449578e-02 1.04385392e-01 3.44134144e-01]\nopt_noise.min_y: -0.024934016181757196\nopt_noise.min_X: [0.379487 0.07398903]\nopt_noise.counter: 20\nopt_noise.mean_X: [[-4.34670042 -4.29344041]\n [-2.76668523 0.9968025 ]\n [ 0.24675965 0.11214783]\n [ 0.29133996 0.60430193]\n [ 0.34674766 1.08969718]\n [ 0.379487 0.07398903]\n [ 0.43014284 0.12837287]\n [ 0.59785002 1.78569096]\n [ 1.37986219 -1.61587239]\n [ 3.30811094 4.61751022]]\nopt_noise.mean_y: [37.26982184 8.8101859 0.07403779 0.39817509 1.39601938 0.03983702\n 0.22425977 3.57985409 4.44886861 32.34818235]\nopt_noise.var_y: [6.97789966e-04 1.29759436e-02 7.13733398e-03 4.95362454e-05\n 1.47422756e-03 4.19528726e-03 1.43698661e-02 1.80688502e-02\n 1.69886138e-04 2.17145039e-03]\nopt_noise.min_mean_X: [0.379487 0.07398903]\nopt_noise.min_mean_y: 0.03983702099066562\nopt_noise.min_var_y: 0.004195287256391378\n```\n:::\n:::\n\n\n### update_storage { #spotoptim.SpotOptim.SpotOptim.update_storage }\n\n```python\nSpotOptim.SpotOptim.update_storage(X_new, y_new)\n```\n\nUpdate storage (`X_`, `y_`) with new evaluation points.\nAppends new design points and their function values to the storage arrays.\nPoints are converted from internal scale to original scale before storage.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-----------------------------------------------------------------|------------|\n| X_new | [ndarray](`ndarray`) | New design points in internal scale, shape (n_new, n_features). | _required_ |\n| y_new | [ndarray](`ndarray`) | Function values at X_new, shape (n_new,). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#36a79315 .cell execution_count=79}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5)\n# Initialize with some data\nopt.X_ = np.array([[1, 2], [3, 4]])\nopt.y_ = np.array([5.0, 25.0])\nprint(\"Initial storage:\")\nprint(opt.X_)\nprint(opt.y_)\n# Add new points\nX_new = np.array([[0, 1], [2, 3]])\ny_new = np.array([1.0, 13.0])\nopt.update_storage(X_new, y_new)\nprint(\"Updated storage:\")\nprint(opt.X_)\nprint(opt.y_)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nInitial storage:\n[[1 2]\n [3 4]]\n[ 5. 25.]\nUpdated storage:\n[[1. 2.]\n [3. 4.]\n [0. 1.]\n [2. 3.]]\n[ 5. 25. 1. 13.]\n```\n:::\n:::\n\n\n### update_success_rate { #spotoptim.SpotOptim.SpotOptim.update_success_rate }\n\n```python\nSpotOptim.SpotOptim.update_success_rate(y_new)\n```\n\nUpdate the rolling success rate of the optimization process.\nA success is counted only if the new value is better (smaller) than the best\nfound y value so far. The success rate is calculated based on the last\n`window_size` successes.\nImportant: This method should be called BEFORE updating self.y_ to correctly\ntrack improvements against the previous best value.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|------------------------------------------------------------------|------------|\n| y_new | [ndarray](`ndarray`) | The new function values to consider for the success rate update. | _required_ |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#f21a2f16 .cell execution_count=80}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10, n_initial=5)\nprint(opt.success_rate)\nopt.X_ = np.array([[1, 2], [3, 4], [0, 1]])\nopt.y_ = np.array([5.0, 3.0, 2.0])\nopt.update_success_rate(np.array([1.5, 2.5]))\nprint(opt.success_rate)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n0.0\n0.5\n```\n:::\n:::\n\n\n### validate_x0 { #spotoptim.SpotOptim.SpotOptim.validate_x0 }\n\n```python\nSpotOptim.SpotOptim.validate_x0(x0)\n```\n\nValidate and process starting point x0. Called in `__init__` and `optimize`.\nThis method checks that x0:\n * Is a numpy array\n * Has the correct number of dimensions\n * Has values within bounds (in original scale)\n * Is properly transformed to internal scale\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|-----------------------------------|----------------------------------|------------|\n| x0 | [array](`array`) - [like](`like`) | Starting point in original scale | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|---------------------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Validated and transformed x0 in internal scale, shape (n_features,) |\n\n#### Raises {.doc-section .doc-section-raises}\n\n| Name | Type | Description |\n|--------|----------------------------|------------------|\n| | [ValueError](`ValueError`) | If x0 is invalid |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#80a0f6a1 .cell execution_count=81}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (5,5), (-10, 10)],\n x0=np.array([1.0, 5.0, 9.0]),\n var_trans=[\"log10\", \"id\", \"sqrt\"]\n)\n# x0 is validated during initialization and transformed to internal scale\nprint(f\"x0 in internal scale: {opt.x0}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nx0 in internal scale: [0. 3.]\n```\n:::\n:::\n\n\n", + "markdown": "---\ntitle: SpotOptim.SpotOptim\n---\n\n\n\n```python\nSpotOptim.SpotOptim(\n fun,\n bounds=None,\n max_iter=20,\n n_initial=10,\n surrogate=None,\n acquisition='y',\n var_type=None,\n var_name=None,\n var_trans=None,\n tolerance_x=None,\n max_time=np.inf,\n repeats_initial=1,\n repeats_surrogate=1,\n ocba_delta=0,\n tensorboard_log=False,\n tensorboard_path=None,\n tensorboard_clean=False,\n fun_mo2so=None,\n seed=None,\n verbose=False,\n warnings_filter='ignore',\n n_infill_points=1,\n max_surrogate_points=30,\n selection_method='distant',\n acquisition_failure_strategy='random',\n penalty=False,\n penalty_val=None,\n acquisition_fun_return_size=3,\n acquisition_optimizer='differential_evolution',\n restart_after_n=100,\n restart_inject_best=True,\n max_restarts=None,\n x0=None,\n de_x0_prob=0.1,\n tricands_fringe=False,\n prob_de_tricands=0.8,\n window_size=None,\n min_tol_metric='chebyshev',\n prob_surrogate=None,\n acquisition_optimizer_kwargs=None,\n args=(),\n kwargs=None,\n)\n```\n\nSPOT optimizer compatible with scipy.optimize interface.\n\n## Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|------------------------------|-------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------|\n| fun | [callable](`callable`) | Objective function to minimize. Should accept array of shape (n_samples, n_features). | _required_ |\n| bounds | list of tuple | Bounds for each dimension as [(low, high), ...]. | `None` |\n| max_iter | [int](`int`) | Maximum number of total function evaluations (including initial design). For example, max_iter=30 with n_initial=10 will perform 10 initial evaluations plus 20 sequential optimization iterations. Defaults to 20. | `20` |\n| n_initial | [int](`int`) | Number of initial design points. Defaults to 10. | `10` |\n| surrogate | [object](`object`) | Surrogate model with scikit-learn interface (fit/predict methods). If None, uses a Gaussian Process Regressor with Matern kernel. Default configuration:: * `from sklearn.gaussian_process import GaussianProcessRegressor` * `from sklearn.gaussian_process.kernels import Matern, ConstantKernel` * `kernel = ConstantKernel(1.0, (1e-2, 1e12)) * Matern(length_scale=1.0, length_scale_bounds=(1e-4, 1e2), nu=2.5)` * `surrogate = GaussianProcessRegressor(kernel=kernel, n_restarts_optimizer=100)` Alternative surrogates can be provided, including SpotOptim's Kriging model, Random Forests, or any scikit-learn compatible regressor. See Examples section. Defaults to None (uses default Gaussian Process configuration). | `None` |\n| acquisition | [str](`str`) | Acquisition function ('ei', 'y', 'pi'). Defaults to 'y'. | `'y'` |\n| var_type | list of str | Variable types for each dimension. Supported types: * 'float': Python floats, continuous optimization (no rounding) * 'int': Python int, float values will be rounded to integers * 'factor': Unordered categorical data, internally mapped to int values (e.g., \"red\"->0, \"green\"->1, etc.) Defaults to None (which sets all dimensions to 'float'). | `None` |\n| var_name | list of str | Variable names for each dimension. If None, uses default names ['x0', 'x1', 'x2', ...]. Defaults to None. | `None` |\n| tolerance_x | [float](`float`) | Minimum distance between points. Defaults to np.sqrt(np.spacing(1)) | `None` |\n| var_trans | list of str | Variable transformations for each dimension. Supported: It can be one of `id`, `log10`, `log`, `ln`, `sqrt`, `exp`, `square`, `cube`, `inv`, `reciprocal`, or `None`. Also supports dynamic strings like `log(x)`, `sqrt(x)`, `pow(x, p)`. Defaults to None (no transformations). | `None` |\n| max_time | [float](`float`) | Maximum runtime in minutes. If np.inf (default), no time limit. The optimization terminates when either max_iter evaluations are reached OR max_time minutes have elapsed, whichever comes first. Defaults to np.inf. | `np.inf` |\n| repeats_initial | [int](`int`) | Number of times to evaluate each initial design point. Useful for noisy objective functions. If > 1, noise handling is activated and statistics (mean, variance) are tracked. Defaults to 1. | `1` |\n| repeats_surrogate | [int](`int`) | Number of times to evaluate each surrogate-suggested point. Useful for noisy objective functions. If > 1, noise handling is activated and statistics (mean, variance) are tracked. Defaults to 1. | `1` |\n| ocba_delta | [int](`int`) | Number of additional evaluations to allocate using Optimal Computing Budget Allocation (OCBA) when noise handling is active. OCBA determines which existing design points should be re-evaluated to best distinguish between alternatives. Only used when repeats_surrogate > 1 and ocba_delta > 0. Requires at least 3 design points with variance information. Defaults to 0 (no OCBA). | `0` |\n| tensorboard_log | [bool](`bool`) | Enable TensorBoard logging. If True, optimization metrics and hyperparameters are logged to TensorBoard. View logs by running: `tensorboard --logdir=` in a separate terminal. Defaults to False. | `False` |\n| tensorboard_path | [str](`str`) | Path for TensorBoard log files. If None and tensorboard_log is True, creates a default path: runs/spotoptim_YYYYMMDD_HHMMSS. Defaults to None. | `None` |\n| tensorboard_clean | [bool](`bool`) | If True, removes old TensorBoard logs before starting optimization so every run begins with a fresh dashboard. With tensorboard_path set, the configured directory itself is removed (and re-created empty by the writer); without a path, all subdirectories of the default 'runs' folder are removed. Use with caution as this permanently deletes the affected log directories. Defaults to False. | `False` |\n| fun_mo2so | [callable](`callable`) | Function to convert multi-objective values to single-objective. Takes an array of shape (n_samples, n_objectives) and returns array of shape (n_samples,). If None and objective function returns multi-objective values, uses first objective. Defaults to None. | `None` |\n| seed | [int](`int`) | Random seed for reproducibility. Defaults to None. | `None` |\n| verbose | [bool](`bool`) | Print progress information. Defaults to False. | `False` |\n| warnings_filter | [Literal](`typing.Literal`)\\[\\'default\\', \\'error\\', \\'ignore\\'\\] | Filter for warnings. One of \"error\", \"ignore\", \"always\", \"all\", \"default\", \"module\", or \"once\". Defaults to \"ignore\". | `'ignore'` |\n| n_infill_points | [int](`int`) | Number of infill points to suggest at each iteration. Defaults to 1. If > 1, multiple distinct points are proposed using the optimizer and fallback strategies. | `1` |\n| max_surrogate_points | [int](`int`) | Maximum number of points to use for surrogate model fitting. If None, all points are used. If the number of evaluated points exceeds this limit, a subset is selected using the selection method. Defaults to 30. | `30` |\n| selection_method | [str](`str`) | Method for selecting points when max_surrogate_points is exceeded. Options: 'distant' (Select points that are distant from each other via K-means clustering) or 'best' (Select all points from the cluster with the best mean objective value). Defaults to 'distant'. | `'distant'` |\n| acquisition_failure_strategy | [str](`str`) | Strategy for handling acquisition function failures. Options: 'random' (space-filling design via Latin Hypercube Sampling) Defaults to 'random'. | `'random'` |\n| penalty | [bool](`bool`) | Whether to use penalty for handling NaN/inf values in objective function evaluations. Defaults to False. | `False` |\n| penalty_val | [float](`float`) | Penalty value to replace NaN/inf values in objective function evaluations. When the objective function returns NaN or inf, these values are replaced with penalty plus a small random noise (sampled from N(0, 0.1)) to avoid identical penalty values. This allows optimization to continue despite occasional function evaluation failures. Defaults to None. | `None` |\n| acquisition_fun_return_size | [int](`int`) | Number of top candidates to return from acquisition function optimization. Defaults to 3. | `3` |\n| acquisition_optimizer | [str](`str`) or [callable](`callable`) | Optimizer to use for maximizing acquisition function. Can be \"differential_evolution\" (default) or any method name supported by scipy.optimize.minimize (e.g., \"Nelder-Mead\", \"L-BFGS-B\"). Can also be a callable with signature compatible with scipy.optimize.minimize (fun, x0, bounds, ...). A specific version is \"de_tricands\", which combines DE with Tricands. It can be parameterized with \"prob_de_tricands\" (probability of using DE). Defaults to \"differential_evolution\". | `'differential_evolution'` |\n| acquisition_optimizer_kwargs | [dict](`dict`) | Kwargs passed to the acquisition function optimizer and GPR surrogate optimizer. Defaults to {'maxiter': 10000, 'gtol': 1e-9}. | `None` |\n| restart_after_n | [int](`int`) | Number of consecutive iterations with zero success rate before triggering a restart. Defaults to 100. | `100` |\n| restart_inject_best | [bool](`bool`) | Whether to inject the best solution found so far as a starting point for the next restart. Defaults to True. | `True` |\n| max_restarts | [Optional](`typing.Optional`)\\[[int](`int`)\\] | Patience-based early-stopping threshold. When set to a non-negative integer ``N``, the optimizer terminates after ``N`` consecutive restarts that fail to improve the best objective value. The returned :class:`scipy.optimize.OptimizeResult` has ``success=True`` and a message of the form ``\"Optimization early stopped: no improvement for N consecutive restarts\"``. This rule complements ``restart_after_n`` and mirrors the ``no_progress_loss`` pattern in Hyperopt and plateau-based stopping in Ray Tune and SMAC. ``None`` (default) disables the rule so the optimizer runs until ``max_iter`` or ``max_time`` is reached. | `None` |\n| x0 | [array](`array`) - [like](`like`) | Starting point for optimization, shape (n_features,). If provided, this point will be evaluated first and included in the initial design. The point should be within the bounds and will be validated before use. Defaults to None (no starting point, uses only LHS design). | `None` |\n| de_x0_prob | [float](`float`) | Probability of using the best point as starting point for differential evolution. Defaults to 0.1. | `0.1` |\n| tricands_fringe | [bool](`bool`) | Whether to use the fringe of the design space for the initial design. Defaults to False. | `False` |\n| prob_de_tricands | [float](`float`) | Probability of using differential evolution as an optimizer on the surrogate model. 1 - prob_de_tricands is the probability of using tricands. Defaults to 0.8. | `0.8` |\n| window_size | [int](`int`) | Window size for success rate calculation. | `None` |\n| min_tol_metric | [str](`str`) | Distance metric used when checking `tolerance_x` for duplicate detection. Default is \"chebyshev\". Supports all metrics from scipy.spatial.distance.cdist, including: * \"chebyshev\": L-infinity distance (hypercube). Default. Matches previous behavior. * \"euclidean\": L2 distance (hypersphere). * \"minkowski\": Lp distance (default p=2). * \"cityblock\": Manhattan/L1 distance. * \"cosine\": Cosine distance. * \"correlation\": Correlation distance. * \"canberra\", \"braycurtis\", \"sqeuclidean\", etc. | `'chebyshev'` |\n\n## Attributes {.doc-section .doc-section-attributes}\n\n| Name | Type | Description |\n|------------------------------|-------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------|\n| X_ | [ndarray](`ndarray`) | All evaluated points, shape (n_samples, n_features). |\n| y_ | [ndarray](`ndarray`) | Function values at X_, shape (n_samples,). For multi-objective problems, these are the converted single-objective values. |\n| y_mo | [ndarray](`ndarray`) or None | Multi-objective function values, shape (n_samples, n_objectives). None for single-objective problems. |\n| best_x_ | [ndarray](`ndarray`) | Best point found, shape (n_features,). |\n| best_y_ | [float](`float`) | Best function value found. |\n| n_iter_ | [int](`int`) | Number of iterations performed. This is not the same as counter. Provided for compatibility with scipy.optimize routines. |\n| counter | [int](`int`) | Total number of function evaluations. |\n| success_rate | [float](`float`) | Rolling success rate over the last window_size evaluations. A success is counted when a new evaluation improves upon the best value found so far. |\n| warnings_filter | [Literal](`typing.Literal`)\\[\\'default\\', \\'error\\', \\'ignore\\'\\] | Filter for warnings during optimization. |\n| max_surrogate_points | [int](`int`) or None | Maximum number of points for surrogate fitting. |\n| selection_method | [str](`str`) | Point selection method. |\n| acquisition_failure_strategy | [str](`str`) | Strategy for handling acquisition failures ('random'). |\n| mean_X | [ndarray](`ndarray`) or None | Aggregated unique design points (if repeats_surrogate > 1). |\n| mean_y | [ndarray](`ndarray`) or None | Mean y values per design point (if repeats_surrogate > 1). |\n| var_y | [ndarray](`ndarray`) or None | Variance of y values per design point (if repeats_surrogate > 1). |\n| min_mean_X | [ndarray](`ndarray`) or None | X value of best mean y (if repeats_surrogate > 1). |\n| min_mean_y | [float](`float`) or None | Best mean y value (if repeats_surrogate > 1). |\n| min_var_y | [float](`float`) or None | Variance of best mean y (if repeats_surrogate > 1). |\n| de_x0_prob | [float](`float`) | Probability of using the best point as starting point for differential evolution. |\n| tricands_fringe | [bool](`bool`) | Whether to use the fringe of the design space for the initial design. |\n| prob_de_tricands | [float](`float`) | Probability of using differential evolution as an optimizer on the surrogate model. |\n\n## Examples {.doc-section .doc-section-examples}\n\n\n::: {#79837348 .cell execution_count=1}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n\ndef objective(X):\n return np.sum(X**2, axis=1)\n\n# Example 1: Basic usage (deterministic function)\nbounds = [(-5, 5), (-5, 5)]\noptimizer = SpotOptim(fun=objective, bounds=bounds, max_iter=10, n_initial=5, verbose=True)\nresult = optimizer.optimize()\nprint(\"Best x:\", result.x)\nprint(\"Best f(x):\", result.fun)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTensorBoard logging disabled\nInitial best: f(x) = 0.264287\nIter 1 | Best: 0.264286 | Rate: 1.00 | Evals: 60.0%\nIter 2 | Best: 0.264273 | Rate: 1.00 | Evals: 70.0%\nIter 3 | Best: 0.209907 | Rate: 1.00 | Evals: 80.0%\nIter 4 | Best: 0.114816 | Rate: 1.00 | Evals: 90.0%\nIter 5 | Best: 0.014866 | Rate: 1.00 | Evals: 100.0%\nBest x: [-0.12168737 0.00765778]\nBest f(x): 0.014866458197035248\n```\n:::\n:::\n\n\n::: {#a2bbfdd0 .cell execution_count=2}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n\ndef objective(X):\n return np.sum(X**2, axis=1)\n\n# Example 2: With custom variable names\noptimizer = SpotOptim(\n fun=objective,\n bounds=[(-5, 5), (-5, 5)],\n var_name=[\"param1\", \"param2\"],\n max_iter=10,\n n_initial=5\n)\nresult = optimizer.optimize()\n# Ensure we can use custom names in plots\noptimizer.plot_surrogate(show=False)\n```\n\n::: {.cell-output .cell-output-display}\n![](SpotOptim.SpotOptim_files/figure-html/cell-3-output-1.png){width=1126 height=950}\n:::\n:::\n\n\n::: {#43921ff5 .cell execution_count=3}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n\n# Example 3: Noisy function with repeated evaluations\ndef noisy_objective(X):\n base = np.sum(X**2, axis=1)\n noise = np.random.normal(0, 0.1, size=base.shape)\n return base + noise\n\noptimizer = SpotOptim(\n fun=noisy_objective,\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10,\n n_initial=5,\n repeats_initial=1, # Evaluate each initial point once\n repeats_surrogate=2, # Evaluate each new point twice\n seed=42, # For reproducibility\n verbose=True\n)\nresult = optimizer.optimize()\n\n# Access noise statistics\nprint(\"Unique design points:\", optimizer.mean_X.shape[0])\nprint(\"Best mean value:\", optimizer.min_mean_y)\nprint(\"Variance at best point:\", optimizer.min_var_y)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTensorBoard logging disabled\nInitial best: f(x) = 3.403652, mean best: f(x) = 3.403652\nIter 1 | Best: 3.279049 | Rate: 0.50 | Evals: 70.0% | Mean Best: 3.369716\nIter 2 | Best: 3.279049 | Curr: 3.392849 | Rate: 0.25 | Evals: 90.0% | Mean Curr: 3.454694\nIter 3 | Best: 1.563282 | Rate: 0.50 | Evals: 110.0% | Mean Best: 1.613581\nUnique design points: 8\nBest mean value: 1.6135806237005457\nVariance at best point: 0.002529978015323257\n```\n:::\n:::\n\n\n::: {#d3b63ba1 .cell execution_count=4}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n\ndef noisy_objective(X):\n base = np.sum(X**2, axis=1)\n noise = np.random.normal(0, 0.1, size=base.shape)\n return base + noise\n\n# Example 4: Noisy function with OCBA (Optimal Computing Budget Allocation)\noptimizer_ocba = SpotOptim(\n fun=noisy_objective,\n bounds=[(-5, 5), (-5, 5)],\n max_iter=20,\n n_initial=5,\n repeats_initial=2, # Initial repeats\n repeats_surrogate=1, # Surrogate repeats\n ocba_delta=3, # Allocate 3 additional evaluations per iteration\n seed=42,\n verbose=True\n)\nresult = optimizer_ocba.optimize()\n\n# OCBA intelligently re-evaluates promising points to reduce uncertainty\nprint(\"Total evaluations:\", result.nfev)\nprint(\"Unique design points:\", optimizer_ocba.mean_X.shape[0])\nprint(\"Best mean value:\", optimizer_ocba.min_mean_y)\nprint(\"Variance at best point:\", optimizer_ocba.min_var_y)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTensorBoard logging disabled\nInitial best: f(x) = 3.328092, mean best: f(x) = 3.368681\n\nIn get_ocba():\nmeans: [25.90094202 19.61660056 23.96405211 3.36868097 10.79578138]\nvars: [6.73858271e-13 2.56053422e-03 1.00799409e-03 1.64745915e-03\n 1.91555606e-03]\ndelta: 3\nn_designs: 5\nRatios: [3.82210611e-11 2.79305049e-01 6.84325095e-02 9.58065217e-01\n 1.00000000e+00]\nBest: 3, Second best: 4\n OCBA: Adding 3 re-evaluation(s)\nIter 1 | Best: 3.103418 | Rate: 0.75 | Evals: 70.0% | Mean Best: 3.103418\nIter 2 | Best: 3.103418 | Curr: 3.354605 | Rate: 0.60 | Evals: 75.0% | Mean Curr: 3.354605\nIter 3 | Best: 1.613729 | Rate: 0.67 | Evals: 80.0% | Mean Best: 1.613729\nIter 4 | Best: 1.230181 | Rate: 0.71 | Evals: 85.0% | Mean Best: 1.230181\nIter 5 | Best: 0.449320 | Rate: 0.75 | Evals: 90.0% | Mean Best: 0.449320\nIter 6 | Best: 0.367163 | Rate: 0.78 | Evals: 95.0% | Mean Best: 0.367163\nIter 7 | Best: 0.367163 | Curr: 0.518496 | Rate: 0.70 | Evals: 100.0% | Mean Curr: 0.518496\nTotal evaluations: 20\nUnique design points: 12\nBest mean value: 0.3671633104119547\nVariance at best point: 0.0\n```\n:::\n:::\n\n\n::: {#cb5ee6f2 .cell execution_count=5}\n``` {.python .cell-code}\nimport numpy as np\nimport shutil\nimport os\nfrom spotoptim import SpotOptim\n\ndef objective(X):\n return np.sum(X**2, axis=1)\n\n# Example 5: With TensorBoard logging\ntb_dir = \"runs/my_optimization\"\noptimizer_tb = SpotOptim(\n fun=objective,\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10,\n n_initial=5,\n tensorboard_log=True, # Enable TensorBoard\n tensorboard_path=tb_dir, # Optional custom path\n verbose=True\n)\nresult = optimizer_tb.optimize()\n\n# View logs in browser: tensorboard --logdir=runs/my_optimization\nprint(\"Logs saved to:\", optimizer_tb.tensorboard_path)\n\n# Cleanup log dir\nif os.path.exists(tb_dir):\n shutil.rmtree(tb_dir)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTensorBoard logging enabled: runs/my_optimization\nInitial best: f(x) = 3.380819\nIter 1 | Best: 3.067962 | Rate: 1.00 | Evals: 60.0%\nIter 2 | Best: 1.420452 | Rate: 1.00 | Evals: 70.0%\nIter 3 | Best: 0.337299 | Rate: 1.00 | Evals: 80.0%\nIter 4 | Best: 0.134625 | Rate: 1.00 | Evals: 90.0%\nIter 5 | Best: 0.015896 | Rate: 1.00 | Evals: 100.0%\nTensorBoard writer closed. View logs with: tensorboard --logdir=runs/my_optimization\nLogs saved to: runs/my_optimization\n```\n:::\n:::\n\n\n::: {#2286ece6 .cell execution_count=6}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.surrogate import Kriging\n\ndef objective(X):\n return np.sum(X**2, axis=1)\n\n# Example 6: Using SpotOptim's Kriging surrogate\nkriging_model = Kriging(\n noise=1e-10, # Regularization parameter\n kernel='gauss', # Gaussian/RBF kernel\n min_theta=-3.0, # Min log10(theta) bound\n max_theta=2.0, # Max log10(theta) bound\n seed=42\n)\noptimizer_kriging = SpotOptim(\n fun=objective,\n bounds=[(-5, 5), (-5, 5)],\n surrogate=kriging_model,\n max_iter=10,\n n_initial=5,\n seed=42,\n verbose=True\n)\nresult = optimizer_kriging.optimize()\nprint(\"Best solution found:\", result.x)\nprint(\"Best value:\", result.fun)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTensorBoard logging disabled\nInitial best: f(x) = 3.251349\nIter 1 | Best: 3.251349 | Curr: 4.425619 | Rate: 0.00 | Evals: 60.0%\nIter 2 | Best: 1.617693 | Rate: 0.50 | Evals: 70.0%\nIter 3 | Best: 1.617693 | Curr: 18.716279 | Rate: 0.33 | Evals: 80.0%\nIter 4 | Best: 0.839564 | Rate: 0.50 | Evals: 90.0%\nIter 5 | Best: 0.102879 | Rate: 0.60 | Evals: 100.0%\nBest solution found: [0.00128033 0.32074518]\nBest value: 0.10287911055669191\n```\n:::\n:::\n\n\n::: {#c7db9152 .cell execution_count=7}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom sklearn.gaussian_process import GaussianProcessRegressor\nfrom sklearn.gaussian_process.kernels import RBF, ConstantKernel, WhiteKernel\n\ndef objective(X):\n return np.sum(X**2, axis=1)\n\n# Example 7: Using sklearn Gaussian Process with custom kernel\n# Custom kernel: constant * RBF + white noise\ncustom_kernel = ConstantKernel(1.0, (1e-2, 1e2)) * RBF(\n length_scale=1.0, length_scale_bounds=(1e-1, 10.0)\n) + WhiteKernel(noise_level=1e-5, noise_level_bounds=(1e-10, 1e-1))\n\ngp_custom = GaussianProcessRegressor(\n kernel=custom_kernel,\n n_restarts_optimizer=15,\n normalize_y=True,\n random_state=42\n)\n\noptimizer_custom_gp = SpotOptim(\n fun=objective,\n bounds=[(-5, 5), (-5, 5)],\n surrogate=gp_custom,\n max_iter=10,\n n_initial=5,\n seed=42\n)\nresult = optimizer_custom_gp.optimize()\n```\n:::\n\n\n::: {#ce439803 .cell execution_count=8}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom sklearn.ensemble import RandomForestRegressor\n\ndef objective(X):\n return np.sum(X**2, axis=1)\n\n# Example 8: Using Random Forest as surrogate\nrf_model = RandomForestRegressor(\n n_estimators=100,\n max_depth=10,\n random_state=42\n)\n\noptimizer_rf = SpotOptim(\n fun=objective,\n bounds=[(-5, 5), (-5, 5)],\n surrogate=rf_model,\n max_iter=10,\n n_initial=5,\n seed=42\n)\nresult = optimizer_rf.optimize()\n\n# Note: Random Forests don't provide uncertainty estimates,\n# so Expected Improvement (EI) may be less effective.\n# Consider using acquisition='y' for pure exploitation.\n```\n:::\n\n\n::: {#b0775e20 .cell execution_count=9}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom sklearn.gaussian_process import GaussianProcessRegressor\nfrom sklearn.gaussian_process.kernels import Matern, RationalQuadratic, ConstantKernel, RBF\n\ndef objective(X):\n return np.sum(X**2, axis=1)\n\n# Example 9: Comparing different kernels for Gaussian Process\n# Matern kernel with nu=1.5 (once differentiable)\nkernel_matern15 = ConstantKernel(1.0) * Matern(length_scale=1.0, nu=1.5)\ngp_matern15 = GaussianProcessRegressor(kernel=kernel_matern15, normalize_y=True)\n\n# Matern kernel with nu=2.5 (twice differentiable, DEFAULT)\nkernel_matern25 = ConstantKernel(1.0) * Matern(length_scale=1.0, nu=2.5)\ngp_matern25 = GaussianProcessRegressor(kernel=kernel_matern25, normalize_y=True)\n\n# RBF kernel (infinitely differentiable, smooth)\nkernel_rbf = ConstantKernel(1.0) * RBF(length_scale=1.0)\ngp_rbf = GaussianProcessRegressor(kernel=kernel_rbf, normalize_y=True)\n\n# Rational Quadratic kernel (mixture of RBF kernels)\nkernel_rq = ConstantKernel(1.0) * RationalQuadratic(length_scale=1.0, alpha=1.0)\ngp_rq = GaussianProcessRegressor(kernel=kernel_rq, normalize_y=True)\n\n# Use any of these as surrogate\noptimizer_rbf = SpotOptim(fun=objective, bounds=[(-5, 5), (-5, 5)],\n surrogate=gp_rbf, max_iter=10, n_initial=5)\nresult = optimizer_rbf.optimize()\n```\n:::\n\n\n## Methods\n\n| Name | Description |\n| --- | --- |\n| [aggregate_mean_var](#spotoptim.SpotOptim.SpotOptim.aggregate_mean_var) | Aggregate X and y values to compute mean and variance per group. |\n| [apply_ocba](#spotoptim.SpotOptim.SpotOptim.apply_ocba) | Apply Optimal Computing Budget Allocation for noisy functions. |\n| [apply_penalty_NA](#spotoptim.SpotOptim.SpotOptim.apply_penalty_NA) | Replace NaN and infinite values with penalty plus random noise. |\n| [check_size_initial_design](#spotoptim.SpotOptim.SpotOptim.check_size_initial_design) | Validate that initial design has sufficient points for surrogate fitting. |\n| [curate_initial_design](#spotoptim.SpotOptim.SpotOptim.curate_initial_design) | Remove duplicates and ensure sufficient unique points in initial design. |\n| [detect_var_type](#spotoptim.SpotOptim.SpotOptim.detect_var_type) | Auto-detect variable types based on factor mappings. |\n| [determine_termination](#spotoptim.SpotOptim.SpotOptim.determine_termination) | Determine termination reason for optimization. |\n| [evaluate_function](#spotoptim.SpotOptim.SpotOptim.evaluate_function) | Evaluate objective function at points X. |\n| [execute_optimization_run](#spotoptim.SpotOptim.SpotOptim.execute_optimization_run) | Entry point for a single sequential optimization run. |\n| [fit_scheduler](#spotoptim.SpotOptim.SpotOptim.fit_scheduler) | Fit surrogate model using appropriate data based on noise handling. |\n| [fit_select_best_cluster](#spotoptim.SpotOptim.SpotOptim.fit_select_best_cluster) | Selects all points from the cluster with the smallest mean y value. |\n| [fit_select_distant_points](#spotoptim.SpotOptim.SpotOptim.fit_select_distant_points) | Selects k points that are distant from each other using K-means clustering. |\n| [fit_selection_dispatcher](#spotoptim.SpotOptim.SpotOptim.fit_selection_dispatcher) | Dispatcher for selection methods. |\n| [fit_surrogate](#spotoptim.SpotOptim.SpotOptim.fit_surrogate) | Fit surrogate model to data. |\n| [gen_design_table](#spotoptim.SpotOptim.SpotOptim.gen_design_table) | Generate a table of the design or results. |\n| [generate_initial_design](#spotoptim.SpotOptim.SpotOptim.generate_initial_design) | Generate initial space-filling design using Latin Hypercube Sampling. |\n| [get_best_hyperparameters](#spotoptim.SpotOptim.SpotOptim.get_best_hyperparameters) | Get the best hyperparameter configuration found during optimization. |\n| [get_best_xy_initial_design](#spotoptim.SpotOptim.SpotOptim.get_best_xy_initial_design) | Determine and store the best point from initial design. |\n| [get_design_table](#spotoptim.SpotOptim.SpotOptim.get_design_table) | Get a table string showing the search space design before optimization. |\n| [get_experiment_filename](#spotoptim.SpotOptim.SpotOptim.get_experiment_filename) | Generate experiment filename with '_exp.pkl' suffix. |\n| [get_importance](#spotoptim.SpotOptim.SpotOptim.get_importance) | Calculate variable importance scores. |\n| [get_initial_design](#spotoptim.SpotOptim.SpotOptim.get_initial_design) | Generate or process initial design points. Ensures that design points are in |\n| [get_ocba](#spotoptim.SpotOptim.SpotOptim.get_ocba) | Optimal Computing Budget Allocation (OCBA). |\n| [get_ocba_X](#spotoptim.SpotOptim.SpotOptim.get_ocba_X) | Calculate OCBA allocation and repeat input array X. |\n| [get_pickle_safe_optimizer](#spotoptim.SpotOptim.SpotOptim.get_pickle_safe_optimizer) | Create a pickle-safe copy of the optimizer. |\n| [get_ranks](#spotoptim.SpotOptim.SpotOptim.get_ranks) | Returns ranks of numbers within input array x. |\n| [get_result_filename](#spotoptim.SpotOptim.SpotOptim.get_result_filename) | Generate result filename with '_res.pkl' suffix. |\n| [get_results_table](#spotoptim.SpotOptim.SpotOptim.get_results_table) | Get a comprehensive table string of optimization results. |\n| [get_shape](#spotoptim.SpotOptim.SpotOptim.get_shape) | Get the shape of the objective function output. |\n| [get_stars](#spotoptim.SpotOptim.SpotOptim.get_stars) | Converts a list of values to a list of stars. |\n| [get_success_rate](#spotoptim.SpotOptim.SpotOptim.get_success_rate) | Get the current success rate of the optimization process. |\n| [handle_default_var_trans](#spotoptim.SpotOptim.SpotOptim.handle_default_var_trans) | Handle default variable transformations. Does not perform any transformations, |\n| [init_storage](#spotoptim.SpotOptim.SpotOptim.init_storage) | Initialize storage for optimization. |\n| [init_surrogate](#spotoptim.SpotOptim.SpotOptim.init_surrogate) | Initialize or configure the surrogate model for optimization. Handles three surrogate configurations: |\n| [inverse_transform_X](#spotoptim.SpotOptim.SpotOptim.inverse_transform_X) | Transform parameter array from internal to original scale. |\n| [inverse_transform_value](#spotoptim.SpotOptim.SpotOptim.inverse_transform_value) | Apply inverse transformation to a single float value. |\n| [load_experiment](#spotoptim.SpotOptim.SpotOptim.load_experiment) | Load experiment configuration from a pickle file. |\n| [load_result](#spotoptim.SpotOptim.SpotOptim.load_result) | Load complete optimization results from a pickle file. |\n| [map_to_factor_values](#spotoptim.SpotOptim.SpotOptim.map_to_factor_values) | Map internal integer factor values back to string labels. |\n| [mo2so](#spotoptim.SpotOptim.SpotOptim.mo2so) | Convert multi-objective values to single-objective. |\n| [modify_bounds_based_on_var_type](#spotoptim.SpotOptim.SpotOptim.modify_bounds_based_on_var_type) | Modify bounds based on variable types. |\n| [optimize](#spotoptim.SpotOptim.SpotOptim.optimize) | Run the optimization process. The optimization terminates when either the total function evaluations reach |\n| [optimize_acquisition_func](#spotoptim.SpotOptim.SpotOptim.optimize_acquisition_func) | Optimize the acquisition function to find the next point to evaluate. |\n| [optimize_sequential_run](#spotoptim.SpotOptim.SpotOptim.optimize_sequential_run) | Perform a single sequential optimization run. |\n| [plot_importance](#spotoptim.SpotOptim.SpotOptim.plot_importance) | Plot variable importance. |\n| [plot_important_hyperparameter_contour](#spotoptim.SpotOptim.SpotOptim.plot_important_hyperparameter_contour) | Plot surrogate contours using spotoptim.plot.visualization.plot_important_hyperparameter_contour. |\n| [plot_parameter_scatter](#spotoptim.SpotOptim.SpotOptim.plot_parameter_scatter) | Plot parameter distributions showing relationship between each parameter and objective. |\n| [plot_progress](#spotoptim.SpotOptim.SpotOptim.plot_progress) | Plot optimization progress using spotoptim.plot.visualization.plot_progress. |\n| [plot_surrogate](#spotoptim.SpotOptim.SpotOptim.plot_surrogate) | Plot the surrogate model for two dimensions. |\n| [print_best](#spotoptim.SpotOptim.SpotOptim.print_best) | Print the best solution found during optimization. |\n| [print_results](#spotoptim.SpotOptim.SpotOptim.print_results) | Alias for print(get_results_table()) for compatibility. |\n| [process_factor_bounds](#spotoptim.SpotOptim.SpotOptim.process_factor_bounds) | Process `bounds` to handle factor variables. |\n| [reinitialize_components](#spotoptim.SpotOptim.SpotOptim.reinitialize_components) | Reinitialize components that were excluded during pickling. |\n| [remove_nan](#spotoptim.SpotOptim.SpotOptim.remove_nan) | Remove rows where y contains NaN or inf values. |\n| [repair_natural_X](#spotoptim.SpotOptim.SpotOptim.repair_natural_X) | Enforce integrality and declared bounds in natural (original) space. |\n| [repair_non_numeric](#spotoptim.SpotOptim.SpotOptim.repair_non_numeric) | Round non-numeric values to integers based on variable type. |\n| [rm_initial_design_NA_values](#spotoptim.SpotOptim.SpotOptim.rm_initial_design_NA_values) | Remove NaN/inf values from initial design evaluations. |\n| [save_experiment](#spotoptim.SpotOptim.SpotOptim.save_experiment) | Save experiment configuration to a pickle file. |\n| [save_result](#spotoptim.SpotOptim.SpotOptim.save_result) | Save complete optimization results to a pickle file. |\n| [select_new](#spotoptim.SpotOptim.SpotOptim.select_new) | Select rows from A that are not in X. |\n| [sensitivity_spearman](#spotoptim.SpotOptim.SpotOptim.sensitivity_spearman) | Compute and print Spearman correlation between parameters and objective values. |\n| [set_seed](#spotoptim.SpotOptim.SpotOptim.set_seed) | Set global random seeds for reproducibility. |\n| [setup_dimension_reduction](#spotoptim.SpotOptim.SpotOptim.setup_dimension_reduction) | Set up dimension reduction by identifying fixed dimensions. |\n| [store_mo](#spotoptim.SpotOptim.SpotOptim.store_mo) | Store multi-objective values in self.y_mo. |\n| [suggest_next_infill_point](#spotoptim.SpotOptim.SpotOptim.suggest_next_infill_point) | Suggest next point to evaluate (dispatcher). |\n| [to_all_dim](#spotoptim.SpotOptim.SpotOptim.to_all_dim) | Expand reduced-dimensional points to full-dimensional representation. |\n| [to_red_dim](#spotoptim.SpotOptim.SpotOptim.to_red_dim) | Reduce full-dimensional points to optimization space. |\n| [transform_X](#spotoptim.SpotOptim.SpotOptim.transform_X) | Transform parameter array from original (natural) to internal scale. |\n| [transform_bounds](#spotoptim.SpotOptim.SpotOptim.transform_bounds) | Transform bounds from original to internal scale. |\n| [transform_value](#spotoptim.SpotOptim.SpotOptim.transform_value) | Apply transformation to a single float value. |\n| [update_repeats_infill_points](#spotoptim.SpotOptim.SpotOptim.update_repeats_infill_points) | Repeat infill point for noisy function evaluation. Used in the sequential_loop. |\n| [update_stats](#spotoptim.SpotOptim.SpotOptim.update_stats) | Update optimization statistics. |\n| [update_storage](#spotoptim.SpotOptim.SpotOptim.update_storage) | Update storage (`X_`, `y_`) with new evaluation points. |\n| [update_success_rate](#spotoptim.SpotOptim.SpotOptim.update_success_rate) | Update the rolling success rate of the optimization process. |\n| [validate_x0](#spotoptim.SpotOptim.SpotOptim.validate_x0) | Validate and process starting point x0. Called in `__init__` and `optimize`. |\n\n### aggregate_mean_var { #spotoptim.SpotOptim.SpotOptim.aggregate_mean_var }\n\n```python\nSpotOptim.SpotOptim.aggregate_mean_var(X, y)\n```\n\nAggregate X and y values to compute mean and variance per group.\nFor repeated evaluations at the same design point, this method computes\nthe mean function value and variance (using population variance, ddof=0).\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-----------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Design points, shape (n_samples, n_features). | _required_ |\n| y | [ndarray](`ndarray`) | Function values, shape (n_samples,). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|---------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| tuple | [Tuple](`typing.Tuple`)\\[[np](`numpy`).[ndarray](`numpy.ndarray`), [np](`numpy`).[ndarray](`numpy.ndarray`), [np](`numpy`).[ndarray](`numpy.ndarray`)\\] | A tuple containing: * X_agg (ndarray): Unique design points, shape (n_groups, n_features) * y_mean (ndarray): Mean y values per group, shape (n_groups,) * y_var (ndarray): Variance of y values per group, shape (n_groups,) |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#2f8bcc57 .cell execution_count=10}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n repeats_initial=2)\nX = np.array([[1, 2], [3, 4], [1, 2]])\ny = np.array([1, 2, 3])\nX_agg, y_mean, y_var = opt.aggregate_mean_var(X, y)\nprint(X_agg.shape)\nprint(y_mean)\nprint(y_var)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n(2, 2)\n[2. 2.]\n[1. 0.]\n```\n:::\n:::\n\n\n### apply_ocba { #spotoptim.SpotOptim.SpotOptim.apply_ocba }\n\n```python\nSpotOptim.SpotOptim.apply_ocba()\n```\n\nApply Optimal Computing Budget Allocation for noisy functions.\n\n### apply_penalty_NA { #spotoptim.SpotOptim.SpotOptim.apply_penalty_NA }\n\n```python\nSpotOptim.SpotOptim.apply_penalty_NA(\n y,\n y_history=None,\n penalty_value=None,\n sd=0.1,\n)\n```\n\nReplace NaN and infinite values with penalty plus random noise.\nUsed in the optimize() method after function evaluations.\nThis method follows the approach from spotpython.utils.repair.apply_penalty_NA,\nreplacing NaN/inf values with a penalty value plus random noise to avoid\nidentical penalty values.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|---------------|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|\n| y | [ndarray](`ndarray`) | Array of objective function values to be repaired. | _required_ |\n| y_history | [ndarray](`ndarray`) | Historical objective function values used for computing penalty statistics. If None, uses y itself. Default is None. | `None` |\n| penalty_value | [float](`float`) | Value to replace NaN/inf with. If None, computes penalty as: max(finite_y_history) + 3 * std(finite_y_history). If all values are NaN/inf or only one finite value exists, falls back to self.penalty_val. Default is None. | `None` |\n| sd | [float](`float`) | Standard deviation for normal distributed random noise added to penalty. Default is 0.1. | `0.1` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Array with NaN/inf replaced by penalty_value + random noise (normal distributed with mean 0 and standard deviation sd). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#3be0678b .cell execution_count=11}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda X: np.sum(X**2, axis=1), bounds=[(-5, 5)])\ny_hist = np.array([1.0, 2.0, 3.0, 5.0])\ny_new = np.array([4.0, np.nan, np.inf])\ny_clean = opt.apply_penalty_NA(y_new, y_history=y_hist)\nprint(f\"np.all(np.isfinite(y_clean)): {np.all(np.isfinite(y_clean))}\")\nprint(f\"y_clean: {y_clean}\")\n# NaN/inf replaced with worst value from history + 3*std + noise\nprint(f\"y_clean[1] > 5.0: {y_clean[1] > 5.0}\") # Should be larger than max finite value in history\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nnp.all(np.isfinite(y_clean)): True\ny_clean: [ 4. 10.21633765 10.29306236]\ny_clean[1] > 5.0: True\n```\n:::\n:::\n\n\n### check_size_initial_design { #spotoptim.SpotOptim.SpotOptim.check_size_initial_design }\n\n```python\nSpotOptim.SpotOptim.check_size_initial_design(y0, n_evaluated)\n```\n\nValidate that initial design has sufficient points for surrogate fitting.\n\nChecks if the number of valid initial design points meets the minimum\nrequirement for fitting a surrogate model. The minimum required is the\nsmaller of:\n * (a) typical minimum for surrogate fitting (3 for multi-dimensional, 2 for 1D), or\n * (b) what the user requested (`n_initial`).\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|-------------|----------------------|-------------------------------------------------------------------------------|------------|\n| y0 | [ndarray](`ndarray`) | Function values at initial design points (after filtering), shape (n_valid,). | _required_ |\n| n_evaluated | [int](`int`) | Original number of points evaluated before filtering. | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Raises {.doc-section .doc-section-raises}\n\n| Name | Type | Description |\n|--------|----------------------------|------------------------------------------------------------------|\n| | [ValueError](`ValueError`) | If the number of valid points is less than the minimum required. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#74c7221a .cell execution_count=12}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\n\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=10\n)\n# Sufficient points - no error\ny0 = np.array([1.0, 2.0, 3.0, 4.0, 5.0])\nopt.check_size_initial_design(y0, n_evaluated=10)\n\n# Insufficient points - raises ValueError\ny0_small = np.array([1.0])\ntry:\n opt.check_size_initial_design(y0_small, n_evaluated=10)\nexcept ValueError as e:\n print(f\"Error: {e}\")\n\n# With verbose output\nopt_verbose = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=10,\n verbose=True\n)\ny0_reduced = np.array([1.0, 2.0, 3.0]) # Less than n_initial but valid\nopt_verbose.check_size_initial_design(y0_reduced, n_evaluated=10)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nError: Insufficient valid initial design points: only 1 finite value(s) out of 10 evaluated. Need at least 3 points to fit surrogate model. Please check your objective function or increase n_initial.\nTensorBoard logging disabled\nNote: Initial design size (3) is smaller than requested (10) due to NaN/inf values\n```\n:::\n:::\n\n\n### curate_initial_design { #spotoptim.SpotOptim.SpotOptim.curate_initial_design }\n\n```python\nSpotOptim.SpotOptim.curate_initial_design(X0)\n```\n\nRemove duplicates and ensure sufficient unique points in initial design.\n\nThis method handles deduplication that can occur after rounding integer/factor\nvariables. If duplicates are found, it generates additional points to reach\nthe target n_initial unique points. Also handles repeating points when\nrepeats_initial > 1.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-------------------------------------------------------------------------|------------|\n| X0 | [ndarray](`ndarray`) | Initial design points in internal scale, shape (n_samples, n_features). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Curated initial design with duplicates removed and repeated if necessary, shape (n_unique * repeats_initial, n_features). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#a7326126 .cell execution_count=13}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\n\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=10,\n var_type=['int', 'int'] # Integer variables may cause duplicates\n)\nX0 = opt.get_initial_design()\nX0_curated = opt.curate_initial_design(X0)\nX0_curated.shape[0] == 10 # Should have n_initial unique points\n```\n\n::: {.cell-output .cell-output-display execution_count=13}\n```\nTrue\n```\n:::\n:::\n\n\n::: {#ebea618c .cell execution_count=14}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\n# With repeats\nopt_repeat = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n repeats_initial=3\n)\nX0 = opt_repeat.get_initial_design()\nX0_curated = opt_repeat.curate_initial_design(X0)\nX0_curated.shape[0] == 15 # 5 unique points * 3 repeats\n```\n\n::: {.cell-output .cell-output-display execution_count=14}\n```\nTrue\n```\n:::\n:::\n\n\n### detect_var_type { #spotoptim.SpotOptim.SpotOptim.detect_var_type }\n\n```python\nSpotOptim.SpotOptim.detect_var_type()\n```\n\nAuto-detect variable types based on factor mappings.\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|----------------|-------------------------------------------------------------------------------------------------------------------------------------------|\n| list | [list](`list`) | List of variable types ('factor' or 'float') for each dimension. Dimensions with factor mappings are assigned 'factor', others 'float'. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#16f64768 .cell execution_count=15}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\n\n# Define a simple objective mapping names to values for demonstration\ndef objective(X):\n # X has shape (n_samples, n_dimensions)\n return X[:, 0] + X[:, 1]\n\n# The first dimension has factor levels ('red', 'green', 'blue')\n# The second dimension is continuous bounds (0, 10)\nspot = SpotOptim(fun=objective, bounds=[('red', 'green', 'blue'), (0, 10)])\nprint(spot.detect_var_type())\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n['factor', 'float']\n```\n:::\n:::\n\n\n### determine_termination { #spotoptim.SpotOptim.SpotOptim.determine_termination }\n\n```python\nSpotOptim.SpotOptim.determine_termination(timeout_start)\n```\n\nDetermine termination reason for optimization.\nChecks the termination conditions and returns an appropriate message\nindicating why the optimization stopped. Three possible termination\nconditions are checked in order of priority:\n 1. Maximum number of evaluations reached\n 2. Maximum time limit exceeded\n 3. Successful completion (neither limit reached)\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|---------------|------------------|------------------------------------------------|------------|\n| timeout_start | [float](`float`) | Start time of optimization (from time.time()). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------------|--------------------------------------------|\n| str | [str](`str`) | Message describing the termination reason. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#a5c65ad0 .cell execution_count=16}\n``` {.python .cell-code}\nimport numpy as np\nimport time\nfrom spotoptim import SpotOptim\nopt = SpotOptim(\n fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10,\n max_time=10.0\n)\n# Case 1: Maximum evaluations reached\nopt.y_ = np.zeros(20) # Simulate 20 evaluations\nstart_time = time.time()\nmsg = opt.determine_termination(start_time)\nprint(msg)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nOptimization terminated: maximum evaluations (10) reached\n```\n:::\n:::\n\n\n::: {#5987ccf7 .cell execution_count=17}\n``` {.python .cell-code}\n# Case 2: Time limit exceeded\nimport numpy as np\nimport time\nfrom spotoptim import SpotOptim\nopt.y_ = np.zeros(10) # Only 10 evaluations\nstart_time = time.time() - 700 # Simulate 11.67 minutes elapsed\nmsg = opt.determine_termination(start_time)\nprint(msg)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nOptimization terminated: maximum evaluations (10) reached\n```\n:::\n:::\n\n\n::: {#732661f5 .cell execution_count=18}\n``` {.python .cell-code}\n# Case 3: Successful completion\nimport numpy as np\nimport time\nfrom spotoptim import SpotOptim\nopt.y_ = np.zeros(10) # Under max_iter\nstart_time = time.time() # Just started\nmsg = opt.determine_termination(start_time)\nprint(msg)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nOptimization terminated: maximum evaluations (10) reached\n```\n:::\n:::\n\n\n### evaluate_function { #spotoptim.SpotOptim.SpotOptim.evaluate_function }\n\n```python\nSpotOptim.SpotOptim.evaluate_function(X)\n```\n\nEvaluate objective function at points X.\nUsed in the optimize() method to evaluate the objective function.\n\nInput Space: `X` is expected in Transformed and Mapped Space (Internal scale, Reduced dimensions).\nProcess as follows:\n 1. Expands `X` to Transformed Space (Full dimensions) if dimension reduction is active.\n 2. Inverse transforms `X` to Natural Space (Original scale).\n 3. Evaluates the user function with points in Natural Space.\n\nIf dimension reduction is active, expands `X` to full dimensions before evaluation.\nSupports both single-objective and multi-objective functions. For multi-objective\nfunctions, converts to single-objective using `mo2so` method.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|--------------------------------------------------------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Points to evaluate in Transformed and Mapped Space, shape (n_samples, n_reduced_features). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|--------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Function values, shape (n_samples,). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#936a5788 .cell execution_count=19}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n# Single-objective function\nopt_so = SpotOptim(\n fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10,\n n_initial=5\n)\nX = np.array([[1.0, 2.0], [3.0, 4.0]])\ny = opt_so.evaluate_function(X)\nprint(f\"Single-objective output: {y}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nSingle-objective output: [ 5. 25.]\n```\n:::\n:::\n\n\n::: {#fd31fac0 .cell execution_count=20}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n# Multi-objective function (default: use first objective)\nopt_mo = SpotOptim(\n fun=lambda X: np.column_stack([\n np.sum(X**2, axis=1),\n np.sum((X-1)**2, axis=1)\n ]),\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10,\n n_initial=5\n)\ny_mo = opt_mo.evaluate_function(X)\nprint(f\"Multi-objective output (first obj): {y_mo}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nMulti-objective output (first obj): [ 5. 25.]\n```\n:::\n:::\n\n\n### execute_optimization_run { #spotoptim.SpotOptim.SpotOptim.execute_optimization_run }\n\n```python\nSpotOptim.SpotOptim.execute_optimization_run(\n timeout_start,\n X0=None,\n y0_known=None,\n max_iter_override=None,\n)\n```\n\nEntry point for a single sequential optimization run.\nDelegates to optimize_sequential_run with the provided arguments.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|-------------------|---------------------------------------------------------------------------|------------------------------------------------------------------------|------------|\n| timeout_start | [float](`float`) | Start time for timeout. | _required_ |\n| X0 | [Optional](`typing.Optional`)\\[[np](`numpy`).[ndarray](`numpy.ndarray`)\\] | Initial design points in Natural Space, shape (n_initial, n_features). | `None` |\n| y0_known | [Optional](`typing.Optional`)\\[[float](`float`)\\] | Known best value for initial design. | `None` |\n| max_iter_override | [Optional](`typing.Optional`)\\[[int](`int`)\\] | Override for maximum number of iterations. | `None` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------------------------------------------------------------------------------------------|------------------------------------------------------------------------------|\n| | [Tuple](`typing.Tuple`)\\[[str](`str`), [OptimizeResult](`scipy.optimize.OptimizeResult`)\\] | Tuple[str, OptimizeResult]: Tuple containing status and optimization result. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#57896a13 .cell execution_count=21}\n``` {.python .cell-code}\nimport time\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n max_iter=10,\n seed=0,\n verbose=True\n)\nstatus, result = opt.execute_optimization_run(timeout_start=time.time())\nprint(status)\nprint(result.message.splitlines()[0])\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTensorBoard logging disabled\nInitial best: f(x) = 8.463203\nIter 1 | Best: 8.463203 | Curr: 18.224245 | Rate: 0.00 | Evals: 60.0%\nIter 2 | Best: 8.412459 | Rate: 0.50 | Evals: 70.0%\nIter 3 | Best: 5.623369 | Rate: 0.67 | Evals: 80.0%\nIter 4 | Best: 2.902974 | Rate: 0.75 | Evals: 90.0%\nIter 5 | Best: 0.022050 | Rate: 0.80 | Evals: 100.0%\nFINISHED\nOptimization terminated: maximum evaluations (10) reached\n```\n:::\n:::\n\n\n### fit_scheduler { #spotoptim.SpotOptim.SpotOptim.fit_scheduler }\n\n```python\nSpotOptim.SpotOptim.fit_scheduler()\n```\n\nFit surrogate model using appropriate data based on noise handling.\nThis method selects the appropriate training data for surrogate fitting:\n * For noisy functions (repeats_surrogate > 1): Uses mean_X and mean_y (aggregated values)\n * For deterministic functions: Uses X_ and y_ (all evaluated points)\nThe data is transformed to internal scale before fitting the surrogate.\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n```python\n>>> import numpy as np\n>>> from spotoptim import SpotOptim\n>>> from sklearn.gaussian_process import GaussianProcessRegressor\n>>> # Deterministic function\n>>> def sphere(X):\n... X = np.atleast_2d(X)\n... return np.sum(X**2, axis=1)\n>>> opt = SpotOptim(\n... fun=sphere,\n... bounds=[(-5, 5), (-5, 5)],\n... surrogate=GaussianProcessRegressor(),\n... n_initial=5\n... )\n>>> # Simulate optimization state\n>>> opt.X_ = np.array([[1, 2], [0, 0], [2, 1]])\n>>> opt.y_ = np.array([5.0, 0.0, 5.0])\n>>> opt.fit_scheduler()\n>>> # Surrogate fitted with X_ and y_\n>>>\n>>> # Noisy function\n>>> def sphere(X):\n... X = np.atleast_2d(X)\n... return np.sum(X**2, axis=1)\n>>> opt_noise = SpotOptim(\n... fun=sphere,\n... bounds=[(-5, 5), (-5, 5)],\n... surrogate=GaussianProcessRegressor(),\n... n_initial=5,\n... repeats_initial=3,\n... )\n>>> # Simulate noisy optimization state\n>>> opt_noise.mean_X = np.array([[1, 2], [0, 0]])\n>>> opt_noise.mean_y = np.array([5.0, 0.0])\n>>> opt_noise.fit_scheduler()\n>>> # Surrogate fitted with mean_X and mean_y\n```\n\n### fit_select_best_cluster { #spotoptim.SpotOptim.SpotOptim.fit_select_best_cluster }\n\n```python\nSpotOptim.SpotOptim.fit_select_best_cluster(X, y, k)\n```\n\nSelects all points from the cluster with the smallest mean y value.\nThis method performs K-means clustering and selects all points from the\ncluster whose center corresponds to the best (smallest) mean objective\nfunction value.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-----------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Design points, shape (n_samples, n_features). | _required_ |\n| y | [ndarray](`ndarray`) | Function values at X, shape (n_samples,). | _required_ |\n| k | [int](`int`) | Number of clusters. | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|---------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| tuple | [Tuple](`typing.Tuple`)\\[[np](`numpy`).[ndarray](`numpy.ndarray`), [np](`numpy`).[ndarray](`numpy.ndarray`)\\] | A tuple containing: * selected_X (ndarray): Selected design points from best cluster, shape (m, n_features). * selected_y (ndarray): Function values at selected points, shape (m,). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#c0224f91 .cell execution_count=22}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n max_surrogate_points=5,\n selection_method='best')\nX = np.random.rand(100, 2)\ny = np.random.rand(100)\nX_sel, y_sel = opt.fit_select_best_cluster(X, y, 5)\nprint(f\"X_sel.shape: {X_sel.shape}\")\nprint(f\"y_sel.shape: {y_sel.shape}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nX_sel.shape: (25, 2)\ny_sel.shape: (25,)\n```\n:::\n:::\n\n\n### fit_select_distant_points { #spotoptim.SpotOptim.SpotOptim.fit_select_distant_points }\n\n```python\nSpotOptim.SpotOptim.fit_select_distant_points(X, y, k)\n```\n\nSelects k points that are distant from each other using K-means clustering.\nThis method performs K-means clustering to find k clusters, then selects\nthe point closest to each cluster center. This ensures a space-filling\nsubset of points for surrogate model training.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-----------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Design points, shape (n_samples, n_features). | _required_ |\n| y | [ndarray](`ndarray`) | Function values at X, shape (n_samples,). | _required_ |\n| k | [int](`int`) | Number of points to select. | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|---------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| tuple | [Tuple](`typing.Tuple`)\\[[np](`numpy`).[ndarray](`numpy.ndarray`), [np](`numpy`).[ndarray](`numpy.ndarray`)\\] | A tuple containing: * selected_X (ndarray): Selected design points, shape (k, n_features). * selected_y (ndarray): Function values at selected points, shape (k,). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#56a024f2 .cell execution_count=23}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n max_surrogate_points=5)\nX = np.random.rand(100, 2)\ny = np.random.rand(100)\nX_sel, y_sel = opt.fit_select_distant_points(X, y, 5)\nprint(X_sel.shape)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n(5, 2)\n```\n:::\n:::\n\n\n### fit_selection_dispatcher { #spotoptim.SpotOptim.SpotOptim.fit_selection_dispatcher }\n\n```python\nSpotOptim.SpotOptim.fit_selection_dispatcher(X, y)\n```\n\nDispatcher for selection methods.\nDepending on the value of `self.selection_method`, this method calls\nthe appropriate selection function to choose a subset of points for\nsurrogate model training when the total number of points exceeds\n`self.max_surrogate_points`.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-----------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Design points, shape (n_samples, n_features). | _required_ |\n| y | [ndarray](`ndarray`) | Function values at X, shape (n_samples,). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|---------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------|\n| tuple | [Tuple](`typing.Tuple`)\\[[np](`numpy`).[ndarray](`numpy.ndarray`), [np](`numpy`).[ndarray](`numpy.ndarray`)\\] | A tuple containing: * selected_X (ndarray): Selected design points. * selected_y (ndarray): Function values at selected points. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#f7884d00 .cell execution_count=24}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n max_surrogate_points=5)\nX = np.random.rand(100, 2)\ny = np.random.rand(100)\nX_sel, y_sel = opt.fit_selection_dispatcher(X, y)\nprint(X_sel.shape[0] <= 5)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTrue\n```\n:::\n:::\n\n\n### fit_surrogate { #spotoptim.SpotOptim.SpotOptim.fit_surrogate }\n\n```python\nSpotOptim.SpotOptim.fit_surrogate(X, y)\n```\n\nFit surrogate model to data.\nUsed by fit_scheduler() to fit the surrogate model.\nIf the number of points exceeds `self.max_surrogate_points`,\na subset of points is selected using the selection dispatcher.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-----------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Design points, shape (n_samples, n_features). | _required_ |\n| y | [ndarray](`ndarray`) | Function values at X, shape (n_samples,). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n```python\n>>> import numpy as np\n>>> from spotoptim import SpotOptim\n>>> from sklearn.gaussian_process import GaussianProcessRegressor\n>>> def sphere(X):\n... X = np.atleast_2d(X)\n... return np.sum(X**2, axis=1)\n>>> opt = SpotOptim(fun=sphere,\n... bounds=[(-5, 5), (-5, 5)],\n... max_surrogate_points=10,\n... surrogate=GaussianProcessRegressor())\n>>> X = np.random.rand(50, 2)\n>>> y = np.random.rand(50)\n>>> opt.fit_surrogate(X, y)\n>>> # Surrogate is now fitted\n```\n\n### gen_design_table { #spotoptim.SpotOptim.SpotOptim.gen_design_table }\n\n```python\nSpotOptim.SpotOptim.gen_design_table(precision=4, tablefmt='github')\n```\n\nGenerate a table of the design or results.\nIf optimization has been run (results available), returns the results table.\nOtherwise, returns the design table (search space configuration).\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|-----------|--------------|-----------------------------------------------------------|------------|\n| tablefmt | [str](`str`) | Table format. Defaults to 'github'. | `'github'` |\n| precision | [int](`int`) | Number of decimal places for float values. Defaults to 4. | `4` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------------|-------------------------|\n| str | [str](`str`) | Formatted table string. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#43f89c38 .cell execution_count=25}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n\ndef sphere(X):\n X = np.atleast_2d(X)\n return np.sum(X**2, axis=1)\n\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-10, 10), (0, 1)],\n var_name=[\"x1\", \"x2\", \"x3\"],\n var_type=[\"float\", \"int\", \"float\"],\n max_iter=10,\n n_initial=5\n)\ntable = opt.gen_design_table()\nprint(table)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n| name | type | lower | upper | default | transform |\n|--------|--------|---------|---------|-----------|-------------|\n| x1 | float | -5 | 5 | 0 | - |\n| x2 | int | -10 | 10 | 0 | - |\n| x3 | float | 0 | 1 | 0.5 | - |\n```\n:::\n:::\n\n\n### generate_initial_design { #spotoptim.SpotOptim.SpotOptim.generate_initial_design }\n\n```python\nSpotOptim.SpotOptim.generate_initial_design()\n```\n\nGenerate initial space-filling design using Latin Hypercube Sampling.\nUsed in the optimize() method to create the initial set of design points.\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|-------------------------------------------------------------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Initial design points, shape (n_initial, n_features). Points are in the intervals defined by `self.bounds`. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#65bfe722 .cell execution_count=26}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nopt = SpotOptim(fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=3,\n var_type=['float', 'int'],\n var_trans=['log10', None])\nX0 = opt.generate_initial_design()\nprint(X0.shape)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n(3, 2)\n```\n:::\n:::\n\n\n### get_best_hyperparameters { #spotoptim.SpotOptim.SpotOptim.get_best_hyperparameters }\n\n```python\nSpotOptim.SpotOptim.get_best_hyperparameters(as_dict=True)\n```\n\nGet the best hyperparameter configuration found during optimization.\nIf noise handling is active (repeats_initial > 1 or OCBA), this returns the parameter\nconfiguration associated with the best *mean* objective value. Otherwise, it returns\nthe configuration associated with the absolute best observed value.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|---------|----------------|---------------------------------------------------------------------------------------------------------------------------------|-----------|\n| as_dict | [bool](`bool`) | If True, returns a dictionary mapping parameter names to their values. If False, returns the raw numpy array. Defaults to True. | `True` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|---------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------|\n| | [Union](`typing.Union`)\\[[Dict](`typing.Dict`)\\[[str](`str`), [Any](`typing.Any`)\\], [np](`numpy`).[ndarray](`numpy.ndarray`), None\\] | Union[Dict[str, Any], np.ndarray, None]: The best hyperparameter configuration. Returns None if optimization hasn't started (no data). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#eb12c00d .cell execution_count=27}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\n\nopt = SpotOptim(fun=sphere,\n bounds=[(-5, 5), (0, 10)],\n n_initial=5,\n var_name=[\"x\", \"y\"],\n verbose=True)\nopt.optimize()\nbest_params = opt.get_best_hyperparameters()\nprint(best_params['x']) # Should be close to 0\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTensorBoard logging disabled\nInitial best: f(x) = 3.265380\nIter 1 | Best: 1.306857 | Rate: 1.00 | Evals: 30.0%\nIter 2 | Best: 0.787999 | Rate: 1.00 | Evals: 35.0%\nIter 3 | Best: 0.255633 | Rate: 1.00 | Evals: 40.0%\nIter 4 | Best: 0.002187 | Rate: 1.00 | Evals: 45.0%\nIter 5 | Best: 0.000115 | Rate: 1.00 | Evals: 50.0%\nIter 6 | Best: 0.000000 | Rate: 1.00 | Evals: 55.0%\nIter 7 | Best: 0.000000 | Curr: 0.000000 | Rate: 0.86 | Evals: 60.0%\nIter 8 | Best: 0.000000 | Curr: 0.000000 | Rate: 0.75 | Evals: 65.0%\nIter 9 | Best: 0.000000 | Rate: 0.78 | Evals: 70.0%\nIter 10 | Best: 0.000000 | Curr: 0.000000 | Rate: 0.70 | Evals: 75.0%\nIter 11 | Best: 0.000000 | Rate: 0.73 | Evals: 80.0%\nIter 12 | Best: 0.000000 | Curr: 0.000000 | Rate: 0.67 | Evals: 85.0%\nIter 13 | Best: 0.000000 | Curr: 0.000000 | Rate: 0.62 | Evals: 90.0%\nIter 14 | Best: 0.000000 | Curr: 0.000000 | Rate: 0.57 | Evals: 95.0%\nIter 15 | Best: 0.000000 | Curr: 0.000000 | Rate: 0.53 | Evals: 100.0%\n-0.00030853572714595323\n```\n:::\n:::\n\n\n### get_best_xy_initial_design { #spotoptim.SpotOptim.SpotOptim.get_best_xy_initial_design }\n\n```python\nSpotOptim.SpotOptim.get_best_xy_initial_design()\n```\n\nDetermine and store the best point from initial design.\nFinds the best (minimum) function value in the initial design,\nstores the corresponding point and value in instance attributes,\nand optionally prints the results if verbose mode is enabled.\nFor noisy functions, also reports the mean best value.\n\n#### Note {.doc-section .doc-section-note}\n\nThis method assumes self.X_ and self.y_ have been initialized\nwith the initial design evaluations.\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#b3d52567 .cell execution_count=28}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n verbose=True\n)\n# Simulate initial design (normally done in optimize())\nopt.X_ = np.array([[1, 2], [0, 0], [2, 1]])\nopt.y_ = np.array([5.0, 0.0, 5.0])\nopt.get_best_xy_initial_design()\nprint(f\"Best x: {opt.best_x_}\")\nprint(f\"Best y: {opt.best_y_}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTensorBoard logging disabled\nInitial best: f(x) = 0.000000\nBest x: [0 0]\nBest y: 0.0\n```\n:::\n:::\n\n\n::: {#002aab48 .cell execution_count=29}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import noisy_sphere\n# With noisy function\nopt_noise = SpotOptim(\n fun=noisy_sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n repeats_surrogate=2,\n verbose=True\n)\nopt_noise.X_ = np.array([[1, 2], [0, 0], [2, 1]])\nopt_noise.y_ = np.array([5.0, 0.0, 5.0])\nopt_noise.min_mean_y = 0.5 # Simulated mean best\nopt_noise.get_best_xy_initial_design()\nprint(f\"Best x: {opt_noise.best_x_}\")\nprint(f\"Best y: {opt_noise.best_y_}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTensorBoard logging disabled\nInitial best: f(x) = 0.000000, mean best: f(x) = 0.500000\nBest x: [0 0]\nBest y: 0.0\n```\n:::\n:::\n\n\n### get_design_table { #spotoptim.SpotOptim.SpotOptim.get_design_table }\n\n```python\nSpotOptim.SpotOptim.get_design_table(tablefmt='github', precision=4)\n```\n\nGet a table string showing the search space design before optimization.\nThis method generates a table displaying the variable names, types, bounds,\nand defaults without requiring an optimization run. Useful for inspecting\nand documenting the search space configuration.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|-----------|--------------|-----------------------------------------------------------|------------|\n| tablefmt | [str](`str`) | Table format for tabulate library. Defaults to 'github'. | `'github'` |\n| precision | [int](`int`) | Number of decimal places for float values. Defaults to 4. | `4` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------------|-------------------------|\n| str | [str](`str`) | Formatted table string. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#be6baea3 .cell execution_count=30}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n\ndef sphere(X):\n X = np.atleast_2d(X)\n return np.sum(X**2, axis=1)\n\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-10, 10), (0, 1)],\n var_name=[\"x1\", \"x2\", \"x3\"],\n var_type=[\"float\", \"int\", \"float\"],\n max_iter=10,\n n_initial=5\n)\ntable = opt.get_design_table()\nprint(table)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n| name | type | lower | upper | default | transform |\n|--------|--------|---------|---------|-----------|-------------|\n| x1 | float | -5 | 5 | 0 | - |\n| x2 | int | -10 | 10 | 0 | - |\n| x3 | float | 0 | 1 | 0.5 | - |\n```\n:::\n:::\n\n\n### get_experiment_filename { #spotoptim.SpotOptim.SpotOptim.get_experiment_filename }\n\n```python\nSpotOptim.SpotOptim.get_experiment_filename(prefix)\n```\n\nGenerate experiment filename with '_exp.pkl' suffix.\n\n### get_importance { #spotoptim.SpotOptim.SpotOptim.get_importance }\n\n```python\nSpotOptim.SpotOptim.get_importance()\n```\n\nCalculate variable importance scores.\nImportance is computed as the normalized sensitivity of each parameter\nbased on the variation in objective values across the evaluated points.\nHigher scores indicate parameters that have more influence on the objective.\nThe importance is calculated as:\n 1. For each dimension, compute the correlation between parameter values\n and objective values\n 2. Normalize to percentage scale (0-100)\n 3. Higher values indicate more important parameters\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|-------------------------------------------|------------------------------------------------------------------|\n| | [List](`typing.List`)\\[[float](`float`)\\] | List[float]: Importance scores for each dimension (0-100 scale). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#4250ccea .cell execution_count=31}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n\ndef test_func(X):\n # x0 has strong effect, x1 has weak effect\n return 10 * X[:, 0]**2 + 0.1 * X[:, 1]**2\n\nopt = SpotOptim(\n fun=test_func,\n bounds=[(-5, 5), (-5, 5)],\n var_name=[\"x0\", \"x1\"],\n max_iter=10,\n n_initial=5,\n seed=42\n)\nresult = opt.optimize()\nimportance = opt.get_importance()\nprint(f\"x0 importance: {importance[0]:.2f}\")\nprint(f\"x1 importance: {importance[1]:.2f}\")\n\n# Use table to display importance\ntable = opt.get_results_table(show_importance=True)\nprint(table)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nx0 importance: 73.24\nx1 importance: 26.76\n| name | type | default | lower | upper | tuned | transform | importance | stars |\n|--------|--------|-----------|---------|---------|---------|-------------|--------------|---------|\n| x0 | float | 0 | -5 | 5 | 0.1701 | - | 73.24 | * |\n| x1 | float | 0 | -5 | 5 | 1.9552 | - | 26.76 | . |\n\nInterpretation: ***: >99%, **: >75%, *: >50%, .: >10%\n```\n:::\n:::\n\n\n### get_initial_design { #spotoptim.SpotOptim.SpotOptim.get_initial_design }\n\n```python\nSpotOptim.SpotOptim.get_initial_design(X0=None)\n```\n\nGenerate or process initial design points. Ensures that design points are in\ninternal (transformed and reduced) scale.\nCalls `generate_initial_design()` if `X0` is None, otherwise processes user-provided `X0`.\nHandles three scenarios:\n * `X0` is None: Generate space-filling design using LHS\n * `X0` is None but starting point(s) `x0` is provided: Generate LHS and include `x0` as first point(s)\n * `X0` is provided: Transform and prepare user-provided initial design\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------|-----------|\n| X0 | [ndarray](`ndarray`) | User-provided initial design points in original scale, shape (n_initial, n_features). If None, generates space-filling design. Defaults to None. | `None` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|-----------------------------------------------------------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Initial design points in internal (transformed and reduced) scale, shape (n_initial, n_features_reduced). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#3c7d16f1 .cell execution_count=32}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nfrom spotoptim.plot.visualization import plot_design_points\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=10\n)\n# Generate default LHS design\nX0 = opt.get_initial_design()\nprint(X0.shape)\nplot_design_points(X0)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n(10, 2)\n```\n:::\n\n::: {.cell-output .cell-output-display}\n![](SpotOptim.SpotOptim_files/figure-html/cell-33-output-2.png){width=565 height=469}\n:::\n\n::: {.cell-output .cell-output-display execution_count=32}\n![](SpotOptim.SpotOptim_files/figure-html/cell-33-output-3.png){width=565 height=469}\n:::\n:::\n\n\n::: {#848bd188 .cell execution_count=33}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nfrom spotoptim.plot.visualization import plot_design_points\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=10,\n x0=np.array([0, 0]) # Starting point to include in initial design\n)\nX0 = opt.get_initial_design()\nprint(X0.shape)\nplot_design_points(X0)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n(10, 2)\n```\n:::\n\n::: {.cell-output .cell-output-display}\n![](SpotOptim.SpotOptim_files/figure-html/cell-34-output-2.png){width=565 height=469}\n:::\n\n::: {.cell-output .cell-output-display execution_count=33}\n![](SpotOptim.SpotOptim_files/figure-html/cell-34-output-3.png){width=565 height=469}\n:::\n:::\n\n\n### get_ocba { #spotoptim.SpotOptim.SpotOptim.get_ocba }\n\n```python\nSpotOptim.SpotOptim.get_ocba(means, vars, delta, verbose=False)\n```\n\nOptimal Computing Budget Allocation (OCBA).\n\n### get_ocba_X { #spotoptim.SpotOptim.SpotOptim.get_ocba_X }\n\n```python\nSpotOptim.SpotOptim.get_ocba_X(X, means, vars, delta, verbose=False)\n```\n\nCalculate OCBA allocation and repeat input array X.\n\n### get_pickle_safe_optimizer { #spotoptim.SpotOptim.SpotOptim.get_pickle_safe_optimizer }\n\n```python\nSpotOptim.SpotOptim.get_pickle_safe_optimizer(\n unpickleables='file_io',\n verbosity=0,\n)\n```\n\nCreate a pickle-safe copy of the optimizer.\n\n### get_ranks { #spotoptim.SpotOptim.SpotOptim.get_ranks }\n\n```python\nSpotOptim.SpotOptim.get_ranks(x)\n```\n\nReturns ranks of numbers within input array x.\n\n### get_result_filename { #spotoptim.SpotOptim.SpotOptim.get_result_filename }\n\n```python\nSpotOptim.SpotOptim.get_result_filename(prefix)\n```\n\nGenerate result filename with '_res.pkl' suffix.\n\n### get_results_table { #spotoptim.SpotOptim.SpotOptim.get_results_table }\n\n```python\nSpotOptim.SpotOptim.get_results_table(\n tablefmt='github',\n precision=4,\n show_importance=False,\n)\n```\n\nGet a comprehensive table string of optimization results.\nThis method generates a formatted table of the search space configuration,\nbest values found, and optionally variable importance scores.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|-----------------|----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|\n| tablefmt | [str](`str`) | Table format for tabulate library. Options include: 'github', 'grid', 'simple', 'plain', 'html', 'latex', etc. Defaults to 'github'. | `'github'` |\n| precision | [int](`int`) | Number of decimal places for float values. Defaults to 4. | `4` |\n| show_importance | [bool](`bool`) | Whether to include importance scores. Importance is calculated as the normalized standard deviation of each parameter's effect on the objective. Requires multiple evaluations. Defaults to False. | `False` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------------|------------------------------------------------------|\n| str | [str](`str`) | Formatted table string that can be printed or saved. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#37195d9d .cell execution_count=34}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n\n# Example 1: Basic usage after optimization\ndef sphere(X):\n X = np.atleast_2d(X)\n return np.sum(X**2, axis=1)\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5), (-5, 5)],\n var_name=[\"x1\", \"x2\", \"x3\"],\n var_type=[\"float\", \"float\", \"float\"],\n max_iter=10,\n n_initial=5\n)\nresult = opt.optimize()\ntable = opt.get_results_table()\nprint(table)\ntable = opt.get_results_table(show_importance=True)\nprint(table)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n| name | type | default | lower | upper | tuned | transform |\n|--------|--------|-----------|---------|---------|---------|-------------|\n| x1 | float | 0 | -5 | 5 | 0.8126 | - |\n| x2 | float | 0 | -5 | 5 | 1.1127 | - |\n| x3 | float | 0 | -5 | 5 | -2.0112 | - |\n| name | type | default | lower | upper | tuned | transform | importance | stars |\n|--------|--------|-----------|---------|---------|---------|-------------|--------------|---------|\n| x1 | float | 0 | -5 | 5 | 0.8126 | - | 9.15 | |\n| x2 | float | 0 | -5 | 5 | 1.1127 | - | 28.21 | . |\n| x3 | float | 0 | -5 | 5 | -2.0112 | - | 62.64 | * |\n\nInterpretation: ***: >99%, **: >75%, *: >50%, .: >10%\n```\n:::\n:::\n\n\n### get_shape { #spotoptim.SpotOptim.SpotOptim.get_shape }\n\n```python\nSpotOptim.SpotOptim.get_shape(y)\n```\n\nGet the shape of the objective function output.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-----------------------------------------------------------------------------|------------|\n| y | [ndarray](`ndarray`) | Objective function output, shape (n_samples,) or (n_samples, n_objectives). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|----------------------------------------------------------------------------------------|----------------------------------------------------------------------------|\n| tuple | [Tuple](`typing.Tuple`)\\[[int](`int`), [Optional](`typing.Optional`)\\[[int](`int`)\\]\\] | (n_samples, n_objectives) where n_objectives is None for single-objective. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#2b7bd14f .cell execution_count=35}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(\n fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10,\n n_initial=5\n)\ny_single = np.array([1.0, 2.0, 3.0])\nn, m = opt.get_shape(y_single)\nprint(f\"n={n}, m={m}\")\ny_multi = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])\nn, m = opt.get_shape(y_multi)\nprint(f\"n={n}, m={m}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nn=3, m=None\nn=3, m=2\n```\n:::\n:::\n\n\n### get_stars { #spotoptim.SpotOptim.SpotOptim.get_stars }\n\n```python\nSpotOptim.SpotOptim.get_stars(input_list)\n```\n\nConverts a list of values to a list of stars.\nUsed to visualize the importance of a variable.\nThresholds: >99: ***, >75: **, >50: *, >10: .\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|------------|----------------|--------------------------------------|------------|\n| input_list | [list](`list`) | A list of importance scores (0-100). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|----------------|-------------------------|\n| list | [list](`list`) | A list of star strings. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#63b63e62 .cell execution_count=36}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nimport numpy as np\n\ndef test_func(X):\n return 10 * X[:, 0]**2 + 0.1 * X[:, 1]**2\n\nopt = SpotOptim(\n fun=test_func,\n bounds=[(-5, 5), (-5, 5)],\n var_name=[\"x0\", \"x1\"],\n max_iter=10,\n n_initial=5,\n seed=42\n)\nopt.optimize()\nopt.get_stars([100, 75, 50, 10, 0])\n```\n\n::: {.cell-output .cell-output-display execution_count=36}\n```\n['***', '*', '.', '', '']\n```\n:::\n:::\n\n\n### get_success_rate { #spotoptim.SpotOptim.SpotOptim.get_success_rate }\n\n```python\nSpotOptim.SpotOptim.get_success_rate()\n```\n\nGet the current success rate of the optimization process.\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|------------------|---------------------------|\n| float | [float](`float`) | The current success rate. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#190da1ea .cell execution_count=37}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda x: x,\n bounds=[(-5, 5), (-5, 5)])\nprint(opt.get_success_rate())\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n0.0\n```\n:::\n:::\n\n\n### handle_default_var_trans { #spotoptim.SpotOptim.SpotOptim.handle_default_var_trans }\n\n```python\nSpotOptim.SpotOptim.handle_default_var_trans()\n```\n\nHandle default variable transformations. Does not perform any transformations,\nonly sets `var_trans` to a list of `None` values if not specified, or normalizes\ntransformation names by converting `id`, `None`, or `None` to `None`.\nAlso validates that `var_trans` length matches the number of dimensions.\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Raises {.doc-section .doc-section-raises}\n\n| Name | Type | Description |\n|--------|----------------------------|------------------------------------------|\n| | [ValueError](`ValueError`) | If var_trans length doesn't match n_dim. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#9f744da6 .cell execution_count=38}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\n# Default behavior - all None\nspot = SpotOptim(fun=lambda x: x, bounds=[(0, 10), (0, 10)])\nprint(f\"spot.var_trans (should be [None, None]): {spot.var_trans}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nspot.var_trans (should be [None, None]): [None, None]\n```\n:::\n:::\n\n\n::: {#f9817d58 .cell execution_count=39}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\n# Normalize transformation names\nspot = SpotOptim(fun=lambda x: x, bounds=[(1, 10), (1, 100)],\n var_trans=['log10', 'id'])\nprint(f\"spot.var_trans (should be ['log10', 'None']): {spot.var_trans}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nspot.var_trans (should be ['log10', 'None']): ['log10', None]\n```\n:::\n:::\n\n\n### init_storage { #spotoptim.SpotOptim.SpotOptim.init_storage }\n\n```python\nSpotOptim.SpotOptim.init_storage(X0, y0)\n```\n\nInitialize storage for optimization.\nSets up the initial data structures needed for optimization tracking:\n * X_: Evaluated design points (in original scale)\n * y_: Function values at evaluated points\n * n_iter_: Iteration counter\nThen updates statistics by calling `update_stats()`.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-------------------------------------------------------------------------|------------|\n| X0 | [ndarray](`ndarray`) | Initial design points in internal scale, shape (n_samples, n_features). | _required_ |\n| y0 | [ndarray](`ndarray`) | Function values at X0, shape (n_samples,). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#20024306 .cell execution_count=40}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5)\nX0 = np.array([[1, 2], [3, 4], [0, 1]])\ny0 = np.array([5.0, 25.0, 1.0])\nopt.init_storage(X0, y0)\nprint(f\"X_ = {opt.X_}\")\nprint(f\"y_ = {opt.y_}\")\nprint(f\"n_iter_ = {opt.n_iter_}\")\nprint(f\"counter = {opt.counter}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nX_ = [[1. 2.]\n [3. 4.]\n [0. 1.]]\ny_ = [ 5. 25. 1.]\nn_iter_ = 0\ncounter = 0\n```\n:::\n:::\n\n\n### init_surrogate { #spotoptim.SpotOptim.SpotOptim.init_surrogate }\n\n```python\nSpotOptim.SpotOptim.init_surrogate()\n```\n\nInitialize or configure the surrogate model for optimization. Handles three surrogate configurations:\n * List of surrogates: sets up multi-surrogate selection with probability weights and per-surrogate `max_surrogate_points`.\n * None (default): creates a `GaussianProcessRegressor` with a\n `ConstantKernel * Matern(nu=2.5)` kernel, 100 optimizer restarts,\n and `normalize_y=True`.\n * User-provided surrogate: accepted as-is; internal bookkeeping\n attributes (`_max_surrogate_points_list`,\n `_active_max_surrogate_points`) are still initialised.\nAfter this method returns the following attributes are set:\n * `self.surrogate` — the active surrogate model.\n * `self._surrogates_list` — `list | None`.\n * `self._prob_surrogate` — normalised selection probabilities or `None`.\n * `self._max_surrogate_points_list` — per-surrogate point caps or `None`.\n * `self._active_max_surrogate_points` — active cap.\n\n#### Raises {.doc-section .doc-section-raises}\n\n| Name | Type | Description |\n|--------|----------------------------|---------------------------------------------------------------------------------|\n| | [ValueError](`ValueError`) | If the surrogate list is empty. |\n| | [ValueError](`ValueError`) | If 'prob_surrogate' length does not match the surrogate list length. |\n| | [ValueError](`ValueError`) | If 'max_surrogate_points' list length does not match the surrogate list length. |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#8b3dc868 .cell execution_count=41}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n# Default surrogate (GaussianProcessRegressor)\nopt = SpotOptim(\n fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n)\nprint(type(opt.surrogate).__name__)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nGaussianProcessRegressor\n```\n:::\n:::\n\n\n::: {#51c2446a .cell execution_count=42}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom sklearn.ensemble import RandomForestRegressor\n# User-provided surrogate\nrf = RandomForestRegressor(n_estimators=50, random_state=42)\nopt = SpotOptim(\n fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n surrogate=rf,\n)\nprint(type(opt.surrogate).__name__)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nRandomForestRegressor\n```\n:::\n:::\n\n\n::: {#8f933c59 .cell execution_count=43}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom sklearn.ensemble import RandomForestRegressor\nfrom sklearn.gaussian_process import GaussianProcessRegressor\n# List of surrogates with selection probabilities\nsurrogates = [GaussianProcessRegressor(), RandomForestRegressor()]\nopt = SpotOptim(\n fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n surrogate=surrogates,\n prob_surrogate=[0.7, 0.3],\n)\nprint(opt._prob_surrogate)\nprint([type(s).__name__ for s in opt._surrogates_list])\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[0.7, 0.3]\n['GaussianProcessRegressor', 'RandomForestRegressor']\n```\n:::\n:::\n\n\n### inverse_transform_X { #spotoptim.SpotOptim.SpotOptim.inverse_transform_X }\n\n```python\nSpotOptim.SpotOptim.inverse_transform_X(X)\n```\n\nTransform parameter array from internal to original scale.\nConverts from transformed space (full dimension) to natural space (original).\nDoes NOT handle dimension expansion (un-mapping).\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-----------------------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Array in Transformed Space, shape (n_samples, n_features) | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Array in Natural Space |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#891c57e4 .cell execution_count=44}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nimport numpy as np\nspot = SpotOptim(fun=sphere, bounds=[(1, 10)], var_trans=['log10'])\nX_trans = np.array([[0], [1], [2]])\nspot.inverse_transform_X(X_trans)\n```\n\n::: {.cell-output .cell-output-display execution_count=44}\n```\narray([[ 1],\n [ 10],\n [100]])\n```\n:::\n:::\n\n\n### inverse_transform_value { #spotoptim.SpotOptim.SpotOptim.inverse_transform_value }\n\n```python\nSpotOptim.SpotOptim.inverse_transform_value(x, trans)\n```\n\nApply inverse transformation to a single float value.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|-----------------------------------------------|----------------------|------------|\n| x | [float](`float`) | Transformed value | _required_ |\n| trans | [Optional](`typing.Optional`)\\[[str](`str`)\\] | Transformation name. | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|------------------|----------------|\n| | [float](`float`) | Original value |\n\n#### Notes {.doc-section .doc-section-notes}\n\nSee also transform_value.\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#8105bf48 .cell execution_count=45}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nspot = SpotOptim(fun=sphere, bounds=[(1, 10)])\nspot.inverse_transform_value(10, 'log10')\nspot.inverse_transform_value(100, 'log(x)')\n```\n\n::: {.cell-output .cell-output-display execution_count=45}\n```\nnp.float64(2.6881171418161356e+43)\n```\n:::\n:::\n\n\n### load_experiment { #spotoptim.SpotOptim.SpotOptim.load_experiment }\n\n```python\nSpotOptim.SpotOptim.load_experiment(filename)\n```\n\nLoad experiment configuration from a pickle file.\n\n### load_result { #spotoptim.SpotOptim.SpotOptim.load_result }\n\n```python\nSpotOptim.SpotOptim.load_result(filename)\n```\n\nLoad complete optimization results from a pickle file.\n\n### map_to_factor_values { #spotoptim.SpotOptim.SpotOptim.map_to_factor_values }\n\n```python\nSpotOptim.SpotOptim.map_to_factor_values(X)\n```\n\nMap internal integer factor values back to string labels.\nFor factor variables, converts integer indices back to original string values.\nOther variable types remain unchanged.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-------------------------------------------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Design points with integer values for factors, shape (n_samples, n_features). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|--------------------------------------------------------------------------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Design points with factor integers replaced by string labels. Dtype will be object or string if mixed types are present. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#12de55cd .cell execution_count=46}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nimport numpy as np\nspot = SpotOptim(\n fun=sphere,\n bounds=[('red', 'blue'), (0, 10)]\n)\nspot.process_factor_bounds()\nX_int = np.array([[0, 5.0], [1, 8.0]])\nX_str = spot.map_to_factor_values(X_int)\nprint(X_str[0])\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n['red' 5.0]\n```\n:::\n:::\n\n\n### mo2so { #spotoptim.SpotOptim.SpotOptim.mo2so }\n\n```python\nSpotOptim.SpotOptim.mo2so(y_mo)\n```\n\nConvert multi-objective values to single-objective.\nConverts multi-objective values to a single-objective value by applying a user-defined\nfunction from `fun_mo2so`. If no user-defined function is given, the\nvalues in the first objective column are used.\n\nThis method is called after the objective function evaluation. It returns a 1D array\nwith the single-objective values.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|----------------------------------------------------------------------------------------------------------|------------|\n| y_mo | [ndarray](`ndarray`) | If multi-objective, shape (n_samples, n_objectives). If single-objective, shape (n_samples,). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|----------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Single-objective values, shape (n_samples,). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#2c784e73 .cell execution_count=47}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n\n# Multi-objective function\ndef mo_fun(X):\n return np.column_stack([\n np.sum(X**2, axis=1),\n np.sum((X-1)**2, axis=1)\n ])\n\n# Example 1: Default behavior (use first objective)\nopt1 = SpotOptim(\n fun=mo_fun,\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10,\n n_initial=5\n)\ny_mo = np.array([[1.0, 2.0], [3.0, 4.0]])\ny_so = opt1.mo2so(y_mo)\nprint(f\"Single-objective (default): {y_so}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nSingle-objective (default): [1. 3.]\n```\n:::\n:::\n\n\n::: {#dbcd70db .cell execution_count=48}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n# Example 2: Custom conversion function (sum of objectives)\ndef custom_mo2so(y_mo):\n return y_mo[:, 0] + y_mo[:, 1]\n\nopt2 = SpotOptim(\n fun=mo_fun,\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10,\n n_initial=5,\n fun_mo2so=custom_mo2so\n)\ny_so_custom = opt2.mo2so(y_mo)\nprint(f\"Single-objective (custom): {y_so_custom}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nSingle-objective (custom): [3. 7.]\n```\n:::\n:::\n\n\n### modify_bounds_based_on_var_type { #spotoptim.SpotOptim.SpotOptim.modify_bounds_based_on_var_type }\n\n```python\nSpotOptim.SpotOptim.modify_bounds_based_on_var_type()\n```\n\nModify bounds based on variable types.\nAdjusts bounds for each dimension according to its var_type:\n * 'int': Ensures bounds are integers (ceiling for lower, floor for upper)\n * 'factor': Bounds already set to (0, n_levels-1) by process_factor_bounds\n * 'float': Explicitly converts bounds to float\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Raises {.doc-section .doc-section-raises}\n\n| Name | Type | Description |\n|--------|----------------------------|--------------------------------------------|\n| | [ValueError](`ValueError`) | If an unsupported var_type is encountered. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#c06f9726 .cell execution_count=49}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nspot = SpotOptim(fun=lambda x: x, bounds=[(0.5, 10.5)], var_type=['int'])\nprint(spot.bounds)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[(1, 10)]\n```\n:::\n:::\n\n\n::: {#4aac4ba2 .cell execution_count=50}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nspot = SpotOptim(fun=lambda x: x, bounds=[(0, 10)], var_type=['float'])\nprint(spot.bounds)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[(0.0, 10.0)]\n```\n:::\n:::\n\n\n### optimize { #spotoptim.SpotOptim.SpotOptim.optimize }\n\n```python\nSpotOptim.SpotOptim.optimize(X0=None)\n```\n\nRun the optimization process. The optimization terminates when either the total function evaluations reach\n `max_iter` (including initial design), or the runtime exceeds max_time minutes. Input/Output spaces are\n * Input `X0`: Expected in Natural Space (original scale, physical units).\n * Output `result.x`: Returned in Natural Space.\n * Output `result.X`: Returned in Natural Space.\n * Internal Optimization: Performed in Transformed and Mapped Space.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-----------------------------------------------------------------------------------------------------------------------------------|-----------|\n| X0 | [ndarray](`ndarray`) | Initial design points in Natural Space, shape (n_initial, n_features). If None, generates space-filling design. Defaults to None. | `None` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|----------------|---------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| OptimizeResult | [OptimizeResult](`scipy.optimize.OptimizeResult`) | Optimization result with fields: * x: best point found in Natural Space * fun: best function value * nfev: number of function evaluations (including initial design) * nit: number of sequential optimization iterations (after initial design) * success: whether optimization succeeded * message: termination message indicating reason for stopping, including statistics (function value, iterations, evaluations) * X: all evaluated points in Natural Space * y: all function values |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#454516ca .cell execution_count=51}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n max_iter=10,\n seed=0,\n x0=np.array([0.1, -0.1]),\n verbose=True\n)\nresult = opt.optimize()\nprint(result.message.splitlines()[0])\nprint(\"Best point:\", result.x)\nprint(\"Best value:\", result.fun)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nStarting point x0 validated and processed successfully.\n Original scale: [ 0.1 -0.1]\n Internal scale: [ 0.1 -0.1]\nTensorBoard logging disabled\nIncluding 1 starting points from x0 in initial design.\nInitial best: f(x) = 0.020000\nIter 1 | Best: 0.020000 | Curr: 14.707944 | Rate: 0.00 | Evals: 60.0%\nOptimizer candidate 1/3 was duplicate/invalid.\nIter 2 | Best: 0.020000 | Curr: 0.020020 | Rate: 0.00 | Evals: 70.0%\nIter 3 | Best: 0.020000 | Curr: 0.322921 | Rate: 0.00 | Evals: 80.0%\nIter 4 | Best: 0.002244 | Rate: 0.25 | Evals: 90.0%\nIter 5 | Best: 0.002179 | Rate: 0.40 | Evals: 100.0%\nOptimization terminated: maximum evaluations (10) reached\nBest point: [0.04474339 0.01330855]\nBest value: 0.002179088112986503\n```\n:::\n:::\n\n\n### optimize_acquisition_func { #spotoptim.SpotOptim.SpotOptim.optimize_acquisition_func }\n\n```python\nSpotOptim.SpotOptim.optimize_acquisition_func()\n```\n\nOptimize the acquisition function to find the next point to evaluate.\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | The optimized point(s). If acquisition_fun_return_size == 1, returns 1D array of shape (n_features,). If acquisition_fun_return_size > 1, returns 2D array of shape (N, n_features), where N is min(acquisition_fun_return_size, population_size). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#dae4da08 .cell execution_count=52}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\ndef sphere(X):\n X = np.atleast_2d(X)\n return np.sum(X**2, axis=1)\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n max_iter=10,\n seed=0,\n)\nopt.optimize()\nx_next = opt.suggest_next_infill_point()\nprint(\"Next point to evaluate:\", x_next)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nNext point to evaluate: [[0.14356455 0.03793884]]\n```\n:::\n:::\n\n\n### optimize_sequential_run { #spotoptim.SpotOptim.SpotOptim.optimize_sequential_run }\n\n```python\nSpotOptim.SpotOptim.optimize_sequential_run(\n timeout_start,\n X0=None,\n y0_known=None,\n max_iter_override=None,\n)\n```\n\nPerform a single sequential optimization run.\nCalls _initialize_run, rm_initial_design_NA_values, check_size_initial_design, init_storage, get_best_xy_initial_design, and _run_sequential_loop.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|-------------------|---------------------------------------------------------------------------|------------------------------------------------------------------------|------------|\n| timeout_start | [float](`float`) | Start time for timeout. | _required_ |\n| X0 | [Optional](`typing.Optional`)\\[[np](`numpy`).[ndarray](`numpy.ndarray`)\\] | Initial design points in Natural Space, shape (n_initial, n_features). | `None` |\n| y0_known | [Optional](`typing.Optional`)\\[[float](`float`)\\] | Known best value for initial design. | `None` |\n| max_iter_override | [Optional](`typing.Optional`)\\[[int](`int`)\\] | Override for maximum number of iterations. | `None` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------------------------------------------------------------------------------------------|------------------------------------------------------------------------------|\n| | [Tuple](`typing.Tuple`)\\[[str](`str`), [OptimizeResult](`scipy.optimize.OptimizeResult`)\\] | Tuple[str, OptimizeResult]: Tuple containing status and optimization result. |\n\n#### Raises {.doc-section .doc-section-raises}\n\n| Name | Type | Description |\n|--------|----------------------------|----------------------------------------------------------------------------------------------------------------------------|\n| | [ValueError](`ValueError`) | If the initial design has no valid points after removing NaN/inf values, or if the initial design is too small to proceed. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#c730d81a .cell execution_count=53}\n``` {.python .cell-code}\nimport time\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nopt = SpotOptim(fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n max_iter=10,\n seed=0,\n verbose=True\n )\nstatus, result = opt.optimize_sequential_run(timeout_start=time.time())\nprint(status)\nprint(result.message.splitlines()[0])\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nTensorBoard logging disabled\nInitial best: f(x) = 8.463203\nIter 1 | Best: 8.463203 | Curr: 18.224245 | Rate: 0.00 | Evals: 60.0%\nIter 2 | Best: 8.412459 | Rate: 0.50 | Evals: 70.0%\nIter 3 | Best: 5.623369 | Rate: 0.67 | Evals: 80.0%\nIter 4 | Best: 2.902974 | Rate: 0.75 | Evals: 90.0%\nIter 5 | Best: 0.022050 | Rate: 0.80 | Evals: 100.0%\nFINISHED\nOptimization terminated: maximum evaluations (10) reached\n```\n:::\n:::\n\n\n### plot_importance { #spotoptim.SpotOptim.SpotOptim.plot_importance }\n\n```python\nSpotOptim.SpotOptim.plot_importance(threshold=0.0, figsize=(10, 6))\n```\n\nPlot variable importance.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|-----------|------------------|---------------------------------------------------|-----------|\n| threshold | [float](`float`) | Minimum importance percentage to include in plot. | `0.0` |\n| figsize | [tuple](`tuple`) | Figure size. | `(10, 6)` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#4d791470 .cell execution_count=54}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nimport numpy as np\n\ndef test_func(X):\n return 10 * X[:, 0]**2 + 0.1 * X[:, 1]**2\n\nopt = SpotOptim(\n fun=test_func,\n bounds=[(-5, 5), (-5, 5)],\n var_name=[\"x0\", \"x1\"],\n max_iter=10,\n n_initial=5,\n seed=42\n)\nopt.optimize()\nopt.plot_importance()\n```\n\n::: {.cell-output .cell-output-display}\n![](SpotOptim.SpotOptim_files/figure-html/cell-55-output-1.png){width=789 height=523}\n:::\n:::\n\n\n### plot_important_hyperparameter_contour { #spotoptim.SpotOptim.SpotOptim.plot_important_hyperparameter_contour }\n\n```python\nSpotOptim.SpotOptim.plot_important_hyperparameter_contour(\n max_imp=3,\n show=True,\n alpha=0.8,\n cmap='jet',\n num=100,\n add_points=True,\n grid_visible=True,\n contour_levels=30,\n figsize=(12, 10),\n)\n```\n\nPlot surrogate contours using spotoptim.plot.visualization.plot_important_hyperparameter_contour.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|----------------|------------------|----------------------------------------------------------|------------|\n| max_imp | [int](`int`) | The maximum number of important hyperparameters to plot. | `3` |\n| show | [bool](`bool`) | Whether to show the plot. | `True` |\n| alpha | [float](`float`) | The alpha value for the plot. | `0.8` |\n| cmap | [str](`str`) | The colormap to use. | `'jet'` |\n| num | [int](`int`) | The number of points to use for the plot. | `100` |\n| add_points | [bool](`bool`) | Whether to add points to the plot. | `True` |\n| grid_visible | [bool](`bool`) | Whether to show the grid. | `True` |\n| contour_levels | [int](`int`) | The number of contour levels to use. | `30` |\n| figsize | [tuple](`tuple`) | The size of the plot. | `(12, 10)` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#eea90861 .cell execution_count=55}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nimport numpy as np\n\ndef test_func(X):\n return 10 * X[:, 0]**2 + 0.1 * X[:, 1]**2\n\n# 2-D problem: max_imp must not exceed n_dim (2)\nopt = SpotOptim(\n fun=test_func,\n bounds=[(-5, 5), (-5, 5)],\n var_name=[\"x0\", \"x1\"],\n max_iter=10,\n n_initial=5,\n seed=42\n)\nopt.optimize()\nopt.plot_important_hyperparameter_contour(max_imp=2)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nPlotting surrogate contours for top 2 most important parameters:\n x0: importance = 73.24% (type: float)\n x1: importance = 26.76% (type: float)\n\nGenerating 1 surrogate plots...\n Plotting x0 vs x1\n```\n:::\n\n::: {.cell-output .cell-output-display}\n![](SpotOptim.SpotOptim_files/figure-html/cell-56-output-2.png){width=1113 height=950}\n:::\n:::\n\n\n### plot_parameter_scatter { #spotoptim.SpotOptim.SpotOptim.plot_parameter_scatter }\n\n```python\nSpotOptim.SpotOptim.plot_parameter_scatter(\n result=None,\n show=True,\n figsize=(12, 10),\n ylabel='Objective Value',\n cmap='viridis_r',\n show_correlation=False,\n log_y=False,\n)\n```\n\nPlot parameter distributions showing relationship between each parameter and objective.\nCreates a grid of scatter plots, one for each parameter dimension, showing how\nthe objective function value varies with each parameter. The best configuration\nis marked with a red star. Parameters with log-scale transformations (var_trans)\nare automatically displayed on a log x-axis.\nOptionally displays Spearman correlation coefficients in plot titles for\nsensitivity analysis. For factor (categorical) variables, correlation is not\ncomputed and they are displayed with discrete positions on the x-axis.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|------------------|---------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|---------------------|\n| result | [OptimizeResult](`scipy.optimize.OptimizeResult`) | Optimization result containing best parameters. If None, uses the best found values from self.best_x_ and self.best_y_. | `None` |\n| show | [bool](`bool`) | Whether to display the plot. Defaults to True. | `True` |\n| figsize | [tuple](`tuple`) | Figure size as (width, height). Defaults to (12, 10). | `(12, 10)` |\n| ylabel | [str](`str`) | Label for y-axis. Defaults to \"Objective Value\". | `'Objective Value'` |\n| cmap | [str](`str`) | Colormap for scatter plot. Defaults to \"viridis_r\". | `'viridis_r'` |\n| show_correlation | [bool](`bool`) | Whether to compute and display Spearman correlation coefficients in plot titles. Requires scipy. Defaults to False. | `False` |\n| log_y | [bool](`bool`) | Whether to use logarithmic scale for y-axis. Defaults to False. | `False` |\n\n#### Raises {.doc-section .doc-section-raises}\n\n| Name | Type | Description |\n|--------|----------------------------|---------------------------------------|\n| | [ValueError](`ValueError`) | If no optimization data is available. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#a1313c2d .cell execution_count=56}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\ndef objective(X):\n X = np.atleast_2d(X)\n return np.sum(X**2, axis=1)\nopt = SpotOptim(\n fun=objective,\n bounds=[(-5, 5), (-5, 5), (-5, 5), (-5, 5)],\n var_name=[\"x0\", \"x1\", \"x2\", \"x3\"],\n max_iter=10,\n n_initial=5,\n seed=42\n)\nresult = opt.optimize()\n# Plot parameter distributions\nopt.plot_parameter_scatter(result)\n# Plot with custom settings\nopt.plot_parameter_scatter(result, cmap=\"plasma\", ylabel=\"Error\")\n```\n\n::: {.cell-output .cell-output-display}\n![](SpotOptim.SpotOptim_files/figure-html/cell-57-output-1.png){width=1141 height=949}\n:::\n\n::: {.cell-output .cell-output-display}\n![](SpotOptim.SpotOptim_files/figure-html/cell-57-output-2.png){width=1141 height=949}\n:::\n:::\n\n\n### plot_progress { #spotoptim.SpotOptim.SpotOptim.plot_progress }\n\n```python\nSpotOptim.SpotOptim.plot_progress(\n show=True,\n log_y=False,\n figsize=(10, 6),\n ylabel='Objective Value',\n mo=False,\n)\n```\n\nPlot optimization progress using spotoptim.plot.visualization.plot_progress.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|---------|------------------|----------------------------------------------|---------------------|\n| show | [bool](`bool`) | Whether to show the plot. | `True` |\n| log_y | [bool](`bool`) | Whether to use a logarithmic y-axis. | `False` |\n| figsize | [tuple](`tuple`) | The size of the plot. | `(10, 6)` |\n| ylabel | [str](`str`) | The label for the y-axis. | `'Objective Value'` |\n| mo | [bool](`bool`) | Whether the optimization is multi-objective. | `False` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#2563ab91 .cell execution_count=57}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nimport numpy as np\n\ndef test_func(X):\n return 10 * X[:, 0]**2 + 0.1 * X[:, 1]**2\n\nopt = SpotOptim(\n fun=test_func,\n bounds=[(-5, 5), (-5, 5)],\n var_name=[\"x0\", \"x1\"],\n max_iter=10,\n n_initial=5,\n seed=42\n)\nopt.optimize()\nopt.plot_progress()\n```\n\n::: {.cell-output .cell-output-display}\n![](SpotOptim.SpotOptim_files/figure-html/cell-58-output-1.png){width=949 height=565}\n:::\n:::\n\n\n### plot_surrogate { #spotoptim.SpotOptim.SpotOptim.plot_surrogate }\n\n```python\nSpotOptim.SpotOptim.plot_surrogate(\n i=0,\n j=1,\n show=True,\n alpha=0.8,\n var_name=None,\n cmap='jet',\n num=100,\n vmin=None,\n vmax=None,\n add_points=True,\n grid_visible=True,\n contour_levels=30,\n figsize=(12, 10),\n)\n```\n\nPlot the surrogate model for two dimensions.\nDelegates to spotoptim.plot.visualization.plot_surrogate.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|----------------|------------------------------------------------------------------------|-------------------------------------------|------------|\n| i | [int](`int`) | The index of the first dimension. | `0` |\n| j | [int](`int`) | The index of the second dimension. | `1` |\n| show | [bool](`bool`) | Whether to show the plot. | `True` |\n| alpha | [float](`float`) | The alpha value for the plot. | `0.8` |\n| var_name | [Optional](`typing.Optional`)\\[[List](`typing.List`)\\[[str](`str`)\\]\\] | The names of the variables. | `None` |\n| cmap | [str](`str`) | The colormap to use. | `'jet'` |\n| num | [int](`int`) | The number of points to use for the plot. | `100` |\n| vmin | [Optional](`typing.Optional`)\\[[float](`float`)\\] | The minimum value for the plot. | `None` |\n| vmax | [Optional](`typing.Optional`)\\[[float](`float`)\\] | The maximum value for the plot. | `None` |\n| add_points | [bool](`bool`) | Whether to add points to the plot. | `True` |\n| grid_visible | [bool](`bool`) | Whether to show the grid. | `True` |\n| contour_levels | [int](`int`) | The number of contour levels to use. | `30` |\n| figsize | [tuple](`tuple`) | The size of the plot. | `(12, 10)` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#c9e8fc9b .cell execution_count=58}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nimport numpy as np\n\ndef test_func(X):\n return 10 * X[:, 0]**2 + 0.1 * X[:, 1]**2\n\nopt = SpotOptim(\n fun=test_func,\n bounds=[(-5, 5), (-5, 5)],\n var_name=[\"x0\", \"x1\"],\n max_iter=10,\n n_initial=5,\n seed=42\n)\nopt.optimize()\nopt.plot_surrogate()\n```\n\n::: {.cell-output .cell-output-display}\n![](SpotOptim.SpotOptim_files/figure-html/cell-59-output-1.png){width=1113 height=950}\n:::\n:::\n\n\n### print_best { #spotoptim.SpotOptim.SpotOptim.print_best }\n\n```python\nSpotOptim.SpotOptim.print_best(\n result=None,\n transformations=None,\n show_name=True,\n precision=4,\n)\n```\n\nPrint the best solution found during optimization.\nThis method displays the best hyperparameters and objective value in a\nformatted table. It supports custom transformations for parameters\n(e.g., converting log-scale values back to original scale).\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|-----------------|---------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|\n| result | [OptimizeResult](`scipy.optimize.OptimizeResult`) | Optimization result object from optimize(). If None, uses the stored best values from the optimizer. Defaults to None. | `None` |\n| transformations | list of callable | List of transformation functions to apply to each parameter. Each function takes a single value and returns the transformed value. Use None for parameters that don't need transformation. Length must match number of dimensions. Example: [None, None, lambda x: 10**x] to convert the 3rd parameter from log10 scale. Defaults to None. | `None` |\n| show_name | [bool](`bool`) | Whether to display variable names. If False, uses generic names like 'x0', 'x1', etc. Defaults to True. | `True` |\n| precision | [int](`int`) | Number of decimal places for floating point values. Defaults to 4. | `4` |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#e0d59d96 .cell execution_count=59}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\n\ndef sphere(X):\n X = np.atleast_2d(X)\n return np.sum(X**2, axis=1)\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n var_name=[\"x1\", \"x2\"],\n max_iter=10,\n n_initial=5\n)\nresult = opt.optimize()\nopt.print_best(result)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n\nBest Solution Found:\n--------------------------------------------------\n x1: -0.0390\n x2: -0.0397\n Objective Value: 0.0031\n Total Evaluations: 10\n```\n:::\n:::\n\n\n### print_results { #spotoptim.SpotOptim.SpotOptim.print_results }\n\n```python\nSpotOptim.SpotOptim.print_results(*args, **kwargs)\n```\n\nAlias for print(get_results_table()) for compatibility.\nPrints the table.\n\n### process_factor_bounds { #spotoptim.SpotOptim.SpotOptim.process_factor_bounds }\n\n```python\nSpotOptim.SpotOptim.process_factor_bounds()\n```\n\nProcess `bounds` to handle factor variables.\nFor dimensions with tuple bounds (factor variables), creates internal\ninteger mappings and replaces bounds with (0, n_levels-1).\nStores mappings in `self._factor_maps`: {dim_idx: {int_val: str_val}}\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Raises {.doc-section .doc-section-raises}\n\n| Name | Type | Description |\n|--------|----------------------------|------------------------------------|\n| | [ValueError](`ValueError`) | If bounds are invalidly formatted. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#22201570 .cell execution_count=60}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nspot = SpotOptim(fun=lambda x: x, bounds=[('red', 'green', 'blue'), (0, 10)])\nspot.process_factor_bounds()\nprint(f\"spot.bounds (should be [(0, 2), (0, 10)]): {spot.bounds}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nspot.bounds (should be [(0, 2), (0, 10)]): [(0, 2), (0, 10)]\n```\n:::\n:::\n\n\n### reinitialize_components { #spotoptim.SpotOptim.SpotOptim.reinitialize_components }\n\n```python\nSpotOptim.SpotOptim.reinitialize_components()\n```\n\nReinitialize components that were excluded during pickling.\n\n### remove_nan { #spotoptim.SpotOptim.SpotOptim.remove_nan }\n\n```python\nSpotOptim.SpotOptim.remove_nan(X, y, stop_on_zero_return=True)\n```\n\nRemove rows where y contains NaN or inf values.\nUsed in the optimize() method after function evaluations.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|---------------------|----------------------|---------------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Design matrix, shape (n_samples, n_features). | _required_ |\n| y | [ndarray](`ndarray`) | Objective values, shape (n_samples,). | _required_ |\n| stop_on_zero_return | [bool](`bool`) | If True, raise error when all values are removed. | `True` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|------------------|-----------------------------------------------|\n| tuple | [tuple](`tuple`) | (X_clean, y_clean) with NaN/inf rows removed. |\n\n#### Raises {.doc-section .doc-section-raises}\n\n| Name | Type | Description |\n|--------|----------------------------|------------------------------------------------------------|\n| | [ValueError](`ValueError`) | If all values are NaN/inf and stop_on_zero_return is True. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#47fe8e9d .cell execution_count=61}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nopt = SpotOptim(fun=sphere, bounds=[(-5, 5)])\nX = np.array([[1, 2], [3, 4], [5, 6]])\ny = np.array([1.0, np.nan, np.inf])\nX_clean, y_clean = opt.remove_nan(X, y, stop_on_zero_return=False)\nprint(\"Clean X:\", X_clean)\nprint(\"Clean y:\", y_clean)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nClean X: [[1 2]]\nClean y: [1.]\n```\n:::\n:::\n\n\n### repair_natural_X { #spotoptim.SpotOptim.SpotOptim.repair_natural_X }\n\n```python\nSpotOptim.SpotOptim.repair_natural_X(X)\n```\n\nEnforce integrality and declared bounds in natural (original) space.\n\nInteger dimensions are rounded to the nearest integer; integer\ndimensions with an active transform are additionally clipped to their\ndeclared natural bounds, because the inverse transform of a continuous\ninternal proposal can land marginally outside them (issue #87). Float\nand factor dimensions pass through unchanged.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|--------------------------------------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Points in natural scale, shape (n_samples, n_features) or (n_features,). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|---------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Repaired copy of ``X`` (same shape as the input). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#ecfea8ec .cell execution_count=62}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(10, 5000)],\n var_type=['int'],\n var_trans=['log10'])\nX_nat = np.array([[4999.99999], [10.4], [5000.2]])\nprint(opt.repair_natural_X(X_nat))\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[[5000.]\n [ 10.]\n [5000.]]\n```\n:::\n:::\n\n\n### repair_non_numeric { #spotoptim.SpotOptim.SpotOptim.repair_non_numeric }\n\n```python\nSpotOptim.SpotOptim.repair_non_numeric(X, var_type)\n```\n\nRound non-numeric values to integers based on variable type.\nThis method applies rounding to variables that are not continuous:\n * 'float': No rounding (continuous values)\n * 'int': Rounded to integers\n * 'factor': Rounded to integers (representing categorical values)\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|----------|----------------------|------------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | X array with values to potentially round. | _required_ |\n| var_type | list of str | List with type information for each dimension. | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|---------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | X array with non-continuous values rounded to integers. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#5de46ef4 .cell execution_count=63}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n var_type=['int', 'float'])\nX = np.array([[1.2, 2.5], [3.7, 4.1], [5.9, 6.8]])\nX_repaired = opt.repair_non_numeric(X, opt.var_type)\nprint(X_repaired)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[[1. 2.5]\n [4. 4.1]\n [6. 6.8]]\n```\n:::\n:::\n\n\n### rm_initial_design_NA_values { #spotoptim.SpotOptim.SpotOptim.rm_initial_design_NA_values }\n\n```python\nSpotOptim.SpotOptim.rm_initial_design_NA_values(X0, y0)\n```\n\nRemove NaN/inf values from initial design evaluations.\nThis method filters out design points that returned NaN or inf values\nduring initial evaluation. Unlike the sequential optimization phase where\npenalties are applied, initial design points with invalid values are\nsimply removed.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-------------------------------------------------------------------------|------------|\n| X0 | [ndarray](`ndarray`) | Initial design points in internal scale, shape (n_samples, n_features). | _required_ |\n| y0 | [ndarray](`ndarray`) | Function values at X0, shape (n_samples,). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|-----------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| | [Tuple](`typing.Tuple`)\\[[np](`numpy`).[ndarray](`numpy.ndarray`), [np](`numpy`).[ndarray](`numpy.ndarray`), [int](`int`)\\] | Tuple[ndarray, ndarray, int]: Filtered (X0, y0) with only finite values and the original count before filtering. X0 has shape (n_valid, n_features), y0 has shape (n_valid,), and the int is the original size. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#44d347ea .cell execution_count=64}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=10\n)\nX0 = np.array([[1, 2], [3, 4], [5, 6]])\ny0 = np.array([5.0, np.nan, np.inf])\nX0_clean, y0_clean, n_eval = opt.rm_initial_design_NA_values(X0, y0)\nprint(X0_clean.shape) # (1, 2)\nprint(y0_clean) # array([5.])\nprint(n_eval) # 3\n# All valid values - no filtering\nX0 = np.array([[1, 2], [3, 4]])\ny0 = np.array([5.0, 25.0])\nX0_clean, y0_clean, n_eval = opt.rm_initial_design_NA_values(X0, y0)\nprint(X0_clean.shape) # (2, 2)\nprint(n_eval) # 2\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n(1, 2)\n[5.]\n3\n(2, 2)\n2\n```\n:::\n:::\n\n\n### save_experiment { #spotoptim.SpotOptim.SpotOptim.save_experiment }\n\n```python\nSpotOptim.SpotOptim.save_experiment(\n filename=None,\n prefix='experiment',\n path=None,\n overwrite=True,\n unpickleables='all',\n verbosity=0,\n)\n```\n\nSave experiment configuration to a pickle file.\n\n### save_result { #spotoptim.SpotOptim.SpotOptim.save_result }\n\n```python\nSpotOptim.SpotOptim.save_result(\n filename=None,\n prefix='result',\n path=None,\n overwrite=True,\n verbosity=0,\n)\n```\n\nSave complete optimization results to a pickle file.\n\n### select_new { #spotoptim.SpotOptim.SpotOptim.select_new }\n\n```python\nSpotOptim.SpotOptim.select_new(A, X, tolerance=0)\n```\n\nSelect rows from A that are not in X.\nUsed in suggest_next_infill_point() to avoid duplicate evaluations.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|-----------|----------------------|------------------------------------------------|------------|\n| A | [ndarray](`ndarray`) | Array with new values. | _required_ |\n| X | [ndarray](`ndarray`) | Array with known values. | _required_ |\n| tolerance | [float](`float`) | Tolerance value for comparison. Defaults to 0. | `0` |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|---------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|\n| tuple | [Tuple](`typing.Tuple`)\\[[np](`numpy`).[ndarray](`numpy.ndarray`), [np](`numpy`).[ndarray](`numpy.ndarray`)\\] | A tuple containing: * ndarray: Array with unknown (new) values. * ndarray: Array with True if value is new, otherwise False. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#babb85c6 .cell execution_count=65}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\ndef sphere(X):\n X = np.atleast_2d(X)\n return np.sum(X**2, axis=1)\nopt = SpotOptim(fun=sphere, bounds=[(-5, 5)])\nA = np.array([[1, 2], [3, 4], [5, 6]])\nX = np.array([[3, 4], [7, 8]])\nnew_A, is_new = opt.select_new(A, X)\nprint(\"New A:\", new_A)\nprint(\"Is new:\", is_new)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nNew A: [[1 2]\n [5 6]]\nIs new: [ True False True]\n```\n:::\n:::\n\n\n### sensitivity_spearman { #spotoptim.SpotOptim.SpotOptim.sensitivity_spearman }\n\n```python\nSpotOptim.SpotOptim.sensitivity_spearman()\n```\n\nCompute and print Spearman correlation between parameters and objective values.\nThis method analyzes the sensitivity of the objective function to each\nhyperparameter by computing Spearman rank correlations. For categorical\n(factor) variables, correlation is not computed as they require visual\ninspection instead.\nThe method automatically handles different parameter types:\n * Integer/float parameters: Direct correlation with objective values\n * Log-transformed parameters (log10, log, ln): Correlation in log-space\n * Factor (categorical) parameters: Skipped with informative message\nSignificance levels:\n * ***: p < 0.001 (highly significant)\n * **: p < 0.01 (significant)\n * *: p < 0.05 (marginally significant)\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#4ec29883 .cell execution_count=66}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nimport numpy as np\n\ndef test_func(X):\n # x0 has strong effect, x1 has weak effect\n X = np.atleast_2d(X)\n return 10 * X[:, 0]**2 + 0.1 * X[:, 1]**2\n\nopt = SpotOptim(\n fun=test_func,\n bounds=[(-5, 5), (-5, 5)],\n var_name=[\"x0\", \"x1\"],\n max_iter=10,\n n_initial=5,\n seed=42\n)\nopt.optimize()\nopt.sensitivity_spearman()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n\nSensitivity Analysis (Spearman Correlation):\n--------------------------------------------------\n x0 : -0.188 (p=0.603)\n x1 : -0.297 (p=0.405)\n```\n:::\n:::\n\n\n#### Note {.doc-section .doc-section-note}\n\nOnly meaningful after optimize() has been called with sufficient evaluations.\n\n### set_seed { #spotoptim.SpotOptim.SpotOptim.set_seed }\n\n```python\nSpotOptim.SpotOptim.set_seed()\n```\n\nSet global random seeds for reproducibility.\nSets seeds for:\n * random\n * numpy.random\n * torch (cpu and cuda)\nOnly performs actions if self.seed is not None.\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#7289336f .cell execution_count=67}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nimport numpy as np\nspot = SpotOptim(fun=lambda x: x, bounds=[(0, 1)], seed=42)\nspot.set_seed()\nnp.random.rand() # Should be deterministic\n```\n\n::: {.cell-output .cell-output-display execution_count=67}\n```\n0.3745401188473625\n```\n:::\n:::\n\n\n### setup_dimension_reduction { #spotoptim.SpotOptim.SpotOptim.setup_dimension_reduction }\n\n```python\nSpotOptim.SpotOptim.setup_dimension_reduction()\n```\n\nSet up dimension reduction by identifying fixed dimensions.\nIdentifies dimensions where lower and upper bounds are equal in Transformed Space.\nReduces `self.bounds`, `self.lower`, `self.upper`, etc., to the Mapped Space\n(active variables only).\nThe resulting `self.bounds` defines the Transformed and Mapped Space used\nfor optimization.\nThis method identifies variables that are fixed (constant) and excludes them\nfrom the optimization process. It stores:\n * Original bounds and metadata in `all_*` attributes\n * Boolean mask of fixed dimensions in `ident`\n * Reduced bounds, types, and names for optimization\n * `red_dim` flag indicating if reduction occurred\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#9c6c8936 .cell execution_count=68}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nspot = SpotOptim(fun=lambda x: x, bounds=[(1, 10), (5, 5), (0, 1)])\nprint(\"Original lower bounds:\", spot.all_lower)\nprint(\"Original upper bounds:\", spot.all_upper)\nprint(\"Fixed dimensions mask:\", spot.ident)\nprint(\"Reduced lower bounds:\", spot.lower)\nprint(\"Reduced upper bounds:\", spot.upper)\nprint(\"Reduced variable names:\", spot.var_name)\nprint(\"Is dimension reduction active?\", spot.red_dim)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nOriginal lower bounds: [1. 5. 0.]\nOriginal upper bounds: [10. 5. 1.]\nFixed dimensions mask: [False True False]\nReduced lower bounds: [1. 0.]\nReduced upper bounds: [10. 1.]\nReduced variable names: ['x0', 'x2']\nIs dimension reduction active? True\n```\n:::\n:::\n\n\n### store_mo { #spotoptim.SpotOptim.SpotOptim.store_mo }\n\n```python\nSpotOptim.SpotOptim.store_mo(y_mo)\n```\n\nStore multi-objective values in self.y_mo.\nIf multi-objective values are present (ndim==2), they are stored in self.y_mo.\nNew values are appended to existing ones. For single-objective problems,\nself.y_mo remains None.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|----------------------------------------------------------------------------------------------------------|------------|\n| y_mo | [ndarray](`ndarray`) | If multi-objective, shape (n_samples, n_objectives). If single-objective, shape (n_samples,). | _required_ |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#7474573f .cell execution_count=69}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(\n fun=lambda X: np.column_stack([\n np.sum(X**2, axis=1),\n np.sum((X-1)**2, axis=1)\n ]),\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10,\n n_initial=5\n)\ny_mo_1 = np.array([[1.0, 2.0], [3.0, 4.0]])\nopt.store_mo(y_mo_1)\nprint(f\"y_mo after first call: {opt.y_mo}\")\ny_mo_2 = np.array([[5.0, 6.0], [7.0, 8.0]])\nopt.store_mo(y_mo_2)\nprint(f\"y_mo after second call: {opt.y_mo}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\ny_mo after first call: [[1. 2.]\n [3. 4.]]\ny_mo after second call: [[1. 2.]\n [3. 4.]\n [5. 6.]\n [7. 8.]]\n```\n:::\n:::\n\n\n### suggest_next_infill_point { #spotoptim.SpotOptim.SpotOptim.suggest_next_infill_point }\n\n```python\nSpotOptim.SpotOptim.suggest_next_infill_point()\n```\n\nSuggest next point to evaluate (dispatcher).\nUsed in both sequential and parallel optimization loops. This method orchestrates\nthe process of generating candidate points from the acquisition function optimizer,\nhandling any failures in the acquisition process with a fallback strategy, and\nensuring that the returned point(s) are valid and ready for evaluation.\nThe returned point is in the Transformed and Mapped Space (Internal Optimization Space).\nThis means:\n 1. Transformations (e.g., log, sqrt) have been applied.\n 2. Dimension reduction has been applied (fixed variables removed).\nProcess:\n 1. Try candidates from acquisition function optimizer.\n 2. Handle acquisition failure (fallback).\n 3. Return last attempt if all fails.\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|------------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Next point(s) to evaluate in Transformed and Mapped Space. |\n| | [np](`numpy`).[ndarray](`numpy.ndarray`) | Shape is (n_infill_points, n_features). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#13986445 .cell execution_count=70}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\ndef sphere(X):\n X = np.atleast_2d(X)\n return np.sum(X**2, axis=1)\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n n_infill_points=2\n)\n# Need to initialize optimization state (X_, y_, surrogate)\n# Normally done inside optimize()\nnp.random.seed(0)\nopt.X_ = np.random.rand(10, 2)\nopt.y_ = np.random.rand(10)\nopt.fit_surrogate(opt.X_, opt.y_)\nx_next = opt.suggest_next_infill_point()\nx_next.shape\n```\n\n::: {.cell-output .cell-output-display execution_count=70}\n```\n(2, 2)\n```\n:::\n:::\n\n\n### to_all_dim { #spotoptim.SpotOptim.SpotOptim.to_all_dim }\n\n```python\nSpotOptim.SpotOptim.to_all_dim(X_red)\n```\n\nExpand reduced-dimensional points to full-dimensional representation.\nThis method restores points from the reduced optimization space to the\nfull-dimensional space by inserting fixed values for constant dimensions.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-------------------------------------------------------------|------------|\n| X_red | [ndarray](`ndarray`) | Points in reduced space, shape (n_samples, n_reduced_dims). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|-----------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Points in full space, shape (n_samples, n_original_dims). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#88687817 .cell execution_count=71}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\ndef sphere(X):\n X = np.atleast_2d(X)\n return np.sum(X**2, axis=1)\n# Create problem with one fixed dimension\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (2, 2), (-5, 5)], # x1 is fixed at 2\n max_iter=10,\n n_initial=3\n)\nX_red = np.array([[1.0, 3.0], [2.0, 4.0]]) # Only x0 and x2\nX_full = opt.to_all_dim(X_red)\nprint(X_full.shape)\nprint(X_full[:, 1])\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n(2, 3)\n[2. 2.]\n```\n:::\n:::\n\n\n### to_red_dim { #spotoptim.SpotOptim.SpotOptim.to_red_dim }\n\n```python\nSpotOptim.SpotOptim.to_red_dim(X_full)\n```\n\nReduce full-dimensional points to optimization space.\nThis method removes fixed dimensions from full-dimensional points,\nextracting only the varying dimensions used in optimization.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-----------------------------------------------------------|------------|\n| X_full | [ndarray](`ndarray`) | Points in full space, shape (n_samples, n_original_dims). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|-------------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Points in reduced space, shape (n_samples, n_reduced_dims). |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#cd589cf0 .cell execution_count=72}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\ndef sphere(X):\n X = np.atleast_2d(X)\n return np.sum(X**2, axis=1)\n# Create problem with one fixed dimension\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (2, 2), (-5, 5)], # x1 is fixed at 2\n max_iter=10,\n n_initial=3\n)\nX_full = np.array([[1.0, 2.0, 3.0], [4.0, 2.0, 5.0]])\nX_red = opt.to_red_dim(X_full)\nprint(X_red.shape)\nprint(np.array_equal(X_red, np.array([[1.0, 3.0], [4.0, 5.0]])))\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n(2, 2)\nTrue\n```\n:::\n:::\n\n\n### transform_X { #spotoptim.SpotOptim.SpotOptim.transform_X }\n\n```python\nSpotOptim.SpotOptim.transform_X(X)\n```\n\nTransform parameter array from original (natural) to internal scale.\nConverts from natural space (Original) to transformed space (full dimension).\nDoes NOT handle dimension reduction (mapping).\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-------------------------------------------------------|------------|\n| X | [ndarray](`ndarray`) | Array in Natural Space, shape (n_samples, n_features) | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|---------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Array in Transformed Space (Full Dimension) |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#a95abe68 .cell execution_count=73}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nimport numpy as np\nfrom spotoptim.function import sphere\nspot = SpotOptim(fun=sphere, bounds=[(1, 10)], var_trans=['log10'])\nX_orig = np.array([[1], [10], [100]])\nspot.transform_X(X_orig)\n```\n\n::: {.cell-output .cell-output-display execution_count=73}\n```\narray([[0],\n [1],\n [2]])\n```\n:::\n:::\n\n\n### transform_bounds { #spotoptim.SpotOptim.SpotOptim.transform_bounds }\n\n```python\nSpotOptim.SpotOptim.transform_bounds()\n```\n\nTransform bounds from original to internal scale.\nUpdates `self.bounds` (and `self.lower`, `self.upper`) from Natural Space\nto Transformed Space. Calls `transform_value` for each bound and converts\nnumpy types to Python native types (`int` or `float` based on `var_type`).\nHandles also reversed bounds, e.g., as an effect of `reciprocal` transformation.\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Notes {.doc-section .doc-section-notes}\n\nUses settings in `self.var_trans`. It can be one of `id`, `log10`, `log`, `ln`, `sqrt`,\n`exp`, `square`, `cube`, `inv`, `reciprocal`, or `None`. Also supports dynamic\nstrings like `log(x)`, `sqrt(x)`, `pow(x, p)`.\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#2854f710 .cell execution_count=74}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nimport numpy as np\nspot = SpotOptim(fun=sphere, bounds=[(1, 10), (0.1, 100)])\nspot.var_trans = ['log10', 'sqrt']\nspot.transform_bounds()\nprint(f\"spot.bounds: {spot.bounds}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nspot.bounds: [(0.0, 1.0), (0.31622776601683794, 10.0)]\n```\n:::\n:::\n\n\n### transform_value { #spotoptim.SpotOptim.SpotOptim.transform_value }\n\n```python\nSpotOptim.SpotOptim.transform_value(x, trans)\n```\n\nApply transformation to a single float value.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|-----------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|\n| x | [float](`float`) | Value to transform | _required_ |\n| trans | [Optional](`typing.Optional`)\\[[str](`str`)\\] | Transformation name. Can be one of `id`, `log10`, `log`, `ln`, `sqrt`, `exp`, `square`, `cube`, `inv`, `reciprocal`, or `None`. Also supports dynamic strings like `log(x)`, `sqrt(x)`, `pow(x, p)`. | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|------------------|-------------------|\n| | [float](`float`) | Transformed value |\n\n#### Raises {.doc-section .doc-section-raises}\n\n| Name | Type | Description |\n|--------|----------------------------|--------------------------------------------|\n| | [TypeError](`TypeError`) | If x is not a float. |\n| | [ValueError](`ValueError`) | If an unknown transformation is specified. |\n\n#### Notes {.doc-section .doc-section-notes}\n\nSee also inverse_transform_value.\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#e46902b3 .cell execution_count=75}\n``` {.python .cell-code}\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nspot = SpotOptim(fun=sphere, bounds=[(1, 10)])\nspot.transform_value(10, 'log10')\nspot.transform_value(100, 'log(x)')\n```\n\n::: {.cell-output .cell-output-display execution_count=75}\n```\nnp.float64(4.605170185988092)\n```\n:::\n:::\n\n\n### update_repeats_infill_points { #spotoptim.SpotOptim.SpotOptim.update_repeats_infill_points }\n\n```python\nSpotOptim.SpotOptim.update_repeats_infill_points(x_next)\n```\n\nRepeat infill point for noisy function evaluation. Used in the sequential_loop.\nFor noisy objective functions (repeats_surrogate > 1), creates multiple\ncopies of the suggested point for repeated evaluation. Otherwise, returns\nthe point in 2D array format.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|----------------------------------------------|------------|\n| x_next | [ndarray](`ndarray`) | Next point to evaluate, shape (n_features,). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|---------------------------------------------------------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Points to evaluate, shape (repeats_surrogate, n_features) or (1, n_features) if repeats_surrogate == 1. |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#fde58fee .cell execution_count=76}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere, noisy_sphere\n# Without repeats\n\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n repeats_surrogate=1\n)\nx_next = np.array([1.0, 2.0])\nx_repeated = opt.update_repeats_infill_points(x_next)\nprint(x_repeated.shape)\n\n# With repeats for noisy function\nopt_noisy = SpotOptim(\n fun=noisy_sphere,\n bounds=[(-5, 5), (-5, 5)],\n repeats_surrogate=3\n)\nx_next = np.array([1.0, 2.0])\nx_repeated = opt_noisy.update_repeats_infill_points(x_next)\nprint(x_repeated.shape)\n# All three copies should be identical\nnp.all(x_repeated[0] == x_repeated[1])\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n(1, 2)\n(3, 2)\n```\n:::\n\n::: {.cell-output .cell-output-display execution_count=76}\n```\nnp.True_\n```\n:::\n:::\n\n\n### update_stats { #spotoptim.SpotOptim.SpotOptim.update_stats }\n\n```python\nSpotOptim.SpotOptim.update_stats()\n```\n\nUpdate optimization statistics.\nUpdates various statistics related to the optimization progress:\n * `min_y`: Minimum y value found so far\n * `min_X`: X value corresponding to minimum y\n * `counter`: Total number of function evaluations\n\n#### Notes {.doc-section .doc-section-notes}\n\n`success_rate` is updated separately via `update_success_rate()` method, which is called after each batch of function evaluations.\n\nIf \"noise\" is True (`repeats_initial > 1` or `repeats_surrogate > 1`), additionally computes:\n * `mean_X`: Unique design points (aggregated from repeated evaluations)\n * `mean_y`: Mean y values per design point\n * `var_y`: Variance of y values per design point\n * `min_mean_X`: X value of the best mean y value\n * `min_mean_y`: Best mean y value\n * `min_var_y`: Variance of the best mean y value\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#a450547a .cell execution_count=77}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\n# Without noise\nopt = SpotOptim(fun=sphere,\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10, n_initial=5)\nopt.optimize()\nprint(\"SpotOptim stats without noise:\")\nprint(f\"opt.X_: {opt.X_}\")\nprint(f\"opt.y_: {opt.y_}\")\nprint(f\"opt.min_y: {opt.min_y}\")\nprint(f\"opt.min_X: {opt.min_X}\")\nprint(f\"opt.counter: {opt.counter}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nSpotOptim stats without noise:\nopt.X_: [[ 0.79685221 4.93435218]\n [-2.94376707 0.39198492]\n [ 3.54124097 -2.31499514]\n [-3.23924783 1.83643808]\n [ 2.69984079 -3.75753273]\n [-2.92568147 0.14332206]\n [-2.98878191 -0.02687276]\n [-2.16813182 0.11638572]\n [-1.27495502 0.00712716]\n [-0.61668307 -0.0282545 ]]\nopt.y_: [24.98280493 8.81941672 17.8995901 13.86523133 21.4081925 8.58015325\n 8.93353946 4.71434121 1.6255611 0.38109632]\nopt.min_y: 0.3810963220083782\nopt.min_X: [-0.61668307 -0.0282545 ]\nopt.counter: 10\n```\n:::\n:::\n\n\n::: {#1a4efcff .cell execution_count=78}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import noisy_sphere\n# With noise\nopt_noise = SpotOptim(fun=noisy_sphere,\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5,\n repeats_surrogate=2,\n repeats_initial=2)\nopt_noise.optimize()\nprint(\"SpotOptim stats with noise:\")\nprint(f\"opt_noise.X_: {opt_noise.X_}\")\nprint(f\"opt_noise.y_: {opt_noise.y_}\")\nprint(f\"opt_noise.min_y: {opt_noise.min_y}\")\nprint(f\"opt_noise.min_X: {opt_noise.min_X}\")\nprint(f\"opt_noise.counter: {opt_noise.counter}\")\nprint(f\"opt_noise.mean_X: {opt_noise.mean_X}\")\nprint(f\"opt_noise.mean_y: {opt_noise.mean_y}\")\nprint(f\"opt_noise.var_y: {opt_noise.var_y}\")\nprint(f\"opt_noise.min_mean_X: {opt_noise.min_mean_X}\")\nprint(f\"opt_noise.min_mean_y: {opt_noise.min_mean_y}\")\nprint(f\"opt_noise.min_var_y: {opt_noise.min_var_y}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nSpotOptim stats with noise:\nopt_noise.X_: [[-0.20218718 1.79926887]\n [-0.20218718 1.79926887]\n [ 1.17880841 -0.57437429]\n [ 1.17880841 -0.57437429]\n [ 3.46682133 -3.91891032]\n [ 3.46682133 -3.91891032]\n [-1.98472183 -1.40064202]\n [-1.98472183 -1.40064202]\n [-4.87727302 3.24025683]\n [-4.87727302 3.24025683]\n [ 0.48564166 0.15942407]\n [ 0.48564166 0.15942407]\n [ 1.31871852 1.08415761]\n [ 1.31871852 1.08415761]\n [ 0.18698375 -0.1973072 ]\n [ 0.18698375 -0.1973072 ]\n [ 0.07616704 -0.34955614]\n [ 0.07616704 -0.34955614]\n [ 0.1018694 -0.05616708]\n [ 0.1018694 -0.05616708]]\nopt_noise.y_: [ 3.24705051e+00 3.19421909e+00 1.61881192e+00 1.88765277e+00\n 2.72974796e+01 2.73235476e+01 5.93750370e+00 6.03070134e+00\n 3.43351680e+01 3.45629920e+01 3.88005019e-01 3.11213677e-01\n 2.85549336e+00 2.86956976e+00 2.90163539e-02 -1.00525720e-01\n 2.13043982e-01 4.40784950e-02 -8.35849499e-02 1.56163803e-01]\nopt_noise.min_y: -0.10052572046695138\nopt_noise.min_X: [ 0.18698375 -0.1973072 ]\nopt_noise.counter: 20\nopt_noise.mean_X: [[-4.87727302 3.24025683]\n [-1.98472183 -1.40064202]\n [-0.20218718 1.79926887]\n [ 0.07616704 -0.34955614]\n [ 0.1018694 -0.05616708]\n [ 0.18698375 -0.1973072 ]\n [ 0.48564166 0.15942407]\n [ 1.17880841 -0.57437429]\n [ 1.31871852 1.08415761]\n [ 3.46682133 -3.91891032]]\nopt_noise.mean_y: [34.44907999 5.98410252 3.2206348 0.12856124 0.03628943 -0.03575468\n 0.34960935 1.75323234 2.86253156 27.3105136 ]\nopt_noise.var_y: [1.29759436e-02 2.17145039e-03 6.97789966e-04 7.13733398e-03\n 1.43698661e-02 4.19528726e-03 1.47422756e-03 1.80688502e-02\n 4.95362454e-05 1.69886138e-04]\nopt_noise.min_mean_X: [ 0.18698375 -0.1973072 ]\nopt_noise.min_mean_y: -0.035754683294528564\nopt_noise.min_var_y: 0.0041952872563913775\n```\n:::\n:::\n\n\n### update_storage { #spotoptim.SpotOptim.SpotOptim.update_storage }\n\n```python\nSpotOptim.SpotOptim.update_storage(X_new, y_new)\n```\n\nUpdate storage (`X_`, `y_`) with new evaluation points.\nAppends new design points and their function values to the storage arrays.\nPoints are converted from internal scale to original scale before storage.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|-----------------------------------------------------------------|------------|\n| X_new | [ndarray](`ndarray`) | New design points in internal scale, shape (n_new, n_features). | _required_ |\n| y_new | [ndarray](`ndarray`) | Function values at X_new, shape (n_new,). | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|--------|---------------|\n| | None | None |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#9c036686 .cell execution_count=79}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n n_initial=5)\n# Initialize with some data\nopt.X_ = np.array([[1, 2], [3, 4]])\nopt.y_ = np.array([5.0, 25.0])\nprint(\"Initial storage:\")\nprint(opt.X_)\nprint(opt.y_)\n# Add new points\nX_new = np.array([[0, 1], [2, 3]])\ny_new = np.array([1.0, 13.0])\nopt.update_storage(X_new, y_new)\nprint(\"Updated storage:\")\nprint(opt.X_)\nprint(opt.y_)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nInitial storage:\n[[1 2]\n [3 4]]\n[ 5. 25.]\nUpdated storage:\n[[1. 2.]\n [3. 4.]\n [0. 1.]\n [2. 3.]]\n[ 5. 25. 1. 13.]\n```\n:::\n:::\n\n\n### update_success_rate { #spotoptim.SpotOptim.SpotOptim.update_success_rate }\n\n```python\nSpotOptim.SpotOptim.update_success_rate(y_new)\n```\n\nUpdate the rolling success rate of the optimization process.\nA success is counted only if the new value is better (smaller) than the best\nfound y value so far. The success rate is calculated based on the last\n`window_size` successes.\nImportant: This method should be called BEFORE updating self.y_ to correctly\ntrack improvements against the previous best value.\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|----------------------|------------------------------------------------------------------|------------|\n| y_new | [ndarray](`ndarray`) | The new function values to consider for the success rate update. | _required_ |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#3ccfd891 .cell execution_count=80}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nopt = SpotOptim(fun=lambda X: np.sum(X**2, axis=1),\n bounds=[(-5, 5), (-5, 5)],\n max_iter=10, n_initial=5)\nprint(opt.success_rate)\nopt.X_ = np.array([[1, 2], [3, 4], [0, 1]])\nopt.y_ = np.array([5.0, 3.0, 2.0])\nopt.update_success_rate(np.array([1.5, 2.5]))\nprint(opt.success_rate)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n0.0\n0.5\n```\n:::\n:::\n\n\n### validate_x0 { #spotoptim.SpotOptim.SpotOptim.validate_x0 }\n\n```python\nSpotOptim.SpotOptim.validate_x0(x0)\n```\n\nValidate and process starting point x0. Called in `__init__` and `optimize`.\nThis method checks that x0:\n * Is a numpy array\n * Has the correct number of dimensions\n * Has values within bounds (in original scale)\n * Is properly transformed to internal scale\n\n#### Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------|-----------------------------------|----------------------------------|------------|\n| x0 | [array](`array`) - [like](`like`) | Starting point in original scale | _required_ |\n\n#### Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|---------|------------------------------------------|---------------------------------------------------------------------|\n| ndarray | [np](`numpy`).[ndarray](`numpy.ndarray`) | Validated and transformed x0 in internal scale, shape (n_features,) |\n\n#### Raises {.doc-section .doc-section-raises}\n\n| Name | Type | Description |\n|--------|----------------------------|------------------|\n| | [ValueError](`ValueError`) | If x0 is invalid |\n\n#### Examples {.doc-section .doc-section-examples}\n\n::: {#a81ac7c2 .cell execution_count=81}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim import SpotOptim\nfrom spotoptim.function import sphere\nopt = SpotOptim(\n fun=sphere,\n bounds=[(-5, 5), (5,5), (-10, 10)],\n x0=np.array([1.0, 5.0, 9.0]),\n var_trans=[\"log10\", \"id\", \"sqrt\"]\n)\n# x0 is validated during initialization and transformed to internal scale\nprint(f\"x0 in internal scale: {opt.x0}\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nx0 in internal scale: [0. 3.]\n```\n:::\n:::\n\n\n", "supporting": [ "SpotOptim.SpotOptim_files/figure-html" ], diff --git a/_freeze/docs/reference/SpotOptim.SpotOptim/figure-html/cell-3-output-1.png b/_freeze/docs/reference/SpotOptim.SpotOptim/figure-html/cell-3-output-1.png index 0f3cf1d..e765227 100644 Binary files a/_freeze/docs/reference/SpotOptim.SpotOptim/figure-html/cell-3-output-1.png and b/_freeze/docs/reference/SpotOptim.SpotOptim/figure-html/cell-3-output-1.png differ diff --git a/_freeze/docs/reference/SpotOptim.SpotOptim/figure-html/cell-33-output-2.png b/_freeze/docs/reference/SpotOptim.SpotOptim/figure-html/cell-33-output-2.png index 26e8847..901f226 100644 Binary files a/_freeze/docs/reference/SpotOptim.SpotOptim/figure-html/cell-33-output-2.png and b/_freeze/docs/reference/SpotOptim.SpotOptim/figure-html/cell-33-output-2.png differ diff --git a/_freeze/docs/reference/SpotOptim.SpotOptim/figure-html/cell-33-output-3.png b/_freeze/docs/reference/SpotOptim.SpotOptim/figure-html/cell-33-output-3.png index 26e8847..901f226 100644 Binary files a/_freeze/docs/reference/SpotOptim.SpotOptim/figure-html/cell-33-output-3.png and b/_freeze/docs/reference/SpotOptim.SpotOptim/figure-html/cell-33-output-3.png differ diff --git a/_freeze/docs/reference/SpotOptim.SpotOptim/figure-html/cell-34-output-2.png b/_freeze/docs/reference/SpotOptim.SpotOptim/figure-html/cell-34-output-2.png index 26ffb3c..1d76d68 100644 Binary files a/_freeze/docs/reference/SpotOptim.SpotOptim/figure-html/cell-34-output-2.png and b/_freeze/docs/reference/SpotOptim.SpotOptim/figure-html/cell-34-output-2.png differ diff --git a/_freeze/docs/reference/SpotOptim.SpotOptim/figure-html/cell-34-output-3.png b/_freeze/docs/reference/SpotOptim.SpotOptim/figure-html/cell-34-output-3.png index 26ffb3c..1d76d68 100644 Binary files a/_freeze/docs/reference/SpotOptim.SpotOptim/figure-html/cell-34-output-3.png and b/_freeze/docs/reference/SpotOptim.SpotOptim/figure-html/cell-34-output-3.png differ diff --git a/_freeze/docs/reference/SpotOptim.SpotOptimConfig/execute-results/html.json b/_freeze/docs/reference/SpotOptim.SpotOptimConfig/execute-results/html.json index 5403334..f632d05 100644 --- a/_freeze/docs/reference/SpotOptim.SpotOptimConfig/execute-results/html.json +++ b/_freeze/docs/reference/SpotOptim.SpotOptimConfig/execute-results/html.json @@ -1,8 +1,8 @@ { - "hash": "9b1327a8a7ad5461d01d3263e80b29e3", + "hash": "1a355faa09c938c98bc256c51126739f", "result": { "engine": "jupyter", - "markdown": "---\ntitle: SpotOptim.SpotOptimConfig\n---\n\n\n\n```python\nSpotOptim.SpotOptimConfig(\n bounds=None,\n max_iter=20,\n n_initial=10,\n surrogate=None,\n acquisition='y',\n var_type=None,\n var_name=None,\n var_trans=None,\n tolerance_x=None,\n max_time=np.inf,\n repeats_initial=1,\n repeats_surrogate=1,\n ocba_delta=0,\n tensorboard_log=False,\n tensorboard_path=None,\n tensorboard_clean=False,\n fun_mo2so=None,\n seed=None,\n verbose=False,\n warnings_filter='ignore',\n n_infill_points=1,\n max_surrogate_points=None,\n selection_method='distant',\n acquisition_failure_strategy='random',\n penalty=False,\n penalty_val=None,\n acquisition_fun_return_size=3,\n acquisition_optimizer='differential_evolution',\n restart_after_n=100,\n restart_inject_best=True,\n max_restarts=None,\n x0=None,\n de_x0_prob=0.1,\n tricands_fringe=False,\n prob_de_tricands=0.8,\n window_size=None,\n min_tol_metric='chebyshev',\n prob_surrogate=None,\n acquisition_optimizer_kwargs=None,\n args=(),\n kwargs=None,\n)\n```\n\nConfiguration parameters for SpotOptim.\n\n## Attributes {.doc-section .doc-section-attributes}\n\n| Name | Type | Description |\n|------------------------------|-----------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| bounds | [Optional](`typing.Optional`)\\[[list](`list`)\\] | Bounds for the input variables. |\n| max_iter | [int](`int`) | Maximum number of iterations. |\n| n_initial | [int](`int`) | Number of initial points. |\n| surrogate | [Optional](`typing.Optional`)\\[[object](`object`)\\] | Surrogate model. |\n| acquisition | [str](`str`) | Acquisition function. |\n| var_type | [Optional](`typing.Optional`)\\[[list](`list`)\\] | Type of variables. |\n| var_name | [Optional](`typing.Optional`)\\[[list](`list`)\\] | Name of variables. |\n| var_trans | [Optional](`typing.Optional`)\\[[list](`list`)\\] | Transformation of variables. |\n| tolerance_x | [Optional](`typing.Optional`)\\[[float](`float`)\\] | Tolerance for input variables. |\n| max_time | [float](`float`) | Maximum time. |\n| repeats_initial | [int](`int`) | Number of repeats for initial points. |\n| repeats_surrogate | [int](`int`) | Number of repeats for surrogate points. |\n| ocba_delta | [int](`int`) | Delta for OCBA. |\n| tensorboard_log | [bool](`bool`) | Whether to log to TensorBoard. |\n| tensorboard_path | [Optional](`typing.Optional`)\\[[str](`str`)\\] | Path to TensorBoard logs. |\n| tensorboard_clean | [bool](`bool`) | Whether to clean old TensorBoard logs (the configured tensorboard_path, or the 'runs' folder if no path is set). |\n| fun_mo2so | [Optional](`typing.Optional`)\\[[Callable](`typing.Callable`)\\] | Function to convert multi-objective to single-objective. |\n| seed | [Optional](`typing.Optional`)\\[[int](`int`)\\] | Seed for random number generator. |\n| verbose | [bool](`bool`) | Whether to print verbose output. |\n| warnings_filter | [Literal](`typing.Literal`)\\[\\'default\\', \\'error\\', \\'ignore\\'\\] | Filter for warnings. |\n| n_infill_points | [int](`int`) | Number of infill points. |\n| max_surrogate_points | [Optional](`typing.Optional`)\\[[Union](`typing.Union`)\\[[int](`int`), [List](`typing.List`)\\[[int](`int`)\\]\\]\\] | Maximum number of surrogate points. |\n| selection_method | [str](`str`) | Method for selecting infill points. |\n| acquisition_failure_strategy | [str](`str`) | Strategy for handling acquisition function failures. |\n| penalty | [bool](`bool`) | Whether to use penalty. |\n| penalty_val | [Optional](`typing.Optional`)\\[[float](`float`)\\] | Penalty value. |\n| acquisition_fun_return_size | [int](`int`) | Size of the acquisition function return. |\n| acquisition_optimizer | [Union](`typing.Union`)\\[[str](`str`), [Callable](`typing.Callable`)\\] | Optimizer for the acquisition function. |\n| restart_after_n | [int](`int`) | Number of iterations after which to restart. |\n| restart_inject_best | [bool](`bool`) | Whether to inject the best point after restart. |\n| max_restarts | [Optional](`typing.Optional`)\\[[int](`int`)\\] | Patience-based early-stopping. When set, the optimizer terminates after this many consecutive restarts that fail to improve the best objective value. ``None`` (default) disables the check and preserves legacy behavior. |\n| x0 | [Optional](`typing.Optional`)\\[[np](`numpy`).[ndarray](`numpy.ndarray`)\\] | Initial guess for the input variables. |\n| de_x0_prob | [float](`float`) | Probability of using differential evolution for initial guess. |\n| tricands_fringe | [bool](`bool`) | Whether to use fringe for tricands. |\n| prob_de_tricands | [float](`float`) | Probability of using tricands for differential evolution. |\n| window_size | [Optional](`typing.Optional`)\\[[int](`int`)\\] | Size of the window for tricands. |\n| min_tol_metric | [str](`str`) | Metric for minimum tolerance. |\n| prob_surrogate | [Optional](`typing.Optional`)\\[[List](`typing.List`)\\[[float](`float`)\\]\\] | Probability of using surrogate. |\n| acquisition_optimizer_kwargs | [Optional](`typing.Optional`)\\[[Dict](`typing.Dict`)\\[[str](`str`), [Any](`typing.Any`)\\]\\] | Keyword arguments for the acquisition function optimizer. |\n| args | [Tuple](`typing.Tuple`) | Arguments for the objective function. |\n| kwargs | [Optional](`typing.Optional`)\\[[Dict](`typing.Dict`)\\[[str](`str`), [Any](`typing.Any`)\\]\\] | Keyword arguments for the objective function. |\n\n## Examples {.doc-section .doc-section-examples}\n\n\n::: {#95e7b401 .cell execution_count=1}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim.SpotOptim import SpotOptim\nfrom sklearn.gaussian_process import GaussianProcessRegressor\nfrom spotoptim.SpotOptim import SpotOptimConfig\nfrom sklearn.gaussian_process.kernels import Matern, ConstantKernel\n\nkernel = ConstantKernel(1.0, (1e-2, 1e12)) * Matern(length_scale=1.0, length_scale_bounds=(1e-4, 1e2), nu=2.5)\nsurrogate = GaussianProcessRegressor(kernel=kernel, n_restarts_optimizer=100)\n\nconfig = SpotOptimConfig(\n bounds=[(0, 1), (0, 1)],\n max_iter=20,\n n_initial=10,\n surrogate=surrogate,\n acquisition=\"y\",\n var_type=[\"continuous\", \"continuous\"],\n var_name=[\"x1\", \"x2\"],\n var_trans=[\"identity\", \"identity\"],\n tolerance_x=1e-6,\n max_time=np.inf,\n repeats_initial=1,\n repeats_surrogate=1,\n ocba_delta=0,\n tensorboard_log=False,\n tensorboard_path=None,\n tensorboard_clean=False,\n fun_mo2so=None,\n seed=None,\n verbose=False,\n warnings_filter=\"ignore\",\n n_infill_points=1,\n max_surrogate_points=None,\n selection_method=\"distant\",\n acquisition_failure_strategy=\"random\",\n penalty=False,\n penalty_val=None,\n acquisition_fun_return_size=3,\n acquisition_optimizer=\"differential_evolution\",\n restart_after_n=100,\n restart_inject_best=True,\n max_restarts=None,\n x0=None,\n de_x0_prob=0.1,\n tricands_fringe=False,\n prob_de_tricands=0.8,\n window_size=None,\n min_tol_metric=\"chebyshev\",\n prob_surrogate=None,\n acquisition_optimizer_kwargs=None,\n args=(),\n kwargs=None,\n)\n```\n:::\n\n\n", + "markdown": "---\ntitle: SpotOptim.SpotOptimConfig\n---\n\n\n\n```python\nSpotOptim.SpotOptimConfig(\n bounds=None,\n max_iter=20,\n n_initial=10,\n surrogate=None,\n acquisition='y',\n var_type=None,\n var_name=None,\n var_trans=None,\n tolerance_x=None,\n max_time=np.inf,\n repeats_initial=1,\n repeats_surrogate=1,\n ocba_delta=0,\n tensorboard_log=False,\n tensorboard_path=None,\n tensorboard_clean=False,\n fun_mo2so=None,\n seed=None,\n verbose=False,\n warnings_filter='ignore',\n n_infill_points=1,\n max_surrogate_points=30,\n selection_method='distant',\n acquisition_failure_strategy='random',\n penalty=False,\n penalty_val=None,\n acquisition_fun_return_size=3,\n acquisition_optimizer='differential_evolution',\n restart_after_n=100,\n restart_inject_best=True,\n max_restarts=None,\n x0=None,\n de_x0_prob=0.1,\n tricands_fringe=False,\n prob_de_tricands=0.8,\n window_size=None,\n min_tol_metric='chebyshev',\n prob_surrogate=None,\n acquisition_optimizer_kwargs=None,\n args=(),\n kwargs=None,\n)\n```\n\nConfiguration parameters for SpotOptim.\n\n## Attributes {.doc-section .doc-section-attributes}\n\n| Name | Type | Description |\n|------------------------------|-----------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| bounds | [Optional](`typing.Optional`)\\[[list](`list`)\\] | Bounds for the input variables. |\n| max_iter | [int](`int`) | Maximum number of iterations. |\n| n_initial | [int](`int`) | Number of initial points. |\n| surrogate | [Optional](`typing.Optional`)\\[[object](`object`)\\] | Surrogate model. |\n| acquisition | [str](`str`) | Acquisition function. |\n| var_type | [Optional](`typing.Optional`)\\[[list](`list`)\\] | Type of variables. |\n| var_name | [Optional](`typing.Optional`)\\[[list](`list`)\\] | Name of variables. |\n| var_trans | [Optional](`typing.Optional`)\\[[list](`list`)\\] | Transformation of variables. |\n| tolerance_x | [Optional](`typing.Optional`)\\[[float](`float`)\\] | Tolerance for input variables. |\n| max_time | [float](`float`) | Maximum time. |\n| repeats_initial | [int](`int`) | Number of repeats for initial points. |\n| repeats_surrogate | [int](`int`) | Number of repeats for surrogate points. |\n| ocba_delta | [int](`int`) | Delta for OCBA. |\n| tensorboard_log | [bool](`bool`) | Whether to log to TensorBoard. |\n| tensorboard_path | [Optional](`typing.Optional`)\\[[str](`str`)\\] | Path to TensorBoard logs. |\n| tensorboard_clean | [bool](`bool`) | Whether to clean old TensorBoard logs (the configured tensorboard_path, or the 'runs' folder if no path is set). |\n| fun_mo2so | [Optional](`typing.Optional`)\\[[Callable](`typing.Callable`)\\] | Function to convert multi-objective to single-objective. |\n| seed | [Optional](`typing.Optional`)\\[[int](`int`)\\] | Seed for random number generator. |\n| verbose | [bool](`bool`) | Whether to print verbose output. |\n| warnings_filter | [Literal](`typing.Literal`)\\[\\'default\\', \\'error\\', \\'ignore\\'\\] | Filter for warnings. |\n| n_infill_points | [int](`int`) | Number of infill points. |\n| max_surrogate_points | [Optional](`typing.Optional`)\\[[Union](`typing.Union`)\\[[int](`int`), [List](`typing.List`)\\[[int](`int`)\\]\\]\\] | Maximum number of surrogate points. Defaults to 30. |\n| selection_method | [str](`str`) | Method for selecting infill points. |\n| acquisition_failure_strategy | [str](`str`) | Strategy for handling acquisition function failures. |\n| penalty | [bool](`bool`) | Whether to use penalty. |\n| penalty_val | [Optional](`typing.Optional`)\\[[float](`float`)\\] | Penalty value. |\n| acquisition_fun_return_size | [int](`int`) | Size of the acquisition function return. |\n| acquisition_optimizer | [Union](`typing.Union`)\\[[str](`str`), [Callable](`typing.Callable`)\\] | Optimizer for the acquisition function. |\n| restart_after_n | [int](`int`) | Number of iterations after which to restart. |\n| restart_inject_best | [bool](`bool`) | Whether to inject the best point after restart. |\n| max_restarts | [Optional](`typing.Optional`)\\[[int](`int`)\\] | Patience-based early-stopping. When set, the optimizer terminates after this many consecutive restarts that fail to improve the best objective value. ``None`` (default) disables the check and preserves legacy behavior. |\n| x0 | [Optional](`typing.Optional`)\\[[np](`numpy`).[ndarray](`numpy.ndarray`)\\] | Initial guess for the input variables. |\n| de_x0_prob | [float](`float`) | Probability of using differential evolution for initial guess. |\n| tricands_fringe | [bool](`bool`) | Whether to use fringe for tricands. |\n| prob_de_tricands | [float](`float`) | Probability of using tricands for differential evolution. |\n| window_size | [Optional](`typing.Optional`)\\[[int](`int`)\\] | Size of the window for tricands. |\n| min_tol_metric | [str](`str`) | Metric for minimum tolerance. |\n| prob_surrogate | [Optional](`typing.Optional`)\\[[List](`typing.List`)\\[[float](`float`)\\]\\] | Probability of using surrogate. |\n| acquisition_optimizer_kwargs | [Optional](`typing.Optional`)\\[[Dict](`typing.Dict`)\\[[str](`str`), [Any](`typing.Any`)\\]\\] | Keyword arguments for the acquisition function optimizer. |\n| args | [Tuple](`typing.Tuple`) | Arguments for the objective function. |\n| kwargs | [Optional](`typing.Optional`)\\[[Dict](`typing.Dict`)\\[[str](`str`), [Any](`typing.Any`)\\]\\] | Keyword arguments for the objective function. |\n\n## Examples {.doc-section .doc-section-examples}\n\n\n::: {#b3536195 .cell execution_count=1}\n``` {.python .cell-code}\nimport numpy as np\nfrom spotoptim.SpotOptim import SpotOptim\nfrom sklearn.gaussian_process import GaussianProcessRegressor\nfrom spotoptim.SpotOptim import SpotOptimConfig\nfrom sklearn.gaussian_process.kernels import Matern, ConstantKernel\n\nkernel = ConstantKernel(1.0, (1e-2, 1e12)) * Matern(length_scale=1.0, length_scale_bounds=(1e-4, 1e2), nu=2.5)\nsurrogate = GaussianProcessRegressor(kernel=kernel, n_restarts_optimizer=100)\n\nconfig = SpotOptimConfig(\n bounds=[(0, 1), (0, 1)],\n max_iter=20,\n n_initial=10,\n surrogate=surrogate,\n acquisition=\"y\",\n var_type=[\"continuous\", \"continuous\"],\n var_name=[\"x1\", \"x2\"],\n var_trans=[\"identity\", \"identity\"],\n tolerance_x=1e-6,\n max_time=np.inf,\n repeats_initial=1,\n repeats_surrogate=1,\n ocba_delta=0,\n tensorboard_log=False,\n tensorboard_path=None,\n tensorboard_clean=False,\n fun_mo2so=None,\n seed=None,\n verbose=False,\n warnings_filter=\"ignore\",\n n_infill_points=1,\n max_surrogate_points=30,\n selection_method=\"distant\",\n acquisition_failure_strategy=\"random\",\n penalty=False,\n penalty_val=None,\n acquisition_fun_return_size=3,\n acquisition_optimizer=\"differential_evolution\",\n restart_after_n=100,\n restart_inject_best=True,\n max_restarts=None,\n x0=None,\n de_x0_prob=0.1,\n tricands_fringe=False,\n prob_de_tricands=0.8,\n window_size=None,\n min_tol_metric=\"chebyshev\",\n prob_surrogate=None,\n acquisition_optimizer_kwargs=None,\n args=(),\n kwargs=None,\n)\n```\n:::\n\n\n", "supporting": [ "SpotOptim.SpotOptimConfig_files/figure-html" ], diff --git a/src/spotoptim/SpotOptim.py b/src/spotoptim/SpotOptim.py index a69963a..33b90e0 100644 --- a/src/spotoptim/SpotOptim.py +++ b/src/spotoptim/SpotOptim.py @@ -58,7 +58,7 @@ class SpotOptimConfig: verbose (bool): Whether to print verbose output. warnings_filter (Literal["default", "error", "ignore"]): Filter for warnings. n_infill_points (int): Number of infill points. - max_surrogate_points (Optional[Union[int, List[int]]]): Maximum number of surrogate points. + max_surrogate_points (Optional[Union[int, List[int]]]): Maximum number of surrogate points. Defaults to 30. selection_method (str): Method for selecting infill points. acquisition_failure_strategy (str): Strategy for handling acquisition function failures. penalty (bool): Whether to use penalty. @@ -116,7 +116,7 @@ class SpotOptimConfig: verbose=False, warnings_filter="ignore", n_infill_points=1, - max_surrogate_points=None, + max_surrogate_points=30, selection_method="distant", acquisition_failure_strategy="random", penalty=False, @@ -161,7 +161,7 @@ class SpotOptimConfig: verbose: bool = False warnings_filter: Literal["default", "error", "ignore"] = "ignore" n_infill_points: int = 1 - max_surrogate_points: Optional[Union[int, List[int]]] = None + max_surrogate_points: Optional[Union[int, List[int]]] = 30 selection_method: str = "distant" acquisition_failure_strategy: str = "random" penalty: bool = False @@ -351,7 +351,7 @@ class SpotOptim(BaseEstimator): max_surrogate_points (int, optional): Maximum number of points to use for surrogate model fitting. If None, all points are used. If the number of evaluated points exceeds this limit, - a subset is selected using the selection method. Defaults to None. + a subset is selected using the selection method. Defaults to 30. selection_method (str, optional): Method for selecting points when max_surrogate_points is exceeded. Options: 'distant' (Select points that are distant from each other via K-means clustering) or @@ -733,7 +733,7 @@ def __init__( verbose: bool = False, warnings_filter: Literal["default", "error", "ignore"] = "ignore", n_infill_points: int = 1, - max_surrogate_points: Optional[Union[int, List[int]]] = None, + max_surrogate_points: Optional[Union[int, List[int]]] = 30, selection_method: str = "distant", acquisition_failure_strategy: str = "random", penalty: bool = False, diff --git a/tests/test_tricands.py b/tests/test_tricands.py index e94c462..8e2d8f7 100644 --- a/tests/test_tricands.py +++ b/tests/test_tricands.py @@ -17,6 +17,13 @@ class TestTricands: """Test suite for tricands module.""" def setup_method(self): + # Close figures leaked by earlier tests on the same xdist worker: + # test_visualization_2d mocks plt.figure, so tricands draws into + # whatever Axes gca() finds — a leaked 3D Axes makes scatter fail + # with "s must be a scalar, or float array-like ...". + import matplotlib.pyplot as plt + + plt.close("all") # Create invalid (too few points) X self.X_small = np.array([[0.1, 0.1]]) # Create valid 2D X