Demo 1:Simon HSP

第 10 章 隐藏结构与群算法 · 本章演示 · 代码演示总索引

可视化:双图(分布+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'}")

运行结果

Demo 1:Simon HSP

运行方式

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

← 本章演示 · ↑ 代码演示总索引 · ⌂ 教程门户