Demo 1:Simon HSP¶
可视化:双图(分布+RREF) —— 3-qubit H^⊥ 样本 + F_2 高斯消元
对应教程:第 10 章 隐藏结构与群算法 中相关小节 · 依赖安装:pip install "unified-quantum[visualization,simulation]"
实现要点¶
HSP 视角:群 G=Z_2^3, 隐藏子群 H={0, s}, f(x)=f(x XOR s)。 电路:H^⊗n → Oracle → H^⊗n → 测量。多次独立采样得到 y·s = 0 (mod 2), 在 F_2 上做高斯消元恢复 s。
注:dummy backend 中 measure() 会强制全局在末尾测量,因此这里省略中间 "测量输出寄存器"那一步。统计上等价:oracle 纠缠态 + H^⊗n 在数据寄存器上 的分布恰为 H^⊥ 上的均匀分布。
完整源码¶
demos/ch10-hidden-structures/01_simon_hsp.py¶
1"""
2ch10 演示 1:Simon 算法的 HSP 视角:3-qubit 隐藏 s=110
3
4对应教程:chenzhaoyun.com/quantum-tutorial/ch10-hidden-structures/abelian-hidden-subgroup.html
5依赖:pip install unified-quantum[visualization]
6运行:python demos/ch10-hidden-structures/01_simon_hsp.py
7
8HSP 视角:群 G=Z_2^3, 隐藏子群 H={0, s}, f(x)=f(x XOR s)。
9电路:H^⊗n → Oracle → H^⊗n → 测量。多次独立采样得到 y·s = 0 (mod 2),
10在 F_2 上做高斯消元恢复 s。
11
12注:dummy backend 中 measure() 会强制全局在末尾测量,因此这里省略中间
13"测量输出寄存器"那一步。统计上等价:oracle 纠缠态 + H^⊗n 在数据寄存器上
14的分布恰为 H^⊥ 上的均匀分布。
15"""
16from uniqc import Circuit, submit_task, wait_for_result
17import matplotlib
18matplotlib.use("Agg")
19import matplotlib.pyplot as plt
20import numpy as np
21from pathlib import Path
22
23OUT = Path(__file__).parent
24N = 3
25S = 0b110 # 隐藏子群的非平凡元素 s = (1,1,0)
26SHOTS = 2000
27N_RUNS = 8
28
29
30def build_simon_circuit() -> Circuit:
31 """Simon's algorithm for n=3, s=110.
32 f(x) = 2*(x_1 XOR x_2) + x_0 是满足 f(x)=f(x XOR s) 的 2-to-1 函数。
33 Oracle: y_0 ^= x_0; y_1 ^= x_1 XOR x_2 (只需 2 个输出比特,因为 f<4)
34 """
35 c = Circuit()
36 for q in range(N):
37 c.h(q)
38 c.cnot(0, 3) # y_0 ^= x_0
39 c.cnot(1, 4) # y_1 ^= x_1
40 c.cnot(2, 4) # y_1 ^= x_2
41 for q in range(N):
42 c.h(q)
43 for q in range(N):
44 c.measure(q)
45 return c
46
47
48def gauss_elim_f2(matrix: np.ndarray) -> np.ndarray:
49 """F_2 高斯消元,返回增广矩阵的行最简形。"""
50 A = matrix.copy().astype(np.uint8)
51 n_rows, n_cols = A.shape
52 pivot_row = 0
53 for col in range(n_cols):
54 pr = -1
55 for r in range(pivot_row, n_rows):
56 if A[r, col] == 1:
57 pr = r
58 break
59 if pr == -1:
60 continue
61 A[[pivot_row, pr]] = A[[pr, pivot_row]]
62 for r in range(n_rows):
63 if r != pivot_row and A[r, col] == 1:
64 A[r] ^= A[pivot_row]
65 pivot_row += 1
66 return A
67
68
69# === 1. 跑 N_RUNS 次电路,每次按概率取代表性 y ===
70circuit = build_simon_circuit()
71print(f"circuit qubits: {circuit.qubit_num}, depth: {circuit.depth}")
72
73samples_y = []
74rng = np.random.default_rng(seed=42)
75for run in range(N_RUNS):
76 counts = wait_for_result(
77 submit_task(circuit=circuit, backend="dummy:local:simulator", shots=SHOTS)
78 ).counts
79 # key 长度 5: [q4, q3, q2, q1, q0];数据寄存器在 key[2:5]
80 data_counts = {}
81 for bs, cnt in counts.items():
82 db = bs[2:5]
83 data_counts[db] = data_counts.get(db, 0) + cnt
84 max_cnt = max(data_counts.values())
85 # 频次相同时随机选,模拟真实量子采样的随机性
86 chosen = rng.choice([k for k, v in data_counts.items() if v == max_cnt])
87 samples_y.append(int(chosen, 2))
88samples_y = np.array(samples_y, dtype=np.uint8)
89
90# === 2. F_2 高斯消元,从 y·s = 0 恢复 s ===
91M = np.array([[(y >> i) & 1 for i in range(N)] + [0] for y in samples_y], dtype=np.uint8)
92rref = gauss_elim_f2(M)
93
94# 找主元列、非主元列;s 在 RREF 对应的 null space 里
95pivot_rows, non_pivot_cols = {}, []
96for col in range(N):
97 pivot = -1
98 for r in range(rref.shape[0]):
99 if rref[r, col] == 1 and all(rref[r, cc] == 0 for cc in range(col)):
100 pivot = r
101 break
102 if pivot >= 0:
103 pivot_rows[col] = pivot
104 else:
105 non_pivot_cols.append(col)
106
107s_vec = np.zeros(N, dtype=np.uint8)
108if not non_pivot_cols:
109 s_recovered = 0
110else:
111 fc = non_pivot_cols[-1]
112 s_vec[fc] = 1
113 for pc, pr in pivot_rows.items():
114 s_vec[pc] = rref[pr, fc]
115 s_recovered = sum(int(s_vec[i]) << i for i in range(N))
116
117# === 3. matplotlib 可视化(2 子图:测量分布 + 高斯消元表)===
118fig, axes = plt.subplots(1, 2, figsize=(13, 5))
119
120# 左图:H^perp 上的测量概率
121# 期望非零分布:{000, 001, 110, 111} (因为 s=110,H^perp = {y : y_1 XOR y_2 = 0})
122H_perp = [y for y in range(2 ** N) if (y & S).bit_count() % 2 == 0]
123y_labels = [f"{y:0{N}b}" for y in range(2 ** N)]
124sample_counts = np.array([sum(1 for s in samples_y if s == y) for y in range(2 ** N)])
125colors = ["#d62728" if y in H_perp else "#d3d3d3" for y in range(2 ** N)]
126axes[0].bar(range(2 ** N), sample_counts, color=colors, edgecolor="black")
127axes[0].set_xticks(range(2 ** N))
128axes[0].set_xticklabels(y_labels, rotation=0, fontsize=10)
129axes[0].set_xlabel("Measured data y (basis state)")
130axes[0].set_ylabel(f"Count (out of {N_RUNS})")
131axes[0].set_title(
132 f"Simon's circuit samples for hidden s={S:0{N}b}\n"
133 f"red bars = H^perp (the {len(H_perp)} legal y satisfying y·s=0)",
134 fontsize=10,
135)
136axes[0].grid(axis="y", alpha=0.3)
137for y in H_perp:
138 axes[0].annotate(
139 f"y·s=0",
140 xy=(y, sample_counts[y]),
141 xytext=(y, sample_counts[y] + 0.3),
142 ha="center",
143 fontsize=8,
144 color="#d62728",
145 )
146
147# 右图:高斯消元后的系统(增广矩阵文本)
148ax = axes[1]
149ax.axis("off")
150table_text = "F_2 Gaussian elimination on samples y_0, ..., y_7\n"
151table_text += "(rows are samples, columns are bits y_2 y_1 y_0, augmented 0)\n\n"
152table_text += "Original matrix:\n"
153for y in samples_y:
154 row_bits = [(y >> i) & 1 for i in range(N)]
155 table_text += f" y={y:0{N}b} | " + " ".join(str(b) for b in row_bits) + " | 0\n"
156table_text += "\nRREF (row echelon form):\n"
157for r in range(rref.shape[0]):
158 row_bits = list(rref[r, :N])
159 table_text += " " + " ".join(str(b) for b in row_bits) + " | " + str(rref[r, N]) + "\n"
160table_text += f"\nRecovered s = {s_recovered:0{N}b} (binary)"
161table_text += f"\nTrue hidden s = {S:0{N}b} (binary)"
162table_text += f"\nMatch: {s_recovered == S}"
163ax.text(0.02, 0.98, table_text, family="monospace", fontsize=9,
164 verticalalignment="top", transform=ax.transAxes)
165
166fig.suptitle(
167 f"Simon's algorithm from HSP perspective: G=Z_2^{N}, H={{0, s={S:0{N}b}}} "
168 f"({N_RUNS} runs × {SHOTS} shots, dummy:local:simulator)",
169 fontsize=11,
170 y=1.02,
171)
172plt.tight_layout()
173plt.savefig(OUT / "01_simon_hsp.png", dpi=120, bbox_inches="tight")
174plt.close()
175
176# === 4. stdout 关键统计 ===
177print("ch10-hidden-structures demo 1: Simon's algorithm from HSP perspective")
178print(f" hidden s = {S:0{N}b} (binary)")
179print(f" G = Z_2^{N}, H = {{0, s}}, H^perp has |G|/|H| = {2**N // 2} elements")
180print(f" H^perp = {{y : y·s = 0 mod 2}} = " +
181 ", ".join(f"{y:0{N}b}" for y in H_perp))
182print(f" samples collected ({N_RUNS} runs): " +
183 ", ".join(f"{y:0{N}b}" for y in samples_y))
184print(f" all samples in H^perp: {all(y in H_perp for y in samples_y)}")
185print(f" recovered s = {s_recovered:0{N}b}, match = {s_recovered == S}")
186print(f" saved: {OUT / '01_simon_hsp.png'}")
运行结果¶

运行方式¶
# 仓库根目录执行;输出 PNG 到 demos/ch10-hidden-structures/01_simon_hsp.png,关键统计到 stdout
.venv/bin/python3 demos/ch10-hidden-structures/01_simon_hsp.py