ตัวอย่างการใช้ Estimator
เวอร์ชันของแพ็กเกจ
โค้ดในหน้านี้พัฒนาโดยใช้ requirements ต่อไปนี้ แนะนำให้ใช้เวอร์ชันเหล่านี้หรือใหม่กว่า
qiskit[all]~=2.4.0
qiskit-ibm-runtime~=0.46.1
ตัวอย่างในส่วนนี้แสดงวิธีการใช้งาน Estimator ที่พบบ่อย ก่อนรันตัวอย่างเหล่านี้ ให้ทำตามคำแนะนำใน ติดตั้ง Qiskit ก่อน
ตัวอย่างทั้งหมดนี้ใช้ primitives จาก Qiskit Runtime แต่สามารถใช้ base primitives แทนได้เช่นกัน
คำนวณและตีความค่าความคาดหวัง (expectation values) ของ quantum operators ที่จำเป็นสำหรับอัลกอริทึมหลายตัวได้อย่างมีประสิทธิภาพด้วย Estimator สำรวจการใช้งานในด้านการสร้างแบบจำลองโมเลกุล, machine learning, และปัญหาการปรับให้เหมาะสม (optimization) ที่ซับซ้อน
รันการทดลองเดี่ยว
ใช้ Estimator เพื่อหาค่าความคาดหวังของคู่ circuit-observable เดี่ยว
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime
import numpy as np
from qiskit.circuit.library import iqp
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.quantum_info import SparsePauliOp, random_hermitian
from qiskit_ibm_runtime import QiskitRuntimeService, EstimatorV2 as Estimator
n_qubits = 50
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=n_qubits
)
mat = np.real(random_hermitian(n_qubits, seed=1234))
circuit = iqp(mat)
observable = SparsePauliOp("Z" * 50)
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)
estimator = Estimator(mode=backend)
job = estimator.run([(isa_circuit, isa_observable)])
result = job.result()
print(f" > Expectation value: {result[0].data.evs}")
print(f" > Metadata: {result[0].metadata}")
> Expectation value: -0.0564042303172738
> Metadata: {'shots': 4096, 'target_precision': 0.015625, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32}
รันหลายการทดลองในงานเดียว
ใช้ Estimator เพื่อหาค่าความคาดหวังของคู่ circuit-observable หลายคู่
import numpy as np
from qiskit.circuit.library import iqp
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.quantum_info import SparsePauliOp, random_hermitian
from qiskit_ibm_runtime import QiskitRuntimeService, EstimatorV2 as Estimator
n_qubits = 50
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=n_qubits
)
rng = np.random.default_rng()
mats = [np.real(random_hermitian(n_qubits, seed=rng)) for _ in range(3)]
pubs = []
circuits = [iqp(mat) for mat in mats]
observables = [
SparsePauliOp("X" * 50),
SparsePauliOp("Y" * 50),
SparsePauliOp("Z" * 50),
]
# Get ISA circuits
pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
for qc, obs in zip(circuits, observables):
isa_circuit = pm.run(qc)
isa_obs = obs.apply_layout(isa_circuit.layout)
pubs.append((isa_circuit, isa_obs))
estimator = Estimator(backend)
job = estimator.run(pubs)
job_result = job.result()
for idx in range(len(pubs)):
pub_result = job_result[idx]
print(f">>> Expectation values for PUB {idx}: {pub_result.data.evs}")
print(f">>> Standard errors for PUB {idx}: {pub_result.data.stds}")
>>> Expectation values for PUB 0: 0.09218950064020487
>>> Standard errors for PUB 0: 0.2666311918779662
>>> Expectation values for PUB 1: -0.7159533073929961
>>> Standard errors for PUB 1: 0.5443960702392404
>>> Expectation values for PUB 2: -0.14271555996035679
>>> Standard errors for PUB 2: 0.2714876601210801
รัน parameterized circuits
ใช้ Estimator เพื่อรันสามการทดลองในงานเดียว โดยใช้ค่า parameter เพื่อเพิ่มความสามารถในการนำ Circuit กลับมาใช้ซ้ำ
import numpy as np
from qiskit.circuit import QuantumCircuit, Parameter
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, EstimatorV2 as Estimator
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
# Step 1: Map classical inputs to a quantum problem
theta = Parameter("θ")
chsh_circuit = QuantumCircuit(2)
chsh_circuit.h(0)
chsh_circuit.cx(0, 1)
chsh_circuit.ry(theta, 0)
number_of_phases = 21
phases = np.linspace(0, 2 * np.pi, number_of_phases)
individual_phases = [[ph] for ph in phases]
ZZ = SparsePauliOp.from_list([("ZZ", 1)])
ZX = SparsePauliOp.from_list([("ZX", 1)])
XZ = SparsePauliOp.from_list([("XZ", 1)])
XX = SparsePauliOp.from_list([("XX", 1)])
ops = [ZZ, ZX, XZ, XX]
# Step 2: Optimize problem for quantum execution.
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
chsh_isa_circuit = pm.run(chsh_circuit)
isa_observables = [
operator.apply_layout(chsh_isa_circuit.layout) for operator in ops
]
# Step 3: Execute using Qiskit primitives.
# Reshape observable array for broadcasting
reshaped_ops = np.fromiter(isa_observables, dtype=object)
reshaped_ops = reshaped_ops.reshape((4, 1))
estimator = Estimator(backend, options={"default_shots": int(1e4)})
job = estimator.run([(chsh_isa_circuit, reshaped_ops, individual_phases)])
# Get results for the first (and only) PUB
pub_result = job.result()[0]
print(f">>> Expectation values: {pub_result.data.evs}")
print(f">>> Standard errors: {pub_result.data.stds}")
print(f">>> Metadata: {pub_result.metadata}")
>>> Expectation values: [[ 0.9821299 0.92848415 0.78219632 0.56555001 0.29732126 -0.02496591
-0.30928839 -0.5779298 -0.79292547 -0.92084995 -0.9806856 -0.93075378
-0.80014701 -0.57627916 -0.32496945 -0.00495192 0.29938456 0.56513735
0.80117866 0.92580187 0.98151091]
[-0.00330128 0.30949472 0.58123108 0.78549759 0.9357057 0.97903496
0.93240442 0.78879887 0.58267539 0.2948453 0.0041266 -0.29835291
-0.57339055 -0.78075201 -0.92477022 -0.97882863 -0.93075378 -0.79148116
-0.57958044 -0.30557445 0.00598356]
[-0.01031649 -0.34250749 -0.59257922 -0.80819387 -0.95159309 -0.99616033
-0.9336424 -0.78054568 -0.57112092 -0.30639977 0.00866585 0.30474913
0.57627916 0.81149515 0.95035511 0.99224006 0.9530374 0.78673557
0.57834246 0.30557445 -0.00866585]
[ 0.99616033 0.93446772 0.80344829 0.5841197 0.29401998 -0.01980766
-0.31300232 -0.59361087 -0.81170148 -0.94849814 -0.99327171 -0.93880064
-0.80860653 -0.58019943 -0.30186051 0.01856968 0.29009972 0.59835645
0.80613057 0.94437155 0.98976411]]
>>> Standard errors: [[0.00346988 0.00453617 0.00722056 0.00981693 0.01144016 0.01501324
0.01334599 0.01100181 0.00916772 0.00689316 0.00381375 0.00555949
0.00576968 0.01074419 0.01298665 0.01231428 0.0128399 0.00946472
0.00819982 0.00494361 0.00359142]
[0.01087106 0.01070164 0.00869617 0.00735853 0.00475886 0.00351362
0.00422178 0.00865889 0.00830071 0.01030088 0.01114086 0.01184411
0.00958307 0.00740947 0.00577496 0.00417023 0.00434772 0.00825295
0.00805684 0.01071724 0.01320466]
[0.01346985 0.01132597 0.01143045 0.00729025 0.00490636 0.00287136
0.0051666 0.00718324 0.00899331 0.00980723 0.00957352 0.01211162
0.00932736 0.00658862 0.00555066 0.00271584 0.00581507 0.00778402
0.00935326 0.01223799 0.01214173]
[0.00297333 0.00520897 0.00730712 0.01099862 0.01320699 0.01250301
0.0151248 0.00924768 0.00639241 0.00529221 0.00270411 0.00463968
0.00729108 0.00685512 0.00993793 0.0101938 0.01109962 0.01130657
0.00795711 0.00532976 0.00299901]]
>>> Metadata: {'shots': 10016, 'target_precision': 0.01, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32}
ใช้ batches และตัวเลือกขั้นสูง
สำรวจโหมดการรัน batch และตัวเลือกขั้นสูงเพื่อปรับปรุงประสิทธิภาพ Circuit บน QPUs
import numpy as np
from qiskit.circuit.library import iqp
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.quantum_info import SparsePauliOp, random_hermitian
from qiskit_ibm_runtime import (
QiskitRuntimeService,
Batch,
EstimatorV2 as Estimator,
)
n_qubits = 15
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=n_qubits
)
rng = np.random.default_rng(1234)
mat = np.real(random_hermitian(n_qubits, seed=rng))
circuit = iqp(mat)
mat = np.real(random_hermitian(n_qubits, seed=rng))
another_circuit = iqp(mat)
observable = SparsePauliOp("X" * n_qubits)
another_observable = SparsePauliOp("Y" * n_qubits)
pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pm.run(circuit)
another_isa_circuit = pm.run(another_circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)
another_isa_observable = another_observable.apply_layout(
another_isa_circuit.layout
)
# The context manager automatically closes the batch.
with Batch(backend=backend) as batch:
estimator = Estimator(mode=batch)
estimator.options.resilience_level = 1
job = estimator.run([(isa_circuit, isa_observable)])
another_job = estimator.run(
[(another_isa_circuit, another_isa_observable)]
)
result = job.result()
another_result = another_job.result()
# first job
print(f" > Expectation value: {result[0].data.evs}")
print(f" > Metadata: {result[0].metadata}")
# second job
print(f" > Another Expectation value: {another_result[0].data.evs}")
print(f" > More Metadata: {another_result[0].metadata}")
> Expectation value: -0.03391665163268988
> Metadata: {'shots': 4096, 'target_precision': 0.015625, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32}
> Another Expectation value: -0.011113040458412918
> More Metadata: {'shots': 4096, 'target_precision': 0.015625, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32}
ขั้นตอนถัดไป
- ระบุตัวเลือก runtime ขั้นสูง
- ฝึกใช้ primitives ผ่านบทเรียน Cost function ใน IBM Quantum® Learning
- เรียนรู้วิธี transpile ในเครื่องได้ในส่วน Transpile
- ลองเปรียบเทียบการตั้งค่า Transpiler
- อ่าน ย้ายไปใช้ V2 primitives
- ทำความเข้าใจ ข้อจำกัดของ Job เมื่อส่งงานไปยัง IBM® QPU