
    z	ie5                        S r SSKJr  SSKJr  SSKrSSKrSSK	J
r
  SSKJr  SSKJr  SSKJrJrJr  SSKr\(       a  SS	KJr   " S
 S\
5      r    SS jrS rS rg)z0A gate to implement time-evolution of operators.    )annotations)TYPE_CHECKINGN)Gate)ParameterValueType)ParameterExpression)PauliSparsePauliOpSparseObservable)EvolutionSynthesisc                     ^  \ rS rSrSr   S         SU 4S jjjr\SS j5       r\R                  SS j5       rSS jr	SSS jjr
SSS jjrSS	 jr    S         SS
 jjrS rSU 4S jjrSrU =r$ )PauliEvolutionGate   u  Time-evolution of an operator consisting of Paulis.

For an Hermitian operator :math:`H` consisting of Pauli terms and (real) evolution time :math:`t`
this gate represents the unitary

.. math::

    U(t) = e^{-itH}.

The evolution gates are related to the Pauli rotation gates by a factor of 2. For example
the time evolution of the Pauli :math:`X` operator is connected to the Pauli :math:`X` rotation
:math:`R_X` by

.. math::

    U(t) = e^{-itX} = R_X(2t).

Compilation:

This gate represents the exact evolution :math:`U(t)`. Implementing this operation exactly,
however, generally requires an exponential number of gates. The compiler therefore typically
implements an *approximation* of the unitary :math:`U(t)`, e.g. using a product formula such
as defined by :class:`.LieTrotter`. By passing the ``synthesis`` argument, you can specify
which method the compiler should use, see :mod:`qiskit.synthesis` for the available options.

Note that the order in which the approximation and methods like :meth:`control` and
:meth:`power` are called matters. Changing the order can lead to different unitaries.

Examples:

.. plot::
   :include-source:
   :nofigs:

    from qiskit.circuit import QuantumCircuit
    from qiskit.circuit.library import PauliEvolutionGate
    from qiskit.quantum_info import SparsePauliOp

    X = SparsePauliOp("X")
    Z = SparsePauliOp("Z")
    I = SparsePauliOp("I")

    # build the evolution gate
    operator = (Z ^ Z) - 0.1 * (X ^ I)
    evo = PauliEvolutionGate(operator, time=0.2)

    # plug it into a circuit
    circuit = QuantumCircuit(2)
    circuit.append(evo, range(2))
    print(circuit.draw())

The above will print (note that the ``-0.1`` coefficient is not printed!):

.. code-block:: text

         ┌──────────────────────────┐
    q_0: ┤0                         ├
         │  exp(-it (ZZ + XI))(0.2) │
    q_1: ┤1                         ├
         └──────────────────────────┘


References:

[1] G. Li et al. Paulihedral: A Generalized Block-Wise Compiler Optimization
Framework For Quantum Simulation Kernels (2021).
`arXiv:2109.03371 <https://arxiv.org/abs/2109.03371>`__
c                  > [        U[        5      (       a  U Vs/ s H  n[        U5      PM     nnO[        U5      nUc  [        U5      n[        U[        5      (       aQ  [	        U5      S:X  a  [        S5      eUS   R                  nUSS  H  nUR                  U:w  d  M  [        S5      e   OUR                  n[        TU ]!  SXb/US9  Xl	        Uc  SSK
Jn  U" 5       nX@l        gs  snf )	a  
Args:
    operator: The operator to evolve. Can also be provided as list of non-commuting
        operators where the elements are sums of commuting operators.
        For example: ``[XY + YX, ZZ + ZI + IZ, YY]``.
    time: The evolution time.
    label: A label for the gate to display in visualizations. Per default, the label is
        set to ``exp(-it <operators>)`` where ``<operators>`` is the sum of the Paulis.
        Note that the label does not include any coefficients of the Paulis. See the
        class docstring for an example.
    synthesis: A synthesis strategy. If None, the default synthesis is the Lie-Trotter
        product formula with a single repetition.
Nr   z0The argument 'operator' cannot be an empty list.   zdWhen represented as a list of operators, all of these operators must have the same number of qubits.PauliEvolution)name
num_qubitsparamslabel)
LieTrotter)
isinstancelist_to_sparse_op_get_default_labellen
ValueErrorr   super__init__operatorqiskit.synthesis.evolutionr   	synthesis)	selfr   timer   r!   opr   r   	__class__s	           `/home/james-whalen/.local/lib/python3.13/site-packages/qiskit/circuit/library/pauli_evolution.pyr   PauliEvolutionGate.__init__e   s    2 h%%4<=Hbb)HH=H$X.H=&x0Eh%%8}! !STT!!//Jqrl==J.$?  # ",,J.:f\ab ="I"; >s   C+c                     U R                   S   $ )z^Return the evolution time as stored in the gate parameters.

Returns:
    The evolution time.
r   r   r"   s    r&   r#   PauliEvolutionGate.time   s     {{1~    c                    U/U l         g)z=Set the evolution time.

Args:
    time: The evolution time.
Nr)   )r"   r#   s     r&   r#   r+      s     fr,   c                x   [        U R                  [        5      (       a   U R                  R                  5       nOU R                  n[        U R                  [        5      (       a%  [        U R                  SS U R                  S   S9nOU R                  n[        U[        5      (       a  [        R                  " U5      nUR                  SS9n[        R                  R                  R!                  SU-  U-  5      nUR#                  5       $ ! [         a  n[        SU R                   35      UeSnAff = f)	zReturn the matrix :math:`e^{-it H}` as ``numpy.ndarray``.

Returns:
    The matrix this gate represents.

Raises:
    ValueError: If the ``time`` parameters is not numeric.
z2Cannot compute matrix with non-numeric parameter: Nr   r   )startT)sparsey             )r   r#   r   numeric	TypeErrorr   r   r   sumr
   r	   from_sparse_observable	to_matrixscr0   linalgexpmtoarray)r"   r#   excr   spmatrixexps         r&   r5   PauliEvolutionGate.to_matrix   s
    dii!455yy((* 99D dmmT**4==,DMM!4DEH}}H h 011$;;HEH %%T%2ii##C$J$9: {{}1   HTs   D 
D9D44D9c                V    [        U R                  U R                  * U R                  S9$ )zQReturn the inverse, which is obtained by flipping the sign of the evolution time.r!   r   r   r#   r!   )r"   	annotateds     r&   inversePauliEvolutionGate.inverse   s    !$--$))t~~VVr,   c                Z    [        U R                  U R                  U-  U R                  S9$ )a3  Raise this gate to the power of ``exponent``.

The outcome represents :math:`e^{-i tp H}` where :math:`p` equals ``exponent``.

Args:
    exponent: The power to raise the gate to.
    annotated: Not applicable to this class. Usually, when this is ``True`` we return an
        :class:`.AnnotatedOperation` with a power modifier set instead of a concrete
        :class:`.Gate`. However, we can efficiently represent powers of Pauli evolutions
        as :class:`.PauliEvolutionGate`, which is used here.

Returns:
    An operation implementing ``gate^exponent``.
r?   r@   )r"   exponentrA   s      r&   powerPauliEvolutionGate.power   s'     "$--X1EQUQ_Q_``r,   c                $    U R                  U5      $ N)rF   )r"   rE   s     r&   _return_repeat!PauliEvolutionGate._return_repeat   s    zz(##r,   c                  ^ Uc  SU-  nO][        U[        5      (       a  [        U5      SS R                  U5      nO*[	        U5      U:w  a  [        S[	        U5       SU S35      e[        U5      mU4S jn[        U R                  [        5      (       a"  U R                   Vs/ s H
  oe" U5      PM     nnOU" U R                  5      n[        XpR                  X R                  S9$ s  snf )	a  Return the controlled version of itself.

The outcome is the specified controlled version of :math:`e^{-itH}`.
The returned gate represents :math:`e^{-it H_C}`, where :math:`H_C` is the original
operator :math:`H`, tensored with :math:`|0\rangle\langle 0|` and
:math:`|1\rangle\langle 1|` projectors (depending on the control state).

Args:
    num_ctrl_qubits: Number of controls to add to gate (default: ``1``).
    label: Optional gate label. Ignored if implemented as an annotated
        operation.
    ctrl_state: The control state in decimal or as a bitstring
        (e.g. ``"111"``). If ``None``, use ``2**num_ctrl_qubits - 1``.
    annotated: Not applicable to this class. Usually, when this is ``True`` we return an
        :class:`.AnnotatedOperation` with a control modifier set instead of a concrete
        :class:`.Gate`. However, we can efficiently represent controlled Pauli evolutions
        as :class:`.PauliEvolutionGate`, which is used here.

Returns:
    Controlled version of the given operation.
N1   zLength of ctrl_state (z) must match num_ctrl_qubits ()c                d   > [        U [        5      (       a  [        R                  " U 5      n U T-  $ rI   )r   r	   r
   from_sparse_pauli_op)r$   
control_ops    r&   	extend_op-PauliEvolutionGate.control.<locals>.extend_op#  s*    "m,,%::2>
?"r,   r?   )r   intbinzfillr   r   r
   r   r   r   r#   r!   )	r"   num_ctrl_qubitsr   
ctrl_staterA   rS   r$   r   rR   s	           @r&   controlPauliEvolutionGate.control   s    8 .J
C((Z,22?CJ:/1 ,S_,= >((7'8;  &j1
	# dmmT**04>"	"H>H /H!(IIuWW	 ?s   &C*c                D    U R                   R                  U 5      U l        g)z4Unroll, where the default synthesis is matrix based.N)r!   
synthesize
definitionr*   s    r&   _definePauliEvolutionGate._define0  s    ..33D9r,   c                b   > [        U[        5      (       a  [        U5      n[        TU ]  U5      $ )z<Gate parameters should be int, float, or ParameterExpression)r   rU   floatr   validate_parameter)r"   	parameterr%   s     r&   rc   %PauliEvolutionGate.validate_parameter4  s*    i%%i(Iw))44r,   )r^   r   r   r!   )g      ?NN)
r   zqiskit.quantum_info.Pauli | SparsePauliOp | SparseObservable | list[qiskit.quantum_info.Pauli | SparsePauliOp | SparseObservable]r#   r   r   
str | Noner!   zEvolutionSynthesis | NonereturnNone)rg   r   )r#   r   rg   rh   )rg   z
np.ndarray)F)rA   bool)rE   rb   rA   ri   rg   r   )rE   rb   rg   r   )r   NNN)
rX   rU   r   rf   rY   zint | str | NonerA   zbool | Nonerg   r   )rd   r   rg   r   )__name__
__module____qualname____firstlineno____doc__r   propertyr#   setterr5   rB   rF   rJ   rZ   r_   rc   __static_attributes____classcell__)r%   s   @r&   r   r      s    CZ $' /37#Q7# !7# 7# -7# 
7# 7#r   
[[ %PW
a"$  ! '+!%<X<X <X %	<X
 <X 
<X|:5 5r,   r   c                ~   [        U [        5      (       a  [        U 5      nO6[        U [        [        45      (       a  U nO[	        S[        U 5       S35      e[        [        R                  " UR                  5      5      (       a  [	        S5      e[        S UR                   5       5      (       a  [	        S5      eU$ )z%Cast the operator to a SparsePauliOp.z)Unsupported operator type for evolution: .z@Operator contains complex coefficients, which are not supported.c              3  B   #    U  H  n[        U[        5      v   M     g 7frI   )r   r   ).0coeffs     r&   	<genexpr> _to_sparse_op.<locals>.<genexpr>J  s     
M}e:e011}s   z?Operator contains ParameterExpression, which are not supported.)
r   r   r	   r
   r   typeanynp	iscomplexcoeffs)r   r0   s     r&   r   r   <  s    
 (E""x(	H/?	@	@DT(^DTTUVWW
2<<&''[\\

Mv}}
MMMZ[[Mr,   c                   [        U [        5      (       aF  [        U 5      S:X  a  U S   R                  5       S S S2   $ SSR	                  S U  5       5      -   S-   $ [        U R
                  5      S:X  a  U R
                  R                  5       S   $ SSR	                  U R
                  R                  5       5      -   S-   $ )Nr   r   (z + c              3  L   #    U  H  oR                  5       S S S2   v   M     g 7f)Nr   )
bit_labels)rv   terms     r&   rx   "_operator_label.<locals>.<genexpr>T  s     MHD 1$B$ 7Hs   "$rO   )r   r
   r   r   joinpaulis	to_labels)r   s    r&   _operator_labelr   P  s    (,--x=AA;))+DbD11UZZMHMMMPSSS 8??q ((*1--HOO557883>>r,   c                    [        U [        5      (       a   SU  Vs/ s H  n[        U5      PM     sn S3$ S[        U 5       S3$ s  snf )Nz	exp(-it (z))zexp(-it rO   )r   r   r   )r   r$   s     r&   r   r   \  sN    (D!!(C(BOB/(CDBGGoh/022 Ds   A)r   z(Pauli | SparsePauliOp | SparseObservablerg   z SparsePauliOp | SparseObservable)rn   
__future__r   typingr   numpyr|   scipyr6   qiskit.circuit.gater   qiskit.circuit.quantumcircuitr   "qiskit.circuit.parameterexpressionr   qiskit.quantum_infor   r	   r
   qiskitr    r   r   r   r   r    r,   r&   <module>r      s\    7 "     $ < B F F =Z5 Z5z6%(	?3r,   