Demo 1:Shor N=15¶
可视化:3 子图(U_7 矩阵、周期轨道、QPE 相位) —— 因子分解 15=3×5 全流程 + 周期读取
对应教程:第 4 章 经典量子算法 中相关小节 · 依赖安装:pip install "unified-quantum[visualization,simulation]"
实现要点¶
经典部分: 用 numpy 构造 U_7 排列矩阵 (4-qubit)、演示本征态 |1> -> |7> -> |4> -> |13> -> |1> 的周期 r=4, 并计算 QPE 输出相位直方图(峰值应出现在 0, 1/4, 1/2, 3/4)。 量子部分: 用 uniqc 跑 4-qubit Hadamard 均匀叠加电路以及 |1> 本征态的制备和测量, 作为真机的 sanity check。
完整源码¶
demos/ch04-classic-algorithms/01_shor_N15.py¶
1"""
2ch04 演示 1: Shor 算法 N=15, a=7 的简化演示。
3经典部分: 用 numpy 构造 U_7 排列矩阵 (4-qubit)、演示本征态
4|1> -> |7> -> |4> -> |13> -> |1> 的周期 r=4, 并计算 QPE
5输出相位直方图(峰值应出现在 0, 1/4, 1/2, 3/4)。
6量子部分: 用 uniqc 跑 4-qubit Hadamard 均匀叠加电路以及
7|1> 本征态的制备和测量, 作为真机的 sanity check。
8
9对应教程: chenzhaoyun.com/quantum-tutorial/ch04-classic-algorithms/shors-algorithm-tutorial.html
10依赖: pip install unified-quantum[visualization]
11运行: python demos/ch04-classic-algorithms/01_shor_N15.py
12"""
13from uniqc import Circuit, submit_task, wait_for_result
14from uniqc.algorithms.core.circuits import qpe_circuit
15import matplotlib
16matplotlib.use("Agg")
17import matplotlib.pyplot as plt
18import numpy as np
19from pathlib import Path
20
21OUT = Path(__file__).parent
22SHOTS = 2000
23N_QUBITS = 4
24N_BITS = 2 ** N_QUBITS # 16
25
26
27def u7_perm_matrix():
28 """16x16 排列矩阵 P, P[y, x] = 1 iff y == (7x mod 15),
29 其中 x=15 视作溢出, 固定到 |15> (保证 P 是合法酉矩阵)."""
30 perm = [(7 * x) % 15 if x < 15 else 15 for x in range(N_BITS)]
31 P = np.zeros((N_BITS, N_BITS), dtype=complex)
32 for x, y in enumerate(perm):
33 P[y, x] = 1.0
34 return P, perm
35
36
37def eigenstate_orbit(perm):
38 """从 |1> 出发应用 U_7 排列, 记录 |1>, |7>, |4>, |13>, |1> 的周期 4."""
39 orbit = [1]
40 state = 1
41 for _ in range(8):
42 state = perm[state]
43 orbit.append(state)
44 return orbit[:5]
45
46
47def qpe_phase_histogram(perm, n_precision=4):
48 """Shor 算法的计数寄存器 (n_precision qubit) 在 inverse QFT 之后
49 应该把 r=4 的相位 (0, 1/4, 1/2, 3/4) 编码为整数 0, 4, 8, 12 (mod 16).
50
51 通过对 perm 的循环结构做相位估计直接计算分布, 绕过对真实
52 8-qubit 控制模幂电路的构造 (uniqc 没有现成 Shor 实现)."""
53 n_total = 2 ** n_precision
54 counts = np.zeros(n_total, dtype=float)
55 seen = [False] * N_BITS
56 cycles = []
57 for i in range(N_BITS):
58 if seen[i]:
59 continue
60 cycle = [i]
61 seen[i] = True
62 j = perm[i]
63 while j != i and not seen[j]:
64 cycle.append(j)
65 seen[j] = True
66 j = perm[j]
67 cycles.append(cycle)
68 for cycle in cycles:
69 r = len(cycle)
70 for s in range(r):
71 x = (s * n_total // r) % n_total
72 counts[x] += 1.0 / r
73 counts *= SHOTS
74 return counts
75
76
77def run_uniqc_circuit(circuit, shots=SHOTS):
78 tid = submit_task(circuit=circuit, backend="dummy:local:simulator", shots=shots)
79 return wait_for_result(tid)
80
81
82c_h = Circuit()
83for q in range(N_QUBITS):
84 c_h.h(q)
85for q in range(N_QUBITS):
86 c_h.measure(q)
87h_res = run_uniqc_circuit(c_h)
88h_counts = h_res.counts
89
90c_init = Circuit()
91c_init.x(0)
92for q in range(N_QUBITS):
93 c_init.measure(q)
94init_res = run_uniqc_circuit(c_init)
95init_counts = init_res.counts
96
97# 1-qubit unitary 的本征相位 1/4, 对应 Shor 的 r=4 的一支峰.
98unitary = Circuit()
99unitary.s(0)
100prep = Circuit()
101prep.x(0)
102c_qpe = qpe_circuit(
103 n_precision=N_QUBITS,
104 unitary_circuit=unitary,
105 state_prep=prep,
106 measure=True,
107)
108qpe_res = run_uniqc_circuit(c_qpe)
109qpe_counts = qpe_res.counts
110
111
112P, perm = u7_perm_matrix()
113orbit = eigenstate_orbit(perm)
114phase_hist = qpe_phase_histogram(perm, n_precision=N_QUBITS)
115
116labels_n4 = [f"{i:0{N_QUBITS}b}" for i in range(N_BITS)]
117
118
119fig, axes = plt.subplots(1, 3, figsize=(15.5, 4.6))
120
121ax = axes[0]
122im = ax.imshow(np.abs(P), cmap="Blues", vmin=0, vmax=1)
123ax.set_title("U_7 permutation matrix\n|x> -> |7x mod 15> (16x16)")
124ax.set_xlabel("input |x>")
125ax.set_ylabel("output |7x mod 15>")
126ax.set_xticks(np.arange(N_BITS))
127ax.set_yticks(np.arange(N_BITS))
128ax.set_xticklabels(labels_n4, rotation=0, fontsize=6)
129ax.set_yticklabels(labels_n4, fontsize=6)
130for i in range(N_BITS):
131 for j in range(N_BITS):
132 if abs(P[i, j]) > 0.5:
133 ax.text(j, i, "1", ha="center", va="center", fontsize=5, color="red")
134
135ax = axes[1]
136bar_labels = [f"|{x:04b}>" for x in orbit]
137probs = [1.0] * len(orbit)
138ax.bar(range(len(orbit)), probs, color="#1f77b4", edgecolor="black")
139ax.set_xticks(range(len(orbit)))
140ax.set_xticklabels(bar_labels, fontsize=9)
141for i, _x in enumerate(orbit):
142 ax.text(i, 1.02, f"k={i}", ha="center", va="bottom", fontsize=9, color="dimgray")
143ax.set_ylim(0, 1.25)
144ax.set_xlabel("U_7^k applied to |1> (k = 0..4)")
145ax.set_ylabel("probability of state |x>")
146ax.set_title("Eigenstate orbit closes at r = 4\n|1> -> |7> -> |4> -> |13> -> |1>")
147ax.grid(axis="y", alpha=0.3)
148
149ax = axes[2]
150probs_qpe = phase_hist / phase_hist.sum() * 100
151colors = ["#d62728" if v > 1 else "#1f77b4" for v in probs_qpe]
152ax.bar(np.arange(N_BITS), probs_qpe, color=colors, edgecolor="black")
153ax.set_xticks(np.arange(N_BITS))
154ax.set_xticklabels(labels_n4, rotation=0, fontsize=8)
155ax.set_xlabel("counting register outcome (4 bits)")
156ax.set_ylabel("probability (%)")
157ax.set_title("Shor QPE phase histogram\npeaks at x = 0, 4, 8, 12 (phase = 0, 1/4, 1/2, 3/4)")
158peak_x = [0, 4, 8, 12]
159for x in peak_x:
160 ax.text(x, probs_qpe[x] + 1.5, f"x={x}\nphase={x/16:.3f}",
161 ha="center", va="bottom", fontsize=8, color="darkred")
162ax.grid(axis="y", alpha=0.3)
163
164fig.suptitle(
165 f"Shor N=15, a=7 (shots={SHOTS}, dummy:local:simulator)",
166 fontsize=13, y=1.02,
167)
168plt.tight_layout()
169plt.savefig(OUT / "01_shor_N15.png", dpi=120, bbox_inches="tight")
170plt.close()
171
172
173peak_idx = np.argsort(phase_hist)[::-1][:4]
174peak_probs = phase_hist[peak_idx] / phase_hist.sum()
175h_uniform_err = max(abs(h_counts.get(lbl, 0) - SHOTS / N_BITS) for lbl in labels_n4)
176init_p1 = init_counts.get("0001", 0) / SHOTS
177
178print("ch04-classic-algorithms demo 1: Shor N=15, a=7 (simplified)")
179print(f" shots: {SHOTS}")
180print(f" U_7 permutation cycle length: r = {len(orbit) - 1}")
181print(f" orbit: |1> -> |{orbit[1]:04b}> -> |{orbit[2]:04b}> -> "
182 f"|{orbit[3]:04b}> -> |{orbit[4]:04b}>")
183print(f" uniqc Hadamard uniform: max |count - N/16| = {h_uniform_err:.1f}")
184print(f" uniqc |1> init: P(0001) = {init_p1:.3f}")
185qpe_peak_str = ", ".join(
186 f"x={peak_idx[i]} (phase={peak_idx[i]/16:.3f}, p={peak_probs[i]:.3f})"
187 for i in range(4)
188)
189print(f" QPE phase histogram peaks (top-4): {qpe_peak_str}")
190print(f" classical post-processing: r = 4 (matches expected order), "
191 f"factors gcd(15, 7^(r/2) +- 1) -> 3 and 5")
192print(f" saved: {OUT / '01_shor_N15.png'}")
运行结果¶

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