hchevva commited on
Commit
5498238
·
verified ·
1 Parent(s): 89e6562

Upload 4 files

Browse files
tests/test_app_flows.py CHANGED
@@ -122,8 +122,53 @@ import app
122
  from quread.engine import QuantumStateVector
123
  from quread.def_translator import DEFGridConfig, build_def_blockages, to_def_blockages_fragment
124
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
  class AppFlowsTest(unittest.TestCase):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  def test_qubit_count_change_reinitializes_simulator(self):
128
  qc, last_counts, selected_gate, _target, _control, _cnot_target, status = app._on_qubit_count_change(3)
129
 
@@ -237,6 +282,34 @@ class AppFlowsTest(unittest.TestCase):
237
  self.assertTrue(hasattr(fig, "axes"))
238
  self.assertGreaterEqual(len(fig.axes), 1)
239
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
  def test_def_export_returns_fragment_file(self):
241
  qc = QuantumStateVector(2)
242
  qc.apply_single("H", target=0)
@@ -258,8 +331,7 @@ class AppFlowsTest(unittest.TestCase):
258
  0.15,
259
  0.45,
260
  0.70,
261
- "composite_risk",
262
- "composite_risk",
263
  "0",
264
  "0",
265
  "40",
@@ -298,8 +370,7 @@ class AppFlowsTest(unittest.TestCase):
298
  0.15,
299
  0.45,
300
  0.70,
301
- "composite_risk",
302
- "composite_risk",
303
  "0",
304
  "0",
305
  "40",
@@ -346,8 +417,7 @@ class AppFlowsTest(unittest.TestCase):
346
  0.15,
347
  0.45,
348
  0.70,
349
- "composite_risk",
350
- "composite_risk",
351
  "0",
352
  "0",
353
  "40",
@@ -381,8 +451,7 @@ class AppFlowsTest(unittest.TestCase):
381
  0.15,
382
  0.45,
383
  0.70,
384
- "composite_risk",
385
- "composite_risk",
386
  "0",
387
  "0",
388
  "-1",
 
122
  from quread.engine import QuantumStateVector
123
  from quread.def_translator import DEFGridConfig, build_def_blockages, to_def_blockages_fragment
124
 
125
+ DEFAULT_SEVERITY_ARGS = (
126
+ "linear",
127
+ "composite_risk",
128
+ 0.45,
129
+ 0.70,
130
+ 67.0,
131
+ 90.0,
132
+ 0.25,
133
+ 0.20,
134
+ 0.15,
135
+ 0.25,
136
+ 0.15,
137
+ )
138
+
139
 
140
  class AppFlowsTest(unittest.TestCase):
141
+ def test_apply_selected_gate_recovers_from_missing_qc_state(self):
142
+ qc, last_counts, status = app.apply_selected_gate(None, None, "H", 0, 2)
143
+
144
+ self.assertIsNotNone(qc)
145
+ self.assertEqual(qc.n_qubits, 2)
146
+ self.assertEqual(len(qc.history), 1)
147
+ self.assertIsNone(last_counts)
148
+ self.assertIn("Applied H on q0", status)
149
+
150
+ def test_metrics_pipeline_recovers_from_missing_qc_state(self):
151
+ metrics, meta, qubit_coords, layout_meta = app._current_metrics_and_layout(
152
+ None,
153
+ 2,
154
+ 2,
155
+ 2,
156
+ None,
157
+ "",
158
+ 0.25,
159
+ 0.20,
160
+ 0.15,
161
+ 0.25,
162
+ 0.15,
163
+ 0.45,
164
+ 0.70,
165
+ )
166
+
167
+ self.assertIn("composite_risk", metrics)
168
+ self.assertEqual(len(metrics["composite_risk"]), 2)
169
+ self.assertEqual(qubit_coords[0], (0, 0))
170
+ self.assertEqual(layout_meta["source"], "default")
171
+
172
  def test_qubit_count_change_reinitializes_simulator(self):
173
  qc, last_counts, selected_gate, _target, _control, _cnot_target, status = app._on_qubit_count_change(3)
174
 
 
282
  self.assertTrue(hasattr(fig, "axes"))
283
  self.assertGreaterEqual(len(fig.axes), 1)
284
 
285
+ def test_severity_csv_export_returns_file(self):
286
+ qc = QuantumStateVector(2)
287
+ path = app._dl_severity_csv(
288
+ qc,
289
+ 2,
290
+ 2,
291
+ 2,
292
+ None,
293
+ "",
294
+ 0.25,
295
+ 0.20,
296
+ 0.15,
297
+ 0.25,
298
+ 0.15,
299
+ 0.45,
300
+ 0.70,
301
+ *DEFAULT_SEVERITY_ARGS,
302
+ )
303
+ try:
304
+ text = pathlib.Path(path).read_text(encoding="utf-8")
305
+ self.assertIn("severity_mode", text.splitlines()[0])
306
+ self.assertIn("pnr_cost", text.splitlines()[0])
307
+ finally:
308
+ try:
309
+ os.remove(path)
310
+ except FileNotFoundError:
311
+ pass
312
+
313
  def test_def_export_returns_fragment_file(self):
314
  qc = QuantumStateVector(2)
315
  qc.apply_single("H", target=0)
 
331
  0.15,
332
  0.45,
333
  0.70,
334
+ *DEFAULT_SEVERITY_ARGS,
 
335
  "0",
336
  "0",
337
  "40",
 
370
  0.15,
371
  0.45,
372
  0.70,
373
+ *DEFAULT_SEVERITY_ARGS,
 
374
  "0",
375
  "0",
376
  "40",
 
417
  0.15,
418
  0.45,
419
  0.70,
420
+ *DEFAULT_SEVERITY_ARGS,
 
421
  "0",
422
  "0",
423
  "40",
 
451
  0.15,
452
  0.45,
453
  0.70,
454
+ *DEFAULT_SEVERITY_ARGS,
 
455
  "0",
456
  "0",
457
  "-1",
tests/test_eda_translator.py CHANGED
@@ -9,6 +9,7 @@ class EDATranslatorTest(unittest.TestCase):
9
  def test_mapping_sorted_by_risk_and_contains_fields(self):
10
  metrics = {
11
  "composite_risk": np.array([0.25, 0.82, 0.51], dtype=float),
 
12
  "gate_error": np.array([0.01, 0.03, 0.02], dtype=float),
13
  "readout_error": np.array([0.02, 0.04, 0.03], dtype=float),
14
  "decoherence_risk": np.array([0.2, 0.7, 0.4], dtype=float),
@@ -20,6 +21,9 @@ class EDATranslatorTest(unittest.TestCase):
20
  self.assertEqual(rows[0]["tier"], "CRITICAL")
21
  self.assertIn("timing_derate", rows[0])
22
  self.assertIn("guardband_mv", rows[0])
 
 
 
23
  self.assertIsNone(rows[0]["layout_row"])
24
  self.assertIsNone(rows[0]["layout_col"])
25
  q2 = next(r for r in rows if int(r["qubit"]) == 2)
@@ -29,6 +33,7 @@ class EDATranslatorTest(unittest.TestCase):
29
  def test_export_generates_nonempty_scripts(self):
30
  metrics = {
31
  "composite_risk": np.array([0.2, 0.6], dtype=float),
 
32
  "gate_error": np.array([0.01, 0.02], dtype=float),
33
  "readout_error": np.array([0.02, 0.03], dtype=float),
34
  "decoherence_risk": np.array([0.2, 0.5], dtype=float),
@@ -40,11 +45,14 @@ class EDATranslatorTest(unittest.TestCase):
40
 
41
  self.assertIn("Generated by Quread", tcl)
42
  self.assertIn("quread_q1_risk", tcl)
 
 
43
  self.assertIn("set quread_q1_row 0", tcl)
44
  self.assertIn("set quread_q1_col 1", tcl)
45
  self.assertIn("qureadRiskRows", skill)
46
  self.assertIn('list("q1"', skill)
47
- self.assertIn(' 0 1 "MEDIUM")', skill)
 
48
 
49
 
50
  if __name__ == "__main__":
 
9
  def test_mapping_sorted_by_risk_and_contains_fields(self):
10
  metrics = {
11
  "composite_risk": np.array([0.25, 0.82, 0.51], dtype=float),
12
+ "activity_norm": np.array([0.25, 0.82, 0.51], dtype=float),
13
  "gate_error": np.array([0.01, 0.03, 0.02], dtype=float),
14
  "readout_error": np.array([0.02, 0.04, 0.03], dtype=float),
15
  "decoherence_risk": np.array([0.2, 0.7, 0.4], dtype=float),
 
21
  self.assertEqual(rows[0]["tier"], "CRITICAL")
22
  self.assertIn("timing_derate", rows[0])
23
  self.assertIn("guardband_mv", rows[0])
24
+ self.assertIn("severity_score", rows[0])
25
+ self.assertIn("pnr_cost", rows[0])
26
+ self.assertIn("density_cap", rows[0])
27
  self.assertIsNone(rows[0]["layout_row"])
28
  self.assertIsNone(rows[0]["layout_col"])
29
  q2 = next(r for r in rows if int(r["qubit"]) == 2)
 
33
  def test_export_generates_nonempty_scripts(self):
34
  metrics = {
35
  "composite_risk": np.array([0.2, 0.6], dtype=float),
36
+ "activity_norm": np.array([0.2, 0.6], dtype=float),
37
  "gate_error": np.array([0.01, 0.02], dtype=float),
38
  "readout_error": np.array([0.02, 0.03], dtype=float),
39
  "decoherence_risk": np.array([0.2, 0.5], dtype=float),
 
45
 
46
  self.assertIn("Generated by Quread", tcl)
47
  self.assertIn("quread_q1_risk", tcl)
48
+ self.assertIn("quread_q1_pnr_cost", tcl)
49
+ self.assertIn("quread_q1_density_cap", tcl)
50
  self.assertIn("set quread_q1_row 0", tcl)
51
  self.assertIn("set quread_q1_col 1", tcl)
52
  self.assertIn("qureadRiskRows", skill)
53
  self.assertIn('list("q1"', skill)
54
+ self.assertIn(' 0 1 "MEDIUM"', skill)
55
+ self.assertIn('"composite_risk" "linear"', skill)
56
 
57
 
58
  if __name__ == "__main__":
tests/test_eda_view.py CHANGED
@@ -15,6 +15,12 @@ class EDAViewParserTest(unittest.TestCase):
15
  "set quread_q1_tier CRITICAL",
16
  "set quread_q1_timing_derate 1.12",
17
  "set quread_q1_guardband_mv 41.0",
 
 
 
 
 
 
18
  "set quread_q1_row 0",
19
  "set quread_q1_col 1",
20
  "",
@@ -34,12 +40,14 @@ class EDAViewParserTest(unittest.TestCase):
34
  self.assertEqual(rows[0]["tier"], "CRITICAL")
35
  self.assertEqual(rows[0]["layout_row"], 0)
36
  self.assertEqual(rows[0]["layout_col"], 1)
 
 
37
 
38
  def test_parse_cadence_skill_rows(self):
39
  text = "\n".join(
40
  [
41
- 'qureadRiskRows = cons(list("q0" 0.200000 "OK" 1.030000 14.000 1 2 "LOW") qureadRiskRows)',
42
- 'qureadRiskRows = cons(list("q2" 0.910000 "CRITICAL" 1.140000 55.000 2 1 "HIGH") qureadRiskRows)',
43
  ]
44
  )
45
  rows, meta = parse_eda_text(text, "cadence_skill")
@@ -49,6 +57,8 @@ class EDAViewParserTest(unittest.TestCase):
49
  self.assertEqual(rows[0]["route_priority"], "HIGH")
50
  self.assertEqual(rows[0]["layout_row"], 2)
51
  self.assertEqual(rows[0]["layout_col"], 1)
 
 
52
 
53
  def test_auto_detect_prefers_recognized_format(self):
54
  syn_text = "set quread_q0_risk 0.5"
 
15
  "set quread_q1_tier CRITICAL",
16
  "set quread_q1_timing_derate 1.12",
17
  "set quread_q1_guardband_mv 41.0",
18
+ "set quread_q1_severity_score 0.82",
19
+ "set quread_q1_severity_percentile 100.0",
20
+ "set quread_q1_pnr_cost 82.0",
21
+ "set quread_q1_density_cap 50.8",
22
+ "set quread_q1_source_metric composite_risk",
23
+ "set quread_q1_severity_mode linear",
24
  "set quread_q1_row 0",
25
  "set quread_q1_col 1",
26
  "",
 
40
  self.assertEqual(rows[0]["tier"], "CRITICAL")
41
  self.assertEqual(rows[0]["layout_row"], 0)
42
  self.assertEqual(rows[0]["layout_col"], 1)
43
+ self.assertAlmostEqual(rows[0]["severity_score"], 0.82, places=6)
44
+ self.assertAlmostEqual(rows[0]["pnr_cost"], 82.0, places=6)
45
 
46
  def test_parse_cadence_skill_rows(self):
47
  text = "\n".join(
48
  [
49
+ 'qureadRiskRows = cons(list("q0" 0.200000 "OK" 1.030000 14.000 1 2 "LOW" 0.200000 0.000000 20.000000 88.000000 "composite_risk" "linear") qureadRiskRows)',
50
+ 'qureadRiskRows = cons(list("q2" 0.910000 "CRITICAL" 1.140000 55.000 2 1 "HIGH" 0.950000 100.000000 95.000000 43.000000 "weighted_blend" "pnr_cost") qureadRiskRows)',
51
  ]
52
  )
53
  rows, meta = parse_eda_text(text, "cadence_skill")
 
57
  self.assertEqual(rows[0]["route_priority"], "HIGH")
58
  self.assertEqual(rows[0]["layout_row"], 2)
59
  self.assertEqual(rows[0]["layout_col"], 1)
60
+ self.assertAlmostEqual(rows[0]["pnr_cost"], 95.0, places=6)
61
+ self.assertEqual(rows[0]["severity_mode"], "pnr_cost")
62
 
63
  def test_auto_detect_prefers_recognized_format(self):
64
  syn_text = "set quread_q0_risk 0.5"
tests/test_severity_mapper.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import unittest
2
+
3
+ import numpy as np
4
+
5
+ from quread.severity_mapper import SeverityConfig, SeverityThresholds, SeverityWeights, compute_severity_rows, severity_rows_to_csv
6
+
7
+
8
+ class SeverityMapperTest(unittest.TestCase):
9
+ def _metrics(self):
10
+ return {
11
+ "activity_count": np.array([1.0, 4.0, 2.0], dtype=float),
12
+ "activity_norm": np.array([0.25, 1.0, 0.5], dtype=float),
13
+ "gate_error": np.array([0.02, 0.75, 0.30], dtype=float),
14
+ "readout_error": np.array([0.03, 0.40, 0.08], dtype=float),
15
+ "coherence_health": np.array([0.95, 0.30, 0.70], dtype=float),
16
+ "decoherence_risk": np.array([0.10, 0.80, 0.35], dtype=float),
17
+ "fidelity": np.array([0.98, 0.50, 0.90], dtype=float),
18
+ "state_fidelity": np.array([0.99, 0.55, 0.92], dtype=float),
19
+ "process_fidelity": np.array([0.98, 0.60, 0.91], dtype=float),
20
+ "composite_risk": np.array([0.18, 0.86, 0.41], dtype=float),
21
+ }
22
+
23
+ def test_linear_mode_uses_selected_heatmap_metric(self):
24
+ rows = compute_severity_rows(
25
+ self._metrics(),
26
+ cfg=SeverityConfig(mode="linear", source_metric="gate_error"),
27
+ qubit_coords={0: (0, 0), 1: (0, 1), 2: (1, 0)},
28
+ )
29
+ self.assertEqual(rows[0]["qubit"], 1)
30
+ self.assertEqual(rows[0]["severity_band"], "CRITICAL")
31
+ self.assertAlmostEqual(rows[0]["severity_score"], 0.75, places=6)
32
+ self.assertEqual(rows[0]["source_metric"], "gate_error")
33
+
34
+ def test_bucket_mode_quantizes_to_three_levels(self):
35
+ rows = compute_severity_rows(
36
+ self._metrics(),
37
+ cfg=SeverityConfig(
38
+ mode="bucket",
39
+ source_metric="composite_risk",
40
+ thresholds=SeverityThresholds(warning=0.4, critical=0.7),
41
+ ),
42
+ )
43
+ values = {int(r["qubit"]): float(r["severity_score"]) for r in rows}
44
+ self.assertEqual(values[0], 0.0)
45
+ self.assertEqual(values[1], 1.0)
46
+ self.assertEqual(values[2], 0.5)
47
+
48
+ def test_percentile_mode_uses_current_session_ranking(self):
49
+ rows = compute_severity_rows(
50
+ self._metrics(),
51
+ cfg=SeverityConfig(
52
+ mode="percentile",
53
+ source_metric="composite_risk",
54
+ thresholds=SeverityThresholds(percentile_warning=50.0, percentile_critical=90.0),
55
+ ),
56
+ )
57
+ by_q = {int(r["qubit"]): r for r in rows}
58
+ self.assertEqual(by_q[1]["severity_band"], "CRITICAL")
59
+ self.assertEqual(by_q[1]["severity_rank"], 1)
60
+ self.assertGreater(by_q[1]["severity_percentile"], by_q[2]["severity_percentile"])
61
+
62
+ def test_weighted_mode_uses_separate_weight_model(self):
63
+ rows = compute_severity_rows(
64
+ self._metrics(),
65
+ cfg=SeverityConfig(
66
+ mode="weighted",
67
+ weights=SeverityWeights(activity=0.0, gate_error=1.0, readout_error=0.0, decoherence=0.0, fidelity=0.0),
68
+ ),
69
+ )
70
+ self.assertEqual(rows[0]["qubit"], 1)
71
+ self.assertEqual(rows[0]["source_metric"], "weighted_blend")
72
+ self.assertAlmostEqual(rows[0]["severity_score"], 0.75, places=6)
73
+
74
+ def test_pnr_cost_mode_emits_richer_outputs(self):
75
+ rows = compute_severity_rows(
76
+ self._metrics(),
77
+ cfg=SeverityConfig(mode="pnr_cost"),
78
+ )
79
+ top = rows[0]
80
+ self.assertEqual(top["severity_band"], "CRITICAL")
81
+ self.assertGreater(top["pnr_cost"], 0.0)
82
+ self.assertGreater(top["timing_derate"], 1.0)
83
+ self.assertLess(top["density_cap"], 100.0)
84
+ self.assertIn(top["route_priority"], {"LOW", "MEDIUM", "HIGH"})
85
+
86
+ def test_severity_rows_to_csv_contains_headers(self):
87
+ csv_text = severity_rows_to_csv(
88
+ compute_severity_rows(
89
+ self._metrics(),
90
+ cfg=SeverityConfig(mode="linear", source_metric="composite_risk"),
91
+ qubit_coords={0: (0, 0), 1: (0, 1), 2: (1, 0)},
92
+ )
93
+ )
94
+ self.assertIn("severity_mode", csv_text.splitlines()[0])
95
+ self.assertIn("pnr_cost", csv_text.splitlines()[0])
96
+ self.assertIn("\n1,0,1,", csv_text)
97
+
98
+
99
+ if __name__ == "__main__":
100
+ unittest.main()