omniopt2 7093__py3-none-any.whl → 7098__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. .omniopt.py +184 -215
  2. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/.omniopt.py +184 -215
  3. {omniopt2-7093.dist-info → omniopt2-7098.dist-info}/METADATA +1 -1
  4. {omniopt2-7093.dist-info → omniopt2-7098.dist-info}/RECORD +35 -35
  5. omniopt2.egg-info/PKG-INFO +1 -1
  6. pyproject.toml +1 -1
  7. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/.colorfunctions.sh +0 -0
  8. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/.general.sh +0 -0
  9. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/.helpers.py +0 -0
  10. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/.omniopt_plot_cpu_ram_usage.py +0 -0
  11. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/.omniopt_plot_general.py +0 -0
  12. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/.omniopt_plot_gpu_usage.py +0 -0
  13. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/.omniopt_plot_kde.py +0 -0
  14. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/.omniopt_plot_scatter.py +0 -0
  15. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/.omniopt_plot_scatter_generation_method.py +0 -0
  16. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/.omniopt_plot_scatter_hex.py +0 -0
  17. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/.omniopt_plot_time_and_exit_code.py +0 -0
  18. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/.omniopt_plot_trial_index_result.py +0 -0
  19. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/.omniopt_plot_worker.py +0 -0
  20. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/.random_generator.py +0 -0
  21. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/.shellscript_functions +0 -0
  22. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/.tpe.py +0 -0
  23. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/LICENSE +0 -0
  24. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/apt-dependencies.txt +0 -0
  25. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/omniopt +0 -0
  26. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/omniopt_docker +0 -0
  27. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/omniopt_evaluate +0 -0
  28. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/omniopt_plot +0 -0
  29. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/omniopt_share +0 -0
  30. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/requirements.txt +0 -0
  31. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/setup.py +0 -0
  32. {omniopt2-7093.data → omniopt2-7098.data}/data/bin/test_requirements.txt +0 -0
  33. {omniopt2-7093.dist-info → omniopt2-7098.dist-info}/WHEEL +0 -0
  34. {omniopt2-7093.dist-info → omniopt2-7098.dist-info}/licenses/LICENSE +0 -0
  35. {omniopt2-7093.dist-info → omniopt2-7098.dist-info}/top_level.txt +0 -0
@@ -565,6 +565,7 @@ class ConfigLoader:
565
565
  verbose_break_run_search_table: bool
566
566
  send_anonymized_usage_stats: bool
567
567
  max_failed_jobs: Optional[int]
568
+ max_abandoned_retrial: int
568
569
  show_ram_every_n_seconds: int
569
570
  config_toml: Optional[str]
570
571
  config_json: Optional[str]
@@ -653,6 +654,7 @@ class ConfigLoader:
653
654
  optional.add_argument('--calculate_pareto_front_of_job', help='This can be used to calculate a pareto-front for a multi-objective job that previously has results, but has been cancelled, and has no pareto-front (yet)', type=str, nargs='+', default=[])
654
655
  optional.add_argument('--show_generate_time_table', help='Generate a table at the end, showing how much time was spent trying to generate new points', action='store_true', default=False)
655
656
  optional.add_argument('--force_choice_for_ranges', help='Force float ranges to be converted to choice', action='store_true', default=False)
657
+ optional.add_argument('--max_abandoned_retrial', help='Maximum number retrials to get when a job is abandoned post-generation', default=20, type=int)
656
658
 
657
659
  speed.add_argument('--dont_warm_start_refitting', help='Do not keep Model weights, thus, refit for every generator (may be more accurate, but slower)', action='store_true', default=False)
658
660
  speed.add_argument('--refit_on_cv', help='Refit on Cross-Validation (helps in accuracy, but makes generating new points slower)', action='store_true', default=False)
@@ -794,9 +796,13 @@ if args.seed is not None:
794
796
 
795
797
  set_rng_seed(args.seed)
796
798
 
799
+ @beartype
800
+ def _fatal_error(message: str, code: int) -> None:
801
+ print_red(message)
802
+ my_exit(code)
803
+
797
804
  if args.max_eval is None and args.generation_strategy is None and args.continue_previous_job is None and (not args.calculate_pareto_front_of_job or len(args.calculate_pareto_front_of_job) == 0):
798
- print_red("Either --max_eval or --generation_strategy must be set.")
799
- my_exit(104)
805
+ _fatal_error("Either --max_eval or --generation_strategy must be set.", 104)
800
806
 
801
807
  arg_result_names = []
802
808
  arg_result_min_or_max = []
@@ -1273,8 +1279,7 @@ class ExternalProgramGenerationNode(ExternalGenerationNode):
1273
1279
  if param_type == ParameterType.STRING:
1274
1280
  return "STRING"
1275
1281
 
1276
- print_red(f"Unknown data type {param_type}")
1277
- my_exit(33)
1282
+ _fatal_error(f"Unknown data type {param_type}", 33)
1278
1283
 
1279
1284
  return ""
1280
1285
 
@@ -1303,8 +1308,7 @@ class ExternalProgramGenerationNode(ExternalGenerationNode):
1303
1308
  "values": param.values
1304
1309
  }
1305
1310
  else:
1306
- print_red(f"Unknown parameter type: {param}")
1307
- my_exit(15)
1311
+ _fatal_error(f"Unknown parameter type: {param}", 15)
1308
1312
 
1309
1313
  return serialized
1310
1314
 
@@ -1583,8 +1587,7 @@ if isinstance(args.num_parallel_jobs, int) or helpers.looks_like_int(args.num_pa
1583
1587
  num_parallel_jobs = int(args.num_parallel_jobs)
1584
1588
 
1585
1589
  if num_parallel_jobs <= 0:
1586
- print_red(f"--num_parallel_jobs must be 1 or larger, is {num_parallel_jobs}")
1587
- my_exit(106)
1590
+ _fatal_error(f"--num_parallel_jobs must be 1 or larger, is {num_parallel_jobs}", 106)
1588
1591
 
1589
1592
  class SearchSpaceExhausted (Exception):
1590
1593
  pass
@@ -1836,11 +1839,9 @@ def log_nr_of_workers() -> None:
1836
1839
  with open(logfile_nr_workers, mode='a+', encoding="utf-8") as f:
1837
1840
  f.write(str(nr_current_workers) + "\n")
1838
1841
  except FileNotFoundError:
1839
- print_red(f"It seems like the folder for writing {logfile_nr_workers} was deleted during the run. Cannot continue.")
1840
- my_exit(99)
1842
+ _fatal_error(f"It seems like the folder for writing {logfile_nr_workers} was deleted during the run. Cannot continue.", 99)
1841
1843
  except OSError as e:
1842
- print_red(f"Tried writing log_nr_of_workers to file {logfile_nr_workers}, but failed with error: {e}. This may mean that the file system you are running on is instable. OmniOpt2 probably cannot do anything about it.")
1843
- my_exit(199)
1844
+ _fatal_error(f"Tried writing log_nr_of_workers to file {logfile_nr_workers}, but failed with error: {e}. This may mean that the file system you are running on is instable. OmniOpt2 probably cannot do anything about it.", 199)
1844
1845
 
1845
1846
  return None
1846
1847
 
@@ -2015,12 +2016,10 @@ else:
2015
2016
  if os.path.exists(prev_job_file):
2016
2017
  global_vars["joined_run_program"] = get_file_as_string(prev_job_file)
2017
2018
  else:
2018
- print_red(f"The previous job file {prev_job_file} could not be found. You may forgot to add the run number at the end.")
2019
- my_exit(44)
2019
+ _fatal_error(f"The previous job file {prev_job_file} could not be found. You may forgot to add the run number at the end.", 44)
2020
2020
 
2021
2021
  if not args.tests and len(global_vars["joined_run_program"]) == 0 and not args.calculate_pareto_front_of_job:
2022
- print_red("--run_program was empty")
2023
- my_exit(19)
2022
+ _fatal_error("--run_program was empty", 19)
2024
2023
 
2025
2024
  global_vars["experiment_name"] = args.experiment_name
2026
2025
 
@@ -2029,20 +2028,17 @@ def load_global_vars(_file: str) -> None:
2029
2028
  global global_vars
2030
2029
 
2031
2030
  if not os.path.exists(_file):
2032
- print_red(f"You've tried to continue a non-existing job: {_file}")
2033
- my_exit(44)
2031
+ _fatal_error(f"You've tried to continue a non-existing job: {_file}", 44)
2034
2032
  try:
2035
2033
  with open(_file, encoding="utf-8") as f:
2036
2034
  global_vars = json.load(f)
2037
2035
  except Exception as e:
2038
- print_red(f"Error while loading old global_vars: {e}, trying to load {_file}")
2039
- my_exit(44)
2036
+ _fatal_error(f"Error while loading old global_vars: {e}, trying to load {_file}", 44)
2040
2037
 
2041
2038
  @beartype
2042
2039
  def load_or_exit(filepath: str, error_msg: str, exit_code: int) -> None:
2043
2040
  if not os.path.exists(filepath):
2044
- print_red(error_msg)
2045
- my_exit(exit_code)
2041
+ _fatal_error(error_msg, exit_code)
2046
2042
 
2047
2043
  @beartype
2048
2044
  def get_file_content_or_exit(filepath: str, error_msg: str, exit_code: int) -> str:
@@ -2052,8 +2048,7 @@ def get_file_content_or_exit(filepath: str, error_msg: str, exit_code: int) -> s
2052
2048
  @beartype
2053
2049
  def check_param_or_exit(param: Any, error_msg: str, exit_code: int) -> None:
2054
2050
  if param is None:
2055
- print_red(error_msg)
2056
- my_exit(exit_code)
2051
+ _fatal_error(error_msg, exit_code)
2057
2052
 
2058
2053
  @beartype
2059
2054
  def check_continue_previous_job(continue_previous_job: Optional[str]) -> dict:
@@ -2103,8 +2098,7 @@ def load_time_or_exit(_args: Any) -> None:
2103
2098
  print_yellow(f"Time-setting: The contents of {time_file} do not contain a single number")
2104
2099
  else:
2105
2100
  if len(args.calculate_pareto_front_of_job) == 0:
2106
- print_red("Missing --time parameter. Cannot continue.")
2107
- my_exit(19)
2101
+ _fatal_error("Missing --time parameter. Cannot continue.", 19)
2108
2102
 
2109
2103
  @beartype
2110
2104
  def load_mem_gb_or_exit(_args: Any) -> Optional[int]:
@@ -2122,8 +2116,7 @@ def load_mem_gb_or_exit(_args: Any) -> Optional[int]:
2122
2116
  print_yellow(f"mem_gb-setting: The contents of {mem_gb_file} do not contain a single number")
2123
2117
  return None
2124
2118
 
2125
- print_red("--mem_gb needs to be set")
2126
- my_exit(19)
2119
+ _fatal_error("--mem_gb needs to be set", 19)
2127
2120
 
2128
2121
  return None
2129
2122
 
@@ -2145,8 +2138,7 @@ def load_max_eval_or_exit(_args: Any) -> None:
2145
2138
  if _args.max_eval:
2146
2139
  set_max_eval(_args.max_eval)
2147
2140
  if _args.max_eval <= 0:
2148
- print_red("--max_eval must be larger than 0")
2149
- my_exit(19)
2141
+ _fatal_error("--max_eval must be larger than 0", 19)
2150
2142
  elif _args.continue_previous_job:
2151
2143
  max_eval_file = f"{_args.continue_previous_job}/state_files/max_eval"
2152
2144
  max_eval_content = get_file_content_or_exit(max_eval_file, f"neither --max_eval nor file {max_eval_file} found", 19)
@@ -2285,8 +2277,7 @@ if not SYSTEM_HAS_SBATCH:
2285
2277
  num_parallel_jobs = 1
2286
2278
 
2287
2279
  if SYSTEM_HAS_SBATCH and not args.force_local_execution and args.raw_samples < args.num_parallel_jobs:
2288
- print_red(f"Has --raw_samples={args.raw_samples}, but --num_parallel_jobs={args.num_parallel_jobs}. Cannot continue, since --raw_samples must be larger or equal to --num_parallel_jobs.")
2289
- my_exit(48)
2280
+ _fatal_error(f"Has --raw_samples={args.raw_samples}, but --num_parallel_jobs={args.num_parallel_jobs}. Cannot continue, since --raw_samples must be larger or equal to --num_parallel_jobs.", 48)
2290
2281
 
2291
2282
  @beartype
2292
2283
  def save_global_vars() -> None:
@@ -2426,14 +2417,12 @@ def get_bounds(this_args: Union[str, list], j: int) -> Tuple[float, float]:
2426
2417
  try:
2427
2418
  lower_bound = float(this_args[j + 2])
2428
2419
  except Exception:
2429
- print_red(f"\n{this_args[j + 2]} is not a number")
2430
- my_exit(181)
2420
+ _fatal_error(f"\n{this_args[j + 2]} is not a number", 181)
2431
2421
 
2432
2422
  try:
2433
2423
  upper_bound = float(this_args[j + 3])
2434
2424
  except Exception:
2435
- print_red(f"\n{this_args[j + 3]} is not a number")
2436
- my_exit(181)
2425
+ _fatal_error(f"\n{this_args[j + 3]} is not a number", 181)
2437
2426
 
2438
2427
  return lower_bound, upper_bound
2439
2428
 
@@ -2482,8 +2471,7 @@ def create_range_param(name: str, lower_bound: Union[float, int], upper_bound: U
2482
2471
  @beartype
2483
2472
  def handle_grid_search(name: Union[list, str], lower_bound: Union[float, int], upper_bound: Union[float, int], value_type: str) -> dict:
2484
2473
  if lower_bound is None or upper_bound is None:
2485
- print_red("handle_grid_search: lower_bound or upper_bound is None")
2486
- my_exit(91)
2474
+ _fatal_error("handle_grid_search: lower_bound or upper_bound is None", 91)
2487
2475
 
2488
2476
  return {}
2489
2477
 
@@ -2587,8 +2575,7 @@ def validate_value_type(value_type: str) -> None:
2587
2575
  @beartype
2588
2576
  def parse_fixed_param(classic_params: list, params: list, j: int, this_args: Union[str, list], name: Union[list, str], search_space_reduction_warning: bool) -> Tuple[int, list, list, bool]:
2589
2577
  if len(this_args) != 3:
2590
- print_red("⚠ --parameter for type fixed must have 3 parameters: <NAME> fixed <VALUE>")
2591
- my_exit(181)
2578
+ _fatal_error("⚠ --parameter for type fixed must have 3 parameters: <NAME> fixed <VALUE>", 181)
2592
2579
 
2593
2580
  value = this_args[j + 2]
2594
2581
 
@@ -2611,8 +2598,7 @@ def parse_fixed_param(classic_params: list, params: list, j: int, this_args: Uni
2611
2598
  @beartype
2612
2599
  def parse_choice_param(classic_params: list, params: list, j: int, this_args: Union[str, list], name: Union[list, str], search_space_reduction_warning: bool) -> Tuple[int, list, list, bool]:
2613
2600
  if len(this_args) != 3:
2614
- print_red("⚠ --parameter for type choice must have 3 parameters: <NAME> choice <VALUE,VALUE,VALUE,...>")
2615
- my_exit(181)
2601
+ _fatal_error("⚠ --parameter for type choice must have 3 parameters: <NAME> choice <VALUE,VALUE,VALUE,...>", 181)
2616
2602
 
2617
2603
  values = re.split(r'\s*,\s*', str(this_args[j + 2]))
2618
2604
 
@@ -2658,12 +2644,10 @@ def parse_experiment_parameters() -> Tuple[list, list]:
2658
2644
  name = this_args[j]
2659
2645
 
2660
2646
  if name in invalid_names:
2661
- print_red(f"\n⚠ Name for argument no. {j} is invalid: {name}. Invalid names are: {', '.join(invalid_names)}")
2662
- my_exit(181)
2647
+ _fatal_error(f"\n⚠ Name for argument no. {j} is invalid: {name}. Invalid names are: {', '.join(invalid_names)}", 181)
2663
2648
 
2664
2649
  if name in param_names:
2665
- print_red(f"\n⚠ Parameter name '{name}' is not unique. Names for parameters must be unique!")
2666
- my_exit(181)
2650
+ _fatal_error(f"\n⚠ Parameter name '{name}' is not unique. Names for parameters must be unique!", 181)
2667
2651
 
2668
2652
  param_names.append(name)
2669
2653
  global_param_names.append(name)
@@ -2671,8 +2655,7 @@ def parse_experiment_parameters() -> Tuple[list, list]:
2671
2655
  try:
2672
2656
  param_type = this_args[j + 1]
2673
2657
  except Exception:
2674
- print_red("Not enough arguments for --parameter")
2675
- my_exit(181)
2658
+ _fatal_error("Not enough arguments for --parameter", 181)
2676
2659
 
2677
2660
  param_parsers = {
2678
2661
  "range": parse_range_param,
@@ -2681,13 +2664,11 @@ def parse_experiment_parameters() -> Tuple[list, list]:
2681
2664
  }
2682
2665
 
2683
2666
  if param_type not in param_parsers:
2684
- print_red(f"⚠ Parameter type '{param_type}' not yet implemented.")
2685
- my_exit(181)
2667
+ _fatal_error(f"⚠ Parameter type '{param_type}' not yet implemented.", 181)
2686
2668
 
2687
2669
  if param_type not in valid_types:
2688
2670
  valid_types_string = ', '.join(valid_types)
2689
- print_red(f"\n⚠ Invalid type {param_type}, valid types are: {valid_types_string}")
2690
- my_exit(181)
2671
+ _fatal_error(f"\n⚠ Invalid type {param_type}, valid types are: {valid_types_string}", 181)
2691
2672
 
2692
2673
  j, params, classic_params, search_space_reduction_warning = param_parsers[param_type](classic_params, params, j, this_args, name, search_space_reduction_warning)
2693
2674
 
@@ -2704,31 +2685,26 @@ def parse_experiment_parameters() -> Tuple[list, list]:
2704
2685
  @beartype
2705
2686
  def check_factorial_range() -> None:
2706
2687
  if args.model and args.model == "FACTORIAL":
2707
- print_red("\n⚠ --model FACTORIAL cannot be used with range parameter")
2708
- my_exit(181)
2688
+ _fatal_error("\n⚠ --model FACTORIAL cannot be used with range parameter", 181)
2709
2689
 
2710
2690
  @beartype
2711
2691
  def check_if_range_types_are_invalid(value_type: str, valid_value_types: list) -> None:
2712
2692
  if value_type not in valid_value_types:
2713
2693
  valid_value_types_string = ", ".join(valid_value_types)
2714
- print_red(f"⚠ {value_type} is not a valid value type. Valid types for range are: {valid_value_types_string}")
2715
- my_exit(181)
2694
+ _fatal_error(f"⚠ {value_type} is not a valid value type. Valid types for range are: {valid_value_types_string}", 181)
2716
2695
 
2717
2696
  @beartype
2718
2697
  def check_range_params_length(this_args: Union[str, list]) -> None:
2719
2698
  if len(this_args) != 5 and len(this_args) != 4 and len(this_args) != 6:
2720
- print_red("\n⚠ --parameter for type range must have 4 (or 5, the last one being optional and float by default, or 6, while the last one is true or false) parameters: <NAME> range <START> <END> (<TYPE (int or float)>, <log_scale: bool>)")
2721
- my_exit(181)
2699
+ _fatal_error("\n⚠ --parameter for type range must have 4 (or 5, the last one being optional and float by default, or 6, while the last one is true or false) parameters: <NAME> range <START> <END> (<TYPE (int or float)>, <log_scale: bool>)", 181)
2722
2700
 
2723
2701
  @beartype
2724
2702
  def die_181_or_91_if_lower_and_upper_bound_equal_zero(lower_bound: Union[int, float], upper_bound: Union[int, float]) -> None:
2725
2703
  if upper_bound is None or lower_bound is None:
2726
- print_red("die_181_or_91_if_lower_and_upper_bound_equal_zero: upper_bound or lower_bound is None. Cannot continue.")
2727
- my_exit(91)
2704
+ _fatal_error("die_181_or_91_if_lower_and_upper_bound_equal_zero: upper_bound or lower_bound is None. Cannot continue.", 91)
2728
2705
  if upper_bound == lower_bound:
2729
2706
  if lower_bound == 0:
2730
- print_red(f"⚠ Lower bound and upper bound are equal: {lower_bound}, cannot automatically fix this, because they -0 = +0 (usually a quickfix would be to set lower_bound = -upper_bound)")
2731
- my_exit(181)
2707
+ _fatal_error(f"⚠ Lower bound and upper bound are equal: {lower_bound}, cannot automatically fix this, because they -0 = +0 (usually a quickfix would be to set lower_bound = -upper_bound)", 181)
2732
2708
  print_red(f"⚠ Lower bound and upper bound are equal: {lower_bound}, setting lower_bound = -upper_bound")
2733
2709
  if upper_bound is not None:
2734
2710
  lower_bound = -upper_bound
@@ -3170,8 +3146,7 @@ def calculate_signed_weighted_euclidean_distance(_args: Union[dict, List[float]]
3170
3146
  pattern = r'^\s*-?\d+(\.\d+)?\s*(,\s*-?\d+(\.\d+)?\s*)*$'
3171
3147
 
3172
3148
  if not re.fullmatch(pattern, weights_string):
3173
- print_red(f"String '{weights_string}' does not match pattern {pattern}")
3174
- my_exit(32)
3149
+ _fatal_error(f"String '{weights_string}' does not match pattern {pattern}", 32)
3175
3150
 
3176
3151
  weights = [float(w.strip()) for w in weights_string.split(",") if w.strip()]
3177
3152
 
@@ -4214,8 +4189,7 @@ def abandon_job(job: Job, trial_index: int) -> bool:
4214
4189
  print_debug(f"abandon_job: removing job {job}, trial_index: {trial_index}")
4215
4190
  global_vars["jobs"].remove((job, trial_index))
4216
4191
  else:
4217
- print_red("ax_client could not be found")
4218
- my_exit(9)
4192
+ _fatal_error("ax_client could not be found", 9)
4219
4193
  except Exception as e:
4220
4194
  print(f"ERROR in line {get_line_info()}: {e}")
4221
4195
  print_debug(f"ERROR in line {get_line_info()}: {e}")
@@ -4320,8 +4294,7 @@ def save_checkpoint(trial_nr: int = 0, eee: Union[None, str, Exception] = None)
4320
4294
  if ax_client:
4321
4295
  ax_client.save_to_json_file(filepath=checkpoint_filepath)
4322
4296
  else:
4323
- print_red("Something went wrong using the ax_client")
4324
- my_exit(9)
4297
+ _fatal_error("Something went wrong using the ax_client", 9)
4325
4298
  except Exception as e:
4326
4299
  save_checkpoint(trial_nr + 1, e)
4327
4300
 
@@ -4417,8 +4390,7 @@ def get_ax_param_representation(data: dict) -> dict:
4417
4390
 
4418
4391
  print("data:")
4419
4392
  pprint(data)
4420
- print_red(f"Unknown data range {data['type']}")
4421
- my_exit(19)
4393
+ _fatal_error(f"Unknown data range {data['type']}", 19)
4422
4394
 
4423
4395
  return {}
4424
4396
 
@@ -4448,8 +4420,7 @@ def set_torch_device_to_experiment_args(experiment_args: Union[None, dict]) -> T
4448
4420
  if experiment_args:
4449
4421
  experiment_args["choose_generation_strategy_kwargs"]["torch_device"] = torch_device
4450
4422
  else:
4451
- print_red("experiment_args could not be created.")
4452
- my_exit(90)
4423
+ _fatal_error("experiment_args could not be created.", 90)
4453
4424
 
4454
4425
  if experiment_args:
4455
4426
  return experiment_args, gpu_string, gpu_color
@@ -4459,8 +4430,7 @@ def set_torch_device_to_experiment_args(experiment_args: Union[None, dict]) -> T
4459
4430
  @beartype
4460
4431
  def die_with_47_if_file_doesnt_exists(_file: str) -> None:
4461
4432
  if not os.path.exists(_file):
4462
- print_red(f"Cannot find {_file}")
4463
- my_exit(47)
4433
+ _fatal_error(f"Cannot find {_file}", 47)
4464
4434
 
4465
4435
  @beartype
4466
4436
  def copy_state_files_from_previous_job(continue_previous_job: str) -> None:
@@ -4740,8 +4710,7 @@ def set_experiment_constraints(experiment_constraints: Optional[list], experimen
4740
4710
  if equation:
4741
4711
  experiment_args["parameter_constraints"].append(constraints_string)
4742
4712
  else:
4743
- print_red(f"Experiment constraint '{constraints_string}' is invalid. Cannot continue.")
4744
- my_exit(19)
4713
+ _fatal_error(f"Experiment constraint '{constraints_string}' is invalid. Cannot continue.", 19)
4745
4714
 
4746
4715
  file_path = os.path.join(get_current_run_folder(), "state_files", "constraints")
4747
4716
 
@@ -4836,8 +4805,7 @@ def get_experiment_parameters(_params: list) -> Tuple[AxClient, Union[list, dict
4836
4805
  global ax_client
4837
4806
 
4838
4807
  if not ax_client:
4839
- print_red("Something went wrong with the ax_client")
4840
- my_exit(9)
4808
+ _fatal_error("Something went wrong with the ax_client", 9)
4841
4809
 
4842
4810
  gpu_string = ""
4843
4811
  gpu_color = "green"
@@ -4884,8 +4852,7 @@ def get_experiment_parameters(_params: list) -> Tuple[AxClient, Union[list, dict
4884
4852
  json.dump(experiment_parameters, outfile)
4885
4853
 
4886
4854
  if not os.path.exists(checkpoint_filepath):
4887
- print_red(f"{checkpoint_filepath} not found. Cannot continue_previous_job without.")
4888
- my_exit(47)
4855
+ _fatal_error(f"{checkpoint_filepath} not found. Cannot continue_previous_job without.", 47)
4889
4856
 
4890
4857
  with open(f'{get_current_run_folder()}/checkpoint_load_source', mode='w', encoding="utf-8") as f:
4891
4858
  print(f"Continuation from checkpoint {continue_previous_job}", file=f)
@@ -4923,17 +4890,13 @@ def get_experiment_parameters(_params: list) -> Tuple[AxClient, Union[list, dict
4923
4890
  new_metrics = [Metric(k) for k in arg_result_names if k not in ax_client.metric_names]
4924
4891
  ax_client.experiment.add_tracking_metrics(new_metrics)
4925
4892
  except AssertionError as error:
4926
- print_red(f"An error has occurred while creating the experiment (0): {error}. This can happen when you have invalid parameter constraints.")
4927
- my_exit(102)
4893
+ _fatal_error(f"An error has occurred while creating the experiment (0): {error}. This can happen when you have invalid parameter constraints.", 102)
4928
4894
  except ValueError as error:
4929
- print_red(f"An error has occurred while creating the experiment (1): {error}")
4930
- my_exit(49)
4895
+ _fatal_error(f"An error has occurred while creating the experiment (1): {error}", 49)
4931
4896
  except TypeError as error:
4932
- print_red(f"An error has occurred while creating the experiment (2): {error}. This is probably a bug in OmniOpt2.")
4933
- my_exit(49)
4897
+ _fatal_error(f"An error has occurred while creating the experiment (2): {error}. This is probably a bug in OmniOpt2.", 49)
4934
4898
  except ax.exceptions.core.UserInputError as error:
4935
- print_red(f"An error occurred while creating the experiment (3): {error}")
4936
- my_exit(49)
4899
+ _fatal_error(f"An error occurred while creating the experiment (3): {error}", 49)
4937
4900
 
4938
4901
  return ax_client, experiment_parameters, experiment_args, gpu_string, gpu_color
4939
4902
 
@@ -5001,8 +4964,7 @@ def parse_single_experiment_parameter_table(classic_params: Optional[Union[list,
5001
4964
 
5002
4965
  rows.append([str(param["name"]), get_type_short(_type), "", "", ", ".join(values), "", ""])
5003
4966
  else:
5004
- print_red(f"Type {_type} is not yet implemented in the overview table.")
5005
- my_exit(15)
4967
+ _fatal_error(f"Type {_type} is not yet implemented in the overview table.", 15)
5006
4968
 
5007
4969
  k = k + 1
5008
4970
 
@@ -5072,8 +5034,7 @@ def print_ax_parameter_constraints_table(experiment_args: dict) -> None:
5072
5034
  @beartype
5073
5035
  def print_result_names_overview_table() -> None:
5074
5036
  if not ax_client:
5075
- print_red("Tried to access ax_client in print_result_names_overview_table, but it failed, because the ax_client was not defined.")
5076
- my_exit(101)
5037
+ _fatal_error("Tried to access ax_client in print_result_names_overview_table, but it failed, because the ax_client was not defined.", 101)
5077
5038
 
5078
5039
  return None
5079
5040
 
@@ -5703,8 +5664,7 @@ def insert_job_into_ax_client(arm_params: dict, result: dict, new_job_type: str
5703
5664
  done_converting = False
5704
5665
 
5705
5666
  if ax_client is None or not ax_client:
5706
- print_red("insert_job_into_ax_client: ax_client was not defined where it should have been")
5707
- my_exit(101)
5667
+ _fatal_error("insert_job_into_ax_client: ax_client was not defined where it should have been", 101)
5708
5668
 
5709
5669
  while not done_converting:
5710
5670
  try:
@@ -6100,8 +6060,7 @@ def mark_trial_as_failed(trial_index: int, _trial: Any) -> None:
6100
6060
  print_debug(f"Marking trial {_trial} as failed")
6101
6061
  try:
6102
6062
  if not ax_client:
6103
- print_red("mark_trial_as_failed: ax_client is not defined")
6104
- my_exit(101)
6063
+ _fatal_error("mark_trial_as_failed: ax_client is not defined", 101)
6105
6064
 
6106
6065
  return None
6107
6066
 
@@ -6135,8 +6094,7 @@ def _finish_job_core_helper_complete_trial(trial_index: int, raw_result: dict) -
6135
6094
  ax_client.update_trial_data(trial_index=trial_index, raw_data=raw_result)
6136
6095
  print_debug(f"Completing trial: {trial_index} with result: {raw_result} after failure... Done!")
6137
6096
  else:
6138
- print_red(f"Error completing trial: {e}")
6139
- my_exit(234)
6097
+ _fatal_error(f"Error completing trial: {e}", 234)
6140
6098
 
6141
6099
  @beartype
6142
6100
  def _finish_job_core_helper_mark_success(_trial: ax.core.trial.Trial, result: Union[float, int, tuple]) -> None:
@@ -6195,8 +6153,7 @@ def finish_job_core(job: Any, trial_index: int, this_jobs_finished: int) -> int:
6195
6153
  else:
6196
6154
  _finish_job_core_helper_mark_failure(job, trial_index, _trial)
6197
6155
  else:
6198
- print_red("ax_client could not be found or used")
6199
- my_exit(9)
6156
+ _fatal_error("ax_client could not be found or used", 9)
6200
6157
 
6201
6158
  print_debug(f"finish_job_core: removing job {job}, trial_index: {trial_index}")
6202
6159
  global_vars["jobs"].remove((job, trial_index))
@@ -6269,8 +6226,8 @@ def finish_previous_jobs(new_msgs: List[str]) -> None:
6269
6226
  global JOBS_FINISHED
6270
6227
 
6271
6228
  if not ax_client:
6272
- print_red("ax_client failed")
6273
- my_exit(101)
6229
+ _fatal_error("ax_client failed", 101)
6230
+
6274
6231
  return None
6275
6232
 
6276
6233
  this_jobs_finished = 0
@@ -6425,8 +6382,7 @@ def orchestrator_start_trial(params_from_out_file: Union[dict, str], trial_index
6425
6382
  print_debug(f"orchestrator_start_trial: appending job {new_job} to global_vars['jobs'], trial_index: {trial_index}")
6426
6383
  global_vars["jobs"].append((new_job, trial_index))
6427
6384
  else:
6428
- print_red("executor or ax_client could not be found properly")
6429
- my_exit(9)
6385
+ _fatal_error("executor or ax_client could not be found properly", 9)
6430
6386
 
6431
6387
  @beartype
6432
6388
  def handle_exclude_node(stdout_path: str, hostname_from_out_file: Union[None, str]) -> None:
@@ -6496,8 +6452,7 @@ def _orchestrate(stdout_path: str, trial_index: int) -> None:
6496
6452
  if handler:
6497
6453
  handler()
6498
6454
  else:
6499
- print_red(f"Orchestrator: {behav} not yet implemented!")
6500
- my_exit(210)
6455
+ _fatal_error(f"Orchestrator: {behav} not yet implemented!", 210)
6501
6456
 
6502
6457
  @beartype
6503
6458
  def write_continue_run_uuid_to_file() -> None:
@@ -6537,14 +6492,12 @@ def execute_evaluation(_params: list) -> Optional[int]:
6537
6492
  print_debug(f"execute_evaluation({_params})")
6538
6493
  trial_index, parameters, trial_counter, next_nr_steps, phase = _params
6539
6494
  if not ax_client:
6540
- print_red("Failed to get ax_client")
6541
- my_exit(9)
6495
+ _fatal_error("Failed to get ax_client", 9)
6542
6496
 
6543
6497
  return None
6544
6498
 
6545
6499
  if not executor:
6546
- print_red("executor could not be found")
6547
- my_exit(9)
6500
+ _fatal_error("executor could not be found", 9)
6548
6501
 
6549
6502
  return None
6550
6503
 
@@ -6608,8 +6561,7 @@ def exclude_defective_nodes() -> None:
6608
6561
  if executor:
6609
6562
  executor.update_parameters(exclude=excluded_string)
6610
6563
  else:
6611
- print_red("executor could not be found")
6612
- my_exit(9)
6564
+ _fatal_error("executor could not be found", 9)
6613
6565
 
6614
6566
  @beartype
6615
6567
  def handle_failed_job(error: Union[None, Exception, str], trial_index: int, new_job: Optional[Job]) -> None:
@@ -6638,8 +6590,7 @@ def cancel_failed_job(trial_index: int, new_job: Job) -> None:
6638
6590
  if ax_client:
6639
6591
  ax_client.log_trial_failure(trial_index=trial_index)
6640
6592
  else:
6641
- print_red("ax_client not defined")
6642
- my_exit(101)
6593
+ _fatal_error("ax_client not defined", 101)
6643
6594
  except Exception as e:
6644
6595
  print(f"ERROR in line {get_line_info()}: {e}")
6645
6596
  new_job.cancel()
@@ -6807,14 +6758,11 @@ def has_no_post_generation_constraints_or_matches_constraints(_post_generation_c
6807
6758
  @beartype
6808
6759
  def die_101_if_no_ax_client_or_experiment_or_gs() -> None:
6809
6760
  if ax_client is None:
6810
- print_red("Error: ax_client is not defined")
6811
- my_exit(101)
6761
+ _fatal_error("Error: ax_client is not defined", 101)
6812
6762
  elif ax_client.experiment is None:
6813
- print_red("Error: ax_client.experiment is not defined")
6814
- my_exit(101)
6763
+ _fatal_error("Error: ax_client.experiment is not defined", 101)
6815
6764
  elif global_gs is None:
6816
- print_red("Error: global_gs is not defined")
6817
- my_exit(101)
6765
+ _fatal_error("Error: global_gs is not defined", 101)
6818
6766
 
6819
6767
  @beartype
6820
6768
  def get_batched_arms(nr_of_jobs_to_get: int) -> list:
@@ -6822,8 +6770,7 @@ def get_batched_arms(nr_of_jobs_to_get: int) -> list:
6822
6770
  attempts = 0
6823
6771
 
6824
6772
  if global_gs is None:
6825
- print_red("Global generation strategy is not set. This is a bug in OmniOpt2.")
6826
- my_exit(107)
6773
+ _fatal_error("Global generation strategy is not set. This is a bug in OmniOpt2.", 107)
6827
6774
 
6828
6775
  return []
6829
6776
 
@@ -6855,101 +6802,140 @@ def get_batched_arms(nr_of_jobs_to_get: int) -> list:
6855
6802
 
6856
6803
  return batched_arms
6857
6804
 
6858
- @disable_logs
6859
6805
  @beartype
6860
6806
  def _fetch_next_trials(nr_of_jobs_to_get: int, recursion: bool = False) -> Optional[Tuple[Dict[int, Any], bool]]:
6861
- global gotten_jobs
6807
+ die_101_if_no_ax_client_or_experiment_or_gs()
6862
6808
 
6863
6809
  if not ax_client:
6864
- print_red("ax_client was not defined")
6865
- my_exit(9)
6810
+ _fatal_error("ax_client was not defined", 9)
6866
6811
 
6867
6812
  if global_gs is None:
6868
- print_red("Global generation strategy is not set. This is a bug in OmniOpt2.")
6869
- my_exit(107)
6813
+ _fatal_error("Global generation strategy is not set. This is a bug in OmniOpt2.", 107)
6870
6814
 
6871
- return None
6815
+ return _generate_trials(nr_of_jobs_to_get, recursion)
6872
6816
 
6873
- trials_dict: dict = {}
6817
+ @beartype
6818
+ def _generate_trials(n: int, recursion: bool) -> Tuple[Dict[int, Any], bool]:
6819
+ global gotten_jobs
6874
6820
 
6821
+ trials_dict: Dict[int, Any] = {}
6875
6822
  trial_durations: List[float] = []
6876
6823
 
6877
- die_101_if_no_ax_client_or_experiment_or_gs()
6824
+ start_time = time.time()
6825
+ cnt = 0
6826
+ retries = 0
6827
+ max_retries = args.max_abandoned_retrial
6878
6828
 
6879
6829
  try:
6880
- all_start_time = time.time()
6830
+ while cnt < n and retries < max_retries:
6831
+ for arm in get_batched_arms(n - cnt):
6832
+ if cnt >= n:
6833
+ break
6881
6834
 
6882
- batched_arms = get_batched_arms(nr_of_jobs_to_get)
6835
+ print_debug(f"Fetching trial {cnt + 1}/{n}...")
6836
+ progressbar_description([_get_trials_message(cnt + 1, n, trial_durations)])
6883
6837
 
6884
- cnt = 0
6838
+ try:
6839
+ result = _create_and_handle_trial(arm)
6840
+ if result is not None:
6841
+ trial_index, trial_duration, trial_successful = result
6885
6842
 
6886
- for k in range(len(batched_arms)):
6887
- print_debug(f"_fetch_next_trials: fetching trial {k + 1}/{nr_of_jobs_to_get}...")
6888
- progressbar_description([_get_trials_message(k + 1, nr_of_jobs_to_get, trial_durations)])
6843
+ except TrialRejected as e:
6844
+ print_debug(f"Trial rejected: {e}")
6845
+ retries += 1
6846
+ continue
6889
6847
 
6890
- start_time = time.time()
6848
+ trial_durations.append(trial_duration)
6891
6849
 
6892
- trial_index = ax_client.experiment.num_trials
6850
+ if trial_successful:
6851
+ cnt += 1
6852
+ trials_dict[trial_index] = arm.parameters
6853
+ gotten_jobs += 1
6893
6854
 
6894
- arm = batched_arms[k]
6895
- generator_run = GeneratorRun(
6896
- arms=[arm],
6897
- generation_node_name=global_gs.current_node_name
6898
- )
6855
+ return _finalize_generation(trials_dict, cnt, n, start_time)
6899
6856
 
6900
- trial = ax_client.experiment.new_trial(generator_run)
6901
- params = arm.parameters
6857
+ except Exception as e:
6858
+ return _handle_generation_failure(e, n, recursion)
6902
6859
 
6903
- trials_dict[trial_index] = params
6904
- gotten_jobs = gotten_jobs + 1
6860
+ class TrialRejected(Exception):
6861
+ pass
6905
6862
 
6906
- print_debug(f"_fetch_next_trials: got trial {k + 1}/{nr_of_jobs_to_get} (trial_index: {trial_index} [gotten_jobs: {gotten_jobs}, k: {k}])")
6907
- end_time = time.time()
6863
+ @beartype
6864
+ def _create_and_handle_trial(arm: Any) -> Optional[Tuple[int, float, bool]]:
6865
+ start = time.time()
6908
6866
 
6909
- trial_durations.append(float(end_time - start_time))
6867
+ if global_gs is None:
6868
+ _fatal_error("global_gs is not set", 107)
6910
6869
 
6911
- if not has_no_post_generation_constraints_or_matches_constraints(post_generation_constraints, params):
6912
- print_debug(f"Marking trial as abandoned since it doesn't fit a Post-Generation-constraint: {params}")
6913
- trial.mark_abandoned()
6914
- abandoned_trial_indices.append(trial_index)
6915
- else:
6916
- trial.mark_running(no_runner_required=True)
6870
+ return None
6917
6871
 
6918
- cnt = cnt + 1
6872
+ _current_node_name = global_gs.current_node_name
6919
6873
 
6920
- all_end_time = time.time()
6921
- all_time = float(all_end_time - all_start_time)
6874
+ trial_index = ax_client.experiment.num_trials
6875
+ generator_run = GeneratorRun(
6876
+ arms=[arm],
6877
+ generation_node_name=_current_node_name
6878
+ )
6922
6879
 
6923
- log_gen_times.append(all_time)
6924
- log_nr_gen_jobs.append(cnt)
6880
+ trial = ax_client.experiment.new_trial(generator_run)
6881
+ params = arm.parameters
6925
6882
 
6926
- if cnt:
6927
- progressbar_description([f"requested {nr_of_jobs_to_get} jobs, got {cnt}, {all_time / cnt} s/job"])
6928
- else:
6929
- progressbar_description([f"requested {nr_of_jobs_to_get} jobs, got {cnt}"])
6883
+ if not has_no_post_generation_constraints_or_matches_constraints(post_generation_constraints, params):
6884
+ print_debug(f"Trial {trial_index} does not meet post-generation constraints. Marking abandoned.")
6885
+ trial.mark_abandoned()
6886
+ abandoned_trial_indices.append(trial_index)
6887
+ raise TrialRejected("Post-generation constraints not met.")
6930
6888
 
6931
- return trials_dict, False
6932
- except np.linalg.LinAlgError as e:
6933
- _handle_linalg_error(e)
6934
- my_exit(242)
6935
- except (ax.exceptions.core.SearchSpaceExhausted, ax.exceptions.generation_strategy.GenerationStrategyRepeatedPoints, ax.exceptions.generation_strategy.MaxParallelismReachedException) as e:
6936
- if str(e) not in error_8_saved:
6937
- if recursion is False and args.revert_to_random_when_seemingly_exhausted:
6938
- print_yellow(f"\n⚠Error 8: {e} From now (done jobs: {count_done_jobs()}) on, random points will be generated.")
6939
- else:
6940
- print_red(f"\n⚠Error 8: {e}")
6889
+ trial.mark_running(no_runner_required=True)
6890
+ end = time.time()
6891
+ return trial_index, float(end - start), True
6941
6892
 
6942
- error_8_saved.append(str(e))
6893
+ @beartype
6894
+ def _finalize_generation(trials_dict: Dict[int, Any], cnt: int, requested: int, start_time: float) -> Tuple[Dict[int, Any], bool]:
6895
+ total_time = time.time() - start_time
6943
6896
 
6944
- if recursion is False and args.revert_to_random_when_seemingly_exhausted:
6945
- print_debug("The search space seems exhausted. Generating random points from here on.")
6897
+ log_gen_times.append(total_time)
6898
+ log_nr_gen_jobs.append(cnt)
6946
6899
 
6947
- set_global_gs_to_random()
6900
+ avg_time_str = f"{total_time / cnt:.2f} s/job" if cnt else "n/a"
6901
+ progressbar_description([f"requested {requested} jobs, got {cnt}, {avg_time_str}"])
6902
+
6903
+ return trials_dict, False
6904
+
6905
+ @beartype
6906
+ def _handle_generation_failure(
6907
+ e: Exception,
6908
+ requested: int,
6909
+ recursion: bool
6910
+ ) -> Tuple[Dict[int, Any], bool]:
6911
+ if isinstance(e, np.linalg.LinAlgError):
6912
+ _handle_linalg_error(e)
6913
+ my_exit(242)
6948
6914
 
6949
- return _fetch_next_trials(nr_of_jobs_to_get, True)
6915
+ elif isinstance(e, (
6916
+ ax.exceptions.core.SearchSpaceExhausted,
6917
+ ax.exceptions.generation_strategy.GenerationStrategyRepeatedPoints,
6918
+ ax.exceptions.generation_strategy.MaxParallelismReachedException
6919
+ )):
6920
+ msg = str(e)
6921
+ if msg not in error_8_saved:
6922
+ _print_exhaustion_warning(e, recursion)
6923
+ error_8_saved.append(msg)
6924
+
6925
+ if not recursion and args.revert_to_random_when_seemingly_exhausted:
6926
+ print_debug("Switching to random search strategy.")
6927
+ set_global_gs_to_random()
6928
+ return _fetch_next_trials(requested, True)
6950
6929
 
6951
6930
  return {}, True
6952
6931
 
6932
+ @beartype
6933
+ def _print_exhaustion_warning(e: Exception, recursion: bool) -> None:
6934
+ if not recursion and args.revert_to_random_when_seemingly_exhausted:
6935
+ print_yellow(f"\n⚠Error 8: {e} From now (done jobs: {count_done_jobs()}) on, random points will be generated.")
6936
+ else:
6937
+ print_red(f"\n⚠Error 8: {e}")
6938
+
6953
6939
  @beartype
6954
6940
  def get_model_kwargs() -> dict:
6955
6941
  if 'Cont_X_trans_Y_trans' in args.transforms:
@@ -7376,8 +7362,7 @@ def parse_generation_strategy_string(gen_strat_str: str) -> Tuple[list, int]:
7376
7362
  matching_model = get_matching_model_name(model_name)
7377
7363
 
7378
7364
  if matching_model in ["RANDOMFOREST", "EXTERNAL_GENERATOR"]:
7379
- print_red(f"Model {matching_model} is not valid for custom generation strategy.")
7380
- my_exit(56)
7365
+ _fatal_error(f"Model {matching_model} is not valid for custom generation strategy.", 56)
7381
7366
 
7382
7367
  if matching_model:
7383
7368
  gen_strat_list.append({matching_model: nr})
@@ -7412,8 +7397,7 @@ def write_state_file(name: str, var: str) -> None:
7412
7397
  file_path = f"{get_current_run_folder()}/state_files/{name}"
7413
7398
 
7414
7399
  if os.path.isdir(file_path):
7415
- print_red(f"{file_path} is a dir. Must be a file.")
7416
- my_exit(246)
7400
+ _fatal_error(f"{file_path} is a dir. Must be a file.", 246)
7417
7401
 
7418
7402
  makedirs(os.path.dirname(file_path))
7419
7403
 
@@ -7460,8 +7444,7 @@ def continue_not_supported_on_custom_generation_strategy() -> None:
7460
7444
  generation_strategy_file = f"{args.continue_previous_job}/state_files/custom_generation_strategy"
7461
7445
 
7462
7446
  if os.path.exists(generation_strategy_file):
7463
- print_red("Trying to continue a job which was started with --generation_strategy. This is currently not possible.")
7464
- my_exit(247)
7447
+ _fatal_error("Trying to continue a job which was started with --generation_strategy. This is currently not possible.", 247)
7465
7448
 
7466
7449
  @beartype
7467
7450
  def get_step_name(model_name: str, nr: int) -> str:
@@ -7503,8 +7486,7 @@ def get_torch_device_str() -> str:
7503
7486
  def create_node(model_name: str, threshold: int, next_model_name: Optional[str]) -> Union[RandomForestGenerationNode, GenerationNode]:
7504
7487
  if model_name == "RANDOMFOREST":
7505
7488
  if len(arg_result_names) != 1:
7506
- print_red("Currently, RANDOMFOREST does not support Multi-Objective-Optimization")
7507
- my_exit(251)
7489
+ _fatal_error("Currently, RANDOMFOREST does not support Multi-Objective-Optimization", 251)
7508
7490
 
7509
7491
  node = RandomForestGenerationNode(
7510
7492
  num_samples=threshold,
@@ -7518,8 +7500,7 @@ def create_node(model_name: str, threshold: int, next_model_name: Optional[str])
7518
7500
 
7519
7501
  if model_name == "TPE":
7520
7502
  if len(arg_result_names) != 1:
7521
- print_red(f"Has {len(arg_result_names)} results. TPE currently only supports single-objective-optimization.")
7522
- my_exit(108)
7503
+ _fatal_error(f"Has {len(arg_result_names)} results. TPE currently only supports single-objective-optimization.", 108)
7523
7504
 
7524
7505
  node = ExternalProgramGenerationNode(f"python3 {script_dir}/.tpe.py", "TPE")
7525
7506
 
@@ -7532,8 +7513,7 @@ def create_node(model_name: str, threshold: int, next_model_name: Optional[str])
7532
7513
 
7533
7514
  if model_name == "EXTERNAL_GENERATOR":
7534
7515
  if args.external_generator is None or args.external_generator == "":
7535
- print_red("--external_generator is missing. Cannot create points for EXTERNAL_GENERATOR without it.")
7536
- my_exit(204)
7516
+ _fatal_error("--external_generator is missing. Cannot create points for EXTERNAL_GENERATOR without it.", 204)
7537
7517
 
7538
7518
  node = ExternalProgramGenerationNode(args.external_generator)
7539
7519
 
@@ -7770,8 +7750,7 @@ def handle_exceptions_create_and_execute_next_runs(e: Exception) -> int:
7770
7750
  print_red(f"Error 2: {e}")
7771
7751
  elif isinstance(e, ax.exceptions.core.DataRequiredError):
7772
7752
  if "transform requires non-empty data" in str(e) and args.num_random_steps == 0:
7773
- print_red(f"Error 3: {e} Increase --num_random_steps to at least 1 to continue.")
7774
- my_exit(233)
7753
+ _fatal_error(f"Error 3: {e} Increase --num_random_steps to at least 1 to continue.", 233)
7775
7754
  else:
7776
7755
  print_debug(f"Error 4: {e}")
7777
7756
  elif isinstance(e, RuntimeError):
@@ -7922,8 +7901,7 @@ executor.update_parameters(
7922
7901
  if args.exclude:
7923
7902
  print_yellow(f"Excluding the following nodes: {args.exclude}")
7924
7903
  else:
7925
- print_red("executor could not be found")
7926
- my_exit(9)
7904
+ _fatal_error("executor could not be found", 9)
7927
7905
 
7928
7906
  @beartype
7929
7907
  def set_global_executor() -> None:
@@ -8178,8 +8156,7 @@ def set_orchestrator() -> None:
8178
8156
  def check_if_has_random_steps() -> None:
8179
8157
  with console.status("[bold green]Checking if has random steps..."):
8180
8158
  if (not args.continue_previous_job and "--continue" not in sys.argv) and (args.num_random_steps == 0 or not args.num_random_steps) and args.model not in ["EXTERNAL_GENERATOR", "SOBOL", "PSEUDORANDOM"]:
8181
- print_red("You have no random steps set. This is only allowed in continued jobs. To start, you need either some random steps, or a continued run.")
8182
- my_exit(233)
8159
+ _fatal_error("You have no random steps set. This is only allowed in continued jobs. To start, you need either some random steps, or a continued run.", 233)
8183
8160
 
8184
8161
  @beartype
8185
8162
  def add_exclude_to_defective_nodes() -> None:
@@ -8192,8 +8169,7 @@ def add_exclude_to_defective_nodes() -> None:
8192
8169
  @beartype
8193
8170
  def check_max_eval(_max_eval: int) -> None:
8194
8171
  if not _max_eval:
8195
- print_red("--max_eval needs to be set!")
8196
- my_exit(19)
8172
+ _fatal_error("--max_eval needs to be set!", 19)
8197
8173
 
8198
8174
  @beartype
8199
8175
  def parse_parameters() -> Any:
@@ -8648,23 +8624,19 @@ def get_result_minimize_flag(path_to_calculate: str, resname: str) -> bool:
8648
8624
  result_min_max_path = os.path.join(path_to_calculate, "result_min_max.txt")
8649
8625
 
8650
8626
  if not os.path.isdir(path_to_calculate):
8651
- print_red(f"Error: Directory '{path_to_calculate}' does not exist.")
8652
- my_exit(24)
8627
+ _fatal_error(f"Error: Directory '{path_to_calculate}' does not exist.", 24)
8653
8628
 
8654
8629
  if not os.path.isfile(result_names_path) or not os.path.isfile(result_min_max_path):
8655
- print_red(f"Error: Missing 'result_names.txt' or 'result_min_max.txt' in '{path_to_calculate}'.")
8656
- my_exit(24)
8630
+ _fatal_error(f"Error: Missing 'result_names.txt' or 'result_min_max.txt' in '{path_to_calculate}'.", 24)
8657
8631
 
8658
8632
  try:
8659
8633
  with open(result_names_path, "r", encoding="utf-8") as f:
8660
8634
  names = [line.strip() for line in f]
8661
8635
  except Exception as e:
8662
- print_red(f"Error: Failed to read 'result_names.txt': {e}")
8663
- my_exit(24)
8636
+ _fatal_error(f"Error: Failed to read 'result_names.txt': {e}", 24)
8664
8637
 
8665
8638
  if resname not in names:
8666
- print_red(f"Error: Result name '{resname}' not found in 'result_names.txt'.")
8667
- my_exit(24)
8639
+ _fatal_error(f"Error: Result name '{resname}' not found in 'result_names.txt'.", 24)
8668
8640
 
8669
8641
  index = names.index(resname)
8670
8642
 
@@ -8672,12 +8644,10 @@ def get_result_minimize_flag(path_to_calculate: str, resname: str) -> bool:
8672
8644
  with open(result_min_max_path, "r", encoding="utf-8") as f:
8673
8645
  minmax = [line.strip().lower() for line in f]
8674
8646
  except Exception as e:
8675
- print_red(f"Error: Failed to read 'result_min_max.txt': {e}")
8676
- my_exit(24)
8647
+ _fatal_error(f"Error: Failed to read 'result_min_max.txt': {e}", 24)
8677
8648
 
8678
8649
  if index >= len(minmax):
8679
- print_red(f"Error: Not enough entries in 'result_min_max.txt' for index {index}.")
8680
- my_exit(24)
8650
+ _fatal_error(f"Error: Not enough entries in 'result_min_max.txt' for index {index}.", 24)
8681
8651
 
8682
8652
  return minmax[index] == "min"
8683
8653
 
@@ -9406,8 +9376,7 @@ def complex_tests(_program_name: str, wanted_stderr: str, wanted_exit_code: int,
9406
9376
  program_path: str = f"./.tests/test_wronggoing_stuff.bin/bin/{_program_name}"
9407
9377
 
9408
9378
  if not os.path.exists(program_path):
9409
- print_red(f"Program path {program_path} not found!")
9410
- my_exit(18)
9379
+ _fatal_error(f"Program path {program_path} not found!", 18)
9411
9380
 
9412
9381
  program_path_with_program: str = f"{program_path}"
9413
9382