Fungsi kos
Dalam pelajaran ini, kita akan belajar cara menilai sebuah fungsi kos:
- Pertama, kita akan belajar tentang primitif Qiskit Runtime
- Tentukan sebuah fungsi kos . Ini adalah fungsi khusus masalah yang mentakrifkan matlamat masalah untuk pengoptimum meminimumkan (atau memaksimumkan)
- Menentukan strategi pengukuran dengan primitif Qiskit Runtime untuk mengoptimumkan kelajuan berbanding ketepatan
Primitif
Semua sistem fizikal, sama ada klasik atau kuantum, boleh wujud dalam pelbagai keadaan. Sebagai contoh, sebuah kereta di jalan raya boleh mempunyai jisim, kedudukan, kelajuan, atau pecutan tertentu yang mencirikan keadaannya. Begitu juga, sistem kuantum juga boleh mempunyai pelbagai konfigurasi atau keadaan, tetapi ia berbeza daripada sistem klasik dari segi cara kita mengendalikan pengukuran dan evolusi keadaan. Ini membawa kepada sifat unik seperti superposisi dan keterikatan yang eksklusif kepada mekanik kuantum. Sama seperti kita boleh menerangkan keadaan kereta menggunakan sifat fizikal seperti kelajuan atau pecutan, kita juga boleh menerangkan keadaan sistem kuantum menggunakan boleh cerapan (observables), yang merupakan objek matematik.
Dalam mekanik kuantum, keadaan diwakili oleh vektor lajur kompleks yang ternormal, atau ket (), dan boleh cerapan adalah pengoperasi linear Hermitian () yang bertindak ke atas ket. Vektor eigen () bagi sesuatu boleh cerapan dikenali sebagai eigenstate. Mengukur sesuatu boleh cerapan untuk salah satu eigenstatenya () akan menghasilkan nilai eigen () yang sepadan sebagai bacaan.
Jika Anda tertanya-tanya cara mengukur sistem kuantum dan apa yang boleh diukur, Qiskit menawarkan dua primitif yang boleh membantu:
Sampler: Diberi keadaan kuantum , primitif ini mendapatkan kebarangkalian setiap keadaan asas pengiraan yang mungkin.Estimator: Diberi boleh cerapan kuantum dan keadaan , primitif ini mengira nilai jangkaan .
Primitif Sampler
Primitif Sampler mengira kebarangkalian mendapatkan setiap keadaan yang mungkin daripada asas pengiraan, diberi litar kuantum yang menyediakan keadaan . Ia mengira
Di mana adalah bilangan qubit, dan ialah perwakilan integer bagi mana-mana rentetan binari output yang mungkin (iaitu, integer asas ).
Sampler Qiskit Runtime menjalankan litar beberapa kali pada peranti kuantum, melakukan pengukuran pada setiap jalankan, dan membina semula taburan kebarangkalian daripada rentetan bit yang diperoleh. Lebih banyak jalankan (atau shots) yang dilakukan, semakin tepat hasilnya, tetapi ini memerlukan lebih banyak masa dan sumber kuantum.
Walau bagaimanapun, oleh kerana bilangan output yang mungkin meningkat secara eksponen dengan bilangan qubit (iaitu, ), bilangan shots juga perlu meningkat secara eksponen bagi menangkap taburan kebarangkalian yang padat. Oleh itu, Sampler hanya cekap untuk taburan kebarangkalian yang jarang; di mana keadaan sasaran mestilah boleh dinyatakan sebagai gabungan linear bagi keadaan asas pengiraan, dengan bilangan sebutan yang meningkat paling banyak secara polinomial dengan bilangan qubit:
Sampler juga boleh dikonfigurasi untuk mendapatkan kebarangkalian daripada bahagian litar, yang mewakili subset bagi semua keadaan yang mungkin.
Primitif Estimator
Primitif Estimator mengira nilai jangkaan bagi boleh cerapan untuk keadaan kuantum ; di mana kebarangkalian boleh cerapan boleh dinyatakan sebagai , dengan ialah eigenstate bagi boleh cerapan . Nilai jangkaan kemudiannya ditakrifkan sebagai purata semua hasil yang mungkin (iaitu, nilai eigen bagi boleh cerapan) bagi pengukuran keadaan , berpemberat dengan kebarangkalian yang sepadan:
Walau bagaimanapun, mengira nilai jangkaan sesuatu boleh cerapan tidak selalunya boleh dilakukan, kerana kita sering tidak tahu asas eigennya. Estimator Qiskit Runtime menggunakan proses algebra yang kompleks untuk menganggar nilai jangkaan pada peranti kuantum sebenar dengan menguraikan boleh cerapan tersebut kepada gabungan boleh cerapan lain yang asas eigennya kita sudah ketahui.
Secara lebih mudah, Estimator menguraikan mana-mana boleh cerapan yang tidak tahu cara mengukurnya kepada boleh cerapan yang lebih mudah dan boleh diukur yang dipanggil pengoperasi Pauli.
Mana-mana pengoperasi boleh dinyatakan sebagai gabungan pengoperasi Pauli.
sedemikian
di mana adalah bilangan qubit, untuk (iaitu, integer asas ), dan .
Selepas melakukan penguraian ini, Estimator menghasilkan litar baru untuk setiap boleh cerapan (daripada litar asal), untuk secara efektif mendiagonalkan boleh cerapan Pauli dalam asas pengiraan dan mengukurnya. Kita boleh mengukur boleh cerapan Pauli dengan mudah kerana kita tahu lebih awal, yang tidak berlaku secara umum untuk boleh cerapan lain.
Untuk setiap , Estimator menjalankan litar yang sepadan pada peranti kuantum beberapa kali, mengukur keadaan output dalam asas pengiraan, dan mengira kebarangkalian untuk mendapatkan setiap output yang mungkin . Ia kemudian mencari nilai eigen bagi yang sepadan dengan setiap output , darabkan dengan , dan tambah semua hasilnya untuk mendapatkan nilai jangkaan boleh cerapan bagi keadaan yang diberikan.
Oleh kerana mengira nilai jangkaan Pauli adalah tidak praktikal (iaitu, pertumbuhan eksponen), Estimator hanya boleh cekap apabila banyak adalah sifar (iaitu, penguraian Pauli yang jarang berbanding padat). Secara formal kita katakan bahawa, agar pengiraan ini boleh diselesaikan dengan cekap, bilangan sebutan bukan sifar mestilah meningkat paling banyak secara polinomial dengan bilangan qubit :
Pembaca mungkin perasan andaian tersirat bahawa pensampelan kebarangkalian juga perlu cekap seperti yang dijelaskan untuk Sampler, yang bermaksud
Contoh berpandu untuk mengira nilai jangkaan
Mari kita andaikan keadaan satu qubit , dan boleh cerapan
dengan nilai jangkaan teori berikut
Oleh kerana kita tidak tahu cara mengukur boleh cerapan ini, kita tidak boleh mengira nilai jangkaannya secara terus, dan kita perlu menyatakannya semula sebagai . Yang boleh ditunjukkan memberikan hasil yang sama dengan memperhatikan bahawa , dan .
Mari kita lihat cara mengira dan secara terus. Oleh kerana dan tidak bertukar (iaitu, mereka tidak berkongsi asas eigen yang sama), mereka tidak boleh diukur serentak, oleh itu kita memerlukan litar pembantu:
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-aer qiskit-ibm-runtime rustworkx
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
# The following code will work for any other initial single-qubit state and observable
original_circuit = QuantumCircuit(1)
original_circuit.h(0)
H = SparsePauliOp(["X", "Z"], [2, -1])
aux_circuits = []
for pauli in H.paulis:
aux_circ = original_circuit.copy()
aux_circ.barrier()
if str(pauli) == "X":
aux_circ.h(0)
elif str(pauli) == "Y":
aux_circ.sdg(0)
aux_circ.h(0)
else:
aux_circ.id(0)
aux_circ.measure_all()
aux_circuits.append(aux_circ)
original_circuit.draw("mpl")
# Auxiliary circuit for X
aux_circuits[0].draw("mpl")
# Auxiliary circuit for Z
aux_circuits[1].draw("mpl")
Kita kini boleh menjalankan pengiraan secara manual menggunakan Sampler dan semak hasilnya dengan Estimator:
from qiskit.primitives import StatevectorSampler, StatevectorEstimator
from qiskit.result import QuasiDistribution
import numpy as np
## SAMPLER
shots = 10000
sampler = StatevectorSampler()
job = sampler.run(aux_circuits, shots=shots)
# Run the sampler job and step through results
expvals = []
for index, pauli in enumerate(H.paulis):
data_pub = job.result()[index].data
bitstrings = data_pub.meas.get_bitstrings()
counts = data_pub.meas.get_counts()
quasi_dist = QuasiDistribution(
{outcome: freq / shots for outcome, freq in counts.items()}
)
# Use the probabilities and known eigenvalues of Pauli operators to estimate
# the expectation value.
val = 0
if str(pauli) == "X":
val += -1 * quasi_dist.get(1, 0)
val += 1 * quasi_dist.get(0, 0)
if str(pauli) == "Y":
val += -1 * quasi_dist.get(1, 0)
val += 1 * quasi_dist.get(0, 0)
if str(pauli) == "Z":
val += 1 * quasi_dist.get(0, 0)
val += -1 * quasi_dist.get(1, 0)
expvals.append(val)
# Print expectation values
print("Sampler results:")
for pauli, expval in zip(H.paulis, expvals):
print(f" >> Expected value of {str(pauli)}: {expval:.5f}")
total_expval = np.sum(H.coeffs * expvals).real
print(f" >> Total expected value: {total_expval:.5f}")
# Use estimator for comparison
observables = [
*H.paulis,
H,
] # Note: run for individual Paulis as well as full observable H
estimator = StatevectorEstimator()
job = estimator.run([(original_circuit, observables)])
estimator_expvals = job.result()[0].data.evs
# Print results
print("Estimator results:")
for obs, expval in zip(observables, estimator_expvals):
if obs is not H:
print(f" >> Expected value of {str(obs)}: {expval:.5f}")
else:
print(f" >> Total expected value: {expval:.5f}")
Sampler results:
>> Expected value of X: 1.00000
>> Expected value of Z: 0.00420
>> Total expected value: 1.99580
Estimator results:
>> Expected value of X: 1.00000
>> Expected value of Z: 0.00000
>> Total expected value: 2.00000
Ketepatan matematik (pilihan)
Dengan menyatakan terhadap asas eigenstate , , diperoleh:
Oleh kerana kita tidak tahu nilai eigen atau eigenstate bagi boleh cerapan sasaran , pertama kita perlu mempertimbangkan penpepenjurunya. Memandangkan adalah Hermitian, terdapat transformasi unitari sedemikian di mana adalah matriks nilai eigen pepenjuru, jadi jika , dan .
Ini bermakna nilai jangkaan boleh ditulis semula sebagai:
Memandangkan jika sistem berada dalam keadaan kebarangkalian mengukur adalah , nilai jangkaan di atas boleh dinyatakan sebagai:
Adalah sangat penting untuk diperhatikan bahawa kebarangkalian diambil daripada keadaan bukannya . Inilah sebabnya matriks adalah amat diperlukan. Mungkin Anda tertanya-tanya cara mendapatkan matriks dan nilai eigen . Jika Anda sudah mempunyai nilai eigen, maka tidak perlu menggunakan komputer kuantum kerana matlamat algoritma variatif adalah untuk mencari nilai eigen tersebut.
Nasib baik, ada jalan keluarnya: mana-mana matriks boleh ditulis sebagai gabungan linear bagi hasil darab tensor bagi matriks Pauli dan identiti, yang semuanya adalah Hermitian dan unitari dengan dan yang diketahui. Inilah yang dilakukan oleh Estimator Runtime secara dalaman dengan menguraikan mana-mana objek Operator kepada SparsePauliOp.
Berikut adalah Pengoperasi yang boleh digunakan:
Jadi mari kita tulis semula terhadap Pauli dan identiti:
di mana untuk (iaitu, asas ), dan :
di mana dan , sedemikian:
Fungsi kos
Secara umum, fungsi kos digunakan untuk menggambarkan matlamat sesuatu masalah dan sejauh mana keadaan percubaan berfungsi berkenaan dengan matlamat tersebut. Definisi ini boleh digunakan dalam pelbagai contoh dalam kimia, pembelajaran mesin, kewangan, pengoptimuman, dan sebagainya.
Mari kita pertimbangkan contoh mudah untuk mencari keadaan asas sesuatu sistem. Objektif kita adalah untuk meminimumkan nilai jangkaan bagi boleh cerapan yang mewakili tenaga (Hamiltonian ):
Kita boleh menggunakan Estimator untuk mengira nilai jangkaan dan menghantar nilai ini kepada pengoptimum untuk diminimumkan. Jika pengoptimuman berjaya, ia akan mengembalikan set nilai parameter optimum , dari mana kita akan dapat membina keadaan penyelesaian yang dicadangkan dan mengira nilai jangkaan yang diperhatikan sebagai .
Perhatikan bahawa kita hanya akan dapat meminimumkan fungsi kos untuk set keadaan terhad yang sedang kita pertimbangkan. Ini membawa kepada dua kemungkinan yang berbeza:
- Ansatz kita tidak mentakrifkan keadaan penyelesaian merentas ruang carian: Jika ini berlaku, pengoptimum kita tidak akan pernah menemui penyelesaian, dan kita perlu bereksperimen dengan ansatz lain yang mungkin dapat mewakili ruang carian kita dengan lebih tepat.
- Pengoptimum kita tidak dapat menemui penyelesaian yang sah ini: Pengoptimuman boleh ditakrifkan secara global dan ditakrifkan secara lokal. Kita akan meneroka maksudnya dalam bahagian kemudian.
Secara keseluruhannya, kita akan melakukan gelung pengoptimuman klasik tetapi bergantung pada penilaian fungsi kos kepada komputer kuantum. Dari perspektif ini, seseorang boleh menganggap pengoptimuman sebagai usaha klasik semata-mata di mana kita memanggil beberapa oracle kuantum kotak hitam setiap kali pengoptimum perlu menilai fungsi kos.
def cost_func_vqe(params, circuit, hamiltonian, estimator):
"""Return estimate of energy from estimator
Parameters:
params (ndarray): Array of ansatz parameters
ansatz (QuantumCircuit): Parameterized ansatz circuit
hamiltonian (SparsePauliOp): Operator representation of Hamiltonian
estimator (Estimator): Estimator primitive instance
Returns:
float: Energy estimate
"""
pub = (circuit, hamiltonian, params)
cost = estimator.run([pub]).result()[0].data.evs
return cost
from qiskit.circuit.library import TwoLocal
observable = SparsePauliOp.from_list([("XX", 1), ("YY", -3)])
reference_circuit = QuantumCircuit(2)
reference_circuit.x(0)
variational_form = TwoLocal(
2,
rotation_blocks=["rz", "ry"],
entanglement_blocks="cx",
entanglement="linear",
reps=1,
)
ansatz = reference_circuit.compose(variational_form)
theta_list = (2 * np.pi * np.random.rand(1, 8)).tolist()
ansatz.decompose().draw("mpl")
Kita akan melakukan ini terlebih dahulu menggunakan simulator: StatevectorEstimator. Ini biasanya disyorkan untuk penyahpepijatan, tetapi kita akan segera mengikuti larian penyahpepijatan dengan pengiraan pada perkakasan kuantum sebenar. Semakin banyak masalah yang menarik kini tidak lagi boleh disimulasikan secara klasik tanpa kemudahan superkomputer terkini.
estimator = StatevectorEstimator()
cost = cost_func_vqe(theta_list, ansatz, observable, estimator)
print(cost)
[-0.58744589]
Kita akan meneruskan dengan menjalankan pada komputer kuantum sebenar. Perhatikan perubahan sintaks. Langkah-langkah yang melibatkan pass_manager akan dibincangkan lebih lanjut dalam contoh seterusnya. Satu langkah yang amat penting dalam algoritma variasi ialah penggunaan sesi Qiskit Runtime. Memulakan sesi membolehkan anda menjalankan berbilang iterasi algoritma variasi tanpa menunggu dalam giliran baru setiap kali parameter dikemas kini. Ini penting jika masa giliran panjang dan/atau banyak iterasi diperlukan. Hanya rakan kongsi dalam Rangkaian IBM Quantum® boleh menggunakan sesi Runtime. Jika anda tidak mempunyai akses kepada sesi, anda boleh mengurangkan bilangan iterasi yang anda hantar pada satu masa, dan simpan parameter terkini untuk digunakan dalam larian masa depan. Jika anda menghantar terlalu banyak iterasi atau menghadapi masa giliran yang terlalu panjang, anda mungkin akan menemui kod ralat 1217, yang merujuk kepada kelewatan panjang antara penghantaran kerja.
# Estimated usage: < 1 min. Benchmarked at 7 seconds on an Eagle processor
# Load necessary packages:
from qiskit_ibm_runtime import (
QiskitRuntimeService,
Session,
EstimatorOptions,
EstimatorV2 as Estimator,
)
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
# Select the least busy backend:
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, min_num_qubits=ansatz.num_qubits, simulator=False
)
# Or get a specific backend:
# backend = service.backend("ibm_brisbane")
# Use a pass manager to transpile the circuit and observable for the specific backend being used:
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_ansatz = pm.run(ansatz)
isa_observable = observable.apply_layout(layout=isa_ansatz.layout)
# Set estimator options
estimator_options = EstimatorOptions(resilience_level=1, default_shots=10_000)
# Open a Runtime session:
with Session(backend=backend) as session:
estimator = Estimator(mode=session, options=estimator_options)
cost = cost_func_vqe(theta_list, isa_ansatz, isa_observable, estimator)
session.close()
print(cost)
Perhatikan bahawa nilai yang diperoleh daripada dua pengiraan di atas adalah sangat serupa. Teknik untuk memperbaiki keputusan akan dibincangkan lebih lanjut di bawah.
Contoh pemetaan kepada sistem bukan fizikal
Masalah potongan maksimum (Max-Cut) ialah masalah pengoptimuman kombinatorial yang melibatkan pembahagian bucu graf kepada dua set yang tidak bertindih sedemikian rupa sehingga bilangan tepi antara dua set dimaksimumkan. Lebih formal, diberikan graf tak berarah , di mana ialah set bucu dan ialah set tepi, masalah Max-Cut meminta pembahagian bucu kepada dua subset yang tidak bertindih, dan , sedemikian rupa sehingga bilangan tepi dengan satu titik hujung dalam dan yang lain dalam dimaksimumkan.
Kita boleh menggunakan Max-Cut untuk menyelesaikan pelbagai masalah termasuk: pengkelompokan, reka bentuk rangkaian, peralihan fasa, dan sebagainya. Kita akan mulakan dengan membina graf masalah:
import rustworkx as rx
from rustworkx.visualization import mpl_draw
n = 4
G = rx.PyGraph()
G.add_nodes_from(range(n))
# The edge syntax is (start, end, weight)
edges = [(0, 1, 1.0), (0, 2, 1.0), (0, 3, 1.0), (1, 2, 1.0), (2, 3, 1.0)]
G.add_edges_from(edges)
mpl_draw(
G, pos=rx.shell_layout(G), with_labels=True, edge_labels=str, node_color="#1192E8"
)
Masalah ini boleh dinyatakan sebagai masalah pengoptimuman binari. Untuk setiap nod , di mana ialah bilangan nod graf (dalam kes ini ), kita akan mempertimbangkan pemboleh ubah binari . Pemboleh ubah ini akan bernilai jika nod berada dalam salah satu kumpulan yang kita labelkan dan jika berada dalam kumpulan lain yang kita labelkan sebagai . Kita juga akan menandakan sebagai (elemen bagi matriks jiran ) berat tepi yang menghubungkan nod ke nod . Kerana graf tidak berarah, . Kemudian kita boleh merumuskan masalah kita sebagai memaksimumkan fungsi kos berikut:
Untuk menyelesaikan masalah ini dengan komputer kuantum, kita akan menyatakan fungsi kos sebagai nilai jangkaan boleh cerapan. Walau bagaimanapun, boleh cerapan yang Qiskit terima secara asli terdiri daripada operator Pauli, yang mempunyai nilai eigen dan bukannya dan . Itulah sebabnya kita akan membuat penggantian pemboleh ubah berikut:
Di mana . Kita boleh menggunakan matriks jiran untuk mengakses berat semua tepi dengan mudah. Ini akan digunakan untuk mendapatkan fungsi kos kita:
Ini bermakna:
Jadi fungsi kos baru yang ingin kita maksimumkan ialah:
Selain itu, kecenderungan semula jadi komputer kuantum adalah untuk mencari minima (biasanya tenaga terendah) bukannya maksima, jadi daripada memaksimumkan kita akan meminimumkan:
Kini kita mempunyai fungsi kos untuk diminimumkan yang pemboleh ubahnya boleh bernilai dan , kita boleh membuat analogi berikut dengan Pauli :
Dengan kata lain, pemboleh ubah akan setara dengan get yang bertindak pada qubit . Tambahan pula:
Kemudian boleh cerapan yang kita akan pertimbangkan ialah:
di mana kita perlu menambah sebutan bebas selepas itu:
Operator ini ialah gabungan linear bagi sebutan dengan operator Z pada nod yang dihubungkan oleh tepi (ingat bahawa qubit ke-0 berada paling kanan): . Setelah operator dibina, ansatz untuk algoritma QAOA boleh dibina dengan mudah menggunakan litar QAOAAnsatz daripada pustaka litar Qiskit.
from qiskit.circuit.library import QAOAAnsatz
from qiskit.quantum_info import SparsePauliOp
hamiltonian = SparsePauliOp.from_list(
[("IIZZ", 1), ("IZIZ", 1), ("IZZI", 1), ("ZIIZ", 1), ("ZZII", 1)]
)
ansatz = QAOAAnsatz(hamiltonian, reps=2)
# Draw
ansatz.decompose(reps=3).draw("mpl")
# Sum the weights, and divide by 2
offset = -sum(edge[2] for edge in edges) / 2
print(f"""Offset: {offset}""")
Offset: -2.5
Dengan Estimator Runtime yang secara langsung menerima Hamiltonian dan ansatz berparameter, serta mengembalikan tenaga yang diperlukan, fungsi kos untuk instance QAOA adalah agak mudah:
def cost_func(params, ansatz, hamiltonian, estimator):
"""Return estimate of energy from estimator
Parameters:
params (ndarray): Array of ansatz parameters
ansatz (QuantumCircuit): Parameterized ansatz circuit
hamiltonian (SparsePauliOp): Operator representation of Hamiltonian
estimator (Estimator): Estimator primitive instance
Returns:
float: Energy estimate
"""
pub = (ansatz, hamiltonian, params)
cost = estimator.run([pub]).result()[0].data.evs
# cost = estimator.run(ansatz, hamiltonian, parameter_values=params).result().values[0]
return cost
import numpy as np
x0 = 2 * np.pi * np.random.rand(ansatz.num_parameters)
estimator = StatevectorEstimator()
cost = cost_func_vqe(x0, ansatz, hamiltonian, estimator)
print(cost)
1.473098768180865
# Estimated usage: < 1 min, benchmarked at 6 seconds on ibm_osaka, 5-23-24
# Load some necessary packages:
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import Session, EstimatorV2 as Estimator
# Select the least busy backend:
backend = service.least_busy(
operational=True, min_num_qubits=ansatz.num_qubits, simulator=False
)
# Or get a specific backend:
# backend = service.backend("ibm_brisbane")
# Use a pass manager to transpile the circuit and observable for the specific backend being used:
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_ansatz = pm.run(ansatz)
isa_hamiltonian = hamiltonian.apply_layout(layout=isa_ansatz.layout)
# Set estimator options
estimator_options = EstimatorOptions(resilience_level=1, default_shots=10_000)
# Open a Runtime session:
with Session(backend=backend) as session:
estimator = Estimator(mode=session, options=estimator_options)
cost = cost_func_vqe(x0, isa_ansatz, isa_hamiltonian, estimator)
# Close session after done
session.close()
print(cost)
1.1120776913677988
Kita akan kembali semula kepada contoh ini dalam Aplikasi untuk meneroka cara memanfaatkan pengoptimum untuk berulang melalui ruang carian. Secara umum, ini merangkumi:
- Memanfaatkan pengoptimum untuk mencari parameter optimum
- Mengikat parameter optimum kepada ansatz untuk mencari nilai eigen
- Menterjemahkan nilai eigen kepada definisi masalah kita
Strategi pengukuran: kelajuan berbanding ketepatan
Seperti yang disebutkan, kita menggunakan komputer kuantum yang berdesing sebagai oracle kotak-hitam, di mana bunyi bising boleh menjadikan nilai yang diperolehi tidak deterministik, mengakibatkan turun-naik rawak yang seterusnya akan merosakkan — atau bahkan menghalang sepenuhnya — penumpuan pengoptimum tertentu kepada penyelesaian yang dicadangkan. Ini adalah masalah umum yang perlu kita tangani semasa kita meneroka utiliti kuantum secara berperingkat dan melangkah ke arah kelebihan kuantum:
Kita boleh menggunakan pilihan penindasan ralat dan mitigasi ralat dalam Qiskit Runtime Primitive untuk menangani bunyi bising dan memaksimumkan utiliti komputer kuantum hari ini.
Penindasan Ralat
Penindasan ralat merujuk kepada teknik yang digunakan untuk mengoptimumkan dan mengubah litar semasa proses kompilasi bagi meminimumkan ralat. Ini adalah teknik pengendalian ralat asas yang biasanya mengakibatkan sedikit overhed pra-pemprosesan klasik kepada masa jalan keseluruhan. Overhed tersebut termasuk transpilasi litar untuk dijalankan pada perkakasan kuantum dengan cara:
- Menyatakan litar menggunakan get natif yang tersedia pada sistem kuantum
- Memetakan qubit maya kepada qubit fizikal
- Menambah SWAP berdasarkan keperluan ketersambungan
- Mengoptimumkan get 1Q dan 2Q
- Menambah penguraian dinamik pada qubit terbiar untuk mencegah kesan dékoheren.
Primitive membolehkan penggunaan teknik penindasan ralat dengan menetapkan pilihan optimization_level dan memilih pilihan transpilasi lanjutan. Dalam kursus seterusnya, kita akan mendalami kaedah pembinaan litar yang berbeza untuk meningkatkan keputusan, tetapi bagi kebanyakan kes, kami mengesyorkan untuk menetapkan optimization_level=3.
Kita akan memvisualisasikan nilai peningkatan pengoptimuman dalam proses transpilasi dengan melihat contoh litar yang mempunyai tingkah laku ideal yang mudah.
from qiskit.circuit import Parameter, QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
theta = Parameter("theta")
qc = QuantumCircuit(2)
qc.x(1)
qc.h(0)
qc.cp(theta, 0, 1)
qc.h(0)
observables = SparsePauliOp.from_list([("ZZ", 1)])
qc.draw("mpl")
Litar di atas boleh menghasilkan nilai jangkaan sinusoidal bagi boleh cerap yang diberikan, dengan syarat kita memasukkan fasa yang merentangi selang yang sesuai, seperti .
## Setup phases
import numpy as np
phases = np.linspace(0, 2 * np.pi, 50)
# phases need to be expressed as a list of lists in order to work
individual_phases = [[phase] for phase in phases]
Kita boleh menggunakan simulator untuk menunjukkan kegunaan transpilasi yang dioptimumkan. Kita akan kembali di bawah untuk menggunakan perkakasan sebenar bagi mendemonstrasikan kegunaan mitigasi ralat. Kita akan menggunakan QiskitRuntimeService untuk mendapatkan Backend sebenar (dalam kes ini, ibm_brisbane), dan menggunakan AerSimulator untuk mensimulasikan Backend tersebut, termasuk tingkah laku bunyi bisingnya.
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_aer import AerSimulator
# get a real backend from the runtime service
service = QiskitRuntimeService()
backend = service.backend("ibm_brisbane")
# generate a simulator that mimics the real quantum system with the latest calibration results
backend_sim = AerSimulator.from_backend(backend)
Kita kini boleh menggunakan pass manager untuk mentranspilasi litar ke dalam "seni bina set arahan" atau ISA bagi backend. Ini adalah keperluan baharu dalam Qiskit Runtime: semua litar yang diserahkan kepada backend mesti mematuhi kekangan sasaran backend, bermakna ia mesti ditulis dalam sebutan ISA backend — iaitu, set arahan yang boleh difahami dan dilaksanakan oleh peranti. Kekangan sasaran ini ditentukan oleh faktor seperti get asas natif peranti, ketersambungan qubit-nya, dan — apabila relevan — spesifikasi masa arahan denyut dan lain-lain.
Perhatikan bahawa dalam kes ini, kita akan melakukannya dua kali: sekali dengan optimization_level = 0, dan sekali lagi dengan ia ditetapkan kepada 3. Setiap kali kita akan menggunakan Estimator primitive untuk menganggar nilai jangkaan boleh cerap pada nilai fasa yang berbeza.
# Import estimator and specify that we are using the simulated backend:
from qiskit_ibm_runtime import EstimatorV2 as Estimator
estimator = Estimator(mode=backend_sim)
circuit = qc
# Use a pass manager to transpile the circuit and observable for the backend being simulated.
# Start with no optimization:
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
pm = generate_preset_pass_manager(backend=backend_sim, optimization_level=0)
isa_circuit = pm.run(circuit)
isa_observables = observables.apply_layout(layout=isa_circuit.layout)
noisy_exp_values = []
pub = (isa_circuit, isa_observables, [individual_phases])
cost = estimator.run([pub]).result()[0].data.evs
noisy_exp_values = cost[0]
# Repeat above steps, but now with optimization = 3:
exp_values_with_opt_es = []
pm = generate_preset_pass_manager(backend=backend_sim, optimization_level=3)
isa_circuit = pm.run(circuit)
isa_observables = observables.apply_layout(layout=isa_circuit.layout)
pub = (isa_circuit, isa_observables, [individual_phases])
cost = estimator.run([pub]).result()[0].data.evs
exp_values_with_opt_es = cost[0]
Akhirnya, kita boleh memplot keputusan, dan kita dapat melihat bahawa ketepatan pengiraan agak baik walaupun tanpa pengoptimuman, tetapi ia sememangnya bertambah baik dengan meningkatkan pengoptimuman ke tahap 3. Perhatikan bahawa dalam litar yang lebih dalam dan lebih rumit, perbezaan antara tahap pengoptimuman 0 dan 3 berkemungkinan lebih ketara. Ini adalah litar yang sangat mudah yang digunakan sebagai model mainan.
import matplotlib.pyplot as plt
plt.plot(phases, noisy_exp_values, "o", label="opt=0")
plt.plot(phases, exp_values_with_opt_es, "o", label="opt=3")
plt.plot(phases, 2 * np.sin(phases / 2) ** 2 - 1, label="ideal")
plt.ylabel("Expectation")
plt.legend()
plt.show()
Mitigasi Ralat
Mitigasi ralat merujuk kepada teknik yang membolehkan pengguna mengurangkan ralat litar dengan memodelkan bunyi bising peranti pada masa pelaksanaan. Biasanya, ini mengakibatkan overhed pra-pemprosesan kuantum berkaitan latihan model dan overhed pasca-pemprosesan klasik untuk memitigasi ralat dalam keputusan mentah menggunakan model yang dijana.
Pilihan resilience_level dalam Qiskit Runtime primitive menentukan tahap daya tahan terhadap ralat yang hendak dibina. Tahap yang lebih tinggi menghasilkan keputusan yang lebih tepat dengan mengorbankan masa pemprosesan yang lebih lama akibat overhed pensampelan kuantum. Tahap daya tahan boleh digunakan untuk mengkonfigurasi pertukaran antara kos dan ketepatan apabila menggunakan mitigasi ralat pada pertanyaan primitive anda.
Apabila melaksanakan mana-mana teknik mitigasi ralat, kita mengharapkan bias dalam keputusan kita berkurangan berbanding bias yang tidak dimitigasi sebelumnya. Dalam sesetengah kes, bias mungkin hilang sepenuhnya. Namun, ini ada kosnya. Semasa kita mengurangkan bias dalam kuantiti anggaran kita, kebolehubahan statistik akan meningkat (iaitu, varians), yang boleh kita akaunkan dengan meningkatkan lagi bilangan shot per litar dalam proses pensampelan kita. Ini akan memperkenalkan overhed melebihi yang diperlukan untuk mengurangkan bias, jadi ia tidak dilakukan secara lalai. Kita boleh memilih tingkah laku ini dengan mudah dengan melaraskan bilangan shot per litar dalam options.executions.shots, seperti yang ditunjukkan dalam contoh di bawah.
Untuk kursus ini, kita akan meneroka model mitigasi ralat ini pada tahap tinggi untuk menggambarkan mitigasi ralat yang boleh dilakukan oleh Qiskit Runtime primitive tanpa memerlukan butiran pelaksanaan penuh.
Pemadaman ralat baca semula berpintal (T-REx)
Pemadaman ralat baca semula berpintal (T-REx) menggunakan teknik yang dikenali sebagai pelilitan Pauli untuk mengurangkan bunyi bising yang diperkenalkan semasa proses pengukuran kuantum. Teknik ini tidak mengandaikan sebarang bentuk bunyi bising tertentu, menjadikannya sangat umum dan berkesan.
Aliran kerja keseluruhan:
- Dapatkan data untuk keadaan sifar dengan pembalikan bit rawak (Pauli X sebelum pengukuran)
- Dapatkan data untuk keadaan yang dikehendaki (berdesing) dengan pembalikan bit rawak (Pauli X sebelum pengukuran)
- Kira fungsi khas untuk setiap set data, dan bahagikan.
Kita boleh menetapkan ini dengan options.resilience_level = 1, seperti yang ditunjukkan dalam contoh di bawah.
Ekstrapolasi sifar bunyi bising
Ekstrapolasi sifar bunyi bising (ZNE) berfungsi dengan terlebih dahulu memperkuatkan bunyi bising dalam litar yang menyediakan keadaan kuantum yang dikehendaki, memperoleh pengukuran untuk beberapa tahap bunyi bising yang berbeza, dan menggunakan pengukuran tersebut untuk membuat kesimpulan tentang keputusan tanpa bunyi bising.
Aliran kerja keseluruhan:
- Perkuatkan bunyi bising litar untuk beberapa faktor bunyi bising
- Jalankan setiap litar yang telah diperkuatkan bunyi bisingnya
- Ekstrapolasi kembali ke had sifar bunyi bising
Kita boleh menetapkan ini dengan options.resilience_level = 2. Kita boleh mengoptimumkan ini lebih lanjut dengan meneroka pelbagai noise_factors, noise_amplifiers, dan extrapolators, tetapi ini di luar skop kursus ini. Kami menggalakkan anda untuk bereksperimen dengan pilihan-pilihan ini seperti yang dihuraikan di sini.
Setiap kaedah datang dengan overhed yang berbeza: pertukaran antara bilangan pengiraan kuantum yang diperlukan (masa) dan ketepatan keputusan kita:
Menggunakan pilihan mitigasi dan penindasan Qiskit Runtime
Berikut adalah cara untuk mengira nilai jangkaan sambil menggunakan mitigasi ralat dan penindasan dalam Qiskit Runtime. Kita boleh menggunakan litar dan boleh cerap yang sama seperti sebelumnya, tetapi kali ini memastikan tahap pengoptimuman tetap pada tahap 2, dan kini menala daya tahan atau teknik mitigasi ralat yang digunakan. Proses mitigasi ralat ini berlaku beberapa kali sepanjang gelung pengoptimuman.
Kita menjalankan bahagian ini pada perkakasan sebenar, kerana mitigasi ralat tidak tersedia pada simulator.
# Estimated usage: 8 minutes, benchmarked on an Eagle processor, 5-23-24
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import (
Session,
EstimatorOptions,
EstimatorV2 as Estimator,
)
# We select the least busy backend
# Select the least busy backend
# backend = service.least_busy(
# operational=True, min_num_qubits=ansatz.num_qubits, simulator=False
# )
# Or use a specific backend
backend = service.backend("ibm_brisbane")
# Initialize some variables to save the results from different runs:
exp_values_with_em0_es = []
exp_values_with_em1_es = []
exp_values_with_em2_es = []
# Use a pass manager to optimize the circuit and observables for the backend chosen:
pm = generate_preset_pass_manager(backend=backend, optimization_level=2)
isa_circuit = pm.run(circuit)
isa_observables = observables.apply_layout(layout=isa_circuit.layout)
# Open a session and run with no error mitigation:
estimator_options = EstimatorOptions(resilience_level=0, default_shots=10_000)
with Session(backend=backend) as session:
estimator = Estimator(mode=session, options=estimator_options)
pub = (isa_circuit, isa_observables, [individual_phases])
cost = estimator.run([pub]).result()[0].data.evs
session.close()
exp_values_with_em0_es = cost[0]
# Open a session and run with resilience = 1:
estimator_options = EstimatorOptions(resilience_level=1, default_shots=10_000)
with Session(backend=backend) as session:
estimator = Estimator(mode=session, options=estimator_options)
pub = (isa_circuit, isa_observables, [individual_phases])
cost = estimator.run([pub]).result()[0].data.evs
session.close()
exp_values_with_em1_es = cost[0]
# Open a session and run with resilience = 2:
estimator_options = EstimatorOptions(resilience_level=2, default_shots=10_000)
with Session(backend=backend) as session:
estimator = Estimator(mode=session, options=estimator_options)
pub = (isa_circuit, isa_observables, [individual_phases])
cost = estimator.run([pub]).result()[0].data.evs
session.close()
exp_values_with_em2_es = cost[0]
Seperti sebelumnya, kita boleh memplot nilai jangkaan yang terhasil sebagai fungsi sudut fasa untuk tiga tahap mitigasi ralat yang digunakan. Dengan susah payah, seseorang dapat melihat bahawa mitigasi ralat meningkatkan keputusan sedikit. Sekali lagi, kesan ini jauh lebih ketara dalam litar yang lebih dalam dan lebih rumit.
import matplotlib.pyplot as plt
plt.plot(phases, exp_values_with_em0_es, "o", label="unmitigated")
plt.plot(phases, exp_values_with_em1_es, "o", label="resil = 1")
plt.plot(phases, exp_values_with_em2_es, "o", label="resil = 2")
plt.plot(phases, 2 * np.sin(phases / 2) ** 2 - 1, label="ideal")
plt.ylabel("Expectation")
plt.legend()
plt.show()
Ringkasan
Dengan pelajaran ini, anda telah belajar cara mencipta fungsi kos:
- Cipta fungsi kos
- Cara memanfaatkan Qiskit Runtime primitive untuk memitigasi dan menindas bunyi bising
- Cara menentukan strategi pengukuran untuk mengoptimumkan kelajuan berbanding ketepatan
Berikut adalah beban kerja variasi tahap tinggi kita:
Fungsi kos kita berjalan pada setiap lelaran gelung pengoptimuman. Pelajaran seterusnya akan meneroka cara pengoptimum klasik menggunakan penilaian fungsi kos kita untuk memilih parameter baharu.
import qiskit
import qiskit_ibm_runtime
print(qiskit.version.get_version_info())
print(qiskit_ibm_runtime.version.get_version_info())
1.1.0
0.23.0