U
    L?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)combined r   U/var/www/html/venv/lib/python3.8/site-packages/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)r3   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)r3   printerr$   lengthsr0   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   rD   r   r   r   rE      s     r9   r   , {})leftrightr   r:   r;   u   ⨂ zx )r9   )r9   )r9   )r   allr$   r!   r>   r=   r	   rK   ZparensrJ   ZlbracketZrbracketr   r   r   Z_use_unicode)
r3   r?   r$   r@   Zpformr0   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(   rC   rD   r   r   r   rE      s     z'TensorProduct._latex.<locals>.<genexpr>c                 s   s   | ]}t |tV  qd S r(   rF   rD   r   r   r   rE      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_wraprG   c                    s(   g | ] } |j f t|jqS r   )Z_print_label_latexr!   r$   rD   rP   r$   r?   r   r   r1      s   z(TensorProduct._latex.<locals>.<listcomp>z{%s%s%s}r   r9   z\left(rH   rI   z\right)r   z\otimes )r   rL   r$   joinZlbracket_latexZrbracket_latexr!   r=   r   r   r   r>   )r3   r?   r$   rA   r@   r0   r   rQ   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r7   r   r   r1      s     z&TensorProduct.doit.<locals>.<listcomp>r2   )r3   r7   r   rV   r   rT      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   )	r3   r7   r$   Zadd_argsr0   Zaar'   r%   nc_partr   r   r   rW      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   rT   rD   r   r   r   r1     s     z-TensorProduct._eval_trace.<locals>.<listcomp>c                    s(   g | ] \}}| kr t | n|qS r   rZ   )r/   idxvaluerY   r   r   r1     s   )getr   r!   r   r$   	enumerate)r3   kwargsexpr   r]   r   _eval_trace  s    zTensorProduct._eval_traceN)__name__
__module____qualname____doc__Zis_commutativer"   classmethodr    r4   r8   rB   rN   rS   rT   rW   rb   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/   ncr   r   r   r1   j  s     z+tensor_product_simp_Mul.<locals>.<listcomp>)r   r   r)   r!   r   rh   hasr   base	TypeErrorr$   r+   r
   r=   tensor_product_simp_Mul)
er%   rX   Zn_nccurrentZn_termsr&   nextr0   Znew_tpr   r   r   rm     sT    ,





rm   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   )ra   )r/   brn   r   r   r1   u  s     z+tensor_product_simp_Pow.<locals>.<listcomp>N)r   r   rk   r   r$   rr   r   rr   r   rh   o  s
    
rh   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   rD   r   r   r   r1     s     z'tensor_product_simp.<locals>.<listcomp>c                 S   s   g | ]}t |qS r   rs   rD   r   r   r   r1     s     c                 S   s   g | ]}t |qS r   rs   rD   r   r   r   r1     s     N)r   r   r$   r   rk   r   rh   r   ra   r   rm   r   r   )rn   r7   r   r   r   r   y  s    "




N)+rf   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   rm   rh   r   r   r   r   r   <module>   s2   	 _\
