Skip to main content
IBM Quantum Platform

Basiselemente

qiskit.primitives

Bei den Primitiven handelt es sich um Rechenbausteine, die in größeren Anwendungen verwendet werden sollen, deren Eingabeeinheiten, die so genannten Primitive Unified Blocks (PUBs), Quantenressourcen benötigen, um effizient Ausgaben zu erzeugen.

BaseEstimatorV2Derzeit gibt es zwei Arten von Primitiven, deren Abstraktionen in ihren neuesten Versionen durch BaseSamplerV2 und definiert sind. Sampler sind dafür zuständig, Quantenkreise (oder Durchläufe von Werten über parametrisierte Kreise) entgegenzunehmen und Werte aus deren klassischen Ausgaberegistern abzutasten. Schätzer akzeptieren Kombinationen aus Schaltkreisen und Observablen (oder deren Durchläufe), um die Erwartungswerte der Observablen zu schätzen.

Qiskit bietet für jede dieser Abstraktionen eine Referenzimplementierung in den StatevectorSampler Klassen und StatevectorEstimator an.

BaseEstimatorV1Die früheren Versionen der Sampler- und Schätzer-Abstraktionen sind durch BaseSamplerV1 und definiert. BaseEstimatorV2Diese Schnittstellen verwenden ein anderes und weniger flexibles Eingabe-Ausgabe-Format für die run Methode und wurden in der Praxis weitgehend durch BaseSamplerV2 und ersetzt. Aus Gründen der Abwärtskompatibilität wurden die ursprünglichen Definitionen der abstrakten Schnittstellen jedoch beibehalten. Weitere Informationen zu den Unterschieden zwischen V1 und V2 finden Sie im Abschnitt „Migration“ auf dieser Seite.


Übersicht über „ EstimatorV2 “

BaseEstimatorV2 ist eine Primitive, die Erwartungswerte für vorgegebene Kombinationen aus Quantenschaltungen und Observablen schätzt.

Nach der Erstellung wird ein Schätzer verwendet, indem dessen run() Methode mit einer Liste von Pubs (Primitive Unified Blocs) aufgerufen wird. Jeder Eintrag enthält drei Werte, die zusammen eine Berechnungseinheit definieren, die der Schätzer ausführen muss:

  • ein einzelnes QuantumCircuit, möglicherweise parametrisiertes Element, dessen Endzustand wir als „ ψ(θ)\psi(\theta) “ definieren,
  • ObservablesArrayLikeeine oder mehrere Observablen (die beliebig festgelegt werden können, einschließlich Pauli, SparsePauliOp, str), die angeben, welche Erwartungswerte geschätzt werden sollen, bezeichnet als HjH_j, und
  • eine Sammlung von Parameterwertsätzen, an die die Schaltung gebunden werden soll, θk\theta_k.

Der Aufruf eines Schätzers liefert ein BasePrimitiveJob Objekt zurück, bei dem der Aufruf der Methode result() zu Schätzungen der Erwartungswerte und Metadaten für jeden Pub führt:

⟨ψ(θk)∣Hj∣ψ(θk)⟩\langle\psi(\theta_k)|H_j|\psi(\theta_k)\rangle

Die Observablen und Parameterwerte eines Pubs können in einem Array mit beliebigen Dimensionen bewertet werden, wobei die Standardübertragungsregeln angewandt werden, so dass das geschätzte Ergebnis für jedes Pub im Allgemeinen ebenfalls in einem Array bewertet wird. Weitere Informationen finden Sie hier.

Hier ein Beispiel, wie ein Schätzer verwendet wird.

from qiskit.primitives import StatevectorEstimator as Estimator
from qiskit.circuit.library import RealAmplitudes
from qiskit.quantum_info import SparsePauliOp

psi1 = RealAmplitudes(num_qubits=2, reps=2)
psi2 = RealAmplitudes(num_qubits=2, reps=3)

H1 = SparsePauliOp.from_list([("II", 1), ("IZ", 2), ("XI", 3)])
H2 = SparsePauliOp.from_list([("IZ", 1)])
H3 = SparsePauliOp.from_list([("ZI", 1), ("ZZ", 1)])

theta1 = [0, 1, 1, 2, 3, 5]
theta2 = [0, 1, 1, 2, 3, 5, 8, 13]
theta3 = [1, 2, 3, 4, 5, 6]

estimator = Estimator()

# calculate [ <psi1(theta1)|H1|psi1(theta1)> ]
job = estimator.run([(psi1, H1, [theta1])])
job_result = job.result() # It will block until the job finishes.
print(f"The primitive-job finished with result {job_result}")

# calculate [ [<psi1(theta1)|H1|psi1(theta1)>,
#              <psi1(theta3)|H3|psi1(theta3)>],
#             [<psi2(theta2)|H2|psi2(theta2)>] ]
job2 = estimator.run(
    [
        (psi1, [H1, H3], [theta1, theta3]),
        (psi2, H2, theta2)
    ],
    precision=0.01
)
job_result = job2.result()
print(f"The primitive-job finished with result {job_result}")

Übersicht über „ SamplerV2 “

BaseSamplerV2 ist eine Primitive, die Ausgabewerte von Quantenschaltungen abtastet.

Nach der Erstellung wird ein Sampler verwendet, indem dessen run() Methode mit einer Liste von Pubs (Primitive Unified Blocs) aufgerufen wird. Jede Pub enthält Werte, die zusammen eine Recheneinheit definieren, die der Sampler ausführen soll:

  • Eine einzelne QuantumCircuit, möglicherweise parametrisiert.
  • Eine Sammlung von Parameterwertsätzen, an die der Schaltkreis gebunden wird, wenn er parametrisch ist.
  • Optional die Anzahl der Schüsse, die in der Laufmethode bestimmt werden, falls nicht festgelegt.

Der Aufruf eines Samplers gibt ein BasePrimitiveJob Objekt zurück, bei dem der Aufruf der Methode result() zu Ausgabe-Samples und Metadaten für jede Veröffentlichung führt.

Hier ist ein Beispiel für die Verwendung eines Samplers.

from qiskit.primitives import StatevectorSampler as Sampler
from qiskit import QuantumCircuit
from qiskit.circuit.library import RealAmplitudes

# create a Bell circuit
bell = QuantumCircuit(2)
bell.h(0)
bell.cx(0, 1)
bell.measure_all()

# create two parameterized circuits
pqc = RealAmplitudes(num_qubits=2, reps=2)
pqc.measure_all()
pqc2 = RealAmplitudes(num_qubits=2, reps=3)
pqc2.measure_all()

theta1 = [0, 1, 1, 2, 3, 5]
theta2 = [0, 1, 2, 3, 4, 5, 6, 7]

# initialization of the sampler
sampler = Sampler()

# collect 128 shots from the Bell circuit
job = sampler.run([bell], shots=128)
job_result = job.result()
print(f"The primitive-job finished with result {job_result}")

# run a sampler job on the parameterized circuits
job2 = sampler.run([(pqc, theta1), (pqc2, theta2)])
job_result = job2.result()
print(f"The primitive-job finished with result {job_result}")

Übersicht über „ EstimatorV1 “

Derzeit gibt es in Qiskit keine Implementierungen der veralteten EstimatorV1 Schnittstelle. Die Definition der abstrakten Schnittstelle aus BaseEstimatorV1 ist jedoch weiterhin Teil des Pakets, um die Abwärtskompatibilität für externe Implementierungen zu gewährleisten.

Eine EstimatorV1 Implementierung wird mit einem leeren Parametersatz initialisiert. BaseEstimatorV1 kann über die .run() Methode mit den folgenden Parametern aufgerufen werden:

  • quantenschaltungen ( ψi(θ)\psi_i(\theta) ): Liste von (parametrisierten) Quantenschaltungen (eine Liste von QuantumCircuit objekten).
  • Observables ( HjH_j ): eine Liste von SparsePauliOp Objekten.
  • parameter values ( θk\theta_k ): Liste der Wertesätze, die an die Parameter der Quantenschaltungen gebunden werden sollen (list of list of float).

Die Methode sollte ein JobV1 Objekt zurückgeben. Der Aufruf qiskit.providers.JobV1.result() liefert eine Liste von Erwartungswerten sowie optionale Metadaten wie Konfidenzintervalle für die Schätzung.

⟨ψi(θk)∣Hj∣ψi(θk)⟩\langle\psi_i(\theta_k)|H_j|\psi_i(\theta_k)\rangle

Hier ein Beispiel, wie eine EstimatorV1 Implementierung verwendet werden könnte. Beachten Sie, dass es derzeit keine Implementierungen der alten Schnittstelle EstimatorV1 in Qiskit gibt.

# This is a fictional import path.
# There are currently no EstimatorV1 implementations in Qiskit.
from estimator_v1_location import EstimatorV1
from qiskit.circuit.library import RealAmplitudes
from qiskit.quantum_info import SparsePauliOp

psi1 = RealAmplitudes(num_qubits=2, reps=2)
psi2 = RealAmplitudes(num_qubits=2, reps=3)

H1 = SparsePauliOp.from_list([("II", 1), ("IZ", 2), ("XI", 3)])
H2 = SparsePauliOp.from_list([("IZ", 1)])
H3 = SparsePauliOp.from_list([("ZI", 1), ("ZZ", 1)])

theta1 = [0, 1, 1, 2, 3, 5]
theta2 = [0, 1, 1, 2, 3, 5, 8, 13]
theta3 = [1, 2, 3, 4, 5, 6]

estimator = EstimatorV1()

# calculate [ <psi1(theta1)|H1|psi1(theta1)> ]
job = estimator.run([psi1], [H1], [theta1])
job_result = job.result() # It will block until the job finishes.
print(f"The primitive-job finished with result {job_result}")

# calculate [ <psi1(theta1)|H1|psi1(theta1)>,
#             <psi2(theta2)|H2|psi2(theta2)>,
#             <psi1(theta3)|H3|psi1(theta3)> ]
job2 = estimator.run(
    [psi1, psi2, psi1],
    [H1, H2, H3],
    [theta1, theta2, theta3]
)
job_result = job2.result()
print(f"The primitive-job finished with result {job_result}")

Übersicht über „ SamplerV1 “

Derzeit gibt es in Qiskit keine Implementierungen der veralteten SamplerV1 Schnittstelle. Die Definition der abstrakten Schnittstelle aus BaseSamplerV1 ist jedoch weiterhin Teil des Pakets, um die Abwärtskompatibilität für externe Implementierungen zu gewährleisten.

Sampler-Klassen berechnen Wahrscheinlichkeiten oder Quasi-Wahrscheinlichkeiten von Bitstrings aus Quantenschaltungen.

A SamplerV1 wird mit einer leeren Parametermenge initialisiert. BaseSamplerV1 Implementierungen können über die .run() Methode mit den folgenden Parametern aufgerufen werden:

  • quantenschaltungen ( ψi(θ)\psi_i(\theta) ): Liste von (parametrisierten) Quantenschaltungen. (eine Liste von QuantumCircuit objekten)
  • parameterwerte ( θk\theta_k ): Liste der Sätze von Parameterwerten, die an die Parameter der Quantenschaltungen gebunden werden. (Liste von Liste von Float)

.run() gibt ein JobV1 Objekt zurück. Der Aufruf qiskit.providers.JobV1.result() liefert ein SamplerResult Objekt, das Wahrscheinlichkeiten oder Quasi-Wahrscheinlichkeiten von Bitfolgen sowie optionale Metadaten wie Fehlerbalken in den Stichproben enthält.

Hier ein Beispiel, wie eine SamplerV1 Implementierung verwendet werden könnte. Beachten Sie, dass es derzeit keine Implementierungen der alten Schnittstelle SamplerV1 in Qiskit gibt.

# This is a fictional import path.
# There are currently no SamplerV1 implementations in Qiskit.
from sampler_v1_location import Sampler
from qiskit import QuantumCircuit
from qiskit.circuit.library import RealAmplitudes

# a Bell circuit
bell = QuantumCircuit(2)
bell.h(0)
bell.cx(0, 1)
bell.measure_all()

# two parameterized circuits
pqc = RealAmplitudes(num_qubits=2, reps=2)
pqc.measure_all()
pqc2 = RealAmplitudes(num_qubits=2, reps=3)
pqc2.measure_all()

theta1 = [0, 1, 1, 2, 3, 5]
theta2 = [0, 1, 2, 3, 4, 5, 6, 7]

# initialization of the sampler
sampler = SamplerV1()

# Sampler runs a job on the Bell circuit
job = sampler.run(
    circuits=[bell], parameter_values=[[]], parameters=[[]]
)
job_result = job.result()
print([q.binary_probabilities() for q in job_result.quasi_dists])

# Sampler runs a job on the parameterized circuits
job2 = sampler.run(
    circuits=[pqc, pqc2],
    parameter_values=[theta1, theta2],
    parameters=[pqc.parameters, pqc2.parameters])
job_result = job2.result()
print([q.binary_probabilities() for q in job_result.quasi_dists])

Migration von Primitives V1 zu V2

Der formale Unterschied zwischen den Primitives- V1 - und V2 -APIs besteht in den Basisklassen, von denen die Implementierungen der Primitive erben; diese sind alle am Ende der Seite aufgeführt. Auf konzeptioneller Ebene gibt es jedoch einige wichtige Unterschiede, die bei der Migration von V1 zu V2: zu beachten sind

  1. Die Primitive von V2 bevorzugen vektorisierte Eingaben, bei denen einzelne Schaltungen mit vektorwertigen (oder allgemeiner: array-wertigen) Spezifikationen gruppiert werden können. Jede Gruppe wird als primitiver einheitlicher Block (Pub) bezeichnet, und jeder Pub erhält sein eigenes Ergebnis. Im Schätzer können Sie zum Beispiel die folgenden Unterschiede vergleichen:

    # Favoured V2 pattern. There is only one pub here, but there could be more.
    job = estimator_v2.run([(circuit, [obs1, obs2, obs3, obs4])])
    evs = job.result()[0].data.evs
    
    # V1 equivalent, where the same circuit must be provided four times.
    job = estimator_v1.run([circuit] * 4, [obs1, obs2, obs3, obs4])
    evs = job.result().values

    Der Einfachheit halber wird im obigen Beispiel nicht gezeigt, dass der Schaltkreis parametrisch sein kann, mit Arrays von Parameterwertsätzen, die gegen das Array von Observablen übertragen werden. Der Probenehmer ist ähnlich, aber ohne Beobachtungswerte:

    # Favoured V2 pattern. There is only one pub here, but there could be more.
    job = sampler_v2.run([(circuit, [vals1, vals2, vals3])])
    samples = job.result()[0].data
    
    # V1 equivalent, where the same circuit must be provided three times.
    sampler_v1.run([circuit] * 3, [vals1, vals2, vals3])
    quasi_dists = job.result().quasi_dists
  2. Der V2 Sampler liefert Stichproben klassischer Ergebnisse, wobei die Schussreihenfolge, in der sie gemessen wurden, beibehalten wird. Dies steht im Gegensatz zum V1 Sampler, der Quasi-Wahrscheinlichkeitsverteilungen ausgibt, die stattdessen eine Schätzung der Verteilung über klassische Ergebnisse sind. Darüber hinaus organisieren die Ergebnisobjekte des V2 Samplers die Daten in Form der klassischen Registernamen ihrer Eingangsschaltungen, was eine natürliche Kompatibilität mit dynamischen Schaltungen bietet.

    Das am ehesten vergleichbare Äquivalent zu Quasi-Wahrscheinlichkeitsverteilungen in der Schnittstelle „ V2 “ ist die get_counts() Methode, die im folgenden Beispiel gezeigt wird. Wir betonen jedoch, dass bei Experimenten im industriellen Maßstab (100+ Qubits) die Wahrscheinlichkeit, dieselbe Bitfolge zweimal zu messen, gering ist, sodass eine Zusammenfassung der Zählwerte in Form eines Wörterbuchs in der Regel keine effiziente Strategie zur Datenverarbeitung darstellt.

    circuit = QuantumCircuit(QuantumRegister(2, "qreg"), ClassicalRegister(2, "alpha"))
    circuit.h(0)
    circuit.cx(0, 1)
    circuit.measure([0, 1], [0, 1])
    
    # V1 sampler usage
    result = sampler_v1.run([circuit]).result()
    quasi_dist = result.quasi_dists[0]
    
    # V2 sampler usage
    result = sampler_v2.run([circuit]).result()
    # these are the bit values from the alpha register, over all shots
    bitvals = result[0].data.alpha
    # we can use it to generate a Counts mapping, which is similar to a quasi prob distribution
    counts = bitvals.get_counts()
    # which can in turn be converted to the V1 type through normalization
    quasi_dist = QuasiDistribution({outcome: freq / shots for outcome, freq in counts.items()})
  3. Die Primitive „ V2 “ haben das Konzept des Sampling-Overheads, das allen Quantensystemen aufgrund ihrer inhärenten probabilistischen Natur eigen ist, aus den Optionen heraus und direkt in die API selbst integriert. shotsFür den Sampler bedeutet dies, dass das shots Argument nun Teil der run() Signatur ist und dass darüber hinaus jede Pub ihren eigenen Wert für angeben kann, der Vorrang vor jedem der Methode übergebenen Wert hat. Der Schätzer verfügt über ein entsprechendes precision Argument, das die Fehlerbalken festlegt, die die primitive Implementierung bei der Schätzung von Erwartungswerten anstreben soll.

    Dieses Konzept ist in der API der V1 Primitive nicht vorhanden, obwohl alle Implementierungen der V1 Primitive irgendwo in ihren Optionen entsprechende Einstellungen haben.

    # Sample two circuits at 128 shots each.
    sampler_v2.run([circuit1, 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_v2.run([(circuit1, None, 123), (circuit2, None, 456)])
    
    # Estimate expectation values for two pubs, both with 0.05 precision.
    estimator_v2.run([(circuit1, obs_array1), (circuit2, obs_array_2)], precision=0.05)

Primitive API

Parameter V2

Kolumne „ 1 “
Kolumne „ 2 “
ParameterLikeEinen Vereinigungstyp darstellen
BindingsArray( [Daten, Form] )Speichert Parameter-Bindungswertsätze für ein qiskit.QuantumCircuit.
Kolumne „ 1 “
Kolumne „ 2 “
BindingsArrayLikeAlias von `Mapping[ParameterLike

Schätzer V2

Kolumne „ 1 “
Kolumne „ 2 “
BaseEstimatorV2()Basisklasse für EstimatorV2 -Implementierungen.
StatevectorEstimator(*[, Standardgenauigkeit,...] )Einfache Implementierung von BaseEstimatorV2 mit vollständiger Zustandsvektorsimulation.
BackendEstimatorV2(*, Backend[, Optionen] )Bewertet Erwartungswerte für vorgegebene Kombinationen von Quantenschaltungen und beobachtbaren Größen.
EstimatorPub(Schaltkreis, Messgrößen[,...] )Einheitlicher Primitivblock für alle Schätzprimitive.
ObservablesArray(Beobachtbare [Größen, num_qubits,...] )Ein ND-Array hermitischer Observablen für eine Estimator Primitive.
ObservableLikeEinen Vereinigungstyp darstellen
Kolumne „ 1 “
Kolumne „ 2 “
EstimatorPubLikeAlias von EstimatorPub
ObservablesArrayLikeAlias von `ObservableLike

Sampler- V2

Kolumne „ 1 “
Kolumne „ 2 “
BaseSamplerV2()Basisklasse für SamplerV2 -Implementierungen.
StatevectorSampler(*[, default_shots, seed] )Einfache Implementierung unter BaseSamplerV2 Verwendung einer vollständigen Zustandsvektorsimulation.
BackendSamplerV2(*, Backend[, Optionen] )Bewertet Bitstrings für bereitgestellte Quantenschaltungen
SamplerPub(Schaltung[, Parameterwerte,...] )Pub (Primitive Unified Bloc) für einen Sampler.
Kolumne „ 1 “
Kolumne „ 2 “
SamplerPubLikeAlias von SamplerPub

Ergebnisse V2

Kolumne „ 1 “
Kolumne „ 2 “
BitArray(array, num_bits)Speichert ein Array von Bitwerten.
DataBin(*[, Form] )Die wichtigsten Daten stammen aus einer einzigen Kneipe von PubResult.
PrimitiveResult(pub_results[, metadata] )Ein Container für mehrere Pub-Ergebnisse und globale Metadaten.
PubResult(Daten[, Metadaten] )Das Ergebnisobjekt für eine einzelne Kneipe (primitiver einheitlicher Block).
SamplerPubResult(Daten[, Metadaten] )Ergebnis von Sampler Pub.
BasePrimitiveJob(job_id, **kwargs)Primitive abstrakte Basisklasse für Jobs.
PrimitiveJob(function, *args, **kwargs)Behandeln Sie einen Job aus den Referenzimplementierungen der Primitiven in Qiskit.

Schätzer V1

Kolumne „ 1 “
Kolumne „ 2 “
BaseEstimatorV1(*[, Optionen] )Basisklasse für EstimatorV1 -Implementierungen.
EstimatorResult(Werte, Metadaten)Ergebnis der Schätzung V1.

Sampler- V1

Kolumne „ 1 “
Kolumne „ 2 “
BaseSamplerV1(*[, Optionen] )Probenehmer V1 Basisklasse
SamplerResult(quasi_dists, metadata)Ergebnis des Probenehmers V1.
War diese Seite hilfreich?
Melden Sie auf GitHub einen Fehler, einen Tippfehler oder fordern Sie Inhalte an.