Skip to main content
IBM Quantum Platform

TeNPy backend basado en capas

qiskit_addon_mpf.backends.tenpy_layers

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

Precaución

La dependencia opcional TeNPy se ofrecía anteriormente bajo una licencia GPLv3. A partir de la publicación de v1.0.4 el 2 de octubre de 2024, se ha ofrecido bajo la licencia Apache v2. La licencia de este paquete sólo es compatible con las versiones con licencia de Apache de TeNPy.

Aviso

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

pip install "qiskit-addon-mpf[tenpy]"
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 tenpy_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 tenpy 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 evolve_step()), 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 TeNPy’s TEBD para simular la estructura exacta del circuito mostrado anteriormente. La razón de ello es una limitación de su interfaz, ya que sólo acepta el Hamiltoniano completo, que luego evoluciona en el tiempo utilizando fórmulas predefinidas de Trotter. 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 TeNPy (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 tenpy_tebd.TEBDEvolver en el flujo de trabajo descrito en tenpy_tebd.

Sugerencia

El flujo de trabajo general del uso de este módulo es el mismo que el del módulo tenpy_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.tenpy_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 evitar este problema, podemos tomar cualquier capa que consista únicamente en puertas de un solo qubit, y aplicarla dos veces (una 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.tenpy_layers import LayerwiseEvolver
>>> approx_evolver_factory = partial(
...     LayerwiseEvolver,
...     layers=layer_models,
...     options={
...         "preserve_norm": False,
...         "trunc_params": {
...             "chi_max": 10,
...             "svd_min": 1e-5,
...             "trunc_cut": None,
...         },
...     },
... )
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 tenpy_layers.LayerwiseEvolver con un tenpy_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.