Demo 2:Grover 4-qubit¶
可视化:2×2 子图 —— 迭代 0/1/2/4 测量概率演化
对应教程:第 3 章 量子算法基础 中相关小节 · 依赖安装:pip install "unified-quantum[visualization,simulation]"
实现要点¶
完整源码¶
demos/ch03-algo-basics/02_grover_4qubit.py¶
1"""
2ch03 演示 2:Grover 4-qubit 标记 |0011⟩,迭代 0/1/2/4 次测量概率演化
3
4对应教程:chenzhaoyun.com/quantum-tutorial/ch03-algo-basics/grover.html
5依赖:pip install unified-quantum[visualization]
6运行:python demos/ch03-algo-basics/02_grover_4qubit.py
7"""
8from uniqc import (
9 Circuit,
10 grover_diffusion,
11 grover_oracle,
12 submit_task,
13 wait_for_result,
14)
15import matplotlib
16matplotlib.use("Agg")
17import matplotlib.pyplot as plt
18import numpy as np
19from pathlib import Path
20
21OUT = Path(__file__).parent
22N_QUBITS = 4
23MARKED = 3 # = |0011>,即"|11>" 在 4-bit 表示下的等价态
24ITERATIONS = (0, 1, 2, 4)
25SHOTS = 2000
26
27
28def run_grover(iterations: int):
29 """构造均匀初态 |s> = H^n|0>,迭代 Grover 算子若干次,返回测量计数。"""
30 oracle = grover_oracle(marked_state=MARKED, n_qubits=N_QUBITS)
31 diff = grover_diffusion(n_qubits=N_QUBITS)
32 c = Circuit()
33 # 1) 均匀叠加初态
34 for q in range(N_QUBITS):
35 c.h(q)
36 # 2) 迭代 Grover = Oracle + Diffusion
37 for _ in range(iterations):
38 c.add_circuit(oracle)
39 c.add_circuit(diff)
40 # 3) 测量每个输入比特
41 for q in range(N_QUBITS):
42 c.measure(q)
43 result = wait_for_result(
44 submit_task(circuit=c, backend="dummy:local:simulator", shots=SHOTS)
45 )
46 # uniqc 的 grover_oracle(marked_state, n_qubits) 会为内部 TOFFOLI
47 # 多塞 3 个 ancilla(qubits 4,5,6);counts key 的高位就是它们。只保留
48 # 输入寄存器的低 N_QUBITS 位即可。
49 input_counts = {}
50 for bs, cnt in result.counts.items():
51 input_counts[bs[-N_QUBITS:]] = input_counts.get(bs[-N_QUBITS:], 0) + cnt
52 return input_counts
53
54
55# === 1. 跑 0/1/2/4 次迭代 ===
56counts_by_iter = {k: run_grover(k) for k in ITERATIONS}
57
58labels = [f"{i:0{N_QUBITS}b}" for i in range(2 ** N_QUBITS)]
59probs_by_iter = {}
60for it, counts in counts_by_iter.items():
61 total = sum(counts.values())
62 probs_by_iter[it] = np.array([counts.get(lbl, 0) / total for lbl in labels])
63
64# === 2. matplotlib 可视化(2x2 子图,对应 4 个迭代深度) ===
65fig, axes = plt.subplots(2, 2, figsize=(13, 8.5), sharey=True)
66axes = axes.flatten()
67
68for ax, it in zip(axes, ITERATIONS):
69 probs = probs_by_iter[it]
70 color = np.where(np.arange(len(probs)) == MARKED, "#d62728", "#1f77b4")
71 ax.bar(np.arange(len(probs)), probs * 100, color=color, edgecolor="black")
72 ax.set_xticks(np.arange(len(probs)))
73 ax.set_xticklabels(labels, rotation=90, fontsize=8)
74 ax.set_xlabel("Basis state")
75 ax.set_ylabel("Probability (%)")
76 p_marked = probs[MARKED]
77 ax.set_title(
78 f"Iteration {it} — P(|{MARKED:0{N_QUBITS}b}>) = {p_marked:.3f}",
79 fontsize=11,
80 )
81 ax.set_ylim(0, 70)
82 ax.grid(axis="y", alpha=0.3)
83
84fig.suptitle(
85 f"Grover on {N_QUBITS} qubits marking |{MARKED:0{N_QUBITS}b}> "
86 f"({SHOTS} shots per iteration, dummy:local:simulator)",
87 fontsize=12,
88 y=0.995,
89)
90plt.tight_layout()
91plt.savefig(OUT / "02_grover_4qubit.png", dpi=120, bbox_inches="tight")
92plt.close()
93
94# === 3. stdout 关键统计 ===
95print("ch03-algo-basics demo 2: Grover 4-qubit amplification")
96print(f" marked state: |{MARKED:0{N_QUBITS}b}> (= int {MARKED})")
97print(f" N = 2^{N_QUBITS} = {2**N_QUBITS}; optimal iterations ≈ "
98 f"{np.pi/4 * np.sqrt(2**N_QUBITS):.2f}")
99print(f" P(marked) per iteration:")
100for it in ITERATIONS:
101 p = probs_by_iter[it][MARKED]
102 print(f" iter {it}: {p:.3f}")
103print(f" saved: {OUT / '02_grover_4qubit.png'}")
运行结果¶

运行方式¶
# 仓库根目录执行;输出 PNG 到 demos/ch03-algo-basics/02_grover_4qubit.png,关键统计到 stdout
.venv/bin/python3 demos/ch03-algo-basics/02_grover_4qubit.py