Skip to main content
IBM Quantum Platform

Ansaetze y formas variacionales

En el corazón de todos los algoritmos variacionales se encuentra la idea clave de analizar las diferencias entre estados, que están convenientemente relacionados a través de algún mapeo bien comportado (por ejemplo, continuo, diferenciable) de un conjunto de parámetros o variables - de ahí el nombre.

En primer lugar, exploraremos cómo construir circuitos parametrizados a mano. Utilizaremos estos circuitos para definir un Capas de puertas parametrizadas que se repiten un número determinado de veces, y los parámetros de las puertas se optimizan durante el algoritmo para minimizar la función de coste. que representa una colección de estados parametrizados para que nuestro algoritmo variacional los explore. A continuación, construiremos nuestro Combinación de un operador de referencia y una forma variacional, para describir el espacio de búsqueda que estamos explorando. aplicando esta forma variacional a nuestro estado de referencia.

También estudiaremos cómo compensar velocidad y precisión al explorar este espacio de búsqueda.

Un diagrama que muestra los componentes clave de la discusión del ansatz, incluidos los ansaetze heurísticos y los ansaetze específicos del problema.

Circuitos cuánticos parametrizados

Los algoritmos variacionales operan explorando y comparando una gama de estados cuánticos ψ(θ)|\psi(\vec{\theta})\rangle, que dependen de un conjunto finito de parámetros kk θ=(θ0,,θk1)\vec{\theta} = (\theta^0, \ldots, \theta^{k-1}). Estos estados pueden prepararse utilizando un circuito cuántico parametrizado, en el que las puertas se definen con parámetros sintonizables. Es posible crear este circuito parametrizado sin vincular ángulos específicos todavía:

from qiskit.circuit import QuantumCircuit, Parameter

theta = Parameter("θ")

qc = QuantumCircuit(3)
qc.rx(theta, 0)
qc.cx(0, 1)
qc.x(2)

qc.draw("mpl")

Output:

Output of the previous code cell
from math import pi

angle_list = [pi / 3, pi / 2]
circuits = [qc.assign_parameters({theta: angle}) for angle in angle_list]

for circuit in circuits:
    display(circuit.draw("mpl"))

Output:

Output of the previous code cell Output of the previous code cell

Forma variacional y Ansatz

Para optimizar iterativamente desde un estado de referencia ρ|\rho\rangle a un estado objetivo ψ(θ)|\psi(\vec\theta)\rangle, necesitamos definir una forma variacional UV(θ)U_V(\vec{\theta}) que representa una colección de estados parametrizados para que nuestro algoritmo variacional los explore:

0URUR0=ρUV(θ)UA(θ)0=UV(θ)UR0=UV(θ)ρ=ψ(θ)\begin{aligned} |0\rangle \xrightarrow{U_R} U_R|0\rangle & = |\rho\rangle \xrightarrow{U_V(\vec{\theta})} U_A(\vec{\theta})|0\rangle \\[1mm] & = U_V(\vec{\theta})U_R|0\rangle \\[1mm] & = U_V(\vec{\theta})|\rho\rangle \\[1mm] & = |\psi(\vec{\theta})\rangle \\[1mm] \end{aligned}

Nótese que el estado parametrizado depende tanto del estado de referencia ρ|\rho\rangle, que no depende de ningún parámetro, como de la forma variacional UV(θ)U_V(\vec{\theta}), que siempre depende de parámetros. Denominamos ansatz a la combinación de estas dos mitades: UA(θ):=UV(θ)URU_A(\vec\theta) := U_V(\vec\theta)U_R.

A medida que construimos nuestro ansatz para representar una colección de estados parametrizados para que los explore nuestro algoritmo variacional, nos damos cuenta de un problema importante: la dimensionalidad. Un sistema nn -qubit (es decir, un espacio de Hilbert) tiene un gran número de estados cuánticos distintos en el espacio de configuración. Necesitaríamos un número ingente de parámetros para explorarla a fondo. Cuantitativamente, su dimensionalidad es D=22nD = 2^{2n}. Para empeorar las cosas, la complejidad del tiempo de ejecución de los algoritmos de búsqueda, y de otros por igual, crece exponencialmente con esta dimensionalidad, un fenómeno al que a menudo se hace referencia en la literatura como la maldición de la dimensionalidad.

Para contrarrestar este contratiempo, es práctica común imponer algunas restricciones razonables a la forma variacional, de modo que sólo se exploren los estados más relevantes. Encontrar un ansatz truncado eficiente es un área activa de investigación, pero cubriremos dos diseños comunes.


Enfoques heurísticos y compensaciones

Si no dispone de ninguna información sobre su problema concreto que pueda ayudarle a restringir la dimensionalidad, puede probar con una familia arbitraria de circuitos parametrizados con menos de 22n2^{2n} parámetros. Sin embargo, hay que tener en cuenta algunas contrapartidas:

  • Velocidad : al reducir el espacio de búsqueda, el algoritmo puede funcionar más rápido.
  • Precisión : Si se reduce el espacio, se corre el riesgo de excluir la solución real del problema, lo que daría lugar a soluciones subóptimas.
  • Ruido : Los circuitos más profundos se ven afectados por el ruido, por lo que debemos experimentar con la conectividad, las puertas y la fidelidad de las puertas de nuestro ansatz.

Existe un equilibrio fundamental entre calidad (o incluso solvencia) y velocidad: cuantos más parámetros, más probabilidades de encontrar un resultado preciso, pero más tiempo se tardará en ejecutar el algoritmo.

Circuitos N-locales

Uno de los ejemplos más utilizados de ansaetze heurísticos son los circuitos N-locales, por varias razones:

  • Implementación eficiente : El ansatz N-local se compone normalmente de puertas locales sencillas que pueden implementarse eficientemente en un ordenador cuántico, utilizando un pequeño número de qubits físicos. Esto facilita la construcción y optimización de circuitos cuánticos.
  • Captura correlaciones importantes : El ansatz N-local puede capturar correlaciones importantes entre los qubits de un sistema cuántico, incluso con un número reducido de puertas. Esto se debe a que las puertas locales pueden actuar sobre qubits vecinos y crear entrelazamiento entre ellos, lo que puede ser importante para simular sistemas cuánticos complejos.

Estos circuitos constan de capas de rotación y de entrelazamiento que se repiten alternativamente una o varias veces de la siguiente manera:

  • Cada capa está formada por puertas de tamaño máximo NN, donde NN tiene que ser menor que el número de qubits.
  • Para una capa de rotación, las puertas se apilan unas sobre otras. Podemos utilizar operaciones de rotación estándar, como RX o CRZ.
  • Para una capa de enredo, podemos utilizar puertas como Toffoli gates o CX con una estrategia de enredo.
  • Ambos tipos de capas pueden estar parametrizadas o no, pero al menos una de ellas debe contener parámetros. De lo contrario, sin al menos un parámetro, ¡no habría variaciones!
  • Opcionalmente, se añade una capa de rotación adicional al final del circuito.

Por ejemplo, creemos un circuito de cinco qubits NLocal con bloques de rotación formados por RX y CRZ compuertas, bloques de entrelazamiento formados por Toffoli compuertas que actúan sobre los qubits [0,1,2][0,1,2], [0,2,3][0,2,3], [4,2,1][4,2,1] y [3,1,0][3,1,0] y 22 repeticiones de cada capa.

from qiskit.circuit.library import NLocal, CCXGate, CRZGate, RXGate
from qiskit.circuit import Parameter

theta = Parameter("θ")
ansatz = NLocal(
    num_qubits=5,
    rotation_blocks=[RXGate(theta), CRZGate(theta)],
    entanglement_blocks=CCXGate(),
    entanglement=[[0, 1, 2], [0, 2, 3], [4, 2, 1], [3, 1, 0]],
    reps=2,
    insert_barriers=True,
)
ansatz.decompose().draw("mpl")

Output:

Output of the previous code cell

En el ejemplo anterior, la puerta más grande es la puerta Toffoli, que actúa sobre tres qubits, lo que hace que el circuito sea 33 -local. Los tipos de circuitos NN -locales más utilizados son los circuitos 22 -locales con puertas de rotación de un solo qubit y puertas de entrelazamiento 22 -qubit.

Vamos a crear un circuito 22 -local usando la clase TwoLocal de Qiskit. La sintaxis es la misma que en NLocal, pero hay algunas diferencias. Por ejemplo, la mayoría de las puertas, como RX, RZ, y CNOT, se pueden pasar como cadenas sin importar las puertas ni crear una instancia de Parameter .

from qiskit.circuit.library import TwoLocal

ansatz = TwoLocal(
    num_qubits=5,
    rotation_blocks=["rx", "rz"],
    entanglement_blocks="cx",
    entanglement="linear",
    reps=2,
    insert_barriers=True,
)
ansatz.decompose().draw("mpl")

Output:

Output of the previous code cell

En este caso, utilizamos la distribución de enredo lineal, en la que cada qubit está enredado con el siguiente. Para conocer otras estrategias, consulte la documentación de TwoLocal .

SU2 eficiente

efficient_su2 es un circuito eficiente desde el punto de vista del hardware que consta de capas de operaciones de un solo qubit que abarcan SU(2) y CX enredos. Se trata de un patrón heurístico que puede utilizarse para preparar funciones de onda de prueba para algoritmos cuánticos variacionales o como circuito de clasificación para el aprendizaje automático.

from qiskit.circuit.library import efficient_su2

ansatz = efficient_su2(4, su2_gates=["rx", "y"], entanglement="linear", reps=1)
ansatz.decompose().draw("mpl")

Output:

Output of the previous code cell

Enfoques específicos para cada problema

Mientras que las ansaetze heurísticas y de hardware eficiente nos ayudan a resolver un problema de forma ingenua, podemos utilizar el conocimiento específico del problema para restringir nuestro espacio de búsqueda de circuitos a un tipo específico. Esto nos ayudará a ganar velocidad sin perder precisión en nuestro proceso de búsqueda.

Optimización

En un problema de corte máximo, queremos dividir los nodos de un grafo de forma que se maximice el número de aristas entre nodos de distintos grupos. La partición de corte máximo deseada para el grafo siguiente es clara: el nodo 0 de la izquierda debe estar separado del resto de los nodos de la derecha por un corte.

import rustworkx as rx
from rustworkx.visualization import mpl_draw

n = 4
G = rx.PyGraph()
G.add_nodes_from(range(n))
# The edge syntax is (start, end, weight)
edges = [(0, 1, 1.0), (0, 2, 1.0), (0, 3, 1.0), (1, 2, 1.0), (2, 3, 1.0)]
G.add_edges_from(edges)

mpl_draw(
    G, pos=rx.shell_layout(G), with_labels=True, edge_labels=str, node_color="#1192E8"
)

Output:

Output of the previous code cell

Para utilizar el algoritmo QAOA en un problema de corte máximo, necesitamos un Hamiltoniano de Pauli que codifique el coste de forma que el valor mínimo de la expectativa del operador corresponda al número máximo de aristas entre los nodos de dos grupos diferentes.

Para este sencillo ejemplo, el operador es una combinación lineal de términos con operadores Z en nodos conectados por una arista (recuérdese que el qubit 0 está más a la derecha): ZZII+IZZI+ZIIZ+IZIZ+IIZZZZII + IZZI + ZIIZ + IZIZ + IIZZ. Una vez construido el operador, el ansatz para el algoritmo QAOA se puede construir fácilmente utilizando el circuito QAOAAnsatz de la biblioteca de circuitos Qiskit.

# Pre-defined ansatz circuit, operator class and visualization tools
from qiskit.circuit.library import QAOAAnsatz
from qiskit.quantum_info import SparsePauliOp

# Problem to Hamiltonian operator
hamiltonian = SparsePauliOp.from_list(
    [("ZZII", 1), ("IZZI", 1), ("ZIIZ", 1), ("IZIZ", 1), ("IIZZ", 1)]
)
# QAOA ansatz circuit
ansatz = QAOAAnsatz(hamiltonian, reps=2)
# Draw
ansatz.decompose(reps=3).draw("mpl")

Output:

Output of the previous code cell

La imagen anterior ilustra el ansatz en puertas básicas para mayor claridad. Sin embargo, puede expresarse en varios niveles de descomposición cambiando el argumento reps o dibujando el circuito sin el método de descomposición. Por ejemplo, la siguiente representación muestra directamente la estructura QAOA con el valor de repetición por defecto, que es reps=1.

ansatz.decompose(reps=2).draw("mpl")

Output:

Output of the previous code cell

Quantum Machine Learning

En el aprendizaje automático, una aplicación común es la clasificación de datos en dos o más categorías. Esto implica codificar un punto de datos en un mapa de características que mapea vectores de características clásicas en el espacio cuántico de Hilbert. La construcción de mapas cuánticos de características basados en circuitos cuánticos parametrizados que son difíciles de simular clásicamente es un paso importante para obtener una ventaja potencial sobre los enfoques clásicos de aprendizaje automático y es un área activa de investigación actual.

En zz_feature_map se puede crear un circuito parametrizado. Podemos pasar nuestros puntos de datos al mapa de características ( xx ) y una forma variacional separada para pasar pesos como parámetros ( θ\theta ).

from qiskit.circuit.library import zz_feature_map, TwoLocal

data = [0.1, 0.2]

zz_feature_map_reference = zz_feature_map(feature_dimension=2, reps=2)
zz_feature_map_reference = zz_feature_map_reference.assign_parameters(data)

variation_form = TwoLocal(2, ["ry", "rz"], "cz", reps=2)
vqc_ansatz = zz_feature_map_reference.compose(variation_form)
vqc_ansatz.decompose().draw("mpl")

Output:

Output of the previous code cell

Resumen

Con esta lección, has aprendido a definir tu espacio de búsqueda con una forma variacional:

  • Preparar estados con un circuito cuántico parametrizado, en el que las puertas se definen con parámetros sintonizables
  • Cómo construir análisis que compensen velocidad y precisión
  • Soluciones heurísticas
  • Respuestas a problemas específicos

Nuestra carga de trabajo variacional de alto nivel tiene el siguiente aspecto:

Un diagrama de circuito que muestra dos unitarios: uno que prepara el estado de referencia y otro que prepara el ansatz.

Para cada parámetro variacional θ\vec\theta, se producirá un estado cuántico diferente. Para encontrar los parámetros óptimos, necesitamos definir una función de coste específica del problema para actualizar iterativamente los parámetros de nuestro ansatz.

¿Le ha resultado útil esta página?
Informe de un error, de una errata o solicite contenido en GitHub.