Coverage for sparkle/configurator/configurator.py: 80%

51 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-09-27 09:10 +0000

1#!/usr/bin/env python3 

2# -*- coding: UTF-8 -*- 

3"""Configurator class to use different algorithm configurators like SMAC.""" 

4 

5from __future__ import annotations 

6from abc import abstractmethod 

7from pathlib import Path 

8 

9from runrunner import Runner, Run 

10from sparkle.solver import Solver 

11from sparkle.solver.validator import Validator 

12from sparkle.instance import InstanceSet 

13from sparkle.types import SparkleObjective 

14 

15 

16class Configurator: 

17 """Abstact class to use different configurators like SMAC.""" 

18 configurator_cli_path = Path(__file__).parent.resolve() / "configurator_cli.py" 

19 

20 def __init__(self: Configurator, validator: Validator, output_path: Path, 

21 executable_path: Path, configurator_target: Path, 

22 objectives: list[SparkleObjective], base_dir: Path, tmp_path: Path, 

23 multi_objective_support: bool = False) -> None: 

24 """Initialize Configurator. 

25 

26 Args: 

27 validator: Validator object to validate configurations runs 

28 output_path: Output directory of the Configurator. 

29 executable_path: Executable of the configurator for Sparkle to call 

30 configurator_target: The wrapper algorithm to standardize configurator 

31 input/output towards solver wrappers. 

32 objectives: The list of Sparkle Objectives the configurator has to 

33 optimize. 

34 base_dir: Where to execute the configuration 

35 tmp_path: Path for the temporary files of the configurator, optional 

36 multi_objective_support: Whether the configurator supports 

37 multi objective optimization for solvers. 

38 """ 

39 self.validator = validator 

40 self.output_path = output_path 

41 self.executable_path = executable_path 

42 self.configurator_target = configurator_target 

43 self.objectives = objectives 

44 self.base_dir = base_dir 

45 self.tmp_path = tmp_path 

46 self.multiobjective = multi_objective_support 

47 self.scenario = None 

48 if len(self.objectives) > 1 and not self.multiobjective: 

49 print("Warning: Multiple objectives specified but current configurator " 

50 f"{self.configurator_path.name} only supports single objective. " 

51 f"Defaulted to first specified objective: {self.objectives[0].name}") 

52 

53 @property 

54 def scenario_class(self: Configurator) -> ConfigurationScenario: 

55 """Return the scenario class of the configurator.""" 

56 return ConfigurationScenario 

57 

58 @abstractmethod 

59 def configure(self: Configurator, 

60 scenario: ConfigurationScenario, 

61 validate_after: bool = True, 

62 sbatch_options: list[str] = [], 

63 num_parallel_jobs: int = None, 

64 base_dir: Path = None, 

65 run_on: Runner = Runner.SLURM) -> Run: 

66 """Start configuration job. 

67 

68 Args: 

69 scenario: ConfigurationScenario to execute. 

70 validate_after: Whether to validate the configuration on the training set 

71 afterwards or not. 

72 sbatch_options: List of slurm batch options to use 

73 num_parallel_jobs: The maximum number of jobs to run in parallel 

74 base_dir: The base_dir of RunRunner where the sbatch scripts will be placed 

75 run_on: On which platform to run the jobs. Default: Slurm. 

76 

77 Returns: 

78 A RunRunner Run object. 

79 """ 

80 raise NotImplementedError 

81 

82 @abstractmethod 

83 def get_optimal_configuration(self: Configurator, 

84 solver: Solver, 

85 instance_set: InstanceSet, 

86 objective: SparkleObjective) -> tuple[float, str]: 

87 """Returns the optimal configuration string for a solver of an instance set.""" 

88 raise NotImplementedError 

89 

90 @staticmethod 

91 def organise_output(output_source: Path, output_target: Path) -> None | str: 

92 """Method to restructure and clean up after a single configurator call.""" 

93 raise NotImplementedError 

94 

95 def set_scenario_dirs(self: Configurator, 

96 solver: Solver, instance_set: InstanceSet) -> None: 

97 """Patching method to allow the rebuilding of configuration scenario.""" 

98 raise NotImplementedError 

99 

100 def get_status_from_logs(self: Configurator) -> None: 

101 """Method to scan the log files of the configurator for warnings.""" 

102 raise NotImplementedError 

103 

104 

105class ConfigurationScenario: 

106 """Template class to handle a configuration scenarios.""" 

107 def __init__(self: ConfigurationScenario, solver: Solver, 

108 instance_set: InstanceSet, 

109 sparkle_objectives: list[SparkleObjective] = None)\ 

110 -> None: 

111 """Initialize scenario paths and names. 

112 

113 Args: 

114 solver: Solver that should be configured. 

115 instance_set: Instances object for the scenario. 

116 sparkle_objectives: SparkleObjectives used for each run of the configuration. 

117 """ 

118 self.solver = solver 

119 self.instance_set = instance_set 

120 self.sparkle_objectives = sparkle_objectives 

121 self.name = f"{self.solver.name}_{self.instance_set.name}" 

122 

123 def create_scenario(self: ConfigurationScenario, parent_directory: Path) -> None: 

124 """Create scenario with solver and instances in the parent directory. 

125 

126 This prepares all the necessary subdirectories related to configuration. 

127 

128 Args: 

129 parent_directory: Directory in which the scenario should be created. 

130 """ 

131 raise NotImplementedError 

132 

133 def create_scenario_file(self: ConfigurationScenario) -> None: 

134 """Create a file with the configuration scenario. 

135 

136 Writes supplementary information to the target algorithm (algo =) as: 

137 algo = {configurator_target} {solver_directory} {sparkle_objective} 

138 """ 

139 raise NotImplementedError 

140 

141 @staticmethod 

142 def from_file(scenario_file: Path, solver: Solver, instance_set: InstanceSet, 

143 ) -> ConfigurationScenario: 

144 """Reads scenario file and initalises ConfigurationScenario.""" 

145 raise NotImplementedError