# Código fuente para qiskit.synthesis.evolution.lie_trotter

# This code is part of Qiskit.
#
#
# obtain a copy of this license in the LICENSE.txt file in the root directory
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""The Lie-Trotter product formula."""

from typing import Callable, Optional, Union, Dict, Any
import numpy as np
from qiskit.circuit.quantumcircuit import QuantumCircuit
from qiskit.quantum_info.operators import SparsePauliOp, Pauli

from .product_formula import ProductFormula

[documentos]class LieTrotter(ProductFormula):
r"""The Lie-Trotter product formula.

The Lie-Trotter formula approximates the exponential of two non-commuting operators
with products of their exponentials up to a second order error:

.. math::

e^{A + B} \approx e^{A}e^{B}.

In this implementation, the operators are provided as sum terms of a Pauli operator.
For example, we approximate

.. math::

e^{-it(XX + ZZ)} = e^{-it XX}e^{-it ZZ} + \mathcal{O}(t^2).

References:

: D. Berry, G. Ahokas, R. Cleve and B. Sanders,
"Efficient quantum algorithms for simulating sparse Hamiltonians" (2006).
arXiv:quant-ph/0508139 <https://arxiv.org/abs/quant-ph/0508139>_
: N. Hatano and M. Suzuki,
"Finding Exponential Product Formulas of Higher Orders" (2005).
arXiv:math-ph/0506007 <https://arxiv.org/pdf/math-ph/0506007.pdf>_
"""

def __init__(
self,
reps: int = 1,
insert_barriers: bool = False,
cx_structure: str = "chain",
atomic_evolution: Optional[
Callable[[Union[Pauli, SparsePauliOp], float], QuantumCircuit]
] = None,
) -> None:
"""
Args:
reps: The number of time steps.
insert_barriers: Whether to insert barriers between the atomic evolutions.
cx_structure: How to arrange the CX gates for the Pauli evolutions, can be
"chain", where next neighbor connections are used, or "fountain", where all
qubits are connected to one.
atomic_evolution: A function to construct the circuit for the evolution of single
Pauli string. Per default, a single Pauli evolution is decomposed in a CX chain
and a single qubit Z rotation.
"""
super().__init__(1, reps, insert_barriers, cx_structure, atomic_evolution)

[documentos]    def synthesize(self, evolution):
# get operators and time to evolve
operators = evolution.operator
time = evolution.time

# construct the evolution circuit
evolution_circuit = QuantumCircuit(operators.num_qubits)
first_barrier = False

if not isinstance(operators, list):
pauli_list = [(Pauli(op), np.real(coeff)) for op, coeff in operators.to_list()]
else:
pauli_list = [(op, 1) for op in operators]

# if we only evolve a single Pauli we don't need to additionally wrap it
wrap = not (len(pauli_list) == 1 and self.reps == 1)

for _ in range(self.reps):
for op, coeff in pauli_list:
if first_barrier:
if self.insert_barriers:
evolution_circuit.barrier()
else:
first_barrier = True

evolution_circuit.compose(
self.atomic_evolution(op, coeff * time / self.reps), wrap=wrap, inplace=True
)

return evolution_circuit

@property
def settings(self) -> Dict[str, Any]:
"""Return the settings in a dictionary, which can be used to reconstruct the object.

Returns:
A dictionary containing the settings of this product formula.

Raises:
NotImplementedError: If a custom atomic evolution is set, which cannot be serialized.
"""
if self._atomic_evolution is not None:
raise NotImplementedError(
"Cannot serialize a product formula with a custom atomic evolution."
)

return {
"reps": self.reps,
"insert_barriers": self.insert_barriers,
"cx_structure": self._cx_structure,
}