diff --git a/.flake8 b/.flake8 index 87d249502..3aa9cac96 100644 --- a/.flake8 +++ b/.flake8 @@ -38,6 +38,7 @@ per-file-ignores = # Need to set something before the APOSMM import libensemble/tests/regression_tests/test_persistent_aposmm*:E402 + libensemble/tests/regression_tests/test_aposmm*:E402 libensemble/tests/regression_tests/test_asktell_aposmm_nlopt.py:E402 libensemble/tests/regression_tests/test_persistent_gp_multitask_ax.py:E402 libensemble/tests/functionality_tests/test_uniform_sampling_then_persistent_localopt_runs.py:E402 diff --git a/libensemble/tests/regression_tests/test_aposmm_exception.py b/libensemble/tests/regression_tests/test_aposmm_exception.py new file mode 100644 index 000000000..5018d5f5e --- /dev/null +++ b/libensemble/tests/regression_tests/test_aposmm_exception.py @@ -0,0 +1,95 @@ +""" +Tests the APOSMM generator's ability to handle exceptions. + +The periodic_func with LN_BOBYQA generates NLopt roundoff-limited errors, +which should propagate as exceptions to the calling script. + +Execute via one of the following commands (e.g. 3 workers): + mpiexec -np 4 python test_aposmm_exception.py + python test_aposmm_exception.py --nworkers 3 --comms local + +When running with the above commands, the number of concurrent evaluations of +the objective function will be 3, as the generator runs on the manager. +""" + +# Do not change these lines - they are parsed by run-tests.sh +# TESTSUITE_COMMS: local mpi +# TESTSUITE_NPROCS: 4 +# TESTSUITE_EXTRA: true + +import numpy as np + +import libensemble.gen_funcs + +libensemble.gen_funcs.rc.aposmm_optimizers = "nlopt" + +from gest_api.vocs import VOCS + +from libensemble import Ensemble +from libensemble.gen_classes import APOSMM +from libensemble.specs import ExitCriteria, GenSpecs, LibeSpecs, SimSpecs + + +def periodic_func(x): + """ + Periodic test function (gest-api version of periodic_func.func_wrapper). + """ + from numpy import cos, sin + + return {"f": sin(x["x0"]) * cos(x["x1"])} + + +# Main block is necessary only when using local comms with spawn start method (default on macOS and Windows). +if __name__ == "__main__": + workflow = Ensemble(parse_args=True) + + vocs = VOCS( + variables={ + "x0": [0, 2 * np.pi], + "x1": [-np.pi / 2, 3 * np.pi / 2], + "x0_on_cube": [0, 1], + "x1_on_cube": [0, 1], + }, + objectives={"f": "MINIMIZE"}, + ) + + aposmm = APOSMM( + vocs, + max_active_runs=6, + initial_sample_size=100, + variables_mapping={ + "x": ["x0", "x1"], + "x_on_cube": ["x0_on_cube", "x1_on_cube"], + "f": ["f"], + }, + localopt_method="LN_BOBYQA", + ) + + workflow.gen_specs = GenSpecs( + generator=aposmm, + vocs=vocs, + initial_batch_size=100, + ) + workflow.sim_specs = SimSpecs(simulator=periodic_func, vocs=vocs) + workflow.exit_criteria = ExitCriteria(sim_max=1000) + workflow.libE_specs = LibeSpecs(abort_on_exception=False) + + exception_raised = False + try: + workflow.run() + except Exception: + if workflow.is_manager: + exception_raised = True + + if workflow.is_manager: + if workflow.libE_specs.comms == "mpi": + from mpi4py import MPI + + if exception_raised: + print("\n\nMPI will be aborted as planned\n\n", flush=True) + MPI.COMM_WORLD.Abort(0) + else: + MPI.COMM_WORLD.Abort(1) + else: + assert exception_raised, "Expected an exception from the NLopt roundoff-limited error" + print("\n\nException received as expected") diff --git a/libensemble/tests/regression_tests/test_asktell_aposmm_nlopt.py b/libensemble/tests/regression_tests/test_aposmm_nlopt.py similarity index 72% rename from libensemble/tests/regression_tests/test_asktell_aposmm_nlopt.py rename to libensemble/tests/regression_tests/test_aposmm_nlopt.py index 2a68d6e72..40ebcc497 100644 --- a/libensemble/tests/regression_tests/test_asktell_aposmm_nlopt.py +++ b/libensemble/tests/regression_tests/test_aposmm_nlopt.py @@ -2,13 +2,12 @@ Runs libEnsemble with APOSMM with the NLopt local optimizer. Execute via one of the following commands (e.g. 3 workers): - mpiexec -np 4 python test_persistent_aposmm_nlopt.py - python test_persistent_aposmm_nlopt.py --nworkers 3 --comms local - python test_persistent_aposmm_nlopt.py --nworkers 3 --comms tcp + mpiexec -np 4 python test_aposmm_nlopt.py + python test_aposmm_nlopt.py --nworkers 3 --comms local + python test_aposmm_nlopt.py --nworkers 3 --comms tcp When running with the above commands, the number of concurrent evaluations of -the objective function will be 2, as one of the three workers will be the -persistent generator. +the objective function will be 3, as the generator runs on the manager. """ # Do not change these lines - they are parsed by run-tests.sh @@ -21,8 +20,6 @@ import libensemble.gen_funcs -# Import libEnsemble items for this test - libensemble.gen_funcs.rc.aposmm_optimizers = "nlopt" from time import time @@ -38,13 +35,12 @@ def six_hump_camel_func(x): """ Definition of the six-hump camel """ - x1 = x["core"] - x2 = x["edge"] + x1 = x["x0"] + x2 = x["x1"] term1 = (4 - 2.1 * x1**2 + (x1**4) / 3) * x1**2 term2 = x1 * x2 term3 = (-4 + 4 * x2**2) * x2**2 - - return {"energy": term1 + term2 + term3} + return {"f": term1 + term2 + term3} # Main block is necessary only when using local comms with spawn start method (default on macOS and Windows). @@ -58,39 +54,39 @@ def six_hump_camel_func(x): vocs = VOCS( variables={ - "core": [-3, 3], - "edge": [-2, 2], - "core_on_cube": [0, 1], - "edge_on_cube": [0, 1], + "x0": [-3, 3], + "x1": [-2, 2], + "x0_on_cube": [0, 1], + "x1_on_cube": [0, 1], }, - objectives={"energy": "MINIMIZE"}, + objectives={"f": "MINIMIZE"}, ) aposmm = APOSMM( vocs, max_active_runs=6, variables_mapping={ - "x": ["core", "edge"], - "x_on_cube": ["core_on_cube", "edge_on_cube"], - "f": ["energy"], + "x": ["x0", "x1"], + "x_on_cube": ["x0_on_cube", "x1_on_cube"], + "f": ["f"], }, - initial_sample_size=200, + initial_sample_size=100, 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, ) workflow.gen_specs = GenSpecs( generator=aposmm, vocs=vocs, - batch_size=5, - initial_batch_size=10, + initial_batch_size=100, ) workflow.sim_specs = SimSpecs(simulator=six_hump_camel_func, vocs=vocs) - workflow.exit_criteria = ExitCriteria(sim_max=3000, wallclock_max=600) + workflow.exit_criteria = ExitCriteria(sim_max=3000) # Perform the run H, _, _ = workflow.run() diff --git a/libensemble/tests/regression_tests/test_aposmm_periodic.py b/libensemble/tests/regression_tests/test_aposmm_periodic.py new file mode 100644 index 000000000..b59183ff1 --- /dev/null +++ b/libensemble/tests/regression_tests/test_aposmm_periodic.py @@ -0,0 +1,96 @@ +""" +Tests the 'periodic' domain use case for APOSMM with an NLopt local +optimization method. + +Execute via one of the following commands (e.g. 3 workers): + mpiexec -np 4 python test_aposmm_periodic.py + python test_aposmm_periodic.py --nworkers 3 --comms local + +When running with the above commands, the number of concurrent evaluations of +the objective function will be 3, as the generator runs on the manager. +""" + +# Do not change these lines - they are parsed by run-tests.sh +# TESTSUITE_COMMS: local mpi +# TESTSUITE_NPROCS: 4 +# TESTSUITE_EXTRA: true + +import numpy as np + +import libensemble.gen_funcs + +libensemble.gen_funcs.rc.aposmm_optimizers = "nlopt" + +from gest_api.vocs import VOCS + +from libensemble import Ensemble +from libensemble.gen_classes import APOSMM +from libensemble.specs import ExitCriteria, GenSpecs, SimSpecs + + +def periodic_func(x): + """ + Periodic test function (gest-api version of periodic_func.func_wrapper). + """ + from numpy import cos, sin + + return {"f": sin(x["x0"]) * cos(x["x1"])} + + +# Main block is necessary only when using local comms with spawn start method (default on macOS and Windows). +if __name__ == "__main__": + workflow = Ensemble(parse_args=True) + + vocs = VOCS( + variables={ + "x0": [0, 2 * np.pi], + "x1": [-np.pi / 2, 3 * np.pi / 2], + "x0_on_cube": [0, 1], + "x1_on_cube": [0, 1], + }, + objectives={"f": "MINIMIZE"}, + ) + + variables_mapping = { + "x": ["x0", "x1"], + "x_on_cube": ["x0_on_cube", "x1_on_cube"], + "f": ["f"], + } + + aposmm = APOSMM( + vocs, + max_active_runs=6, + initial_sample_size=100, + variables_mapping=variables_mapping, + localopt_method="LN_BOBYQA", + xtol_abs=1e-8, + ftol_abs=1e-8, + periodic=True, + print=True, + ) + + workflow.gen_specs = GenSpecs( + generator=aposmm, + vocs=vocs, + initial_batch_size=100, + ) + workflow.sim_specs = SimSpecs(simulator=periodic_func, vocs=vocs) + workflow.exit_criteria = ExitCriteria(sim_max=1000) + + H, _, _ = workflow.run() + + if workflow.is_manager: + min_ids = np.where(H["local_min"]) + + # The minima are known on this test problem. If the above [lb, ub] domain is + # shifted/scaled to [0,1]^n, they all have value [0.25, 0.75] or [0.75, 0.25] + minima = np.array([[0.25, 0.75], [0.75, 0.25]]) + tol = 2e-4 + + for x in H["x_on_cube"][min_ids]: + print(x) + print(np.linalg.norm(x - minima[0])) + print(np.linalg.norm(x - minima[1]), flush=True) + + for x in H["x_on_cube"][min_ids]: + assert np.linalg.norm(x - minima[0]) < tol or np.linalg.norm(x - minima[1]) < tol diff --git a/libensemble/tests/regression_tests/test_aposmm_scipy.py b/libensemble/tests/regression_tests/test_aposmm_scipy.py new file mode 100644 index 000000000..7a24588d2 --- /dev/null +++ b/libensemble/tests/regression_tests/test_aposmm_scipy.py @@ -0,0 +1,103 @@ +""" +Runs libEnsemble with APOSMM and SciPy local optimization routines. + +Execute via one of the following commands (e.g. 3 workers): + mpiexec -np 4 python test_aposmm_scipy.py + python test_aposmm_scipy.py --nworkers 3 --comms local + python test_aposmm_scipy.py --nworkers 3 --comms tcp + +When running with the above commands, the number of concurrent evaluations of +the objective function will be 3, as the generator runs on the manager. +""" + +# Do not change these lines - they are parsed by run-tests.sh +# TESTSUITE_COMMS: mpi local +# TESTSUITE_NPROCS: 4 + +import numpy as np + +import libensemble.gen_funcs + +libensemble.gen_funcs.rc.aposmm_optimizers = "scipy" +from time import time + +from gest_api.vocs import VOCS + +from libensemble import Ensemble +from libensemble.gen_classes import APOSMM +from libensemble.specs import ExitCriteria, GenSpecs, SimSpecs +from libensemble.tests.regression_tests.support import six_hump_camel_minima as minima + + +def six_hump_camel_func(x): + """ + Definition of the six-hump camel + """ + x1 = x["x0"] + x2 = x["x1"] + term1 = (4 - 2.1 * x1**2 + (x1**4) / 3) * x1**2 + term2 = x1 * x2 + term3 = (-4 + 4 * x2**2) * x2**2 + return {"f": term1 + term2 + term3} + + +# Main block is necessary only when using local comms with spawn start method (default on macOS and Windows). +if __name__ == "__main__": + workflow = Ensemble(parse_args=True) + + if workflow.is_manager: + start_time = time() + + n = 2 + + vocs = VOCS( + variables={ + "x0": [-3, 3], + "x1": [-2, 2], + "x0_on_cube": [0, 1], + "x1_on_cube": [0, 1], + }, + objectives={"f": "MINIMIZE"}, + ) + + aposmm = APOSMM( + vocs, + max_active_runs=6, + variables_mapping={ + "x": ["x0", "x1"], + "x_on_cube": ["x0_on_cube", "x1_on_cube"], + "f": ["f"], + }, + initial_sample_size=100, + sample_points=np.round(minima, 1), + localopt_method="scipy_Nelder-Mead", + opt_return_codes=[0], + nu=1e-8, + mu=1e-8, + dist_to_bound_multiple=0.01, + ) + + workflow.gen_specs = GenSpecs( + generator=aposmm, + vocs=vocs, + initial_batch_size=100, + ) + + workflow.sim_specs = SimSpecs(simulator=six_hump_camel_func, vocs=vocs) + workflow.exit_criteria = ExitCriteria(sim_max=1000) + + H, _, _ = workflow.run() + + if workflow.is_manager: + print("[Manager]:", H[np.where(H["local_min"])]["x"]) + print("[Manager]: Time taken =", time() - start_time, flush=True) + + 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 >= 2, f"Found {min_found} minima" diff --git a/libensemble/tests/regression_tests/test_aposmm_timeout.py b/libensemble/tests/regression_tests/test_aposmm_timeout.py new file mode 100644 index 000000000..3ece7bbb3 --- /dev/null +++ b/libensemble/tests/regression_tests/test_aposmm_timeout.py @@ -0,0 +1,84 @@ +""" +Test the APOSMM generator's ability to properly exit when a timeout has occurred. + +Execute via one of the following commands (e.g. 3 workers): + mpiexec -np 4 python test_aposmm_timeout.py + python test_aposmm_timeout.py --nworkers 3 --comms local + python test_aposmm_timeout.py --nworkers 3 --comms tcp + +When running with the above commands, the number of concurrent evaluations of +the objective function will be 3, as the generator runs on the manager. +""" + +# Do not change these lines - they are parsed by run-tests.sh +# TESTSUITE_COMMS: local mpi tcp +# TESTSUITE_NPROCS: 4 +# TESTSUITE_EXTRA: true + +import numpy as np + +import libensemble.gen_funcs + +libensemble.gen_funcs.rc.aposmm_optimizers = "nlopt" + +from gest_api.vocs import VOCS + +from libensemble import Ensemble +from libensemble.gen_classes import APOSMM +from libensemble.specs import ExitCriteria, GenSpecs, SimSpecs + + +def periodic_func(x): + """ + Periodic test function (gest-api version of periodic_func.func_wrapper). + """ + from numpy import cos, sin + + return {"f": sin(x["x0"]) * cos(x["x1"])} + + +# Main block is necessary only when using local comms with spawn start method (default on macOS and Windows). +if __name__ == "__main__": + workflow = Ensemble(parse_args=True) + + vocs = VOCS( + variables={ + "x0": [0, 2 * np.pi], + "x1": [-np.pi / 2, 3 * np.pi / 2], + "x0_on_cube": [0, 1], + "x1_on_cube": [0, 1], + }, + objectives={"f": "MINIMIZE"}, + ) + + aposmm = APOSMM( + vocs, + max_active_runs=6, + initial_sample_size=100, + variables_mapping={ + "x": ["x0", "x1"], + "x_on_cube": ["x0_on_cube", "x1_on_cube"], + "f": ["f"], + }, + localopt_method="LN_BOBYQA", + xtol_abs=1e-8, + ftol_abs=1e-8, + periodic=True, + print=True, + ) + + workflow.gen_specs = GenSpecs( + generator=aposmm, + vocs=vocs, + initial_batch_size=100, + ) + workflow.sim_specs = SimSpecs(simulator=periodic_func, vocs=vocs) + + # Setting a very high sim_max and a short wallclock_max so timeout will occur + workflow.exit_criteria = ExitCriteria(sim_max=50000, wallclock_max=5) + + H, _, flag = workflow.run() + + if workflow.is_manager: + assert flag == 2, "Test should have timed out" + assert np.any(H["local_min"]), "Expected at least one local minimum to be found" diff --git a/libensemble/tests/regression_tests/test_persistent_aposmm_exception.py b/libensemble/tests/regression_tests/test_persistent_aposmm_exception.py deleted file mode 100644 index d018c307e..000000000 --- a/libensemble/tests/regression_tests/test_persistent_aposmm_exception.py +++ /dev/null @@ -1,97 +0,0 @@ -""" -Tests the APOSMM generator function's ability to handle exceptions - -Execute via one of the following commands (e.g. 3 workers): - mpiexec -np 4 python test_persistent_aposmm_exception.py - python test_persistent_aposmm_exception.py --nworkers 3 - -When running with the above commands, the number of concurrent evaluations of -the objective function will be 2, as one of the three workers will be the -persistent generator. -""" - -# Do not change these lines - they are parsed by run-tests.sh -# TESTSUITE_COMMS: local mpi -# TESTSUITE_NPROCS: 4 -# TESTSUITE_EXTRA: true - -import multiprocessing -import sys - -import numpy as np - -import libensemble.gen_funcs - -# Import libEnsemble items for this test -from libensemble.libE import libE -from libensemble.sim_funcs.periodic_func import func_wrapper as sim_f - -libensemble.gen_funcs.rc.aposmm_optimizers = "nlopt" -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 parse_args - - -def assertion(passed): - """Raise assertion or MPI Abort""" - if libE_specs["comms"] == "mpi": - from mpi4py import MPI - - if passed: - print("\n\nMPI will be aborted as planned\n\n", flush=True) - MPI.COMM_WORLD.Abort(0) # Abort with success - else: - MPI.COMM_WORLD.Abort(1) # Abort with failure - else: - assert passed - print("\n\nException received as expected") - - -# 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() - - if nworkers < 2: - sys.exit("Cannot run with a persistent worker if only one worker -- aborting...") - - n = 2 - sim_specs = { - "sim_f": sim_f, - "in": ["x"], - "out": [("f", float)], - } - - gen_out = [("x", float, n), ("x_on_cube", float, n), ("sim_id", int), ("local_min", bool), ("local_pt", bool)] - - gen_specs = { - "gen_f": gen_f, - "persis_in": ["f"] + [n[0] for n in gen_out], - "out": gen_out, - "initial_batch_size": 100, - "user": { - "initial_sample_size": 100, - "localopt_method": "LN_BOBYQA", - "lb": np.array([0, -np.pi / 2]), - "ub": np.array([2 * np.pi, 3 * np.pi / 2]), - }, - } - - alloc_specs = {"alloc_f": alloc_f} - - exit_criteria = {"sim_max": 1000} - - libE_specs["abort_on_exception"] = False - try: - # Perform the run, which will fail because we want to test exception handling - H, persis_info, flag = libE(sim_specs, gen_specs, exit_criteria, alloc_specs=alloc_specs, libE_specs=libE_specs) - except Exception as e: - if is_manager: - if e.args[1].endswith("NLopt roundoff-limited"): - assertion(True) - else: - assertion(False) - else: - if is_manager: - assertion(False) diff --git a/libensemble/tests/regression_tests/test_persistent_aposmm_nlopt.py b/libensemble/tests/regression_tests/test_persistent_aposmm_nlopt.py deleted file mode 100644 index 28da42d53..000000000 --- a/libensemble/tests/regression_tests/test_persistent_aposmm_nlopt.py +++ /dev/null @@ -1,106 +0,0 @@ -""" -Runs libEnsemble with APOSMM with the NLopt local optimizer. - -Execute via one of the following commands (e.g. 3 workers): - mpiexec -np 4 python test_persistent_aposmm_nlopt.py - python test_persistent_aposmm_nlopt.py --nworkers 3 - python test_persistent_aposmm_nlopt.py --nworkers 3 --comms tcp - -When running with the above commands, the number of concurrent evaluations of -the objective function will be 2, as one of the three workers will be the -persistent generator. -""" - -# Do not change these lines - they are parsed by run-tests.sh -# TESTSUITE_COMMS: local mpi tcp -# TESTSUITE_NPROCS: 3 -# TESTSUITE_EXTRA: true - -import sys -from math import gamma, pi, sqrt - -import numpy as np - -import libensemble.gen_funcs - -# Import libEnsemble items for this test -from libensemble.libE import libE -from libensemble.sim_funcs.six_hump_camel import six_hump_camel as sim_f - -libensemble.gen_funcs.rc.aposmm_optimizers = "nlopt" -from time import time - -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.tests.regression_tests.support import six_hump_camel_minima as minima -from libensemble.tools import parse_args, save_libE_output - -# Main block is necessary only when using local comms with spawn start method (default on macOS and Windows). -if __name__ == "__main__": - nworkers, is_manager, libE_specs, _ = parse_args() - - if is_manager: - start_time = time() - - if nworkers < 2: - sys.exit("Cannot run with a persistent worker if only one worker -- aborting...") - - n = 2 - sim_specs = { - "sim_f": sim_f, - "in": ["x"], - "out": [("f", float)], - } - - gen_out = [ - ("x", float, n), - ("x_on_cube", float, n), - ("sim_id", int), - ("local_min", bool), - ("local_pt", bool), - ] - - gen_specs = { - "gen_f": gen_f, - "persis_in": ["f"] + [n[0] for n in gen_out], - "out": gen_out, - "initial_batch_size": 100, - "user": { - "initial_sample_size": 100, - "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, - "lb": np.array([-3, -2]), - "ub": np.array([3, 2]), - }, - } - - alloc_specs = {"alloc_f": alloc_f} - - exit_criteria = {"sim_max": 3000} - - # Perform the run - H, persis_info, flag = libE( - sim_specs, - gen_specs, - exit_criteria, - alloc_specs=alloc_specs, - libE_specs=libE_specs, - ) - - if is_manager: - print("[Manager]:", H[np.where(H["local_min"])]["x"]) - print("[Manager]: Time taken =", time() - start_time, flush=True) - - tol = 1e-5 - 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) - assert np.min(np.sum((H[H["local_min"]]["x"] - m) ** 2, 1)) < tol - - save_libE_output(H, persis_info, __file__, nworkers) diff --git a/libensemble/tests/regression_tests/test_persistent_aposmm_periodic.py b/libensemble/tests/regression_tests/test_persistent_aposmm_periodic.py deleted file mode 100644 index 509e851ef..000000000 --- a/libensemble/tests/regression_tests/test_persistent_aposmm_periodic.py +++ /dev/null @@ -1,106 +0,0 @@ -""" -Tests the 'periodic' domain use case for APOSMM with both NLopt and SciPy -local optimization methods. - -Execute via one of the following commands (e.g. 3 workers): - mpiexec -np 4 python test_persistent_aposmm_periodic.py - python test_persistent_aposmm_periodic.py --nworkers 3 - -When running with the above commands, the number of concurrent evaluations of -the objective function will be 2, as one of the three workers will be the -persistent generator. -""" - -# Do not change these lines - they are parsed by run-tests.sh -# TESTSUITE_COMMS: local mpi -# TESTSUITE_NPROCS: 4 -# TESTSUITE_EXTRA: true - -import multiprocessing -import sys - -import numpy as np - -import libensemble.gen_funcs - -libensemble.gen_funcs.rc.aposmm_optimizers = ["nlopt", "scipy"] -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 - -# Import libEnsemble items for this test -from libensemble.libE import libE -from libensemble.sim_funcs.periodic_func import func_wrapper as sim_f -from libensemble.tools import parse_args - -# 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() - - if nworkers < 2: - sys.exit("Cannot run with a persistent worker if only one worker -- aborting...") - - n = 2 - sim_specs = { - "sim_f": sim_f, - "in": ["x"], - "out": [("f", float)], - } - - gen_out = [ - ("x", float, n), - ("x_on_cube", float, n), - ("sim_id", int), - ("local_min", bool), - ("local_pt", bool), - ] - - gen_specs = { - "gen_f": gen_f, - "persis_in": ["f"] + [n[0] for n in gen_out], - "out": gen_out, - "user": { - "initial_sample_size": 100, - "localopt_method": "LN_BOBYQA", - "xtol_abs": 1e-8, - "ftol_abs": 1e-8, - "lb": np.array([0, -np.pi / 2]), - "ub": np.array([2 * np.pi, 3 * np.pi / 2]), - "periodic": True, - "print": True, - }, - } - - alloc_specs = {"alloc_f": alloc_f} - - exit_criteria = {"sim_max": 1000} - - for run in range(2): - if run == 1: - gen_specs["user"]["localopt_method"] = "scipy_COBYLA" - gen_specs["user"]["opt_return_codes"] = [1] - gen_specs["user"].pop("xtol_abs") - gen_specs["user"].pop("ftol_abs") - gen_specs["user"]["scipy_kwargs"] = {"tol": 1e-8} - - persis_info = {} - # Perform the run - H, persis_info, flag = libE(sim_specs, gen_specs, exit_criteria, persis_info, alloc_specs, libE_specs) - - if is_manager: - assert persis_info[0].get("run_order"), "Run_order should have been given back" - min_ids = np.where(H["local_min"]) - - # The minima are known on this test problem. If the above [lb, ub] domain is - # shifted/scaled to [0,1]^n, they all have value [0.25, 0.75] or [0.75, 0.25] - minima = np.array([[0.25, 0.75], [0.75, 0.25]]) - tol = 2e-4 - - for x in H["x_on_cube"][min_ids]: - print(x) - print(np.linalg.norm(x - minima[0])) - print(np.linalg.norm(x - minima[1]), flush=True) - - for x in H["x_on_cube"][min_ids]: - assert np.linalg.norm(x - minima[0]) < tol or np.linalg.norm(x - minima[1]) < tol diff --git a/libensemble/tests/regression_tests/test_persistent_aposmm_scipy.py b/libensemble/tests/regression_tests/test_persistent_aposmm_scipy.py deleted file mode 100644 index 6556a6c73..000000000 --- a/libensemble/tests/regression_tests/test_persistent_aposmm_scipy.py +++ /dev/null @@ -1,130 +0,0 @@ -""" -Runs libEnsemble with APOSMM and SciPy local optimization routines. - -Execute via one of the following commands (e.g. 3 workers): - mpiexec -np 4 python test_persistent_aposmm_scipy.py - python test_persistent_aposmm_scipy.py --nworkers 3 - python test_persistent_aposmm_scipy.py --nworkers 3 --comms tcp - -When running with the above commands, the number of concurrent evaluations of -the objective function will be 2, as one of the three workers will be the -persistent generator. -""" - -# Do not change these lines - they are parsed by run-tests.sh -# TESTSUITE_COMMS: mpi local -# TESTSUITE_NPROCS: 4 - -import multiprocessing -import sys - -import numpy as np - -import libensemble.gen_funcs - -# Import libEnsemble items for this test -from libensemble.libE import libE -from libensemble.sim_funcs.six_hump_camel import six_hump_camel as sim_f - -libensemble.gen_funcs.rc.aposmm_optimizers = "scipy" -from time import time - -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.tests.regression_tests.support import six_hump_camel_minima as minima -from libensemble.tools import parse_args, save_libE_output - -# 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() - - if is_manager: - start_time = time() - - if nworkers < 2: - sys.exit("Cannot run with a persistent worker if only one worker -- aborting...") - - n = 2 - sim_specs = { - "sim_f": sim_f, - "in": ["x"], - "out": [("f", float)], - } - - gen_out = [ - ("x", float, n), - ("x_on_cube", float, n), - ("sim_id", int), - ("local_min", bool), - ("local_pt", bool), - ] - - gen_specs = { - "gen_f": gen_f, - "persis_in": ["f"] + [n[0] for n in gen_out], - "out": gen_out, - "initial_batch_size": 100, - "user": { - "initial_sample_size": 100, - "sample_points": np.round(minima, 1), - "localopt_method": "scipy_Nelder-Mead", - "opt_return_codes": [0], - "nu": 1e-8, - "mu": 1e-8, - "dist_to_bound_multiple": 0.01, - "max_active_runs": 6, - "lb": np.array([-3, -2]), - "ub": np.array([3, 2]), - }, - } - - alloc_specs = {"alloc_f": alloc_f} - - exit_criteria = {"sim_max": 1000} - - for run in range(2): - if run == 1: - gen_specs["user"]["localopt_method"] = "scipy_BFGS" - gen_specs["user"]["opt_return_codes"] = [0] - gen_specs["persis_in"].append("grad") - sim_specs["out"] = [("f", float), ("grad", float, n)] - - # Perform the run - H, persis_info, flag = libE(sim_specs, gen_specs, exit_criteria, alloc_specs=alloc_specs, libE_specs=libE_specs) - - if is_manager: - print("[Manager]:", H[np.where(H["local_min"])]["x"]) - print("[Manager]: Time taken =", time() - start_time, flush=True) - - 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 >= 2, f"Found {min_found} minima" - - save_libE_output(H, persis_info, __file__, nworkers) - - # Now let's run on the same problem with a really large n (but we won't test - # convergence to all local min). Note that sim_f uses only entries x[0:2] - n = 400 - gen_specs["out"][0:2] = [("x", float, n), ("x_on_cube", float, n)] - gen_specs["user"]["lb"] = np.zeros(n) - gen_specs["user"]["ub"] = np.ones(n) - gen_specs["user"]["lb"][:2] = [-3, -2] - gen_specs["user"]["ub"][:2] = [3, 2] - gen_specs["user"]["rk_const"] = 4.90247 - gen_specs["user"].pop("sample_points") - gen_specs["user"]["localopt_method"] = "scipy_Nelder-Mead" - sim_specs["out"] = [("f", float)] - gen_specs["persis_in"].remove("grad") - - H, persis_info, flag = libE(sim_specs, gen_specs, exit_criteria, alloc_specs=alloc_specs, libE_specs=libE_specs) - - if is_manager: - assert np.sum(H["sim_ended"]) >= exit_criteria["sim_max"] - 10, "Not enough runs finished" diff --git a/libensemble/tests/regression_tests/test_persistent_aposmm_timeout.py b/libensemble/tests/regression_tests/test_persistent_aposmm_timeout.py deleted file mode 100644 index e1c115bb9..000000000 --- a/libensemble/tests/regression_tests/test_persistent_aposmm_timeout.py +++ /dev/null @@ -1,91 +0,0 @@ -""" -Test the APOSMM generator function's capabilities to properly exit when a -timeout has occurred. - -Execute via one of the following commands (e.g. 3 workers): - mpiexec -np 4 python test_persistent_aposmm_timeout.py - python test_persistent_aposmm_timeout.py --nworkers 3 - python test_persistent_aposmm_timeout.py --nworkers 3 --comms tcp - -When running with the above commands, the number of concurrent evaluations of -the objective function will be 2, as one of the three workers will be the -persistent generator. -""" - -# Do not change these lines - they are parsed by run-tests.sh -# TESTSUITE_COMMS: local mpi tcp -# TESTSUITE_NPROCS: 4 -# TESTSUITE_EXTRA: true - -import multiprocessing -import sys - -import numpy as np - -import libensemble.gen_funcs - -libensemble.gen_funcs.rc.aposmm_optimizers = "nlopt" - -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 - -# Import libEnsemble items for this test -from libensemble.libE import libE -from libensemble.sim_funcs.periodic_func import func_wrapper as sim_f -from libensemble.tools import parse_args, save_libE_output - -# 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() - - if nworkers < 2: - sys.exit("Cannot run with a persistent worker if only one worker -- aborting...") - - n = 2 - sim_specs = { - "sim_f": sim_f, - "in": ["x"], - "out": [("f", float)], - } - - gen_out = [ - ("x", float, n), - ("x_on_cube", float, n), - ("sim_id", int), - ("local_min", bool), - ("local_pt", bool), - ] - - gen_specs = { - "gen_f": gen_f, - "persis_in": ["f"] + [n[0] for n in gen_out], - "out": gen_out, - "initial_batch_size": 100, - "user": { - "initial_sample_size": 100, - "localopt_method": "LN_BOBYQA", - "xtol_abs": 1e-8, - "ftol_abs": 1e-8, - "run_max_eval": 30, - "lb": np.array([0, -np.pi / 2]), - "ub": np.array([2 * np.pi, 3 * np.pi / 2]), - "periodic": True, - "print": True, - }, - } - - alloc_specs = {"alloc_f": alloc_f} - - # Setting a very high sim_max value and a short wallclock_max so timeout will occur - exit_criteria = {"sim_max": 50000, "wallclock_max": 5} - - # Perform the run - H, persis_info, flag = libE(sim_specs, gen_specs, exit_criteria, alloc_specs=alloc_specs, libE_specs=libE_specs) - - if is_manager: - assert flag == 2, "Test should have timed out" - assert persis_info[0].get("run_order"), "Run_order should have been given back" - min_ids = np.where(H["local_min"]) - save_libE_output(H, persis_info, __file__, nworkers)