Rauschmodelle für Multi-Qubit-Gates erstellen

Das Microsoft Quantum Development Kit (QDK) Python Paket unterstützt flexible Rauschmodelle für Multi-Qubit-Gatter in Simulationen von Quantenprogrammen. Sie können korrelierte Fehler und andere Rauscheffekte über mehrere Qubits modellieren, um das Verhalten der Quantenhardware genauer darzustellen.

Weitere Informationen zu Rauschmodellen im QDK finden Sie unter Erstellen von Rauschmodellen für Quantensimulationen im QDK.

Voraussetzungen

Um Rauschmodelle im QDK zu erstellen, installieren Sie die folgenden Tools.

pip install --upgrade "qdk[jupyter]"

Korreliertes Rauschen

Mehr-Qubit-Gates können korreliertes Rauschen erzeugen, bei dem dasselbe Rauschmuster auf alle Qubits angewendet wird, auf die das Gate wirkt. Um korreliertes Rauschen bei Multi-Qubit-Gattern festzulegen, geben Sie für jedes Qubit einen Rauschparameter an.

Der folgende Python-Code legt beispielsweise korrelierte Bit-Flips auf $CX$-Gates mit einer Wahrscheinlichkeit von 2 % fest. Wenn Rauschen auf einem $CX$-Gate auftreten, gilt ein $X$-Gate sowohl für das Steuer-Qubit als auch für das Ziel-Qubit. Das Rauschen ist korreliert, da es immer auf beide Qubits wirkt.

from qdk.simulation import NoiseConfig

noise = NoiseConfig()

noise.cx.xx = 0.02

Um das Rauschen unkorreliert zu machen, legen Sie mehrere Rauschtypen mit dem Parameter „identity“ fest.

noise.cx.xi = 0.02 # Bit flip on control qubit, do nothing to target qubit
noise.cx.ix = 0.02 # Do nothing to control qubit, bit flip on target qubit

Im unkorrelierten Modell tritt jeder Rauschparameter unabhängig mit einer Wahrscheinlichkeit von 2 % auf. Da für ein einzelnes Gatter nur ein Rauschparameter gelten kann, kann dieses Rauschmodell nicht $X$-Rauschen auf beide Qubits im selben Gatter anwenden.

Um die Möglichkeit von Rauschen auf beiden Qubits zu modellieren, konfigurieren Sie eine weitere Rauscheinstellung, die Rauschen auf beide Qubits anwendet.

noise.cx.xi = 0.02 # Bit flip on control qubit, do nothing to target qubit
noise.cx.ix = 0.02 # Do nothing to control qubit, bit flip on target qubit
noise.cx.xx = 0.02 # Bit flip on both qubits

Qubit-Verlustrichtlinien

Qubit-Verlust ist eine Art von Rauschen, bei dem Qubits vom Gerät verloren gehen. Verlustregeln legen das Verhalten eines Mehr-Qubit-Gatters fest, wenn zu Beginn des Vorgangs eines oder mehrere der Qubits fehlen. Das QDK unterstützt die folgenden Verlustrichtlinien.

Verlustrichtlinie Gates, für die die Richtlinie gelten kann Auswirkung auf verbleibende Qubits
SKIP Alle Tore Das Tor wirkt sich nicht auf die verbleibenden Qubits aus
PROPAGATE Alle Tore Die anderen Qubits gehen ebenfalls verloren
DEGRADE rxx ,ryy, und rzz Als Single-Qubit-Gate auf das verbleibende Qubit anwenden
RESIDUAL_S_DAGGER Alle Tore Das s_sdj-Gatter auf die verbleibenden Qubits anwenden
APPLY_ANYWAY swap Das verbleibende Qubit tauscht weiterhin Zustände mit dem verlorenen Qubit aus.

Damit sich Verlustrichtlinien auf Ihre Simulation auswirken, müssen Sie Qubit-Verluste in Ihr Rauschmodell einbeziehen. Verlorene Qubits werden während der Simulation nachverfolgt. Verlustrichtlinien gelten, wenn ein Gate mit mindestens einem verlorenen Qubit arbeitet.

Verwenden Sie LossPolicy aus dem qdk.simulation-Modul, um Verlustrichtlinien in Ihr Rauschmodell einzuschließen. Der folgende Code zeigt Beispiele zum Festlegen der einzelnen Richtlinien.

from qdk.simulation import NoiseConfig, LossPolicy

noise = NoiseConfig()

noise.x.l = 0.01 # 1% chance of qubit loss after X gates

noise.cz.on_loss   = LossPolicy.SKIP               # Don't apply CZ to remaining qubit
noise.cx.on_loss   = LossPolicy.PROPAGATE          # Both qubits are lost from CX gate
noise.rxx.on_loss  = LossPolicy.DEGRADE            # Apply Rx gate to remaining qubit
noise.ryy.on_loss  = LossPolicy.RESIDUAL_S_DAGGER  # Apply S-adjoint to remaining qubit
noise.swap.on_loss = LossPolicy.APPLY_ANYWAY       # Perform swap anyway

Für alle Verlustrichtlinien kann sich das konfigurierte Rauschen weiterhin auf die verbleibenden Qubits auswirken. Der nachfolgende Code kann z. B. weiterhin Bit-Flip-Rauschen auf CZ-Gates anwenden, auch wenn eines der Qubits in einem CZ-Gate fehlt.

noise.z.l = 0.01 # Introduce qubit loss

noise.cz.xx = 0.02 # Set correlated bit flip noise on CZ gates
noise.cz.on_loss = LossPolicy.SKIP

Benutzerdefiniertes systeminternes Rauschen

Zum Erstellen komplexerer Rauschmodelle verfügt das QDK über benutzerdefiniertes systeminternes Rauschen für Q#- und OpenQASM-Programme. Systeminternes Rauschen verhält sich wie benutzerdefinierte Gatter, die Sie in Ihr Programm einfügen, um korreliertes Rauschen zu modellieren. Sie können benutzerdefiniertes systeminternes Rauschen verwenden, um das Rauschen an den Gattern zu modellieren, die von NoiseConfig unterstützt werden, oder an benutzerdefinierten Gattern.

Die folgenden Beispiele zeigen, wie Sie ein benutzerdefiniertes systeminternes Rauschen erstellen, das Übersprechen zwischen drei Qubits modelliert. Das systeminterne Rauschen wendet korrelierte Bit-Flips auf zwei der Qubits an, nachdem ein $CNOT$-Gatter angewendet wurde.

Hinzufügen von systeminternem Rauschen zu einem Q#-Programm

Verwenden Sie in Q#-Programmen @NoiseIntrinsic(), um ein systeminternes Rauschen zu deklarieren. Verwenden Sie anschließend die Methode intrinsic aus NoiseConfig, um das systeminterne Rauschen zu konfigurieren.

Um das systeminterne Rauschen aus dem Beispiel zu konfigurieren und zu verwenden, führen Sie die folgenden Schritte in einem Jupyter Notebook aus.

  1. Importieren Sie die erforderlichen Objekte, und legen Sie das QIR-Zielprofil fest.

    from qdk import init, TargetProfile
    from qdk import qsharp
    from qdk.simulation import run_qir, NoiseConfig
    
    init(target_profile=TargetProfile.Adaptive_RIF)
    
  2. Schreiben Sie ein Q#-Programm mit dem Namen GHZ, das nach jedem $CNOT$-Gatter eins systeminternes Rauschen mit dem Namen Crosstalk3Q aufruft.

    %%qsharp
    
    // A noise intrinsic representing crosstalk on 3 qubits.
    // In the ideal circuit this is a no-op; the simulator injects
    // Pauli errors according to the NoiseConfig.
    @NoiseIntrinsic()
    operation Crosstalk3Q(q0: Qubit, q1: Qubit, q2: Qubit) : Unit {
        body intrinsic;
    }
    
    // Prepare a GHZ state on 3 qubits, with crosstalk after each CNOT.
    operation GHZ() : Result[] {
        use qs = Qubit[3];
        H(qs[0]);
        CNOT(qs[0], qs[1]);
        Crosstalk3Q(qs[0], qs[1], qs[2]);  // crosstalk hits all 3 qubits
        CNOT(qs[1], qs[2]);
        Crosstalk3Q(qs[0], qs[1], qs[2]);  // crosstalk again
        MResetEachZ(qs)
    }
    
  3. Konfigurieren Sie die Rauschtabelle für das systeminterne Rauschen. Legen Sie die Anzahl der Qubits, die Typen von Rauschen und die Wahrscheinlichkeit für jeden Rauschtyp fest.

    noise = NoiseConfig()
    table = noise.intrinsic("Crosstalk3Q", num_qubits=3)
    table.ixx = 0.10  # 10% XX on qubits 1-2
    table.xxi = 0.05  #  5% XX on qubits 0-1
    
  4. Kompilieren Sie das Programm auf QIR.

    qir = qsharp.compile("GHZ()")
    
  5. Führen Sie die Simulation aus und stellen Sie das Histogramm der Ergebnisse dar.

    result = run_qir(qir, shots=1000, noise=noise)
    Histogram(result)
    
  6. Um das Ergebnis mit einer Simulation ohne Rauschen zu vergleichen, führen Sie die Simulation ohne Rauschmodell erneut aus.

    result = run_qir(qir, shots=1000)
    Histogram(result)
    

Hinzufügen von systeminternem Rauschen zu einem OpenQASM-Programm

Verwenden Sie @qdk.qir.noise_intrinsic in OpenQASM-Programmen, um ein systeminternes Rauschen als benutzerdefinierte Gatterdefinition zu erstellen. Verwenden Sie anschließend die Methode intrinsic aus NoiseConfig, um das systeminterne Rauschen zu konfigurieren.

Um ein OpenQASM-Programm mit einem systeminternen Rauschen mit dem Namen crosstalk_3q zu schreiben und das Programm in QIR zu kompilieren, führen Sie den folgenden Code in einem Jupyter Notebook aus.

from qdk.openqasm import compile, OutputSemantics
from qdk import TargetProfile
from qdk.simulation import run_qir, NoiseConfig
from qdk.widgets import Histogram

qasm_source = """
OPENQASM 3.0;
include "stdgates.inc";

// A noise intrinsic representing crosstalk on 3 qubits.
// In the ideal circuit this is a no-op; the simulator injects
// Pauli errors according to the NoiseConfig.
@qdk.qir.noise_intrinsic
gate crosstalk_3q q0, q1, q2 {}

qubit[3] qs;

// Prepare a GHZ state on 3 qubits, with crosstalk after each CNOT.
h qs[0];
cx qs[0], qs[1];
crosstalk_3q qs[0], qs[1], qs[2];  // crosstalk hits all 3 qubits
cx qs[1], qs[2];
crosstalk_3q qs[0], qs[1], qs[2];  // crosstalk again

bit[3] res = measure qs;
"""

qir_qasm = compile(
    qasm_source,
    output_semantics=OutputSemantics.OpenQasm,
    target_profile=TargetProfile.Base,
)

Führen Sie den folgenden Code aus, um das intrinsische Rauschen zu konfigurieren und die Simulation auszuführen.

noise = NoiseConfig()
table = noise.intrinsic("crosstalk_3q", num_qubits=3)
table.ixx = 0.10  # 10% XX on qubits 1-2
table.xxi = 0.05  #  5% XX on qubits 0-1

result = run_qir(qir_qasm, shots=1000, noise=noise)
Histogram(result)