Coverage for sparkle/platform/output/structures.py: 37%

41 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-09-29 10:17 +0000

1#!/usr/bin/env python3 

2"""Sparkle output structures.""" 

3 

4from __future__ import annotations 

5from pathlib import Path 

6 

7from runrunner.base import Status 

8 

9from sparkle.solver import Solver 

10from sparkle.types import SolverStatus, SparkleObjective 

11from sparkle.instance import InstanceSet 

12from sparkle.structures import PerformanceDataFrame 

13 

14 

15class ValidationResults: 

16 """Class that stores validation information and results.""" 

17 

18 def __init__( 

19 self: ValidationResults, 

20 solver: Solver, 

21 configuration: dict, 

22 instance_set: InstanceSet, 

23 results: list[list[str, Status, float, float]], 

24 ) -> None: 

25 """Initalize ValidationResults. 

26 

27 Args: 

28 solver: The name of the solver 

29 configuration: The configuration being used 

30 instance_set: The set of instances 

31 results: Validation results in the format: 

32 [["instance", "status", "quality", "runtime"]] 

33 """ 

34 self.solver = solver 

35 self.configuration = configuration 

36 self.instance_set = instance_set 

37 self.result_header = ["instance", "status", "quality", "runtime"] 

38 self.result_vals = results 

39 

40 

41class SelectionSolverData: 

42 """Class that stores solver information.""" 

43 

44 def __init__( 

45 self: SelectionSolverData, 

46 solver_performance_ranking: list[tuple[str, float]], 

47 num_solvers: int, 

48 ) -> None: 

49 """Initalize SelectionSolverData. 

50 

51 Args: 

52 solver_performance_ranking: list with solvers ranked by avg. performance 

53 num_solvers: The number of solvers 

54 """ 

55 self.solver_performance_ranking = solver_performance_ranking 

56 self.single_best_solver = solver_performance_ranking[0][0] 

57 self.num_solvers = num_solvers 

58 

59 

60class SelectionPerformance: 

61 """Class that stores selection performance results.""" 

62 

63 def __init__( 

64 self: SelectionSolverData, 

65 performance_path: Path, 

66 vbs_performance: float, 

67 objective: SparkleObjective, 

68 ) -> None: 

69 """Initalize SelectionPerformance. 

70 

71 Args: 

72 performance_path: Path to portfolio selector performance 

73 vbs_performance: The performance of the virtual best selector 

74 objective: The objective (Performance type) 

75 """ 

76 performance_data = PerformanceDataFrame(performance_path) 

77 from sparkle.selector import SelectionScenario 

78 

79 self.actual_performance_data = performance_data.get_value( 

80 solver=SelectionScenario.__selector_solver_name__, objective=objective.name 

81 ) 

82 self.vbs_performance = vbs_performance 

83 self.actual_performance = performance_data.mean(objective=objective.name) 

84 self.metric = objective.name 

85 

86 

87class ParallelPortfolioResults: 

88 """Class that stores parallel portfolio results.""" 

89 

90 def __init__( 

91 self: ParallelPortfolioResults, 

92 unsolved_instances: int, 

93 sbs: str, 

94 runtime_solvers: dict[str, float], 

95 instance_results: dict[str, list], 

96 ) -> None: 

97 """Initalize SelectionSolverData. 

98 

99 Args: 

100 unsolved_instances: Number of unsolved instances 

101 sbs: Name of the single best solver 

102 runtime_solvers: Dictionary containing penalised average runtime per solver 

103 instance_results: Dictionary containing 

104 """ 

105 self.unsolved_instances = unsolved_instances 

106 self.sbs = sbs 

107 self.runtime_solvers = runtime_solvers 

108 self.instance_results = instance_results 

109 

110 self.solver_performance = {} 

111 # Iterate over each instance and aggregate the results 

112 for _, results in self.instance_results.items(): 

113 for solver_result in results: 

114 solver_name = solver_result[0] 

115 outcome = solver_result[1] 

116 # Initialize the solver's record in solver_performance if not present 

117 if solver_name not in self.solver_performance: 

118 self.solver_performance[solver_name] = { 

119 status: 0 for status in SolverStatus 

120 } 

121 # Increment the appropriate outcome count 

122 self.solver_performance[solver_name][outcome] += 1