Skip to main content
IBM Quantum Platform

TeNPy backend baseado em camadas

qiskit_addon_mpf.backends.tenpy_layers

Um backend de evolução de tempo em camadas usando tenpy.

Cuidado

A dependência opcional TeNPy foi oferecida anteriormente sob uma licença GPLv3. Desde o lançamento do v1.0.4 em 2 de outubro de 2024, ele foi oferecido sob a licença Apache v2. A licença deste pacote é compatível apenas com as versões licenciadas do Apache do TeNPy.

Aviso

Esse backend só estará disponível se as dependências opcionais tiverem sido instaladas:

pip install "qiskit-addon-mpf[tenpy]"
LayerwiseEvolverUm caso especial do TEBDEvolver baseado em modelos de evolução em camadas.
LayerModelUm modelo para representar uma camada de interações de evolução temporal.

Método subjacente

Esse módulo fornece um backend de evolução temporal semelhante ao baseado em TEBD fornecido pelo módulo tenpy_tebd módulo. A principal diferença é que esse módulo oferece ao usuário total flexibilidade para definir suas fórmulas de produto, não o limitando às opções incorporadas na tenpy biblioteca.

Em sua essência, o algoritmo fornecido por esse módulo ainda é um algoritmo TEBD [1]. No entanto, em vez de impor as atualizações alternadas para os vínculos pares e ímpares do estado de evolução temporal (consulte também evolve_step()), essa implementação terceiriza a responsabilidade de atualizar os vínculos de forma alternada para a definição de várias camadas de evolução temporal.

É melhor explicar isso com um exemplo. Vamos supor que temos um Hamiltoniano genérico atuando em uma cadeia unidimensional de locais.

Dica

Abaixo, somos muito cuidadosos com a ordem dos termos Pauli do Hamiltoniano, pois isso afeta diretamente a estrutura do circuito de evolução temporal mais tarde.

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

Vamos agora inspecionar o circuito de evolução temporal desse Hamiltoniano usando uma fórmula de Suzuki-Trotter de segunda ordem.

>>> 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>
Saída do código anterior.

No circuito acima, podemos identificar claramente sua estrutura em camadas. Podemos enfatizar isso ainda mais, dividindo o circuito em várias camadas, conforme mostrado abaixo (recombinamos o layers em um único circuito com barreiras entre eles para facilitar a visualização).

>>> 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>
Saída do código anterior.
Dica

A assimetria das camadas centrais é resultado da implementação da fórmula de Qiskit SuzukiTrotter fórmula de Qiskit. Em sua forma de segunda ordem, ele combina as duas evoluções de meio período do termo final no Hamiltoniano em uma única evolução de duas vezes o comprimento. Poderíamos transpilar esse circuito para recolher todas essas portas subequentes nas duas camadas centrais (como na última), mas, para simplificar o exemplo, não faremos isso aqui.

Não é possível instruir o algoritmo TeNPy’s TEBD a simular a estrutura exata do circuito mostrado acima. O motivo para isso é uma limitação em sua interface, pois ele só aceita o Hamiltoniano completo a ser fornecido, que é então evoluído no tempo usando fórmulas de Trotter predefinidas. No entanto, ao fazer isso, ele não trata a ordem dos termos de Pauli em um Hamiltoniano com qualquer significado (como fazemos aqui).

Se alguém quiser calcular os coeficientes MPF dinâmicos de uma evolução temporal empregando uma estrutura de fórmula de produto diferente das implementadas em TeNPy (como o exemplo acima), poderá usar o algoritmo de evolução temporal fornecido por esse módulo. Em vez de usar um único Hamiltoniano monolítico cuja evolução temporal deve ser modelada, o LayerwiseEvolver aceita uma lista de objetos LayerModel cada um descrevendo uma camada individual da fórmula do produto. Isso proporciona ao usuário total flexibilidade na definição da decomposição de Trotter até o nível mais granular.

No entanto, é preciso ter cuidado para garantir que a propriedade do TEBD de atualizar títulos pares e ímpares de forma alternada ainda seja garantida. Felizmente, para circuitos quânticos que consistem em, no máximo, portas de dois qubits, essa propriedade é satisfeita por construção.


Exemplo de código

Nesta seção, vamos nos basear no exemplo acima e mostrar como pegar uma fórmula Trotter personalizada e usá-la para construir uma fórmula LayerwiseEvolver que pode ser usada para substituir o tenpy_tebd.TEBDEvolver no fluxo de trabalho descrito em tenpy_tebd.

Dica

O fluxo de trabalho geral do uso desse módulo é o mesmo do módulo tenpy_tebd portanto, não deixe de ler essas instruções também.

Em termos simples, devemos converter cada um dos circuitos layers (veja acima) em uma LayerModel instância. Para isso, podemos usar seu método from_quantum_circuit() método.

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

No código acima, você pode ver como a conversão é simples para camadas que contêm apenas portas de dois qubits atuando em qubits mutuamente exclusivos (que as camadas de profundidade 1 garantem).

No entanto, devemos ter mais cuidado com as camadas que incluem portas de um único qubit. A razão para isso é que o algoritmo TEBD subjacente ao LayerwiseEvolver deve atualizar os vínculos pares e ímpares de forma alternada. E como as portas de um único qubit não são aplicadas em um local, mas, em vez disso, são divididas ao meio e aplicadas às ligações em ambos os lados, uma camada de portas de um único qubit atuando em todos os qubits quebraria essa suposição.

Para contornar esse problema, podemos pegar qualquer camada que consista apenas em portas de um único qubit e aplicá-la duas vezes (uma nas ligações pares e outra nas ligações ímpares).

>>> 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])

Agora que sabemos como tratar as camadas que consistem em portas de dois qubits e de um único qubit, podemos transformar as camadas 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

No final, temos 8 LayerModelum para cada uma das 4 camadas de dois qubits e dois para cada uma das 2 camadas de um único qubit.

Por fim, podemos definir nosso ApproxEvolverFactory para ser usado na função setup_dynamic_lse() função.

>>> 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,
...         },
...     },
... )
Cuidado

Deve-se observar que, nesse fluxo de trabalho, ainda não fixamos a etapa de tempo usada pela fórmula de Trotter. Também configuramos apenas uma única repetição da fórmula de Trotter, pois o restante será feito pelo algoritmo interno DynamicMPF interno, executado durante setup_dynamic_lse().

Obviamente, você também pode usar isso para especificar um arquivo ExactEvolverFactory. Mas você também pode misturar e combinar um tenpy_layers.LayerwiseEvolver com um tenpy_tebd.TEBDEvolver.


Recursos

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

Esta página foi útil?
Relate um bug, erro de digitação ou solicite conteúdo no GitHub.