Přeskočit na hlavní obsah

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.

poznámka

Žá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")

Output of the previous code cell

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]]
Transpiluj do ISA obvodů a observables

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")

Output of the previous code cell

poznámka

Každý kvantový Circuit předaný Sampleru musí obsahovat měření.

Transpiluj do ISA obvodů a observables

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.

poznámka

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

Doporučení