U
    h:                     @   s  d 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 ddlmZmZ ddlmZm Z m!Z! ddl"m#Z# ddgZ$da%dd Z&G dd deZ'dd Z(dd Z)dd Z*dS )zAbstract tensor product.    )Add)Expr)Mul)Pow)sympify)DenseMatrix)ImmutableDenseMatrix)
prettyForm)QuantumErrorDagger)
Commutator)AntiCommutator)KetBra)numpy_ndarrayscipy_sparse_matrixmatrix_tensor_product)TrTensorProducttensor_product_simpFc                 C   s   | a dS )a  Set flag controlling whether tensor products of states should be
    printed as a combined bra/ket or as an explicit tensor product of different
    bra/kets. This is a global setting for all TensorProduct class instances.

    Parameters
    ----------
    combine : bool
        When true, tensor product states are combined into one ket/bra, and
        when false explicit tensor product notation is used between each
        ket/bra.
    N)_combined_printing)Zcombined r   G/tmp/pip-unpacked-wheel-6t8vlncq/sympy/physics/quantum/tensorproduct.pycombined_tensor_printing%   s    r   c                   @   sh   e Zd ZdZdZdd Ze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S )r   a  The tensor product of two or more arguments.

    For matrices, this uses ``matrix_tensor_product`` to compute the Kronecker
    or tensor product matrix. For other objects a symbolic ``TensorProduct``
    instance is returned. The tensor product is a non-commutative
    multiplication that is used primarily with operators and states in quantum
    mechanics.

    Currently, the tensor product distinguishes between commutative and
    non-commutative arguments.  Commutative arguments are assumed to be scalars
    and are pulled out in front of the ``TensorProduct``. Non-commutative
    arguments remain in the resulting ``TensorProduct``.

    Parameters
    ==========

    args : tuple
        A sequence of the objects to take the tensor product of.

    Examples
    ========

    Start with a simple tensor product of SymPy matrices::

        >>> from sympy import Matrix
        >>> from sympy.physics.quantum import TensorProduct

        >>> m1 = Matrix([[1,2],[3,4]])
        >>> m2 = Matrix([[1,0],[0,1]])
        >>> TensorProduct(m1, m2)
        Matrix([
        [1, 0, 2, 0],
        [0, 1, 0, 2],
        [3, 0, 4, 0],
        [0, 3, 0, 4]])
        >>> TensorProduct(m2, m1)
        Matrix([
        [1, 2, 0, 0],
        [3, 4, 0, 0],
        [0, 0, 1, 2],
        [0, 0, 3, 4]])

    We can also construct tensor products of non-commutative symbols:

        >>> from sympy import Symbol
        >>> A = Symbol('A',commutative=False)
        >>> B = Symbol('B',commutative=False)
        >>> tp = TensorProduct(A, B)
        >>> tp
        AxB

    We can take the dagger of a tensor product (note the order does NOT reverse
    like the dagger of a normal product):

        >>> from sympy.physics.quantum import Dagger
        >>> Dagger(tp)
        Dagger(A)xDagger(B)

    Expand can be used to distribute a tensor product across addition:

        >>> C = Symbol('C',commutative=False)
        >>> tp = TensorProduct(A+B,C)
        >>> tp
        (A + B)xC
        >>> tp.expand(tensorproduct=True)
        AxC + BxC
    Fc                 G   s|   t |d ttttfrt| S | t|\}}t| }t	|dkrH|S t	|dkr`||d  S t
j| f| }|| S d S )Nr      )
isinstanceMatrixImmutableMatrixr   r   r   flattenr   r   lenr   __new__)clsargsc_partnew_argstpr   r   r   r!   {   s    zTensorProduct.__new__c                 C   sD   g }g }|D ].}|  \}}|t| |t| q||fS N)args_cncextendlistappendr   Z
_from_args)r"   r#   r$   Znc_partsargcpZncpr   r   r   r      s    zTensorProduct.flattenc                 C   s   t dd | jD  S )Nc                 S   s   g | ]}t |qS r   r   ).0ir   r   r   
<listcomp>   s     z/TensorProduct._eval_adjoint.<locals>.<listcomp>r   r#   )selfr   r   r   _eval_adjoint   s    zTensorProduct._eval_adjointc                 K   s   t | jddS )NT)Ztensorproduct)r   expand)r2   Zruler#   hintsr   r   r   _eval_rewrite   s    zTensorProduct._eval_rewritec                 G   s   t | j}d}t|D ]h}t| j| tttfr8|d }||| j|  }t| j| tttfrj|d }||d kr|d }q|S )N ()r   x)r    r#   ranger   r   r   r   _print)r2   printerr#   lengthsr/   r   r   r   	_sympystr   s    

zTensorProduct._sympystrc           
      G   s  t rDtdd | jD s0tdd | jD rDt| j}|jd| }t|D ]}|jd| }t| j| j}t|D ]H}|j| j| j| f| }	t||	 }||d krzt|d }qzt| j| jdkrt|jddd	 }t|| }||d krPt|d }qPt|	| jd
 j
 }t|| jd
 j }|S t| j}|jd| }t|D ]}|j| j| f| }t| j| ttfrt|jddd	 }t|| }||d krd|jrt|d }nt|d }qd|S )Nc                 s   s   | ]}t |tV  qd S r'   r   r   r.   r,   r   r   r   	<genexpr>   s     z(TensorProduct._pretty.<locals>.<genexpr>c                 s   s   | ]}t |tV  qd S r'   r   r   rB   r   r   r   rC      s     r7   r   , {})leftrightr   r8   r9   u   ⨂ zx )r7   )r7   )r7   )r   allr#   r    r<   r;   r	   rI   parensrH   ZlbracketZrbracketr   r   r   Z_use_unicode)
r2   r=   r#   r>   Zpformr/   Z
next_pformZlength_ijZ
part_pformr   r   r   _pretty   sN    

zTensorProduct._prettyc                    s   t rptdd | jD s,tdd | jD rpdd  d fdd| jD }d	| jd
 j|| jd
 jf S t| j}d}t|D ]r}t| j| t	t
fr|d }|d j| j| f  d }t| j| t	t
fr|d }||d kr|d }q|S )Nc                 s   s   | ]}t |tV  qd S r'   rA   rB   r   r   r   rC      s     z'TensorProduct._latex.<locals>.<genexpr>c                 s   s   | ]}t |tV  qd S r'   rD   rB   r   r   r   rC      s     c                 S   s   |dkr| S d|  S )Nr   z\left\{%s\right\}r   )labelZnlabelsr   r   r   _label_wrap   s    z)TensorProduct._latex.<locals>._label_wraprE   c                    s(   g | ] } |j f t|jqS r   )Z_print_label_latexr    r#   rB   rO   r#   r=   r   r   r0      s   z(TensorProduct._latex.<locals>.<listcomp>z{%s%s%s}r   r7   z\left(rF   rG   z\right)r   z\otimes )r   rJ   r#   joinZlbracket_latexZrbracket_latexr    r;   r   r   r   r<   )r2   r=   r#   r?   r>   r/   r   rP   r   _latex   s.    

"
zTensorProduct._latexc                    s   t  fdd| jD  S )Nc                    s   g | ]}|j f  qS r   )doit)r.   itemr5   r   r   r0      s     z&TensorProduct.doit.<locals>.<listcomp>r1   )r2   r5   r   rU   r   rS      s    zTensorProduct.doitc           	      K   s   | j }g }tt|D ]}t|| tr|| j D ]t}t|d| |f ||d d   }| \}}t|dkrt|d tr|d  f}|t	| t	|   q2 qq|rt| S | S dS )z*Distribute TensorProducts across addition.Nr   r   )
r#   r;   r    r   r   r   r(   _eval_expand_tensorproductr+   r   )	r2   r5   r#   Zadd_argsr/   Zaar&   r$   nc_partr   r   r   rV      s    &z(TensorProduct._eval_expand_tensorproductc                    s\   | dd  t| } d ks(t dkr<tdd |jD  S t fddt|jD  S d S )Nindicesr   c                 S   s   g | ]}t | qS r   r   rS   rB   r   r   r   r0     s     z-TensorProduct._eval_trace.<locals>.<listcomp>c                    s(   g | ] \}}| kr t | n|qS r   rY   )r.   idxvaluerX   r   r   r0     s   )getr   r    r   r#   	enumerate)r2   kwargsexpr   r\   r   _eval_trace  s    zTensorProduct._eval_traceN)__name__
__module____qualname____doc__Zis_commutativer!   classmethodr   r3   r6   r@   rM   rR   rS   rV   ra   r   r   r   r   r   5   s   C

,c           
      C   s  t | ts| S |  \}}t|}|dkr.| S |dkr\t |d trXt| t|d  S | S | tr|d }t |tst |trt |jtrt|}nt	d| t|j
}t|j
}|dd D ]}t |tr |t|j
krtd||f tt|D ]}|| |j
|  ||< q nht |tr|t |jtrnt|}	tt|D ]}|| |	j
|  ||< qNnt	d| nt	d| |}qt| t|  S | trdd |D }tt| t|  S | S dS )at  Simplify a Mul with TensorProducts.

    Current the main use of this is to simplify a ``Mul`` of ``TensorProduct``s
    to a ``TensorProduct`` of ``Muls``. It currently only works for relatively
    simple cases where the initial ``Mul`` only has scalars and raw
    ``TensorProduct``s, not ``Add``, ``Pow``, ``Commutator``s of
    ``TensorProduct``s.

    Parameters
    ==========

    e : Expr
        A ``Mul`` of ``TensorProduct``s to be simplified.

    Returns
    =======

    e : Expr
        A ``TensorProduct`` of ``Mul``s.

    Examples
    ========

    This is an example of the type of simplification that this function
    performs::

        >>> from sympy.physics.quantum.tensorproduct import                     tensor_product_simp_Mul, TensorProduct
        >>> from sympy import Symbol
        >>> A = Symbol('A',commutative=False)
        >>> B = Symbol('B',commutative=False)
        >>> C = Symbol('C',commutative=False)
        >>> D = Symbol('D',commutative=False)
        >>> e = TensorProduct(A,B)*TensorProduct(C,D)
        >>> e
        AxB*CxD
        >>> tensor_product_simp_Mul(e)
        (A*C)x(B*D)

    r   r   zTensorProduct expected, got: %rNz.TensorProducts of different lengths: %r and %rc                 S   s   g | ]}t |qS r   )tensor_product_simp_Pow)r.   Zncr   r   r   r0   j  s     z+tensor_product_simp_Mul.<locals>.<listcomp>)r   r   r(   r    r   rg   Zhasr   base	TypeErrorr#   r*   r
   r;   tensor_product_simp_Mul)
er$   rW   Zn_nccurrentZn_termsr%   nextr/   Znew_tpr   r   r   rj     sT    ,





rj   c                    s<   t  ts S t  jtr4t fdd jjD  S  S dS )z=Evaluates ``Pow`` expressions whose base is ``TensorProduct``c                    s   g | ]}| j  qS r   )r`   )r.   brk   r   r   r0   u  s     z+tensor_product_simp_Pow.<locals>.<listcomp>N)r   r   rh   r   r#   ro   r   ro   r   rg   o  s
    
rg   c                 K   s   t | trtdd | jD  S t | trNt | jtr<t| S t| j| j S nRt | t	r`t
| S t | tr~tdd | jD  S t | trtdd | jD  S | S dS )a3  Try to simplify and combine TensorProducts.

    In general this will try to pull expressions inside of ``TensorProducts``.
    It currently only works for relatively simple cases where the products have
    only scalars, raw ``TensorProducts``, not ``Add``, ``Pow``, ``Commutators``
    of ``TensorProducts``. It is best to see what it does by showing examples.

    Examples
    ========

    >>> from sympy.physics.quantum import tensor_product_simp
    >>> from sympy.physics.quantum import TensorProduct
    >>> from sympy import Symbol
    >>> A = Symbol('A',commutative=False)
    >>> B = Symbol('B',commutative=False)
    >>> C = Symbol('C',commutative=False)
    >>> D = Symbol('D',commutative=False)

    First see what happens to products of tensor products:

    >>> e = TensorProduct(A,B)*TensorProduct(C,D)
    >>> e
    AxB*CxD
    >>> tensor_product_simp(e)
    (A*C)x(B*D)

    This is the core logic of this function, and it works inside, powers, sums,
    commutators and anticommutators as well:

    >>> tensor_product_simp(e**2)
    (A*C)x(B*D)**2

    c                 S   s   g | ]}t |qS r   r   rB   r   r   r   r0     s     z'tensor_product_simp.<locals>.<listcomp>c                 S   s   g | ]}t |qS r   rp   rB   r   r   r   r0     s     c                 S   s   g | ]}t |qS r   rp   rB   r   r   r   r0     s     N)r   r   r#   r   rh   r   rg   r   r`   r   rj   r   r   )rk   r5   r   r   r   r   y  s    "




N)+re   Zsympy.core.addr   Zsympy.core.exprr   Zsympy.core.mulr   Zsympy.core.powerr   Zsympy.core.sympifyr   Zsympy.matrices.denser   r   Zsympy.matrices.immutabler   r   Z sympy.printing.pretty.stringpictr	   Zsympy.physics.quantum.qexprr
   Zsympy.physics.quantum.daggerr   Z sympy.physics.quantum.commutatorr   Z$sympy.physics.quantum.anticommutatorr   Zsympy.physics.quantum.stater   r   Z!sympy.physics.quantum.matrixutilsr   r   r   Zsympy.physics.quantum.tracer   __all__r   r   r   rj   rg   r   r   r   r   r   <module>   s2   	 _\
