From 4d37b780e27c8b63a2c8039067ab04aadf1bc31e Mon Sep 17 00:00:00 2001 From: Lukas Rothenberger Date: Mon, 8 Jan 2024 15:53:25 +0100 Subject: [PATCH] feat(optimizer): add argument --evolutionary --- .../discopop_optimizer/OptimizerArguments.py | 9 +++++++++ discopop_library/discopop_optimizer/__main__.py | 5 ++++- .../optimization/evolutionary_algorithm.py | 4 ++-- discopop_library/discopop_optimizer/optimizer.py | 4 +++- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/discopop_library/discopop_optimizer/OptimizerArguments.py b/discopop_library/discopop_optimizer/OptimizerArguments.py index e234f165a..cd06eca29 100644 --- a/discopop_library/discopop_optimizer/OptimizerArguments.py +++ b/discopop_library/discopop_optimizer/OptimizerArguments.py @@ -7,6 +7,7 @@ # directory for details. import os.path from dataclasses import dataclass +from typing import List, Optional @dataclass @@ -16,6 +17,7 @@ class OptimizerArguments(object): verbose: bool interactive: bool exhaustive: bool + evolutionary: Optional[List[str]] doall_microbench_file: str reduction_microbench_file: str allow_nested_parallelism: bool @@ -24,6 +26,13 @@ class OptimizerArguments(object): check_called_function_for_nested_parallelism: bool def __post_init__(self): + # fix correct optimization method + if not self.exhaustive: + if self.evolutionary == None: + self.evolutionary = [str(50), str(5)] + elif self.evolutionary != None: + self.evolutionary = None + self.__validate() def __validate(self): diff --git a/discopop_library/discopop_optimizer/__main__.py b/discopop_library/discopop_optimizer/__main__.py index b835683a1..91c15fc3d 100644 --- a/discopop_library/discopop_optimizer/__main__.py +++ b/discopop_library/discopop_optimizer/__main__.py @@ -24,7 +24,9 @@ def parse_args() -> OptimizerArguments: parser.add_argument("-v", "--verbose", action="store_true", help="Enable verbose output.") parser.add_argument("-x", "--exhaustive", action="store_true", - help="Enable exhaustive search. By default, an evolutionary search is performed.") + help="Enable exhaustive search. By default, an evolutionary search with a population size of 50 and 5 generations is performed.") + parser.add_argument("-e", "--evolutionary", type=str, default=None, nargs=2, metavar=("population_size", "generations"), + help="Enable evolutionary search. By default, an evolutionary search with a population size of 50 and 5 generations is performed.") parser.add_argument( "--doall-microbench-file", type=str, default="None", help="Do-All microbenchmark results" @@ -56,6 +58,7 @@ def parse_args() -> OptimizerArguments: verbose=arguments.verbose, interactive=arguments.interactive, exhaustive=arguments.exhaustive, + evolutionary=arguments.evolutionary, doall_microbench_file=arguments.doall_microbench_file, reduction_microbench_file=arguments.reduction_microbench_file, allow_nested_parallelism=arguments.allow_nested_parallelism, diff --git a/discopop_library/discopop_optimizer/optimization/evolutionary_algorithm.py b/discopop_library/discopop_optimizer/optimization/evolutionary_algorithm.py index 65ce74733..da0c16599 100644 --- a/discopop_library/discopop_optimizer/optimization/evolutionary_algorithm.py +++ b/discopop_library/discopop_optimizer/optimization/evolutionary_algorithm.py @@ -43,8 +43,8 @@ def perform_evolutionary_search( optimizer_dir: str, ) -> Optional[OptimizerOutputPattern]: ### SETTINGS - population_size = 50 - generations = 5 + population_size = int(arguments.evolutionary[0]) + generations = int(arguments.evolutionary[1]) selection_strength = 0.85 # 0.8 --> 80% of the population will be selected for the next generation crossovers = int(population_size / 10) mutations = int(population_size / 10) diff --git a/discopop_library/discopop_optimizer/optimizer.py b/discopop_library/discopop_optimizer/optimizer.py index 2e2cb66e8..11d06c923 100644 --- a/discopop_library/discopop_optimizer/optimizer.py +++ b/discopop_library/discopop_optimizer/optimizer.py @@ -195,7 +195,7 @@ def run(arguments: OptimizerArguments): best_configuration = evaluate_all_decision_combinations( experiment, available_decisions, arguments, optimizer_dir ) - else: + elif arguments.evolutionary != None: # perform evolutionary search best_configuration = perform_evolutionary_search( experiment, @@ -203,6 +203,8 @@ def run(arguments: OptimizerArguments): arguments, optimizer_dir, ) + else: + raise ValueError("No optimization method specified!") if best_configuration is not None: best_configuration = optimize_updates(experiment, best_configuration, arguments)