From c8d6a82b447a30d18d91c7df55297de868498925 Mon Sep 17 00:00:00 2001 From: jlnav Date: Thu, 21 Aug 2025 15:48:36 -0500 Subject: [PATCH 01/32] starting to populate the APOSMM class with common kwargs, for better documenting, and so we don't have to check the existence of settings in kwargso --- libensemble/gen_classes/aposmm.py | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/libensemble/gen_classes/aposmm.py b/libensemble/gen_classes/aposmm.py index 45a522279..60122a1d4 100644 --- a/libensemble/gen_classes/aposmm.py +++ b/libensemble/gen_classes/aposmm.py @@ -1,4 +1,5 @@ import copy +from math import gamma, pi, sqrt from typing import List import numpy as np @@ -18,22 +19,44 @@ def __init__( self, vocs: VOCS, History: npt.NDArray = [], - persis_info: dict = {}, - gen_specs: dict = {}, - libE_info: dict = {}, + initial_sample_size: int = 100, + sample_points: npt.NDArray = None, + localopt_method: str = "LN_BOBYQA", + rk_const: float = None, + xtol_abs: float = 1e-6, + ftol_abs: float = 1e-6, + dist_to_bound_multiple: float = 0.5, + max_active_runs: int = 6, **kwargs, ) -> None: + from libensemble.gen_funcs.persistent_aposmm import aposmm self.VOCS = vocs + gen_specs = {} + persis_info = {} + libE_info = {} gen_specs["gen_f"] = aposmm self.n = len(list(self.VOCS.variables.keys())) + if not rk_const: + rk_const = 0.5 * ((gamma(1 + (self.n / 2)) * 5) ** (1 / self.n)) / sqrt(pi) + gen_specs["user"] = {} gen_specs["user"]["lb"] = np.array([vocs.variables[i].domain[0] for i in vocs.variables]) gen_specs["user"]["ub"] = np.array([vocs.variables[i].domain[1] for i in vocs.variables]) + gen_specs["user"]["initial_sample_size"] = initial_sample_size + if sample_points: + gen_specs["user"]["sample_points"] = sample_points + gen_specs["user"]["localopt_method"] = localopt_method + gen_specs["user"]["rk_const"] = rk_const + gen_specs["user"]["xtol_abs"] = xtol_abs + gen_specs["user"]["ftol_abs"] = ftol_abs + gen_specs["user"]["dist_to_bound_multiple"] = dist_to_bound_multiple + gen_specs["user"]["max_active_runs"] = max_active_runs + if not gen_specs.get("out"): # gen_specs never especially changes for aposmm even as the problem varies gen_specs["out"] = [ ("x", float, self.n), From 1dce05935cbf2be9dc2df1498daf1d32153a3b4d Mon Sep 17 00:00:00 2001 From: jlnav Date: Fri, 22 Aug 2025 07:49:11 -0500 Subject: [PATCH 02/32] small fixes --- libensemble/gen_classes/aposmm.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libensemble/gen_classes/aposmm.py b/libensemble/gen_classes/aposmm.py index 60122a1d4..d5597ecf6 100644 --- a/libensemble/gen_classes/aposmm.py +++ b/libensemble/gen_classes/aposmm.py @@ -27,6 +27,7 @@ def __init__( ftol_abs: float = 1e-6, dist_to_bound_multiple: float = 0.5, max_active_runs: int = 6, + random_seed: int = 1, **kwargs, ) -> None: @@ -35,7 +36,7 @@ def __init__( self.VOCS = vocs gen_specs = {} - persis_info = {} + persis_info = {"1": np.random.default_rng(random_seed)} libE_info = {} gen_specs["gen_f"] = aposmm self.n = len(list(self.VOCS.variables.keys())) @@ -48,7 +49,7 @@ def __init__( gen_specs["user"]["ub"] = np.array([vocs.variables[i].domain[1] for i in vocs.variables]) gen_specs["user"]["initial_sample_size"] = initial_sample_size - if sample_points: + if sample_points is not None: gen_specs["user"]["sample_points"] = sample_points gen_specs["user"]["localopt_method"] = localopt_method gen_specs["user"]["rk_const"] = rk_const From 77845a0a202b6f6350eeaba996374746e4572109 Mon Sep 17 00:00:00 2001 From: jlnav Date: Fri, 22 Aug 2025 08:08:34 -0500 Subject: [PATCH 03/32] docstring for APOSMM class --- libensemble/gen_classes/aposmm.py | 51 ++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/libensemble/gen_classes/aposmm.py b/libensemble/gen_classes/aposmm.py index d5597ecf6..ac792c31c 100644 --- a/libensemble/gen_classes/aposmm.py +++ b/libensemble/gen_classes/aposmm.py @@ -12,7 +12,56 @@ class APOSMM(PersistentGenInterfacer): """ - Standalone object-oriented APOSMM generator + APOSMM coordinates multiple local optimization runs, dramatically reducing time for + discovering multiple minima on parallel systems. + + This *generator* adheres to the `Generator Standard `_. + + .. seealso:: + + `https://doi.org/10.1007/s12532-017-0131-4 `_ + + Parameters + ---------- + vocs: VOCS + The VOCS object, adhering to the VOCS interface from the Generator Standard. + + History: npt.NDArray = [] + An optional history of previously evaluated points. + + initial_sample_size: int = 100 + Number of uniformly sampled points + to be evaluated before starting the localopt runs. Can be + zero if no additional sampling is desired, but if zero there must be past values + provided in the History. + + sample_points: npt.NDArray = None + Points to be sampled (original domain). + If more sample points are needed by APOSMM during the course of the + optimization, points will be drawn uniformly over the domain. + + localopt_method: str = "LN_BOBYQA" + The local optimization method to use. + + rk_const: float = None + Multiplier in front of the ``r_k`` value. + If not provided, it will be set to ``0.5 * ((gamma(1 + (n / 2)) * 5) ** (1 / n)) / sqrt(pi)`` + + xtol_abs: float = 1e-6 + Localopt method's convergence tolerance. + + ftol_abs: float = 1e-6 + Localopt method's convergence tolerance. + + dist_to_bound_multiple: float = 0.5 + What fraction of the distance to the nearest boundary should the initial + step size be in localopt runs. + + max_active_runs: int = 6 + Bound on number of runs APOSMM is advancing. + + random_seed: int = 1 + Seed for the random number generator. """ def __init__( From 2635236e1dda64b0c244cf94442bbf234d23e880 Mon Sep 17 00:00:00 2001 From: jlnav Date: Fri, 22 Aug 2025 13:37:57 -0500 Subject: [PATCH 04/32] evaluate an APOSMM with only VOCS passed in --- .../unit_tests/test_persistent_aposmm.py | 91 ++++++++++--------- 1 file changed, 50 insertions(+), 41 deletions(-) diff --git a/libensemble/tests/unit_tests/test_persistent_aposmm.py b/libensemble/tests/unit_tests/test_persistent_aposmm.py index d04d56198..392cee0d0 100644 --- a/libensemble/tests/unit_tests/test_persistent_aposmm.py +++ b/libensemble/tests/unit_tests/test_persistent_aposmm.py @@ -122,6 +122,52 @@ def test_standalone_persistent_aposmm(): assert min_found >= 6, f"Found {min_found} minima" +def _evaluate_aposmm_instance(my_APOSMM): + from libensemble.message_numbers import FINISHED_PERSISTENT_GEN_TAG + from libensemble.sim_funcs.six_hump_camel import six_hump_camel_func + from libensemble.tests.regression_tests.support import six_hump_camel_minima as minima + + initial_sample = my_APOSMM.suggest(100) + + total_evals = 0 + eval_max = 2000 + + for point in initial_sample: + point["energy"] = six_hump_camel_func(np.array([point["core"], point["edge"]])) + total_evals += 1 + + my_APOSMM.ingest(initial_sample) + + potential_minima = [] + + while total_evals < eval_max: + + sample, detected_minima = my_APOSMM.suggest(6), my_APOSMM.suggest_updates() + if len(detected_minima): + for m in detected_minima: + potential_minima.append(m) + for point in sample: + point["energy"] = six_hump_camel_func(np.array([point["core"], point["edge"]])) + total_evals += 1 + my_APOSMM.ingest(sample) + H, persis_info, exit_code = my_APOSMM.finalize() + + assert exit_code == FINISHED_PERSISTENT_GEN_TAG, "Standalone persistent_aposmm didn't exit correctly" + assert persis_info.get("run_order"), "Standalone persistent_aposmm didn't do any localopt runs" + + assert len(potential_minima) >= 6, f"Found {len(potential_minima)} minima" + + tol = 1e-3 + min_found = 0 + for m in minima: + # The minima are known on this test problem. + # We use their values to test APOSMM has identified all minima + print(np.min(np.sum((H[H["local_min"]]["x"] - m) ** 2, 1)), flush=True) + if np.min(np.sum((H[H["local_min"]]["x"] - m) ** 2, 1)) < tol: + min_found += 1 + assert min_found >= 6, f"Found {min_found} minima" + + @pytest.mark.extra def test_standalone_persistent_aposmm_combined_func(): from math import gamma, pi, sqrt @@ -176,14 +222,11 @@ def test_asktell_with_persistent_aposmm(): import libensemble.gen_funcs from libensemble.gen_classes import APOSMM - from libensemble.message_numbers import FINISHED_PERSISTENT_GEN_TAG - from libensemble.sim_funcs.six_hump_camel import six_hump_camel_func from libensemble.tests.regression_tests.support import six_hump_camel_minima as minima libensemble.gen_funcs.rc.aposmm_optimizers = "nlopt" n = 2 - eval_max = 2000 variables = {"core": [-3, 3], "edge": [-2, 2]} objectives = {"energy": "MINIMIZE"} @@ -202,45 +245,11 @@ def test_asktell_with_persistent_aposmm(): max_active_runs=6, ) - initial_sample = my_APOSMM.suggest(100) - - total_evals = 0 - eval_max = 2000 - - for point in initial_sample: - point["energy"] = six_hump_camel_func(np.array([point["core"], point["edge"]])) - total_evals += 1 - - my_APOSMM.ingest(initial_sample) - - potential_minima = [] + _evaluate_aposmm_instance(my_APOSMM) - while total_evals < eval_max: - - sample, detected_minima = my_APOSMM.suggest(6), my_APOSMM.suggest_updates() - if len(detected_minima): - for m in detected_minima: - potential_minima.append(m) - for point in sample: - point["energy"] = six_hump_camel_func(np.array([point["core"], point["edge"]])) - total_evals += 1 - my_APOSMM.ingest(sample) - H, persis_info, exit_code = my_APOSMM.finalize() - - assert exit_code == FINISHED_PERSISTENT_GEN_TAG, "Standalone persistent_aposmm didn't exit correctly" - assert persis_info.get("run_order"), "Standalone persistent_aposmm didn't do any localopt runs" - - assert len(potential_minima) >= 6, f"Found {len(potential_minima)} minima" - - tol = 1e-3 - min_found = 0 - for m in minima: - # The minima are known on this test problem. - # We use their values to test APOSMM has identified all minima - print(np.min(np.sum((H[H["local_min"]]["x"] - m) ** 2, 1)), flush=True) - if np.min(np.sum((H[H["local_min"]]["x"] - m) ** 2, 1)) < tol: - min_found += 1 - assert min_found >= 6, f"Found {min_found} minima" + # test initializing/using with default parameters: + my_APOSMM = APOSMM(vocs) + _evaluate_aposmm_instance(my_APOSMM) if __name__ == "__main__": From 4e73c93adf8f444d015990ba97d8523130bac0eb Mon Sep 17 00:00:00 2001 From: jlnav Date: Tue, 26 Aug 2025 14:26:27 -0500 Subject: [PATCH 05/32] replace completely-typed out gen_specs['user'] update from parameters with loop over fields and grabbing the value from locals, as suggested by shuds --- libensemble/gen_classes/aposmm.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/libensemble/gen_classes/aposmm.py b/libensemble/gen_classes/aposmm.py index ac792c31c..3fa1537ac 100644 --- a/libensemble/gen_classes/aposmm.py +++ b/libensemble/gen_classes/aposmm.py @@ -97,15 +97,23 @@ def __init__( gen_specs["user"]["lb"] = np.array([vocs.variables[i].domain[0] for i in vocs.variables]) gen_specs["user"]["ub"] = np.array([vocs.variables[i].domain[1] for i in vocs.variables]) - gen_specs["user"]["initial_sample_size"] = initial_sample_size if sample_points is not None: gen_specs["user"]["sample_points"] = sample_points - gen_specs["user"]["localopt_method"] = localopt_method - gen_specs["user"]["rk_const"] = rk_const - gen_specs["user"]["xtol_abs"] = xtol_abs - gen_specs["user"]["ftol_abs"] = ftol_abs - gen_specs["user"]["dist_to_bound_multiple"] = dist_to_bound_multiple - gen_specs["user"]["max_active_runs"] = max_active_runs + + FIELDS = [ + "initial_sample_size", + "localopt_method", + "rk_const", + "xtol_abs", + "ftol_abs", + "dist_to_bound_multiple", + "max_active_runs", + ] + + for k in FIELDS: + val = locals().get(k) + if val is not None: + gen_specs["user"][k] = val if not gen_specs.get("out"): # gen_specs never especially changes for aposmm even as the problem varies gen_specs["out"] = [ From 4357173fe51320991759cd63cf033a72df446983 Mon Sep 17 00:00:00 2001 From: jlnav Date: Wed, 27 Aug 2025 08:08:30 -0500 Subject: [PATCH 06/32] coverage adjusts --- libensemble/gen_classes/aposmm.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/libensemble/gen_classes/aposmm.py b/libensemble/gen_classes/aposmm.py index 3fa1537ac..b92bb3aa2 100644 --- a/libensemble/gen_classes/aposmm.py +++ b/libensemble/gen_classes/aposmm.py @@ -97,11 +97,9 @@ def __init__( gen_specs["user"]["lb"] = np.array([vocs.variables[i].domain[0] for i in vocs.variables]) gen_specs["user"]["ub"] = np.array([vocs.variables[i].domain[1] for i in vocs.variables]) - if sample_points is not None: - gen_specs["user"]["sample_points"] = sample_points - FIELDS = [ "initial_sample_size", + "sample_points", "localopt_method", "rk_const", "xtol_abs", @@ -115,15 +113,14 @@ def __init__( if val is not None: gen_specs["user"][k] = val - if not gen_specs.get("out"): # gen_specs never especially changes for aposmm even as the problem varies - gen_specs["out"] = [ - ("x", float, self.n), - ("x_on_cube", float, self.n), - ("sim_id", int), - ("local_min", bool), - ("local_pt", bool), - ] - gen_specs["persis_in"] = ["x", "f", "local_pt", "sim_id", "sim_ended", "x_on_cube", "local_min"] + gen_specs["out"] = [ + ("x", float, self.n), + ("x_on_cube", float, self.n), + ("sim_id", int), + ("local_min", bool), + ("local_pt", bool), + ] + gen_specs["persis_in"] = ["x", "f", "local_pt", "sim_id", "sim_ended", "x_on_cube", "local_min"] super().__init__(vocs, History, persis_info, gen_specs, libE_info, **kwargs) if not self.persis_info.get("nworkers"): From ddcddba4b9861b3027338f5fe0962768e81478a2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Sep 2025 19:26:35 +0000 Subject: [PATCH 07/32] Bump crate-ci/typos from 1.35.7 to 1.36.2 Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.35.7 to 1.36.2. - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/v1.35.7...v1.36.2) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.36.2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/basic.yml | 2 +- .github/workflows/extra.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index 42e66ea67..1ed397f16 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -115,4 +115,4 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - - uses: crate-ci/typos@v1.35.7 + - uses: crate-ci/typos@v1.36.2 diff --git a/.github/workflows/extra.yml b/.github/workflows/extra.yml index 3f9a4e7b7..7a9e1bc2d 100644 --- a/.github/workflows/extra.yml +++ b/.github/workflows/extra.yml @@ -144,4 +144,4 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - - uses: crate-ci/typos@v1.35.7 + - uses: crate-ci/typos@v1.36.2 From 04485bed60c13958717b14ca7edd578e73fbd14c Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Tue, 16 Sep 2025 13:20:20 -0500 Subject: [PATCH 08/32] Adding test for ibcdfo with jax --- install/install_ibcdfo.sh | 2 +- ...declare_hfun_and_combine_model_with_jax.py | 50 +++++++ ...t_persistent_aposmm_ibcdfo_pounders_jax.py | 135 ++++++++++++++++++ .../test_persistent_gp_multitask_ax.py | 2 +- 4 files changed, 187 insertions(+), 2 deletions(-) create mode 100644 libensemble/tests/regression_tests/declare_hfun_and_combine_model_with_jax.py create mode 100644 libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_pounders_jax.py diff --git a/install/install_ibcdfo.sh b/install/install_ibcdfo.sh index efd5f6dcb..0ed790f01 100644 --- a/install/install_ibcdfo.sh +++ b/install/install_ibcdfo.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -git clone --recurse-submodules -b develop https://github.com/POptUS/IBCDFO.git +git clone --recurse-submodules -b main https://github.com/POptUS/IBCDFO.git pushd IBCDFO/minq/py/minq5/ export PYTHONPATH="$PYTHONPATH:$(pwd)" echo "PYTHONPATH=$PYTHONPATH" >> $GITHUB_ENV diff --git a/libensemble/tests/regression_tests/declare_hfun_and_combine_model_with_jax.py b/libensemble/tests/regression_tests/declare_hfun_and_combine_model_with_jax.py new file mode 100644 index 000000000..0e49363e2 --- /dev/null +++ b/libensemble/tests/regression_tests/declare_hfun_and_combine_model_with_jax.py @@ -0,0 +1,50 @@ +# This declares the hfun for Test_compare_pounder_pounders_with_jax.py and +# then used jax to combine the quadratic models of each component of the +# inputs to the hfun. +# +# For other general use cases of pounders on smooth hfuns, only the hfun below +# needs to be changed (and combinemodels_jax can be given to pounders) + + +import jax +import numpy + +jax.config.update("jax_enable_x64", True) + + +def hfun(z): + res = z[0] * z[1] - z[2] ** 2 + return res + + +@jax.jit +def hfun_d(z, zd): + resd = jax.jvp(hfun, (z,), (zd,)) + return resd + + +@jax.jit +def hfun_dd(z, zd, zdt, zdd): + _, resdd = jax.jvp(hfun_d, (z, zd), (zdt, zdd)) + return resdd + + +def G_combine(Cres, Gres): + n, m = Gres.shape + G = numpy.zeros(n) + for i in range(n): + _, G[i] = hfun_d(Cres, Gres[i, :]) + return G + + +def H_combine(Cres, Gres, Hres): + n, _, m = Hres.shape + H = numpy.zeros((n, n)) + for i in range(n): + for j in range(n): + _, H[i, j] = hfun_dd(Cres, Gres[i, :], Gres[j, :], Hres[i, j, :]) + return H + + +def combinemodels_jax(Cres, Gres, Hres): + return G_combine(Cres, Gres), H_combine(Cres, Gres, Hres) diff --git a/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_pounders_jax.py b/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_pounders_jax.py new file mode 100644 index 000000000..be8ecf084 --- /dev/null +++ b/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_pounders_jax.py @@ -0,0 +1,135 @@ +""" +Runs libEnsemble with APOSMM+IBCDFO on two test problems. Only a single +optimization run is being performed for the below setup. + +The first case uses POUNDERS to solve the chwirut least-squares problem. For +this case, all chwirut 214 residual calculations for a given point are +performed as a single simulation evaluation. + +The second case uses the generalized POUNDERS to minimize normalized beamline +emittance. The "beamline simulation" is a synthetic polynomial test function +that takes in 4 variables and returning 3 outputs. These outputs represent +position , momentum , and the correlation between them . + +These values are then mapped to the normalized emittance - . + +Execute via one of the following commands: + mpiexec -np 3 python test_persistent_aposmm_ibcdfo_pounders.py + python test_persistent_aposmm_ibcdfo_pounders.py --nworkers 2 +Both will run with 1 manager, 1 worker running APOSMM+IBCDFO, and 1 worker +doing the simulation evaluations. +""" + +# Do not change these lines - they are parsed by run-tests.sh +# TESTSUITE_COMMS: local mpi +# TESTSUITE_NPROCS: 3 + +import multiprocessing +import sys + +import numpy as np + +import libensemble.gen_funcs +from libensemble.libE import libE +from libensemble.sim_funcs.chwirut1 import chwirut_eval + +libensemble.gen_funcs.rc.aposmm_optimizers = "ibcdfo" + +from libensemble.alloc_funcs.persistent_aposmm_alloc import persistent_aposmm_alloc as alloc_f +from libensemble.gen_funcs.persistent_aposmm import aposmm as gen_f +from libensemble.tools import add_unique_random_streams, parse_args, save_libE_output + +try: + from ibcdfo.pounders import pounders # noqa: F401 + from declare_hfun_and_combine_model_with_jax import hfun, combinemodels_jax + +except ModuleNotFoundError: + sys.exit("Please 'pip install ibcdfo'") + +try: + from minqsw import minqsw # noqa: F401 + +except ModuleNotFoundError: + sys.exit("Ensure https://github.com/POptUS/minq has been cloned and that minq/py/minq5/ is on the PYTHONPATH") + + +def sum_squared(x): + return np.sum(np.power(x, 2)) + + +def synthetic_beamline_mapping(H, _, sim_specs): + x = H["x"][0] + assert len(x) == 4, "Assuming 4 inputs to this function" + y = np.zeros(3) # Synthetic beamline outputs + y[0] = x[0] ** 2 + 1.0 + y[1] = x[1] ** 2 + 2.0 + y[2] = x[2] * x[3] + 0.5 + + Out = np.zeros(1, dtype=sim_specs["out"]) + Out["fvec"] = y + Out["f"] = y[0] * y[1] - y[2] ** 2 + return Out + + +# Main block is necessary only when using local comms with spawn start method (default on macOS and Windows). +if __name__ == "__main__": + multiprocessing.set_start_method("fork", force=True) + + nworkers, is_manager, libE_specs, _ = parse_args() + + assert nworkers == 2, "This test is just for two workers" + + m = 3 + n = 4 + sim_f = synthetic_beamline_mapping + + sim_specs = { + "sim_f": sim_f, + "in": ["x"], + "out": [("f", float), ("fvec", float, m)], + } + + gen_out = [ + ("x", float, n), + ("x_on_cube", float, n), + ("sim_id", int), + ("local_min", bool), + ("local_pt", bool), + ("started_run", bool), + ] + + gen_specs = { + "gen_f": gen_f, + "persis_in": ["f", "fvec"] + [n[0] for n in gen_out], + "out": gen_out, + "user": { + "initial_sample_size": 1, + "stop_after_k_runs": 1, + "max_active_runs": 1, + "sample_points": np.atleast_2d(0.1 * (np.arange(n) + 1)), + "localopt_method": "ibcdfo_pounders", + "run_max_eval": 100 * (n + 1), + "components": m, + "lb": -1 * np.ones(n), + "ub": np.ones(n), + }, + } + + gen_specs["user"]["hfun"] = hfun + gen_specs["user"]["combinemodels"] = combinemodels_jax + + alloc_specs = {"alloc_f": alloc_f} + + persis_info = add_unique_random_streams({}, nworkers + 1) + + exit_criteria = {"sim_max": 500} + + # Perform the run + H, persis_info, flag = libE(sim_specs, gen_specs, exit_criteria, persis_info, alloc_specs, libE_specs) + + if is_manager: + print(H[["x", "f", "local_min"]]) + assert persis_info[1].get("run_order"), "Run_order should have been given back" + assert flag == 0 + + save_libE_output(H, persis_info, __file__, nworkers) diff --git a/libensemble/tests/regression_tests/test_persistent_gp_multitask_ax.py b/libensemble/tests/regression_tests/test_persistent_gp_multitask_ax.py index 8c589161a..990493a17 100644 --- a/libensemble/tests/regression_tests/test_persistent_gp_multitask_ax.py +++ b/libensemble/tests/regression_tests/test_persistent_gp_multitask_ax.py @@ -50,7 +50,7 @@ def run_simulation(H, persis_info, sim_specs, libE_info): z = 8 elif task == "cheap_model": z = 1 - print('in sim', task) + print("in sim", task) libE_output = np.zeros(1, dtype=sim_specs["out"]) calc_status = WORKER_DONE From df4a395502ace46545331b1cf4f1f37f17ae9fbb Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Tue, 16 Sep 2025 13:23:49 -0500 Subject: [PATCH 09/32] clenaup --- .../test_persistent_aposmm_ibcdfo_pounders_jax.py | 1 - 1 file changed, 1 deletion(-) diff --git a/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_pounders_jax.py b/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_pounders_jax.py index be8ecf084..a1ed55163 100644 --- a/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_pounders_jax.py +++ b/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_pounders_jax.py @@ -31,7 +31,6 @@ import libensemble.gen_funcs from libensemble.libE import libE -from libensemble.sim_funcs.chwirut1 import chwirut_eval libensemble.gen_funcs.rc.aposmm_optimizers = "ibcdfo" From b370e2b09f70f31ef67dbcbb7f9baf994a6f6561 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 19:09:59 +0000 Subject: [PATCH 10/32] Bump the python-updates group across 1 directory with 3 updates Bumps the python-updates group with 3 updates in the / directory: [pytest](https://github.com/pytest-dev/pytest), [pytest-cov](https://github.com/pytest-dev/pytest-cov) and [globus-compute-sdk](https://github.com/globus/globus-compute). Updates `pytest` from 8.4.1 to 8.4.2 - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/8.4.1...8.4.2) Updates `pytest-cov` from 6.2.1 to 7.0.0 - [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest-cov/compare/v6.2.1...v7.0.0) Updates `globus-compute-sdk` from 3.12.0 to 3.13.0 - [Release notes](https://github.com/globus/globus-compute/releases) - [Changelog](https://github.com/globus/globus-compute/blob/main/docs/changelog.rst) - [Commits](https://github.com/globus/globus-compute/compare/3.12.0...3.13.0) --- updated-dependencies: - dependency-name: pytest dependency-version: 8.4.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: python-updates - dependency-name: pytest-cov dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: python-updates - dependency-name: globus-compute-sdk dependency-version: 3.13.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: python-updates ... Signed-off-by: dependabot[bot] --- install/misc_feature_requirements.txt | 2 +- install/testing_requirements.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/install/misc_feature_requirements.txt b/install/misc_feature_requirements.txt index 2f6284657..af74c8024 100644 --- a/install/misc_feature_requirements.txt +++ b/install/misc_feature_requirements.txt @@ -1 +1 @@ -globus-compute-sdk==3.12.0 +globus-compute-sdk==3.13.0 diff --git a/install/testing_requirements.txt b/install/testing_requirements.txt index 43f0b2291..fa05af02b 100644 --- a/install/testing_requirements.txt +++ b/install/testing_requirements.txt @@ -1,7 +1,7 @@ flake8==7.3.0 coverage>=7.5 -pytest==8.4.1 -pytest-cov==6.2.1 +pytest==8.4.2 +pytest-cov==7.0.0 pytest-timeout==2.4.0 mock==5.2.0 python-dateutil==2.9.0.post0 From e6769bc99d2e8bd3c7573c2523281f866e49b8e6 Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Wed, 17 Sep 2025 08:22:10 -0500 Subject: [PATCH 11/32] Starting a manifold sampling example --- .../gen_funcs/aposmm_localopt_support.py | 68 ++++++++- libensemble/gen_funcs/persistent_aposmm.py | 2 +- ...sistent_aposmm_ibcdfo_manifold_sampling.py | 134 ++++++++++++++++++ 3 files changed, 199 insertions(+), 5 deletions(-) create mode 100644 libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_manifold_sampling.py diff --git a/libensemble/gen_funcs/aposmm_localopt_support.py b/libensemble/gen_funcs/aposmm_localopt_support.py index 3545afd89..584294043 100644 --- a/libensemble/gen_funcs/aposmm_localopt_support.py +++ b/libensemble/gen_funcs/aposmm_localopt_support.py @@ -9,6 +9,7 @@ "run_local_tao", "run_local_dfols", "run_local_ibcdfo_pounders", + "run_local_ibcdfo_manifold_sampling", "run_local_scipy_opt", "run_external_localopt", ] @@ -26,7 +27,7 @@ class APOSMMException(Exception): """Raised for any exception in APOSMM""" -optimizer_list = ["petsc", "nlopt", "dfols", "scipy", "ibcdfo", "external"] +optimizer_list = ["petsc", "nlopt", "dfols", "scipy", "ibcdfo_pounders", "ibcdfo_manifold_sampling", "external"] optimizers = libensemble.gen_funcs.rc.aposmm_optimizers if optimizers is not None: @@ -42,8 +43,10 @@ class APOSMMException(Exception): import nlopt # noqa: F401 if "dfols" in optimizers: import dfols # noqa: F401 - if "ibcdfo" in optimizers: - from ibcdfo import pounders # noqa: F401 + if "ibcdfo_pounders" in optimizers: + from ibcdfo.pounders import pounders # noqa: F401 + if "ibcdfo_manifold_sampling" in optimizers: + from ibcdfo.manifold_sampling import manifold_sampling_primal # noqa: F401 if "scipy" in optimizers: from scipy import optimize as sp_opt # noqa: F401 if "external_localopt" in optimizers: @@ -79,6 +82,7 @@ class LocalOptInterfacer(object): - PETSc/TAO [``'pounders'``, ``'blmvm'``, ``'nm'``] - SciPy [``'scipy_Nelder-Mead'``, ``'scipy_COBYLA'``, ``'scipy_BFGS'``] - DFOLS [``'dfols'``] + - IBCDFO [``'pounders'``, ``'manifold_sampling_primal'``] - External local optimizer [``'external_localopt'``] (which use files to pass/receive ``x/f`` values) """ @@ -123,6 +127,8 @@ def __init__(self, user_specs, x0, f0, grad0=None): run_local_opt = run_local_dfols elif user_specs["localopt_method"] in ["ibcdfo_pounders"]: run_local_opt = run_local_ibcdfo_pounders + elif user_specs["localopt_method"] in ["ibcdfo_manifold_sampling"]: + run_local_opt = run_local_ibcdfo_manifold_sampling elif user_specs["localopt_method"] in ["external_localopt"]: run_local_opt = run_external_localopt else: @@ -416,6 +422,60 @@ def run_local_dfols(user_specs, comm_queue, x0, f0, child_can_read, parent_can_r finish_queue(x_opt, opt_flag, comm_queue, parent_can_read, user_specs) +def run_local_ibcdfo_manifold_sampling(user_specs, comm_queue, x0, f0, child_can_read, parent_can_read): + """ + Runs a IBCDFO local optimization run starting at ``x0``, governed by the + parameters in ``user_specs``. + + Although IBCDFO methods can receive previous evaluations, few other methods + support that, so APOSMM assumes the first point will be re-evaluated (but + not be sent back to the manager). + """ + n = len(x0) + # Define bound constraints (lower <= x <= upper) + lb = np.zeros(n) + ub = np.ones(n) + + # Set random seed (for reproducibility) + np.random.seed(0) + + # dist_to_bound = min(min(ub - x0), min(x0 - lb)) + # assert dist_to_bound > np.finfo(np.float64).eps, "The distance to the boundary is too small" + + run_max_eval = user_specs.get("run_max_eval", 100 * (n + 1)) + # g_tol = 1e-8 + # delta_0 = 0.5 * dist_to_bound + # m = len(f0) + subprob_switch = "linprog" + + + [X, F, hF, flag, xkin] = manifold_sampling_primal( + user_specs["hfun"], + lambda x: scipy_dfols_callback_fun(x, comm_queue, child_can_read, parent_can_read, user_specs), + x0, + lb + ub + run_max_eval, + subprob_switch + ) + + assert flag >= 0 or flag == -6, "IBCDFO errored" + + x_opt = X[xkin] + + if flag == 0 or flag == -6: + opt_flag = 1 + else: + print( + "[APOSMM] The IBCDFO run started from " + str(x0) + " stopped with an exit " + "flag of " + str(flag) + ". No point from this run will be " + "ruled as a minimum! APOSMM may start a new run from some point " + "in this run." + ) + opt_flag = 0 + + finish_queue(x_opt, opt_flag, comm_queue, parent_can_read, user_specs) + def run_local_ibcdfo_pounders(user_specs, comm_queue, x0, f0, child_can_read, parent_can_read): """ @@ -447,7 +507,7 @@ def run_local_ibcdfo_pounders(user_specs, comm_queue, x0, f0, child_can_read, pa else: Options = None - [X, F, hF, flag, xkin] = pounders.pounders( + [X, F, hF, flag, xkin] = pounders( lambda x: scipy_dfols_callback_fun(x, comm_queue, child_can_read, parent_can_read, user_specs), x0, n, diff --git a/libensemble/gen_funcs/persistent_aposmm.py b/libensemble/gen_funcs/persistent_aposmm.py index b1e3a3d9a..685fa4021 100644 --- a/libensemble/gen_funcs/persistent_aposmm.py +++ b/libensemble/gen_funcs/persistent_aposmm.py @@ -739,7 +739,7 @@ def initialize_children(user_specs): "nm", ]: fields_to_pass = ["x_on_cube", "f"] - elif user_specs["localopt_method"] in ["pounders", "ibcdfo_pounders", "dfols"]: + elif user_specs["localopt_method"] in ["pounders", "ibcdfo_pounders", "ibcdfo_manifold_sampling", "dfols"]: fields_to_pass = ["x_on_cube", "fvec"] else: raise NotImplementedError(f"Unknown local optimization method {user_specs['localopt_method']}.") diff --git a/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_manifold_sampling.py b/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_manifold_sampling.py new file mode 100644 index 000000000..4de0f5d24 --- /dev/null +++ b/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_manifold_sampling.py @@ -0,0 +1,134 @@ +""" +Runs libEnsemble with APOSMM+IBCDFO on two test problems. Only a single +optimization run is being performed for the below setup. + +The first case uses POUNDERS to solve the chwirut least-squares problem. For +this case, all chwirut 214 residual calculations for a given point are +performed as a single simulation evaluation. + +The second case uses the generalized POUNDERS to minimize normalized beamline +emittance. The "beamline simulation" is a synthetic polynomial test function +that takes in 4 variables and returning 3 outputs. These outputs represent +position , momentum , and the correlation between them . + +These values are then mapped to the normalized emittance - . + +Execute via one of the following commands: + mpiexec -np 3 python test_persistent_aposmm_ibcdfo_pounders.py + python test_persistent_aposmm_ibcdfo_pounders.py --nworkers 2 +Both will run with 1 manager, 1 worker running APOSMM+IBCDFO, and 1 worker +doing the simulation evaluations. +""" + +# Do not change these lines - they are parsed by run-tests.sh +# TESTSUITE_COMMS: local mpi +# TESTSUITE_NPROCS: 3 + +import multiprocessing +import sys + +import numpy as np + +import libensemble.gen_funcs +from libensemble.libE import libE + +libensemble.gen_funcs.rc.aposmm_optimizers = "ibcdfo" + +from libensemble.alloc_funcs.persistent_aposmm_alloc import persistent_aposmm_alloc as alloc_f +from libensemble.gen_funcs.persistent_aposmm import aposmm as gen_f +from libensemble.tools import add_unique_random_streams, parse_args, save_libE_output + +try: + from ibcdfo.pounders import pounders # noqa: F401 + from declare_hfun_and_combine_model_with_jax import hfun, combinemodels_jax + +except ModuleNotFoundError: + sys.exit("Please 'pip install ibcdfo'") + +try: + from minqsw import minqsw # noqa: F401 + +except ModuleNotFoundError: + sys.exit("Ensure https://github.com/POptUS/minq has been cloned and that minq/py/minq5/ is on the PYTHONPATH") + + +def sum_squared(x): + return np.sum(np.power(x, 2)) + + +def synthetic_beamline_mapping(H, _, sim_specs): + x = H["x"][0] + assert len(x) == 4, "Assuming 4 inputs to this function" + y = np.zeros(3) # Synthetic beamline outputs + y[0] = x[0] ** 2 + 1.0 + y[1] = x[1] ** 2 + 2.0 + y[2] = x[2] * x[3] + 0.5 + + Out = np.zeros(1, dtype=sim_specs["out"]) + Out["fvec"] = y + Out["f"] = y[0] * y[1] - y[2] ** 2 + return Out + + +# Main block is necessary only when using local comms with spawn start method (default on macOS and Windows). +if __name__ == "__main__": + multiprocessing.set_start_method("fork", force=True) + + nworkers, is_manager, libE_specs, _ = parse_args() + + assert nworkers == 2, "This test is just for two workers" + + m = 3 + n = 4 + sim_f = synthetic_beamline_mapping + + sim_specs = { + "sim_f": sim_f, + "in": ["x"], + "out": [("f", float), ("fvec", float, m)], + } + + gen_out = [ + ("x", float, n), + ("x_on_cube", float, n), + ("sim_id", int), + ("local_min", bool), + ("local_pt", bool), + ("started_run", bool), + ] + + gen_specs = { + "gen_f": gen_f, + "persis_in": ["f", "fvec"] + [n[0] for n in gen_out], + "out": gen_out, + "user": { + "initial_sample_size": 1, + "stop_after_k_runs": 1, + "max_active_runs": 1, + "sample_points": np.atleast_2d(0.1 * (np.arange(n) + 1)), + "localopt_method": "ibcdfo_MSP", + "run_max_eval": 100 * (n + 1), + "components": m, + "lb": -1 * np.ones(n), + "ub": np.ones(n), + }, + } + + gen_specs["user"]["hfun"] = hfun + gen_specs["user"]["combinemodels"] = combinemodels_jax + + alloc_specs = {"alloc_f": alloc_f} + + persis_info = add_unique_random_streams({}, nworkers + 1) + + exit_criteria = {"sim_max": 500} + + # Perform the run + H, persis_info, flag = libE(sim_specs, gen_specs, exit_criteria, persis_info, alloc_specs, libE_specs) + + if is_manager: + print(H[["x", "f", "local_min"]]) + assert persis_info[1].get("run_order"), "Run_order should have been given back" + assert flag == 0 + + save_libE_output(H, persis_info, __file__, nworkers) From 0fcc9b555eaf2432486b4e1672afcb6dc9c84408 Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Wed, 17 Sep 2025 10:00:08 -0500 Subject: [PATCH 12/32] Fixing ibcdfo tests --- libensemble/gen_funcs/aposmm_localopt_support.py | 8 ++++---- ...st_persistent_aposmm_ibcdfo_manifold_sampling.py | 13 ++++++------- .../test_persistent_aposmm_ibcdfo_pounders.py | 2 +- .../test_persistent_aposmm_ibcdfo_pounders_jax.py | 2 +- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/libensemble/gen_funcs/aposmm_localopt_support.py b/libensemble/gen_funcs/aposmm_localopt_support.py index 584294043..b18335970 100644 --- a/libensemble/gen_funcs/aposmm_localopt_support.py +++ b/libensemble/gen_funcs/aposmm_localopt_support.py @@ -449,12 +449,12 @@ def run_local_ibcdfo_manifold_sampling(user_specs, comm_queue, x0, f0, child_can subprob_switch = "linprog" - [X, F, hF, flag, xkin] = manifold_sampling_primal( + [X, F, hF, xkin, flag] = manifold_sampling_primal( user_specs["hfun"], lambda x: scipy_dfols_callback_fun(x, comm_queue, child_can_read, parent_can_read, user_specs), x0, - lb - ub + lb, + ub, run_max_eval, subprob_switch ) @@ -463,7 +463,7 @@ def run_local_ibcdfo_manifold_sampling(user_specs, comm_queue, x0, f0, child_can x_opt = X[xkin] - if flag == 0 or flag == -6: + if flag > 0: opt_flag = 1 else: print( diff --git a/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_manifold_sampling.py b/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_manifold_sampling.py index 4de0f5d24..3f7228c84 100644 --- a/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_manifold_sampling.py +++ b/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_manifold_sampling.py @@ -32,15 +32,15 @@ import libensemble.gen_funcs from libensemble.libE import libE -libensemble.gen_funcs.rc.aposmm_optimizers = "ibcdfo" +libensemble.gen_funcs.rc.aposmm_optimizers = "ibcdfo_manifold_sampling" from libensemble.alloc_funcs.persistent_aposmm_alloc import persistent_aposmm_alloc as alloc_f from libensemble.gen_funcs.persistent_aposmm import aposmm as gen_f from libensemble.tools import add_unique_random_streams, parse_args, save_libE_output try: - from ibcdfo.pounders import pounders # noqa: F401 - from declare_hfun_and_combine_model_with_jax import hfun, combinemodels_jax + from ibcdfo.manifold_sampling import manifold_sampling_primal # noqa: F401 + from ibcdfo.manifold_sampling.h_examples import pw_maximum as hfun except ModuleNotFoundError: sys.exit("Please 'pip install ibcdfo'") @@ -66,7 +66,7 @@ def synthetic_beamline_mapping(H, _, sim_specs): Out = np.zeros(1, dtype=sim_specs["out"]) Out["fvec"] = y - Out["f"] = y[0] * y[1] - y[2] ** 2 + Out["f"] = np.max(y) return Out @@ -106,7 +106,7 @@ def synthetic_beamline_mapping(H, _, sim_specs): "stop_after_k_runs": 1, "max_active_runs": 1, "sample_points": np.atleast_2d(0.1 * (np.arange(n) + 1)), - "localopt_method": "ibcdfo_MSP", + "localopt_method": "ibcdfo_manifold_sampling", "run_max_eval": 100 * (n + 1), "components": m, "lb": -1 * np.ones(n), @@ -115,7 +115,6 @@ def synthetic_beamline_mapping(H, _, sim_specs): } gen_specs["user"]["hfun"] = hfun - gen_specs["user"]["combinemodels"] = combinemodels_jax alloc_specs = {"alloc_f": alloc_f} @@ -127,7 +126,7 @@ def synthetic_beamline_mapping(H, _, sim_specs): H, persis_info, flag = libE(sim_specs, gen_specs, exit_criteria, persis_info, alloc_specs, libE_specs) if is_manager: - print(H[["x", "f", "local_min"]]) + assert np.min(H["f"]) == 2.0, "The best is 2" assert persis_info[1].get("run_order"), "Run_order should have been given back" assert flag == 0 diff --git a/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_pounders.py b/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_pounders.py index 7523704a0..753337c9b 100644 --- a/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_pounders.py +++ b/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_pounders.py @@ -33,7 +33,7 @@ from libensemble.libE import libE from libensemble.sim_funcs.chwirut1 import chwirut_eval -libensemble.gen_funcs.rc.aposmm_optimizers = "ibcdfo" +libensemble.gen_funcs.rc.aposmm_optimizers = "ibcdfo_pounders" from libensemble.alloc_funcs.persistent_aposmm_alloc import persistent_aposmm_alloc as alloc_f from libensemble.gen_funcs.persistent_aposmm import aposmm as gen_f diff --git a/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_pounders_jax.py b/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_pounders_jax.py index a1ed55163..9d635ae60 100644 --- a/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_pounders_jax.py +++ b/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_pounders_jax.py @@ -32,7 +32,7 @@ import libensemble.gen_funcs from libensemble.libE import libE -libensemble.gen_funcs.rc.aposmm_optimizers = "ibcdfo" +libensemble.gen_funcs.rc.aposmm_optimizers = "ibcdfo_pounders" from libensemble.alloc_funcs.persistent_aposmm_alloc import persistent_aposmm_alloc as alloc_f from libensemble.gen_funcs.persistent_aposmm import aposmm as gen_f From 3fe637697d382df415223b571b5d0f551e87db9a Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Wed, 17 Sep 2025 10:07:38 -0500 Subject: [PATCH 13/32] black --- libensemble/gen_funcs/aposmm_localopt_support.py | 16 ++++++++-------- ...persistent_aposmm_ibcdfo_manifold_sampling.py | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libensemble/gen_funcs/aposmm_localopt_support.py b/libensemble/gen_funcs/aposmm_localopt_support.py index b18335970..2de29c870 100644 --- a/libensemble/gen_funcs/aposmm_localopt_support.py +++ b/libensemble/gen_funcs/aposmm_localopt_support.py @@ -422,6 +422,7 @@ def run_local_dfols(user_specs, comm_queue, x0, f0, child_can_read, parent_can_r finish_queue(x_opt, opt_flag, comm_queue, parent_can_read, user_specs) + def run_local_ibcdfo_manifold_sampling(user_specs, comm_queue, x0, f0, child_can_read, parent_can_read): """ Runs a IBCDFO local optimization run starting at ``x0``, governed by the @@ -448,15 +449,14 @@ def run_local_ibcdfo_manifold_sampling(user_specs, comm_queue, x0, f0, child_can # m = len(f0) subprob_switch = "linprog" - [X, F, hF, xkin, flag] = manifold_sampling_primal( - user_specs["hfun"], - lambda x: scipy_dfols_callback_fun(x, comm_queue, child_can_read, parent_can_read, user_specs), - x0, - lb, - ub, - run_max_eval, - subprob_switch + user_specs["hfun"], + lambda x: scipy_dfols_callback_fun(x, comm_queue, child_can_read, parent_can_read, user_specs), + x0, + lb, + ub, + run_max_eval, + subprob_switch, ) assert flag >= 0 or flag == -6, "IBCDFO errored" diff --git a/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_manifold_sampling.py b/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_manifold_sampling.py index 3f7228c84..5da91035e 100644 --- a/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_manifold_sampling.py +++ b/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_manifold_sampling.py @@ -66,7 +66,7 @@ def synthetic_beamline_mapping(H, _, sim_specs): Out = np.zeros(1, dtype=sim_specs["out"]) Out["fvec"] = y - Out["f"] = np.max(y) + Out["f"] = np.max(y) return Out From 00b6fc0ef1fb775e5b191fea7684efaef69543f5 Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Wed, 17 Sep 2025 10:15:05 -0500 Subject: [PATCH 14/32] Black --- libensemble/tests/functionality_tests/check_libE_stats.py | 2 +- .../tests/regression_tests/test_persistent_gp_multitask_ax.py | 2 +- libensemble/tests/unit_tests_logger/test_logger.py | 2 +- scripts/plot_libe_calcs_util_v_time.py | 2 +- scripts/plot_libe_histogram.py | 2 +- scripts/plot_libe_tasks_util_v_time.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libensemble/tests/functionality_tests/check_libE_stats.py b/libensemble/tests/functionality_tests/check_libE_stats.py index 424c07d8b..304925dc1 100644 --- a/libensemble/tests/functionality_tests/check_libE_stats.py +++ b/libensemble/tests/functionality_tests/check_libE_stats.py @@ -1,4 +1,4 @@ -""" Script to check format of libE_stats.txt +"""Script to check format of libE_stats.txt Checks matching start and end times existing for calculation and tasks if required. Checks that dates/times are in a valid format. diff --git a/libensemble/tests/regression_tests/test_persistent_gp_multitask_ax.py b/libensemble/tests/regression_tests/test_persistent_gp_multitask_ax.py index 8c589161a..990493a17 100644 --- a/libensemble/tests/regression_tests/test_persistent_gp_multitask_ax.py +++ b/libensemble/tests/regression_tests/test_persistent_gp_multitask_ax.py @@ -50,7 +50,7 @@ def run_simulation(H, persis_info, sim_specs, libE_info): z = 8 elif task == "cheap_model": z = 1 - print('in sim', task) + print("in sim", task) libE_output = np.zeros(1, dtype=sim_specs["out"]) calc_status = WORKER_DONE diff --git a/libensemble/tests/unit_tests_logger/test_logger.py b/libensemble/tests/unit_tests_logger/test_logger.py index e06331b3d..fdf13725f 100644 --- a/libensemble/tests/unit_tests_logger/test_logger.py +++ b/libensemble/tests/unit_tests_logger/test_logger.py @@ -124,7 +124,7 @@ def test_custom_log_levels(): logger_test.manager_warning("This manager_warning message should log") logger_test.vdebug("This vdebug message should log") - with open(LogConfig.config.filename, 'r') as f: + with open(LogConfig.config.filename, "r") as f: file_content = f.read() assert "This manager_warning message should log" in file_content assert "This vdebug message should log" in file_content diff --git a/scripts/plot_libe_calcs_util_v_time.py b/scripts/plot_libe_calcs_util_v_time.py index 9f9f22edd..fc6750a10 100755 --- a/scripts/plot_libe_calcs_util_v_time.py +++ b/scripts/plot_libe_calcs_util_v_time.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -""" User function utilization plot +"""User function utilization plot Script to produce utilization plot based on how many workers are running user functions (sim or gens) at any given time. The plot is written to a file. diff --git a/scripts/plot_libe_histogram.py b/scripts/plot_libe_histogram.py index e5145bc05..936557140 100755 --- a/scripts/plot_libe_histogram.py +++ b/scripts/plot_libe_histogram.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -""" Histogram of user function run-times (completed & killed). +"""Histogram of user function run-times (completed & killed). Script to produce a histogram plot giving a count of user function (sim or gen) calls by run-time intervals. Color shows completed versus killed versus diff --git a/scripts/plot_libe_tasks_util_v_time.py b/scripts/plot_libe_tasks_util_v_time.py index ece34bdaf..cb5ced723 100644 --- a/scripts/plot_libe_tasks_util_v_time.py +++ b/scripts/plot_libe_tasks_util_v_time.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -""" User tasks utilization plot +"""User tasks utilization plot Script to produce utilisation plot based on how many workers are running user tasks (submitted via a libEnsemble executor) at any given time. This does not From 63c082aa912368c059090c1a2505cd21baf2f993 Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Wed, 17 Sep 2025 11:15:29 -0500 Subject: [PATCH 15/32] Updated IBCDFO branch --- install/install_ibcdfo.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/install_ibcdfo.sh b/install/install_ibcdfo.sh index efd5f6dcb..4a55fb143 100644 --- a/install/install_ibcdfo.sh +++ b/install/install_ibcdfo.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -git clone --recurse-submodules -b develop https://github.com/POptUS/IBCDFO.git +git clone --recurse-submodules -b updates_manifold_sampling https://github.com/POptUS/IBCDFO.git pushd IBCDFO/minq/py/minq5/ export PYTHONPATH="$PYTHONPATH:$(pwd)" echo "PYTHONPATH=$PYTHONPATH" >> $GITHUB_ENV From 5d0ae3d7a2ad70fd5d2f262ab1054fde5d96673d Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Wed, 17 Sep 2025 11:16:00 -0500 Subject: [PATCH 16/32] reverting --- install/install_ibcdfo.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/install_ibcdfo.sh b/install/install_ibcdfo.sh index 4a55fb143..efd5f6dcb 100644 --- a/install/install_ibcdfo.sh +++ b/install/install_ibcdfo.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -git clone --recurse-submodules -b updates_manifold_sampling https://github.com/POptUS/IBCDFO.git +git clone --recurse-submodules -b develop https://github.com/POptUS/IBCDFO.git pushd IBCDFO/minq/py/minq5/ export PYTHONPATH="$PYTHONPATH:$(pwd)" echo "PYTHONPATH=$PYTHONPATH" >> $GITHUB_ENV From 334dc8d16e23b7b6de249a7ba034d8d986fc7cd9 Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Wed, 17 Sep 2025 11:17:05 -0500 Subject: [PATCH 17/32] Updated IBCDFO branch --- install/install_ibcdfo.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/install_ibcdfo.sh b/install/install_ibcdfo.sh index 0ed790f01..4a55fb143 100644 --- a/install/install_ibcdfo.sh +++ b/install/install_ibcdfo.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -git clone --recurse-submodules -b main https://github.com/POptUS/IBCDFO.git +git clone --recurse-submodules -b updates_manifold_sampling https://github.com/POptUS/IBCDFO.git pushd IBCDFO/minq/py/minq5/ export PYTHONPATH="$PYTHONPATH:$(pwd)" echo "PYTHONPATH=$PYTHONPATH" >> $GITHUB_ENV From 756a854c5e83b344fa7bf873935dc22739c3f303 Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Thu, 18 Sep 2025 12:16:02 -0500 Subject: [PATCH 18/32] Removing unused def --- .../test_persistent_aposmm_ibcdfo_manifold_sampling.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_manifold_sampling.py b/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_manifold_sampling.py index 5da91035e..9f987eadc 100644 --- a/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_manifold_sampling.py +++ b/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_manifold_sampling.py @@ -52,10 +52,6 @@ sys.exit("Ensure https://github.com/POptUS/minq has been cloned and that minq/py/minq5/ is on the PYTHONPATH") -def sum_squared(x): - return np.sum(np.power(x, 2)) - - def synthetic_beamline_mapping(H, _, sim_specs): x = H["x"][0] assert len(x) == 4, "Assuming 4 inputs to this function" From 385be08845bd5b1511a6442e04012915e75bf4b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Sep 2025 21:55:29 +0000 Subject: [PATCH 19/32] Bump crate-ci/typos from 1.36.2 to 1.36.3 Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.36.2 to 1.36.3. - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/v1.36.2...v1.36.3) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.36.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/basic.yml | 2 +- .github/workflows/extra.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index 1ed397f16..a36035051 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -115,4 +115,4 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - - uses: crate-ci/typos@v1.36.2 + - uses: crate-ci/typos@v1.36.3 diff --git a/.github/workflows/extra.yml b/.github/workflows/extra.yml index 7a9e1bc2d..48819ae8c 100644 --- a/.github/workflows/extra.yml +++ b/.github/workflows/extra.yml @@ -144,4 +144,4 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - - uses: crate-ci/typos@v1.36.2 + - uses: crate-ci/typos@v1.36.3 From 35610f53c27e122d95fea31d5b11e13ee1ec3df1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Sep 2025 22:15:42 +0000 Subject: [PATCH 20/32] Bump the python-updates group across 1 directory with 2 updates Bumps the python-updates group with 2 updates in the / directory: [globus-compute-sdk](https://github.com/globus/globus-compute) and [anyio](https://github.com/agronholm/anyio). Updates `globus-compute-sdk` from 3.13.0 to 3.15.0 - [Release notes](https://github.com/globus/globus-compute/releases) - [Changelog](https://github.com/globus/globus-compute/blob/main/docs/changelog.rst) - [Commits](https://github.com/globus/globus-compute/compare/3.13.0...3.15.0) Updates `anyio` from 4.10.0 to 4.11.0 - [Release notes](https://github.com/agronholm/anyio/releases) - [Changelog](https://github.com/agronholm/anyio/blob/master/docs/versionhistory.rst) - [Commits](https://github.com/agronholm/anyio/compare/4.10.0...4.11.0) --- updated-dependencies: - dependency-name: globus-compute-sdk dependency-version: 3.15.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: python-updates - dependency-name: anyio dependency-version: 4.11.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: python-updates ... Signed-off-by: dependabot[bot] --- install/misc_feature_requirements.txt | 2 +- install/testing_requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/install/misc_feature_requirements.txt b/install/misc_feature_requirements.txt index af74c8024..0f2e99939 100644 --- a/install/misc_feature_requirements.txt +++ b/install/misc_feature_requirements.txt @@ -1 +1 @@ -globus-compute-sdk==3.13.0 +globus-compute-sdk==3.15.0 diff --git a/install/testing_requirements.txt b/install/testing_requirements.txt index fa05af02b..18ef919b7 100644 --- a/install/testing_requirements.txt +++ b/install/testing_requirements.txt @@ -5,7 +5,7 @@ pytest-cov==7.0.0 pytest-timeout==2.4.0 mock==5.2.0 python-dateutil==2.9.0.post0 -anyio==4.10.0 +anyio==4.11.0 matplotlib==3.10.6 mpmath==1.3.0 rich==14.1.0 From 6c0df1db812739defceb467f994d8f5c06d02ad3 Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Tue, 30 Sep 2025 08:57:52 -0500 Subject: [PATCH 21/32] Updating IBCDFO branch --- install/install_ibcdfo.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/install_ibcdfo.sh b/install/install_ibcdfo.sh index 4a55fb143..0ed790f01 100644 --- a/install/install_ibcdfo.sh +++ b/install/install_ibcdfo.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -git clone --recurse-submodules -b updates_manifold_sampling https://github.com/POptUS/IBCDFO.git +git clone --recurse-submodules -b main https://github.com/POptUS/IBCDFO.git pushd IBCDFO/minq/py/minq5/ export PYTHONPATH="$PYTHONPATH:$(pwd)" echo "PYTHONPATH=$PYTHONPATH" >> $GITHUB_ENV From f6665b04cdf4a5cd1fb795564e17e16b3988011a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 19:06:16 +0000 Subject: [PATCH 22/32] Bump crate-ci/typos from 1.36.3 to 1.37.3 Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.36.3 to 1.37.3. - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/v1.36.3...v1.37.3) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.37.3 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/basic.yml | 2 +- .github/workflows/extra.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index a36035051..59aa477b2 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -115,4 +115,4 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - - uses: crate-ci/typos@v1.36.3 + - uses: crate-ci/typos@v1.37.3 diff --git a/.github/workflows/extra.yml b/.github/workflows/extra.yml index 48819ae8c..26ba757f0 100644 --- a/.github/workflows/extra.yml +++ b/.github/workflows/extra.yml @@ -144,4 +144,4 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - - uses: crate-ci/typos@v1.36.3 + - uses: crate-ci/typos@v1.37.3 From b7b539f6d590f04de2d9a96bd9d8db798060a080 Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Mon, 6 Oct 2025 14:29:38 -0500 Subject: [PATCH 23/32] typo --- libensemble/gen_funcs/persistent_sampling.py | 2 +- pyproject.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libensemble/gen_funcs/persistent_sampling.py b/libensemble/gen_funcs/persistent_sampling.py index 401ccdaa9..375d7f438 100644 --- a/libensemble/gen_funcs/persistent_sampling.py +++ b/libensemble/gen_funcs/persistent_sampling.py @@ -30,7 +30,7 @@ def _get_user_params(user_specs): @persistent_input_fields(["sim_id"]) -@output_data([("x", float, (2,))]) # The dimesion of 2 is a default and can be overwritten +@output_data([("x", float, (2,))]) # The dimension of 2 is a default and can be overwritten def persistent_uniform(_, persis_info, gen_specs, libE_info): """ This generation function always enters into persistent mode and returns diff --git a/pyproject.toml b/pyproject.toml index 68d5654da..80535d8cb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -134,6 +134,7 @@ HPE = "HPE" RO = "RO" lst = "lst" noy = "noy" +inpt = "inpt" [tool.typos.files] extend-exclude = ["*.bib", "*.xml", "docs/nitpicky"] From 95dd27569eb9b35dce25c84c93b91b496c9e90ef Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Mon, 6 Oct 2025 14:30:16 -0500 Subject: [PATCH 24/32] typo --- libensemble/gen_funcs/persistent_gpCAM.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libensemble/gen_funcs/persistent_gpCAM.py b/libensemble/gen_funcs/persistent_gpCAM.py index 05b08bb5e..262ca2d6b 100644 --- a/libensemble/gen_funcs/persistent_gpCAM.py +++ b/libensemble/gen_funcs/persistent_gpCAM.py @@ -158,7 +158,7 @@ def persistent_gpCAM(H_in, persis_info, gen_specs, libE_info): """ This generation function constructs a global surrogate of `f` values. It is a batched method that produces a first batch uniformly random from (lb, ub). - On subequent iterations, it calls an optimization method to produce the next + On subsequent iterations, it calls an optimization method to produce the next batch of points. This optimization might be too slow (relative to the simulation evaluation time) for some use cases. From 1a68569cea248a34fe91d91fbf89722878b14725 Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Mon, 6 Oct 2025 14:33:16 -0500 Subject: [PATCH 25/32] typo --- libensemble/gen_funcs/persistent_ax_multitask.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libensemble/gen_funcs/persistent_ax_multitask.py b/libensemble/gen_funcs/persistent_ax_multitask.py index ede50e46b..0a2e07f20 100644 --- a/libensemble/gen_funcs/persistent_ax_multitask.py +++ b/libensemble/gen_funcs/persistent_ax_multitask.py @@ -376,9 +376,9 @@ def max_utility_from_GP(n, m, gr, hifi_task): f, cov = m.predict(obsf) # Compute expected utility u = -np.array(f["hifi_metric"]) - best_arm_indx = np.flip(np.argsort(u))[:n] + best_arm_index = np.flip(np.argsort(u))[:n] gr_new = GeneratorRun( - arms=[gr.arms[i] for i in best_arm_indx], + arms=[gr.arms[i] for i in best_arm_index], weights=[1.0] * n, ) return gr_new From 11970ae38c22dcd9dfa6ff51bcf7b06bf01624cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Oct 2025 19:12:01 +0000 Subject: [PATCH 26/32] Bump crate-ci/typos from 1.37.3 to 1.38.1 Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.37.3 to 1.38.1. - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/v1.37.3...v1.38.1) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.38.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/basic.yml | 2 +- .github/workflows/extra.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index 59aa477b2..aa363f426 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -115,4 +115,4 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - - uses: crate-ci/typos@v1.37.3 + - uses: crate-ci/typos@v1.38.1 diff --git a/.github/workflows/extra.yml b/.github/workflows/extra.yml index 26ba757f0..e41de99af 100644 --- a/.github/workflows/extra.yml +++ b/.github/workflows/extra.yml @@ -144,4 +144,4 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - - uses: crate-ci/typos@v1.37.3 + - uses: crate-ci/typos@v1.38.1 From d74e5f13ad0b81670fdbc52b8a53d48488eb667a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Oct 2025 19:22:23 +0000 Subject: [PATCH 27/32] Bump the python-updates group with 3 updates Bumps the python-updates group with 3 updates: [matplotlib](https://github.com/matplotlib/matplotlib), [globus-compute-sdk](https://github.com/globus/globus-compute) and [rich](https://github.com/Textualize/rich). Updates `matplotlib` from 3.10.6 to 3.10.7 - [Release notes](https://github.com/matplotlib/matplotlib/releases) - [Commits](https://github.com/matplotlib/matplotlib/compare/v3.10.6...v3.10.7) Updates `globus-compute-sdk` from 3.15.0 to 3.16.0 - [Release notes](https://github.com/globus/globus-compute/releases) - [Changelog](https://github.com/globus/globus-compute/blob/main/docs/changelog.rst) - [Commits](https://github.com/globus/globus-compute/compare/3.15.0...3.16.0) Updates `rich` from 14.1.0 to 14.2.0 - [Release notes](https://github.com/Textualize/rich/releases) - [Changelog](https://github.com/Textualize/rich/blob/master/CHANGELOG.md) - [Commits](https://github.com/Textualize/rich/compare/v14.1.0...v14.2.0) --- updated-dependencies: - dependency-name: matplotlib dependency-version: 3.10.7 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: python-updates - dependency-name: globus-compute-sdk dependency-version: 3.16.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: python-updates - dependency-name: rich dependency-version: 14.2.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: python-updates ... Signed-off-by: dependabot[bot] --- install/misc_feature_requirements.txt | 2 +- install/testing_requirements.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/install/misc_feature_requirements.txt b/install/misc_feature_requirements.txt index 0f2e99939..fca53eac4 100644 --- a/install/misc_feature_requirements.txt +++ b/install/misc_feature_requirements.txt @@ -1 +1 @@ -globus-compute-sdk==3.15.0 +globus-compute-sdk==3.16.0 diff --git a/install/testing_requirements.txt b/install/testing_requirements.txt index 18ef919b7..0d6a40fa2 100644 --- a/install/testing_requirements.txt +++ b/install/testing_requirements.txt @@ -6,6 +6,6 @@ pytest-timeout==2.4.0 mock==5.2.0 python-dateutil==2.9.0.post0 anyio==4.11.0 -matplotlib==3.10.6 +matplotlib==3.10.7 mpmath==1.3.0 -rich==14.1.0 +rich==14.2.0 From 948c88baebb021e980996c03f3b84b51107d3acc Mon Sep 17 00:00:00 2001 From: jlnav Date: Thu, 23 Oct 2025 12:53:00 -0500 Subject: [PATCH 28/32] this specific gen_specs['out'] assignment no longer needed, as conflicts with using variables_mapping later on --- libensemble/gen_classes/aposmm.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/libensemble/gen_classes/aposmm.py b/libensemble/gen_classes/aposmm.py index 5fe417dc5..60ae2ef8b 100644 --- a/libensemble/gen_classes/aposmm.py +++ b/libensemble/gen_classes/aposmm.py @@ -129,13 +129,6 @@ def __init__( if val is not None: gen_specs["user"][k] = val - gen_specs["out"] = [ - ("x", float, self.n), - ("x_on_cube", float, self.n), - ("sim_id", int), - ("local_min", bool), - ("local_pt", bool), - ] gen_specs["persis_in"] = ["x", "f", "local_pt", "sim_id", "sim_ended", "x_on_cube", "local_min"] super().__init__(vocs, History, persis_info, gen_specs, libE_info, **kwargs) From 047673d1cf90dccce10769c278c4cd25ce7632af Mon Sep 17 00:00:00 2001 From: jlnav Date: Thu, 23 Oct 2025 13:44:24 -0500 Subject: [PATCH 29/32] adjust for finalize and export; plus now variables_mapping is required --- libensemble/tests/unit_tests/test_persistent_aposmm.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/libensemble/tests/unit_tests/test_persistent_aposmm.py b/libensemble/tests/unit_tests/test_persistent_aposmm.py index 00dc0edf0..3299da917 100644 --- a/libensemble/tests/unit_tests/test_persistent_aposmm.py +++ b/libensemble/tests/unit_tests/test_persistent_aposmm.py @@ -150,7 +150,8 @@ def _evaluate_aposmm_instance(my_APOSMM): point["energy"] = six_hump_camel_func(np.array([point["core"], point["edge"]])) total_evals += 1 my_APOSMM.ingest(sample) - H, persis_info, exit_code = my_APOSMM.finalize() + my_APOSMM.finalize() + H, persis_info, exit_code = my_APOSMM.export() assert exit_code == FINISHED_PERSISTENT_GEN_TAG, "Standalone persistent_aposmm didn't exit correctly" assert persis_info.get("run_order"), "Standalone persistent_aposmm didn't do any localopt runs" @@ -254,10 +255,6 @@ def test_asktell_with_persistent_aposmm(): _evaluate_aposmm_instance(my_APOSMM) - # test initializing/using with default parameters: - my_APOSMM = APOSMM(vocs) - _evaluate_aposmm_instance(my_APOSMM) - def _run_aposmm_export_test(variables_mapping): """Helper function to run APOSMM export tests with given variables_mapping""" From b681398e18b0f0492e19fa6d1591aa8ee75090e4 Mon Sep 17 00:00:00 2001 From: jlnav Date: Thu, 23 Oct 2025 14:45:11 -0500 Subject: [PATCH 30/32] don't need persis_info declared like this --- libensemble/gen_classes/aposmm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libensemble/gen_classes/aposmm.py b/libensemble/gen_classes/aposmm.py index 60ae2ef8b..f5b3de14d 100644 --- a/libensemble/gen_classes/aposmm.py +++ b/libensemble/gen_classes/aposmm.py @@ -101,7 +101,7 @@ def __init__( self.VOCS = vocs gen_specs = {} - persis_info = {"1": np.random.default_rng(random_seed)} + persis_info = {} libE_info = {} gen_specs["gen_f"] = aposmm self.n = len(list(self.VOCS.variables.keys())) From b828cb4df8b469337cfed82e620a3247e2b2ec41 Mon Sep 17 00:00:00 2001 From: jlnav Date: Fri, 24 Oct 2025 10:00:41 -0500 Subject: [PATCH 31/32] fixes and refactors as suggested by shuds - *works on multistage lpa* --- libensemble/gen_classes/aposmm.py | 48 +++++++++++++------------------ 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/libensemble/gen_classes/aposmm.py b/libensemble/gen_classes/aposmm.py index f5b3de14d..dc12e00a7 100644 --- a/libensemble/gen_classes/aposmm.py +++ b/libensemble/gen_classes/aposmm.py @@ -101,17 +101,14 @@ def __init__( self.VOCS = vocs gen_specs = {} + gen_specs["user"] = {} persis_info = {} libE_info = {} gen_specs["gen_f"] = aposmm - self.n = len(list(self.VOCS.variables.keys())) + n = len(list(vocs.variables.keys())) if not rk_const: - rk_const = 0.5 * ((gamma(1 + (self.n / 2)) * 5) ** (1 / self.n)) / sqrt(pi) - - gen_specs["user"] = {} - gen_specs["user"]["lb"] = np.array([vocs.variables[i].domain[0] for i in vocs.variables]) - gen_specs["user"]["ub"] = np.array([vocs.variables[i].domain[1] for i in vocs.variables]) + rk_const = 0.5 * ((gamma(1 + (n / 2)) * 5) ** (1 / n)) / sqrt(pi) FIELDS = [ "initial_sample_size", @@ -129,7 +126,6 @@ def __init__( if val is not None: gen_specs["user"][k] = val - gen_specs["persis_in"] = ["x", "f", "local_pt", "sim_id", "sim_ended", "x_on_cube", "local_min"] super().__init__(vocs, History, persis_info, gen_specs, libE_info, **kwargs) # Set bounds using the correct x mapping @@ -137,29 +133,25 @@ def __init__( self.gen_specs["user"]["lb"] = np.array([vocs.variables[var].domain[0] for var in x_mapping]) self.gen_specs["user"]["ub"] = np.array([vocs.variables[var].domain[1] for var in x_mapping]) - if not gen_specs.get("out"): - x_size = len(self.variables_mapping.get("x", [])) - x_on_cube_size = len(self.variables_mapping.get("x_on_cube", [])) - assert x_size > 0 and x_on_cube_size > 0, "Both x and x_on_cube must be specified in variables_mapping" - assert ( - x_size == x_on_cube_size - ), f"x and x_on_cube must have same length but got {x_size} and {x_on_cube_size}" - - gen_specs["out"] = [ - ("x", float, x_size), - ("x_on_cube", float, x_on_cube_size), - ("sim_id", int), - ("local_min", bool), - ("local_pt", bool), - ] - - gen_specs["persis_in"] = ["sim_id", "x", "x_on_cube", "f", "sim_ended"] - if "components" in kwargs or "components" in gen_specs.get("user", {}): - gen_specs["persis_in"].append("fvec") + x_size = len(self.variables_mapping.get("x", [])) + x_on_cube_size = len(self.variables_mapping.get("x_on_cube", [])) + assert x_size > 0 and x_on_cube_size > 0, "Both x and x_on_cube must be specified in variables_mapping" + assert x_size == x_on_cube_size, f"x and x_on_cube must have same length but got {x_size} and {x_on_cube_size}" + + gen_specs["out"] = [ + ("x", float, x_size), + ("x_on_cube", float, x_on_cube_size), + ("sim_id", int), + ("local_min", bool), + ("local_pt", bool), + ] + + gen_specs["persis_in"] = ["sim_id", "x", "x_on_cube", "f", "sim_ended"] + if "components" in kwargs or "components" in gen_specs.get("user", {}): + gen_specs["persis_in"].append("fvec") # SH - Need to know if this is gen_on_manager or not. - if not self.persis_info.get("nworkers"): - self.persis_info["nworkers"] = kwargs.get("nworkers", gen_specs["user"].get("max_active_runs", 4)) + self.persis_info["nworkers"] = kwargs.get("nworkers", gen_specs["user"].get("max_active_runs", 4)) self.all_local_minima = [] self._suggest_idx = 0 self._last_suggest = None From c0407212d3ee3ac7e05486960643d7031e558086 Mon Sep 17 00:00:00 2001 From: jlnav Date: Wed, 29 Oct 2025 14:07:13 -0500 Subject: [PATCH 32/32] make initial_sample_size and max_active_runs required arguments for aposmm class - and rearrange to be higher in the docstring and signature --- libensemble/gen_classes/aposmm.py | 24 +++++++++---------- .../test_asktell_aposmm_nlopt.py | 2 +- .../unit_tests/test_persistent_aposmm.py | 8 +++---- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/libensemble/gen_classes/aposmm.py b/libensemble/gen_classes/aposmm.py index dc12e00a7..886171821 100644 --- a/libensemble/gen_classes/aposmm.py +++ b/libensemble/gen_classes/aposmm.py @@ -35,22 +35,23 @@ class APOSMM(PersistentGenInterfacer): "x": ["var1", "var2", "var3"], "x_on_cube": ["var1_on_cube", "var2_on_cube", "var3_on_cube"], } - gen = APOSMM(vocs, variables_mapping=variables_mapping, ...) + gen = APOSMM(vocs, 3, 3, variables_mapping=variables_mapping, ...) Parameters ---------- vocs: VOCS The VOCS object, adhering to the VOCS interface from the Generator Standard. + max_active_runs: int + Bound on number of runs APOSMM is advancing. + + initial_sample_size: int + Number of uniformly sampled points to be evaluated internally before starting + the localopt runs. `.suggest()` will return samples from these points. + History: npt.NDArray = [] An optional history of previously evaluated points. - initial_sample_size: int = 100 - Number of uniformly sampled points - to be evaluated before starting the localopt runs. Can be - zero if no additional sampling is desired, but if zero there must be past values - provided in the History. - sample_points: npt.NDArray = None Points to be sampled (original domain). If more sample points are needed by APOSMM during the course of the @@ -73,9 +74,6 @@ class APOSMM(PersistentGenInterfacer): What fraction of the distance to the nearest boundary should the initial step size be in localopt runs. - max_active_runs: int = 6 - Bound on number of runs APOSMM is advancing. - random_seed: int = 1 Seed for the random number generator. """ @@ -83,15 +81,15 @@ class APOSMM(PersistentGenInterfacer): def __init__( self, vocs: VOCS, + max_active_runs: int, + initial_sample_size: int, History: npt.NDArray = [], - initial_sample_size: int = 100, sample_points: npt.NDArray = None, localopt_method: str = "LN_BOBYQA", rk_const: float = None, xtol_abs: float = 1e-6, ftol_abs: float = 1e-6, dist_to_bound_multiple: float = 0.5, - max_active_runs: int = 6, random_seed: int = 1, **kwargs, ) -> None: @@ -151,7 +149,7 @@ def __init__( gen_specs["persis_in"].append("fvec") # SH - Need to know if this is gen_on_manager or not. - self.persis_info["nworkers"] = kwargs.get("nworkers", gen_specs["user"].get("max_active_runs", 4)) + self.persis_info["nworkers"] = gen_specs["user"].get("max_active_runs") self.all_local_minima = [] self._suggest_idx = 0 self._last_suggest = None diff --git a/libensemble/tests/regression_tests/test_asktell_aposmm_nlopt.py b/libensemble/tests/regression_tests/test_asktell_aposmm_nlopt.py index 0f80e42ca..67716dca1 100644 --- a/libensemble/tests/regression_tests/test_asktell_aposmm_nlopt.py +++ b/libensemble/tests/regression_tests/test_asktell_aposmm_nlopt.py @@ -59,6 +59,7 @@ aposmm = APOSMM( vocs, + max_active_runs=workflow.nworkers, # should this match nworkers always? practically? variables_mapping={"x": ["core", "edge"], "x_on_cube": ["core_on_cube", "edge_on_cube"], "f": ["energy"]}, initial_sample_size=100, sample_points=minima, @@ -66,7 +67,6 @@ rk_const=0.5 * ((gamma(1 + (n / 2)) * 5) ** (1 / n)) / sqrt(pi), xtol_abs=1e-6, ftol_abs=1e-6, - max_active_runs=workflow.nworkers, # should this match nworkers always? practically? ) # SH TODO - dont want this stuff duplicated - pass with vocs instead diff --git a/libensemble/tests/unit_tests/test_persistent_aposmm.py b/libensemble/tests/unit_tests/test_persistent_aposmm.py index 3299da917..05aee2137 100644 --- a/libensemble/tests/unit_tests/test_persistent_aposmm.py +++ b/libensemble/tests/unit_tests/test_persistent_aposmm.py @@ -242,15 +242,15 @@ def test_asktell_with_persistent_aposmm(): my_APOSMM = APOSMM( vocs, - variables_mapping=variables_mapping, + max_active_runs=6, initial_sample_size=100, + variables_mapping=variables_mapping, sample_points=np.round(minima, 1), localopt_method="LN_BOBYQA", rk_const=0.5 * ((gamma(1 + (n / 2)) * 5) ** (1 / n)) / sqrt(pi), xtol_abs=1e-6, ftol_abs=1e-6, dist_to_bound_multiple=0.5, - max_active_runs=6, ) _evaluate_aposmm_instance(my_APOSMM) @@ -273,13 +273,13 @@ def _run_aposmm_export_test(variables_mapping): vocs = VOCS(variables=variables, objectives=objectives) aposmm = APOSMM( vocs, - variables_mapping=variables_mapping, + max_active_runs=6, initial_sample_size=10, + variables_mapping=variables_mapping, localopt_method="LN_BOBYQA", xtol_abs=1e-6, ftol_abs=1e-6, dist_to_bound_multiple=0.5, - max_active_runs=6, ) # Test basic export before finalize H, _, _ = aposmm.export()