a
    khJ%                     @   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 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)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__ K/var/www/auris/lib/python3.9/site-packages/sympy/physics/quantum/density.pyr   )   s
    
zDensity._eval_argsc                 C   s   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   s   g | ]}|d  qS )r   r    .0r   r    r    r!   
<listcomp>C       z"Density.states.<locals>.<listcomp>r   r   selfr    r    r!   states6   s    zDensity.statesc                 C   s   t d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                 S   s   g | ]}|d  qS )   r    r"   r    r    r!   r$   R   r%   z!Density.probs.<locals>.<listcomp>r&   r'   r    r    r!   probsE   s    zDensity.probsc                 C   s   | 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_stateT   s    zDensity.get_statec                 C   s   | 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(   r-   probr    r    r!   get_probi   s    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#   r.   r0   opr    r!   r$      r%   z$Density.apply_op.<locals>.<listcomp>)r   r   )r(   r3   new_argsr    r2   r!   apply_op~   s    zDensity.apply_opc              
   K   sx   g }| j D ]d\}}| }t|trXt|j ddD ]"}||| |d |d   q2q
||| ||  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(   hintsZtermsr.   r0   r   r    r    r!   doit   s    
zDensity.doitc                 C   s`   |  \}}|  \}}t|dks0t|dkr8tdt| tt|  }t| t|  | S )Nr   zHAtleast one-pair of Non-commutative instance required for outer product.)Zargs_cncr   r   r   r   )r(   Zarg1Zarg2Zc_part1Znc_part1Zc_part2Znc_part2r3   r    r    r!   r8      s    zDensity._generate_outer_prodc                 K   s   t |  fi |S N)r   r:   )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   r>   r    r    r!   _print_operator_name_pretty   s    z#Density._print_operator_name_prettyc                 K   s   | dg }t|  | S )Nindices)getr   r:   )r(   kwargsrB   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!   rF      s    zDensity.entropy)__name__
__module____qualname____doc__classmethodr   r)   r+   r/   r1   r5   r:   r8   r=   r@   rA   rE   rF   __classcell__r    r    r   r!   r      s   r   c                 C   s   t | trt| } t | tr$t| } t | trR|   }tt	dd |D  S t | t
rddl}|j| }|	|||  S tddS )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 r;   r   )r#   er    r    r!   	<genexpr>   r%   zentropy.<locals>.<genexpr>r   Nz4numpy.ndarray, scipy.sparse or SymPy matrix expected)r   r   r   r   r   MatrixZ	eigenvalskeysr   sumr   numpyZlinalgeigvalsr	   r   )ZdensityrS   npr    r    r!   rF      s    



rF   c                 C   s   t | trt| n| } t |tr(t|n|}t | tr@t |tsXtdt| t|f | j|jkrr| jrrt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   rO   r   typeshapeZ	is_squarer   ZHalfr   r:   )Zstate1Zstate2Zsqrt_state1r    r    r!   fidelity  s    ,
rW   N)"	itertoolsr   Zsympy.core.addr   Zsympy.core.containersr   Zsympy.core.functionr   Zsympy.core.mulr   Zsympy.core.singletonr   Z&sympy.functions.elementary.exponentialr	   Zsympy.matrices.denser
   rO   Z sympy.printing.pretty.stringpictr   Zsympy.physics.quantum.daggerr   Zsympy.physics.quantum.operatorr   Zsympy.physics.quantum.representr   Z!sympy.physics.quantum.matrixutilsr   r   r   Zsympy.physics.quantum.tracer   r   rF   rW   r    r    r    r!   <module>   s"    E,