Fungsi biaya
Dalam pelajaran ini, kita akan belajar cara mengevaluasi sebuah fungsi biaya:
- Pertama, kita akan belajar tentang primitif Qiskit Runtime
- Mendefinisikan sebuah fungsi biaya . Ini adalah fungsi yang spesifik untuk masalah tertentu yang mendefinisikan tujuan masalah bagi optimizer untuk diminimalkan (atau dimaksimalkan)
- Mendefinisikan strategi pengukuran dengan primitif Qiskit Runtime untuk mengoptimalkan kecepatan versus akurasi
Primitif
Semua sistem fisik, baik klasik maupun kuantum, bisa ada dalam keadaan yang berbeda-beda. Misalnya, sebuah mobil di jalan bisa memiliki massa, posisi, kecepatan, atau percepatan tertentu yang mencirikan keadaannya. Demikian pula, sistem kuantum juga bisa memiliki konfigurasi atau keadaan yang berbeda, namun berbeda dari sistem klasik dalam cara kita menangani pengukuran dan evolusi keadaan. Hal ini mengarah pada sifat-sifat unik seperti superposisi dan keterikatan yang eksklusif untuk mekanika kuantum. Sama seperti kita bisa menggambarkan keadaan mobil menggunakan sifat fisik seperti kecepatan atau percepatan, kita juga bisa menggambarkan keadaan sistem kuantum menggunakan observabel, yang merupakan objek matematis.
Dalam mekanika kuantum, keadaan direpresentasikan oleh vektor kolom kompleks yang dinormalisasi, atau ket (), dan observabel adalah operator linear Hermitian () yang bekerja pada ket. Vektor eigen () dari sebuah observabel dikenal sebagai eigenstate. Mengukur observabel untuk salah satu eigenstate-nya () akan memberikan nilai eigen yang sesuai () sebagai hasil baca.
Jika kamu bertanya-tanya bagaimana cara mengukur sistem kuantum dan apa yang bisa kamu ukur, Qiskit menawarkan dua primitif yang bisa membantu:
Sampler: Diberikan keadaan kuantum , primitif ini mendapatkan probabilitas dari setiap kemungkinan keadaan basis komputasional.Estimator: Diberikan observabel kuantum dan keadaan , primitif ini menghitung nilai ekspektasi dari .
Primitif Sampler
Primitif Sampler menghitung probabilitas mendapatkan setiap kemungkinan keadaan dari basis komputasional, diberikan sebuah Circuit kuantum yang mempersiapkan keadaan . Ia menghitung
Di mana adalah jumlah qubit, dan representasi integer dari semua kemungkinan string biner output (yaitu, bilangan bulat basis ).
Qiskit Runtime Sampler menjalankan Circuit beberapa kali pada perangkat kuantum, melakukan pengukuran pada setiap jalannya, dan merekonstruksi distribusi probabilitas dari bitstring yang didapatkan. Semakin banyak jalannya (atau shot), semakin akurat hasilnya, namun ini membutuhkan lebih banyak waktu dan sumber daya kuantum.
Namun, karena jumlah kemungkinan output tumbuh secara eksponensial seiring dengan jumlah qubit (yaitu, ), jumlah shot juga perlu tumbuh secara eksponensial agar bisa menangkap distribusi probabilitas yang padat. Oleh karena itu, Sampler hanya efisien untuk distribusi probabilitas yang jarang; di mana keadaan target harus bisa diekspresikan sebagai kombinasi linear dari keadaan basis komputasional, dengan jumlah suku yang tumbuh paling banyak secara polinomial seiring dengan jumlah qubit:
Sampler juga bisa dikonfigurasi untuk mengambil probabilitas dari sebagian Circuit, yang merepresentasikan subset dari total kemungkinan keadaan.
Primitif Estimator
Primitif Estimator menghitung nilai ekspektasi dari observabel untuk keadaan kuantum ; di mana probabilitas observabel bisa diekspresikan sebagai , dengan adalah eigenstate dari observabel . Nilai ekspektasi kemudian didefinisikan sebagai rata-rata dari semua kemungkinan hasil (yaitu, nilai eigen dari observabel) dari sebuah pengukuran keadaan , berbobot oleh probabilitas yang sesuai:
Namun, menghitung nilai ekspektasi dari sebuah observabel tidak selalu bisa dilakukan, karena kita sering tidak mengetahui eigenbasis-nya. Qiskit Runtime Estimator menggunakan proses aljabar yang kompleks untuk memperkirakan nilai ekspektasi pada perangkat kuantum nyata dengan menguraikan observabel menjadi kombinasi dari observabel lain yang eigenbasis-nya sudah kita ketahui.
Dalam istilah yang lebih sederhana, Estimator menguraikan setiap observabel yang tidak diketahui cara mengukurnya menjadi observabel yang lebih sederhana dan bisa diukur yang disebut operator Pauli.
Setiap operator bisa diekspresikan sebagai kombinasi dari operator Pauli.
sehingga
di mana adalah jumlah qubit, untuk (yaitu, bilangan bulat basis ), dan .
Setelah melakukan dekomposisi ini, Estimator menghasilkan Circuit baru untuk setiap observabel (dari Circuit asli), untuk secara efektif mendiagonalisasi observabel Pauli dalam basis komputasional dan mengukurnya. Kita bisa dengan mudah mengukur observabel Pauli karena kita mengetahui sebelumnya, yang tidak demikian halnya untuk observabel lain pada umumnya.
Untuk setiap , Estimator menjalankan Circuit yang sesuai pada perangkat kuantum beberapa kali, mengukur keadaan output dalam basis komputasional, dan menghitung probabilitas untuk mendapatkan setiap kemungkinan output . Kemudian ia mencari nilai eigen dari yang sesuai dengan setiap output , mengalikannya dengan , dan menjumlahkan semua hasilnya untuk mendapatkan nilai ekspektasi dari observabel untuk keadaan yang diberikan.
Karena menghitung nilai ekspektasi dari Pauli tidak praktis (yaitu, tumbuh secara eksponensial), Estimator hanya bisa efisien ketika sejumlah besar bernilai nol (yaitu, dekomposisi Pauli yang jarang bukan yang padat). Secara formal kita katakan bahwa, agar komputasi ini bisa diselesaikan secara efisien, jumlah suku yang tidak nol harus tumbuh paling banyak secara polinomial seiring dengan jumlah qubit :
Pembaca mungkin memperhatikan asumsi implisit bahwa pengambilan sampel probabilitas juga perlu efisien seperti yang dijelaskan untuk Sampler, yang berarti
Contoh terpandu untuk menghitung nilai ekspektasi
Mari kita asumsikan keadaan qubit tunggal , dan observabel
dengan nilai ekspektasi teoritis berikut
Karena kita tidak tahu cara mengukur observabel ini, kita tidak bisa menghitung nilai ekspektasinya secara langsung, dan kita perlu mengekspresikannya kembali sebagai . Yang bisa ditunjukkan menghasilkan hasil yang sama dengan memperhatikan bahwa , dan .
Mari kita lihat cara menghitung dan secara langsung. Karena dan tidak komutatif (yaitu, mereka tidak berbagi eigenbasis yang sama), mereka tidak bisa diukur secara bersamaan, sehingga kita memerlukan Circuit bantu:
# 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")
Sekarang kita bisa melakukan komputasi secara manual menggunakan Sampler dan memeriksa hasilnya di 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
Ketelitian matematis (opsional)
Mengekspresikan terhadap basis eigenstate dari , , maka:
Karena kita tidak mengetahui nilai eigen atau eigenstate dari observabel target , pertama-tama kita perlu mempertimbangkan diagonalisasinya. Mengingat bahwa bersifat Hermitian, terdapat transformasi uniter sedemikian sehingga di mana adalah matriks nilai eigen diagonal, sehingga jika , dan .
Ini berarti nilai ekspektasi bisa ditulis ulang sebagai: