§
    OŠtjJ%  ã                   óÞ   — 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!dS )é    )Úproduct)ÚAdd)ÚTuple)Úexpand)ÚMul)ÚS©Úlog)ÚMutableDenseMatrix©Ú
prettyForm)ÚDagger)ÚHermitianOperator)Ú	represent)Únumpy_ndarrayÚscipy_sparse_matrixÚto_numpy)ÚTrc                   óz   ‡ — 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 ]9}t          |t          ¦  «        rt	          |¦  «        dk    s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      €ú[/var/www/html/CA-Chatbot/venv/lib/python3.11/site-packages/sympy/physics/quantum/density.pyr   zDensity._eval_args)   sn   ø€ õ ‰wŒw×!Ò! $Ñ'Ô'ˆàð 	8ð 	8ˆCå˜s¥EÑ*Ô*ð 8­s°3©x¬x¸1ª}¨}Ý ð "7ñ 8ô 8ð 8ð 0=ð ˆó    c                 ó2   — t          d„ | j        D ¦   «         Ž S )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>)

        c                 ó   — g | ]
}|d          ‘ŒS )r   © ©Ú.0r    s     r"   ú
<listcomp>z"Density.states.<locals>.<listcomp>C   ó   € Ð3Ð3Ð3 #�s˜1”vÐ3Ð3Ð3r#   ©r   r   ©Úselfs    r"   ÚstateszDensity.states6   ó    € õ Ð3Ð3¨¬Ð3Ñ3Ô3Ð4Ð4r#   c                 ó2   — t          d„ | j        D ¦   «         Ž S )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)

        c                 ó   — g | ]
}|d          ‘ŒS )é   r&   r'   s     r"   r)   z!Density.probs.<locals>.<listcomp>R   r*   r#   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

        r2   r5   )r-   r6   Úprobs      r"   Úget_probzDensity.get_probi   s   € ð$ Œy˜Ô Ô"ˆØˆr#   c                 ó<   ‡— ˆfd„| j         D ¦   «         }t          |Ž S )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))

        c                 ó$   •— g | ]\  }}‰|z  |f‘ŒS r&   r&   )r(   r7   r:   Úops      €r"   r)   z$Density.apply_op.<locals>.<listcomp>’   s&   ø€ ÐDÐDÐD©¨%°�R˜‘X˜tÐ$ÐDÐDÐDr#   )r   r   )r-   r>   Únew_argss    ` r"   Úapply_opzDensity.apply_op~   s,   ø€ ð( EÐDÐDÐD¸$¼)ÐDÑDÔDˆÝ˜Ð!Ð!r#   c           
      ó€  — g }| j         D ]¬\  }}|                     ¦   «         }t          |t          ¦  «        rRt	          |j         d¬¦  «        D ]:}|                     ||                      |d         |d         ¦  «        z  ¦  «         Œ;Œ€|                     ||                      ||¦  «        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   r2   )r   r   r   r   r   ÚappendÚ_generate_outer_prod)r-   ÚhintsÚtermsr7   r:   r    s         r"   ÚdoitzDensity.doit•   sä   € ð  ˆØ!œYð 	Kð 	K‰MˆU�DØ—L’L‘N”NˆEÝ˜5¥#Ñ&Ô&ð KÝ" 5¤:°aÐ8Ñ8Ô8ð Ið I�CØ—L’L  d×&?Ò&?ÀÀAÄØ@CÀAÄñ'Hô 'Hñ "Hñ Iô Ið Ið IðIð —’˜T $×";Ò";¸EÀ5Ñ"IÔ"IÑIÑJÔJÐJÐJå�Eˆ{Ðr#   c                 ó4  — |                      ¦   «         \  }}|                      ¦   «         \  }}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_part2r>   s           r"   rD   zDensity._generate_outer_prod±   s’   € Ø ŸMšM™OœOÑˆ�Ø ŸMšM™OœOÑˆ�å�‰MŒM˜QÒÐ¥# h¡-¤-°1Ò"4Ð"4Ýð 3ñ 4ô 4ð 4õ �(ˆ^�F¥3¨ >Ñ2Ô2Ñ2ˆå�Gˆ}�S '˜]Ñ*¨RÑ/Ð/r#   c                 ó@   — t          |                      ¦   «         fi |¤ŽS ©N)r   rG   )r-   Úoptionss     r"   Ú
_representzDensity._representÁ   s    € Ý˜Ÿš™œÐ0Ð0¨Ð0Ð0Ð0r#   c                 ó   — dS )Nz\rhor&   ©r-   Úprinterr   s      r"   Ú_print_operator_name_latexz"Density._print_operator_name_latexÄ   s   € Øˆwr#   c                 ó    — t          d¦  «        S )Nu   Ï�r   rU   s      r"   Ú_print_operator_name_prettyz#Density._print_operator_name_prettyÇ   s   € ÝÐ6Ñ7Ô7Ð7r#   c                 ó–   — |                      dg ¦  «        }t          |                      ¦   «         |¦  «                             ¦   «         S )NÚindices)Úgetr   rG   )r-   Úkwargsr[   s      r"   Ú_eval_tracezDensity._eval_traceÊ   s9   € Ø—*’*˜Y¨Ñ+Ô+ˆÝ�$—)’)‘+”+˜wÑ'Ô'×,Ò,Ñ.Ô.Ð.r#   c                 ó    — t          | ¦  «        S )zl Compute the entropy of a density matrix.

        Refer to density.entropy() method  for examples.
        )Úentropyr,   s    r"   r`   zDensity.entropyÎ   s   € õ
 �t‰}Œ}Ðr#   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__Úclassmethodr   r.   r3   r8   r;   r@   rG   rD   rS   rW   rY   r^   r`   Ú__classcell__)r!   s   @r"   r   r      s  ø€ € € € € ðð ð, ð
ð 
ð 
ð 
ñ „[ð
ð5ð 5ð 5ð5ð 5ð 5ðð ð ð*ð ð ð*"ð "ð "ð.ð ð ð80ð 0ð 0ð 1ð 1ð 1ðð ð ð8ð 8ð 8ð/ð /ð /ðð ð ð ð ð ð r#   r   c                 ó2  — t          | t          ¦  «        rt          | ¦  «        } t          | t          ¦  «        rt	          | ¦  «        } t          | t
          ¦  «        rM|                      ¦   «                              ¦   «         }t          t          d„ |D ¦   «         ¦  «         ¦  «        S t          | t          ¦  «        rJddl}|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   ó:   K  — | ]}|t          |¦  «        z  V — Œd S rQ   r	   )r(   Úes     r"   ú	<genexpr>zentropy.<locals>.<genexpr>ø   s,   è è € Ð5Ð5¨˜1�S ™VœV™8Ð5Ð5Ð5Ð5Ð5Ð5r#   r   Nz4numpy.ndarray, scipy.sparse or SymPy matrix expected)r   r   r   r   r   ÚMatrixÚ	eigenvalsÚkeysr   Úsumr   ÚnumpyÚlinalgÚeigvalsr
   r   )Údensityrq   Únps      r"   r`   r`   Ö   s  € õ4 �'�7Ñ#Ô#ð %Ý˜GÑ$Ô$ˆå�'Õ.Ñ/Ô/ð $Ý˜7Ñ#Ô#ˆå�'�6Ñ"Ô"ð 	DØ×#Ò#Ñ%Ô%×*Ò*Ñ,Ô,ˆÝ•sÐ5Ð5¨WÐ5Ñ5Ô5Ñ5Ô5Ð5Ñ6Ô6Ð6Ý	�G�]Ñ	+Ô	+ð DØÐÐÐØ”)×#Ò# GÑ,Ô,ˆØ—’�w˜rŸvšv g™œÑ.Ñ/Ô/Ð/Ð/åØBñDô Dð 	Dr#   c                 ó   — t          | t          ¦  «        rt          | ¦  «        n| } t          |t          ¦  «        rt          |¦  «        n|}t          | t          ¦  «        rt          |t          ¦  «        s0t	          dt          | ¦  «        ›dt          |¦  «        ›d�¦  «        ‚| j        |j        k    r| j        rt	          d¦  «        ‚| t          j	        z  }t          ||z  |z  t          j	        z  ¦  «                             ¦   «         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   rk   r   ÚtypeÚshapeÚ	is_squarer   ÚHalfr   rG   )Ústate1Ústate2Úsqrt_state1s      r"   Úfidelityr|     s  € õX #-¨VµWÑ"=Ô"=ÐI�Y�vÑÔÐÀ6€FÝ",¨VµWÑ"=Ô"=ÐI�Y�vÑÔÐÀ6€Få�f�fÑ%Ô%ð 7­Z¸ÅÑ-GÔ-Gð 7Ýˆjå˜v™,œ,˜,˜,­¨V©¬¨¨ð6ñ 7ô 7ð 	7ð „|�v”|Ò#Ð#¨Ô(8Ð#Ýð Eñ Fô Fð 	Fð �!œ&‘.€KÝˆ{˜6Ñ! +Ñ-µ´Ñ6Ñ7Ô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   rk   Ú 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   r`   r|   r&   r#   r"   ú<module>r‹      sm  ðØ Ð Ð Ð Ð Ð à Ð Ð Ð Ð Ð Ø 'Ð 'Ð 'Ð 'Ð 'Ð 'Ø &Ð &Ð &Ð &Ð &Ð &Ø Ð Ð Ð Ð Ð Ø "Ð "Ð "Ð "Ð "Ð "Ø 6Ð 6Ð 6Ð 6Ð 6Ð 6Ø =Ð =Ð =Ð =Ð =Ð =Ø 7Ð 7Ð 7Ð 7Ð 7Ð 7Ø /Ð /Ð /Ð /Ð /Ð /Ø <Ð <Ð <Ð <Ð <Ð <Ø 5Ð 5Ð 5Ð 5Ð 5Ð 5Ø ZÐ ZÐ ZÐ ZÐ ZÐ ZÐ ZÐ ZÐ ZÐ ZØ *Ð *Ð *Ð *Ð *Ð *ðAð Að Að Að AÐñ Aô Að AðH)Dð )Dð )DðX9?ð 9?ð 9?ð 9?ð 9?r#   