مهندس کوانتومی

21. الگوریتم برنشتاین–وازیرانی (Bernstein–Vazirani)

21.1رشته‌های پنهان

برنشتاین و وازیرانی (Bernstein–Vazirani) در ۱۹۹۳ به‌جای گزاره، رشته‌ای را پنهان کردند: f(x) = a·x ⊕ b = (a₁x₁ ⊕ … ⊕ aₙxₙ) ⊕ b، و تکلیف، بازیابی رشتهٔ پنهان a است. ثابت b در اورکل لانه کرده و خواهیم دید که قرارداد کیوبیت کمکی بی‌اثرش می‌کند. این نتیجه از نظر تاریخی مهم است چون نخستین جدایی در برابر الگوریتم‌های کلاسیک خطای محدود بود — BQP در برابر BPP در جهان اورکل — و حلقه‌ای را که دویچ–یوزا باز گذاشته بود بست. همچنین نخستین الگوریتمی است که خروجی‌اش یک رشته است نه یک حکم تک‌بیتی.

21.2ساخت اورکل

Uf: |x⟩|y⟩ ↦ |x⟩|y ⊕ a·x ⊕ b⟩ از گیت‌های کلاسیک برگشت‌پذیر ساخنی است: برای هر i که aᵢ = 1، یک CNOT از کیوبیت ورودی i به کیوبیت کمکی توازی را حساب می‌کند، به‌علاوه یک X روی کمکی اگر b = 1. حالا کمکی را در |−⟩ بگذرانید. هر CNOT آن‌وقت فازی پس می‌زند: CNOT_{i→a}|x⟩|−⟩ = (−1)^{aᵢxᵢ}|x⟩|−⟩ — باز هم پس‌زنی فاز — پس کل اورکل روی ثبات ورودی به‌صورت (−1)^{a·x ⊕ b} = (−1)^b·(−1)^{a·x} عمل می‌کند. ضریب سراسری (−1)^b مشاهده‌ناپذیر است؛ b با قرارداد کمکی پاک شده و فقط الگوی فازی a می‌ماند.

21.3راه‌حل کوانتومی

q0 … q(n-1):  |0> ─H─●─H─M     readout = a, with certainty
                 │
q_n:          |1> ─H─Uf──      Uf: |x>|y> ↦ |x>|y ⊕ (a·x ⊕ b)>

مدار عیناً همان دویچ–یوزاست — فقط ساختار موعودشدهٔ f عوض شده. پس از اورکل ثبات ورودی (1/√2ⁿ)·Σ_x (−1)^{a·x}|x⟩ را نگه می‌دارد. اعمال H^{⊗n} (که |x⟩ → (1/√2ⁿ)·Σ_y (−1)^{x·y}|y⟩) دامنهٔ حالت پایهٔ y را چنین می‌دهد: (1/2ⁿ)·Σ_x (−1)^{x·(a⊕y)} — جمعی از ±1 روی 2ⁿ جمله که اگر y = a برابر ۱ و در غیر این صورت ۰ است، با همان حذفِ ۲۰.۴. اندازه‌گیری هر بار، دقیقاً a را برمی‌گرداند؛ بدون shot.

21.4مقایسهٔ کلاسیک

هر پرس‌وجوی کلاسیک یک معادلهٔ خطی a·x = c در بیت‌های مجهول a₁…aₙ برمی‌گرداند؛ پیش از معین‌شدن a به n معادلهٔ مستقل خطی نیاز است — کران پایین اطلاعات‌نظری، نه آرتیفکت طراحی الگوریتم. الگوریتم کوانتومی هر n بیت را در یک پرس‌وجو استخراج می‌کند. توضیح صادقانه این نیست که «همهٔ 2ⁿ ورودی را موازی پرس‌وجو کرد»: یک بار پرس‌وجو کرد، اما روی برهم‌نهی، و عمل هم‌زمان اورکل روی همهٔ ورودی‌هاست که اجازه می‌دهد یک اندازه‌گیری سراسری، تابع خطی را آشکار کند. این نخستین جدایی اورکلی BQP در برابر BPP بود و جامعه را قانع کرد که کران‌های پایین کلاسیکِ تصادفی، مزیت کوانتومی را حل نمی‌کنند.

21.5پیاده‌سازی

import numpy as np
n, a, b = 4, 0b1011, 1
N = 2 ** n
H1 = np.array([[1, 1], [1, -1]]) / np.sqrt(2)
Hn = H1
for _ in range(n - 1):
    Hn = np.kron(Hn, H1)                       # والش–هادامارد روی n کیوبیت
f = np.array([(bin(x & a).count("1") + b) % 2 for x in range(N)])
psi = np.ones(N, dtype=complex) / np.sqrt(N)   # H روی همهٔ ورودی‌ها
psi *= (-1.0) ** f                             # اورکل به‌صورت فاز (کمکی |->)
psi = Hn @ psi                                 # هاداماردهای نهایی
y = int(np.argmax(np.abs(psi)))
print(f"recovered a = {y:04b}   expected a = {a:04b}   exact: {y == a}")

میان‌بُر را ببینید: وقتی کیوبیت کمکی را تحلیلی و به‌صورت |−⟩ دنبال می‌کنیم، اورکل عین فاز قطری (−1)^{f(x)} است — نیازی به شبیه‌سازی 2n بعدی نیست. Hn که از کرونکرکردن بلوک‌های ۲×۲ ساخته می‌شود تبدیل والش–هادامارد است، نه FFT؛ برای f(x) = a·x روی ضرب داخلی بیتی این دو با هم فرق دارند.