§
    ^²Åj&  ã                   óî   — 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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)ÚTensorProductÚtensor_product_simp)Ú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      €úNC:\Projects\Historical\venv\Lib\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>D   ó   € Ð3Ð3Ð3 #�s˜1”vÐ3Ð3Ð3r%   ©r   r!   ©Úselfs    r$   ÚstateszDensity.states7   ó    € õ Ð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>S   r,   r%   r-   r.   s    r$   ÚprobszDensity.probsF   r1   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_stateU   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

        r4   r7   )r/   r8   Úprobs      r$   Úget_probzDensity.get_probj   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*   r9   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   r4   )r!   r   r   r   r   ÚappendÚ_generate_outer_prod)r/   ÚhintsÚtermsr9   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                 ó  — |                      ¦   «         \  }}|                      ¦   «         \  }}t          |¦  «        dk    st          |¦  «        dk    rt          d¦  «        ‚t          |d         t          ¦  «        rRt          |¦  «        dk    r?t          |¦  «        dk    r,t          |d         t          |d         ¦  «        z  ¦  «        }n t          |Ž t          t          |Ž ¦  «        z  }t          |Ž t          |Ž z  |z  S )Nr   zHAtleast one-pair of Non-commutative instance required for outer product.r4   )Úargs_cncr   r   r   r   r   r   r   )r/   Úarg1Úarg2Úc_part1Únc_part1Úc_part2Únc_part2r@   s           r$   rF   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õ �x ”{¥MÑ2Ô2ð 	7µs¸8±}´}ÈÒ7IÐ7IÝ˜‘M”M QÒ&Ð&Ý$ X¨a¤[µ¸À¼Ñ1DÔ1DÑ%DÑEÔEˆBˆBå�h�¥¥s¨H ~Ñ 6Ô 6Ñ6ˆBå�Gˆ}�S '˜]Ñ*¨RÑ/Ð/r%   c                 ó@   — t          |                      ¦   «         fi |¤ŽS ©N)r   rI   )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   rW   s      r$   Ú_print_operator_name_prettyz#Density._print_operator_name_prettyË   s   € ÝÐ6Ñ7Ô7Ð7r%   c                 ó–   — |                      dg ¦  «        }t          |                      ¦   «         |¦  «                             ¦   «         S )NÚindices)Úgetr   rI   )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$   rb   zDensity.entropyÒ   s   € õ
 �t‰}Œ}Ðr%   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__Úclassmethodr   r0   r5   r:   r=   rB   rI   rF   rU   rY   r[   r`   rb   Ú__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 rS   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   )Údensityrs   Únps      r$   rb   rb   Ú   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   rm   r   ÚtypeÚshapeÚ	is_squarer   ÚHalfr   rI   )Ú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   rm   Ú 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.tensorproductr   r   Úsympy.physics.quantum.tracer   r   rb   r~   r(   r%   r$   ú<module>rŽ      s…  ðØ Ð Ð Ð Ð Ð à Ð Ð Ð Ð Ð Ø 'Ð 'Ð 'Ð 'Ð 'Ð 'Ø &Ð &Ð &Ð &Ð &Ð &Ø Ð Ð Ð Ð Ð Ø "Ð "Ð "Ð "Ð "Ð "Ø 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Ø RÐ RÐ RÐ RÐ RÐ RÐ RÐ RØ *Ð *Ð *Ð *Ð *Ð *ðDð Dð Dð Dð DÐñ Dô Dð DðN)Dð )Dð )DðX9?ð 9?ð 9?ð 9?ð 9?r%   