Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Usare qodec e il qdk.ec modulo del Microsoft Quantum Development Kit (QDK) per definire un codice QEC (Quantum Error Correction) e trasformarlo in un protocollo eseguibile. In questo articolo si definisce un codice di errore, si crea una baseline qodec, si convalidano le dichiarazioni, si calcola la distanza dei gadget e si salva il protocollo.
Gli esempi in questo articolo usano il codice $[[4,2,2]]$ C4 , che archivia due qubit logici in quattro qubit fisici e rileva qualsiasi singolo errore fisico Pauli .
Prerequisites
Completare queste attività prima di iniziare:
- Installare QDK per la correzione degli errori.
- Usare un ambiente con Python 3.11 o successiva.
- Verificare che il qodecStim parser sia disponibile. Su LinuxArm64 o WindowsArm64, installa Stim dai sorgenti e quindi riavvia Python o il kernel Jupyter prima di chiamare
build_qodec.
Definisci il codice
Creare un qodec.Code oggetto con gli stabilizzatori di codice e un rappresentante logico X e Z per ogni qubit logico.
import qodec
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"],
)
Il pacchetto qodec usa la notazione sparsa per le stringhe Pauli. Ogni termine ha una Pauli lettera e un'etichetta qubit fisica. Ad esempio, X_0 X_2 si applica X ai qubit fisici 0 e 2.
La definizione del codice è un oggetto matematico statico. Non include i circuiti che preparano, conservano o misurano gli stati codificati.
Analizzare il codice
Per esaminare un'istantanea degli operatori di codice, creare un CodeProfile.
from qdk import ec
profile = ec.CodeProfile(c4)
print("Physical support:", sorted(profile.support))
print("Physical qubits:", profile.length)
print("Logical qubits:", profile.logical_qubit_count)
print("Stabilizers:", profile.stabilizers)
print("Logical X operators:", profile.x)
print("Logical Z operators:", profile.z)
Il profilo non cambia se in un secondo momento si modifica l'oggetto originale qodec.Code .
Calcolare la distanza del codice
Per trovare il numero minimo di errori fisici consentiti che causano un effetto logico nontriviale con sindrome zero, chiamare distance.
distance = profile.distance()
print("Code distance:", distance)
error = distance.witness.product
syndrome = profile.syndrome_of(error)
logical_effect = profile.logical_effect_of(error)
print("Witness:", error)
print("Syndrome:", sorted(syndrome))
print("Logical effect:", logical_effect)
assert distance.value == 2
assert profile.is_logical(error)
Per impostazione predefinita, la ricerca assegna un costo a ogni errore X, Y o Z a qubit singolo. L'oggetto restituito Distance ha limiti certificati e un testimone per qualsiasi limite superiore finito.
Quando una ricerca esatta completa costa troppo, usare distance_bounds.
bounds = profile.distance_bounds(upper_bound=4)
print("Distance bounds:", bounds)
print("Lower bound:", bounds.lower_bound)
print("Upper bound:", bounds.upper_bound)
Il risolutore predefinito è HiGHS. Per usare un risolutore diverso, impostare solver="enumeration", oppure installare MWPF e impostare solver="mwpf".
Creare una linea di base qodec
Un qodec descrive come eseguire istruzioni codificate. Ha set di istruzioni, codici, livelli, gadget, circuiti, controlli ed equazioni di lettura.
Usare build_qodec per creare un protocollo a due livelli dal C4 codice.
protocol = ec.build_qodec(
c4,
strategy="bare-css/v1",
strict=False,
)
Questo esempio usa bare-css/v1 per consentire di esaminare un protocollo semplice senza flag qubit.
Caution
La bare-css/v1 strategia non promette circuiti tolleranti ai guasti. Calcolare la distanza di ogni gadget prima di usare il protocollo per esperimenti rumorosi.
Il generatore tenta di creare queste istruzioni logiche:
prepare_z_allprepare_x_allsyndromemeasure_z_allmeasure_x_allh_allcx_all
Il _all suffisso indica che un'istruzione agisce su ogni qubit logico in un blocco. Ad esempio, cx_all applica CNOT tra i qubit logici corrispondenti in due blocchi.
Non tutti i codici supportano ogni istruzione candidata. Con strict=True, che è l'impostazione predefinita, il builder genera un errore quando non riesce a compilare e verificare un candidato. Con strict=False, il generatore mantiene le istruzioni supportate e registra le omissioni in protocol.metadata["qdk.ec"]["build"]["omitted"].
Esamina il livello logico e i relativi widget.
logical_layer = protocol.layers[0]
print("Instructions:")
for mnemonic in logical_layer.instruction_set.instructions:
print(" -", mnemonic)
print("Gadgets:")
for mnemonic in logical_layer.gadgets:
print(" -", mnemonic)
Il secondo livello contiene il set di istruzioni fisiche Stim usato dai circuiti generati.
Esaminare un gadget
Un'istruzione condizionale dichiara un contratto. Il suo componente fornisce il circuito che implementa il contratto.
Ispezionare il prepare_z_all gadget.
gadget = logical_layer.gadgets["prepare_z_all"]
gadget_profile = ec.GadgetProfile(gadget)
print("Declared objective:")
print(gadget_profile.objective)
print("Computed action:")
print(gadget_profile.action)
Confrontare l'azione calcolata dal circuito con l'obiettivo dell'istruzione dichiarato.
objective = gadget_profile.objective
assert objective is not None
if gadget_profile.action.is_equivalent_to(objective):
print("The gadget implements its declared instruction.")
else:
print(objective.why_not_equivalent_to(gadget_profile.action))
Un GadgetProfile acquisisce uno snapshot dell'input, quindi non riflette le modifiche successive. Dopo aver modificato un gadget, creare un nuovo profilo.
Verificare il protocollo
Usare audit per controllare l'intero oggetto qodec.
report = ec.audit(protocol)
print(report)
Se il controllo non rileva errori o avvisi, viene stampato:
audit: ok
Il controllo controlla queste aree:
- Algebra di codice
- Struttura delle istruzioni e dei layer
- Chiamate di circuit e associazioni di parametri
- Azioni del gadget
- Controlli ed equazioni di visualizzazione
- Segnala equazioni
- Relazioni tra frame di input e output
- Limiti di riferimento e completezza del protocollo
Per agire su livelli di gravità specifici, utilizza le raccolte rapporti.
if report.errors:
for diagnostic in report.errors:
print(diagnostic)
raise ValueError("The qodec has audit errors.")
if report.warnings:
for diagnostic in report.warnings:
print(diagnostic)
Il report.ok valore indica che il report non contiene errori. Gli avvisi non modificano tale proprietà.
Deriva le equazioni mancanti
Utilizzare filled quando un gadget bozza o qodec omette controlli o equazioni logiche di lettura che la simulazione esatta può derivare.
Nell'esempio seguente viene creata una copia incompleta del protocollo.
draft = qodec.Qodec.loads(protocol.dumps())
draft_gadgets = draft.layers[0].gadgets
draft_gadgets["measure_x_all"].readouts = []
draft_gadgets["cx_all"].checks = []
print(ec.audit(draft))
Compilare le equazioni supportate e quindi verificare il risultato.
completed = ec.filled(draft)
print(ec.audit(completed))
La filled funzione restituisce un nuovo gadget o qodec non ne modifica l'input. Deriva i controlli, le equazioni di lettura osservabili e le relazioni tra quadri. Mantiene le associazioni di flag perché la simulazione senza rumore non è in grado di identificare quali errori un flag dovrebbe rilevare.
Se il protocollo originale ha già equazioni dirette verificate, filled le mantiene quando possibile.
Analizza i guasti dei gadget
Un controllo senza errori dimostra la coerenza priva di anomalie. Non dimostra la tolleranza ai guasti.
Chiamare GadgetProfile.distance per trovare il numero minimo di errori di circuito consentiti che causano un errore logico, mentre tutti i controlli e i flag dichiarati restano a zero. Il guasto combinato deve anche lasciare ogni uscita all'interno del suo spazio di codice.
protocol = completed
for mnemonic, gadget in sorted(protocol.layers[0].gadgets.items()):
result = ec.GadgetProfile(gadget).distance()
witness = result.witness if result.upper_bound is not None else "none"
print(f"{mnemonic}: distance={result}, witness={witness}")
Il modello di errore predefinito include questi eventi dopo ogni chiamata al circuito:
- Errore Pauli nei qubit che la chiamata interessa
- Capovolgimento di un bit di output generato dalla chiamata
- Combinazione correlata di tali errori
Ogni evento in una singola chiamata costa uno, anche quando presenta un errore multiqubit correlato.
Un codice può avere distanza due mentre uno dei suoi dispositivi ha distanza 1. Ad esempio, un singolo errore di circuito può propagarsi attraverso un'ancilla e creare un errore logico non rilevato. Aggiungere controlli o circuiti di segnalazione, quindi creare un nuovo GadgetProfile e calcolare di nuovo la distanza.
Esaminare un guasto specifico
Usare FaultEvent.after per definire un guasto in corrispondenza di un indice di chiamata a circuito con base zero.
gadget = protocol.layers[0].gadgets["syndrome"]
profile = ec.GadgetProfile(gadget)
fault = ec.FaultEvent.after(0, ec.Pauli("X_0"))
(effect,) = profile.effects_of([fault])
print("Fault:", fault)
print("Changed quantities:", effect)
Un FaultEffect può includere controlli modificati, letture logiche e indicatori del frame di output. Usare set di errori espliciti quando il modello a livello di circuito predefinito non corrisponde ai presupposti hardware.
result = profile.distance(faults=[fault])
print(result)
Le ricerche di gadget esatte possono richiedere molto tempo perché l'insieme dei guasti predefinito aumenta in modo esponenziale con il supporto di ogni chiamata. Usare distance_bounds, un insieme di guasti esplicito o un upper_bound quando è necessario limitare la ricerca.
Salva il protocollo
Controlla l'ultima qodec prima di salvarla.
report = ec.audit(protocol)
if report.errors or report.warnings:
raise ValueError(str(report))
Salvare il protocollo come singolo YAML bundle e quindi caricarlo di nuovo per verificare che corrisponda all'originale.
from pathlib import Path
output_directory = Path("qodec-output")
output_directory.mkdir(exist_ok=True)
saved_path = protocol.save(str(output_directory), single_file=True)
loaded = qodec.Qodec.load(saved_path)
assert loaded == protocol
print("Saved qodec:", saved_path)
Un bundle in un unico file archivia il manifest, le definizioni di codice, i set di istruzioni, i gadget e le origini del circuito in un unico file YAML, semplificando la condivisione e il ricaricamento.
Eseguire il protocollo
Dopo che il qodec ha superato il controllo e soddisfa i requisiti di distanza, compilare un programma logico in Quantum Intermediate Representation (QIR) ed eseguirlo attraverso il protocollo. Vedere Eseguire e decodificare programmi logici.
Per un esempio completo che aggiunge circuiti di flag e confronta le frequenze di errore logiche, vedere la procedura dettagliata del protocollo QEC nel QDK repository GitHub.