U
    ZÊ¹j&  ã                   @   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__© ú\/var/www/html/bwave/python/venv/lib/python3.8/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>D   s     z"Density.states.<locals>.<listcomp>©r   r   ©Úselfr"   r"   r#   Ústates7   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&   S   s     z!Density.probs.<locals>.<listcomp>r'   r(   r"   r"   r#   ÚprobsF   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_stateU   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_probj   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/   r1   ©Úopr"   r#   r&   “   s     z$Density.apply_op.<locals>.<listcomp>)r   r   )r)   r4   Únew_argsr"   r3   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/   r1   r   r"   r"   r#   Údoit–   s    
ÿzDensity.doitc                 C   s    |  ¡ \}}|  ¡ \}}t|ƒdks0t|ƒdkr8tdƒ‚t|d tƒrxt|ƒdkrxt|ƒdkrxt|d t|d ƒ ƒ}nt|Ž tt|Ž ƒ }t|Ž t|Ž  | S )Nr   zHAtleast one-pair of Non-commutative instance required for outer product.r+   )Zargs_cncr   r   r   r   r   r   r   )r)   Zarg1Zarg2Zc_part1Znc_part1Zc_part2Znc_part2r4   r"   r"   r#   r9   ²   s    
ÿzDensity._generate_outer_prodc                 K   s   t |  ¡ f|Ž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)   ÚkwargsrC   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#   rG   Ò   s    zDensity.entropy)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Úclassmethodr   r*   r,   r0   r2   r6   r;   r9   r>   rA   rB   rF   rG   Ú__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
ƒr†d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>ü   s     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densityrT   Únpr"   r"   r#   rG   Ú   s    



ÿrG   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   rP   r   ÚtypeÚshapeZ	is_squarer   ZHalfr   r;   )Zstate1Zstate2Zsqrt_state1r"   r"   r#   Úfidelity  s    ,þ
rX   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
   rP   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.tensorproductr   r   Zsympy.physics.quantum.tracer   r   rG   rX   r"   r"   r"   r#   Ú<module>   s$    H,