Demo 2:模幂 U_7

第 9 章 高等代数与数论量子算法 · 本章演示 · 代码演示总索引

可视化:3 子图 —— 16 输入态全测 + QPE

对应教程:第 9 章 高等代数与数论量子算法 中相关小节 · 依赖安装:pip install "unified-quantum[visualization,simulation]"

实现要点

模型: 取 N=15, a=7. U_7 在 Z_15 上的轨道结构 (用于 Shor 周期查找): 固定点: 0, 5, 10, 15 (其中 15 -> 0, 不是真正的"不动"而是溢出折叠). 3 个不相交 4-cycle: (1,7,4,13), (2,14,8,11), (3,6,12,9). 所以周期 r = 4.

量子部分: 因为 uniqc 不支持 add_gate('U', matrix=...), 这里用"单输入目标" 的等价实现: 对每个 x in [0, 15], 构造多受控 X 门, 只在输入为 |x> 时将 diff 位置翻转, 把 |x> 映射到 |7x mod 15>. 控制只用"非 diff"位, 避免互相干扰. 对其它输入态, 电路作用为 identity (按基态正交, 不会污染 |x> 那一支). 16 次独立测量验证全部 a*x mod N 映射.

QPE 部分: 用 1-qubit S 门 eigenstate |1> (与 ch04 demo 1 一致的简化路径), 4-qubit 精度寄存器测相位 1/4 -> r=4.

完整源码

demos/ch09-algebra-number-theory/02_modular_exp.py
  1"""
  2ch09 演示 2: Shor 算法的模幂子程序 U_a |x> = |a*x mod N>.
  3
  4模型: 取 N=15, a=7. U_7 在 Z_15 上的轨道结构 (用于 Shor 周期查找):
  5  固定点: 0, 5, 10, 15  (其中 15 -> 0, 不是真正的"不动"而是溢出折叠).
  6  3 个不相交 4-cycle: (1,7,4,13), (2,14,8,11), (3,6,12,9).
  7  所以周期 r = 4.
  8
  9量子部分: 因为 uniqc 不支持 add_gate('U', matrix=...), 这里用"单输入目标"
 10的等价实现: 对每个 x in [0, 15], 构造多受控 X 门, 只在输入为 |x> 时将 diff
 11位置翻转, 把 |x> 映射到 |7x mod 15>. 控制只用"非 diff"位, 避免互相干扰.
 12对其它输入态, 电路作用为 identity (按基态正交, 不会污染 |x> 那一支).
 1316 次独立测量验证全部 a*x mod N 映射.
 14
 15QPE 部分: 用 1-qubit S 门 eigenstate |1> (与 ch04 demo 1 一致的简化路径),
 164-qubit 精度寄存器测相位 1/4 -> r=4.
 17
 18对应教程: chenzhaoyun.com/quantum-tutorial/ch04-classic-algorithms/shors-algorithm-tutorial.html
 19依赖: pip install unified-quantum[visualization]
 20运行: python demos/ch09-algebra-number-theory/02_modular_exp.py
 21"""
 22from uniqc import Circuit, submit_task, wait_for_result
 23from uniqc.algorithms.core.circuits import qpe_circuit
 24import matplotlib
 25matplotlib.use("Agg")
 26import matplotlib.pyplot as plt
 27import numpy as np
 28from pathlib import Path
 29
 30OUT = Path(__file__).parent
 31SHOTS_PER_X = 60
 32N_Q = 4
 33N_STATES = 2 ** N_Q
 34N_MOD = 15
 35A = 7
 36N_PREC = 4
 37
 38
 39def u7_map():
 40    """返回 16 元素数组 perm, perm[x] = 7x mod 15, 并把 15 折叠到 0."""
 41    perm = [(A * x) % N_MOD for x in range(N_STATES)]
 42    perm[-1] = 0
 43    return perm
 44
 45
 46def orbit(start):
 47    seen = {start: 0}
 48    state, cycle = start, [start]
 49    while True:
 50        state = (A * state) % N_MOD
 51        if state in seen:
 52            return cycle, len(cycle) - seen[state]
 53        seen[state] = len(cycle)
 54        cycle.append(state)
 55
 56
 57def cx_neg(c, target, controls):
 58    """X(target) 受控于 (qubit, value) 列表 (0/1), 用 pre/post-flip 处理 0."""
 59    for q, v in controls:
 60        if v == 0:
 61            c.x(q)
 62    c.add_gate('X', qubits=target, control_qubits=[q for q, _ in controls])
 63    for q, v in controls:
 64        if v == 0:
 65            c.x(q)
 66
 67
 68def build_u7_single_target(x_val):
 69    """构造对单一输入 |x_val> -> |7x_val mod 15> 的电路. 控制只用非 diff 位."""
 70    y_val = (A * x_val) % N_MOD if x_val < 15 else 0
 71    xb = [(x_val >> i) & 1 for i in range(N_Q)]
 72    yb = [(y_val >> i) & 1 for i in range(N_Q)]
 73    diff = [i for i in range(N_Q) if xb[i] != yb[i]]
 74    nd = [i for i in range(N_Q) if xb[i] == yb[i]]
 75    if not diff:
 76        return None
 77    c = Circuit()
 78    for i in range(N_Q):
 79        if xb[i]:
 80            c.x(i)
 81    for tgt in diff:
 82        ctrls = [(j, xb[j]) for j in nd if j != tgt]
 83        if ctrls:
 84            cx_neg(c, tgt, ctrls)
 85        else:
 86            c.x(tgt)
 87    for q in range(N_Q):
 88        c.measure(q)
 89    return c
 90
 91
 92def decode(bs):
 93    """uniqc bitstring 直接当二进制读即为整数值."""
 94    return int(bs[-N_Q:], 2)
 95
 96
 97# ---- 1. 经典前置 ----
 98perm = u7_map()
 99M = np.zeros((N_STATES, N_STATES), dtype=int)
100for x, y in enumerate(perm):
101    M[y, x] = 1
102cycle1, period_r = orbit(1)
103cycle2, _ = orbit(2)
104cycle3, _ = orbit(3)
105
106# 16 次测量验证 7x mod 15 映射
107measured_y, expected_y = [], []
108for x in range(N_STATES):
109    y_exp = perm[x]
110    expected_y.append(y_exp)
111    if x == y_exp:
112        measured_y.append(y_exp)
113        continue
114    c = build_u7_single_target(x)
115    res = wait_for_result(submit_task(circuit=c, backend="dummy:local:simulator",
116                                      shots=SHOTS_PER_X))
117    measured_y.append(decode(max(res.counts, key=res.counts.get)))
118
119# ---- 2. QPE on S eigenstate (proxy for r=4) ----
120unitary = Circuit(); unitary.s(0)
121prep = Circuit(); prep.x(0)
122c_qpe = qpe_circuit(n_precision=N_PREC, unitary_circuit=unitary,
123                     state_prep=prep, measure=True)
124qpe_counts = wait_for_result(submit_task(circuit=c_qpe, backend="dummy:local:simulator",
125                                         shots=2000)).counts
126qpe_dist = np.zeros(N_STATES, dtype=float)
127for bs, cnt in qpe_counts.items():
128    qpe_dist[int(bs[-N_PREC:], 2)] += cnt
129qpe_dist /= qpe_dist.sum()
130
131
132# ---- 3. 可视化: 排列热图 + 验证柱图 + QPE 相位直方图 ----
133fig, axes = plt.subplots(1, 3, figsize=(16.5, 4.8))
134labels_n4 = [f"{i:04b}" for i in range(N_STATES)]
135
136ax = axes[0]
137ax.imshow(M, cmap="Blues", vmin=0, vmax=1)
138for i in range(N_STATES):
139    for j in range(N_STATES):
140        if M[i, j] == 1:
141            ax.text(j, i, "1", ha="center", va="center", fontsize=7, color="red")
142ax.set_title(f"U_7 map  |x> -> |{A}x mod {N_MOD}>  (16x16, 15->0 fold, r={period_r})")
143ax.set_xlabel("input  |x>")
144ax.set_ylabel("output  |7x mod 15>")
145ax.set_xticks(np.arange(N_STATES))
146ax.set_yticks(np.arange(N_STATES))
147ax.set_xticklabels(labels_n4, rotation=0, fontsize=7)
148ax.set_yticklabels(labels_n4, fontsize=7)
149
150ax = axes[1]
151xs = np.arange(N_STATES); w = 0.4
152agree = sum(1 for i in range(N_STATES) if expected_y[i] == measured_y[i])
153ax.bar(xs - w / 2, expected_y, width=w, color="#1f77b4", edgecolor="black",
154       label=f"expected  {A}x mod {N_MOD}")
155ax.bar(xs + w / 2, measured_y, width=w, color="#d62728", edgecolor="black",
156       label=f"measured (shots={SHOTS_PER_X})")
157ax.set_xticks(xs)
158ax.set_xticklabels(labels_n4, rotation=0, fontsize=7)
159ax.set_xlabel("input  |x>"); ax.set_ylabel("output index")
160ax.set_title(f"Verification: x -> {A}x mod {N_MOD} for all 16 inputs\nagreement = {agree}/{N_STATES}")
161ax.set_ylim(0, N_STATES); ax.legend(fontsize=8, loc="upper left"); ax.grid(axis="y", alpha=0.3)
162
163ax = axes[2]
164probs = qpe_dist * 100
165ax.bar(np.arange(N_STATES), probs,
166       color=["#d62728" if k in (0, 4, 8, 12) else "#1f77b4" for k in range(N_STATES)],
167       edgecolor="black")
168ax.set_xticks(np.arange(N_STATES))
169ax.set_xticklabels([f"{k:04b}" for k in range(N_STATES)], rotation=0, fontsize=7)
170ax.set_xlabel("counting register (k)  ->  phase = k / 16"); ax.set_ylabel("probability (%)")
171ax.set_title("QPE on eigenstate |1> of S gate (period-4 proxy)\npeak at k=4 (phase 1/4) confirms r = 4")
172for k in (0, 4, 8, 12):
173    ax.text(k, probs[k] + 1.5, f"k={k}\nphase={k/N_STATES:.3f}",
174            ha="center", va="bottom", fontsize=7, color="darkred")
175ax.set_ylim(0, max(probs.max() * 1.25, 30))
176ax.grid(axis="y", alpha=0.3)
177fig.suptitle(f"Modular exponentiation U_{A} on Z_{N_MOD}: "
178             f"permutation matrix + measured mapping + QPE phase histogram",
179             fontsize=12, y=1.02)
180plt.tight_layout()
181plt.savefig(OUT / "02_modular_exp.png", dpi=120, bbox_inches="tight")
182plt.close()
183
184
185# ---- 4. stdout 关键统计 ----
186peak_k = int(np.argmax(qpe_dist))
187print("ch09-algebra-number-theory demo 2: modular exponentiation U_7 on N=15")
188print(f"  per-x shots: {SHOTS_PER_X}  (16 runs total = {16 * SHOTS_PER_X} shots)")
189print(f"  orbit structure:")
190print(f"    cycle 1: {[f'{x:04b}' for x in cycle1]}  (r = {period_r})")
191print(f"    cycle 2: {[f'{x:04b}' for x in cycle2]}")
192print(f"    cycle 3: {[f'{x:04b}' for x in cycle3]}")
193print(f"  agreement (16 inputs): {agree}/{N_STATES}")
194disc = [(i, measured_y[i], expected_y[i])
195        for i in range(N_STATES) if measured_y[i] != expected_y[i]]
196print(f"  discrepancies: {disc}")
197print(f"  QPE peak: k = {peak_k}  (phase = {peak_k/N_STATES:.4f})")
198print(f"  QPE peak probability: {qpe_dist[peak_k]*100:.2f}%")
199print(f"  saved: {OUT / '02_modular_exp.png'}")

运行结果

Demo 2:模幂 U_7

运行方式

# 仓库根目录执行;输出 PNG 到 demos/ch09-algebra-number-theory/02_modular_exp.png,关键统计到 stdout
.venv/bin/python3 demos/ch09-algebra-number-theory/02_modular_exp.py

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