← Volver

Qué hace realmente un transpilador cuántico

Análisis del proceso que transforma un circuito lógico en instrucciones ejecutables por un dispositivo cuántico concreto: descomposición de puertas, asignación de cúbits, routing, inserción de SWAP, optimización y scheduling.

Transpilador
Qué es un transpilador cuántico

Del circuito lógico al hardware: cómo compila un computador cuántico

Cuando dibujamos un circuito cuántico solemos trabajar con un modelo ideal. Disponemos de cúbits perfectamente conectados, aplicamos cualquier puerta que necesitemos y asumimos que todas las operaciones tienen un coste similar. Básicamente, lo mismo que hacemos cuando programamos en cualquier lenguaje, pero, en este caso, programamos mediante puertas.

El circuito expresa con claridad el algoritmo que queremos ejecutar, pero no necesariamente algo que un dispositivo cuántico concreto pueda entender, dado, además, las diferentes tecnologías de implementación de computadores cuánticos que existen actualmente.

Antes de llegar al hardware, el circuito debe atravesar un proceso de compilación cuántica, también denominado con frecuencia transpilación. Durante este proceso, el circuito original se reescribe para ajustarse al conjunto de instrucciones, la conectividad, los tiempos y las características físicas del dispositivo destino elegido.

El resultado puede ser visualmente muy distinto del circuito inicial. Puede contener más puertas, utilizar otros cúbits físicos, incorporar operaciones SWAP y presentar una profundidad considerablemente mayor, además de todo lo necesario para la corrección de errores.

Sin embargo, ambos circuitos deben representar, salvo las aproximaciones permitidas, la misma transformación lógica.

Esta diferencia entre equivalencia lógica y eficiencia física es una de las claves de la ingeniería de software cuántico, aunque siempre hago la misma comparación, salvando las distancias: cuando compilamos un programar hecho en C# o Rust, por poner un ejemplo, finalmente, al final de la cadena desde la compilación a la ejecución, todo se traduce a una aplicación en lenguaje ensamblador que ejecutará finalmente el computador (clásico, claro), y antes de llegar ahí, el compilador o el runtime de ejecución ha realizado una cantidad enorme de optimizaciones en la sombra de la que el programador (cómodo con su código de alto nivel), no llega a enterarse nunca.

El objetivo de este artículo es introducir los conceptos fundamentales de un transpilador cuántico.

El circuito lógico no es todavía un programa ejecutable

Un circuito lógico describe una secuencia de operaciones sobre cúbits lógicos. Por ejemplo:

q0: ──H────■────
           │
q1: ───────X────

Este circuito prepara un estado entrelazado mediante una puerta de Hadamard y una CNOT. Desde el punto de vista matemático, la descripción es suficiente: primero se aplica HH sobre q0q_0 y después una CNOT controlada por q0q_0 y dirigida a q1q_1.

Sin embargo, para ejecutar el circuito sobre un dispositivo real hay que responder a varias preguntas:

  • ¿Admite el hardware una puerta Hadamard nativa?
  • ¿Cómo se implementa físicamente la CNOT?
  • ¿Qué cúbits físicos se utilizarán?
  • ¿Están esos cúbits conectados directamente?
  • ¿Qué tasas de error presentan?
  • ¿Cuánto dura cada operación?
  • ¿Pueden ejecutarse varias puertas simultáneamente?
  • ¿Existen restricciones de control o interferencias entre cúbits próximos?

Un backend cuántico acepta únicamente los circuitos que cumplen su arquitectura del conjunto de instrucciones, o ISA. Esto implica utilizar las puertas admitidas por el dispositivo y respetar sus restricciones de conectividad.

La compilación es, por tanto, una combinación de traducción, optimización y resolución de restricciones.

Este es un sector que actualmente está en pleno desarrollo, a medida que avanzan las capacidades de los computadores cuánticos.

Las etapas de la compilación cuántica

Aunque cada plataforma utiliza su propia terminología, el flujo de compilación puede entenderse mediante las siguientes etapas (y si has aprendido a programar en ensamblador en algún momento de tu carrera profesional, no te va a sorprender demasiado):

Circuito lógico
      │
      ▼
Descomposición de puertas
      │
      ▼
Asignación de cúbits
      │
      ▼
Routing e inserción de SWAP
      │
      ▼
Optimización
      │
      ▼
Scheduling
      │
      ▼
Instrucciones ejecutables

Estas etapas no siempre se aplican una sola vez ni siguen un flujo estrictamente lineal. Una decisión de routing puede introducir nuevas puertas, lo que obliga a repetir la descomposición y abre nuevas posibilidades de optimización. Los compiladores modernos organizan estas transformaciones mediante secuencias de pases, bucles y decisiones condicionadas.

Descomposición de puertas

El primer problema consiste en traducir las puertas abstractas del circuito al conjunto de puertas nativas del dispositivo.

Un algoritmo puede contener operaciones como:

  • Hadamard.
  • CNOT.
  • Toffoli.
  • SWAP.
  • Rotaciones arbitrarias.
  • Puertas controladas por varios cúbits.
  • Operaciones definidas por el programador.

El hardware, sin embargo, suele proporcionar un conjunto mucho más reducido de instrucciones elementales. Por ello, una puerta lógica debe expresarse como una secuencia de puertas que el dispositivo pueda implementar.

Por hacer una comparación y salvando las distancias, cualquier operación de álgebra termina reduciéndose siempre a las operaciones de aritmética elementales (sumar, restar, dividir y multiplicar).

Por ejemplo, una puerta SWAP puede descomponerse mediante tres CNOT:

q0: ──■────X────■──
      │    │    │
q1: ──X────■────X──

La relación lógica puede escribirse como:

SWAP⁡(a,b)=CNOT⁡(a,b)CNOT⁡(b,a)CNOT⁡(a,b)\operatorname{SWAP}(a,b) = \operatorname{CNOT}(a,b) \operatorname{CNOT}(b,a) \operatorname{CNOT}(a,b)

Esta descomposición es exacta en el modelo ideal, pero no es gratuita en un dispositivo físico. Si cada puerta de dos cúbits introduce ruido, reemplazar una operación abstracta por varias puertas nativas incrementa la probabilidad de error.

Descomposición aproximada

Algunas rotaciones arbitrarias no pueden expresarse exactamente con un conjunto finito de puertas. En esos casos, el compilador genera una aproximación:

U≈GmGm−1⋯G2G1U \approx G_m G_{m-1}\cdots G_2G_1

, donde cada GiG_i pertenece al conjunto de puertas disponible.

Al aumentar la precisión de la aproximación suele aumentar también el número de puertas. Aparece así una decisión de ingeniería:

  • Una secuencia más larga aproxima mejor la operación ideal.
  • Una secuencia más corta acumula menos ruido físico.

La mejor solución matemática no siempre es la mejor solución experimental.

Asignación de cúbits lógicos a cúbits físicos

Un cúbit lógico es aquel que utilizamos realmente para realizar una operación, pero para que funcione correctamente, está soportado por un conjunto de otros cútbits dedicados a corregir errores, entre otras tareas; según la naturaleza del computador cuántico, esta proporción puede ser de 1 a 5 o incluso de 1 a 9 (esto es, por cada cúbit lógico útil, existen otros 9 que lo apoyan).

Los identificadores q0q_0, q1q_1 o q2q_2 de un circuito son abstracciones. El dispositivo dispone de cúbits físicos concretos, cada uno con características diferentes.

La asignación, conocida como qubit mapping o qubit placement, establece una correspondencia:

π:QL→QP\pi : Q_L \rightarrow Q_P

, donde QLQ_L es el conjunto de cúbits lógicos y QPQ_P el conjunto de cúbits físicos.

Por ejemplo:

q0 lógico → Q7 físico
q1 lógico → Q8 físico
q2 lógico → Q12 físico

Esta asignación influye directamente en el circuito final porque los cúbits físicos pueden diferir en un conjunto de factores, como:

  • Fidelidad de las operaciones.
  • Tasa de error de lectura.
  • Tiempos de relajación y descoherencia.
  • Conectividad con otros cúbits.
  • Duración de sus puertas.
  • Calidad de las operaciones de dos cúbits.

Una estrategia sencilla podría seleccionar los cúbits con mejores fidelidades individuales. Sin embargo, posiblemente esos cúbits estén alejados entre sí y requieran muchas operaciones de routing. Otra estrategia podría escoger una región muy conectada del procesador, aunque alguno de sus cúbits sea más ruidoso.

El problema de asignación no consiste, por tanto, en encontrar los «mejores cúbits» de forma aislada. Consiste en encontrar la mejor región física para el patrón de interacciones del circuito.

El grafo de conectividad del dispositivo

En un circuito abstracto suponemos que cualquier cúbit puede interactuar con cualquier otro. En muchos dispositivos reales, las puertas de dos cúbits solo pueden ejecutarse entre determinados pares.

Esta restricción se representa mediante un grafo de acoplamiento:

GH=(V,E)G_H = (V,E)

, donde:

  • Cada vértice v∈Vv\in V representa un cúbit físico.
  • Dada arista (u,v)∈E(u,v)\in E indica que el hardware permite una interacción directa entre esos cúbits.

Consideremos esta topología lineal:

Q0 ─── Q1 ─── Q2 ─── Q3

Una puerta entre Q0Q_0 y Q1Q_1 puede ejecutarse directamente. Una puerta entre Q0Q_0 y Q3Q_3 no.

Si el circuito exige esa interacción, el compilador debe modificar la ubicación de los estados cuánticos o utilizar una construcción equivalente compatible con la conectividad disponible.

Aquí comienza el problema de routing.

Routing e inserción de puertas SWAP

El routing determina cómo mover los estados lógicos por la topología física para que cada operación de dos cúbits pueda ejecutarse entre cúbits conectados.

Supongamos la asignación:

q0 → Q0
q1 → Q3

y una puerta lógica:

CNOT⁡(q0,q1)\operatorname{CNOT}(q_0,q_1)

Como Q0Q_0 y Q3Q_3 no son adyacentes, el compilador puede insertar operaciones SWAP:

Estado inicial:

q0        q1
 │         │
Q0 ─ Q1 ─ Q2 ─ Q3

Después del routing:

     q0    q1
      │     │
Q0 ─ Q1 ─ Q2 ─ Q3

Cada SWAP intercambia los estados contenidos en dos cúbits físicos. Es importante entender que no se «mueven» físicamente los cúbits. Lo que cambia es la correspondencia entre estados lógicos y posiciones físicas.

Si inicialmente:

π(q0)=Q0,π(q1)=Q3\pi(q_0)=Q_0,\qquad \pi(q_1)=Q_3

, después de intercambiar Q0Q_0 y Q1Q_1, queda:

π′(q0)=Q1,π′(q1)=Q3\pi'(q_0)=Q_1,\qquad \pi'(q_1)=Q_3

El compilador debe mantener esta correspondencia actualizada durante el resto del circuito.

El coste real de una SWAP

Una SWAP puede representarse mediante tres CNOT. Por tanto, insertar cinco SWAP podría introducir hasta quince operaciones adicionales de dos cúbits antes de nuevas optimizaciones.

Este coste es importante porque las operaciones de dos cúbits suelen ser más delicadas que las de un solo cúbit. El routing puede convertir un circuito lógico pequeño en un circuito físico mucho más profundo.

Routing global frente a decisiones locales

Una estrategia ingenua podría seleccionar siempre el camino más corto para acercar los dos cúbits de la siguiente puerta. Sin embargo, esta decisión local puede ser perjudicial para operaciones posteriores.

Consideremos la secuencia:

CNOT⁡(q0,q3),CNOT⁡(q0,q2),CNOT⁡(q0,q1)\operatorname{CNOT}(q_0,q_3), \quad \operatorname{CNOT}(q_0,q_2), \quad \operatorname{CNOT}(q_0,q_1)

Mover q0q_0 hacia q3q_3 puede resolver la primera interacción, pero alejarlo de los demás cúbits. Una decisión aparentemente óptima para la operación actual puede aumentar el coste total del circuito.

Un algoritmo de routing debe equilibrar diferentes objetivos:

  • Número de puertas SWAPs.
  • Profundidad añadida.
  • Duración total.
  • Fidelidad estimada.
  • Paralelismo disponible.
  • Calidad de los enlaces físicos.
  • Coste de las operaciones futuras.

Las estrategias de compilación pueden utilizar métodos basados en solvers, heurísticas y técnicas de aprendizaje automático. Sus funciones objetivo pueden considerar el número de puertas, la duración, la fidelidad y la escalabilidad de la compilación.

Optimización del circuito físico

Después de descomponer puertas e insertar operaciones de routing, el circuito contiene oportunidades de simplificación.

Entre las optimizaciones habituales se encuentran:

Cancelación de puertas inversas

Si una puerta aparece seguida de su inversa:

UU†=IU U^\dagger = I

, ambas pueden eliminarse, puesto que su aplicación no tiene efecto alguno (es como si en la siguiente expresión x = 28*2 + 2 - 2, se optimizara por x = 28*2).

Para una puerta autoinversa como XX:

XX=IXX=I

El fragmento siguiente no realiza ninguna transformación:

──X──X──

Fusión de rotaciones

Dos rotaciones consecutivas alrededor del mismo eje pueden combinarse:

Rz(α)Rz(β)=Rz(α+β)R_z(\alpha)R_z(\beta)=R_z(\alpha+\beta)

Por tanto:

──Rz(α)──Rz(β)──

puede transformarse en:

──Rz(α+β)──

Reordenación de operaciones

Las puertas independientes o conmutativas pueden reorganizarse para:

  • Exponer cancelaciones.
  • Reducir la profundidad.
  • Aumentar el paralelismo.
  • Facilitar el routing.
  • Agrupar operaciones compatibles.

Eliminación de SWAP innecesarias

No siempre es necesario devolver cada estado lógico a su posición física original. Si el circuito termina con mediciones, el compilador puede conservar la permutación final y reinterpretar los resultados clásicos.

Por ejemplo, si al final:

q0 lógico → Q4 físico
q1 lógico → Q2 físico

puede ser más económico medir Q4Q_4 y Q2Q_2 y reordenar posteriormente los bits clásicos que insertar nuevas SWAP.

Optimización dependiente del hardware

Dos secuencias algebraicamente equivalentes pueden tener costes físicos muy diferentes. Un compilador consciente del hardware puede preferir:

  • Enlaces con menor error.
  • Direcciones de control más favorables.
  • Puertas nativas calibradas.
  • Secuencias con menor duración.
  • Regiones con mejores métricas experimentales.

Por esta razón, optimizar únicamente el número total de puertas resulta insuficiente.

Scheduling: cuándo se ejecuta cada operación

Una vez determinada la secuencia física de instrucciones, todavía es necesario decidir cuándo se ejecutará cada una. El scheduling asigna un instante de inicio a cada operación:

s:O→R≥0s: O \rightarrow \mathbb{R}_{\geq 0}

, donde OO representa el conjunto de operaciones del circuito.

La asignación debe respetar varias restricciones.

Dependencias lógicas

Si una puerta utiliza el resultado cuántico producido por otra, no puede comenzar antes de que finalice la operación anterior:

s(oj)≥s(oi)+d(oi)s(o_j) \geq s(o_i)+d(o_i)

donde d(oi)d(o_i) es la duración de oio_i.

Exclusión de recursos

Dos operaciones que utilizan simultáneamente el mismo cúbit no pueden solaparse:

qubits(oi)∩qubits(oj)≠∅⇒oi y oj no se solapan\text{qubits}(o_i)\cap\text{qubits}(o_j)\neq\varnothing \Rightarrow o_i\text{ y }o_j\text{ no se solapan}

Restricciones físicas

El dispositivo puede imponer limitaciones adicionales relacionadas con:

  • Electrónica de control compartida.
  • Operaciones de medida.
  • Reinicio de cúbits.
  • Sincronización.
  • Alineación temporal.
  • Interferencias entre operaciones próximas.

El scheduling transforma una secuencia lógica en un programa temporal.

Tiempo →    0      1      2      3

Q0          H      ├─CNOT─┤     M
Q1          X      ├─CNOT─┤     M
Q2          ├─Rz───────────┤     M

La profundidad lógica cuenta capas, pero la duración física debe considerar que no todas las puertas tardan lo mismo.

Profundidad lógica y tiempo de ejecución no son equivalentes

La profundidad de un circuito se define normalmente como la longitud del camino más largo de operaciones dependientes:

D(C)=max⁡p∈P(C)∣p∣D(C)=\max_{p\in P(C)} |p|

Esta medida es útil, pero no refleja necesariamente el tiempo real.

Consideremos dos circuitos:

Circuito A:
Capa 1: H
Capa 2: CNOT
Capa 3: H

Circuito B:
Capa 1: Rz
Capa 2: Rz
Capa 3: Rz

Ambos tienen profundidad tres. Sin embargo, las duraciones de sus operaciones pueden ser distintas:

TA=d(H)+d(CNOT⁡)+d(H)T_A=d(H)+d(\operatorname{CNOT})+d(H) TB=3d(Rz)T_B=3d(R_z)

Si determinadas rotaciones se implementan mediante actualizaciones del marco de referencia en lugar de pulsos físicos, la diferencia temporal puede ser todavía mayor.

Una métrica más representativa es la duración del camino crítico:

T(C)=max⁡p∈P(C)∑g∈pd(g)T(C)=\max_{p\in P(C)} \sum_{g\in p} d(g)

Por tanto:

misma profundidad⇏misma duracioˊn\text{misma profundidad} \not\Rightarrow \text{misma duración}

y también:

menor profundidad⇏menor error\text{menor profundidad} \not\Rightarrow \text{menor error}

Por qué dos circuitos equivalentes pueden comportarse de forma diferente

Dos circuitos C1C_1 y C2C_2 son equivalentes si implementan la misma transformación, ignorando posiblemente una fase global:

UC1=eiϕUC2U_{C_1}=e^{i\phi}U_{C_2}

Esta equivalencia matemática no implica equivalencia física.

Diferente número de puertas

Una descomposición puede utilizar menos operaciones que otra:

Ng(C1)≠Ng(C2)N_g(C_1)\neq N_g(C_2)

Distinta profundidad

Un circuito puede permitir ejecutar varias puertas en paralelo:

D(C1)<D(C2)D(C_1)<D(C_2)

aunque ambos tengan un número similar de operaciones.

Diferente coste de routing

Una formulación puede ajustarse al grafo de conectividad del dispositivo y otra requerir numerosas SWAP:

NSWAP(C1)≪NSWAP(C2)N_{\mathrm{SWAP}}(C_1)\ll N_{\mathrm{SWAP}}(C_2)

Distinta fidelidad estimada

Como aproximación simplificada, si cada operación gig_i tiene una probabilidad de éxito fif_i, la fidelidad total puede estimarse mediante:

F(C)≈∏ifiF(C)\approx\prod_i f_i

Esta expresión no representa todos los efectos del ruido real, pero muestra algo importante: añadir puertas reduce la probabilidad acumulada de ejecutar correctamente el circuito.

Diferente duración

Incluso dos circuitos con la misma profundidad pueden utilizar operaciones con tiempos diferentes:

T(C1)≠T(C2)T(C_1)\neq T(C_2)

Distinta exposición a la decoherencia

Un cúbit que permanece inactivo mientras espera otras operaciones continúa expuesto al ruido. Por ello, los huecos introducidos por el scheduling también importan.

Un ejemplo sencillo

Supongamos tres cúbits lógicos y tres cúbits físicos con conectividad lineal:

Q0 ─── Q1 ─── Q2

El circuito lógico contiene:

q0: ──H────■────
           │
q1: ───────┼────
           │
q2: ───────X────

La operación de dos cúbits conecta q0q_0 con q2q_2.

Asignación A

q0 → Q0
q1 → Q1
q2 → Q2

La interacción entre q0q_0 y q2q_2 no es directa. El compilador debe introducir routing.

Una posibilidad es:

SWAP(Q0,Q1)
CNOT(Q1,Q2)

La correspondencia después de la SWAP es:

q0 → Q1
q1 → Q0
q2 → Q2

Asignación B

q0 → Q1
q1 → Q0
q2 → Q2

Ahora q0q_0 y q2q_2 son adyacentes y la CNOT puede ejecutarse directamente.

Los dos casos parten del mismo circuito lógico. Sin embargo, una mejor asignación inicial evita una SWAP y, con ella, varias operaciones físicas adicionales.

Esta es la razón por la que asignación y routing deben analizarse conjuntamente.

No existe una única función objetivo

Cuando se afirma que un circuito está «optimizado», conviene preguntar: ¿optimizado respecto a qué?

Un compilador puede intentar minimizar:

min⁡Ngates\min N_{\text{gates}}

o bien:

min⁡D(C)\min D(C)

También puede minimizar:

min⁡T(C)\min T(C)

, o maximizar una estimación de fidelidad:

max⁡F(C)\max F(C)

Otra posibilidad es utilizar una función combinada:

min⁡(αN2q+βD+γT+δE)\min \left( \alpha N_{\mathrm{2q}} +\beta D +\gamma T +\delta E \right)

, donde:

  • N2qN_{\mathrm{2q}} es el número de puertas de dos cúbits;
  • DD es la profundidad;
  • TT es la duración estimada;
  • EE es el error esperado;
  • α,β,γ,δ\alpha,\beta,\gamma,\delta representan la importancia relativa de cada objetivo.

Reducir la profundidad puede exigir utilizar enlaces más ruidosos. Minimizar SWAP puede concentrar demasiadas operaciones sobre un grupo de cúbits. Escoger los cúbits con mejores fidelidades puede aumentar las distancias de routing.

La compilación cuántica es, en gran medida, un problema de optimización multiobjetivo, similar a lo que resuelven los compiladores de lenguajes de alto nivel.

Algunas métricas interesantes que debemos comparar

Para evaluar dos circuitos compilados no basta con observar el dibujo final. Conviene comparar:

Tamaño

S(C)=nuˊmero total de operacionesS(C)=\text{número total de operaciones}

Profundidad

D(C)=nuˊmero de capas dependientesD(C)=\text{número de capas dependientes}

Puertas de dos cúbits

N2q(C)N_{2q}(C)

Suele ser una métrica especialmente relevante porque estas operaciones condicionan gran parte del routing y del error acumulado.

SWAP añadidas

NSWAP(C)N_{\mathrm{SWAP}}(C)

Permite medir el coste introducido por la conectividad física.

Duración estimada

T(C)T(C)

Depende de las duraciones reales de las instrucciones y del scheduling.

Fidelidad o error esperado

Puede utilizarse una aproximación basada en las propiedades conocidas del dispositivo, manteniendo presente que el ruido físico no siempre es independiente ni estacionario.

Calidad del resultado

Finalmente, debe compararse la distribución experimental con el resultado ideal mediante una métrica apropiada para el experimento.

Ninguno de estos indicadores, considerado aisladamente, describe por completo la calidad de la compilación.

Puntos a destacar como conclusión

El circuito que escribe un desarrollador cuántico es una descripción lógica, no el programa físico definitivo.

Para ejecutarlo, el compilador debe:

  1. Descomponer las operaciones en puertas compatibles con el dispositivo.
  2. Asignar los cúbits lógicos a cúbits físicos.
  3. Resolver las restricciones de conectividad.
  4. Insertar SWAP cuando sea necesario.
  5. Simplificar y reorganizar el circuito.
  6. Planificar temporalmente cada instrucción.
  7. Generar una representación compatible con el hardware de destino.

Cada decisión modifica el coste físico de la ejecución. Una mala asignación puede producir un routing costoso. El routing puede introducir numerosas puertas de dos cúbits. La descomposición puede aumentar la profundidad. El scheduling puede añadir esperas, y todas estas transformaciones pueden amplificar el efecto del ruido.

Por eso, dos circuitos matemáticamente equivalentes pueden presentar profundidades, duraciones y tasas de error radicalmente diferentes.

La compilación cuántica no es una etapa secundaria situada entre el algoritmo y el dispositivo. Es el proceso que determina si una formulación lógica elegante puede convertirse en un experimento físicamente viable. Para un ingeniero de software cuántico, comprender esta transformación es tan importante como conocer el propio algoritmo.

Algunas referencias

Si te interesa este tema especialmente y de una actividad muy alta en computación cuántica, aquí te dejo algunas referencias: