@@ -13,7 +13,10 @@ def make_metrics_for_main(surr_names, n_timesteps=4, n_quantities=3):
1313 for i , name in enumerate (surr_names ):
1414 metrics [name ] = {
1515 "timesteps" : np .zeros (n_timesteps ),
16- "accuracy" : {"absolute_errors" : np .zeros ((1 , n_timesteps , n_quantities ))},
16+ "accuracy" : {
17+ "absolute_errors" : np .zeros ((1 , n_timesteps , n_quantities )),
18+ "absolute_errors_log" : np .zeros ((1 , n_timesteps , n_quantities )),
19+ },
1720 "n_params" : 123 + i ,
1821 }
1922 return metrics
@@ -47,7 +50,10 @@ def make_metrics_for_dynamic(surr_names, n_timesteps=4, n_quantities=2):
4750 metrics = {}
4851 for name in surr_names :
4952 metrics [name ] = {
50- "accuracy" : {"absolute_errors" : np .zeros ((1 , n_timesteps , n_quantities ))},
53+ "accuracy" : {
54+ "absolute_errors" : np .zeros ((1 , n_timesteps , n_quantities )),
55+ "absolute_errors_log" : np .zeros ((1 , n_timesteps , n_quantities )),
56+ },
5157 "gradients" : {
5258 "gradients" : np .ones ((1 , n_timesteps , n_quantities )),
5359 "avg_correlation" : 0.5 ,
@@ -80,6 +86,75 @@ def make_metrics_for_generalization(surr_names):
8086 return base
8187
8288
89+ def make_metrics_for_interpolation (surr_names ):
90+ base = {}
91+ for name in surr_names :
92+ base [name ] = {
93+ "interpolation" : {
94+ "intervals" : np .array ([1 , 2 , 4 ]),
95+ "model_errors" : np .array ([0.1 , 0.2 , 0.25 ]),
96+ }
97+ }
98+ return base
99+
100+
101+ def make_metrics_for_extrapolation (surr_names , timesteps_len = 5 ):
102+ base = {}
103+ for name in surr_names :
104+ base [name ] = {
105+ "extrapolation" : {
106+ "cutoffs" : np .array ([2 , timesteps_len ]),
107+ "model_errors" : np .array ([0.3 , 0.22 ]),
108+ }
109+ }
110+ return base
111+
112+
113+ def make_metrics_for_sparse (surr_names ):
114+ base = {}
115+ for name in surr_names :
116+ base [name ] = {
117+ "sparse" : {
118+ "n_train_samples" : np .array ([100 , 50 , 25 ]),
119+ "model_errors" : np .array ([0.15 , 0.2 , 0.28 ]),
120+ }
121+ }
122+ return base
123+
124+
125+ def make_metrics_for_batchsize (surr_names ):
126+ base = {}
127+ for name in surr_names :
128+ base [name ] = {
129+ "batch_size" : {
130+ "batch_elements" : np .array ([32 , 64 , 128 ]),
131+ "model_errors" : np .array ([0.12 , 0.11 , 0.13 ]),
132+ }
133+ }
134+ return base
135+
136+
137+ def make_metrics_for_UQ (surr_names , timesteps ):
138+ base = {}
139+ T = len (timesteps )
140+ for name in surr_names :
141+ uq_std = np .full ((1 , T , 1 ), 0.25 )
142+ uq_err = np .full ((1 , T , 1 ), 0.2 )
143+ base [name ] = {
144+ "timesteps" : np .array (timesteps ),
145+ "accuracy" : {"absolute_errors_log" : np .full ((1 , T , 1 ), 0.18 )},
146+ "UQ" : {
147+ "pred_uncertainty_log" : uq_std ,
148+ "absolute_errors_log" : uq_err ,
149+ "axis_max" : 1 ,
150+ "max_counts" : 1 ,
151+ "correlation_metrics_log" : 0.4 ,
152+ "targets_log" : np .zeros ((1 , T , 1 )),
153+ },
154+ }
155+ return base
156+
157+
83158@pytest .fixture (autouse = True )
84159def stub_plots_and_io (monkeypatch ):
85160 calls = []
@@ -90,12 +165,13 @@ def stub_plots_and_io(monkeypatch):
90165 "plot_generalization_error_comparison" ,
91166 "plot_uncertainty_over_time_comparison" ,
92167 "plot_comparative_error_correlation_heatmaps" ,
168+ "plot_mean_deltadex_over_time_main_vs_ensemble" ,
169+ "plot_catastrophic_detection_curves" ,
170+ "plot_errors_over_time" ,
93171 "plot_error_distribution_comparative" ,
94- "plot_uncertainty_confidence" ,
95172 "plot_loss_comparison" ,
96173 "plot_loss_comparison_equal" ,
97174 "plot_loss_comparison_train_duration" ,
98- "plot_relative_errors" ,
99175 "plot_error_distribution_comparative" ,
100176 ]:
101177 monkeypatch .setattr (bf , fn , lambda * a , _n = fn , ** k : calls .append ((_n , a , k )))
@@ -146,22 +222,35 @@ def load(self, *args, **kw):
146222 ]
147223
148224
149- def test_compare_relative_errors (stub_plots_and_io , cfg ):
225+ def test_compare_errors (stub_plots_and_io , cfg ):
150226 timesteps = [0.0 , 1.0 , 2.0 ]
151227 metrics = make_metrics_for_relative (["M1" ], timesteps )
152- bf .compare_relative_errors (metrics , cfg )
228+ # also include deltadex branch to verify both paths
229+ metrics ["M1" ]["accuracy" ]["absolute_errors_log" ] = np .arange (
230+ len (timesteps )
231+ ).reshape (1 , len (timesteps ), 1 )
232+
233+ bf .compare_errors (metrics , cfg )
153234 # mean and median come from np.mean/median over rel errors
154235 mean_err = np .mean (metrics ["M1" ]["accuracy" ]["relative_errors" ], axis = (0 , 2 ))
155236 median_err = np .median (metrics ["M1" ]["accuracy" ]["relative_errors" ], axis = (0 , 2 ))
156- # first call to plot_relative_errors
237+ # first call to plot_errors_over_time (relative)
157238 _n , args , kw = stub_plots_and_io [0 ]
158- assert _n == "plot_relative_errors "
239+ assert _n == "plot_errors_over_time "
159240 # args = ( mean_dict, median_dict, timesteps, cfg )
160241 assert pytest .approx (list (args [0 ].values ())[0 ]) == mean_err
161242 assert pytest .approx (list (args [1 ].values ())[0 ]) == median_err
162243 assert np .all (args [2 ] == timesteps )
244+ assert kw .get ("mode" ) == "relative"
163245 # second call
164246 assert stub_plots_and_io [1 ][0 ] == "plot_error_distribution_comparative"
247+ assert stub_plots_and_io [1 ][2 ].get ("mode" ) == "relative"
248+
249+ # third and fourth calls should be for Δdex branch
250+ assert stub_plots_and_io [2 ][0 ] == "plot_errors_over_time"
251+ assert stub_plots_and_io [2 ][2 ].get ("mode" ) == "deltadex"
252+ assert stub_plots_and_io [3 ][0 ] == "plot_error_distribution_comparative"
253+ assert stub_plots_and_io [3 ][2 ].get ("mode" ) == "deltadex"
165254
166255
167256def test_compare_inference_time (stub_plots_and_io , cfg ):
@@ -197,38 +286,112 @@ def test_compare_gradients(stub_plots_and_io, cfg):
197286 assert kw .get ("show_title" , False ) is True
198287
199288
200- def test_compare_UQ_and_confidence (stub_plots_and_io , cfg , monkeypatch ):
201- base = make_metrics_for_generalization (["M1" ])
202- # ADD a dummy timesteps array
203- base ["M1" ]["timesteps" ] = np .array ([0.0 , 1.0 ])
289+ def test_compare_interpolation (stub_plots_and_io , cfg ):
290+ m = make_metrics_for_interpolation (["M1" , "M2" ])
291+ bf .compare_interpolation (m , cfg )
292+ name , args , kw = stub_plots_and_io [0 ]
293+ assert name == "plot_generalization_error_comparison"
294+ surrogates , intervals , model_errors , xlabel , filename , conf = args
295+ assert surrogates == ["M1" , "M2" ]
296+ assert xlabel == "Interpolation Interval"
297+ assert filename == "errors_interpolation.png"
298+ assert all (isinstance (arr , np .ndarray ) for arr in intervals )
299+ assert all (isinstance (arr , np .ndarray ) for arr in model_errors )
300+ assert conf is cfg
301+ assert kw .get ("show_title" , False ) is True
204302
205- # stub out plot_uncertainty_confidence to return known scores
206- monkeypatch .setattr (bf , "plot_uncertainty_confidence" , lambda * a , ** k : {"M1" : 0.42 })
207303
208- bf .compare_UQ (base , cfg )
304+ def test_compare_extrapolation (stub_plots_and_io , cfg ):
305+ m = make_metrics_for_extrapolation (["M1" ])
306+ bf .compare_extrapolation (m , cfg )
307+ name , args , kw = stub_plots_and_io [0 ]
308+ assert name == "plot_generalization_error_comparison"
309+ surrogates , cutoffs , model_errors , xlabel , filename , conf = args
310+ assert surrogates == ["M1" ]
311+ assert xlabel == "Extrapolation Cutoff"
312+ assert filename == "errors_extrapolation.png"
313+ assert isinstance (cutoffs [0 ], np .ndarray )
314+ assert isinstance (model_errors [0 ], np .ndarray )
315+ assert conf is cfg
316+
209317
210- # after compare_UQ, confidence_scores should exist in metrics
211- assert base ["M1" ]["UQ" ]["confidence_scores" ] == 0.42
318+ def test_compare_sparse (stub_plots_and_io , cfg ):
319+ m = make_metrics_for_sparse (["M1" ])
320+ bf .compare_sparse (m , cfg )
321+ name , args , kw = stub_plots_and_io [0 ]
322+ assert name == "plot_generalization_error_comparison"
323+ surrogates , n_train_samples , model_errors , xlabel , filename , conf = args
324+ assert surrogates == ["M1" ]
325+ assert xlabel == "Number of Training Samples"
326+ assert filename == "errors_sparse.png"
327+ assert isinstance (n_train_samples [0 ], np .ndarray )
328+ assert isinstance (model_errors [0 ], np .ndarray )
329+ assert conf is cfg
330+
331+
332+ def test_compare_batchsize (stub_plots_and_io , cfg ):
333+ m = make_metrics_for_batchsize (["M1" ])
334+ bf .compare_batchsize (m , cfg )
335+ name , args , kw = stub_plots_and_io [0 ]
336+ assert name == "plot_generalization_error_comparison"
337+ surrogates , batch_elements , model_errors , xlabel , filename , conf = args
338+ assert surrogates == ["M1" ]
339+ assert xlabel == "Batch Size"
340+ assert filename == "errors_batch_size.png"
341+ assert isinstance (batch_elements [0 ], np .ndarray )
342+ assert isinstance (model_errors [0 ], np .ndarray )
343+ assert conf is cfg
344+
345+
346+ def test_compare_UQ (stub_plots_and_io , cfg ):
347+ timesteps = [0.0 , 1.0 , 2.0 ]
348+ m = make_metrics_for_UQ (["M1" ], timesteps )
349+ bf .compare_UQ (m , cfg )
350+ names = [c [0 ] for c in stub_plots_and_io ]
351+ assert names [:4 ] == [
352+ "plot_mean_deltadex_over_time_main_vs_ensemble" ,
353+ "plot_uncertainty_over_time_comparison" ,
354+ "plot_comparative_error_correlation_heatmaps" ,
355+ "plot_catastrophic_detection_curves" ,
356+ ]
212357
213358
214359def test_tabular_comparison_creates_files (tmp_path , stub_plots_and_io , monkeypatch ):
215360 metrics = {
216361 "M1" : {
217362 "accuracy" : {
218- "mean_squared_error" : 0.1 ,
219- "mean_absolute_error" : 0.2 ,
363+ "root_mean_squared_error_real" : 0.1 ,
364+ "mean_absolute_error_real" : 0.2 ,
365+ "median_absolute_error_real" : 0.15 ,
366+ "percentile_absolute_error_real" : 0.25 ,
367+ "root_mean_squared_error_log" : 0.05 ,
368+ "mean_absolute_error_log" : 0.04 ,
369+ "median_absolute_error_log" : 0.035 ,
370+ "percentile_absolute_error_log" : 0.06 ,
220371 "mean_relative_error" : 0.3 ,
372+ "median_relative_error" : 0.25 ,
373+ "percentile_relative_error" : 0.35 ,
221374 "main_model_epochs" : 4 ,
222375 "main_model_training_time" : 7.0 ,
376+ "error_percentile" : 99 ,
223377 }
224378 },
225379 "M2" : {
226380 "accuracy" : {
227- "mean_squared_error" : 0.01 ,
228- "mean_absolute_error" : 0.02 ,
229- "mean_relative_error" : 0.03 ,
381+ "root_mean_squared_error_real" : 0.08 ,
382+ "mean_absolute_error_real" : 0.18 ,
383+ "median_absolute_error_real" : 0.14 ,
384+ "percentile_absolute_error_real" : 0.22 ,
385+ "root_mean_squared_error_log" : 0.04 ,
386+ "mean_absolute_error_log" : 0.03 ,
387+ "median_absolute_error_log" : 0.028 ,
388+ "percentile_absolute_error_log" : 0.05 ,
389+ "mean_relative_error" : 0.25 ,
390+ "median_relative_error" : 0.2 ,
391+ "percentile_relative_error" : 0.3 ,
230392 "main_model_epochs" : 5 ,
231393 "main_model_training_time" : 3.0 ,
394+ "error_percentile" : 99 ,
232395 }
233396 },
234397 }
@@ -244,6 +407,7 @@ def test_tabular_comparison_creates_files(tmp_path, stub_plots_and_io, monkeypat
244407 "sparse" : {"enabled" : False },
245408 "batch_scaling" : {"enabled" : False },
246409 "verbose" : False ,
410+ "iterative" : False ,
247411 }
248412
249413 # run inside tmp_path
0 commit comments