hchevva commited on
Commit
d49a735
·
verified ·
1 Parent(s): cc0edce

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +191 -0
app.py CHANGED
@@ -32,6 +32,7 @@ from quread.metrics import (
32
  MetricThresholds,
33
  )
34
  from quread.layout_mapper import parse_layout_csv_text
 
35
 
36
  # --- Qubit cap (configurable) ---
37
  DEFAULT_MAX_QUBITS = 16 # safe default for CPU Spaces; change if you want
@@ -448,6 +449,55 @@ def _ideal_vs_noisy_plot(
448
  return fig
449
 
450
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
451
  # ---------- Styling ----------
452
  CSS = """
453
  #title h1 { font-size: 38px !important; margin-bottom: 4px; letter-spacing: -0.02em; }
@@ -686,6 +736,45 @@ with gr.Blocks(theme=theme, css=CSS, title="Quread.ai — State Vector Studio")
686
  hotspot_detail_md = gr.Markdown()
687
  hotspot_detail_plot = gr.Plot()
688
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
689
  with gr.Tab("Explain"):
690
  with gr.Group(elem_classes=["card"]):
691
  gr.Markdown("<div class='section-title'>Explain (GPT-4o)</div>")
@@ -1079,6 +1168,88 @@ with gr.Blocks(theme=theme, css=CSS, title="Quread.ai — State Vector Studio")
1079
  )
1080
  return _write_tmp("qubit_metrics.csv", to_metrics_csv(metrics))
1081
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1082
  heat_btn.click(
1083
  fn=_heat_and_hotspots_from_current,
1084
  inputs=[
@@ -1121,6 +1292,26 @@ with gr.Blocks(theme=theme, css=CSS, title="Quread.ai — State Vector Studio")
1121
  outputs=[metrics_csv_dl],
1122
  )
1123
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1124
  synopsys_tcl_dl.click(
1125
  fn=_dl_synopsys_tcl,
1126
  inputs=[
 
32
  MetricThresholds,
33
  )
34
  from quread.layout_mapper import parse_layout_csv_text
35
+ from quread.trends import compute_metric_trends
36
 
37
  # --- Qubit cap (configurable) ---
38
  DEFAULT_MAX_QUBITS = 16 # safe default for CPU Spaces; change if you want
 
449
  return fig
450
 
451
 
452
+ def _metric_label(metric_key: str) -> str:
453
+ labels = {
454
+ "composite_risk": "Composite risk",
455
+ "gate_error": "Gate error",
456
+ "readout_error": "Readout error",
457
+ "decoherence_risk": "Decoherence risk",
458
+ "fidelity": "Fidelity",
459
+ "state_fidelity": "State fidelity",
460
+ "process_fidelity": "Process fidelity",
461
+ "coherence_health": "Coherence health",
462
+ }
463
+ return labels.get(metric_key, metric_key.replace("_", " ").title())
464
+
465
+
466
+ def _plot_metric_trends(series, labels, ranking_rows, metric_key, top_k):
467
+ if series.size == 0:
468
+ fig, ax = plt.subplots(figsize=(7, 3))
469
+ ax.set_title("No trend data")
470
+ ax.axis("off")
471
+ fig.tight_layout()
472
+ return fig
473
+
474
+ k = max(1, min(int(top_k), len(ranking_rows)))
475
+ selected_qubits = [int(ranking_rows[i]["qubit"]) for i in range(k)]
476
+ x = np.arange(series.shape[0])
477
+ fig, ax = plt.subplots(figsize=(8, 4))
478
+ for q in selected_qubits:
479
+ ax.plot(x, series[:, q], marker="o", linewidth=2, label=f"q{q}")
480
+
481
+ xticks = labels
482
+ if len(xticks) > 12:
483
+ step = max(1, len(xticks) // 10)
484
+ keep = [idx for idx in range(len(xticks)) if idx % step == 0 or idx == len(xticks) - 1]
485
+ ax.set_xticks(keep)
486
+ ax.set_xticklabels([xticks[i] for i in keep], rotation=35, ha="right")
487
+ else:
488
+ ax.set_xticks(x)
489
+ ax.set_xticklabels(xticks, rotation=35, ha="right")
490
+
491
+ ax.set_ylim(0.0, 1.0)
492
+ ax.set_ylabel(_metric_label(metric_key))
493
+ ax.set_xlabel("Snapshot")
494
+ ax.set_title(f"Temporal drift: top {k} qubits by latest {_metric_label(metric_key).lower()}")
495
+ ax.grid(alpha=0.2, linestyle="--")
496
+ ax.legend(ncols=2, fontsize=8)
497
+ fig.tight_layout()
498
+ return fig
499
+
500
+
501
  # ---------- Styling ----------
502
  CSS = """
503
  #title h1 { font-size: 38px !important; margin-bottom: 4px; letter-spacing: -0.02em; }
 
736
  hotspot_detail_md = gr.Markdown()
737
  hotspot_detail_plot = gr.Plot()
738
 
739
+ with gr.Group(elem_classes=["card"]):
740
+ gr.Markdown("<div class='section-title'>Temporal Drift (Calibration Snapshots)</div>")
741
+ with gr.Row():
742
+ trend_metric = gr.Dropdown(
743
+ choices=[
744
+ "composite_risk",
745
+ "gate_error",
746
+ "readout_error",
747
+ "decoherence_risk",
748
+ "fidelity",
749
+ "state_fidelity",
750
+ "process_fidelity",
751
+ "coherence_health",
752
+ ],
753
+ value="composite_risk",
754
+ label="Trend metric",
755
+ )
756
+ trend_top_k = gr.Slider(1, 32, value=8, step=1, label="Trend lines (top qubits)")
757
+ trend_btn = gr.Button("Analyze drift", variant="secondary")
758
+ with gr.Accordion("Snapshot Input", open=False):
759
+ trend_snapshots_file = gr.File(
760
+ label="Snapshots file (.json/.jsonl/.txt)",
761
+ file_types=[".json", ".jsonl", ".txt"],
762
+ type="filepath",
763
+ )
764
+ trend_snapshots_text = gr.Textbox(
765
+ lines=8,
766
+ label="Snapshots JSON/JSONL (optional)",
767
+ placeholder='[{"timestamp":"2026-02-12","qubits":{"0":{"gate_error":0.012,"readout_error":0.02,"t1_us":82,"t2_us":61,"fidelity":0.991}}}]',
768
+ )
769
+ gr.Markdown("<div class='small-note'>If both are provided, file input is used.</div>")
770
+ trend_status = gr.Markdown("Upload snapshots and click Analyze drift.")
771
+ trend_plot = gr.Plot()
772
+ trend_table = gr.Dataframe(
773
+ headers=["qubit", "latest", "baseline", "delta"],
774
+ interactive=False,
775
+ label="Latest ranking (highest selected metric first)",
776
+ )
777
+
778
  with gr.Tab("Explain"):
779
  with gr.Group(elem_classes=["card"]):
780
  gr.Markdown("<div class='section-title'>Explain (GPT-4o)</div>")
 
1168
  )
1169
  return _write_tmp("qubit_metrics.csv", to_metrics_csv(metrics))
1170
 
1171
+ def _trend_from_snapshots(
1172
+ qc,
1173
+ n_qubits,
1174
+ snapshots_file,
1175
+ snapshots_text,
1176
+ trend_metric_value,
1177
+ trend_top_qubits,
1178
+ activity_w,
1179
+ gate_error_w,
1180
+ readout_error_w,
1181
+ decoherence_w,
1182
+ fidelity_w,
1183
+ warning_thr,
1184
+ critical_thr,
1185
+ ):
1186
+ text = _read_uploaded_text(snapshots_file).strip()
1187
+ if not text:
1188
+ text = str(snapshots_text or "").strip()
1189
+
1190
+ if not text:
1191
+ fig, ax = plt.subplots(figsize=(7, 3))
1192
+ ax.set_title("Temporal drift")
1193
+ ax.text(0.5, 0.5, "Provide calibration snapshots (JSON/JSONL).", ha="center", va="center")
1194
+ ax.axis("off")
1195
+ fig.tight_layout()
1196
+ return fig, "No snapshots provided.", []
1197
+
1198
+ csv_text = to_csv(qc.history)
1199
+ weights, thresholds = _metric_controls_to_models(
1200
+ activity_w,
1201
+ gate_error_w,
1202
+ readout_error_w,
1203
+ decoherence_w,
1204
+ fidelity_w,
1205
+ warning_thr,
1206
+ critical_thr,
1207
+ )
1208
+
1209
+ try:
1210
+ series, labels, ranking, meta = compute_metric_trends(
1211
+ csv_text,
1212
+ int(n_qubits),
1213
+ text,
1214
+ metric=str(trend_metric_value),
1215
+ state_vector=np.asarray(qc.state, dtype=complex),
1216
+ weights=weights,
1217
+ thresholds=thresholds,
1218
+ )
1219
+ except Exception as exc:
1220
+ fig, ax = plt.subplots(figsize=(7, 3))
1221
+ ax.set_title("Temporal drift")
1222
+ ax.text(0.5, 0.5, f"Unable to parse snapshots: {exc}", ha="center", va="center")
1223
+ ax.axis("off")
1224
+ fig.tight_layout()
1225
+ return fig, f"Drift analysis failed: {exc}", []
1226
+
1227
+ fig = _plot_metric_trends(
1228
+ series,
1229
+ labels,
1230
+ ranking,
1231
+ str(meta.get("metric", trend_metric_value)),
1232
+ int(trend_top_qubits),
1233
+ )
1234
+ table_rows = []
1235
+ for row in ranking:
1236
+ table_rows.append(
1237
+ [
1238
+ int(row["qubit"]),
1239
+ round(float(row["latest"]), 6),
1240
+ round(float(row["baseline"]), 6),
1241
+ round(float(row["delta"]), 6),
1242
+ ]
1243
+ )
1244
+ status = (
1245
+ f"Snapshots parsed: {int(meta.get('parsed', 0))}"
1246
+ f" | Skipped: {int(meta.get('skipped', 0))}"
1247
+ f" | Format: {meta.get('format', 'unknown')}"
1248
+ f" | Points: {int(meta.get('points', 0))}"
1249
+ f" | Metric: {meta.get('metric', trend_metric_value)}"
1250
+ )
1251
+ return fig, status, table_rows
1252
+
1253
  heat_btn.click(
1254
  fn=_heat_and_hotspots_from_current,
1255
  inputs=[
 
1292
  outputs=[metrics_csv_dl],
1293
  )
1294
 
1295
+ trend_btn.click(
1296
+ fn=_trend_from_snapshots,
1297
+ inputs=[
1298
+ qc_state,
1299
+ n_qubits,
1300
+ trend_snapshots_file,
1301
+ trend_snapshots_text,
1302
+ trend_metric,
1303
+ trend_top_k,
1304
+ w_activity,
1305
+ w_gate,
1306
+ w_readout,
1307
+ w_decoherence,
1308
+ w_fidelity,
1309
+ thr_warning,
1310
+ thr_critical,
1311
+ ],
1312
+ outputs=[trend_plot, trend_status, trend_table],
1313
+ )
1314
+
1315
  synopsys_tcl_dl.click(
1316
  fn=_dl_synopsys_tcl,
1317
  inputs=[