Přesná simulace s primitivy Qiskit SDK
Verze balíčků
Kód na této stránce byl vyvinut s využitím následujících požadavků. Doporučujeme používat tyto verze nebo novější.
qiskit[all]~=2.3.0
Referenční primitiva v Qiskit SDK provádějí lokální simulace stavového vektoru. Tyto simulace nepodporují modelování šumu zařízení, ale jsou užitečné pro rychlé prototypování algoritmů před tím, než se začneš zabývat pokročilejšími simulačními technikami (pomocí Qiskit Aer) nebo spuštěním na skutečných zařízeních (primitiva Qiskit Runtime).
Primitivum Estimator dokáže vypočítat střední hodnoty obvodů a primitivum Sampler může vzorkovat z výstupních distribucí obvodů.
Následujíc í části ukazují, jak používat referenční primitiva ke spuštění svého workflow lokálně.
Použití referenčního Estimatoru
Referenční implementace EstimatorV2 v qiskit.primitives, která běží na lokálním simulátoru stavového vektoru,
je třída StatevectorEstimator. Jako vstupy přijímá Circuit, observables a parametry a vrací lokálně vypočítané střední hodnoty.
Následující kód připravuje vstupy, které budou použity v příkladech níže. Očekávaný typ vstupu pro
observables je qiskit.quantum_info.SparsePauliOp. Všimni si, že
Circuit v příkladu je parametrizovaný, ale Estimator lze spustit i na neparametrizovaných obvodech.
Žádný Circuit předaný Estimatoru nesmí obsahovat žádná měření.
# 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]]
Workflow primitiv Qiskit Runtime vyžaduje, aby byly Circuit a observables transformovány tak, aby používaly pouze instrukce podporované QPU (označované jako obvody a observables architektury instrukční sady (ISA)). Referenční primitiva stále přijímají abstraktní instrukce, protože se spoléhají na lokální simulace stavového vektoru, ale transpilace obvodu může být přesto přínosná z hlediska jeho optimalizace.
# 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)
Inicializace Estimatoru
Vytvoř instanci qiskit.primitives.StatevectorEstimator.
from qiskit.primitives import StatevectorEstimator
estimator = StatevectorEstimator()
Spuštění a získání výsledků
Tento příklad používá pouze jeden Circuit (typu QuantumCircuit) a jedno
observable.
Spusť odhad zavoláním metody StatevectorEstimator.run, která vrací instanci objektu PrimitiveJob. Výsledky z úlohy (jako objekt qiskit.primitives.PrimitiveResult) získáš metodou 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'>
Získání střední hodnoty z výsledku
Výstup výsledků primitiv je pole objektů PubResult, kde každá položka pole je objekt PubResult, který ve svých datech obsahuje pole vyhodnocení odpovídající každé kombinaci Circuit–observable v PUBu.
Abychom získali střední hodnoty a metadata pro první (a v tomto případě jediné) vyhodnocení Circuit, musíme přistoupit k vyhodnocovacím data pro 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': {}}
Nastavení možností spuštění Estimatoru
Ve výchozím nastavení provádí referenční Estimator přesný výpočet stavového vektoru na základě
třídy quantum_info.Statevector.
To lze ale upravit tak, aby se zohlednil vliv vzorkovací režie (také známé jako „shot noise").
Estimator přijímá argument precision, který vyjadřuje chybové úsečky, na které by se implementace
primitiva měla zaměřit při odhadech středních hodnot. Jde o vzorkovací režii a je definována výhradně v metodě .run(). To ti umožňuje doladit tuto možnost až na úroveň PUBu.
# Estimate expectation values for two PUBs, both with 0.05 precision.
precise_job = estimator.run(
[(circuit, observable, parameter_values)], precision=0.05
)
Úplný příklad najdeš na stránce Příklady primitiv.
Použití referenčního Sampleru
Referenční implementace SamplerV2 v qiskit.primitives je třída StatevectorSampler. Jako vstupy přijímá Circuit a parametry a vrací výsledky vzorkování z výstupních pravděpodobnostních distribucí jako kvazi-pravděpodobnostní distribuci výstupních stavů.
Následující kód připravuje vstupy použité v příkladech níže. Všimni si, že tyto příklady spouštějí jeden parametrizovaný Circuit, ale Sampler lze spustit i na neparametrizovaných obvodech.
from qiskit import QuantumCircuit
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure_all()
circuit.draw("mpl", style="iqp")
Každý kvantový Circuit předaný Sampleru musí obsahovat měření.
Workflow primitiv Qiskit Runtime vyžaduje, aby byly Circuit transformovány tak, aby používaly pouze instrukce podporované QPU (označované jako ISA Circuit). Referenční primitiva stále přijímají abstraktní instrukce, protože se spoléhají na lokální simulace stavového vektoru, ale transpilace obvodu mů že být přesto přínosná z hlediska jeho optimalizace.
# 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)
Inicializace SamplerV2
Vytvoř instanci qiskit.primitives.StatevectorSampler:
from qiskit.primitives import StatevectorSampler
sampler = StatevectorSampler()
Spuštění a získání výsledků
# 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'>
Primitiva přijímají jako vstupy více PUBů a každý PUB dostane vlastní výsledek. Můžeš tedy spouštět různé Circuit s různými kombinacemi parametrů/observables a získávat výsledky 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'>
Získání pravděpodobnostní distribuce nebo výsledku měření
Vzorky výsledků měření jsou vráceny jako bitové řetězce nebo počty. Bitové řetězce ukazují výsledky měření a zachovávají pořadí shotů, v jakém byly naměřeny. Objekty výsledků Sampleru organizují data podle názvů klasických registrů vstupních obvodů, kvůli kompatibilitě s dynamickými obvody.
Název klasického registru je ve výchozím nastavení "meas". Tento název bude později použit pro přístup k bitovým řetězcům měření.
# 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}
Změna možností spuštění
Ve výchozím nastavení provádí referenční Sampler přesný výpočet stavového vektoru na základě
třídy quantum_info.Statevector.
To lze ale upravit tak, aby se zohlednil vliv vzorkovací režie (také známé jako „shot noise"). Pro usnadnění správy této režie přijímá rozhraní Sampleru argument shots, který lze definovat na úrovni PUBu.
Tento příklad předpokládá, že máš definované dva 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>
Úplný příklad najdeš na stránce Příklady primitiv.
Další kroky
- Pro výkonnější simulaci, která zvládne větší Circuit, nebo pro zahrnutí modelů šumu do simulace, viz Přesná a zašuměná simulace s primitivy Qiskit Aer.
- Jak používat Quantum Composer pro simulaci se dozvíš v průvodci IBM Quantum Composer.
- Přečti si referenci Qiskit Estimator API.
- Přečti si referenci Qiskit Sampler API.
- Přečti si Migrace na primitiva V2.