o
    *ήcC9                     @   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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)MutableDenseMatrix)
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   J/tmp/pip-target-vg8gfxp4/lib/python/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   sx   t |d tttfrt| S | t|\}}t| }t|dkr#|S t|dkr/||d  S t	j
| g|R  }|| S )Nr      )
isinstanceMatrixr   r   r   flattenr   r   lenr   __new__)clsargsc_partnew_argstpr   r   r   r    z   s   zTensorProduct.__new__c                 C   sD   g }g }|D ]}|  \}}|t| |t| q||fS N)args_cncextendlistappendr   
_from_args)r!   r"   r#   nc_partsargcpncpr   r   r   r      s   zTensorProduct.flattenc                 C   s   t dd | jD  S )Nc                 S      g | ]}t |qS r   r
   ).0ir   r   r   
<listcomp>       z/TensorProduct._eval_adjoint.<locals>.<listcomp>r   r"   )selfr   r   r   _eval_adjoint      zTensorProduct._eval_adjointc                 K   s   t | jddS )NT)tensorproduct)r   expand)r6   ruler"   hintsr   r   r   _eval_rewrite   s   zTensorProduct._eval_rewritec                 G   s   t | j}d}t|D ]4}t| j| tttfr|d }||| j|  }t| j| tttfr5|d }||d kr?|d }q|S )N ()r   x)r   r"   ranger   r   r   r   _print)r6   printerr"   lengthsr2   r   r   r   	_sympystr   s   
zTensorProduct._sympystrc           
      G   s  t rtdd | jD stdd | jD rt| j}|jdg|R  }t|D ]d}|jdg|R  }t| j| j}t|D ]%}|j| j| j| g|R  }	t||	 }||d krdt|d }q?t| j| jdkrxt|jddd	 }t|| }||d krt|d }q(t|	| jd
 j
 }t|| jd
 j }|S t| j}|jdg|R  }t|D ]@}|j| j| g|R  }t| j| ttfrt|jddd	 }t|| }||d kr|jrt|d }qt|d }q|S )Nc                 s       | ]}t |tV  qd S r&   r   r   r1   r-   r   r   r   	<genexpr>       z(TensorProduct._pretty.<locals>.<genexpr>c                 s   rH   r&   r   r   rJ   r   r   r   rK      rL   r>   r   , {})leftrightr   r?   r@   u   ⨂ zx )r   allr"   r   rC   rB   r   rR   parensrQ   lbracketrbracketr   r   r   _use_unicode)
r6   rD   r"   rE   pformr2   
next_pformlength_ij
part_pformr   r   r   _pretty   sT   

zTensorProduct._prettyc                    s   t r8tdd | jD stdd | jD r8dd  d fdd| jD }d	| jd
 j|| jd
 jf S t| j}d}t|D ]:}t| j| t	t
frS|d }|d j| j| gR   d }t| j| t	t
frs|d }||d kr}|d }qC|S )Nc                 s   rH   r&   rI   rJ   r   r   r   rK      rL   z'TensorProduct._latex.<locals>.<genexpr>c                 s   rH   r&   rM   rJ   r   r   r   rK      rL   c                 S   s   |dkr| S d|  S )Nr   z\left\{%s\right\}r   )labelnlabelsr   r   r   _label_wrap   r8   z)TensorProduct._latex.<locals>._label_wraprN   c                    s*   g | ]} |j gR  t|jqS r   )_print_label_latexr   r"   rJ   r`   r"   rD   r   r   r3      s
    z(TensorProduct._latex.<locals>.<listcomp>z{%s%s%s}r   r>   z\left(rO   rP   z\right)r   z\otimes )r   rS   r"   joinlbracket_latexrbracket_latexr   rB   r   r   r   rC   )r6   rD   r"   rF   rE   r2   r   rb   r   _latex   s0   

$zTensorProduct._latexc                    s   t  fdd| jD  S )Nc                    s   g | ]
}|j d i  qS )r   )doit)r1   itemr<   r   r   r3      s    z&TensorProduct.doit.<locals>.<listcomp>r5   )r6   r<   r   ri   r   rg      s   zTensorProduct.doitc                 K   s   | j }g }tt|D ]4}t|| tr?|| j D ]#}t|d| |f ||d d   }t|tr7| }|| q nq|rFt| S | S )z*Distribute TensorProducts across addition.Nr   )r"   rB   r   r   r   r   _eval_expand_tensorproductr*   )r6   r<   r"   add_argsr2   aar%   r   r   r   rj      s   &
z(TensorProduct._eval_expand_tensorproductc                    sX   | dd  t| } d u st dkrtdd |jD  S t fddt|jD  S )Nindicesr   c                 S   s   g | ]}t | qS r   r   rg   rJ   r   r   r   r3     s    z-TensorProduct._eval_trace.<locals>.<listcomp>c                    s(   g | ]\}}| v rt | n|qS r   rn   )r1   idxvaluerm   r   r   r3   
  s    )getr   r   r   r"   	enumerate)r6   kwargsexpr   rq   r   _eval_trace  s   zTensorProduct._eval_traceN)__name__
__module____qualname____doc__is_commutativer    classmethodr   r7   r=   rG   r]   rf   rg   rj   rv   r   r   r   r   r   4   s    C

,c           
      C   s  t | ts| S |  \}}t|}|dkr| S |dkr.t |d tr,t| t|d  S | S | tr|d }t |tsRt |trLt |jtrKt|}nt	d| t|j
}t|j
}|dd D ]]}t |tr|t|j
krxtd||f tt|D ]}|| |j
|  ||< q~n0t |trt |jtrt|}	tt|D ]}|| |	j
|  ||< qnt	d| t	d| |}qbt| t|  S | trdd |D }tt| t|  S | 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   r0   r   )tensor_product_simp_Pow)r1   ncr   r   r   r3   e  r4   z+tensor_product_simp_Mul.<locals>.<listcomp>)r   r   r'   r   r   r}   hasr   base	TypeErrorr"   r)   r	   rB   tensor_product_simp_Mul)
er#   nc_partn_nccurrentn_termsr$   nextr2   new_tpr   r   r   r     sZ   
,







r   c                    s8   t  ts S t  jtrt fdd jjD  S  S )z=Evaluates ``Pow`` expressions whose base is ``TensorProduct``c                    s   g | ]}| j  qS r   )ru   )r1   br   r   r   r3   p  s    z+tensor_product_simp_Pow.<locals>.<listcomp>)r   r   r   r   r"   r   r   r   r   r}   j  s
   
r}   c                 K   s   t | trtdd | jD  S t | tr&t | jtrt| S t| j| j S t | t	r/t
| S t | tr>tdd | jD  S t | trMtdd | jD  S | 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   r0   r   r   rJ   r   r   r   r3     r4   z'tensor_product_simp.<locals>.<listcomp>c                 S   r0   r   r   rJ   r   r   r   r3     r4   c                 S   r0   r   r   rJ   r   r   r   r3     r4   )r   r   r"   r   r   r   r}   r   ru   r   r   r   r   )r   r<   r   r   r   r   t  s   
"



N)(rz   sympy.core.addr   sympy.core.exprr   sympy.core.mulr   sympy.core.powerr   sympy.core.sympifyr   sympy.matrices.denser   r    sympy.printing.pretty.stringpictr   sympy.physics.quantum.qexprr	   sympy.physics.quantum.daggerr    sympy.physics.quantum.commutatorr   $sympy.physics.quantum.anticommutatorr   sympy.physics.quantum.stater   r   !sympy.physics.quantum.matrixutilsr   r   r   sympy.physics.quantum.tracer   __all__r   r   r   r   r}   r   r   r   r   r   <module>   s2    	 [\
