@@ -161,7 +161,7 @@ def load_ablation_results():
161161 # -- Metric cards --
162162 m1 , m2 , m3 , m4 , m5 = st .columns (5 )
163163 m1 .metric ("Records ingested" , "281M" )
164- m2 .metric ("Datasets" , "3 ( UK-DALE, LCL, SSEN) " )
164+ m2 .metric ("Datasets" , "3" , help = " UK-DALE, LCL, SSEN" )
165165 m3 .metric ("Tests passing" , "212" )
166166 m4 .metric ("GNN accuracy" , "98.33%" )
167167 m5 .metric ("Inference latency" , "16.56 ms" )
@@ -303,6 +303,7 @@ def load_ablation_results():
303303 horizon = c3 .selectbox ("Forecast horizon (intervals)" , [24 , 48 , 96 ], index = 1 )
304304
305305 if st .button ("Generate and evaluate" ):
306+ try :
306307 with st .spinner ("Running hybrid verifier pipeline..." ):
307308 # Generate scenario
308309 np .random .seed (int (time .time ()) % 10000 )
@@ -319,9 +320,15 @@ def load_ablation_results():
319320 # Apply scenario to create forecast
320321 forecast_1d = scenario .apply_to_timeseries (context [:horizon ])
321322
323+ # Ensure forecast covers enough nodes for the verifier
324+ n_eval = len (graph_data .node_type )
325+ eval_input = np .zeros (n_eval )
326+ n_copy = min (len (forecast_1d ), n_eval )
327+ eval_input [:n_copy ] = forecast_1d [:n_copy ]
328+
322329 # Run through hybrid verifier
323330 reward , details = verifier .evaluate (
324- forecast_1d [: graph_data . num_nodes ] ,
331+ eval_input ,
325332 scenario = scenario ,
326333 return_details = True ,
327334 )
@@ -405,7 +412,7 @@ def load_ablation_results():
405412 )
406413
407414 early_exits = breakdown .get ("early_exit_count" , 0 )
408- total_nodes = graph_data .num_nodes
415+ total_nodes = len ( graph_data .node_type )
409416 st .markdown (f"**Early exits:** { early_exits } /{ total_nodes } nodes" )
410417
411418 # -- Expandable details --
@@ -433,6 +440,11 @@ def load_ablation_results():
433440 meta_display ["affected_nodes" ] = dict (list (an .items ())[:10 ])
434441 meta_display ["affected_nodes_truncated" ] = f"...{ len (an )} total"
435442 st .json (meta_display )
443+ except Exception as e :
444+ st .error (f"Anomaly detection failed: { e } " )
445+ import traceback
446+ with st .expander ("Traceback" ):
447+ st .code (traceback .format_exc ())
436448
437449
438450# =========================================================================
@@ -708,6 +720,15 @@ def load_ablation_results():
708720 marker = dict (size = 8 ),
709721 yaxis = "y2" ,
710722 ))
723+ fig_sweep .add_annotation (
724+ text = "Post-fix: voltage auto-detection heuristic prevents<br>early-exit degradation. See debugging narrative below." ,
725+ xref = "paper" , yref = "paper" ,
726+ x = 0.5 , y = 0.5 ,
727+ showarrow = False ,
728+ font = dict (size = 11 , color = "#A0AAB4" ),
729+ bgcolor = "rgba(30,40,50,0.7)" ,
730+ borderpad = 8 ,
731+ )
711732 fig_sweep .update_layout (
712733 template = PLOTLY_TEMPLATE ,
713734 height = 300 ,
@@ -856,13 +877,14 @@ def load_ablation_results():
856877 status .markdown ("Training complete" )
857878
858879 # -- Charts --
859- chart_left , chart_right = st .columns (2 )
880+ row1_left , row1_right = st .columns (2 )
860881
861- with chart_left :
882+ eps_x = list (range (1 , num_episodes + 1 ))
883+
884+ with row1_left :
862885 fig_rew = go .Figure ()
863886 fig_rew .add_trace (go .Scatter (
864- x = list (range (1 , num_episodes + 1 )),
865- y = rewards_history ,
887+ x = eps_x , y = rewards_history ,
866888 mode = "lines+markers" ,
867889 name = "Mean reward" ,
868890 line = dict (color = TEAL , width = 2 ),
@@ -879,11 +901,10 @@ def load_ablation_results():
879901 )
880902 st .plotly_chart (fig_rew , use_container_width = True )
881903
882- with chart_right :
904+ with row1_right :
883905 fig_loss = go .Figure ()
884906 fig_loss .add_trace (go .Scatter (
885- x = list (range (1 , num_episodes + 1 )),
886- y = solver_losses ,
907+ x = eps_x , y = solver_losses ,
887908 mode = "lines+markers" ,
888909 name = "Solver loss" ,
889910 line = dict (color = RED , width = 2 ),
@@ -900,27 +921,51 @@ def load_ablation_results():
900921 )
901922 st .plotly_chart (fig_loss , use_container_width = True )
902923
903- # Scenario distribution
904- if scenario_types :
905- type_counts = {}
906- for t in scenario_types :
907- type_counts [t ] = type_counts .get (t , 0 ) + 1
924+ # Curriculum level chart
925+ row2_left , row2_right = st .columns (2 )
908926
909- fig_dist = go .Figure (go .Bar (
910- x = list (type_counts .keys ()),
911- y = list (type_counts .values ()),
912- marker_color = CHART_COLORS [:len (type_counts )],
927+ with row2_left :
928+ fig_cur = go .Figure ()
929+ fig_cur .add_trace (go .Scatter (
930+ x = eps_x , y = curriculum_levels ,
931+ mode = "lines+markers" ,
932+ name = "Curriculum level" ,
933+ line = dict (color = STEEL , width = 2 ),
934+ marker = dict (size = 6 ),
913935 ))
914- fig_dist .update_layout (
936+ fig_cur .update_layout (
915937 template = PLOTLY_TEMPLATE ,
916- title = "Scenario type distribution " ,
917- height = 250 ,
938+ title = "Proposer difficulty per episode " ,
939+ height = 300 ,
918940 margin = dict (l = 50 , r = 20 , t = 40 , b = 40 ),
919- xaxis_title = "Scenario type " ,
920- yaxis_title = "Count " ,
941+ xaxis_title = "Episode " ,
942+ yaxis_title = "Difficulty " ,
921943 ** DARK_LAYOUT ,
922944 )
923- st .plotly_chart (fig_dist , use_container_width = True )
945+ st .plotly_chart (fig_cur , use_container_width = True )
946+
947+ with row2_right :
948+ # Scenario distribution
949+ if scenario_types :
950+ type_counts = {}
951+ for t in scenario_types :
952+ type_counts [t ] = type_counts .get (t , 0 ) + 1
953+
954+ fig_dist = go .Figure (go .Bar (
955+ x = list (type_counts .keys ()),
956+ y = list (type_counts .values ()),
957+ marker_color = CHART_COLORS [:len (type_counts )],
958+ ))
959+ fig_dist .update_layout (
960+ template = PLOTLY_TEMPLATE ,
961+ title = "Scenario type distribution" ,
962+ height = 300 ,
963+ margin = dict (l = 50 , r = 20 , t = 40 , b = 40 ),
964+ xaxis_title = "Scenario type" ,
965+ yaxis_title = "Count" ,
966+ ** DARK_LAYOUT ,
967+ )
968+ st .plotly_chart (fig_dist , use_container_width = True )
924969
925970 except Exception as e :
926971 st .error (f"Training failed: { e } " )
0 commit comments