Simulasi eksak dengan primitif Qiskit SDK
Versi paket
Kode di halaman ini dikembangkan menggunakan persyaratan berikut. Kami menyarankan menggunakan versi ini atau yang lebih baru.
qiskit[all]~=2.3.0
Primitif referensi di Qiskit SDK melakukan simulasi statevector lokal. Simulasi ini tidak mendukung pemodelan noise perangkat, tetapi berguna untuk membuat prototipe algoritma dengan cepat sebelum melihat teknik simulasi yang lebih canggih (menggunakan Qiskit Aer) atau menjalankan pada perangkat nyata (Qiskit Runtime primitives).
Primitif Estimator dapat menghitung nilai ekspektasi dari Circuit, dan primitif Sampler dapat mengambil sampel dari distribusi output Circuit.
Bagian berikut menunjukkan cara menggunakan primitif referensi untuk menjalankan alur kerjamu secara lokal.
Gunakan Estimator referensiβ
Implementasi referensi dari EstimatorV2 di qiskit.primitives yang berjalan pada simulator statevector lokal
adalah kelas StatevectorEstimator. Ia dapat menerima Circuit, observable, dan parameter sebagai input dan mengembalikan nilai ekspektasi yang dihitung secara lokal.
Kode berikut mempersiapkan input yang akan digunakan dalam contoh-contoh berikutnya. Tipe input yang diharapkan untuk
observable adalah qiskit.quantum_info.SparsePauliOp. Perhatikan bahwa
Circuit dalam contoh ini bersifat parametrized, tetapi kamu juga bisa menjalankan Estimator pada Circuit yang tidak diparametrasi.
Setiap Circuit yang diteruskan ke Estimator tidak boleh menyertakan pengukuran apa pun.
# Added by doQumentation β required packages for this notebook
!pip install -q numpy qiskit
from qiskit import QuantumCircuit
from qiskit.circuit import Parameter
# circuit for which you want to obtain the expected value
circuit = QuantumCircuit(2)
circuit.ry(Parameter("theta"), 0)
circuit.h(0)
circuit.cx(0, 1)
circuit.draw("mpl", style="iqp")
from qiskit.quantum_info import SparsePauliOp
import numpy as np
# observable(s) whose expected values you want to compute
observable = SparsePauliOp(["II", "XX", "YY", "ZZ"], coeffs=[1, 1, -1, 1])
# value(s) for the circuit parameter(s)
parameter_values = [[0], [np.pi / 6], [np.pi / 2]]
Alur kerja primitif Qiskit Runtime memerlukan Circuit dan observable untuk diubah agar hanya menggunakan instruksi yang didukung oleh QPU (disebut sebagai instruction set architecture (ISA) Circuit dan observable). Primitif referensi masih menerima instruksi abstrak, karena mereka mengandalkan simulasi statevector lokal, tetapi men-transpile Circuit mungkin tetap bermanfaat dari segi optimasi Circuit.
# Generate a pass manager without providing a backend
from qiskit.transpiler import generate_preset_pass_manager
pm = generate_preset_pass_manager(optimization_level=1)
isa_circuit = pm.run(circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)
Inisialisasi Estimatorβ
Buat instance qiskit.primitives.StatevectorEstimator.
from qiskit.primitives import StatevectorEstimator
estimator = StatevectorEstimator()
Jalankan dan dapatkan hasilβ
Contoh ini hanya menggunakan satu Circuit (bertipe QuantumCircuit) dan satu
observable.
Jalankan estimasi dengan memanggil metode StatevectorEstimator.run, yang mengembalikan instance dari objek PrimitiveJob. Kamu bisa mendapatkan hasil dari job (sebagai objek qiskit.primitives.PrimitiveResult)
dengan metode qiskit.primitives.PrimitiveJob.result.
job = estimator.run([(circuit, observable, parameter_values)])
result = job.result()
print(f" > Result class: {type(result)}")
> Result class: <class 'qiskit.primitives.containers.primitive_result.PrimitiveResult'>
Dapatkan nilai ekspektasi dari hasilβ
Output hasil primitif berupa array dari objek PubResult, di mana setiap item dalam array adalah objek PubResult yang berisi dalam datanya array evaluasi yang sesuai dengan setiap kombinasi Circuit-observable dalam PUB.
Untuk mengambil nilai ekspektasi dan metadata untuk evaluasi Circuit pertama (dan dalam hal ini satu-satunya), kita harus mengakses data evaluasi untuk PUB 0:
print(f" > Expectation value: {result[0].data.evs}")
print(f" > Metadata: {result[0].metadata}")
> Expectation value: [4. 3.73205081 2. ]
> Metadata: {'target_precision': 0.0, 'circuit_metadata': {}}
Atur opsi run Estimatorβ
Secara default, Estimator referensi melakukan perhitungan statevector eksak berdasarkan
kelas quantum_info.Statevector.
Namun, ini bisa dimodifikasi untuk memperkenalkan efek dari sampling overhead (juga dikenal sebagai "shot noise").
Estimator menerima argumen precision yang mengekspresikan error bar yang harus dicapai oleh
implementasi primitif untuk estimasi nilai ekspektasi. Ini adalah sampling overhead dan didefinisikan secara eksklusif di metode .run(). Ini memungkinkan kamu menyesuaikan opsi hingga ke tingkat PUB.
# Estimate expectation values for two PUBs, both with 0.05 precision.
precise_job = estimator.run(
[(circuit, observable, parameter_values)], precision=0.05
)
Untuk contoh lengkap, lihat halaman Contoh Primitives.
Gunakan Sampler referensiβ
Implementasi referensi dari SamplerV2 di qiskit.primitives adalah kelas StatevectorSampler. Ia menerima Circuit dan parameter sebagai input dan mengembalikan hasil dari pengambilan sampel dari distribusi probabilitas output sebagai distribusi kuasi-probabilitas dari state output.
Kode berikut mempersiapkan input yang digunakan dalam contoh-contoh berikutnya. Perhatikan bahwa contoh-contoh ini menjalankan satu Circuit yang diparametrasi, tetapi kamu juga bisa menjalankan Sampler pada Circuit yang tidak diparametrasi.
from qiskit import QuantumCircuit
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure_all()
circuit.draw("mpl", style="iqp")
Setiap rangkaian kuantum yang diteruskan ke Sampler harus menyertakan pengukuran.
Alur kerja primitif Qiskit Runtime memerlukan Circuit untuk diubah agar hanya menggunakan instruksi yang didukung oleh QPU (disebut sebagai ISA Circuit). Primitif referensi masih menerima instruksi abstrak, karena mereka mengandalkan simulasi statevector lokal, tetapi men-transpile Circuit mungkin tetap bermanfaat dari segi optimasi Circuit.
# Generate a pass manager without providing a backend
from qiskit.transpiler import generate_preset_pass_manager
pm = generate_preset_pass_manager(optimization_level=1)
isa_circuit = pm.run(qc)
Inisialisasi SamplerV2β
Buat instance qiskit.primitives.StatevectorSampler:
from qiskit.primitives import StatevectorSampler
sampler = StatevectorSampler()
Jalankan dan dapatkan hasilβ
# execute 1 circuit with Sampler
job = sampler.run([circuit])
pub_result = job.result()[0]
print(f" > Result class: {type(pub_result)}")
> Result class: <class 'qiskit.primitives.containers.sampler_pub_result.SamplerPubResult'>
Primitif menerima beberapa PUB sebagai input, dan setiap PUB mendapatkan hasilnya sendiri. Oleh karena itu, kamu bisa menjalankan berbagai Circuit dengan kombinasi parameter/observable yang berbeda, dan mengambil hasil PUB:
from qiskit.transpiler import generate_preset_pass_manager
# create two circuits
circuit1 = circuit.copy()
circuit2 = circuit.copy()
# transpile circuits
pm = generate_preset_pass_manager(optimization_level=1)
isa_circuit1 = pm.run(circuit1)
isa_circuit2 = pm.run(circuit2)
# execute 2 circuits using Sampler
job = sampler.run([(isa_circuit1), (isa_circuit2)])
pub_result_1 = job.result()[0]
pub_result_2 = job.result()[1]
print(f" > Result class: {type(pub_result)}")
> Result class: <class 'qiskit.primitives.containers.sampler_pub_result.SamplerPubResult'>
Dapatkan distribusi probabilitas atau hasil pengukuranβ
Sampel hasil pengukuran dikembalikan sebagai bitstring atau counts. Bitstring menampilkan hasil pengukuran, mempertahankan urutan shot di mana mereka diukur. Objek hasil Sampler mengorganisir data berdasarkan nama register klasik dari Circuit input mereka, untuk kompatibilitas dengan sirkuit dinamis.
Nama register klasik secara default adalah "meas". Nama ini akan digunakan nanti untuk mengakses bitstring pengukuran.
# Define quantum circuit with 2 qubits
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure_all()
circuit.draw()
βββββ β βββ
q_0: β€ H ββββ ββββββ€Mββββ
ββββββββ΄ββ β ββ₯ββββ
q_1: ββββββ€ X ββββββ«ββ€Mβ
βββββ β β ββ₯β
meas: 2/βββββββββββββββ©βββ©β
0 1
# Transpile circuit
pm = generate_preset_pass_manager(optimization_level=1)
isa_circuit = pm.run(circuit)
# Run using sampler
result = sampler.run([circuit]).result()
# Access result data for PUB 0
data_pub = result[0].data
# Access bitstring for the classical register "meas"
bitstrings = data_pub.meas.get_bitstrings()
print(f"The number of bitstrings is: {len(bitstrings)}")
# Get counts for the classical register "meas"
counts = data_pub.meas.get_counts()
print(f"The counts are: {counts}")
The number of bitstrings is: 1024
The counts are: {'11': 515, '00': 509}
Ubah opsi runβ
Secara default, Sampler referensi melakukan perhitungan statevector eksak berdasarkan
kelas quantum_info.Statevector.
Namun, ini bisa dimodifikasi untuk memperkenalkan efek dari sampling overhead (juga dikenal sebagai "shot noise"). Untuk membantu mengelola overhead ini, antarmuka Sampler menerima argumen shots yang dapat didefinisikan di tingkat PUB.
Contoh ini mengasumsikan kamu telah mendefinisikan dua Circuit.
# Sample two circuits at 128 shots each.
sampler.run([isa_circuit1, isa_circuit2], shots=128)
# Sample two circuits at different amounts of shots. The "None"s are necessary
# as placeholders
# for the lack of parameter values in this example.
sampler.run([(isa_circuit1, None, 123), (isa_circuit2, None, 456)])
<qiskit.primitives.primitive_job.PrimitiveJob at 0x7fa430e39dd0>
Untuk contoh lengkap, lihat halaman Contoh Primitives.
Langkah selanjutnyaβ
- Untuk simulasi berkinerja lebih tinggi yang dapat menangani Circuit yang lebih besar, atau untuk memasukkan model noise ke dalam simulasimu, lihat Simulasi eksak dan berisik dengan primitif Qiskit Aer.
- Untuk mempelajari cara menggunakan Quantum Composer untuk simulasi, lihat panduan IBM Quantum Composer.
- Baca referensi Qiskit Estimator API.
- Baca referensi Qiskit Sampler API.
- Baca Migrasi ke primitif V2.