Demo 2:Bernstein-Vazirani

第 4 章 经典量子算法 · 本章演示 · 代码演示总索引

可视化:双子图(测量柱+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'}")

运行结果

Demo 2:Bernstein-Vazirani

运行方式

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

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