Langkau ke kandungan utama

Algoritma Grover

Anggaran penggunaan: kurang dari satu minit pada pemproses Eagle r3 (NOTA: Ini adalah anggaran sahaja. Masa larian anda mungkin berbeza.)

Hasil pembelajaran

Setelah menyelesaikan tutorial ini, anda dijangka dapat memahami maklumat berikut:

  • Cara membina oracle Grover yang menandakan satu atau lebih keadaan asas pengiraan
  • Cara menggunakan fungsi grover_operator() daripada perpustakaan Circuit Qiskit
  • Cara menentukan bilangan iterasi Grover yang optimum untuk masalah tertentu
  • Cara melaksanakan algoritma Grover menggunakan primitif Sampler Qiskit Runtime

Prasyarat

Adalah disyorkan agar anda membiasakan diri dengan topik-topik berikut:

Latar belakang

Amplifikasi amplitud ialah algoritma kuantum atau subrutin tujuan umum yang boleh digunakan untuk mendapatkan pecutan kuadratik berbanding beberapa algoritma klasik. Algoritma Grover adalah yang pertama menunjukkan pecutan ini pada masalah carian tidak berstruktur. Untuk merumuskan masalah carian Grover, kita memerlukan fungsi oracle yang menandakan satu atau lebih keadaan asas pengiraan sebagai keadaan yang ingin kita cari, dan Circuit amplifikasi yang meningkatkan amplitud keadaan yang ditandakan, seterusnya menekan keadaan yang lain.

Di sini, kami menunjukkan cara membina oracle Grover dan menggunakan grover_operator() dari perpustakaan Circuit Qiskit untuk menyediakan instans carian Grover dengan mudah. Primitif Sampler masa jalan membolehkan pelaksanaan Circuit Grover dengan lancar.

Keperluan

Sebelum memulakan tutorial ini, pastikan anda telah memasang yang berikut:

  • Qiskit SDK v2.0 atau lebih baharu, dengan sokongan visualisasi
  • Qiskit Runtime v0.22 atau lebih baharu (pip install qiskit-ibm-runtime)

Persediaan

# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib qiskit qiskit-ibm-runtime
# Built-in modules
import math

# Imports from Qiskit
from qiskit import QuantumCircuit
from qiskit.circuit.library import grover_operator, MCMTGate, ZGate
from qiskit.visualization import plot_distribution
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

# Imports from Qiskit Runtime
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import SamplerV2 as Sampler

def grover_oracle(marked_states):
"""Build a Grover oracle for multiple marked states

Here we assume all input marked states have the same number of bits

Parameters:
marked_states (str or list): Marked states of oracle

Returns:
QuantumCircuit: Quantum circuit representing Grover oracle
"""
if not isinstance(marked_states, list):
marked_states = [marked_states]
# Compute the number of qubits in circuit
num_qubits = len(marked_states[0])

qc = QuantumCircuit(num_qubits)
# Mark each target state in the input list
for target in marked_states:
# Flip target bit-string to match Qiskit bit-ordering
rev_target = target[::-1]
# Find the indices of all the '0' elements in bit-string
zero_inds = [
ind
for ind in range(num_qubits)
if rev_target.startswith("0", ind)
]
# Add a multi-controlled Z-gate with pre- and post-applied X-gates (open-controls)
# where the target bit-string has a '0' entry
if zero_inds:
qc.x(zero_inds)
qc.compose(MCMTGate(ZGate(), num_qubits - 1, 1), inplace=True)
if zero_inds:
qc.x(zero_inds)
return qc

Contoh simulator skala kecil

Dalam bahagian ini, kita akan melalui setiap langkah algoritma Grover pada skala kecil menggunakan simulator tempatan, sebelum menjalankan masalah yang sama pada perkakasan kuantum sebenar.

Langkah 1: Petakan input klasik kepada masalah kuantum

Algoritma Grover memerlukan sebuah oracle yang menentukan satu atau lebih keadaan asas pengiraan yang ditandakan, di mana "ditandakan" bermaksud keadaan dengan fasa -1. Gate controlled-Z, atau generalisasi multi-controlled-nya ke atas NN qubit, menandakan keadaan 2N12^{N}-1 ('1'*NN bit-string). Menandakan keadaan asas dengan satu atau lebih '0' dalam perwakilan binari memerlukan penerapan X-Gate pada qubit yang berkaitan sebelum dan selepas gate controlled-Z, yang bersamaan dengan mempunyai open-control pada qubit tersebut. Dalam kod berikut, kita takrifkan oracle yang menandakan satu atau lebih keadaan asas input yang ditakrifkan melalui perwakilan bitstring mereka. Gate MCMT digunakan untuk melaksanakan gate Z multi-controlled.

Instans Grover tertentu

Sekarang kita dah ada fungsi oracle, kita boleh takrifkan instans carian Grover yang tertentu. Dalam contoh ini kita akan menandakan dua keadaan pengiraan daripada lapan yang tersedia dalam ruang pengiraan tiga qubit:

marked_states = ["011", "100"]

oracle = grover_oracle(marked_states)
oracle.draw(output="mpl", style="iqp")

Output of the previous code cell

Operator Grover

Fungsi grover_operator() terbina dalam Qiskit mengambil Circuit oracle dan mengembalikan Circuit yang terdiri daripada Circuit oracle itu sendiri serta Circuit yang mengamplifikasi keadaan yang ditandakan oleh oracle. Di sini, kita gunakan kaedah decompose() pada Circuit untuk melihat gate dalam operator tersebut:

grover_op = grover_operator(oracle)
grover_op.decompose().draw(output="mpl", style="iqp")

Output of the previous code cell

Pengulangan penerapan Circuit grover_op ini akan mengamplifikasi keadaan yang ditandakan, menjadikannya bit-string yang paling mungkin dalam taburan output dari Circuit. Terdapat bilangan penerapan optimum yang ditentukan oleh nisbah keadaan yang ditandakan kepada jumlah keseluruhan keadaan pengiraan yang mungkin:

optimal_num_iterations = math.floor(
math.pi
/ (4 * math.asin(math.sqrt(len(marked_states) / 2**grover_op.num_qubits)))
)

Circuit Grover penuh

Eksperimen Grover yang lengkap bermula dengan gate Hadamard pada setiap qubit; mencipta superposisi sekata bagi semua keadaan asas pengiraan, diikuti dengan operator Grover (grover_op) yang diulang sebanyak bilangan optimum. Di sini kita menggunakan kaedah QuantumCircuit.power(INT) untuk menerapkan operator Grover secara berulang.

qc = QuantumCircuit(grover_op.num_qubits)
# Create even superposition of all basis states
qc.h(range(grover_op.num_qubits))
# Apply Grover operator the optimal number of times
qc.compose(grover_op.power(optimal_num_iterations), inplace=True)
# Measure all qubits
qc.measure_all()
qc.draw(output="mpl", style="iqp")

Output of the previous code cell

Langkah 2: Optimumkan masalah untuk pelaksanaan perkakasan kuantum

Untuk simulasi skala kecil ini, kita transpilkan Circuit tanpa menyasarkan perkakasan tertentu.

pm = generate_preset_pass_manager(optimization_level=3)
circuit_isa = pm.run(qc)
circuit_isa.draw(output="mpl", idle_wires=False, style="iqp")

Output of the previous code cell

Langkah 3: Laksanakan menggunakan primitif Qiskit

Amplifikasi amplitud ialah masalah pensampelan yang sesuai untuk dilaksanakan dengan primitif SamplerV2. Di sini kita gunakan StatevectorSampler daripada qiskit.primitives untuk simulasi tempatan.

from qiskit.primitives import StatevectorSampler

sampler = StatevectorSampler()
result = sampler.run([circuit_isa], shots=10_000).result()
dist = result[0].data.meas.get_counts()

Langkah 4: Proses selepas dan kembalikan keputusan dalam format klasik yang dikehendaki

plot_distribution(dist)

Output of the previous code cell

Contoh perkakasan

Langkah 1-4

Algoritma Grover pada dasarnya ialah algoritma tahan kesalahan — gate Z multi-controlled yang menjadi teras oracle dan operator peresapan membawa kepada kedalaman gate dua-Qubit yang berkembang sangat pesat dengan bilangan qubit (seperti yang akan kita tunjukkan dalam bahagian seterusnya). Ini bermakna algoritma ini tidak berskala dengan baik pada perkakasan bising masa kini. Atas sebab itu, kita menunjukkan pelaksanaan perkakasan pada skala kecil yang sama seperti contoh simulator di atas, daripada mencuba saiz masalah yang lebih besar.

# -------------------------Step 1-------------------------
marked_states = ["011", "100"]

oracle = grover_oracle(marked_states)
grover_op = grover_operator(oracle)

optimal_num_iterations = math.floor(
math.pi
/ (4 * math.asin(math.sqrt(len(marked_states) / 2**grover_op.num_qubits)))
)

qc = QuantumCircuit(grover_op.num_qubits)
qc.h(range(grover_op.num_qubits))
qc.compose(grover_op.power(optimal_num_iterations), inplace=True)
qc.measure_all()

# -------------------------Step 2-------------------------
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)

target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
circuit_isa = pm.run(qc)

# -------------------------Step 3-------------------------
sampler = Sampler(mode=backend)
sampler.options.default_shots = 10_000
sampler.options.environment.job_tags = ["TUT-GA"]
result = sampler.run([circuit_isa]).result()
dist = result[0].data.meas.get_counts()

# -------------------------Step 4-------------------------
plot_distribution(dist)

Output of the previous code cell

Perbincangan: Penskalaan kedalaman gate dua-Qubit

Sebab utama algoritma Grover dianggap sebagai algoritma tahan kesalahan ialah pertumbuhan pesat kedalaman gate dua-Qubit Circuit apabila bilangan qubit meningkat. Gate Z multi-controlled yang menjadi teras oracle dan operator peresapan terurai kepada bilangan gate dua-Qubit yang berkembang secara eksponen dengan bilangan qubit kawalan. Digabungkan dengan fakta bahawa bilangan iterasi Grover optimum itu sendiri berkembang sebagai O(2n)O(\sqrt{2^n}), kedalaman dua-Qubit keseluruhan menjadi tidak praktikal untuk perkakasan bising dengan cepat.

Di bawah, kita membina Circuit Grover untuk bilangan qubit yang semakin meningkat, mentranspilkannya, dan memplot kedalaman gate dua-Qubit yang terhasil untuk menggambarkan penskalaan ini.

import matplotlib.pyplot as plt

num_qubits_list = list(range(3, 10))
two_q_depths = []
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)
for n in num_qubits_list:
# Mark a single state for simplicity
marked = ["1" * n]
oracle_n = grover_oracle(marked)
grover_op_n = grover_operator(oracle_n)

# Optimal number of iterations
num_iters = math.floor(
math.pi / (4 * math.asin(math.sqrt(len(marked) / 2**n)))
)

# Build the full Grover circuit
qc_n = QuantumCircuit(n)
qc_n.h(range(n))
qc_n.compose(grover_op_n.power(num_iters), inplace=True)
qc_n.measure_all()

# Transpile to a basis gate set and count 2Q depth
pm_n = generate_preset_pass_manager(backend=backend, optimization_level=3)
qc_transpiled = pm_n.run(qc_n)

# Compute depth restricted to 2-qubit operations
depth_2q = qc_transpiled.depth(lambda x: x.operation.num_qubits == 2)

two_q_depths.append(depth_2q)
print(f"n={n}: optimal_iters={num_iters}, 2Q depth={depth_2q}")

# Plot
fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(
num_qubits_list,
two_q_depths,
"o-",
linewidth=2,
markersize=8,
color="#6929C4",
)
ax.set_xlabel("Number of qubits", fontsize=13)
ax.set_ylabel("Two-qubit gate depth", fontsize=13)
ax.set_title("Grover's algorithm: 2Q depth scaling", fontsize=14)
ax.set_yscale("log")
ax.grid(True, alpha=0.3)
ax.set_xticks(num_qubits_list)
plt.tight_layout()
plt.show()
n=3: optimal_iters=2, 2Q depth=39
n=4: optimal_iters=3, 2Q depth=111
n=5: optimal_iters=4, 2Q depth=466
n=6: optimal_iters=6, 2Q depth=1646
n=7: optimal_iters=8, 2Q depth=3550
n=8: optimal_iters=12, 2Q depth=7989
n=9: optimal_iters=17, 2Q depth=14824

Output of the previous code cell

Seperti yang ditunjukkan oleh plot, kedalaman gate dua-Qubit berkembang dengan sangat pesat mengikut bilangan qubit — lebih kurang secara eksponen. Ini menjadikan algoritma Grover tidak praktikal pada perkakasan kuantum bising masa kini di luar saiz masalah yang sangat kecil. Algoritma ini tetap menjadi sasaran penting untuk komputer kuantum tahan kesalahan masa depan, di mana pembetulan ralat akan membolehkan Circuit yang dalam dilaksanakan dengan boleh dipercayai.

Langkah seterusnya

Cadangan

Jika anda mendapati kerja ini menarik, anda mungkin berminat dengan bahan berikut: