@@ -57,7 +57,7 @@ def test_get_trace(self) -> None:
5757 exp = get_experiment_with_observations (
5858 observations = [[11 ], [10 ], [9 ], [15 ], [5 ]], minimize = True
5959 )
60- self .assertEqual (get_trace (exp ), [ 11 , 10 , 9 , 9 , 5 ] )
60+ self .assertEqual (get_trace (exp ), { 0 : 11 , 1 : 10 , 2 : 9 , 3 : 9 , 4 : 5 } )
6161
6262 # Same experiment with maximize via new optimization config.
6363 opt_conf = none_throws (exp .optimization_config ).clone ()
@@ -67,7 +67,7 @@ def test_get_trace(self) -> None:
6767 opt_conf .objective .metric_names [0 ]: opt_conf .objective .metric_names [0 ]
6868 },
6969 )
70- self .assertEqual (get_trace (exp , opt_conf ), [ 11 , 11 , 11 , 15 , 15 ] )
70+ self .assertEqual (get_trace (exp , opt_conf ), { 0 : 11 , 1 : 11 , 2 : 11 , 3 : 15 , 4 : 15 } )
7171
7272 with self .subTest ("Single objective with constraints" ):
7373 # The second metric is the constraint and needs to be >= 0
@@ -76,48 +76,52 @@ def test_get_trace(self) -> None:
7676 minimize = False ,
7777 constrained = True ,
7878 )
79- self .assertEqual (get_trace (exp ), [float ("-inf" ), 10 , 10 , 10 , 11 ])
79+ self .assertEqual (
80+ get_trace (exp ),
81+ {0 : float ("-inf" ), 1 : 10 , 2 : 10 , 3 : 10 , 4 : 11 },
82+ )
8083
8184 exp = get_experiment_with_observations (
8285 observations = [[11 , - 1 ], [10 , 1 ], [9 , 1 ], [15 , - 1 ], [11 , 1 ]],
8386 minimize = True ,
8487 constrained = True ,
8588 )
86- self .assertEqual (get_trace (exp ), [ float ("inf" ), 10 , 9 , 9 , 9 ] )
89+ self .assertEqual (get_trace (exp ), { 0 : float ("inf" ), 1 : 10 , 2 : 9 , 3 : 9 , 4 : 9 } )
8790
8891 # Scalarized.
8992 exp = get_experiment_with_observations (
9093 observations = [[1 , 1 ], [2 , 2 ], [3 , 3 ]],
9194 scalarized = True ,
9295 )
93- self .assertEqual (get_trace (exp ), [ 2 , 4 , 6 ] )
96+ self .assertEqual (get_trace (exp ), { 0 : 2 , 1 : 4 , 2 : 6 } )
9497
9598 # Multi objective.
9699 exp = get_experiment_with_observations (
97100 observations = [[1 , 1 ], [- 1 , 100 ], [1 , 2 ], [3 , 3 ], [2 , 4 ], [2 , 1 ]],
98101 )
99- self .assertEqual (get_trace (exp ), [ 1 , 1 , 2 , 9 , 11 , 11 ] )
102+ self .assertEqual (get_trace (exp ), { 0 : 1 , 1 : 1 , 2 : 2 , 3 : 9 , 4 : 11 , 5 : 11 } )
100103
101104 # W/o ObjectiveThresholds (inferring ObjectiveThresholds from scaled nadir)
102105 assert_is_instance (
103106 exp .optimization_config , MultiObjectiveOptimizationConfig
104107 ).objective_thresholds = []
105108 trace = get_trace (exp )
109+ trace_values = list (trace .values ())
106110 # With inferred thresholds via scaled nadir, check trace properties:
107111 # - All values should be non-negative
108- self .assertTrue (all (v >= 0.0 for v in trace ))
112+ self .assertTrue (all (v >= 0.0 for v in trace_values ))
109113 # - Trace should be non-decreasing (cumulative best)
110- for i in range (1 , len (trace )):
111- self .assertGreaterEqual (trace [i ], trace [i - 1 ])
114+ for i in range (1 , len (trace_values )):
115+ self .assertGreaterEqual (trace_values [i ], trace_values [i - 1 ])
112116 # - Final value should be positive (non-trivial HV)
113- self .assertGreater (trace [- 1 ], 0.0 )
117+ self .assertGreater (trace_values [- 1 ], 0.0 )
114118
115119 # Multi-objective w/ constraints.
116120 exp = get_experiment_with_observations (
117121 observations = [[- 1 , 1 , 1 ], [1 , 2 , 1 ], [3 , 3 , - 1 ], [2 , 4 , 1 ], [2 , 1 , 1 ]],
118122 constrained = True ,
119123 )
120- self .assertEqual (get_trace (exp ), [ 0 , 2 , 2 , 8 , 8 ] )
124+ self .assertEqual (get_trace (exp ), { 0 : 0 , 1 : 2 , 2 : 2 , 3 : 8 , 4 : 8 } )
121125
122126 # W/ relative constraints & status quo.
123127 exp .status_quo = Arm (parameters = {"x" : 0.5 , "y" : 0.5 }, name = "status_quo" )
@@ -149,17 +153,17 @@ def test_get_trace(self) -> None:
149153 ]
150154 status_quo_data = Data (df = pd .DataFrame .from_records (df_dict ))
151155 exp .attach_data (data = status_quo_data )
152- self .assertEqual (get_trace (exp ), [ 0 , 2 , 2 , 8 , 8 ] )
156+ self .assertEqual (get_trace (exp ), { 0 : 0 , 1 : 2 , 2 : 2 , 3 : 8 , 4 : 8 } )
153157
154158 # W/ first objective being minimized.
155159 exp = get_experiment_with_observations (
156160 observations = [[1 , 1 ], [- 1 , 2 ], [3 , 3 ], [- 2 , 4 ], [2 , 1 ]], minimize = True
157161 )
158- self .assertEqual (get_trace (exp ), [ 0 , 2 , 2 , 8 , 8 ] )
162+ self .assertEqual (get_trace (exp ), { 0 : 0 , 1 : 2 , 2 : 2 , 3 : 8 , 4 : 8 } )
159163
160164 # W/ empty data.
161165 exp = get_experiment_with_trial ()
162- self .assertEqual (get_trace (exp ), [] )
166+ self .assertEqual (get_trace (exp ), {} )
163167
164168 # test batch trial
165169 exp = get_experiment_with_batch_trial (with_status_quo = False )
@@ -191,7 +195,7 @@ def test_get_trace(self) -> None:
191195 ]
192196 )
193197 exp .attach_data (Data (df = pd .DataFrame .from_records (df_dict )))
194- self .assertEqual (get_trace (exp ), [ 2.0 ] )
198+ self .assertEqual (get_trace (exp ), { 0 : 2.0 } )
195199 # test that there is performance metric in the trace for each
196200 # completed/early-stopped trial
197201 trial1 = assert_is_instance (trial , BatchTrial ).clone_to (include_sq = False )
@@ -214,7 +218,7 @@ def test_get_trace(self) -> None:
214218 ]
215219 )
216220 exp .attach_data (Data (df = pd .DataFrame .from_records (df_dict2 )))
217- self .assertEqual (get_trace (exp ), [ 2.0 , 2.0 , 20.0 ] )
221+ self .assertEqual (get_trace (exp ), { 0 : 2.0 , 2 : 20.0 } )
218222
219223 def test_get_trace_with_non_completed_trials (self ) -> None :
220224 with self .subTest ("minimize with abandoned trial" ):
@@ -224,12 +228,11 @@ def test_get_trace_with_non_completed_trials(self) -> None:
224228 # Mark trial 2 (value=9) as abandoned
225229 exp .trials [2 ].mark_abandoned (unsafe = True )
226230
227- # Abandoned trial carries forward the last best value
231+ # Abandoned trial is excluded from trace
228232 trace = get_trace (exp )
229- self .assertEqual (len (trace ), 5 )
230- # Trial 0: 11, Trial 1: 10, Trial 2 (abandoned): carry forward 10
233+ # Trial 0: 11, Trial 1: 10, Trial 2 (abandoned): excluded
231234 # Trial 3: 10 (15 > 10), Trial 4: 5
232- self .assertEqual (trace , [ 11 , 10 , 10 , 10 , 5 ] )
235+ self .assertEqual (trace , { 0 : 11 , 1 : 10 , 3 : 10 , 4 : 5 } )
233236
234237 with self .subTest ("maximize with abandoned trial" ):
235238 exp = get_experiment_with_observations (
@@ -238,12 +241,11 @@ def test_get_trace_with_non_completed_trials(self) -> None:
238241 # Mark trial 1 (value=3) as abandoned
239242 exp .trials [1 ].mark_abandoned (unsafe = True )
240243
241- # Abandoned trial carries forward the last best value
244+ # Abandoned trial is excluded from trace
242245 trace = get_trace (exp )
243- self .assertEqual (len (trace ), 5 )
244- # Trial 0: 1, Trial 1 (abandoned): carry forward 1,
246+ # Trial 0: 1, Trial 1 (abandoned): excluded,
245247 # Trial 2: 2, Trial 3: 5, Trial 4: 5
246- self .assertEqual (trace , [ 1 , 1 , 2 , 5 , 5 ] )
248+ self .assertEqual (trace , { 0 : 1 , 2 : 2 , 3 : 5 , 4 : 5 } )
247249
248250 with self .subTest ("minimize with failed trial" ):
249251 exp = get_experiment_with_observations (
@@ -252,12 +254,11 @@ def test_get_trace_with_non_completed_trials(self) -> None:
252254 # Mark trial 2 (value=9) as failed
253255 exp .trials [2 ].mark_failed (unsafe = True )
254256
255- # Failed trial carries forward the last best value
257+ # Failed trial is excluded from trace
256258 trace = get_trace (exp )
257- self .assertEqual (len (trace ), 5 )
258- # Trial 0: 11, Trial 1: 10, Trial 2 (failed): carry forward 10
259+ # Trial 0: 11, Trial 1: 10, Trial 2 (failed): excluded
259260 # Trial 3: 10 (15 > 10), Trial 4: 5
260- self .assertEqual (trace , [ 11 , 10 , 10 , 10 , 5 ] )
261+ self .assertEqual (trace , { 0 : 11 , 1 : 10 , 3 : 10 , 4 : 5 } )
261262
262263 def test_get_trace_with_include_status_quo (self ) -> None :
263264 with self .subTest ("Multi-objective: status quo dominates in some trials" ):
@@ -347,9 +348,11 @@ def test_get_trace_with_include_status_quo(self) -> None:
347348 # The last value MUST differ because status quo dominates
348349 # Without status quo, only poor arms contribute (low hypervolume)
349350 # With status quo, excellent values contribute (high hypervolume)
351+ last_without = list (trace_without_sq .values ())[- 1 ]
352+ last_with = list (trace_with_sq .values ())[- 1 ]
350353 self .assertGreater (
351- trace_with_sq [ - 1 ] ,
352- trace_without_sq [ - 1 ] ,
354+ last_with ,
355+ last_without ,
353356 f"Status quo dominates in trial 3, so trace with SQ should be higher. "
354357 f"Without SQ: { trace_without_sq } , With SQ: { trace_with_sq } " ,
355358 )
@@ -418,9 +421,11 @@ def test_get_trace_with_include_status_quo(self) -> None:
418421 # The last value MUST differ because status quo is best
419422 # Without status quo: best in trial 3 is 15.0, cumulative min is 9
420423 # With status quo: best in trial 3 is 5.0, cumulative min is 5
424+ last_without = list (trace_without_sq .values ())[- 1 ]
425+ last_with = list (trace_with_sq .values ())[- 1 ]
421426 self .assertLess (
422- trace_with_sq [ - 1 ] ,
423- trace_without_sq [ - 1 ] ,
427+ last_with ,
428+ last_without ,
424429 f"Status quo is best in trial 3, so trace with SQ should be "
425430 f"lower (minimize). Without SQ: { trace_without_sq } , "
426431 f"With SQ: { trace_with_sq } " ,
@@ -502,19 +507,20 @@ def _make_pref_opt_config(self, profile_name: str) -> PreferenceOptimizationConf
502507 preference_profile_name = profile_name ,
503508 )
504509
505- def _assert_valid_trace (self , trace : list [ float ], expected_len : int ) -> None :
510+ def _assert_valid_trace (self , trace : dict [ int , float ], expected_len : int ) -> None :
506511 """Assert trace has expected length, contains floats, is non-decreasing and has
507512 more than one unique value."""
508513 self .assertEqual (len (trace ), expected_len )
509- for value in trace :
514+ trace_values = list (trace .values ())
515+ for value in trace_values :
510516 self .assertIsInstance (value , float )
511- for i in range (1 , len (trace )):
517+ for i in range (1 , len (trace_values )):
512518 self .assertGreaterEqual (
513- trace [i ],
514- trace [i - 1 ],
519+ trace_values [i ],
520+ trace_values [i - 1 ],
515521 msg = f"Trace not monotonically increasing at index { i } : { trace } " ,
516522 )
517- unique_values = set (trace )
523+ unique_values = set (trace_values )
518524 self .assertGreater (
519525 len (unique_values ),
520526 1 ,
0 commit comments