Ë
    täiJ%  ã                   óÖ   — d dl mZ d dlmZ d dlmZ d dlmZ d dlm	Z	 d dl
mZ d dlmZ d dlmZ d d	lmZ d d
lmZ d dlmZ d dlmZ d dlmZmZmZ d dlmZ  G d„ de«      Zd„ Z d„ Z!y)é    )Úproduct)ÚAdd)ÚTuple)Úexpand)ÚMul)ÚS©Úlog)ÚMutableDenseMatrix©Ú
prettyForm)ÚDagger)ÚHermitianOperator)Ú	represent)Únumpy_ndarrayÚscipy_sparse_matrixÚto_numpy)ÚTrc                   ót   ‡ — e Zd ZdZeˆ fd„«       Zd„ Zd„ Zd„ Zd„ Z	d„ Z
d„ Zd	„ Zd
„ Zd„ Zd„ Zd„ Zd„ Zˆ xZS )ÚDensitya  Density operator for representing mixed states.

    TODO: Density operator support for Qubits

    Parameters
    ==========

    values : tuples/lists
    Each tuple/list should be of form (state, prob) or [state,prob]

    Examples
    ========

    Create a density operator with 2 states represented by Kets.

    >>> from sympy.physics.quantum.state import Ket
    >>> from sympy.physics.quantum.density import Density
    >>> d = Density([Ket(0), 0.5], [Ket(1),0.5])
    >>> d
    Density((|0>, 0.5),(|1>, 0.5))

    c                 ó†   •— t         ‰| �  |«      }|D ]+  }t        |t        «      rt	        |«      dk(  rŒ"t        d«      ‚ |S )Né   z?Each argument should be of form [state,prob] or ( state, prob ))ÚsuperÚ
_eval_argsÚ
isinstancer   ÚlenÚ
ValueError)ÚclsÚargsÚargÚ	__class__s      €úl/Volumes/fast/ai/experiments/MLX_z-image/.venv/lib/python3.12/site-packages/sympy/physics/quantum/density.pyr   zDensity._eval_args)   sK   ø€ ô ‰wÑ! $Ó'ˆãˆCä˜s¤EÔ*¬s°3«x¸1«}Ü ð "7ó 8ð 8ð ð ˆó    c                 óR   — t        | j                  D �cg c]  }|d   ‘Œ	 c}Ž S c c}w )a  Return list of all states.

        Examples
        ========

        >>> from sympy.physics.quantum.state import Ket
        >>> from sympy.physics.quantum.density import Density
        >>> d = Density([Ket(0), 0.5], [Ket(1),0.5])
        >>> d.states()
        (|0>, |1>)

        r   ©r   r   ©Úselfr    s     r"   ÚstateszDensity.states6   ó)   € ô ¨¯ªÓ3© #�s˜1“v¨Ñ3Ð4Ð4ùÒ3ó   ”$c                 óR   — t        | j                  D �cg c]  }|d   ‘Œ	 c}Ž S c c}w )a#  Return list of all probabilities.

        Examples
        ========

        >>> from sympy.physics.quantum.state import Ket
        >>> from sympy.physics.quantum.density import Density
        >>> d = Density([Ket(0), 0.5], [Ket(1),0.5])
        >>> d.probs()
        (0.5, 0.5)

        é   r%   r&   s     r"   ÚprobszDensity.probsE   r)   r*   c                 ó*   — | j                   |   d   }|S )at  Return specific state by index.

        Parameters
        ==========

        index : index of state to be returned

        Examples
        ========

        >>> from sympy.physics.quantum.state import Ket
        >>> from sympy.physics.quantum.density import Density
        >>> d = Density([Ket(0), 0.5], [Ket(1),0.5])
        >>> d.states()[1]
        |1>

        r   ©r   )r'   ÚindexÚstates      r"   Ú	get_statezDensity.get_stateT   s   € ð$ —	‘	˜%Ñ  Ñ#ˆØˆr#   c                 ó*   — | j                   |   d   }|S )a¢  Return probability of specific state by index.

        Parameters
        ===========

        index : index of states whose probability is returned.

        Examples
        ========

        >>> from sympy.physics.quantum.state import Ket
        >>> from sympy.physics.quantum.density import Density
        >>> d = Density([Ket(0), 0.5], [Ket(1),0.5])
        >>> d.probs()[1]
        0.500000000000000

        r,   r/   )r'   r0   Úprobs      r"   Úget_probzDensity.get_probi   s   € ð$ �y‰y˜Ñ Ñ"ˆØˆr#   c                 ód   — | j                   D ��cg c]  \  }}||z  |f‘Œ }}}t        |Ž S c c}}w )aã  op will operate on each individual state.

        Parameters
        ==========

        op : Operator

        Examples
        ========

        >>> from sympy.physics.quantum.state import Ket
        >>> from sympy.physics.quantum.density import Density
        >>> from sympy.physics.quantum.operator import Operator
        >>> A = Operator('A')
        >>> d = Density([Ket(0), 0.5], [Ket(1),0.5])
        >>> d.apply_op(A)
        Density((A*|0>, 0.5),(A*|1>, 0.5))

        )r   r   )r'   Úopr1   r4   Únew_argss        r"   Úapply_opzDensity.apply_op~   s:   € ð( ;?¿)º)ÔD¹)©¨%°�R˜‘X˜tÒ$¸)ˆÑDÜ˜Ð!Ð!ùó Es   �,c           
      óT  — g }| j                   D ]�  \  }}|j                  «       }t        |t        «      rGt	        |j                   d¬«      D ],  }|j                  || j                  |d   |d   «      z  «       Œ. Œm|j                  || j                  ||«      z  «       Œ’ t        |Ž S )a¥  Expand the density operator into an outer product format.

        Examples
        ========

        >>> from sympy.physics.quantum.state import Ket
        >>> from sympy.physics.quantum.density import Density
        >>> from sympy.physics.quantum.operator import Operator
        >>> A = Operator('A')
        >>> d = Density([Ket(0), 0.5], [Ket(1),0.5])
        >>> d.doit()
        0.5*|0><0| + 0.5*|1><1|

        r   )Úrepeatr   r,   )r   r   r   r   r   ÚappendÚ_generate_outer_prod)r'   ÚhintsÚtermsr1   r4   r    s         r"   ÚdoitzDensity.doit•   s¡   € ð  ˆØ!ŸYœY‰MˆU�DØ—L‘L“NˆEÜ˜5¤#Ô&Ü" 5§:¡:°a×8�CØ—L‘L  d×&?Ñ&?ÀÀAÁØ@CÀAÁó'Hñ "Hõ Iñ 9ð —‘˜T $×";Ñ";¸EÀ5Ó"IÑIÕJð 'ô �Eˆ{Ðr#   c                 óø   — |j                  «       \  }}|j                  «       \  }}t        |«      dk(  st        |«      dk(  rt        d«      ‚t        |Ž t	        t        |Ž «      z  }t        |Ž t        |Ž z  |z  S )Nr   zHAtleast one-pair of Non-commutative instance required for outer product.)Úargs_cncr   r   r   r   )r'   Úarg1Úarg2Úc_part1Únc_part1Úc_part2Únc_part2r7   s           r"   r=   zDensity._generate_outer_prod±   s|   € Ø ŸM™M›OÑˆ�Ø ŸM™M›OÑˆ�ä�‹M˜QÒ¤# h£-°1Ò"4Üð 3ó 4ð 4ô �(ˆ^œF¤3¨ >Ó2Ñ2ˆä�Gˆ}œS '˜]Ñ*¨RÑ/Ð/r#   c                 ó6   — t        | j                  «       fi |¤ŽS ©N)r   r@   )r'   Úoptionss     r"   Ú
_representzDensity._representÁ   s   € Ü˜Ÿ™›Ñ0¨Ñ0Ð0r#   c                  ó   — y)Nz\rho© ©r'   Úprinterr   s      r"   Ú_print_operator_name_latexz"Density._print_operator_name_latexÄ   s   € Ør#   c                 ó   — t        d«      S )Nu   Ï�r   rO   s      r"   Ú_print_operator_name_prettyz#Density._print_operator_name_prettyÇ   s   € ÜÐ6Ó7Ð7r#   c                 óv   — |j                  dg «      }t        | j                  «       |«      j                  «       S )NÚindices)Úgetr   r@   )r'   ÚkwargsrU   s      r"   Ú_eval_tracezDensity._eval_traceÊ   s.   € Ø—*‘*˜Y¨Ó+ˆÜ�$—)‘)“+˜wÓ'×,Ñ,Ó.Ð.r#   c                 ó   — t        | «      S )zl Compute the entropy of a density matrix.

        Refer to density.entropy() method  for examples.
        )Úentropy)r'   s    r"   rZ   zDensity.entropyÎ   s   € ô
 �t‹}Ðr#   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__Úclassmethodr   r(   r-   r2   r5   r9   r@   r=   rL   rQ   rS   rX   rZ   Ú__classcell__)r!   s   @r"   r   r      sX   ø„ ñð, ó
ó ð
ò5ò5òò*ò*"ò.ò80ò 1òò8ò/ör#   r   c                 ó¾  — t        | t        «      rt        | «      } t        | t        «      rt	        | «      } t        | t
        «      r:| j                  «       j                  «       }t        t        d„ |D «       «       «      S t        | t        «      rCddl}|j                  j                  | «      }|j                  ||j                  |«      z  «       S t        d«      ‚)aÃ  Compute the entropy of a matrix/density object.

    This computes -Tr(density*ln(density)) using the eigenvalue decomposition
    of density, which is given as either a Density instance or a matrix
    (numpy.ndarray, sympy.Matrix or scipy.sparse).

    Parameters
    ==========

    density : density matrix of type Density, SymPy matrix,
    scipy.sparse or numpy.ndarray

    Examples
    ========

    >>> from sympy.physics.quantum.density import Density, entropy
    >>> from sympy.physics.quantum.spin import JzKet
    >>> from sympy import S
    >>> up = JzKet(S(1)/2,S(1)/2)
    >>> down = JzKet(S(1)/2,-S(1)/2)
    >>> d = Density((up,S(1)/2),(down,S(1)/2))
    >>> entropy(d)
    log(2)/2

    c              3   ó8   K  — | ]  }|t        |«      z  –— Œ y ­wrJ   r	   )Ú.0Úes     r"   Ú	<genexpr>zentropy.<locals>.<genexpr>ø   s   è ø€ Ð5©W¨˜1œS ›V�8©Wùs   ‚r   Nz4numpy.ndarray, scipy.sparse or SymPy matrix expected)r   r   r   r   r   ÚMatrixÚ	eigenvalsÚkeysr   Úsumr   ÚnumpyÚlinalgÚeigvalsr
   r   )Údensityrl   Únps      r"   rZ   rZ   Ö   s¹   € ô4 �'œ7Ô#Ü˜GÓ$ˆä�'Ô.Ô/Ü˜7Ó#ˆä�'œ6Ô"Ø×#Ñ#Ó%×*Ñ*Ó,ˆÜ”sÑ5©WÓ5Ó5Ð5Ó6Ð6Ü	�Gœ]Ô	+ÛØ—)‘)×#Ñ# GÓ,ˆØ—‘�w˜rŸv™v g›Ñ.Ó/Ð/Ð/äØBóDð 	Dr#   c                 óä  — t        | t        «      rt        | «      n| } t        |t        «      rt        |«      n|}t        | t        «      rt        |t        «      s$t	        dt        | «      ›dt        |«      ›d�«      ‚| j                  |j                  k7  r| j                  rt	        d«      ‚| t        j                  z  }t        ||z  |z  t        j                  z  «      j                  «       S )a¨   Computes the fidelity [1]_ between two quantum states

    The arguments provided to this function should be a square matrix or a
    Density object. If it is a square matrix, it is assumed to be diagonalizable.

    Parameters
    ==========

    state1, state2 : a density matrix or Matrix


    Examples
    ========

    >>> from sympy import S, sqrt
    >>> from sympy.physics.quantum.dagger import Dagger
    >>> from sympy.physics.quantum.spin import JzKet
    >>> from sympy.physics.quantum.density import fidelity
    >>> from sympy.physics.quantum.represent import represent
    >>>
    >>> up = JzKet(S(1)/2,S(1)/2)
    >>> down = JzKet(S(1)/2,-S(1)/2)
    >>> amp = 1/sqrt(2)
    >>> updown = (amp*up) + (amp*down)
    >>>
    >>> # represent turns Kets into matrices
    >>> up_dm = represent(up*Dagger(up))
    >>> down_dm = represent(down*Dagger(down))
    >>> updown_dm = represent(updown*Dagger(updown))
    >>>
    >>> fidelity(up_dm, up_dm)
    1
    >>> fidelity(up_dm, down_dm) #orthogonal states
    0
    >>> fidelity(up_dm, updown_dm).evalf().round(3)
    0.707

    References
    ==========

    .. [1] https://en.wikipedia.org/wiki/Fidelity_of_quantum_states

    zBstate1 and state2 must be of type Density or Matrix received type=z for state1 and type=z for state2z]The dimensions of both args should be equal and the matrix obtained should be a square matrix)r   r   r   rf   r   ÚtypeÚshapeÚ	is_squarer   ÚHalfr   r@   )Ústate1Ústate2Úsqrt_state1s      r"   Úfidelityrw     sÆ   € ôX #-¨V´WÔ"=ŒY�vÔÀ6€FÜ",¨V´WÔ"=ŒY�vÔÀ6€Fä�fœfÔ%¬Z¸ÄÔ-GÝä˜v�,¬¨V­ð6ó 7ð 	7ð ‡|�|�v—|‘|Ò#¨×(8Ò(8Üð Eó Fð 	Fð œ!Ÿ&™&‘.€KÜˆ{˜6Ñ! +Ñ-´·±Ñ6Ó7×<Ñ<Ó>Ð>r#   N)"Ú	itertoolsr   Úsympy.core.addr   Úsympy.core.containersr   Úsympy.core.functionr   Úsympy.core.mulr   Úsympy.core.singletonr   Ú&sympy.functions.elementary.exponentialr
   Úsympy.matrices.denser   rf   Ú sympy.printing.pretty.stringpictr   Úsympy.physics.quantum.daggerr   Úsympy.physics.quantum.operatorr   Úsympy.physics.quantum.representr   Ú!sympy.physics.quantum.matrixutilsr   r   r   Úsympy.physics.quantum.tracer   r   rZ   rw   rN   r#   r"   Ú<module>r†      sN   ðÝ å Ý 'Ý &Ý Ý "Ý 6Ý =Ý 7Ý /Ý <Ý 5ß ZÑ ZÝ *ôAÐô AòH)DóX9?r#   