Exécuter et décoder des programmes logiques

Utilisez l’Microsoft Quantum Development Kit (QDK) pour compiler un programme ou OpenQASM une logique Q# sur Quantum Intermediate Representation (QIR), puis utilisez qdk.simulation.run_qir pour exécuter le programme via un qodec. Configurez un modèle de bruit, puis choisissez le décodeur de syndrome intégré ou le décodeur au niveau du circuit facultatif deq .

Prerequisites

Effectuez ces tâches avant de commencer :

Les Q# exemples utilisent un qodec nom protocol qui contient des instructions pour le C4 code. Pour en créer un, consultez Développer et valider un protocole QEC.

import qodec
from qdk import ec

c4 = qodec.Code(
    "C4",
    stabilizers=["X_0 X_1 X_2 X_3", "Z_0 Z_1 Z_2 Z_3"],
    x=["X_0 X_1", "X_0 X_2"],
    z=["Z_0 Z_2", "Z_0 Z_1"],
)

protocol = ec.build_qodec(
    c4,
    strategy="bare-css/v1",
    strict=False,
)

report = ec.audit(protocol)
if report.errors or report.warnings:
    raise ValueError(str(report))

Auditez le qodec avant de l’exécuter. Le runtime approuve les qodecvérifications, les lectures, les indicateurs et les équations de trame, afin que les déclarations non valides puissent entraîner des échecs logiques incorrects ou de décodeur.

Ce flux de travail utilise qdk.simulation.run_qir avec un qodec. L’outil qodec utilise le package distinct StimPython pour analyser -formater les circuits Stimgadgets. Il n’appelle qdk.stim.runpas . Sur LinuxArm64 ou WindowsArm64, installez Stim à partir de la source et redémarrez Python ou le Jupyter noyau avant d’exécuter un qodecStimcircuit -format.

Mettre en correspondance les QIR appels aux qodec instructions

Mettre en correspondance chaque appel quantique dans le QIR programme à une instruction dans le qodecjeu d’instructions supérieur. L’instruction mnemonique doit correspondre exactement au nom de l’appelé QIR .

Le tableau suivant présente des exemples de mappages :

Appel source Mnémonique requis qodec
Q# X(q) ou OpenQASMx q; __quantum__qis__x__body
Q# H(q) ou OpenQASMh q; __quantum__qis__h__body
Q# CNOT(a, b) ou OpenQASMcx a, b; __quantum__qis__cx__body
Q# Adjoint S(q) ou OpenQASMsdg q; __quantum__qis__s__adj
Q# M(q) ou OpenQASMc = measure q; __quantum__qis__m__body
Q# opération intrinsèque Foo Foo
OpenQASM porte intrinsèque ou def nommée foo foo

QIR les arguments sont liés aux éléments d’instruction qodec dans cet ordre :

  1. Les arguments de pointeur Qubit sont liés aux opérandes de bloc.
  2. Les arguments scalaires sont liés aux paramètres d’instruction.
  3. Les arguments de pointeur de résultat reçoivent des résultats d’instruction et tous les indicateurs retournés.

Le compilateur génère une erreur si un appel quantique ne correspond pas à une instruction dans le jeu d’instructions supérieur.

Déclarer des instructions logiques dans Q#

Un qodec élément généré à partir du C4 code expose des instructions personnalisées telles que prepare_z_all, , measure_z_allsyndrome, et cx_all. Déclarez Q# des opérations intrinsèques avec les mêmes noms.

Initialiser Q# avec le profil cible adaptatif, car les opérations de mesure personnalisées le nécessitent.

from qdk import TargetProfile, qsharp

qsharp.init(target_profile=TargetProfile.Adaptive_RI)

Déclarez les instructions en tant qu’opérations C4Q# .

qsharp.eval("""
@Measurement()
operation prepare_z_all(block : Qubit) : Result { body intrinsic; }

@Measurement()
operation prepare_x_all(block : Qubit) : Result { body intrinsic; }

@Measurement()
operation measure_z_all(block : Qubit) : (Result, Result) { body intrinsic; }

@Measurement()
operation measure_x_all(block : Qubit) : (Result, Result) { body intrinsic; }

operation cx_all(control : Qubit, target : Qubit) : Unit { body intrinsic; }
operation syndrome(block : Qubit) : Unit { body intrinsic; }
""")

Dans ce programme, chacun Q#Qubit représente un bloc encodé. Le C4 bloc a deux qubits logiques. Chaque opération de mesure retourne donc deux résultats logiques. Chaque opération de préparation retourne un indicateur de rejet.

Compiler une expérience logique Q#

Définissez une expérience de préparation et de mesure de l’état (SPAM).

qsharp.eval("""
operation TestSpamZ() : (Result[], Result[]) {
    use block = Qubit();
    let reject = prepare_z_all(block);
    let (left, right) = measure_z_all(block);
    ([reject], [left, right])
}
""")

Compilez l’opération TestSpamZ sur QIR.

qir = str(qsharp.compile("TestSpamZ()"))

Le QIR maintient les appels vers prepare_z_all et measure_z_all. Lorsque le programme s’exécute, le qodec runtime correspond à ces noms par rapport au jeu d’instructions supérieur et remplace chaque appel logique par son gadget.

Exécuter avec le décodeur intégré

Appelez run_qir et passez le qodec. Si decoder c’est Nonele cas, le runtime utilise le décodeur de poids Pauli minimal intégré.

from qdk.simulation import run_qir

results = run_qir(
    qir,
    qodec=protocol,
    type="stabilizer",
    shots=100,
    seed=42,
)

print(results[:5])

Pour exécuter un qodecsimulateur, utilisez ces options de simulateur :

Valeur type Behavior
None ou "stabilizer" Utiliser le back-end stabilisateur
"cpu" Utiliser le back-end de vecteur d’état pour les programmes pris en charge
"gpu" Non pris en charge avec un qodec

Le runtime prépare chaque qubit de programme avant sa première utilisation, sauf si la première instruction crée son bloc. Une instruction de préparation contient des blocs de sortie, aucun bloc d’entrée et une action qui stabilise logique Z.

Les corrections de décodeur à qubit Pauli unique et qodec les mises à jour d’images utilisent un cadre sans Pauli bruit, pas de portes physiques bruyantes.

Configurer le bruit du simulateur

Définissez le bruit sur les opérations du simulateur, et non sur qodec les noms d’instructions. Le runtime traduit chaque instruction de couche inférieure en une ou plusieurs opérations de simulateur, de sorte que les paramètres de bruit s’appliquent à ces opérations.

La C4 procédure pas à pas utilise ces mappages :

Instruction de couche inférieure Opération de simulateur champ NoiseConfig
R Préparer ou réinitialiser sur Z+ mresetz
H Hadamard h
CX X contrôlé cx
M Mesure de base Z mresetz

Créez un modèle de bruit simple de 1% :

from qdk.simulation import NoiseConfig

noise = NoiseConfig()
for gate in (noise.h, noise.cx):
    gate.set_depolarizing(0.01)
noise.mresetz.x = 0.01

Exécutez l’expérience avec le bruit :

results = run_qir(
    qir,
    qodec=protocol,
    noise=noise,
    type="stabilizer",
    shots=1000,
    seed=42,
    on_shot_failure="discard",
)

Bruit sur les actions sur mresetz le qubit après mesure ou préparation. Il ne retourne pas un bit de mesure que le simulateur a déjà enregistré. Pour étudier les retournements de bits enregistrés, utilisez qodec les modèles d’erreur de lecture et l’analyse des gadgets.

Échecs de capture de contrôle

Permet on_shot_failure de choisir la façon dont le runtime répond lorsqu’un qodec indicateur, un décodeur ou une lecture ne produit pas de capture acceptée.

Value Behavior
"discard" Omettre les captures ayant échoué dans la liste retournée. Cette valeur est la valeur par défaut.
"raise" Arrêtez quand le premier coup échoue.
"retry" Redémarrez la capture ayant échoué, jusqu’à max_retries des tentatives supplémentaires.

Avec la "discard" stratégie, l’argument shots compte les coups tentés, de sorte que la liste retournée peut avoir moins d’éléments que shots.

Un indicateur déclenche la stratégie de capture uniquement lorsque le programme logique ne reçoit pas cet indicateur. Si une Q#@Measurement() opération retourne un extra Result pour l’indicateur, le programme reçoit l’indicateur et décide s’il faut rejeter la capture.

Dans l’exemple TestSpamZ , le programme retourne l’indicateur de préparation dans le premier tableau. Par conséquent, le on_shot_failure="discard" paramètre ne supprime pas les lignes où l’indicateur retourné est One.

Sélectionner un décodeur

Pour choisir la façon dont les erreurs sont décodées, utilisez le decoder paramètre pour passer un appel de préparation de décodeur pour chaque couche encodée.

Les QDK décodeurs suivants sont les suivants :

Décodeur Utilisez-le pour
Décodeur de syndrome par défaut Déduire les corrections minimales de poids Pauli par la preuve du syndrome. Utilisez decoder=None.
Décodeur de trame Effectuez le suivi des trames sans bruit sans déduire les erreurs physiques. Utilisez prepare_frame_decoder.
deq décodeur Décoder des modèles d’erreur au niveau du circuit avec deq. Utilisez prepare_deq_decoder.

Utiliser la configuration par défaut deq

Installez deq et deq-runtimepassez prepare_deq_decoderensuite .

from qdk.simulation.decoders import prepare_deq_decoder

results = run_qir(
    qir,
    qodec=protocol,
    decoder=prepare_deq_decoder,
    noise=noise,
    type="stabilizer",
    shots=1000,
    seed=42,
    on_shot_failure="discard",
)

Par défaut, l’adaptateur deq utilise la propagation des croyances de relais et un coordinateur de fenêtre. Pour modifier ces paramètres, utilisez une fabrique d’exécution.

Configurer un runtime monolithique deq

Pour choisir deq les paramètres directement, passez une fabrique d’exécution à prepare_deq_decoder.

from functools import partial
from deq.runtime import Runtime
from qdk.simulation import decoders


def make_runtime(seed: int) -> Runtime:
    return Runtime(
        decoder="black-box-relay-bp",
        decoder_config={"parallel": 1, "seed": seed},
        coordinator="monolithic",
        controller="jit",
    )


results = run_qir(
    qir,
    qodec=protocol,
    decoder=partial(
        decoders.prepare_deq_decoder,
        runtime_factory=make_runtime,
    ),
    noise=noise,
    type="stabilizer",
    shots=1000,
    seed=42,
    on_shot_failure="discard",
)

Retournez un nouvel Runtime appel d’usine. Le QDK démarrage et la fermeture de chaque runtime.

Note

L’adaptateur deq nécessite :

  • Une couche encodée
  • Trace d’exécution indépendante Clifford de la mesure
  • Back-end stabilisateur
  • Modèle de bruit sans perte de qubit

L’adaptateur deq ne prend pas en charge la stratégie de nouvelle tentative. Les programmes non pris en charge déclenchent une erreur au lieu de revenir à un autre décodeur.

Rejeter les résultats de faible confiance deq

L’adaptateur deq retourne un score pour chaque lecture logique. Les scores inférieurs indiquent une préférence plus forte pour la correction choisie. Les scores ne sont pas des probabilités d’échec étalonnées.

Pour rejeter les résultats de faible confiance, passez max_readout_score lorsque vous préparez le décodeur, comme dans l’exemple suivant :

from functools import partial
from qdk.simulation import decoders

scored_decoder = partial(
    decoders.prepare_deq_decoder,
    max_readout_score=0.2,
)

results = run_qir(
    qir,
    qodec=protocol,
    decoder=scored_decoder,
    noise=noise,
    type="stabilizer",
    shots=1000,
    on_shot_failure="discard",
)

Le runtime accepte une capture uniquement lorsque chaque lecture logique retournée a un score au-dessous du seuil ou au-dessous du seuil. Le seuil ne s’applique pas aux indicateurs bruts ou aux lectures intermédiaires inutilisées.

Le rejet basé sur le score peut réduire le taux d’erreur logique des tirs acceptés. Mais il réduit également le nombre de tirs acceptés et ajoute le travail de décodeur.

Compiler des OpenQASM programmes

Les opérations standard OpenQASM utilisent les mêmes QIR règles mnemoniques que les opérations standard Q# .

from qdk import TargetProfile, openqasm

source = """
OPENQASM 3.0;
include "stdgates.inc";
qubit q;
bit c;
x q;
c = measure q;
"""

qir = openqasm.compile(
    source,
    target_profile=TargetProfile.Adaptive_RI,
)

print(qir)

Pour exécuter ce programme via un qodec, assurez-vous que l’ensemble qodecd’instructions principales a __quantum__qis__x__body et __quantum__qis__m__body, avec des opérandes de bloc compatibles et un résultat de mesure.

Une OpenQASM porte intrinsèque ou une sous-routine nommée foo utilise le mnémonique foo. Les arguments Qubit sont liés aux opérandes de bloc. Les floatarguments et bool les intarguments sont liés aux paramètres d’instruction dans l’ordre de déclaration.

OpenQASM présente ces limitations pour qodec les appels :

  • Les intrinsèques personnalisées ne peuvent pas retourner un QIRResult. Pour obtenir un résultat de mesure, utilisez l’instruction standard measure .
  • OpenQASM les programmes ne peuvent pas exécuter de mesures personnalisées, recevoir plusieurs résultats d’un appel ou recevoir des indicateurs retournés. Dans ce cas, utilisez des Q#@Measurement() opérations.
  • Le runtime contrôle tous les indicateurs que le OpenQASM programme ne peut pas recevoir, et ces indicateurs peuvent rejeter une capture.

Pour obtenir des exemples de mappage détaillés, consultez les notebooks suivants QDK :

Passer en revue les exigences et limitations

Passez en revue ces exigences, limitations et différences de résultats avant d’exécuter une grande expérience.

Exigences:

  • Chaque QIR appel quantique doit être résolu en une instruction de couche qodec supérieure.
  • Auditez le protocole avant de l’exécuter. Le qodec runtime approuve les équations que vous écrivez et ne les vérifie pas.

Limites :

  • GPU la simulation ne prend pas en charge qodec l’exécution.
  • Le jeu d’erreurs de gadget par défaut peut croître de manière exponentielle, de sorte que les recherches de distance exactes peuvent prendre beaucoup de temps.
  • Les packages et Stim les deq packages ont des limitations de plateforme. Pour plus d’informations, consultez Installer QDK pour corriger les erreurs.

Différences de résultats :

  • Les nombres de sorties exacts peuvent varier en fonction du décodeur.
  • Les stratégies d’abandon et de nouvelle tentative peuvent modifier la distribution des résultats retournée.

Pour une expérience complète Q# avec les balayages sonores, deq le décodage et le rejet basé sur la confiance, consultez la procédure pas à pas du protocole QEC.