o
    jg&                     @   s   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 deZ"dd Z#d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                       s   e Zd ZdZe fddZdd Zdd Zdd	 Zd
d Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Z  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                    s8   t  |}|D ]}t|trt|dkstdq|S )N   z?Each argument should be of form [state,prob] or ( state, prob ))super
_eval_args
isinstancer   len
ValueError)clsargsarg	__class__ U/var/www/html/zoom/venv/lib/python3.10/site-packages/sympy/physics/quantum/density.pyr   *   s   zDensity._eval_argsc                 C      t d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                 S      g | ]}|d  qS )r   r"   .0r   r"   r"   r#   
<listcomp>D       z"Density.states.<locals>.<listcomp>r   r   selfr"   r"   r#   states7      zDensity.statesc                 C   r$   )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                 S   r%   )   r"   r&   r"   r"   r#   r(   S   r)   z!Density.probs.<locals>.<listcomp>r*   r+   r"   r"   r#   probsF   r.   zDensity.probsc                 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stater"   r"   r#   	get_stateU      zDensity.get_statec                 C   r1   )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/   r2   )r,   r3   probr"   r"   r#   get_probj   r6   zDensity.get_probc                    s    fd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                    s   g | ]
\}} | |fqS r"   r"   )r'   r4   r7   opr"   r#   r(      s    z$Density.apply_op.<locals>.<listcomp>)r   r   )r,   r:   new_argsr"   r9   r#   apply_op   s   zDensity.apply_opc              
   K   sx   g }| j D ]2\}}| }t|tr,t|j ddD ]}||| |d |d   qq||| ||  q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termsr4   r7   r   r"   r"   r#   doit   s   

zDensity.doitc                 C   s   |  \}}|  \}}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  }n
t| tt|  }t| t|  | 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_part2r:   r"   r"   r#   r?      s   zDensity._generate_outer_prodc                 K   s   t |  fi |S N)r   rB   )r,   optionsr"   r"   r#   
_represent   s   zDensity._representc                 G   s   dS )Nz\rhor"   r,   printerr   r"   r"   r#   _print_operator_name_latex   s   z"Density._print_operator_name_latexc                 G   s   t dS )Nu   ρr   rM   r"   r"   r#   _print_operator_name_pretty   s   z#Density._print_operator_name_prettyc                 K   s   | dg }t|  | S )Nindices)getr   rB   )r,   kwargsrQ   r"   r"   r#   _eval_trace   s   zDensity._eval_tracec                 C   s   t | S )zl Compute the entropy of a density matrix.

        Refer to density.entropy() method  for examples.
        )entropyr+   r"   r"   r#   rU      s   zDensity.entropy)__name__
__module____qualname____doc__classmethodr   r-   r0   r5   r8   r<   rB   r?   rL   rO   rP   rT   rU   __classcell__r"   r"   r    r#   r      s     r   c                 C   s   t | tr	t| } t | trt| } t | tr)|   }tt	dd |D  S t | t
rCddl}|j| }|	|||  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                 s   s    | ]	}|t | V  qd S rJ   r   )r'   er"   r"   r#   	<genexpr>   s    zentropy.<locals>.<genexpr>r   Nz4numpy.ndarray, scipy.sparse or SymPy matrix expected)r   r   r   r   r   Matrix	eigenvalskeysr   sumr   numpylinalgeigvalsr	   r   )densityrd   npr"   r"   r#   rU      s   



rU   c                 C   s   t | tr	t| n| } t |trt|n|}t | tr t |ts,tdt| t|f | j|jkr9| jr9td| tj	 }t
|| | t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

    zfstate1 and state2 must be of type Density or Matrix received type=%s for state1 and type=%s for state2z]The dimensions of both args should be equal and the matrix obtained should be a square matrix)r   r   r   r^   r   typeshape	is_squarer   Halfr   rB   )state1state2sqrt_state1r"   r"   r#   fidelity  s   ,
rn   N)%	itertoolsr   sympy.core.addr   sympy.core.containersr   sympy.core.functionr   sympy.core.mulr   sympy.core.singletonr   &sympy.functions.elementary.exponentialr	   sympy.matrices.denser
   r^    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   rU   rn   r"   r"   r"   r#   <module>   s&     H,