Skip to main content
IBM Quantum Platform

Backend basado en capas Quimb

qiskit_addon_mpf.backends.quimb_layers

Un backend de evolución temporal por capas que utiliza quimb.

Aviso

Este backend sólo está disponible si se han instalado las dependencias opcionales:

pip install "qiskit-addon-mpf[quimb]"
LayerwiseEvolverUn caso especial de la TEBDEvolver basado en modelos de evolución por capas.
LayerModelUn modelo para representar una capa de interacciones tiempo-evolución.

Método subyacente

Este módulo proporciona un backend de evolución temporal similar al basado en TEBD proporcionado por el módulo quimb_tebd basado en TEBD. La principal diferencia es que este módulo ofrece al usuario total flexibilidad para definir las fórmulas de sus productos, por lo que no se limita a las opciones integradas en la quimb biblioteca.

En esencia, el algoritmo proporcionado por este módulo sigue siendo un algoritmo TEBD [1]. Sin embargo, en lugar de imponer las actualizaciones alternas de los enlaces pares e impares del estado de evolución temporal (véase también quimb_tebd.TEBDEvolver.sweep()), esta implementación externaliza la responsabilidad de actualizar los enlaces de forma alterna a la definición de múltiples capas de evolución temporal.

Esto se explica mejor con un ejemplo. Supongamos que tenemos algún Hamiltoniano genérico actuando sobre una cadena unidimensional de sitios.

Sugerencia

A continuación somos muy deliberados sobre el orden de los términos de Pauli del Hamiltoniano porque esto afecta directamente a la estructura del circuito de evolución temporal más adelante.

>>> from qiskit.quantum_info import SparsePauliOp
>>> hamil = SparsePauliOp.from_sparse_list(
...     [("ZZ", (i, i+1), 1.0) for i in range(1, 9, 2)] +
...     [("Z", (i,), 0.5) for i in range(10)] +
...     [("ZZ", (i, i+1), 1.0) for i in range(0, 9, 2)],
...     num_qubits=10,
... )

Inspeccionemos ahora el circuito de evolución temporal de este hamiltoniano utilizando una fórmula de Suzuki-Trotter de segundo orden.

>>> from qiskit.synthesis import SuzukiTrotter
>>> from qiskit_addon_utils.problem_generators import generate_time_evolution_circuit
>>> circuit = generate_time_evolution_circuit(hamil, time=1.0, synthesis=SuzukiTrotter(order=2))
>>> circuit.draw("mpl")  
<Figure size 956...x869... with 1 Axes>
Salida del código anterior.

En el circuito anterior, podemos identificar claramente su estructura por capas. Podemos enfatizar esto aún más, dividiendo el circuito en múltiples capas como se muestra a continuación (recombinamos el layers en un solo circuito con barreras entre ellos para facilitar la visualización).

>>> from qiskit_addon_utils.slicing import combine_slices, slice_by_gate_types
>>> layers = slice_by_gate_types(circuit)
>>> combine_slices(layers, include_barriers=True).draw("mpl")  
<Figure size 1374...x869... with 1 Axes>
Salida del código anterior.
Sugerencia

La asimetría de las capas centrales es el resultado de la aplicación de la fórmula de Qiskit SuzukiTrotter de Qiskit. En su forma de segundo orden, combina las dos evoluciones de medio tiempo del término final del hamiltoniano en una sola del doble de longitud. Podríamos transpilar este circuito para colapsar todas esas puertas subequivalentes en las dos capas centrales (igual que en el anterior), pero en aras de la simplicidad de este ejemplo, no lo haremos aquí.

No es posible instruir al algoritmo TEBD de Quimb para que simule la estructura exacta del circuito mostrado arriba. La razón de ello es una limitación de su interfaz, ya que sólo acepta que se proporcione el Hamiltoniano completo, que luego evoluciona en el tiempo utilizando fórmulas de Trotter predefinidas. Sin embargo, al hacerlo no trata el orden de los términos de Pauli en un Hamiltoniano con ningún significado (como hacemos aquí).

Si se desea calcular los coeficientes MPF dinámicos de una evolución temporal empleando una estructura de fórmula de producto distinta de las implementadas en Quimb (como el ejemplo anterior), se puede utilizar el algoritmo de evolución temporal proporcionado por este módulo. En lugar de tomar un único hamiltoniano monolítico cuya evolución temporal se desea modelizar, el programa LayerwiseEvolver acepta una lista de objetos LayerModel cada uno de los cuales describe una capa individual de la fórmula del producto. Esto ofrece al usuario una flexibilidad total para definir la descomposición Trotter hasta el nivel más granular.

Sin embargo, hay que tener cuidado para garantizar la propiedad de la TEBD de actualizar los bonos pares e impares de forma alterna. Afortunadamente, para los circuitos cuánticos que constan como máximo de puertas de dos qubits, esta propiedad se cumple por construcción.


Ejemplo de código

En esta sección, nos basamos en el ejemplo anterior y mostramos cómo tomar una fórmula Trotter personalizada y utilizarla para construir una fórmula LayerwiseEvolver que puede utilizarse para sustituir al quimb_tebd.TEBDEvolver en el flujo de trabajo descrito en quimb_tebd.

Sugerencia

El flujo de trabajo general del uso de este módulo es el mismo que el del módulo quimb_tebd así que asegúrese de leer también esas instrucciones.

En pocas palabras, debemos convertir cada uno de los circuitos layers (véase más arriba) en una LayerModel instancia. Para ello, podemos utilizar su from_quantum_circuit() método.

>>> from qiskit_addon_mpf.backends.quimb_layers import LayerModel
>>> model0 = LayerModel.from_quantum_circuit(layers[0])
>>> layer_models = [model0]

En el código anterior se puede ver lo sencilla que es la conversión para capas que contienen sólo puertas de dos qubits que actúan sobre qubits mutuamente excluyentes (lo que garantizan las capas de profundidad 1).

Sin embargo, debemos tener más cuidado con las capas que incluyen puertas de un solo qubit. La razón de ello es que el algoritmo TEBD subyacente al LayerwiseEvolver debe actualizar los enlaces pares e impares de forma alterna. Y como las puertas de un solo qubit no se aplican en un sitio, sino que se dividen por la mitad y se aplican a los enlaces de cada lado, una capa de puertas de un solo qubit actuando sobre todos los qubits rompería esta suposición.

Para eludir este problema, podemos tomar cualquier capa que consista únicamente en puertas single-qubit, y aplicar dos veces (una vez en los enlaces pares y otra en los impares).

>>> model1a = LayerModel.from_quantum_circuit(layers[1], keep_only_odd=True)
>>> model1b = LayerModel.from_quantum_circuit(layers[1], keep_only_odd=False)
>>> layer_models.extend([model1a, model1b])

Ahora que sabemos cómo tratar las capas compuestas por puertas de dos qubits y de un qubit, podemos transformar las capas restantes.

>>> for layer in layers[2:]:
...     num_qubits = len(layer.data[0].qubits)
...     if num_qubits == 2:
...         layer_models.append(LayerModel.from_quantum_circuit(layer))
...     else:
...         layer_models.append(
...             LayerModel.from_quantum_circuit(layer, keep_only_odd=True)
...         )
...         layer_models.append(
...             LayerModel.from_quantum_circuit(layer, keep_only_odd=False)
...         )
>>> assert len(layer_models) == 8

Al final, tenemos 8 LayerModeluna para cada una de las 4 capas de dos qubits y dos para cada una de las 2 capas de un qubit.

Por último, podemos definir nuestro ApproxEvolverFactory que se utilizará dentro de la función setup_dynamic_lse() función

>>> from functools import partial
>>> from qiskit_addon_mpf.backends.quimb_layers import LayerwiseEvolver
>>> approx_evolver_factory = partial(
...     LayerwiseEvolver,
...     layers=layer_models,
...     split_opts={"max_bond": 10, "cutoff": 1e-5},
... )
Precaución

Cabe señalar que en este flujo de trabajo aún no hemos fijado el paso temporal utilizado por la fórmula de Trotter. También hemos establecido una única repetición de la fórmula Trotter, ya que el resto lo hará el algoritmo interno DynamicMPF interno, ejecutado durante setup_dynamic_lse().

Por supuesto, también se puede utilizar para especificar un archivo ExactEvolverFactory. Pero también se puede mezclar un quimb_layers.LayerwiseEvolver con un quimb_tebd.TEBDEvolver.


Recursos

[1]: https://en.wikipedia.org/wiki/Time-evolving _block_decimation

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