Zum Hauptinhalt springen

Classical feedforward and control flow (dynamische Schaltungen)

Paketversionen

Der Code auf dieser Seite wurde mit den folgenden Anforderungen entwickelt. Wir empfehlen die Verwendung dieser oder neuerer Versionen.

qiskit[all]~=2.4.0

Dynamische Schaltungen sind leistungsstarke Werkzeuge, mit denen du Qubits während der Ausführung einer Quantenschaltung messen und anschließend klassische Logikoperationen innerhalb der Schaltung basierend auf dem Ergebnis dieser Mid-Circuit-Messungen durchführen kannst. Dieser Prozess wird auch als Classical Feedforward bezeichnet. Obwohl es noch frühe Tage sind, um zu verstehen, wie man dynamische Schaltungen am besten nutzt, hat die Quantenforschungsgemeinschaft bereits eine Reihe von Anwendungsfällen identifiziert, wie zum Beispiel:

if-Anweisung

Die if-Anweisung wird verwendet, um Operationen basierend auf dem Wert eines klassischen Bits oder Registers bedingt auszuführen.

Im folgenden Beispiel wenden wir ein Hadamard-Gate auf ein Qubit an und messen es. Wenn das Ergebnis 1 ist, wenden wir ein X-Gate auf das Qubit an, was den Effekt hat, es zurück in den 0-Zustand zu kippen. Wir messen dann das Qubit erneut. Das resultierende Messergebnis sollte mit 100%iger Wahrscheinlichkeit 0 sein.

# Added by doQumentation — required packages for this notebook
!pip install -q qiskit
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister

qubits = QuantumRegister(1)
clbits = ClassicalRegister(1)
circuit = QuantumCircuit(qubits, clbits)
(q0,) = qubits
(c0,) = clbits

circuit.h(q0)
circuit.measure(q0, c0)
with circuit.if_test((c0, 1)):
circuit.x(q0)
circuit.measure(q0, c0)
circuit.draw("mpl")

# example output counts: {'0': 1024}

Output of the previous code cell

Der with-Anweisung kann ein Zuweisungsziel gegeben werden, das selbst ein Context Manager ist, der gespeichert und anschließend zur Erstellung eines else-Blocks verwendet werden kann, der ausgeführt wird, wenn die Inhalte des if-Blocks nicht ausgeführt werden.

Im folgenden Beispiel initialisieren wir Register mit zwei Qubits und zwei klassischen Bits. Wir wenden ein Hadamard-Gate auf das erste Qubit an und messen es. Wenn das Ergebnis 1 ist, wenden wir ein Hadamard-Gate auf das zweite Qubit an; andernfalls wenden wir ein X-Gate auf das zweite Qubit an. Schließlich messen wir auch das zweite Qubit.

qubits = QuantumRegister(2)
clbits = ClassicalRegister(2)
circuit = QuantumCircuit(qubits, clbits)
(q0, q1) = qubits
(c0, c1) = clbits

circuit.h(q0)
circuit.measure(q0, c0)
with circuit.if_test((c0, 1)) as else_:
circuit.h(q1)
with else_:
circuit.x(q1)
circuit.measure(q1, c1)

circuit.draw("mpl")

# example output counts: {'01': 260, '11': 272, '10': 492}

Output of the previous code cell

Neben der Bedingung auf einem einzelnen klassischen Bit ist es auch möglich, auf den Wert eines klassischen Registers zu bedingen, das aus mehreren Bits besteht.

Im folgenden Beispiel wenden wir Hadamard-Gates auf zwei Qubits an und messen sie. Wenn das Ergebnis 01 ist, das heißt, das erste Qubit ist 1 und das zweite Qubit ist 0, wenden wir ein X-Gate auf ein drittes Qubit an. Schließlich messen wir das dritte Qubit. Beachte, dass wir aus Gründen der Klarheit den Zustand des dritten klassischen Bits, der 0 ist, in der if-Bedingung angegeben haben. In der Schaltungszeichnung wird die Bedingung durch die Kreise auf den klassischen Bits angezeigt, auf die bedingt wird. Ein ausgefüllter Kreis zeigt eine Bedingung auf 1 an, während ein nicht ausgefüllter Kreis eine Bedingung auf 0 anzeigt.

qubits = QuantumRegister(3)
clbits = ClassicalRegister(3)
circuit = QuantumCircuit(qubits, clbits)
(q0, q1, q2) = qubits
(c0, c1, c2) = clbits

circuit.h([q0, q1])
circuit.measure(q0, c0)
circuit.measure(q1, c1)
with circuit.if_test((clbits, 0b001)):
circuit.x(q2)
circuit.measure(q2, c2)

circuit.draw("mpl")

# example output counts: {'101': 269, '011': 260, '000': 252, '010': 243}

Output of the previous code cell

Klassische Ausdrücke

Das Qiskit-Modul für klassische Ausdrücke qiskit.circuit.classical enthält eine experimentelle Darstellung von Laufzeitoperationen auf klassischen Werten während der Schaltungsausführung. Aufgrund von Hardwareeinschränkungen werden derzeit nur QuantumCircuit.if_test()-Bedingungen unterstützt.

Das folgende Beispiel zeigt, dass du die Berechnung der Parität verwenden kannst, um einen n-Qubit-GHZ-Zustand mit dynamischen Schaltungen zu erstellen. Erzeuge zunächst n/2n/2 Bell-Paare auf benachbarten Qubits. Klebe dann diese Paare zusammen, indem du eine Schicht von CNOT-Gates zwischen den Paaren verwendest. Miss dann das Ziel-Qubit aller vorherigen CNOT-Gates und setze jedes gemessene Qubit auf den Zustand 0\vert 0 \rangle zurück. Wende XX auf jede ungemessene Stelle an, für die die Parität aller vorhergehenden Bits ungerade ist. Schließlich werden CNOT-Gates auf die gemessenen Qubits angewendet, um die bei der Messung verlorene Verschränkung wiederherzustellen.

In der Paritätsberechnung beinhaltet das erste Element des konstruierten Ausdrucks das Anheben des Python-Objekts mr[0] zu einem Value-Knoten (lift wird verwendet, um beliebige Objekte in klassische Ausdrücke umzuwandeln). Dies ist für mr[1] und das mögliche folgende klassische Register nicht notwendig, da sie Eingaben für expr.bit_xor sind und das notwendige Anheben in diesen Fällen automatisch erfolgt. Solche Ausdrücke können in Schleifen und anderen Konstrukten aufgebaut werden.

from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.circuit.classical import expr

num_qubits = 8
if num_qubits % 2 or num_qubits < 4:
raise ValueError("num_qubits must be an even integer ≥ 4")
meas_qubits = list(range(2, num_qubits, 2)) # qubits to measure and reset

qr = QuantumRegister(num_qubits, "qr")
mr = ClassicalRegister(len(meas_qubits), "m")
qc = QuantumCircuit(qr, mr)

# Create local Bell pairs
qc.reset(qr)
qc.h(qr[::2])
for ctrl in range(0, num_qubits, 2):
qc.cx(qr[ctrl], qr[ctrl + 1])

# Glue neighboring pairs
for ctrl in range(1, num_qubits - 1, 2):
qc.cx(qr[ctrl], qr[ctrl + 1])

# Measure boundary qubits between pairs,reset to 0
for k, q in enumerate(meas_qubits):
qc.measure(qr[q], mr[k])
qc.reset(qr[q])

# Parity-conditioned X corrections
# Each non-measured qubit gets flipped iff the parity (XOR) of all
# preceding measurement bits is 1
for tgt in range(num_qubits):
if tgt in meas_qubits: # skip measured qubits
continue
# all measurement registers whose physical qubit index < tgt
left_bits = [k for k, q in enumerate(meas_qubits) if q < tgt]
if not left_bits: # skip if list empty
continue

# build XOR-parity expression
parity = expr.lift(
mr[left_bits[0]]
) # lift the first bit to Value so it will be treated like a boolean.
for k in left_bits[1:]:
parity = expr.bit_xor(
mr[k], parity
) # calculate parity with all other bits
with qc.if_test(parity): # Add X if parity is 1
qc.x(qr[tgt])

# Re-entangle measured qubits
for ctrl in range(1, num_qubits - 1, 2):
qc.cx(qr[ctrl], qr[ctrl + 1])
qc.draw(output="mpl", style="iqp", idle_wires=False, fold=-1)

Output of the previous code cell

Nächste Schritte

Empfehlungen