
    z	i#                        S r SSKJr  SSKrSSKJr  SSKJr  SSKr	SSK
Jr  SSKJr  SSKJr  SSKrS	S
KJrJr  \R(                  (       a  SSKJr  SSKJr   " S S\5      rSS jrg)z#The Suzuki-Trotter product formula.    )annotationsN)Callable)chain)ParameterExpression)QuantumCircuit)SparsePauliOp   )ProductFormulareorder_paulis)ParameterValueType)PauliEvolutionGatec                     ^  \ rS rSrSr       S	SS.                 S
U 4S jjjjr    SS jr\S 5       rSr	U =r
$ )SuzukiTrotter"   a  The (higher order) Suzuki-Trotter product formula.

The Suzuki-Trotter formulas improve the error of the Lie-Trotter approximation.
For example, the second order decomposition is

.. math::

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

Higher order decompositions are based on recursions, see Ref. [1] for more details.

In this implementation, the operators are provided as sum terms of a Pauli operator.
For example, in the second order Suzuki-Trotter decomposition we approximate

.. math::

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

References:
    [1]: 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>`_
    [2]: 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>`_
F)"atomic_evolution_sparse_observablec               j   > US:  a  US-  S:X  a  [        SU S35      e[        T	U ]	  UUUUUUUUS9  g)a  
Args:
    order: The order of the product formula.
    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. This only takes effect when ``atomic_evolution is None``.
    atomic_evolution: A function to apply the evolution of a single
        :class:`~.quantum_info.Pauli`, or :class:`.SparsePauliOp` of only commuting terms,
        to a circuit. The function takes in three arguments: the circuit to append the
        evolution to, the Pauli operator to evolve, and the evolution time. By default, a
        single Pauli evolution is decomposed into a chain of ``CX`` gates and a single
        ``RZ`` gate.
    wrap: Whether to wrap the atomic evolutions into custom gate objects. This only takes
        effect when ``atomic_evolution is None``.
    preserve_order: If ``False``, allows reordering the terms of the operator to
        potentially yield a shallower evolution circuit. Not relevant
        when synthesizing operator with a single term.
    atomic_evolution_sparse_observable: If a custom ``atomic_evolution`` is passed,
        which does not yet support :class:`.SparseObservable`\ s as input, set this
        argument to ``False`` to automatically apply a conversion to :class:`.SparsePauliOp`.
        This argument is supported until Qiskit 2.2, at which point all atomic evolutions
        are required to support :class:`.SparseObservable`\ s as input.

Raises:
    ValueError: If order is not even
r	      zfSuzuki product formulae are symmetric and therefore only defined for when the order is 1 or even, not .)preserve_orderr   N)
ValueErrorsuper__init__)
selforderrepsinsert_barrierscx_structureatomic_evolutionwrapr   r   	__class__s
            c/home/james-whalen/.local/lib/python3.13/site-packages/qiskit/synthesis/evolution/suzuki_trotter.pyr   SuzukiTrotter.__init__>   sb    V 19a88=waA 
 	)/Q 	 		
    c                v  ^ ^	 UR                   nUR                  m	U U	4S jn[        U[        5      (       a  U Vs/ s H
  oC" U5      PM     nnOU" U5       Vs/ s H  of/PM     nnT R	                  T R
                  U5      nT R                  [        [        R                  " U5      5      -  nU$ s  snf s  snf )a  Expand the Hamiltonian into a Suzuki-Trotter sequence of sparse gates.

For example, the Hamiltonian ``H = IX + ZZ`` for an evolution time ``t`` and
1 repetition for an order 2 formula would get decomposed into a list of 3-tuples
containing ``(pauli, indices, rz_rotation_angle)``, that is:

.. code-block:: text

    ("X", [0], t), ("ZZ", [0, 1], 2t), ("X", [0], t)

Note that the rotation angle contains a factor of 2, such that that evolution
of a Pauli :math:`P` over time :math:`t`, which is :math:`e^{itP}`, is represented
by ``(P, indices, 2 * t)``.

For ``N`` repetitions, this sequence would be repeated ``N`` times and the coefficients
divided by ``N``.

Args:
    evolution: The evolution gate to expand.

Returns:
    The Pauli network implementing the Trotter expansion.
c           
     &  > [        U [        5      (       a  U R                  5       OU R                  5       nU VVVs/ s H&  u  p#nX#[        U5      T-  S-  TR                  -  4PM(     nnnnTR
                  (       d  [        U5      $ U$ s  snnnf )Nr   )
isinstancer   to_sparse_listreal_or_failr   r   r   )operatorsparse_listpauliindicescoeffpaulisr   times         r!   r'   ,SuzukiTrotter.expand.<locals>.to_sparse_list   s     h66 ''),,.  .9-8)EE e!4t!;a!?$))!KL-8   &&%f--Ms   -B)	r)   r/   r&   list_recurser   r   r   from_iterable)
r   	evolution	operatorsr'   r)   non_commutingopproduct_formula	flattenedr/   s
   `        @r!   expandSuzukiTrotter.expandz   s    4 &&	~~	  i&&FOPi(^H5iMPM -;9,EF,EbT,EMF --

MBIIU%8%8%I JJ	 Q Gs   B1B6c                   U S:X  a  U$ U S:X  aV  US S  VVVVs/ s H!  nU VVVs/ s H  u  p4oSXES-  4PM     snnnPM#     nnnnnUS   /nXg-   [        [        U5      5      -   $ SSSSU S-
  -  -  -
  -  nS[        R                  U S-
  U VVVVs/ s H!  nU VVVs/ s H  u  p4oSXEU-  4PM     snnnPM#     snnnn5      -  n	[        R                  U S-
  U VVVVs/ s H(  nU VVVs/ s H  u  p4nX4USSU-  -
  -  4PM     snnnPM*     snnnn5      n
X-   U	-   $ s  snnnf s  snnnnf s  snnnf s  snnnnf s  snnnf s  snnnnf )Nr	   r      )r1   reversedr   r2   )r   grouped_paulisr.   labelqubitsr-   halvesfull	reductionouterinners              r!   r2   SuzukiTrotter._recurse   s   A:!!aZ -Sb11F IOO0Du+O1   #2&'D=4(8#999 QqEAI!778I..	 #1"0 U[[TZ<PE5VY%67TZ["0 E "**	 #1
 #1 5;4:0E5 Q]1B(CD4: #1	E =5((3 P \sE   D&
D	D&
D5D.0	D5E+D=	ED&
.D5=E )r   r	   Fr   NFT)r   intr   rJ   r   boolr   strr   zYCallable[[QuantumCircuit, qiskit.quantum_info.Pauli | SparsePauliOp, float], None] | Noner   rK   r   rK   r   rK   returnNone)r4   r   rM   z/list[tuple[str, list[int], ParameterValueType]])__name__
__module____qualname____firstlineno____doc__r   r:   staticmethodr2   __static_attributes____classcell__)r    s   @r!   r   r   "   s    :  %# #:
 49:
:
 :
 	:

 :
:
 :
 :
 -1:
 
:
 :
x8+8	88t ) )r#   r   c                   [        U [        5      (       a  U $ U[        R                  " [        5      R
                  -  n[        [        R                  " U 5      5      U:  a  [        R                  " U 5      $ [        SU  S35      e)zReturn real if close, otherwise fail. Unbound parameters are left unchanged.

Based on NumPy's ``real_if_close``, i.e. ``tol`` is in terms of machine precision for float.
zEncountered complex value z, but expected real.)
r&   r   npfinfofloatepsabsimagrealr   )valuetolabstols      r!   r(   r(      sh    
 %,--288E?&&&F
2775>V#wwu~
1%8LM
NNr#   )d   )rS   
__future__r   typingcollections.abcr   	itertoolsr   numpyrX   "qiskit.circuit.parameterexpressionr   qiskit.circuit.quantumcircuitr   qiskit.quantum_infor   qiskitr8   r
   r   TYPE_CHECKINGr   &qiskit.circuit.library.pauli_evolutionr   r   r(   rI   r#   r!   <module>rn      sL    * "  $   B 8 -  ;	@Ir)N r)jOr#   