Demo 3:Childs-Goldstone 空间搜索

第 12 章 量子图算法 · 本章演示 · 代码演示总索引

可视化:3 子图 —— C4 + γ=1/√2 + Rabi 振荡

对应教程:第 12 章 量子图算法 中相关小节 · 依赖安装:pip install "unified-quantum[visualization,simulation]"

实现要点

核心:4-环 C4 上做 Childs-Goldstone 连续时间空间搜索。Hamiltonian H = -γ A - |w⟩⟨w| 取 γ ≈ 1/√N = 1/2 (对 C_N 的渐近最优 γ 是 1/(2 sin(π/N)),对 N=4 ≈ 0.707), 初态 |s⟩ = (1/2) Σ_i |i⟩ 是 A 的本征态(本征值 2)。H 把 |s⟩ 局限在 span{|s⟩, |w⟩} 的 2 维子空间里做 Rabi 振荡;振幅在 t ≈ π√N/2 时刻翻转到 |w⟩,P(target) 接近 1。相比之下,经典随机游走 P_t = T^t|s⟩ 需要 O(N)=4 步 才能把概率抬到 1/4 量级。这里画 P(target) vs t 的连续时间量子振荡曲线, 并叠加经典随机游走的概率作为参考;同时画 4 个节点振幅 |⟨i|ψ(t)⟩|² 的时间演化。

完整源码

demos/ch12-quantum-graphs/03_spatial_search.py
  1"""
  2ch12-quantum-graphs demo 3: Childs–Goldstone spatial search on the 4-cycle
  3
  4对应教程:chenzhaoyun.com/quantum-tutorial/ch12-quantum-graphs/adjacency-matrix-properties.html
  5核心:4-环 C4 上做 Childs-Goldstone 连续时间空间搜索。Hamiltonian
  6       H = -γ A - |w⟩⟨w|
  7     取 γ ≈ 1/√N = 1/2 (对 C_N 的渐近最优 γ 是 1/(2 sin(π/N)),对 N=4 ≈ 0.707),
  8     初态 |s⟩ = (1/2) Σ_i |i⟩ 是 A 的本征态(本征值 2)。H 把 |s⟩ 局限在
  9     span{|s⟩, |w⟩} 的 2 维子空间里做 Rabi 振荡;振幅在 t ≈ π√N/2 时刻翻转到
 10     |w⟩,P(target) 接近 1。相比之下,经典随机游走 P_t = T^t|s⟩ 需要 O(N)=4 步
 11     才能把概率抬到 1/4 量级。这里画 P(target) vs t 的连续时间量子振荡曲线,
 12     并叠加经典随机游走的概率作为参考;同时画 4 个节点振幅 |⟨i|ψ(t)⟩|² 的时间演化。
 13
 14依赖:pip install unified-quantum[visualization]
 15运行:python demos/ch12-quantum-graphs/03_spatial_search.py
 16"""
 17from __future__ import annotations
 18
 19from pathlib import Path
 20
 21import matplotlib
 22matplotlib.use("Agg")
 23import matplotlib.pyplot as plt
 24import numpy as np
 25from scipy.linalg import expm
 26
 27OUT = Path(__file__).parent
 28N = 4
 29TARGET = 0
 30
 31# === 1. C4 adjacency matrix A ===
 32A = np.zeros((N, N))
 33for i in range(N):
 34    A[i, (i + 1) % N] = A[i, (i - 1) % N] = 1
 35
 36# Eigenvalues of A for sanity check
 37evals_A = np.linalg.eigvalsh(A)
 38print("ch12-quantum-graphs-demo-3: Childs–Goldstone search on C4")
 39print(f"  C4 adjacency eigenvalues: {np.round(evals_A, 4).tolist()}  "
 40      "(expected: -2, 0, 0, 2)")
 41
 42# === 2. Continuous-time spatial search Hamiltonian H = -γ A - |w⟩⟨w| ===
 43# Optimal γ for C_N: γ* = 1 / (2 sin(π/N)); for N=4 → γ* = 1/√2 ≈ 0.7071
 44GAMMA = 1.0 / np.sqrt(2.0)
 45T_QUANT_MAX = 10.0
 46N_QUANT_STEPS = 400
 47t_quant = np.linspace(0, T_QUANT_MAX, N_QUANT_STEPS)
 48
 49W = np.zeros((N, N))
 50W[TARGET, TARGET] = 1.0
 51H = -GAMMA * A - W   # Childs–Goldstone Hamiltonian
 52# Initial state |s> = (1/√N) Σ |i>
 53s = np.ones(N) / np.sqrt(N)
 54
 55target_probs_q = np.zeros(N_QUANT_STEPS)
 56all_node_probs_q = np.zeros((N_QUANT_STEPS, N))
 57for k, t in enumerate(t_quant):
 58    psi_t = expm(-1j * H * t) @ s
 59    probs = np.abs(psi_t) ** 2
 60    target_probs_q[k] = probs[TARGET]
 61    all_node_probs_q[k] = probs
 62
 63# === 3. Classical random walk on C4 starting from uniform distribution ===
 64T_class = A / 2.0   # transition matrix (degree = 2 for every node)
 65p_class = np.ones(N) / N   # uniform start = (1/N, ..., 1/N); stationary for C4
 66T_CLASS_MAX = 30
 67target_probs_c = np.zeros(T_CLASS_MAX)
 68all_node_probs_c = np.zeros((T_CLASS_MAX, N))
 69for t in range(T_CLASS_MAX):
 70    target_probs_c[t] = p_class[TARGET]
 71    all_node_probs_c[t] = p_class
 72    p_class = T_class @ p_class
 73
 74# === 4. Run a tiny uniqc sanity check on the uniform superposition |s> ===
 75try:
 76    from uniqc import Circuit, submit_task, wait_for_result
 77    c = Circuit()
 78    c.h(0); c.h(1)       # |s> = (|00>+|01>+|10>+|11>)/2 on q0, q1
 79    c.measure(0); c.measure(1)
 80    r = wait_for_result(
 81        submit_task(circuit=c, backend="dummy:local:simulator", shots=2000)
 82    )
 83    counts = r.counts
 84    total = sum(counts.values())
 85    expected = ["00", "01", "10", "11"]
 86    diffs = [abs(counts.get(bs, 0) / total - 0.25) for bs in expected]
 87    print(f"  uniqc sanity: |s> uniform prep, max deviation from 0.25 = "
 88          f"{max(diffs):.3f}")
 89except Exception as e:
 90    print(f"  uniqc sanity skipped: {e}")
 91
 92
 93# === 5. matplotlib 可视化 ===
 94fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(13.0, 5.2))
 95
 96# Left: P(target=node 0) vs time, continuous-time quantum vs classical random walk
 97ax1.plot(t_quant, target_probs_q, "-", color="#1f77b4", lw=2.0,
 98         label=fr"continuous-time search ($\gamma={GAMMA:.3f}$, $\hbar=1$)")
 99ax1.plot(np.arange(T_CLASS_MAX), target_probs_c, "o--", color="#ff7f0e",
100         lw=1.6, ms=6, label=f"classical random walk ({T_CLASS_MAX} steps)")
101# Mark the theoretically predicted search time T* = π√N/2
102T_star = np.pi * np.sqrt(N) / 2.0
103ax1.axvline(T_star, color="gray", ls=":", lw=1.0, alpha=0.7,
104            label=fr"theory $T^*=\pi\sqrt{{N}}/2\approx{T_star:.2f}$")
105ax1.axhline(1.0, color="#2ca02c", ls=":", lw=1.0, alpha=0.7,
106            label=r"ideal $P=1$")
107ax1.axhline(1.0 / N, color="#888888", ls=":", lw=1.0, alpha=0.7,
108            label=fr"classical uniform $1/N={1.0/N:.3f}$")
109ax1.set_xlabel(r"time $t$")
110ax1.set_ylabel(r"$P(\mathrm{target} = \mathrm{node}\ 0)$")
111ax1.set_ylim(-0.02, 1.08)
112ax1.set_title("Childs–Goldstone search on C4: target probability vs time")
113ax1.grid(alpha=0.3)
114ax1.legend(loc="upper right", fontsize=8, framealpha=0.9)
115
116# Right: heatmap of |⟨i|ψ(t)⟩|² for all 4 nodes over time
117im = ax2.imshow(all_node_probs_q.T, aspect="auto", origin="lower",
118                cmap="viridis", vmin=0.0, vmax=0.6,
119                extent=[t_quant[0], t_quant[-1], -0.5, N - 0.5])
120ax2.set_yticks(range(N))
121ax2.set_yticklabels([f"node {n}" + (" (target)" if n == TARGET else "")
122                      for n in range(N)])
123ax2.set_xlabel(r"time $t$")
124ax2.set_title(r"wave-packet $|\langle i|e^{-iHt}|s\rangle|^2$")
125ax2.axvline(T_star, color="#ff6f61", ls="--", lw=1.4,
126            label=fr"$T^*={T_star:.2f}$")
127ax2.legend(loc="upper right", fontsize=8, framealpha=0.9)
128cbar = plt.colorbar(im, ax=ax2)
129cbar.set_label(r"probability at node $i$")
130
131# C4 graph inset (square with target highlighted)
132inset = fig.add_axes([0.04, 0.55, 0.16, 0.32])
133inset.set_xlim(-1.3, 1.3)
134inset.set_ylim(-1.3, 1.3)
135inset.set_aspect("equal")
136inset.axis("off")
137theta = (np.arange(N) * 2 * np.pi / N + np.pi / 2)
138xs, ys = np.cos(theta), np.sin(theta)
139for i in range(N):
140    j = (i + 1) % N
141    inset.plot([xs[i], xs[j]], [ys[i], ys[j]], "k-", lw=1.6)
142for n in range(N):
143    fc = "#d62728" if n == TARGET else "#cccccc"
144    ec = "black"
145    inset.scatter(xs[n], ys[n], s=420, c=fc, ec=ec, lw=1.2, zorder=3)
146    inset.text(xs[n], ys[n], str(n), ha="center", va="center",
147               fontsize=11, fontweight="bold",
148               color="white" if n != TARGET else "white", zorder=4)
149inset.set_title("C4 with target node 0", fontsize=9)
150
151plt.suptitle("ch12-quantum-graphs demo 3: Childs–Goldstone spatial search on C4",
152             y=1.02)
153plt.tight_layout()
154out_path = OUT / "03_spatial_search.png"
155plt.savefig(out_path, dpi=120, bbox_inches="tight")
156plt.close()
157
158# === 6. stdout 关键统计 ===
159peak_idx = int(np.argmax(target_probs_q))
160peak_t = float(t_quant[peak_idx])
161print(f"\n  search parameters: N={N}, target=node {TARGET}, γ={GAMMA:.4f}")
162print(f"  theory search time T* = π·√N/2 = {T_star:.3f}")
163print(f"  observed P(target) peak = {target_probs_q[peak_idx]:.3f} at t={peak_t:.2f}")
164print(f"  P(target) at classical uniform 1/N = {1.0/N:.3f}")
165print(f"  P(target) at classical step {N} = {target_probs_c[N]:.3f}")
166print(f"  P(target) at classical max ({T_CLASS_MAX} steps) = "
167      f"{target_probs_c.max():.3f}")
168print(f"  speedup at first peak: quantum t≈{peak_t:.2f} vs classical O(N)={N} steps")
169print(f"  H eigvals (rad/s): {np.round(np.linalg.eigvalsh(H), 3).tolist()}")
170print(f"  shots used in uniqc sanity: 2000")
171print(f"  PNG -> {out_path}")

运行结果

Demo 3:Childs-Goldstone 空间搜索

运行方式

# 仓库根目录执行;输出 PNG 到 demos/ch12-quantum-graphs/03_spatial_search.png,关键统计到 stdout
.venv/bin/python3 demos/ch12-quantum-graphs/03_spatial_search.py

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