diff --git a/optimas/explorations/base.py b/optimas/explorations/base.py index 9b9d0bb1..802e58ec 100644 --- a/optimas/explorations/base.py +++ b/optimas/explorations/base.py @@ -31,14 +31,16 @@ class Exploration: The generator used to suggest new Trials. evaluator : Evaluator The evaluator that will execute the Trials. - max_evals : int + max_evals : int, optional Maximum number of trials that will be evaluated in the exploration. - sim_workers : int - Number of parallel workers performing simulations. + If not given, the exploration can run indefinitely. + sim_workers : int, optional + Number of parallel workers performing simulations. By default, 1. run_async : bool, optional - Whether the evaluators should be performed asynchronously (i.e., + Whether the evaluations should be performed asynchronously (i.e., without waiting for all workers to finish before staring a new - evaluation). By default, True. + evaluation). This is useful when the completion time of the + evaluations is not uniform. By default, False. history : str, optional Path to a history file of a past exploration from which to restart the new one. By default, None. @@ -71,9 +73,9 @@ def __init__( self, generator: Generator, evaluator: Evaluator, - max_evals: int, - sim_workers: int, - run_async: Optional[bool] = True, + max_evals: Optional[int] = np.inf, + sim_workers: Optional[int] = 1, + run_async: Optional[bool] = False, history: Optional[str] = None, history_save_period: Optional[int] = None, exploration_dir_path: Optional[str] = "./exploration", @@ -120,7 +122,9 @@ def run(self, n_evals: Optional[int] = None) -> None: sim_max = remaining_evals else: sim_max = min(n_evals, remaining_evals) - exit_criteria = {"sim_max": sim_max} + exit_criteria = {} + if np.isfinite(sim_max): + exit_criteria["sim_max"] = sim_max # Get initial number of generator trials. n_trials_initial = self.generator.n_trials diff --git a/tests/test_exploration_resume.py b/tests/test_exploration_resume.py index 1dda4df7..d32c43ca 100644 --- a/tests/test_exploration_resume.py +++ b/tests/test_exploration_resume.py @@ -42,7 +42,7 @@ def test_exploration_in_steps(): evaluator=ev, max_evals=30, sim_workers=2, - exploration_dir_path="./tests_output/test_template_evaluator", + exploration_dir_path="./tests_output/test_exploration_steps", ) # Run exploration in several steps. @@ -59,6 +59,51 @@ def test_exploration_in_steps(): assert exploration.history["gen_informed"][-1] +def test_exploration_in_steps_without_limit(): + """ + Test that an exploration runs correctly when doing so in several steps + without a limit on the maximum number of evaluations. + """ + # Define variables and objectives. + var1 = VaryingParameter("x0", -50.0, 5.0) + var2 = VaryingParameter("x1", -5.0, 15.0) + obj = Objective("f", minimize=False) + + # Define evaluator. + gen = RandomSamplingGenerator( + varying_parameters=[var1, var2], objectives=[obj] + ) + + # Create template evaluator. + ev = TemplateEvaluator( + sim_template=os.path.join( + os.path.abspath(os.path.dirname(__file__)), + "resources", + "template_simulation_script.py", + ), + analysis_func=analysis_func, + ) + + # Create exploration. + exploration = Exploration( + generator=gen, + evaluator=ev, + sim_workers=2, + exploration_dir_path="./tests_output/test_exploration_steps_no_limit", + ) + + # Run exploration in several steps. + steps = [3, 4, 10, 5] + for step in steps: + exploration.run(step) + + # Check final state. + assert exploration._n_evals == len(exploration.history) + assert exploration._n_evals == gen.n_trials + assert exploration._n_evals == sum(steps) + assert exploration.history["gen_informed"][-1] + + def test_exploration_resume(): """Test that an exploration correctly resumes from a previous run.""" # Define variables and objectives. @@ -87,7 +132,7 @@ def test_exploration_resume(): evaluator=ev, max_evals=40, sim_workers=2, - exploration_dir_path="./tests_output/test_template_evaluator", + exploration_dir_path="./tests_output/test_exploration_steps", resume=True, ) @@ -103,4 +148,5 @@ def test_exploration_resume(): if __name__ == "__main__": test_exploration_in_steps() + test_exploration_in_steps_without_limit() test_exploration_resume()