Bernstein-Vazirani Algorithm
With a single oracle query, recover a hidden n-bit string s from a
black-box function f(x)=s·x — where any classical deterministic query algorithm needs n queries in
the worst case; even a randomized algorithm with high success probability still needs Ω(n) queries.
The problem it solves
Someone has fixed a hidden bit-string s and handed you an oracle that computes the
mod-2 inner product of s with your input x:
f(x) = s·x = (s0x0 ⊕ s1x1 ⊕ … ⊕ sn−1xn−1)
Your job is to determine s. Classically, each query returns just one parity bit,
so you are forced to probe one position at a time: use x = 100…0 to read s0,
x = 010…0 to read s1, and so on. For a classical deterministic algorithm, getting
all n bits takes n queries.
| Hidden string length n | Classical queries | Bernstein–Vazirani |
|---|---|---|
| 8 | 8 | 1 |
| 64 | 64 | 1 |
| 1000 | 1000 | 1 |
From O(n) to O(1): however long s is, the quantum algorithm asks just once.
Intuition — reading every bit in one question
The classical limitation is that each input "flattens" the entire hidden string into a single parity
bit, discarding the detail. Bernstein–Vazirani instead feeds all 2n inputs through the
oracle in a uniform superposition at once, letting the oracle write every bit of s
simultaneously into the phase structure of the state; a layer of Hadamards then "decodes" those
phases back to the computational basis, so that s appears directly as the measurement
result.
Why it works — the Hadamard sandwich and phase kickback
As in Deutsch, first prepare the auxiliary qubit in |−⟩. Then the oracle
|x⟩|y⟩ → |x⟩|y⊕f(x)⟩ reduces to a pure phase acting on the data register:
|x⟩ → (−1)s·x |x⟩
Applying the oracle to the uniform superposition (1/√2n) Σx |x⟩ tags
every basis state |x⟩ with the phase (−1)s·x. The key identity is that
under an n-qubit Hadamard,
H⊗n (1/√2n) Σx (−1)s·x |x⟩ = |s⟩
In other words, a uniform superposition phased by (−1)s·x, run through a
Hadamard transform, undergoes constructive interference toward |s⟩ and destructive
interference that erases everything else. So the closing Hadamard sandwich turns the
phase-encoded hidden string exactly back into the computational basis state |s⟩, and one
measurement reads out all n bits.
The mechanism
| Step | Role |
|---|---|
| Prepare |−⟩ auxiliary | Makes the oracle act by phase kickback: writes (−1)s·x onto the data register. |
| First Hadamard layer | Prepares the uniform superposition of all inputs, so one query covers every x. |
| Oracle | Encodes every bit of the hidden string s into each basis state's phase (−1)s·x. |
| Final Hadamard layer | Decodes the phase encoding into the computational basis state |s⟩ via interference. |
What it shows — and what it doesn't
- A deterministic, exponential query advantage. The n→1 speedup is deterministic and holds every run — but the advantage is in query complexity, not the speed of general computation.
- It is a close cousin of Deutsch–Jozsa. The same Hadamard-sandwich-plus-kickback skeleton is used here to read out an entire string at once, rather than to decide a single global bit.
- The oracle must genuinely encode
s. It is the oracle's internal structure (which positions are controlled) that carries the answer; the algorithm only extracts it efficiently — it cannot guess from nothing. - It is a stepping stone to deeper algorithms. The same interference-based decoding idea is pushed to far more powerful forms in the period-finding of Simon's and Shor's algorithms.
The algorithm, step by step
- Prepare the auxiliary qubit in
|−⟩(xthenh). - Apply
hto the n data qubits, making a uniform superposition of all inputs. - Call the oracle; via phase kickback, each basis state acquires the phase
(−1)s·x. - Apply
hto the data register again; interference converges onto|s⟩. - Measure the data register and read off
sdirectly.
Seeing it in code
Read it against the theory above: x(aux); h(aux) prepares the auxiliary in
|−⟩; the first h(q) makes the n-qubit uniform superposition; the for
loop is the oracle — it places an x.ctrl(q[i], aux) only on the positions where
secret[i] == 1, writing the inner product s·x into the phase by kickback; the
closing h(q) completes the decoding, and mz(q) hands back the hidden string. In
the example secret = [1,0,1,1], so the counts peak at "1011".
If a backend displays bit strings with a different endianness, the output string may appear
reversed; it still corresponds to the same hidden string. This page interprets outputs in
q[0], q[1], … order.
import qalgora
@qalgora.kernel
def bv(secret: list[int]):
n = len(secret)
q = qalgora.qvector(n)
aux = qalgora.qubit()
x(aux); h(aux)
h(q)
for i in range(n): # oracle encodes the secret string
if secret[i] == 1:
x.ctrl(q[i], aux)
h(q)
mz(q)
print(qalgora.sample(bv, [1, 0, 1, 1])) # peaks at "1011"
secret (say to [1,1,1,1,0,0,1,0]) and watch the counts peak move exactly
onto that string — no matter how long s is, the oracle is still called only once, in sharp
contrast to the bit-by-bit classical approach. The Deutsch algorithm page
shows the same phase-kickback mechanism that underpins this one.
References
- E. Bernstein and U. Vazirani, "Quantum complexity theory," SIAM J. Comput. 26(5), 1411-1473 (1997). doi:10.1137/S0097539796300921
Bernstein-Vazirani 算法
仅凭一次谕示(oracle)查询,从黑盒函数 f(x)=s·x 中恢复出隐藏的 n 比特串 s——而任何确定性经典查询算法在最坏情况下需要 n 次查询;若允许随机算法并要求高成功率,查询复杂度仍为 Ω(n) 量级。
它解决的问题
有人选定了一个隐藏比特串 s,并交给你一个谕示,它计算 s 与你的输入 x 的带模 2 内积:
f(x) = s·x = (s0x0 ⊕ s1x1 ⊕ … ⊕ sn−1xn−1)
你的任务是确定 s。经典上,每次查询只能问回一个奇偶比特,因此你只能逐位试探:用 x = 100…0 问出 s0,用 x = 010…0 问出 s1,依此类推。对确定性经典算法而言,要拿全 n 个比特,就要 n 次查询。
| 隐藏串长度 n | 经典查询次数 | Bernstein–Vazirani |
|---|---|---|
| 8 | 8 | 1 |
| 64 | 64 | 1 |
| 1000 | 1000 | 1 |
从 O(n) 到 O(1):无论 s 多长,量子算法都只问一次。
直觉 一次问出全部比特
经典查询的局限在于:每个输入都把整个隐藏串"压扁"成一个奇偶比特,丢掉了细节。Bernstein–Vazirani 的思路是把所有 2n 个输入做成均匀叠加同时喂给谕示,让谕示把 s 的每一位都同时写进量子态的相位结构里;随后用一层 Hadamard 把这些相位"解码"回计算基,使 s 直接显形为测量结果。
为何成立 Hadamard 夹心与相位回踢
与 Deutsch 一样,先把辅助比特预备为 |−⟩。这样谕示 |x⟩|y⟩ → |x⟩|y⊕f(x)⟩ 就退化为对数据寄存器的纯相位作用:
|x⟩ → (−1)s·x |x⟩
对均匀叠加 (1/√2n) Σx |x⟩ 施加谕示后,每个基矢 |x⟩ 都带上了 (−1)s·x 的相位。关键恒等式是:对 n 比特施加 Hadamard 时,
H⊗n (1/√2n) Σx (−1)s·x |x⟩ = |s⟩
也就是说,"被 (−1)s·x 调相的均匀叠加"经 Hadamard 变换后,会发生相长干涉指向 |s⟩、相消干涉抹去其余一切。于是末端的 Hadamard 夹层把相位编码的隐藏串精确地还原成计算基态 |s⟩,单次测量即可读出全部 n 位。
核心机制
| 步骤 | 作用 |
|---|---|
| 制备 |−⟩ 辅助比特 | 令谕示以相位回踢形式生效:把 (−1)s·x 写到数据寄存器上。 |
| 首层 Hadamard | 制备全体输入的均匀叠加,使一次查询覆盖所有 x。 |
| 谕示 | 把隐藏串 s 的每一位编码进各基矢的相位 (−1)s·x。 |
| 末层 Hadamard | 通过干涉把相位编码解码为计算基态 |s⟩。 |
它能说明什么 又不能说明什么
- 确定性、指数级的查询优势。n→1 的加速是确定的、每次都成立——但优势体现在查询复杂度上,而非通用计算的速度。
- 它是 Deutsch–Jozsa 的近亲。同一套 Hadamard 夹心加相位回踢的骨架,这里被用来一次性读出整个串,而非仅判断一个全局比特。
- 谕示必须真把
s编码进去。是谕示内部结构(哪些位被控制)携带了答案;算法只是高效地把它抽取出来,并不能凭空猜测。 - 它是更深算法的垫脚石。同样的干涉式解码思想,在 Simon 算法和 Shor 算法的周期查找中被推向更强大的形态。
算法逐步拆解
- 把辅助比特预备为
|−⟩(先x再h)。 - 对 n 个数据比特施加
h,制备所有输入的均匀叠加。 - 调用谕示;通过相位回踢,每个基矢获得相位
(−1)s·x。 - 对数据寄存器再施加
h,干涉收敛到|s⟩。 - 测量数据寄存器,直接读出
s。
对照代码理解
请对照上文原理来读:x(aux); h(aux) 把辅助比特制成 |−⟩;首个 h(q) 制备 n 比特均匀叠加;for 循环就是谕示——只在 secret[i] == 1 的位上放一条 x.ctrl(q[i], aux),从而把内积 s·x 经相位回踢写入相位;末端 h(q) 完成解码,mz(q) 便直接给出隐藏串。示例中 secret = [1,0,1,1],故计数峰落在 "1011"。
若后端采用不同的比特串显示端序,输出字符串可能按相反顺序显示;物理含义仍对应同一个隐藏串。本文默认按 q[0], q[1], ... 的顺序解释输出。
import qalgora
@qalgora.kernel
def bv(secret: list[int]):
n = len(secret)
q = qalgora.qvector(n)
aux = qalgora.qubit()
x(aux); h(aux)
h(q)
for i in range(n): # oracle encodes the secret string
if secret[i] == 1:
x.ctrl(q[i], aux)
h(q)
mz(q)
print(qalgora.sample(bv, [1, 0, 1, 1])) # peaks at "1011"
secret(例如 [1,1,1,1,0,0,1,0]),观察计数峰精确移到那串比特上——无论 s 多长,谕示始终只被调用一次。这与逐位试探的经典做法形成鲜明对照。Deutsch 算法展示了支撑这里的同一套相位回踢机制。
参考文献
- E. Bernstein and U. Vazirani, "Quantum complexity theory," SIAM J. Comput. 26(5), 1411-1473 (1997). doi:10.1137/S0097539796300921