Ejecutar y descodificar programas lógicos

Use el Microsoft Quantum Development Kit (QDK) para compilar un programa Quantum Intermediate Representation o Q# lógico a OpenQASM (QIR) y, a continuación, use qdk.simulation.run_qir para ejecutar el programa a través de qodec. Configure un modelo de ruido y, a continuación, elija el descodificador de síndrome integrado o el descodificador opcional de nivel de circuito deq.

Prerequisites

Completa estas tareas antes de empezar:

En los ejemplos se usa un Q#qodec denominado protocol que tiene instrucciones para el código C4. Para crear uno, consulte Desarrollar y validar un protocolo 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))

Audite qodec antes de ejecutarlo. El tiempo de ejecución confía en las comprobaciones, lecturas, marcas y ecuaciones de marco de qodec, por lo que las declaraciones no válidas pueden provocar resultados lógicos incorrectos o errores de descodificador.

Este flujo de trabajo usa qdk.simulation.run_qir con un qodec. Las herramientas qodec usan el paquete independiente StimPython paquete para analizar circuitos gadget en formato Stim. No llama a qdk.stim.run. En LinuxArm64 o WindowsArm64, instale Stim desde el origen y reinicie Python o el Jupyter kernel antes de ejecutar un qodec que tenga circuitos de Stimformato .

Hacer coincidir las llamadas QIR con las instrucciones qodec

Relaciona cada llamada cuántica del programa QIR con una instrucción del conjunto superior de instrucciones de qodec. El nemónico de instrucción debe coincidir exactamente con el nombre del QIR invocado.

En la tabla siguiente se muestran asignaciones de ejemplo:

Llamada fuente Se requiere qodec mnemónico
Q# X(q) o OpenQASMx q; __quantum__qis__x__body
Q# H(q) o OpenQASMh q; __quantum__qis__h__body
Q# CNOT(a, b) o OpenQASMcx a, b; __quantum__qis__cx__body
Q# Adjoint S(q) o OpenQASMsdg q; __quantum__qis__s__adj
Q# M(q) o OpenQASMc = measure q; __quantum__qis__m__body
Q# operación intrínseca Foo Foo
OpenQASM compuerta intrínseca o def denominada foo foo

QIR los argumentos se enlazan a qodec los elementos de instrucción en este orden:

  1. Los argumentos de puntero de cúbit se enlazan a operandos de bloque.
  2. Los argumentos escalares se enlazan a parámetros de instrucción.
  3. Los argumentos del puntero de resultado reciben los resultados de la instrucción y cualquier indicador devuelto.

El compilador genera un error si una llamada cuántica no coincide con una instrucción en el conjunto de instrucciones de nivel superior.

Declarar instrucciones lógicas en Q#

Un qodec compilado a partir del código C4 expone instrucciones personalizadas como prepare_z_all, measure_z_all, syndrome y cx_all. Declara Q# operaciones intrínsecas con los mismos nombres.

Inicialice Q# con el perfil de destino adaptable porque las operaciones de medición personalizadas lo requieren.

from qdk import TargetProfile, qsharp

qsharp.init(target_profile=TargetProfile.Adaptive_RI)

Declare las C4 instrucciones como Q# operaciones.

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; }
""")

En este programa, cada Q#Qubit representa un bloque codificado. El C4 bloque tiene dos cúbits lógicos, por lo que cada operación de medida devuelve dos resultados lógicos. Cada operación de preparación devuelve una marca de rechazo.

Compile un experimento lógico Q#

Defina un experimento de preparación y medición de estado (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])
}
""")

Compile la operación TestSpamZ a QIR.

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

QIR mantiene las llamadas a prepare_z_all y measure_z_all. Cuando se ejecuta el programa, el entorno de ejecución qodec compara estos nombres con el conjunto de instrucciones de nivel superior y reemplaza cada llamada lógica por su gadget.

Ejecutar con el descodificador integrado

Llame a run_qir y pase qodec. Si decoder es None, el tiempo de ejecución usa el descodificador de peso Pauli mínimo integrado.

from qdk.simulation import run_qir

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

print(results[:5])

Para ejecutar un qodec, utilice estas opciones de simulador:

type valor Behavior
None o "stabilizer" Usar el back-end del estabilizador
"cpu" Use el back-end de vector de estado para programas admitidos
"gpu" No se admite con un qodec

El tiempo de ejecución prepara cada cúbit del programa antes de su primer uso a menos que la primera instrucción cree su bloque. Una instrucción de preparación tiene bloques de salida, ningún bloque de entrada y una acción que estabiliza el estado lógico Z.

Las correcciones del decodificador de un solo cúbit Pauli y las actualizaciones del marco qodec usan un marco sin Pauli ruido, no puertas físicas ruidosas.

Configurar el ruido del simulador

Defina el ruido en las operaciones del simulador, no en los nombres de instrucción qodec. El tiempo de ejecución traduce cada instrucción de nivel inferior en una o varias operaciones del simulador, por lo que la configuración de ruido se aplica a esas operaciones.

La guía guiada C4 usa estas asociaciones:

Instrucción de la capa inferior Operación del simulador campo NoiseConfig
R Preparar o restablecer a Z+ mresetz
H Hadamard h
CX X controlado cx
M Medición en base Z mresetz

Cree un modelo simple de 1% ruido:

from qdk.simulation import NoiseConfig

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

Ejecute el experimento con ruido:

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

El ruido en mresetz actúa sobre el cúbit después de la medición o preparación. No invierte un bit de medición que el simulador ya ha registrado. Para estudiar inversiones de bits registradas, use los modelos de error de lectura y el análisis de gadgets qodec.

Fallos de las tomas de control

Usa on_shot_failure para elegir cómo responde el tiempo de ejecución cuando un indicador qodec, un descodificador o una lectura no produce un disparo aceptado.

Value Behavior
"discard" Omita los intentos fallidos de la lista devuelta. Este valor es el predeterminado.
"raise" Detenga cuando falle el primer disparo.
"retry" Reinicie la captura fallida, hasta max_retries intentos adicionales.

Con la "discard" directiva, el shots argumento cuenta los disparos intentados, por lo que la lista devuelta puede tener menos elementos que shots.

Un indicador desencadena la política de disparo solo cuando el programa lógico no recibe ese indicador. Si una Q#@Measurement() operación devuelve un extra Result para la flag, el programa recibe la flag y decide si rechazar la toma.

En el TestSpamZ ejemplo, el programa devuelve el indicador de preparación en el primer array. Por lo tanto, la on_shot_failure="discard" configuración no quita filas donde la marca devuelta es One.

Seleccione un descodificador

Para elegir cómo se descodifican los errores, use el parámetro decoder para pasar una función invocable de preparación del decodificador para cada capa codificada.

QDK tiene los siguientes descodificadores:

Descodificador Úsela para
Descodificador predeterminado de síndrome Inferir correcciones de peso mínimo Pauli de la evidencia del síndrome. Utilice decoder=None.
Descodificador de fotogramas Realice un seguimiento de fotogramas sin ruido sin inferir fallos físicos. Utilice prepare_frame_decoder.
deq descodificador Descodifica modelos de error de nivel de circuito con deq. Utilice prepare_deq_decoder.

Use la configuración predeterminada deq

Instale deq y deq-runtime, a continuación, pase prepare_deq_decoder.

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",
)

De forma predeterminada, el adaptador deq usa relay belief propagation y un window coordinator. Para cambiar esta configuración, use una factoría de tiempo de ejecución.

Configurar un entorno de ejecución monolítico deq

Para elegir directamente la configuración de deq, pase una factoría en tiempo de ejecución a 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",
)

Devuelve un nuevo Runtime en cada llamada al método de fábrica. El QDK se inicia y se cierra en cada tiempo de ejecución.

Note

El deq adaptador requiere:

  • Una capa codificada
  • Una traza de ejecución independiente de la medición Clifford
  • Componente de servidor del estabilizador
  • Un modelo de ruido sin pérdida de cúbits

El deq adaptador no admite la política de reintento. Los programas no admitidos generan un error en lugar de recurrir a otro descodificador como alternativa.

Rechazar los resultados de confianza deq baja

El deq adaptador devuelve una puntuación para cada lectura lógica. Las puntuaciones más bajas indican una preferencia más fuerte para la corrección elegida. Las puntuaciones no son probabilidades de error calibradas.

Para rechazar los resultados de confianza baja, pase max_readout_score al preparar el descodificador, como en el ejemplo siguiente:

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",
)

El tiempo de ejecución acepta una toma solo cuando cada lectura lógica devuelta tiene una puntuación igual o inferior al umbral. El umbral no se aplica a marcas sin procesar ni a lecturas intermedias sin usar.

El rechazo basado en la puntuación puede reducir la tasa de errores lógicos de los disparos aceptados. Pero también reduce el número de disparos aceptados y añade carga de trabajo al decodificador.

Compilar OpenQASM programas

Las operaciones estándar OpenQASM usan las mismas QIR reglas mnemónicas que las operaciones estándar 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)

Para ejecutar este programa a través de qodec, asegúrese de que el conjunto de instrucciones superior de qodec tiene __quantum__qis__x__body y __quantum__qis__m__body, con operandos de bloque compatibles y un resultado de medición.

Una OpenQASM compuerta intrínseca o subrutina denominada foo usa el mnemónico foo. Los argumentos de cúbit se enlazan a operandos de bloque. Los argumentos float, int y bool se enlazan a parámetros de instrucción en orden de declaración.

OpenQASM tiene estas limitaciones para las llamadas a qodec:

  • Los intrínsecos personalizados no pueden devolver un QIRResult. Para obtener un resultado de medición, use la instrucción estándar measure .
  • OpenQASM los programas no pueden ejecutar mediciones personalizadas, recibir varios resultados de una llamada o recibir indicadores devueltos. En estos casos, use las operaciones Q#@Measurement().
  • El entorno de ejecución controla los indicadores que el programa OpenQASM no puede recibir, y estos indicadores pueden rechazar un disparo.

Para obtener ejemplos detallados de asignación, consulte los siguientes QDK notebooks:

Revisión de los requisitos y limitaciones

Revise estos requisitos, limitaciones y diferencias de resultados antes de ejecutar un experimento grande.

Requisitos:

  • Cada QIR llamada cuántica debe resolverse en una instrucción de la capa superior qodec.
  • Audite el protocolo antes de ejecutarlo. El qodec tiempo de ejecución confía en las ecuaciones que escribes y no las comprueba.

Limitations:

  • GPU la simulación no admite qodec la ejecución.
  • El conjunto de errores del gadget predeterminado puede crecer exponencialmente, por lo que las búsquedas de distancia exactas pueden tardar mucho tiempo.
  • Los paquetes deq y Stim tienen limitaciones de plataforma. Para obtener más información, consulte Instalar QDK para la corrección de errores.

Diferencias de resultados:

  • Los recuentos exactos de salida pueden variar según el descodificador.
  • Las directivas de descarte y reintento pueden cambiar la distribución de resultados devuelta.

Para obtener un experimento completo Q# con barridos de ruido, deq descodificación y rechazo basado en confianza, consulte el tutorial del protocolo QEC.