Demo 2:Bernstein-Vazirani¶
可视化:双子图(测量柱+oracle 示意) —— 4-qubit 一次查询读出隐藏 s=1011
对应教程:第 4 章 经典量子算法 中相关小节 · 依赖安装:pip install "unified-quantum[visualization,simulation]"
实现要点¶
经典查询需要 n=4 次, BV 算法只用 1 次即可读出 s. 构造 Oracle: f(x) = s . x (mod 2), 对 s 的每一位 s_i=1 的输入 qubit 施加 CNOT(i, output). 末态 H 后测量, 应 100% 命中 s.
完整源码¶
demos/ch04-classic-algorithms/02_bv_4qubit.py¶
1"""
2ch04 演示 2: Bernstein-Vazirani 算法, n=4, 隐藏字符串 s=1011.
3经典查询需要 n=4 次, BV 算法只用 1 次即可读出 s.
4构造 Oracle: f(x) = s . x (mod 2), 对 s 的每一位 s_i=1
5的输入 qubit 施加 CNOT(i, output). 末态 H 后测量, 应 100% 命中 s.
6
7对应教程: chenzhaoyun.com/quantum-tutorial/ch04-classic-algorithms/bernstein-vazirani-algorithm-tutorial.html
8依赖: pip install unified-quantum[visualization]
9运行: python demos/ch04-classic-algorithms/02_bv_4qubit.py
10"""
11from uniqc import Circuit, submit_task, wait_for_result
12import matplotlib
13matplotlib.use("Agg")
14import matplotlib.pyplot as plt
15import numpy as np
16from pathlib import Path
17
18OUT = Path(__file__).parent
19SHOTS = 2000
20N_INPUT = 4
21N_OUTPUT = 1
22N_QUBITS = N_INPUT + N_OUTPUT
23S = (1, 0, 1, 1) # hidden string, s_0 s_1 s_2 s_3
24S_STR = "".join(str(b) for b in S)
25
26
27def build_bv_circuit(secret_bits):
28 """构造完整的 BV 电路: X on output, H on all, oracle (CNOT chains),
29 H on input, 测量 input. secret_bits 是 (s_0, ..., s_{n-1}) 元组."""
30 c = Circuit()
31 c.x(N_INPUT)
32 for q in range(N_QUBITS):
33 c.h(q)
34 for i, s_i in enumerate(secret_bits):
35 if s_i == 1:
36 c.cnot(i, N_INPUT)
37 for q in range(N_INPUT):
38 c.h(q)
39 for q in range(N_INPUT):
40 c.measure(q)
41 return c
42
43
44c_bv = build_bv_circuit(S)
45tid = submit_task(circuit=c_bv, backend="dummy:local:simulator", shots=SHOTS)
46result = wait_for_result(tid)
47counts = result.counts
48
49total = sum(counts.values())
50labels = [f"{i:0{N_INPUT}b}" for i in range(2 ** N_INPUT)]
51
52# bitstring 在 uniqc counts 中是反向的: bitstring[i] = qubit[n-1-i], 长度等于 n_qubits.
53# 未被测量的 qubit (这里是 q[4], output) 在 bitstring 中默认为 0, 不影响输入解读.
54def key_to_input_bits(bs):
55 """把 counts 里的 bitstring 截取成 q[0..3] 的输入比特串."""
56 return bs[-(N_INPUT):][::-1]
57
58
59input_counts = {}
60for bs, cnt in counts.items():
61 inp = key_to_input_bits(bs)
62 input_counts[inp] = input_counts.get(inp, 0) + cnt
63vals = np.array([input_counts.get(lbl, 0) for lbl in labels])
64
65correct_counts = 0
66mismatches = []
67for inp, cnt in input_counts.items():
68 if inp == S_STR:
69 correct_counts += cnt
70 else:
71 mismatches.append((inp, cnt))
72
73
74fig, axes = plt.subplots(1, 2, figsize=(13, 4.8))
75
76ax = axes[0]
77colors = ["#d62728" if lbl == S_STR else "#1f77b4" for lbl in labels]
78ax.bar(np.arange(len(labels)), vals / total * 100, color=colors, edgecolor="black")
79ax.set_xticks(np.arange(len(labels)))
80ax.set_xticklabels(labels, rotation=0, fontsize=8)
81ax.set_xlabel("input register measurement (q3 q2 q1 q0)")
82ax.set_ylabel("probability (%)")
83ax.set_title(
84 f"BV measurement on input qubits\nred bar = s = {S_STR}, expect 100%"
85)
86for i, lbl in enumerate(labels):
87 if vals[i] > 0:
88 ax.text(i, vals[i] / total * 100 + 1.5,
89 f"{vals[i]/total*100:.1f}%", ha="center", va="bottom", fontsize=7)
90ax.set_ylim(0, 115)
91ax.grid(axis="y", alpha=0.3)
92
93ax = axes[1]
94ax.barh(range(N_INPUT), [1 if b == 1 else 0 for b in S[::-1]],
95 color="#1f77b4", edgecolor="black")
96ax.set_yticks(range(N_INPUT))
97ax.set_yticklabels([f"q[{i}] (s_{i})" for i in range(N_INPUT - 1, -1, -1)])
98ax.set_xticks([0, 1])
99ax.set_xticklabels(["0", "1"])
100ax.set_xlabel("oracle bit s_i (1 = CNOT(q[i], output) is applied)")
101ax.set_title(f"Oracle structure for s = {S_STR}\nf(x) = x_0 XOR x_2 XOR x_3 (mod 2)")
102ax.set_xlim(-0.05, 1.4)
103for i, b in enumerate(S[::-1]):
104 if b == 1:
105 ax.text(1.05, i, "CNOT", va="center", fontsize=9, color="darkred")
106ax.grid(axis="x", alpha=0.3)
107
108fig.suptitle(
109 f"Bernstein-Vazirani n={N_INPUT}, s={S_STR} "
110 f"(shots={SHOTS}, dummy:local:simulator)",
111 fontsize=12, y=1.02,
112)
113plt.tight_layout()
114plt.savefig(OUT / "02_bv_4qubit.png", dpi=120, bbox_inches="tight")
115plt.close()
116
117
118p_correct = correct_counts / total
119print("ch04-classic-algorithms demo 2: Bernstein-Vazirani n=4, s=1011")
120print(f" shots: {total}")
121print(f" hidden string: s = {S_STR}")
122print(f" P(measured = s) = {p_correct:.4f}")
123print(f" unique measurement outcomes: {int((vals > 0).sum())}")
124if mismatches:
125 print(f" mismatches (top 3): {mismatches[:3]}")
126else:
127 print(" no mismatches: every shot recovered s exactly")
128print(f" saved: {OUT / '02_bv_4qubit.png'}")
运行结果¶

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