
    sg&                         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$y)    )product)Add)Tuple)expand)Mul)Slog)MutableDenseMatrix
prettyForm)Dagger)HermitianOperator)	represent)numpy_ndarrayscipy_sparse_matrixto_numpy)TensorProducttensor_product_simp)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      P/var/www/html/venv/lib/python3.12/site-packages/sympy/physics/quantum/density.pyr   zDensity._eval_args*   sP     w!$' 	8CsE*s3x1}  "7 8 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.states7   %     3#s1v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.probsF   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_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

        r.   r1   )r)   r2   probs      r$   get_probzDensity.get_probj   s    $ yy"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)   opr3   r6   new_argss        r$   apply_opzDensity.apply_op   s9    ( ;?))D%RXt$D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termsr3   r6   r"   s         r$   doitzDensity.doit   s      !YY 	KMUDLLNE5#&"5::a8 ICLLd&?&?A@CA'H "H II T$";";E5"IIJ	K E{r%   c                    |j                         \  }}|j                         \  }}t        |      dk(  st        |      dk(  rt        d      t        |d   t              r:t        |      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.r.   )args_cncr   r   r   r   r   r   r   )r)   arg1arg2c_part1nc_part1c_part2nc_part2r9   s           r$   r?   zDensity._generate_outer_prod   s     MMO MMOMQ#h-1"4 3 4 4 x{M2s8}7IMQ&$Xa[1D%DEBhsH~ 66BG}S']*R//r%   c                 6    t        | j                         fi |S N)r   rB   )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   rQ   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   rB   )r)   kwargsrW   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$   r\   zDensity.entropy   s    
 t}r%   )__name__
__module____qualname____doc__classmethodr   r*   r/   r4   r7   r;   rB   r?   rN   rS   rU   rZ   r\   __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rL   r	   ).0es     r$   	<genexpr>zentropy.<locals>.<genexpr>   s     51SV85s   r   Nz4numpy.ndarray, scipy.sparse or SymPy matrix expected)r   r   r   r   r   Matrix	eigenvalskeysr   sumr   numpylinalgeigvalsr
   r   )densityrn   nps      r$   r\   r\      s    4 '7#G$'./7#'6"##%**,s5W55566	G]	+))##G,wrvvg.///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   rh   r   typeshape	is_squarer   Halfr   rB   )state1state2sqrt_state1s      r$   fidelityry     s    X #-VW"=Yv6F",VW"=Yv6Fff%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   rh    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   r\   ry   rP   r%   r$   <module>r      sQ      ' &  " 6 = 7 / < 5 Z Z R *D DN)DX9?r%   