hchevva commited on
Commit
e603457
·
verified ·
1 Parent(s): 3317675

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +130 -4
app.py CHANGED
@@ -31,6 +31,7 @@ from quread.metrics import (
31
  MetricWeights,
32
  MetricThresholds,
33
  )
 
34
 
35
  # --- Qubit cap (configurable) ---
36
  DEFAULT_MAX_QUBITS = 16 # safe default for CPU Spaces; change if you want
@@ -76,6 +77,51 @@ def _write_tmp(filename: str, content: str) -> str:
76
  return f.name
77
 
78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  def _circuit_hash(history):
80
  return hashlib.sha256(str(history).encode()).hexdigest()
81
 
@@ -238,13 +284,19 @@ def _metric_controls_to_models(
238
  return weights, thresholds
239
 
240
 
241
- def _hotspot_rows(metrics, n_qubits, top_k):
242
  rows = []
243
  n = int(n_qubits)
244
  for q in range(n):
245
  risk = float(metrics["composite_risk"][q])
246
  level = int(metrics["hotspot_level"][q])
247
  status = "critical" if level == 2 else ("warning" if level == 1 else "ok")
 
 
 
 
 
 
248
  rows.append(
249
  [
250
  q,
@@ -258,6 +310,8 @@ def _hotspot_rows(metrics, n_qubits, top_k):
258
  round(float(metrics["coherence_health"][q]), 6),
259
  round(float(metrics["decoherence_risk"][q]), 6),
260
  round(float(metrics["fidelity"][q]), 6),
 
 
261
  ]
262
  )
263
  rows.sort(key=lambda x: x[2], reverse=True)
@@ -265,7 +319,7 @@ def _hotspot_rows(metrics, n_qubits, top_k):
265
  return rows[:k]
266
 
267
 
268
- def _hotspot_detail_markdown(metrics, meta, n_qubits, focus_qubit):
269
  n = int(n_qubits)
270
  if n < 1:
271
  return "No qubits available."
@@ -279,6 +333,10 @@ def _hotspot_detail_markdown(metrics, meta, n_qubits, focus_qubit):
279
  thr_warning = float(getattr(thresholds, "warning", 0.45))
280
  thr_critical = float(getattr(thresholds, "critical", 0.70))
281
  fidelity_backend = str(meta.get("fidelity_backend", "unknown"))
 
 
 
 
282
 
283
  return (
284
  f"### Hotspot Detail: q{q}\n"
@@ -286,6 +344,7 @@ def _hotspot_detail_markdown(metrics, meta, n_qubits, focus_qubit):
286
  f"- Composite risk: **{risk:.6f}**\n"
287
  f"- Thresholds: warning={thr_warning:.2f}, critical={thr_critical:.2f}\n"
288
  f"- Fidelity backend: `{fidelity_backend}`\n"
 
289
  f"- Activity count: {float(metrics['activity_count'][q]):.3f}\n"
290
  f"- Gate error: {float(metrics['gate_error'][q]):.6f}\n"
291
  f"- Readout error: {float(metrics['readout_error'][q]):.6f}\n"
@@ -573,6 +632,13 @@ with gr.Blocks(theme=theme, css=CSS, title="Quread.ai — State Vector Studio")
573
  label="Calibration JSON (optional)",
574
  placeholder='{"qubits":{"0":{"gate_error":0.012,"readout_error":0.02,"t1_us":82,"t2_us":61,"fidelity":0.991}}}',
575
  )
 
 
 
 
 
 
 
576
  with gr.Accordion("Advanced Weights & Thresholds", open=False):
577
  gr.Markdown("<div class='small-note'>Composite risk weights are normalized automatically.</div>")
578
  with gr.Row():
@@ -610,6 +676,8 @@ with gr.Blocks(theme=theme, css=CSS, title="Quread.ai — State Vector Studio")
610
  "coherence_health",
611
  "decoherence_risk",
612
  "fidelity",
 
 
613
  ],
614
  interactive=False,
615
  label="Hotspot ranking (highest composite risk first)",
@@ -756,6 +824,9 @@ with gr.Blocks(theme=theme, css=CSS, title="Quread.ai — State Vector Studio")
756
  def _dl_synopsys_tcl(
757
  qc,
758
  n_qubits,
 
 
 
759
  calibration_text,
760
  activity_w,
761
  gate_error_w,
@@ -783,15 +854,25 @@ with gr.Blocks(theme=theme, css=CSS, title="Quread.ai — State Vector Studio")
783
  weights=weights,
784
  thresholds=thresholds,
785
  )
 
 
 
 
 
 
786
  mapping = build_eda_mapping(
787
  metrics,
788
  cfg=None,
 
789
  )
790
  return _write_tmp("quread_risk_synopsys.tcl", to_synopsys_tcl(mapping))
791
 
792
  def _dl_cadence_skill(
793
  qc,
794
  n_qubits,
 
 
 
795
  calibration_text,
796
  activity_w,
797
  gate_error_w,
@@ -819,9 +900,16 @@ with gr.Blocks(theme=theme, css=CSS, title="Quread.ai — State Vector Studio")
819
  weights=weights,
820
  thresholds=thresholds,
821
  )
 
 
 
 
 
 
822
  mapping = build_eda_mapping(
823
  metrics,
824
  cfg=None,
 
825
  )
826
  return _write_tmp("quread_risk_cadence.il", to_cadence_skill_reliability(mapping))
827
 
@@ -838,6 +926,7 @@ with gr.Blocks(theme=theme, css=CSS, title="Quread.ai — State Vector Studio")
838
  cols,
839
  metric,
840
  render_mode,
 
841
  calibration_text,
842
  activity_w,
843
  gate_error_w,
@@ -864,6 +953,12 @@ with gr.Blocks(theme=theme, css=CSS, title="Quread.ai — State Vector Studio")
864
  threshold_value = None if float(metric_thr) <= 0 else float(metric_thr)
865
  render_choice = str(render_mode or "interactive").strip().lower()
866
  notes = []
 
 
 
 
 
 
867
 
868
  if render_choice == "interactive":
869
  if plotly_available():
@@ -877,6 +972,7 @@ with gr.Blocks(theme=theme, css=CSS, title="Quread.ai — State Vector Studio")
877
  weights=weights,
878
  thresholds=thresholds,
879
  highlight_threshold=threshold_value,
 
880
  )
881
  else:
882
  fig = make_metric_heatmap(
@@ -889,6 +985,7 @@ with gr.Blocks(theme=theme, css=CSS, title="Quread.ai — State Vector Studio")
889
  weights=weights,
890
  thresholds=thresholds,
891
  highlight_threshold=threshold_value,
 
892
  )
893
  notes.append("Plotly unavailable in this runtime; using static heatmap.")
894
  else:
@@ -902,6 +999,7 @@ with gr.Blocks(theme=theme, css=CSS, title="Quread.ai — State Vector Studio")
902
  weights=weights,
903
  thresholds=thresholds,
904
  highlight_threshold=threshold_value,
 
905
  )
906
 
907
  metrics, meta = compute_metrics_from_csv(
@@ -912,8 +1010,23 @@ with gr.Blocks(theme=theme, css=CSS, title="Quread.ai — State Vector Studio")
912
  weights=weights,
913
  thresholds=thresholds,
914
  )
915
- hotspot_rows = _hotspot_rows(metrics, int(n_qubits), int(top_k))
 
 
 
 
 
916
  note = notes
 
 
 
 
 
 
 
 
 
 
917
  skipped = int(meta.get("skipped_rows", 0))
918
  if skipped:
919
  note.append(f"Skipped malformed CSV rows: {skipped}")
@@ -924,7 +1037,13 @@ with gr.Blocks(theme=theme, css=CSS, title="Quread.ai — State Vector Studio")
924
  if fidelity_backend:
925
  note.append(f"Fidelity backend: {fidelity_backend}")
926
  summary = " | ".join(note) if note else "Hotspot ranking updated."
927
- detail_md = _hotspot_detail_markdown(metrics, meta, int(n_qubits), int(focus_qubit))
 
 
 
 
 
 
928
  detail_fig = _hotspot_detail_plot(metrics, meta, int(n_qubits), int(focus_qubit))
929
  return fig, summary, hotspot_rows, detail_md, detail_fig
930
 
@@ -969,6 +1088,7 @@ with gr.Blocks(theme=theme, css=CSS, title="Quread.ai — State Vector Studio")
969
  chip_cols,
970
  heat_metric,
971
  heat_render_mode,
 
972
  calibration_json,
973
  w_activity,
974
  w_gate,
@@ -1006,6 +1126,9 @@ with gr.Blocks(theme=theme, css=CSS, title="Quread.ai — State Vector Studio")
1006
  inputs=[
1007
  qc_state,
1008
  n_qubits,
 
 
 
1009
  calibration_json,
1010
  w_activity,
1011
  w_gate,
@@ -1023,6 +1146,9 @@ with gr.Blocks(theme=theme, css=CSS, title="Quread.ai — State Vector Studio")
1023
  inputs=[
1024
  qc_state,
1025
  n_qubits,
 
 
 
1026
  calibration_json,
1027
  w_activity,
1028
  w_gate,
 
31
  MetricWeights,
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
 
77
  return f.name
78
 
79
 
80
+ def _read_uploaded_text(uploaded_file) -> str:
81
+ if uploaded_file is None:
82
+ return ""
83
+
84
+ if isinstance(uploaded_file, bytes):
85
+ return uploaded_file.decode("utf-8", errors="replace")
86
+ if isinstance(uploaded_file, str):
87
+ path = pathlib.Path(uploaded_file)
88
+ if path.exists():
89
+ return path.read_text(encoding="utf-8", errors="replace")
90
+ return ""
91
+
92
+ if isinstance(uploaded_file, dict):
93
+ raw = uploaded_file.get("data")
94
+ if isinstance(raw, bytes):
95
+ return raw.decode("utf-8", errors="replace")
96
+ maybe_path = uploaded_file.get("name") or uploaded_file.get("path")
97
+ if maybe_path:
98
+ path = pathlib.Path(str(maybe_path))
99
+ if path.exists():
100
+ return path.read_text(encoding="utf-8", errors="replace")
101
+ return ""
102
+
103
+ maybe_path = getattr(uploaded_file, "name", None)
104
+ if maybe_path:
105
+ path = pathlib.Path(str(maybe_path))
106
+ if path.exists():
107
+ return path.read_text(encoding="utf-8", errors="replace")
108
+
109
+ raw = getattr(uploaded_file, "data", None)
110
+ if isinstance(raw, bytes):
111
+ return raw.decode("utf-8", errors="replace")
112
+ return ""
113
+
114
+
115
+ def _resolve_layout_coords(layout_file, n_qubits, rows, cols):
116
+ layout_text = _read_uploaded_text(layout_file)
117
+ return parse_layout_csv_text(
118
+ layout_text,
119
+ int(n_qubits),
120
+ rows=int(rows),
121
+ cols=int(cols),
122
+ )
123
+
124
+
125
  def _circuit_hash(history):
126
  return hashlib.sha256(str(history).encode()).hexdigest()
127
 
 
284
  return weights, thresholds
285
 
286
 
287
+ def _hotspot_rows(metrics, n_qubits, top_k, qubit_coords=None):
288
  rows = []
289
  n = int(n_qubits)
290
  for q in range(n):
291
  risk = float(metrics["composite_risk"][q])
292
  level = int(metrics["hotspot_level"][q])
293
  status = "critical" if level == 2 else ("warning" if level == 1 else "ok")
294
+ layout_row = ""
295
+ layout_col = ""
296
+ if qubit_coords and q in qubit_coords:
297
+ rr, cc = qubit_coords[q]
298
+ layout_row = int(rr)
299
+ layout_col = int(cc)
300
  rows.append(
301
  [
302
  q,
 
310
  round(float(metrics["coherence_health"][q]), 6),
311
  round(float(metrics["decoherence_risk"][q]), 6),
312
  round(float(metrics["fidelity"][q]), 6),
313
+ layout_row,
314
+ layout_col,
315
  ]
316
  )
317
  rows.sort(key=lambda x: x[2], reverse=True)
 
319
  return rows[:k]
320
 
321
 
322
+ def _hotspot_detail_markdown(metrics, meta, n_qubits, focus_qubit, qubit_coords=None):
323
  n = int(n_qubits)
324
  if n < 1:
325
  return "No qubits available."
 
333
  thr_warning = float(getattr(thresholds, "warning", 0.45))
334
  thr_critical = float(getattr(thresholds, "critical", 0.70))
335
  fidelity_backend = str(meta.get("fidelity_backend", "unknown"))
336
+ coord_line = ""
337
+ if qubit_coords and q in qubit_coords:
338
+ rr, cc = qubit_coords[q]
339
+ coord_line = f"- Layout coordinate: row={int(rr)}, col={int(cc)}\n"
340
 
341
  return (
342
  f"### Hotspot Detail: q{q}\n"
 
344
  f"- Composite risk: **{risk:.6f}**\n"
345
  f"- Thresholds: warning={thr_warning:.2f}, critical={thr_critical:.2f}\n"
346
  f"- Fidelity backend: `{fidelity_backend}`\n"
347
+ f"{coord_line}"
348
  f"- Activity count: {float(metrics['activity_count'][q]):.3f}\n"
349
  f"- Gate error: {float(metrics['gate_error'][q]):.6f}\n"
350
  f"- Readout error: {float(metrics['readout_error'][q]):.6f}\n"
 
632
  label="Calibration JSON (optional)",
633
  placeholder='{"qubits":{"0":{"gate_error":0.012,"readout_error":0.02,"t1_us":82,"t2_us":61,"fidelity":0.991}}}',
634
  )
635
+ with gr.Accordion("Physical Layout Mapper", open=False):
636
+ layout_csv_file = gr.File(
637
+ label="Layout CSV (optional): qubit,row,col",
638
+ file_types=[".csv"],
639
+ type="filepath",
640
+ )
641
+ gr.Markdown("<div class='small-note'>Accepted aliases: qubit_id/q/id and row(r/y), col(c/x).</div>")
642
  with gr.Accordion("Advanced Weights & Thresholds", open=False):
643
  gr.Markdown("<div class='small-note'>Composite risk weights are normalized automatically.</div>")
644
  with gr.Row():
 
676
  "coherence_health",
677
  "decoherence_risk",
678
  "fidelity",
679
+ "layout_row",
680
+ "layout_col",
681
  ],
682
  interactive=False,
683
  label="Hotspot ranking (highest composite risk first)",
 
824
  def _dl_synopsys_tcl(
825
  qc,
826
  n_qubits,
827
+ rows,
828
+ cols,
829
+ layout_file,
830
  calibration_text,
831
  activity_w,
832
  gate_error_w,
 
854
  weights=weights,
855
  thresholds=thresholds,
856
  )
857
+ qubit_coords, _layout_meta = _resolve_layout_coords(
858
+ layout_file,
859
+ int(n_qubits),
860
+ int(rows),
861
+ int(cols),
862
+ )
863
  mapping = build_eda_mapping(
864
  metrics,
865
  cfg=None,
866
+ qubit_coords=qubit_coords,
867
  )
868
  return _write_tmp("quread_risk_synopsys.tcl", to_synopsys_tcl(mapping))
869
 
870
  def _dl_cadence_skill(
871
  qc,
872
  n_qubits,
873
+ rows,
874
+ cols,
875
+ layout_file,
876
  calibration_text,
877
  activity_w,
878
  gate_error_w,
 
900
  weights=weights,
901
  thresholds=thresholds,
902
  )
903
+ qubit_coords, _layout_meta = _resolve_layout_coords(
904
+ layout_file,
905
+ int(n_qubits),
906
+ int(rows),
907
+ int(cols),
908
+ )
909
  mapping = build_eda_mapping(
910
  metrics,
911
  cfg=None,
912
+ qubit_coords=qubit_coords,
913
  )
914
  return _write_tmp("quread_risk_cadence.il", to_cadence_skill_reliability(mapping))
915
 
 
926
  cols,
927
  metric,
928
  render_mode,
929
+ layout_file,
930
  calibration_text,
931
  activity_w,
932
  gate_error_w,
 
953
  threshold_value = None if float(metric_thr) <= 0 else float(metric_thr)
954
  render_choice = str(render_mode or "interactive").strip().lower()
955
  notes = []
956
+ qubit_coords, layout_meta = _resolve_layout_coords(
957
+ layout_file,
958
+ int(n_qubits),
959
+ int(rows),
960
+ int(cols),
961
+ )
962
 
963
  if render_choice == "interactive":
964
  if plotly_available():
 
972
  weights=weights,
973
  thresholds=thresholds,
974
  highlight_threshold=threshold_value,
975
+ qubit_coords=qubit_coords,
976
  )
977
  else:
978
  fig = make_metric_heatmap(
 
985
  weights=weights,
986
  thresholds=thresholds,
987
  highlight_threshold=threshold_value,
988
+ qubit_coords=qubit_coords,
989
  )
990
  notes.append("Plotly unavailable in this runtime; using static heatmap.")
991
  else:
 
999
  weights=weights,
1000
  thresholds=thresholds,
1001
  highlight_threshold=threshold_value,
1002
+ qubit_coords=qubit_coords,
1003
  )
1004
 
1005
  metrics, meta = compute_metrics_from_csv(
 
1010
  weights=weights,
1011
  thresholds=thresholds,
1012
  )
1013
+ hotspot_rows = _hotspot_rows(
1014
+ metrics,
1015
+ int(n_qubits),
1016
+ int(top_k),
1017
+ qubit_coords=qubit_coords,
1018
+ )
1019
  note = notes
1020
+ if layout_meta.get("source") == "uploaded":
1021
+ note.append(
1022
+ "Layout map uploaded: "
1023
+ f"mapped={int(layout_meta.get('mapped', 0))}, "
1024
+ f"fallback={int(layout_meta.get('fallback', 0))}, "
1025
+ f"skipped={int(layout_meta.get('skipped', 0))}, "
1026
+ f"duplicates={int(layout_meta.get('duplicates', 0))}"
1027
+ )
1028
+ else:
1029
+ note.append("Layout map: using default row-major mapping.")
1030
  skipped = int(meta.get("skipped_rows", 0))
1031
  if skipped:
1032
  note.append(f"Skipped malformed CSV rows: {skipped}")
 
1037
  if fidelity_backend:
1038
  note.append(f"Fidelity backend: {fidelity_backend}")
1039
  summary = " | ".join(note) if note else "Hotspot ranking updated."
1040
+ detail_md = _hotspot_detail_markdown(
1041
+ metrics,
1042
+ meta,
1043
+ int(n_qubits),
1044
+ int(focus_qubit),
1045
+ qubit_coords=qubit_coords,
1046
+ )
1047
  detail_fig = _hotspot_detail_plot(metrics, meta, int(n_qubits), int(focus_qubit))
1048
  return fig, summary, hotspot_rows, detail_md, detail_fig
1049
 
 
1088
  chip_cols,
1089
  heat_metric,
1090
  heat_render_mode,
1091
+ layout_csv_file,
1092
  calibration_json,
1093
  w_activity,
1094
  w_gate,
 
1126
  inputs=[
1127
  qc_state,
1128
  n_qubits,
1129
+ chip_rows,
1130
+ chip_cols,
1131
+ layout_csv_file,
1132
  calibration_json,
1133
  w_activity,
1134
  w_gate,
 
1146
  inputs=[
1147
  qc_state,
1148
  n_qubits,
1149
+ chip_rows,
1150
+ chip_cols,
1151
+ layout_csv_file,
1152
  calibration_json,
1153
  w_activity,
1154
  w_gate,