การจำลองแบบแม่นยำด้วย Qiskit SDK primitives
เวอร์ชันแพ็กเกจ
โค้ดในหน้านี้พัฒนาโดยใช้ข้อกำหนดต่อไปนี้ แนะนำให้ใช้เวอร์ชันเหล่านี้หรือใหม่กว่า
qiskit[all]~=2.3.0
Reference primitives ใน Qiskit SDK ทำการจำลอง statevector แบบ local โดยการจำลองเหล่านี้ไม่รองรับการสร้างแบบจำลองสัญญาณรบกวนของอุปกรณ์ แต่มีประโยชน์สำหรับการสร้างต้นแบบอัลกอริธึมอย่างรวดเร็วก่อนที่จะศึกษาเทคนิคการจำลองขั้นสูง (โดยใช้ Qiskit Aer) หรือรันบนอุปกรณ์จริง (Qiskit Runtime primitives)
Estimator primitive สามารถคำนวณค่าความคาดหวังของวงจรได้ และ Sampler primitive สามารถสุ่มตัวอย่างจากการกระจายผลลัพธ์ของวงจรได้
ส่วนต่อไปนี้แสดงวิธีใช้ reference primitives เพื่อรัน workflow ของคุณในเครื่อง
ใช้งาน reference Estimator
การใช้งาน reference ของ EstimatorV2 ใน qiskit.primitives ที่รันบน local statevector simulators คือคลาส StatevectorEstimator มันรับ Circuit, observable และ parameter เป็น input และคืนค่าความคาดหวังที่คำนวณในเครื่อง
โค้ดต่อไปนี้เตรียม input ที่จะใช้ในตัวอย่างที่ตามมา ประเภท input ที่รองรับสำหรับ observable คือ qiskit.quantum_info.SparsePauliOp โปรดสังเกตว่า Circuit ในตัวอย่างมีการกำหนดค่าพารามิเตอร์ แต่คุณสามารถรัน Estimator กับ Circuit ที่ไม่มีพารามิเตอร์ได้เช่นกัน
Circuit ที่ส่งให้ Estimator จะต้องไม่มีการวัดผลใด ๆ
# 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]]
ขั้นตอนการทำงานของ Qiskit Runtime primitives ต้องการให้ Circuit และ observable ถูกแปลงให้ใช้เฉพาะคำสั่งที่รองรับโดย QPU (เรียกว่า instruction set architecture (ISA) circuits และ observables) Reference primitives ยังคงรับคำสั่งแบบ abstract ได้ เนื่องจากพึ่งพาการจำลอง statevector แบบ local แต่การ transpile Circuit อาจยังเป็นประโยชน์ในแง่ของการปรับแต่ง 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)
Initialize Estimator
สร้าง instance ของ qiskit.primitives.StatevectorEstimator
from qiskit.primitives import StatevectorEstimator
estimator = StatevectorEstimator()
รันและรับผลลัพธ์
ตัวอย่างนี้ใช้ Circuit เดียว (ประเภท QuantumCircuit) และ observable เดียว
รันการประมาณโดยเรียกใช้เมธอด StatevectorEstimator.run ซึ่งคืนค่า instance ของออบเจ็กต์ PrimitiveJob คุณสามารถรับผลลัพธ์จาก job (เป็นออบเจ็กต์ qiskit.primitives.PrimitiveResult) ด้วยเมธอด 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'>
รับค่าความคาดหวังจากผลลัพธ์
ผลลัพธ์ของ primitives จะส่งออกเป็น array ของออบเจ็กต์ PubResult โดยแต่ละรายการใน array คือออบเจ็กต์ PubResult ที่มีอยู่ใน data ของ array การประเมินที่สอดคล้องกับทุกคู่ Circuit-observable ใน PUB
ในการดึงค่าความคาดหวังและ metadata สำหรับการประเมิน Circuit แรก (และในกรณีนี้เพียงอันเดียว) เราต้องเข้าถึง data การประเมินสำหรับ 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': {}}
กำหนดตัวเลือกการรัน Estimator
โดยค่าเริ่มต้น reference Estimator จะทำการคำนวณ statevector แบบแม่นยำโดยอิงจากคลาส quantum_info.Statevector
อย่างไรก็ตาม สามารถปรับแต่งเพื่อนำผลกระทบของ sampling overhead มาใช้ (หรือที่เรียกว่า "shot noise")
Estimator รับ argument precision ที่แสดงถึง error bar ที่การใช้งาน primitive ควรมุ่งหมายสำหรับการประมาณค่าความคาดหวัง นี่คือ sampling overhead และกำหนดเฉพาะในเมธอด .run() เท่านั้น ซึ่งช่วยให้คุณปรับแต่งตัวเลือกได้ถึงระดับ PUB
# Estimate expectation values for two PUBs, both with 0.05 precision.
precise_job = estimator.run(
[(circuit, observable, parameter_values)], precision=0.05
)
สำหรับตัวอย่างฉบับสมบูรณ์ ดูหน้า ตัวอย่าง Primitives
ใช้งาน reference Sampler
การใช้งาน reference ของ SamplerV2 ใน qiskit.primitives คือคลาส StatevectorSampler มันรับ Circuit และ parameter เป็น input และคืนผลลัพธ์จากการสุ่มตัวอย่างจากการกระจายความน่าจะเป็นของผลลัพธ์เป็น quasi-probability distribution ของ state ผลลัพธ์
โค้ดต่อไปนี้เตรียม input ที่ใช้ในตัวอย่างที่ตามมา โปรดสังเกตว่าตัวอย่างเหล่านี้รัน Circuit ที่มีพารามิเตอร์เพียงวงจรเดียว แต่คุณยังสามารถรัน Sampler กับ Circuit ที่ไม่มีพารามิเตอร์ได้
from qiskit import QuantumCircuit
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure_all()
circuit.draw("mpl", style="iqp")
วงจรควอนตัมทุกวงจรที่ส่งให้ Sampler ต้องมีการวัดผล
ขั้นตอนการทำงานของ Qiskit Runtime primitives ต้องการให้ Circuit ถูกแปลงให้ใช้เฉพาะคำสั่งที่รองรับโด ย QPU (เรียกว่า ISA circuits) Reference primitives ยังคงรับคำสั่งแบบ abstract ได้ เนื่องจากพึ่งพาการจำลอง statevector แบบ local แต่การ transpile Circuit อาจยังเป็นประโยชน์ในแง่ของการปรับแต่ง 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)
Initialize SamplerV2
สร้าง instance ของ qiskit.primitives.StatevectorSampler:
from qiskit.primitives import StatevectorSampler
sampler = StatevectorSampler()
รันและรับผลลัพธ์
# 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'>
Primitives รับ PUB หลายรายการเป็น input และแต่ละ PUB จะได้รับผลลัพธ์ของตัวเอง ดังนั้นคุณสามารถรัน Circuit ต่าง ๆ ด้วยการรวมกันของ parameter/observable ต่าง ๆ และดึงผลลัพธ์ 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'>
รับการกระจายความน่าจะเป็นหรือผลการวัด
ตัวอย่างผลการวัดจะถูกคืนค่าเป็น bitstrings หรือ counts Bitstrings แสดงผลการ วัด โดยรักษาลำดับ shot ที่วัดได้ ออบเจ็กต์ผลลัพธ์ของ Sampler จัดระเบียบข้อมูลตามชื่อ classical register ของ Circuit input เพื่อความเข้ากันได้กับ dynamic circuits
ชื่อของ classical register จะเป็น "meas" โดยค่าเริ่มต้น ชื่อนี้จะใช้ในภายหลังเพื่อเข้าถึง bitstrings การวัด
# 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}
เปลี่ยนตัวเลือกการรัน
โดยค่าเริ่มต้น reference Sampler จะทำการคำนวณ statevector แบบแม่นยำโดยอิงจากคลาส quantum_info.Statevector
อย่างไรก็ตาม สามารถปรับแต่งเพื่อนำผลกระทบของ sampling overhead มาใช้ (หรือที่เรียกว่า "shot noise") เพื่อช่วยจัดการ overhead นี้ อินเทอร์เฟซ Sampler รับ argument shots ที่สามารถกำหนดได้ในระดับ PUB
ตัวอย่างนี้สมมติว่าคุณได้กำหนด 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>
สำหรับตัวอย่างฉบับสมบูรณ์ ดูหน้า ตัวอย่าง Primitives
ขั้นตอนต่อไป
- สำหรับการจำลองที่มีประสิทธิภาพสูงขึ้นซึ่งรองรับ Circuit ขนาดใหญ่ขึ้น หรือเพื่อรวม noise model เข้าไปในการจำลอง ดู การจำลองแบบแม่นยำและมี noise ด้วย Qiskit Aer primitives
- หากต้องการเรียนรู้วิธีใช้ Quantum Composer สำหรับการจำลอง ดูคู่มือ IBM Quantum Composer
- อ่าน Qiskit Estimator API reference
- อ่าน Qiskit Sampler API reference
- อ่าน ย้ายไปยัง V2 primitives