hchevva commited on
Commit
067fe70
·
verified ·
1 Parent(s): 735cde3

Create heatmap.py

Browse files
Files changed (1) hide show
  1. quread/heatmap.py +110 -0
quread/heatmap.py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # quread/heatmap.py
2
+ from __future__ import annotations
3
+
4
+ import csv
5
+ import io
6
+ from dataclasses import dataclass
7
+ from typing import Dict, List, Optional, Tuple
8
+
9
+ import numpy as np
10
+ import matplotlib.pyplot as plt
11
+
12
+
13
+ @dataclass
14
+ class HeatmapConfig:
15
+ rows: int = 8 # chip rows
16
+ cols: int = 8 # chip cols
17
+ missing_value: float = 0.0
18
+
19
+
20
+ def _default_qubit_coords(n_qubits: int, rows: int, cols: int) -> Dict[int, Tuple[int, int]]:
21
+ """
22
+ Simple default mapping: q0.. mapped row-major across the chip grid.
23
+ Override later with user-uploaded mapping if needed.
24
+ """
25
+ m: Dict[int, Tuple[int, int]] = {}
26
+ for q in range(n_qubits):
27
+ r = q // cols
28
+ c = q % cols
29
+ if r >= rows:
30
+ break
31
+ m[q] = (r, c)
32
+ return m
33
+
34
+
35
+ def _parse_history_rows(csv_text: str) -> List[dict]:
36
+ """
37
+ Expects the CSV you generate in Task 2A:
38
+ step,gate,target,control,theta
39
+ """
40
+ f = io.StringIO(csv_text or "")
41
+ reader = csv.DictReader(f)
42
+ rows = []
43
+ for r in reader:
44
+ rows.append({
45
+ "step": int(r.get("step", "0") or 0),
46
+ "gate": (r.get("gate") or "").strip(),
47
+ "target": r.get("target", "").strip(),
48
+ "control": r.get("control", "").strip(),
49
+ "theta": (r.get("theta") or "").strip(),
50
+ })
51
+ return rows
52
+
53
+
54
+ def make_activity_heatmap(
55
+ csv_text: str,
56
+ n_qubits: int,
57
+ cfg: Optional[HeatmapConfig] = None,
58
+ qubit_coords: Optional[Dict[int, Tuple[int, int]]] = None,
59
+ ) -> plt.Figure:
60
+ """
61
+ Builds a heatmap counting how many times each qubit participates in an operation.
62
+ - Single-qubit op increments its target qubit.
63
+ - CNOT increments both control and target.
64
+ """
65
+ cfg = cfg or HeatmapConfig()
66
+ coords = qubit_coords or _default_qubit_coords(n_qubits, cfg.rows, cfg.cols)
67
+
68
+ grid = np.full((cfg.rows, cfg.cols), cfg.missing_value, dtype=float)
69
+
70
+ # count per qubit
71
+ counts = np.zeros((n_qubits,), dtype=float)
72
+
73
+ rows = _parse_history_rows(csv_text)
74
+ for r in rows:
75
+ gate = r["gate"].upper()
76
+
77
+ # target
78
+ if r["target"] != "":
79
+ t = int(r["target"])
80
+ if 0 <= t < n_qubits:
81
+ counts[t] += 1.0
82
+
83
+ # control for CNOT
84
+ if gate == "CNOT" and r["control"] != "":
85
+ c = int(r["control"])
86
+ if 0 <= c < n_qubits:
87
+ counts[c] += 1.0
88
+
89
+ # place into chip grid
90
+ for q, (rr, cc) in coords.items():
91
+ if 0 <= q < n_qubits and 0 <= rr < cfg.rows and 0 <= cc < cfg.cols:
92
+ grid[rr, cc] = counts[q]
93
+
94
+ # plot
95
+ fig, ax = plt.subplots(figsize=(6, 5))
96
+ im = ax.imshow(grid, interpolation="nearest")
97
+ ax.set_title("Qubit activity heatmap (from circuit CSV)")
98
+ ax.set_xlabel("Chip column")
99
+ ax.set_ylabel("Chip row")
100
+ fig.colorbar(im, ax=ax, fraction=0.046, pad=0.04)
101
+
102
+ # annotate qubit ids on mapped cells
103
+ for q, (rr, cc) in coords.items():
104
+ if 0 <= rr < cfg.rows and 0 <= cc < cfg.cols:
105
+ ax.text(cc, rr, f"q{q}", ha="center", va="center", fontsize=9)
106
+
107
+ ax.set_xticks(range(cfg.cols))
108
+ ax.set_yticks(range(cfg.rows))
109
+ fig.tight_layout()
110
+ return fig