Algoritma Shor
Estimasi penggunaan: Tiga detik pada prosesor Eagle r3 (CATATAN: Ini hanya perkiraan. Waktu eksekusi kamu bisa berbeda.)
Algoritma Shor, yang dikembangkan oleh Peter Shor pada tahun 1994, adalah algoritma kuantum revolusioner untuk memfaktorkan bilangan bulat dalam waktu polinomial. Signifikansinya terletak pada kemampuannya memfaktorkan bilangan bulat besar secara eksponensial lebih cepat dari algoritma klasik mana pun yang diketahui, mengancam keamanan sistem kriptografi yang banyak digunakan seperti RSA, yang bergantung pada sulitnya memfaktorkan bilangan besar. Dengan menyelesaikan masalah ini secara efisien pada komputer kuantum yang cukup powerful, algoritma Shor berpotensi merevolusi bidang-bidang seperti kriptografi, keamanan siber, dan matematika komputasi — menegaskan kekuatan transformatif dari komputasi kuantum.
Tutorial ini berfokus pada demonstrasi algoritma Shor dengan memfaktorkan 15 di komputer kuantum.
Pertama, kita mendefinisikan masalah pencarian orde dan membangun Circuit yang sesuai dari protokol estimasi fase kuantum. Selanjutnya, kita menjalankan Circuit pencarian orde di hardware nyata menggunakan Circuit dengan kedalaman terpendek yang bisa kita transpilasikan. Bagian terakhir melengkapi algoritma Shor dengan menghubungkan masalah pencarian orde ke faktorisasi bilangan bulat.
Kita mengakhiri tutorial ini dengan diskusi tentang demonstrasi lain dari algoritma Shor di hardware nyata, berfokus pada implementasi generik maupun yang disesuaikan untuk memfaktorkan bilangan bulat tertentu seperti 15 dan 21. Catatan: Tutorial ini lebih berfokus pada implementasi dan demonstrasi Circuit yang berkaitan dengan algoritma Shor. Untuk sumber edukasi yang lebih mendalam tentang materi ini, silakan lihat kursus Fundamentals of quantum algorithms oleh Dr. John Watrous, dan makalah-makalah di bagian Referensi.
Persyaratan​
Sebelum memulai tutorial ini, pastikan kamu sudah menginstal:
- Qiskit SDK v2.0 atau lebih baru, dengan dukungan visualisasi
- Qiskit Runtime v0.40 atau lebih baru (
pip install qiskit-ibm-runtime)
Persiapan​
# Added by doQumentation — required packages for this notebook
!pip install -q numpy pandas qiskit qiskit-ibm-runtime
import numpy as np
import pandas as pd
from fractions import Fraction
from math import floor, gcd, log
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.circuit.library import QFT, UnitaryGate
from qiskit.transpiler import CouplingMap, generate_preset_pass_manager
from qiskit.visualization import plot_histogram
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import SamplerV2 as Sampler
Langkah 1: Memetakan input klasik ke masalah kuantum​
Latar belakang​
Algoritma Shor untuk faktorisasi bilangan bulat menggunakan masalah perantara yang dikenal sebagai masalah pencarian orde. Di bagian ini, kita mendemonstrasikan cara menyelesaikan masalah pencarian orde menggunakan estimasi fase kuantum.
Masalah estimasi fase​
Dalam masalah estimasi fase, kita diberikan keadaan kuantum dari Qubit, bersama dengan Circuit kuantum yang bekerja pada Qubit. Kita dijanjikan bahwa adalah vektor eigen dari matriks uniter yang menggambarkan aksi Circuit tersebut, dan tujuan kita adalah menghitung atau mendekati nilai eigen yang berkorespondensi dengan . Dengan kata lain, Circuit harus menghasilkan aproksimasi dari bilangan yang memenuhi
Tujuan dari Circuit estimasi fase adalah untuk mengaproksimasi dalam bit. Secara matematis, kita ingin menemukan sedemikian sehingga , di mana . Gambar berikut menunjukkan Circuit kuantum yang mengestimasi dalam bit dengan melakukan pengukuran pada Qubit.
Pada Circuit di atas, Qubit teratas diinisialisasi dalam keadaan , dan Qubit terbawah diinisialisasi dalam , yang dijanjikan sebagai vektor eigen dari . Komponen pertama dalam Circuit estimasi fase adalah operasi uniter terkontrol yang bertanggung jawab melakukan phase kickback ke Qubit kontrol yang bersesuaian. Uniter-uniter terkontrol ini dipangkatkan sesuai posisi Qubit kontrol, mulai dari bit paling tidak signifikan hingga bit paling signifikan. Karena adalah vektor eigen dari , keadaan Qubit bawah tidak terpengaruh oleh operasi ini, tetapi informasi fase dari nilai eigen merambat ke Qubit teratas.
Ternyata, setelah operasi phase kickback melalui uniter-uniter terkontrol, semua keadaan yang mungkin dari Qubit teratas saling ortogonal untuk setiap vektor eigen dari uniter . Oleh karena itu, keadaan-keadaan ini dapat dibedakan dengan sempurna, dan kita dapat memutar basis yang mereka bentuk kembali ke basis komputasi untuk melakukan pengukuran. Analisis matematis menunjukkan bahwa matriks rotasi ini berkorespondensi dengan transformasi Fourier kuantum invers (QFT) dalam ruang Hilbert berdimensi . Intuisi di balik ini adalah bahwa struktur periodik dari operator eksponensiasi modular dikodekan dalam keadaan kuantum, dan QFT mengubah periodisitas ini menjadi puncak yang terukur dalam domain frekuensi.
Untuk pemahaman yang lebih mendalam tentang mengapa Circuit QFT digunakan dalam algoritma Shor, kita merujuk pembaca ke kursus Fundamentals of quantum algorithms. Kita sekarang siap menggunakan Circuit estimasi fase untuk pencarian orde.
Masalah pencarian orde​
Untuk mendefinisikan masalah pencarian orde, kita mulai dengan beberapa konsep teori bilangan. Pertama, untuk setiap bilangan bulat positif , definisikan himpunan sebagai Semua operasi aritmetika di dilakukan modulo . Khususnya, semua elemen yang koprima dengan bersifat istimewa dan membentuk sebagai Untuk suatu elemen , bilangan bulat positif terkecil sedemikian sehingga didefinisikan sebagai orde dari modulo . Seperti yang akan kita lihat nanti, menemukan orde dari akan memungkinkan kita memfaktorkan . Untuk membangun Circuit pencarian orde dari Circuit estimasi fase, kita perlu dua pertimbangan. Pertama, kita perlu mendefinisikan uniter yang akan memungkinkan kita menemukan orde , dan kedua, kita perlu mendefinisikan vektor eigen dari untuk mempersiapkan keadaan awal Circuit estimasi fase.
Untuk menghubungkan masalah pencarian orde ke estimasi fase, kita mempertimbangkan operasi yang didefinisikan pada sistem yang keadaan klasiknya berkorespondensi dengan , di mana kita mengalikan dengan elemen tetap . Khususnya, kita mendefinisikan operator perkalian sedemikian sehingga untuk setiap . Perlu dicatat bahwa secara implisit kita mengambil hasil perkalian modulo di dalam ket di ruas kanan persamaan. Analisis matematis menunjukkan bahwa adalah operator uniter. Lebih lanjut, ternyata memiliki pasangan vektor eigen dan nilai eigen yang memungkinkan kita menghubungkan orde dari ke masalah estimasi fase. Secara spesifik, untuk pilihan mana pun, kita memiliki bahwa adalah vektor eigen dari yang nilai eigennya berkorespondensi adalah , di mana Dari pengamatan, kita melihat bahwa pasangan vektor eigen/nilai eigen yang nyaman adalah keadaan dengan . Oleh karena itu, jika kita bisa menemukan vektor eigen , kita bisa mengestimasi fase dengan Circuit kuantum kita dan dengan demikian mendapatkan estimasi orde . Namun, hal itu tidak mudah dilakukan, dan kita perlu mempertimbangkan alternatif lain.
Mari kita pertimbangkan apa yang akan dihasilkan Circuit jika kita mempersiapkan keadaan komputasi sebagai keadaan awal. Ini bukan keadaan eigen dari , tetapi merupakan superposisi seragam dari keadaan-keadaan eigen yang baru saja kita deskripsikan. Dengan kata lain, relasi berikut berlaku. Implikasi dari persamaan di atas adalah bahwa jika kita menetapkan keadaan awal ke , kita akan memperoleh hasil pengukuran yang persis sama seolah-olah kita telah memilih secara seragam acak dan menggunakan sebagai vektor eigen dalam Circuit estimasi fase. Dengan kata lain, pengukuran pada Qubit teratas menghasilkan aproksimasi dari nilai di mana dipilih secara seragam acak. Ini memungkinkan kita mempelajari dengan tingkat keyakinan yang tinggi setelah beberapa eksekusi independen, yang merupakan tujuan kita.
Operator eksponensiasi modular​
Sejauh ini, kita menghubungkan masalah estimasi fase ke masalah pencarian orde dengan mendefinisikan dan dalam Circuit kuantum kita. Oleh karena itu, bahan terakhir yang tersisa adalah menemukan cara efisien untuk mendefinisikan eksponen modular dari sebagai untuk . Untuk melakukan komputasi ini, kita menemukan bahwa untuk pangkat mana pun yang kita pilih, kita dapat membuat Circuit untuk bukan dengan mengiterasi kali Circuit untuk , melainkan dengan menghitung dan kemudian menggunakan Circuit untuk . Karena kita hanya membutuhkan pangkat yang merupakan pangkat dua itu sendiri, kita dapat melakukan ini secara efisien secara klasik menggunakan pengkuadratan iteratif.
Langkah 2: Mengoptimalkan masalah untuk eksekusi pada hardware kuantum​
Contoh spesifik dengan dan ​
Kita bisa berhenti sejenak di sini untuk mendiskusikan contoh spesifik dan membangun Circuit pencarian orde untuk . Perhatikan bahwa kemungkinan yang non-trivial untuk adalah . Untuk contoh ini, kita pilih . Kita akan membangun operator dan operator eksponensiasi modular . Aksi dari pada keadaan basis komputasi adalah sebagai berikut. Dari pengamatan, kita bisa melihat bahwa keadaan basis diacak, sehingga kita memiliki matriks permutasi. Kita dapat membangun operasi ini pada empat Qubit dengan Gate swap. Di bawah ini, kita membangun operasi dan controlled-.
def M2mod15():
"""
M2 (mod 15)
"""
b = 2
U = QuantumCircuit(4)
U.swap(2, 3)
U.swap(1, 2)
U.swap(0, 1)
U = U.to_gate()
U.name = f"M_{b}"
return U
# Get the M2 operator
M2 = M2mod15()
# Add it to a circuit and plot
circ = QuantumCircuit(4)
circ.compose(M2, inplace=True)
circ.decompose(reps=2).draw(output="mpl", fold=-1)
def controlled_M2mod15():
"""
Controlled M2 (mod 15)
"""
b = 2
U = QuantumCircuit(4)
U.swap(2, 3)
U.swap(1, 2)
U.swap(0, 1)
U = U.to_gate()
U.name = f"M_{b}"
c_U = U.control()
return c_U
# Get the controlled-M2 operator
controlled_M2 = controlled_M2mod15()
# Add it to a circuit and plot
circ = QuantumCircuit(5)
circ.compose(controlled_M2, inplace=True)
circ.decompose(reps=1).draw(output="mpl", fold=-1)
Gate yang bekerja pada lebih dari dua Qubit akan didekomposisi lebih lanjut menjadi Gate dua Qubit.
circ.decompose(reps=2).draw(output="mpl", fold=-1)

Sekarang kita perlu membangun operator eksponensiasi modular. Untuk mendapatkan presisi yang cukup dalam estimasi fase, kita akan menggunakan delapan Qubit untuk pengukuran estimasi. Oleh karena itu, kita perlu membangun dengan untuk setiap .
def a2kmodN(a, k, N):
"""Compute a^{2^k} (mod N) by repeated squaring"""
for _ in range(k):
a = int(np.mod(a**2, N))
return a
k_list = range(8)
b_list = [a2kmodN(2, k, 15) for k in k_list]
print(b_list)
[2, 4, 1, 1, 1, 1, 1, 1]
Seperti yang bisa kita lihat dari daftar nilai , selain yang sebelumnya kita bangun, kita juga perlu membangun dan . Perhatikan bahwa bekerja secara trivial pada keadaan basis komputasi, sehingga ini hanyalah operator identitas.
bekerja pada keadaan basis komputasi sebagai berikut.
Oleh karena itu, permutasi ini dapat dibangun dengan operasi swap berikut.
def M4mod15():
"""
M4 (mod 15)
"""
b = 4
U = QuantumCircuit(4)
U.swap(1, 3)
U.swap(0, 2)
U = U.to_gate()
U.name = f"M_{b}"
return U
# Get the M4 operator
M4 = M4mod15()
# Add it to a circuit and plot
circ = QuantumCircuit(4)
circ.compose(M4, inplace=True)
circ.decompose(reps=2).draw(output="mpl", fold=-1)
def controlled_M4mod15():
"""
Controlled M4 (mod 15)
"""
b = 4
U = QuantumCircuit(4)
U.swap(1, 3)
U.swap(0, 2)
U = U.to_gate()
U.name = f"M_{b}"
c_U = U.control()
return c_U
# Get the controlled-M4 operator
controlled_M4 = controlled_M4mod15()
# Add it to a circuit and plot
circ = QuantumCircuit(5)
circ.compose(controlled_M4, inplace=True)
circ.decompose(reps=1).draw(output="mpl", fold=-1)
Gate yang bekerja pada lebih dari dua Qubit akan didekomposisi lebih lanjut menjadi Gate dua Qubit.
circ.decompose(reps=2).draw(output="mpl", fold=-1)

Kita melihat bahwa operator untuk tertentu adalah operasi permutasi. Karena ukuran masalah permutasi yang relatif kecil di sini, karena hanya membutuhkan empat Qubit, kita bisa mensintesis operasi ini langsung dengan Gate SWAP secara inspeksi. Secara umum, ini mungkin bukan pendekatan yang skalabel. Sebagai gantinya, kita mungkin perlu membangun matriks permutasi secara eksplisit, dan menggunakan kelas UnitaryGate dari Qiskit serta metode transpilasi untuk mensintesis matriks permutasi ini. Namun, hal ini dapat menghasilkan Circuit yang jauh lebih dalam. Contohnya sebagai berikut.
def mod_mult_gate(b, N):
"""
Modular multiplication gate from permutation matrix.
"""
if gcd(b, N) > 1:
print(f"Error: gcd({b},{N}) > 1")
else:
n = floor(log(N - 1, 2)) + 1
U = np.full((2**n, 2**n), 0)
for x in range(N):
U[b * x % N][x] = 1
for x in range(N, 2**n):
U[x][x] = 1
G = UnitaryGate(U)
G.name = f"M_{b}"
return G
# Let's build M2 using the permutation matrix definition
M2_other = mod_mult_gate(2, 15)
# Add it to a circuit
circ = QuantumCircuit(4)
circ.compose(M2_other, inplace=True)
circ = circ.decompose()
# Transpile the circuit and get the depth
coupling_map = CouplingMap.from_line(4)
pm = generate_preset_pass_manager(coupling_map=coupling_map)
transpiled_circ = pm.run(circ)
print(f"qubits: {circ.num_qubits}")
print(
f"2q-depth: {transpiled_circ.depth(lambda x: x.operation.num_qubits==2)}"
)
print(f"2q-size: {transpiled_circ.size(lambda x: x.operation.num_qubits==2)}")
print(f"Operator counts: {transpiled_circ.count_ops()}")
transpiled_circ.decompose().draw(
output="mpl", fold=-1, style="clifford", idle_wires=False
)
qubits: 4
2q-depth: 94
2q-size: 96
Operator counts: OrderedDict({'cx': 45, 'swap': 32, 'u': 24, 'u1': 7, 'u3': 4, 'unitary': 3, 'circuit-335': 1, 'circuit-338': 1, 'circuit-341': 1, 'circuit-344': 1, 'circuit-347': 1, 'circuit-350': 1, 'circuit-353': 1, 'circuit-356': 1, 'circuit-359': 1, 'circuit-362': 1, 'circuit-365': 1, 'circuit-368': 1, 'circuit-371': 1, 'circuit-374': 1, 'circuit-377': 1, 'circuit-380': 1})

Mari kita bandingkan jumlah ini dengan kedalaman Circuit yang telah dikompilasi dari implementasi manual Gate kita.
# Get the M2 operator from our manual construction
M2 = M2mod15()
# Add it to a circuit
circ = QuantumCircuit(4)
circ.compose(M2, inplace=True)
circ = circ.decompose(reps=3)
# Transpile the circuit and get the depth
coupling_map = CouplingMap.from_line(4)
pm = generate_preset_pass_manager(coupling_map=coupling_map)
transpiled_circ = pm.run(circ)
print(f"qubits: {circ.num_qubits}")
print(
f"2q-depth: {transpiled_circ.depth(lambda x: x.operation.num_qubits==2)}"
)
print(f"2q-size: {transpiled_circ.size(lambda x: x.operation.num_qubits==2)}")
print(f"Operator counts: {transpiled_circ.count_ops()}")
transpiled_circ.draw(
output="mpl", fold=-1, style="clifford", idle_wires=False
)
qubits: 4
2q-depth: 9
2q-size: 9
Operator counts: OrderedDict({'cx': 9})
Seperti yang bisa kita lihat, pendekatan matriks permutasi menghasilkan Circuit yang jauh lebih dalam bahkan untuk satu Gate saja dibandingkan implementasi manual kita. Oleh karena itu, kita akan melanjutkan dengan implementasi operasi sebelumnya. Sekarang, kita siap membangun Circuit pencarian orde lengkap menggunakan operator eksponensiasi modular terkontrol yang telah kita definisikan sebelumnya. Dalam kode berikut, kita juga mengimpor Circuit QFT dari pustaka Circuit Qiskit, yang menggunakan Gate Hadamard pada setiap Qubit, serangkaian Gate controlled-U1 (atau Z, tergantung fasenya), dan lapisan Gate swap.
# Order finding problem for N = 15 with a = 2
N = 15
a = 2
# Number of qubits
num_target = floor(log(N - 1, 2)) + 1 # for modular exponentiation operators
num_control = 2 * num_target # for enough precision of estimation
# List of M_b operators in order
k_list = range(num_control)
b_list = [a2kmodN(2, k, 15) for k in k_list]
# Initialize the circuit
control = QuantumRegister(num_control, name="C")
target = QuantumRegister(num_target, name="T")
output = ClassicalRegister(num_control, name="out")
circuit = QuantumCircuit(control, target, output)
# Initialize the target register to the state |1>
circuit.x(num_control)
# Add the Hadamard gates and controlled versions of the
# multiplication gates
for k, qubit in enumerate(control):
circuit.h(k)
b = b_list[k]
if b == 2:
circuit.compose(
M2mod15().control(), qubits=[qubit] + list(target), inplace=True
)
elif b == 4:
circuit.compose(
M4mod15().control(), qubits=[qubit] + list(target), inplace=True
)
else:
continue # M1 is the identity operator
# Apply the inverse QFT to the control register
circuit.compose(QFT(num_control, inverse=True), qubits=control, inplace=True)
# Measure the control register
circuit.measure(control, output)
circuit.draw("mpl", fold=-1)
Perhatikan bahwa kita menghilangkan operasi eksponensiasi modular terkontrol dari Qubit kontrol yang tersisa karena adalah operator identitas.
Perhatikan bahwa nantinya dalam tutorial ini, kita akan menjalankan Circuit ini pada Backend ibm_marrakesh. Untuk melakukan ini, kita mentranspilasi Circuit sesuai Backend spesifik ini dan melaporkan kedalaman Circuit serta jumlah Gate.
service = QiskitRuntimeService()
backend = service.backend("ibm_marrakesh")
pm = generate_preset_pass_manager(optimization_level=2, backend=backend)
transpiled_circuit = pm.run(circuit)
print(
f"2q-depth: {transpiled_circuit.depth(lambda x: x.operation.num_qubits==2)}"
)
print(
f"2q-size: {transpiled_circuit.size(lambda x: x.operation.num_qubits==2)}"
)
print(f"Operator counts: {transpiled_circuit.count_ops()}")
transpiled_circuit.draw(
output="mpl", fold=-1, style="clifford", idle_wires=False
)
2q-depth: 187
2q-size: 260
Operator counts: OrderedDict({'sx': 521, 'rz': 354, 'cz': 260, 'measure': 8, 'x': 4})

Langkah 3: Eksekusi menggunakan Qiskit primitives​
Pertama, kita bahas apa yang secara teoritis akan kita dapatkan jika menjalankan Circuit ini di simulator ideal. Di bawah ini ada sekumpulan hasil simulasi dari Circuit di atas menggunakan 1024 shots. Seperti terlihat, kita mendapatkan distribusi yang kira-kira seragam di empat bitstring pada control qubit.
# Obtained from the simulator
counts = {"00000000": 264, "01000000": 268, "10000000": 249, "11000000": 243}
plot_histogram(counts)
Dengan mengukur control qubit, kita mendapatkan estimasi fase delapan-bit dari operator . Kita bisa mengonversi representasi biner ini ke desimal untuk menemukan fase yang terukur. Seperti terlihat dari histogram di atas, empat bitstring berbeda diukur, dan masing-masing berkorespondensi dengan nilai fase sebagai berikut.
# Rows to be displayed in table
rows = []
# Corresponding phase of each bitstring
measured_phases = []
for output in counts:
decimal = int(output, 2) # Convert bitstring to decimal
phase = decimal / (2**num_control) # Find corresponding eigenvalue
measured_phases.append(phase)
# Add these values to the rows in our table:
rows.append(
[
f"{output}(bin) = {decimal:>3}(dec)",
f"{decimal}/{2 ** num_control} = {phase:.2f}",
]
)
# Print the rows in a table
headers = ["Register Output", "Phase"]
df = pd.DataFrame(rows, columns=headers)
print(df)
Register Output Phase
0 00000000(bin) = 0(dec) 0/256 = 0.00
1 01000000(bin) = 64(dec) 64/256 = 0.25
2 10000000(bin) = 128(dec) 128/256 = 0.50
3 11000000(bin) = 192(dec) 192/256 = 0.75
Ingat bahwa setiap fase yang terukur berkorespondensi dengan di mana diambil secara acak merata dari . Oleh karena itu, kita bisa menggunakan algoritma continued fractions untuk mencoba menemukan dan orde . Python sudah memiliki fungsionalitas ini secara bawaan. Kita bisa menggunakan modul fractions untuk mengubah float menjadi objek Fraction, misalnya:
Fraction(0.666)
Fraction(5998794703657501, 9007199254740992)
Karena ini menghasilkan pecahan yang mengembalikan hasil secara tepat (dalam kasus ini, 0.6660000...), hasilnya bisa jadi rumit seperti di atas. Kita bisa menggunakan metode .limit_denominator() untuk mendapatkan pecahan yang paling mendekati float kita, dengan penyebut di bawah nilai tertentu:
# Get fraction that most closely resembles 0.666
# with denominator < 15
Fraction(0.666).limit_denominator(15)
Fraction(2, 3)
Ini jauh lebih rapi. Orde (r) harus lebih kecil dari N, jadi kita akan menetapkan penyebut maksimum menjadi 15:
# Rows to be displayed in a table
rows = []
for phase in measured_phases:
frac = Fraction(phase).limit_denominator(15)
rows.append(
[phase, f"{frac.numerator}/{frac.denominator}", frac.denominator]
)
# Print the rows in a table
headers = ["Phase", "Fraction", "Guess for r"]
df = pd.DataFrame(rows, columns=headers)
print(df)
Phase Fraction Guess for r
0 0.00 0/1 1
1 0.25 1/4 4
2 0.50 1/2 2
3 0.75 3/4 4
Kita bisa melihat bahwa dua dari nilai eigen yang terukur memberi kita hasil yang benar: , dan kita bisa melihat bahwa algoritma Shor untuk order finding punya kemungkinan gagal. Hasil yang buruk ini terjadi karena , atau karena dan tidak koprima — dan alih-alih mendapatkan , kita mendapatkan faktor dari . Solusi paling mudah adalah dengan mengulangi eksperimen sampai kita mendapatkan hasil yang memuaskan. Sejauh ini, kita mengimplementasikan masalah order finding untuk dengan menggunakan Circuit estimasi fase di simulator. Langkah terakhir dari algoritma Shor adalah menghubungkan masalah order finding dengan masalah faktorisasi bilangan bulat. Bagian terakhir dari algoritma ini murni klasikal dan bisa diselesaikan di komputer klasik setelah pengukuran fase diperoleh dari komputer kuantum. Oleh karena itu, kita menunda bagian terakhir algoritma sampai setelah kita mendemonstrasikan cara menjalankan Circuit order finding di hardware nyata.
Eksekusi di hardware​
Sekarang kita bisa menjalankan Circuit order finding yang sebelumnya sudah kita transpile untuk ibm_marrakesh. Di sini kita beralih ke dynamical decoupling (DD) untuk penekanan error, dan gate twirling untuk mitigasi error. DD melibatkan penerapan serangkaian pulsa kontrol yang waktunya tepat pada perangkat kuantum, secara efektif merata-ratakan interaksi lingkungan yang tidak diinginkan dan dekoherensi. Gate twirling, di sisi lain, mengacak Gate kuantum tertentu untuk mengubah coherent error menjadi Pauli error, yang terakumulasi secara linear bukan kuadratik. Kedua teknik ini sering digabungkan untuk meningkatkan koherensi dan fidelitas komputasi kuantum.
# Sampler primitive to obtain the probability distribution
sampler = Sampler(backend)
# Turn on dynamical decoupling with sequence XpXm
sampler.options.dynamical_decoupling.enable = True
sampler.options.dynamical_decoupling.sequence_type = "XpXm"
# Enable gate twirling
sampler.options.twirling.enable_gates = True
pub = transpiled_circuit
job = sampler.run([pub], shots=1024)
result = job.result()[0]
counts = result.data["out"].get_counts()
plot_histogram(counts, figsize=(35, 5))

Seperti terlihat, kita mendapatkan bitstring yang sama dengan jumlah tertinggi. Karena hardware kuantum memiliki noise, ada sedikit kebocoran ke bitstring lain yang bisa kita saring secara statistik.
# Dictionary of bitstrings and their counts to keep
counts_keep = {}
# Threshold to filter
threshold = np.max(list(counts.values())) / 2
for key, value in counts.items():
if value > threshold:
counts_keep[key] = value
print(counts_keep)
{'00000000': 58, '01000000': 41, '11000000': 42, '10000000': 40}
Langkah 4: Pasca-proses dan kembalikan hasil dalam format klasikal yang diinginkan​
Faktorisasi Bilangan Bulat​
Sejauh ini, kita membahas cara mengimplementasikan masalah order finding menggunakan Circuit estimasi fase. Sekarang, kita hubungkan masalah order finding dengan faktorisasi bilangan bulat, yang melengkapi algoritma Shor. Perlu diingat bahwa bagian algoritma ini bersifat klasikal. Kita sekarang mendemonstrasikan ini menggunakan contoh dan . Ingat bahwa fase yang kita ukur adalah , di mana dan adalah bilangan bulat acak antara dan . Dari persamaan ini, kita punya yang berarti harus membagi . Jika juga genap, maka kita bisa menulis Jika tidak genap, kita tidak bisa melanjutkan dan harus mencoba lagi dengan nilai yang berbeda; jika tidak, ada probabilitas tinggi bahwa greatest common divisor dari dan salah satu dari , atau adalah faktor sejati dari .
Karena beberapa eksekusi algoritma akan gagal secara statistik, kita akan mengulang algoritma ini sampai setidaknya satu faktor dari ditemukan. Sel di bawah mengulang algoritma sampai setidaknya satu faktor dari ditemukan. Kita akan menggunakan hasil eksekusi hardware di atas untuk menebak fase dan faktor yang berkorespondensi di setiap iterasi.
a = 2
N = 15
FACTOR_FOUND = False
num_attempt = 0
while not FACTOR_FOUND:
print(f"\nATTEMPT {num_attempt}:")
# Here, we get the bitstring by iterating over outcomes
# of a previous hardware run with multiple shots.
# Instead, we can also perform a single-shot measurement
# here in the loop.
bitstring = list(counts_keep.keys())[num_attempt]
num_attempt += 1
# Find the phase from measurement
decimal = int(bitstring, 2)
phase = decimal / (2**num_control) # phase = k / r
print(f"Phase: theta = {phase}")
# Guess the order from phase
frac = Fraction(phase).limit_denominator(N)
r = frac.denominator # order = r
print(f"Order of {a} modulo {N} estimated as: r = {r}")
if phase != 0:
# Guesses for factors are gcd(a^{r / 2} ± 1, 15)
if r % 2 == 0:
x = pow(a, r // 2, N) - 1
d = gcd(x, N)
if d > 1:
FACTOR_FOUND = True
print(f"*** Non-trivial factor found: {x} ***")
ATTEMPT 0:
Phase: theta = 0.0
Order of 2 modulo 15 estimated as: r = 1
ATTEMPT 1:
Phase: theta = 0.25
Order of 2 modulo 15 estimated as: r = 4
*** Non-trivial factor found: 3 ***
Diskusi​
Karya terkait​
Di bagian ini, kita membahas karya-karya penting lainnya yang telah mendemonstrasikan algoritma Shor di hardware nyata.
Karya seminal [3] dari IBM® mendemonstrasikan algoritma Shor untuk pertama kalinya, memfaktorkan angka 15 menjadi faktor prima 3 dan 5 menggunakan komputer kuantum nuclear magnetic resonance (NMR) tujuh-Qubit. Eksperimen lain [4] memfaktorkan 15 menggunakan qubit fotonik. Dengan memanfaatkan satu Qubit yang didaur ulang berkali-kali dan mengenkode register kerja dalam keadaan dimensi lebih tinggi, para peneliti mengurangi jumlah Qubit yang dibutuhkan menjadi sepertiga dari protokol standar, menggunakan algoritma yang dikompilasi dua-foton. Makalah penting dalam demonstrasi algoritma Shor adalah [5], yang menggunakan teknik iterative phase estimation Kitaev [8] untuk mengurangi kebutuhan Qubit dari algoritma. Para penulis menggunakan tujuh control qubit dan empat cache qubit, bersama dengan implementasi modular multiplier. Namun, implementasi ini memerlukan pengukuran mid-circuit dengan operasi feed-forward dan daur ulang Qubit dengan operasi reset. Demonstrasi ini dilakukan pada komputer kuantum ion-trap.
Karya yang lebih baru [6] berfokus pada pemfaktoran 15, 21, dan 35 di hardware IBM Quantum®. Mirip dengan karya sebelumnya, para peneliti menggunakan versi kompilasi dari algoritma yang menggunakan semi-classical quantum Fourier transform seperti yang diusulkan Kitaev untuk meminimalkan jumlah Qubit fisik dan Gate. Karya paling baru [7] juga melakukan demonstrasi proof-of-concept untuk memfaktorkan bilangan bulat 21. Demonstrasi ini juga melibatkan penggunaan versi kompilasi dari rutinitas quantum phase estimation, dan membangun di atas demonstrasi sebelumnya oleh [4]. Para penulis melampaui karya tersebut dengan menggunakan konfigurasi approximate Toffoli gate dengan residual phase shift. Algoritma ini diimplementasikan di prosesor IBM quantum hanya menggunakan lima Qubit, dan keberadaan entanglement antara control qubit dan register qubit berhasil diverifikasi.
Skalabilitas algoritma​
Perlu dicatat bahwa enkripsi RSA biasanya melibatkan ukuran kunci sekitar 2048 hingga 4096 bit. Mencoba memfaktorkan angka 2048-bit dengan algoritma Shor akan menghasilkan Circuit kuantum dengan jutaan Qubit, termasuk overhead koreksi error dan kedalaman Circuit sekitar satu miliar, yang melampaui batas hardware kuantum saat ini untuk dieksekusi. Oleh karena itu, algoritma Shor akan memerlukan metode konstruksi Circuit yang dioptimalkan atau koreksi error kuantum yang andal agar praktis layak untuk membobol sistem kriptografi modern. Kami merujuk Anda ke [9] untuk diskusi lebih rinci tentang estimasi sumber daya untuk algoritma Shor.
Tantangan​
Selamat telah menyelesaikan tutorial ini! Sekarang adalah waktu yang tepat untuk menguji pemahaman Anda. Bisakah Anda mencoba membangun Circuit untuk memfaktorkan 21? Anda bisa memilih sesuai pilihan Anda sendiri. Anda perlu menentukan akurasi bit dari algoritma untuk memilih jumlah Qubit, dan Anda perlu merancang operator modular exponentiation . Kami mendorong Anda untuk mencoba sendiri, lalu membaca tentang metodologi yang ditunjukkan di Fig. 9 dari [6] dan Fig. 2 dari [7].
def M_a_mod21():
"""
M_a (mod 21)
"""
# Your code here
pass
Referensi​
- Shor, Peter W. "Polynomial-time algorithms for prime factorization and discrete logarithms on a quantum computer." SIAM review 41.2 (1999): 303-332.
- IBM Quantum Fundamentals of Quantum Algorithms course by Dr. John Watrous.
- Vandersypen, Lieven MK, et al. "Experimental realization of Shor's quantum factoring algorithm using nuclear magnetic resonance." Nature 414.6866 (2001): 883-887.
- Martin-Lopez, Enrique, et al. "Experimental realization of Shor's quantum factoring algorithm using qubit recycling." Nature photonics 6.11 (2012): 773-776.
- Monz, Thomas, et al. "Realization of a scalable Shor algorithm." Science 351.6277 (2016): 1068-1070.
- Amico, Mirko, Zain H. Saleem, and Muir Kumph. "Experimental study of Shor's factoring algorithm using the IBM Q Experience." Physical Review A 100.1 (2019): 012305.
- Skosana, Unathi, and Mark Tame. "Demonstration of Shor's factoring algorithm for N=21 on IBM quantum processors." Scientific reports 11.1 (2021): 16599.
- Kitaev, A. Yu. "Quantum measurements and the Abelian stabilizer problem." arXiv preprint quant-ph/9511026 (1995).
- Gidney, Craig, and Martin Ekerå. "How to factor 2048 bit RSA integers in 8 hours using 20 million noisy qubits." Quantum 5 (2021): 433.