Skip to content

Commit

Permalink
Joss software release (#51)
Browse files Browse the repository at this point in the history
* fix: changed output error message for constraint checks; fix minor copy array bounds for scalar value; added univariate test

* chore: updated installation text in readme.md

* fix: reference to scipy.optimize.OptimizeResult

* fix: added citation to quasi-monte carlo submodule for sobol init

* fix: space for error message

* Update bads.py

---------

Co-authored-by: Luigi Acerbi <luigi.acerbi@gmail.com>
  • Loading branch information
GurjeetSinghSangra and lacerbi committed Feb 22, 2024
1 parent 1bee482 commit a029e63
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 9 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ BADS is effective when:

## Installation

PyBADS is available via `pip` and `conda-forge`.
PyBADS is available via `pip` and `conda-forge`, and requires Python version 3.9 or newer.

1. Install with:
```console
Expand All @@ -36,7 +36,6 @@ PyBADS is available via `pip` and `conda-forge`.
```console
conda install --channel=conda-forge pybads
```
PyBADS requires Python version 3.9 or newer.
2. (Optional): Install Jupyter to view the example Notebooks. You can skip this step if you are working from a Conda environment which already has Jupyter, but be aware that if the wrong `jupyter` executable is found on your path then import errors may arise.
```console
conda install jupyter
Expand Down
8 changes: 4 additions & 4 deletions pybads/bads/bads.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,9 @@ def __init__(

# Initialize variables and algorithm structures
if plausible_lower_bounds is None and lower_bounds is not None:
plausible_lower_bounds = lower_bounds.copy()
plausible_lower_bounds = np.atleast_2d(lower_bounds).copy()
if plausible_upper_bounds is None and upper_bounds is not None:
plausible_upper_bounds = upper_bounds.copy()
plausible_upper_bounds = np.atleast_2d(upper_bounds).copy()

if x0 is None:
if (
Expand Down Expand Up @@ -355,9 +355,9 @@ def _bounds_check_(
or plausible_upper_bounds.shape != (1, D)
):
raise ValueError(
"""All input vectors (x0, lower_bounds, upper_bounds,
f"""All input vectors (lower_bounds, upper_bounds,
plausible_lower_bounds, plausible_upper_bounds), if specified,
need to be row vectors with D elements."""
need to be of the same dimension D={D} as the starting point x_0={x0}."""
)

# check that plausible bounds are finite
Expand Down
2 changes: 2 additions & 0 deletions pybads/bads/optimize_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
class OptimizeResult(dict):
"""
It represents the optimization result.
The class is based on ``scipy.optimize.OptimizeResult``.
See also: https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.OptimizeResult.html.
Attributes:
Expand Down
2 changes: 1 addition & 1 deletion pybads/function_logger/function_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def __call__(self, x: np.ndarray, record_duplicate_data: bool = True):
else:
err.args += (
"\n FunctionLogger:FuncError "
+ "Error in executing the logged function"
+ "Error in executing the logged function "
+ "with input: "
+ str(x_orig),
)
Expand Down
31 changes: 30 additions & 1 deletion pybads/init_functions/init_sobol.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,36 @@
from scipy.stats.qmc import Sobol


def init_sobol(u0, lb, ub, plb, pub, fun_eval_start):
def init_sobol(u0=np.ndarray, lb=np.ndarray, ub=np.ndarray, plb=np.ndarray, pub=np.ndarray, fun_eval_start=int):
"""
Initialize the Sobol sequence.
This method relies on the scipy.stats.qmc.Sobol class for generating the Sobol sequence (Roy et. al 2023).
You can find more information about the Sobol sequence in the documentation of the Sobol class.
Roy et al., (2023). Quasi-Monte Carlo Methods in Python. Journal of Open Source Software, 8(84), 5309, https://doi.org/10.21105/joss.05309
Parameters
----------
u0 : array_like
Initial point.
lb : array_like
Lower bounds.
ub : array_like
Upper bounds.
plb : array_like
Lower bounds for the parameters.
pub : array_like
Upper bounds for the parameters.
fun_eval_start : int
Number of initial function evaluations.
Returns
-------
u_init : array_like
Initial points.
n_samples : int
Number of samples used for the initialization.
"""

max_seed = 997
if np.all(np.isfinite(u0)):
Expand Down
10 changes: 9 additions & 1 deletion pybads/testing/bads/test_bads_optimization.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ def test_ellipsoid_opt():
D, x0, LB, UB, PLB, PUB, tol_errs = get_test_opt_conf()
fun = lambda x: np.sum((np.atleast_2d(x) / np.arange(1, len(x) + 1) ** 2) ** 2)
run_bads(fun, x0, LB, UB, PLB, PUB, tol_errs, f_min=0.0, assert_flag=True)

def test_univariate_input_and_opt():
rfn = lambda x: x**2 + 3.2 + np.random.normal(scale=0.1)
plb = -5
pub = 5
x0 = 3
opt = BADS(rfn, x0, plausible_lower_bounds=plb, plausible_upper_bounds=pub)
opt.optimize()

def test_1D_opt():
D, x0, LB, UB, PLB, PUB, tol_errs = get_test_opt_conf(D=1)
Expand Down Expand Up @@ -88,4 +96,4 @@ def test_he_noisy_sphere_opt():
D, x0, LB, UB, PLB, PUB, tol_errs = get_test_opt_conf()
fun = he_noisy_sphere
oracle_fun = lambda x: np.sum(np.atleast_2d(x)**2, axis=1) # True objective function
run_bads(fun, x0, LB, UB, PLB, PUB, tol_errs, f_min=0.0, oracle_fun=oracle_fun, uncertainty_handling=2, assert_flag=True)
run_bads(fun, x0, LB, UB, PLB, PUB, tol_errs, f_min=0.0, oracle_fun=oracle_fun, uncertainty_handling=2, assert_flag=True)

0 comments on commit a029e63

Please sign in to comment.