o
    *ήcN-                    @   s  d dl Zd dlZd dlmZmZ d dlmZ d dlZd dlmZ d dl	m
Z
mZmZmZ d dl	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 d dl m!Z! d dl"m#Z# d dl$m%Z%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/m0Z0m1Z1m2Z2m3Z3 d dl4m5Z5 d dl6m7Z7 d dl8m9Z9m:Z: d dl+m;Z; d dl<m=Z=m>Z>m?Z?m@Z@mAZAmBZB d dlCmDZD d dlEmFZF d dlGmHZH G dd deZIG d d! d!eIZJG d"d# d#eZKG d$d% d%eIZLG d&d' d'eIZMG d(d) d)eZNG d*d+ d+eNZOG d,d- d-eNZPG d.d/ d/eNZQG d0d1 d1eNZRG d2d3 d3eNZSG d4d5 d5eNZTG d6d7 d7eNZUG d8d9 d9ZVG d:d; d;ZWG d<d= d=ZXd>d? ZYd@dA ZZdBdC Z[dDdE Z\dFdG Z]dHdI Z^dJdK Z_dLdM Z`dNdO ZadPdQ ZbdRdS ZcdS )T    N)defaultdictCounter)reduce)
accumulate)OptionalListDictTuple)Integer)EqualityKroneckerDelta)Basic)r	   )Expr)FunctionLambda)Mul)Sdefault_sort_key)DummySymbol)MatrixCommon)diagonalize_vector)
MatrixExpr)
ZeroMatrix)permutedimstensorcontractiontensordiagonaltensorproduct)ImmutableDenseNDimArray)	NDimArray)IndexedIndexedBase)MatrixElement)$_apply_recursively_over_nested_lists_sort_contraction_indices_get_mapping_from_subranks*_build_push_indices_up_func_transformation_get_contraction_links,_build_push_indices_down_func_transformationPermutation)
_af_invert_sympifyc                   @   s.   e Zd ZU eedf ed< dd Zdd ZdS )
_ArrayExpr.shapec                 C   s*   t |tjjs
|f}t| | | |S N)
isinstancecollectionsabcIterableArrayElement_check_shape_getselfitem r=   W/tmp/pip-target-vg8gfxp4/lib/python/sympy/tensor/array/expressions/array_expressions.py__getitem__*   s   
z_ArrayExpr.__getitem__c                 C   
   t | |S r2   )_get_array_element_or_slicer:   r=   r=   r>   r9   0      
z_ArrayExpr._getN)__name__
__module____qualname__tTupler   __annotations__r?   r9   r=   r=   r=   r>   r0   '   s   
 r0   c                   @   sD   e Zd ZdZdejdd fddZedd Zedd	 Z	d
d Z
dS )ArraySymbolz1
    Symbol representing an array expression
    r1   returnc                 C   s2   t |tr	t|}ttt| }t| ||}|S r2   )r3   strr   r	   mapr/   r   __new__)clssymbolr1   objr=   r=   r>   rL   9   s
   
zArraySymbol.__new__c                 C   
   | j d S Nr   _argsr;   r=   r=   r>   nameA      
zArraySymbol.namec                 C   rP   N   rR   rT   r=   r=   r>   r1   E   rV   zArraySymbol.shapec                    sP   t dd  jD std fddtjdd  jD  D }t|j j S )Nc                 s       | ]}|j V  qd S r2   
is_Integer.0ir=   r=   r>   	<genexpr>J       z*ArraySymbol.as_explicit.<locals>.<genexpr>z1cannot express explicit array with symbolic shapec                       g | ]} | qS r=   r=   r\   rT   r=   r>   
<listcomp>L       z+ArraySymbol.as_explicit.<locals>.<listcomp>c                 S      g | ]}t |qS r=   ranger]   jr=   r=   r>   rb   L   rc   )allr1   
ValueError	itertoolsproductr    reshape)r;   datar=   rT   r>   as_explicitI   s   $zArraySymbol.as_explicitN)rC   rD   rE   __doc__typingr6   rL   propertyrU   r1   ro   r=   r=   r=   r>   rH   4   s    

rH   c                   @   sP   e Zd ZdZdZdZdZdd Zedd Z	e
dd Ze
d	d
 Zdd ZdS )r7   z!
    An element of an array.
    Tc                 C   sX   t |tr	t|}t|}t |tjjs|f}tt|}| || t	
| ||}|S r2   )r3   rJ   r   r/   r4   r5   r6   tupler8   r   rL   )rM   rU   indicesrO   r=   r=   r>   rL   Y   s   
zArrayElement.__new__c                 C   sp   t |}t|dr)td}t|t|jkr|tdd t||jD r)tdtdd |D r6tdd S )Nr1   z3number of indices does not match shape of the arrayc                 s   s     | ]\}}||kd kV  qdS )TNr=   )r]   r^   sr=   r=   r>   r_   k       z,ArrayElement._check_shape.<locals>.<genexpr>zshape is out of boundsc                 s   s    | ]	}|d k dkV  qdS )r   TNr=   r\   r=   r=   r>   r_   m       zshape contains negative values)rs   hasattr
IndexErrorlenr1   anyziprj   )rM   rU   rt   index_errorr=   r=   r>   r8   d   s   
zArrayElement._check_shapec                 C   rP   rQ   rR   rT   r=   r=   r>   rU   p   rV   zArrayElement.namec                 C   rP   rW   rR   rT   r=   r=   r>   rt   t   rV   zArrayElement.indicesc                 C   sN   t |tstjS || krtjS |j| jkrtjS tdd t| j	|j	D S )Nc                 s   s    | ]
\}}t ||V  qd S r2   r   r]   r^   rh   r=   r=   r>   r_          z0ArrayElement._eval_derivative.<locals>.<genexpr>)
r3   r7   r   ZeroOnerU   r   fromiterr|   rt   )r;   ru   r=   r=   r>   _eval_derivativex   s   
zArrayElement._eval_derivativeN)rC   rD   rE   rp   	_diff_wrt	is_symbolis_commutativerL   classmethodr8   rr   rU   rt   r   r=   r=   r=   r>   r7   P   s    


r7   c                   @   4   e Zd ZdZdd Zedd Zdd Zdd	 Zd
S )	ZeroArrayzM
    Symbolic array of zeros. Equivalent to ``ZeroMatrix`` for matrices.
    c                 G   2   t |dkr	tjS tt|}tj| g|R  }|S rQ   )rz   r   r   rK   r/   r   rL   rM   r1   rO   r=   r=   r>   rL      
   
zZeroArray.__new__c                 C      | j S r2   rR   rT   r=   r=   r>   r1         zZeroArray.shapec                 C   s(   t dd | jD stdtj| j S )Nc                 s   rY   r2   rZ   r\   r=   r=   r>   r_      r`   z(ZeroArray.as_explicit.<locals>.<genexpr>/Cannot return explicit form for symbolic shape.)ri   r1   rj   r    zerosrT   r=   r=   r>   ro      s   zZeroArray.as_explicitc                 C      t jS r2   )r   r   r:   r=   r=   r>   r9         zZeroArray._getN	rC   rD   rE   rp   rL   rr   r1   ro   r9   r=   r=   r=   r>   r          
r   c                   @   r   )OneArrayz!
    Symbolic array of ones.
    c                 G   r   rQ   )rz   r   r   rK   r/   r   rL   r   r=   r=   r>   rL      r   zOneArray.__new__c                 C   r   r2   rR   rT   r=   r=   r>   r1      r   zOneArray.shapec                 C   sD   t dd | jD stdtdd tttj| jD j| j S )Nc                 s   rY   r2   rZ   r\   r=   r=   r>   r_      r`   z'OneArray.as_explicit.<locals>.<genexpr>r   c                 S   s   g | ]}t jqS r=   r   r   r\   r=   r=   r>   rb          z(OneArray.as_explicit.<locals>.<listcomp>)	ri   r1   rj   r    rf   r   operatormulrm   rT   r=   r=   r>   ro      s   (zOneArray.as_explicitc                 C   r   r2   r   r:   r=   r=   r>   r9      r   zOneArray._getNr   r=   r=   r=   r>   r      r   r   c                   @   s4   e Zd Zedd Zdd Zedd Zdd Zd	S )
_CodegenArrayAbstractc                 C   s   | j dd S )a  
        Returns the ranks of the objects in the uppermost tensor product inside
        the current object.  In case no tensor products are contained, return
        the atomic ranks.

        Examples
        ========

        >>> from sympy.tensor.array import tensorproduct, tensorcontraction
        >>> from sympy import MatrixSymbol
        >>> M = MatrixSymbol("M", 3, 3)
        >>> N = MatrixSymbol("N", 3, 3)
        >>> P = MatrixSymbol("P", 3, 3)

        Important: do not confuse the rank of the matrix with the rank of an array.

        >>> tp = tensorproduct(M, N, P)
        >>> tp.subranks
        [2, 2, 2]

        >>> co = tensorcontraction(tp, (1, 2), (3, 4))
        >>> co.subranks
        [2, 2, 2]
        N)	_subranksrT   r=   r=   r>   subranks   s   z_CodegenArrayAbstract.subranksc                 C   
   t | jS )z*
        The sum of ``subranks``.
        )sumr   rT   r=   r=   r>   subrank   s   
z_CodegenArrayAbstract.subrankc                 C   r   r2   _shaperT   r=   r=   r>   r1      r   z_CodegenArrayAbstract.shapec                    s6     dd}|r| j fdd| jD   S |  S )NdeepTc                    s   g | ]
}|j d i  qS )r=   )doitr]   arghintsr=   r>   rb          z._CodegenArrayAbstract.doit.<locals>.<listcomp>)getfuncargs_canonicalize)r;   r   r   r=   r   r>   r      s   z_CodegenArrayAbstract.doitN)rC   rD   rE   rr   r   r   r1   r   r=   r=   r=   r>   r      s    

r   c                   @   4   e Zd ZdZdd Zdd Zedd Zdd	 Zd
S )ArrayTensorProductzF
    Class to represent the tensor product of array-like objects.
    c                 O   s   dd |D }| dd}dd |D }tj| g|R  }||_dd |D }tdd |D r4d |_n
td	d |D |_|rD| S |S )
Nc                 S   rd   r=   r.   r   r=   r=   r>   rb      rc   z.ArrayTensorProduct.__new__.<locals>.<listcomp>canonicalizeFc                 S   rd   r=   get_rankr   r=   r=   r>   rb      rc   c                 S   rd   r=   	get_shaper\   r=   r=   r>   rb      rc   c                 s       | ]}|d u V  qd S r2   r=   r\   r=   r=   r>   r_          z-ArrayTensorProduct.__new__.<locals>.<genexpr>c                 s   s    | ]
}|D ]}|V  qqd S r2   r=   r~   r=   r=   r>   r_      r   )popr   rL   r   r{   r   rs   r   )rM   r   kwargsr   ranksrO   shapesr=   r=   r>   rL      s   zArrayTensorProduct.__new__c                    s  | j }| |}dd |D g }t|D ]\}t|tsq|fdd|jjD  |j|< q|rGt	t
| ttd t| S t|dkrQ|d S tdd |D rjttjdd |D d	}t| S d
d t|D }|rdd |D ttdg d d  t
dd |D  } fdd| D }t|g|R  S dd t|D }|rSg }	g }
dd |D ttdg d d  t|D ]K\}t|trt|t|j }t|j}|	 fddt|D  |
 fddt||| D  q|	 fddtt|D  q|	|
 t
dd |D  }dd |D }ttdg| d d fdd| D }t	t|g|R  t|	S | j|ddiS )Nc                 S   rd   r=   r   r   r=   r=   r>   rb     rc   z4ArrayTensorProduct._canonicalize.<locals>.<listcomp>c                    s    g | ]} fd d|D qS )c                    s    g | ]}|t d    qS r2   )r   r]   kr^   r   r=   r>   rb   	       z?ArrayTensorProduct._canonicalize.<locals>.<listcomp>.<listcomp>r=   rg   r   r=   r>   rb   	  r   rX   r   c                 s   s    | ]
}t |ttfV  qd S r2   r3   r   r   r   r=   r=   r>   r_     r   z3ArrayTensorProduct._canonicalize.<locals>.<genexpr>c                 S   rd   r=   r   r\   r=   r=   r>   rb     rc   r=   c                 S       i | ]\}}t |tr||qS r=   )r3   ArrayContractionr]   r^   r   r=   r=   r>   
<dictcomp>  r   z4ArrayTensorProduct._canonicalize.<locals>.<dictcomp>c                 S   &   g | ]}t |trt|nt|qS r=   )r3   r   _get_subrankr   r   r=   r=   r>   rb        & c                 S       g | ]}t |tr|jn|qS r=   )r3   r   exprr   r=   r=   r>   rb     r   c                    4   g | ]\ }|j D ]}t fd d|D q	qS )c                 3       | ]	}  | V  qd S r2   r=   r   cumulative_ranksr^   r=   r>   r_     rw   >ArrayTensorProduct._canonicalize.<locals>.<listcomp>.<genexpr>)contraction_indicesrs   r]   r   rh   r   r^   r>   rb        4 c                 S   r   r=   )r3   ArrayDiagonalr   r=   r=   r>   r      r   c                 S   rd   r=   r   r   r=   r=   r>   rb   $  rc   c                       g | ]}  | qS r=   r=   rg   r   r=   r>   rb   *      c                    r   r=   r=   rg   r   r=   r>   rb   +  r   c                    r   r=   r=   rg   r   r=   r>   rb   -  r   c                 S   r   r=   )r3   r   r   r   r=   r=   r>   rb   /  r   c                 S   r   r=   )r3   r   r   r   r   r=   r=   r>   rb   0  r   c                    r   )c                 3   r   r2   r=   r   )cumulative_ranks2r^   r=   r>   r_   2  rw   r   )diagonal_indicesrs   r   )r   r   r>   rb   2  r   r   F)r   _flatten	enumerater3   PermuteDimsextendpermutationcyclic_formr   _permute_dims_array_tensor_productr,   r   rz   r{   r   r   addr   listr   items_array_contractionr   r   r   rf   _array_diagonalr-   r   )r;   r   permutation_cyclesr   r   contractionstpr   	diagonalsinverse_permutation	last_permi1i2ranks2r   r=   )r   r   r^   r   r>   r      sV   

"
&$
z ArrayTensorProduct._canonicalizec                    s    fdd|D }|S )Nc                    s,   g | ]}t | r|jn|gD ]}|qqS r=   )r3   r   )r]   r   r^   rM   r=   r>   rb   9  s   , z/ArrayTensorProduct._flatten.<locals>.<listcomp>r=   )rM   r   r=   r   r>   r   7  s   zArrayTensorProduct._flattenc                 C   s   t dd | jD  S )Nc                 S   "   g | ]}t |d r| n|qS ro   rx   ro   r   r=   r=   r>   rb   =     " z2ArrayTensorProduct.as_explicit.<locals>.<listcomp>)r   r   rT   r=   r=   r>   ro   <  s   zArrayTensorProduct.as_explicitN)	rC   rD   rE   rp   rL   r   r   r   ro   r=   r=   r=   r>   r      s    9
r   c                   @   r   )ArrayAddz0
    Class for elementwise array additions.
    c                 O   s   dd |D }dd |D }t t|}t|dkrtddd |D }tdd |D dkr4td	|d
d}tj| g|R  }||_tdd |D rSd |_	n|d |_	|r^|
 S |S )Nc                 S   rd   r=   r.   r   r=   r=   r>   rb   F  rc   z$ArrayAdd.__new__.<locals>.<listcomp>c                 S   rd   r=   r   r   r=   r=   r>   rb   G  rc   rX   z!summing arrays of different ranksc                 S      g | ]}|j qS r=   r1   r   r=   r=   r>   rb   K  r   c                 S   s   h | ]}|d ur|qS r2   r=   r\   r=   r=   r>   	<setcomp>L  r   z#ArrayAdd.__new__.<locals>.<setcomp>zmismatching shapes in additionr   Fc                 s   r   r2   r=   r\   r=   r=   r>   r_   S  r   z#ArrayAdd.__new__.<locals>.<genexpr>r   )r   setrz   rj   r   r   rL   r   r{   r   r   )rM   r   r   r   r   r   rO   r=   r=   r>   rL   E  s"   
zArrayAdd.__new__c                 C   s   | j }| |}dd |D }dd |D }t|dkr/tdd |D r)tdt|d  S t|dkr9|d S | j|d	d
iS )Nc                 S   rd   r=   r   r   r=   r=   r>   rb   a  rc   z*ArrayAdd._canonicalize.<locals>.<listcomp>c                 S   s   g | ]}t |ttfs|qS r=   r   r   r=   r=   r>   rb   b      r   c                 s   s    | ]	}|d u r|V  qd S r2   r=   r\   r=   r=   r>   r_   d  rw   z)ArrayAdd._canonicalize.<locals>.<genexpr>zIcannot handle addition of ZeroMatrix/ZeroArray and undefined shape objectrX   r   F)r   _flatten_argsrz   r{   NotImplementedErrorr   r   )r;   r   r   r=   r=   r>   r   [  s   
zArrayAdd._canonicalizec                 C   s4   g }|D ]}t |tr||j q|| q|S r2   )r3   r   r   r   append)rM   r   new_argsr   r=   r=   r>   r   k  s   
zArrayAdd._flatten_argsc                 C   s   t tjdd | jD S )Nc                 S   r   r   r   r   r=   r=   r>   rb   x  r   z(ArrayAdd.as_explicit.<locals>.<listcomp>)r   r   r   r   rT   r=   r=   r>   ro   u  s   zArrayAdd.as_explicitN)	rC   rD   rE   rp   rL   r   r   r   ro   r=   r=   r=   r>   r   @  s    
	r   c                   @   s   e Zd ZdZdddZdd Zedd Zed	d
 Ze	dd Z
e	dd Ze	dd Ze	dd Zdd Ze	dd Zdd Ze	dd Ze	dd ZdS )r   a  
    Class to represent permutation of axes of arrays.

    Examples
    ========

    >>> from sympy.tensor.array import permutedims
    >>> from sympy import MatrixSymbol
    >>> M = MatrixSymbol("M", 3, 3)
    >>> cg = permutedims(M, [1, 0])

    The object ``cg`` represents the transposition of ``M``, as the permutation
    ``[1, 0]`` will act on its indices by switching them:

    `M_{ij} \Rightarrow M_{ji}`

    This is evident when transforming back to matrix form:

    >>> from sympy.tensor.array.expressions.conv_array_to_matrix import convert_array_to_matrix
    >>> convert_array_to_matrix(cg)
    M.T

    >>> N = MatrixSymbol("N", 3, 2)
    >>> cg = permutedims(N, [1, 0])
    >>> cg.shape
    (2, 3)

    There are optional parameters that can be used as alternative to the permutation:

    >>> from sympy.tensor.array.expressions import ArraySymbol, PermuteDims
    >>> M = ArraySymbol("M", (1, 2, 3, 4, 5))
    >>> expr = PermuteDims(M, index_order_old="ijklm", index_order_new="kijml")
    >>> expr
    PermuteDims(M, (0 2 1)(3 4))
    >>> expr.shape
    (3, 1, 2, 5, 4)

    Permutations of tensor products are simplified in order to achieve a
    standard form:

    >>> from sympy.tensor.array import tensorproduct
    >>> M = MatrixSymbol("M", 4, 5)
    >>> tp = tensorproduct(M, N)
    >>> tp.shape
    (4, 5, 3, 2)
    >>> perm1 = permutedims(tp, [2, 3, 1, 0])

    The args ``(M, N)`` have been sorted and the permutation has been
    simplified, the expression is equivalent:

    >>> perm1.expr.args
    (N, M)
    >>> perm1.shape
    (3, 2, 5, 4)
    >>> perm1.permutation
    (2 3)

    The permutation in its array form has been simplified from
    ``[2, 3, 1, 0]`` to ``[0, 1, 3, 2]``, as the arguments of the tensor
    product `M` and `N` have been switched:

    >>> perm1.permutation.array_form
    [0, 1, 3, 2]

    We can nest a second permutation:

    >>> perm2 = permutedims(perm1, [1, 0, 2, 3])
    >>> perm2.shape
    (2, 3, 5, 4)
    >>> perm2.permutation.array_form
    [1, 0, 3, 2]
    Nc                    s   ddl m} t|}t|}|  ||| |   j}||kr%td|dd}	t	| | }
t|g|
_
t|d u rDd |
_nt fddttD |
_|	r[|
 S |
S )Nr   r+   z8Permutation size must be the length of the shape of exprr   Fc                 3   s    | ]	} | V  qd S r2   r=   r\   r   r1   r=   r>   r_     rw   z&PermuteDims.__new__.<locals>.<genexpr>)sympy.combinatoricsr,   r/   r   _get_permutation_from_argumentssizerj   r   r   rL   r   r   r   rs   rf   rz   r   )rM   r   r   index_order_oldindex_order_newr   r,   	expr_rankpermutation_sizer   rO   r=   r   r>   rL     s$   "zPermuteDims.__new__c                    s   | j  | j}t tr j } j}|| }| t tr$|  |\ }t tr1|  |\ }t tt	frDt fdd|j
D  S |j
}|t|krO S | j |ddS )Nc                       g | ]} j | qS r=   r   r\   r   r=   r>   rb         z-PermuteDims._canonicalize.<locals>.<listcomp>F)r   )r   r   r3   r   r   '_PermuteDims_denestarg_ArrayContractionr   )_PermuteDims_denestarg_ArrayTensorProductr   r   
array_formsortedr   )r;   r   subexprsubpermplistr=   r  r>   r     s"   


zPermuteDims._canonicalizec                 C   rP   rQ   r   rT   r=   r=   r>   r     rV   zPermuteDims.exprc                 C   rP   rW   r  rT   r=   r=   r>   r     rV   zPermuteDims.permutationc                    s   t |jt|j ttdg|j fddtt D dd tD }|j	dd d dd |D } fd	d|D }fd
d|D }t
t dd |D }t| |fS )Nr   c                    s$   g | ]} |  |d    qS rX   r=   r\   )cumulperm_image_formr=   r>   rb         $ zIPermuteDims._PermuteDims_denestarg_ArrayTensorProduct.<locals>.<listcomp>c                 S   s   g | ]
\}}|t |fqS r=   )r  )r]   r^   compr=   r=   r>   rb     r   c                 S      | d S rW   r=   xr=   r=   r>   <lambda>      zGPermuteDims._PermuteDims_denestarg_ArrayTensorProduct.<locals>.<lambda>keyc                 S      g | ]}|d  qS r   r=   r\   r=   r=   r>   rb     rc   c                    ra   r=   r=   r\   r  r=   r>   rb   
  rc   c                    ra   r=   r=   r\   )perm_image_form_in_componentsr=   r>   rb     rc   c                 S      g | ]	}|D ]}|qqS r=   r=   r~   r=   r=   r>   rb         )r-   r
  r   r   r   r   rf   rz   r   sortr,   r   )rM   r   r   psperm_args_image_formargs_sortedperm_image_form_sorted_argsnew_permutationr=   )r   r  r  r  r>   r	    s   

z5PermuteDims._PermuteDims_denestarg_ArrayTensorProductc                    s  t |ts	||fS t |jts||fS |jj dd |jjD }|j}dd |D }ttdg| g t|j	}d}t
|D ])\}}	g }
t| |d  D ]}||v rXqQ|
||  |d7 }qQ|
 q@fddt
|jD ||j}|d fdd|D }tt
|}|jd	d
 d dd |D }fdd|D }tdd |D  fdd|D }fdd|D }tt| g|R  }ttdd fdd|D D }||fS )Nc                 S   rd   r=   r   r   r=   r=   r>   rb     rc   zGPermuteDims._PermuteDims_denestarg_ArrayContraction.<locals>.<listcomp>c                 S   r  r=   r=   r~   r=   r=   r>   rb     r   r   rX   c                    s0   g | ]\}}d d t  |  |d  D qS )c                 S   s   g | ]}|qS r=   r=   rg   r=   r=   r>   rb   ,      RPermuteDims._PermuteDims_denestarg_ArrayContraction.<locals>.<listcomp>.<listcomp>rX   re   r]   r^   er  r=   r>   rb   ,     0 r   c                       g | ]} fd d|D qS )c                    s   g | ]
}|d ur |qS r2   r=   rg   r   r=   r>   rb   /  r   r(  r=   r\   r.  r=   r>   rb   /  r   c                 S   r  rW   r=   r  r=   r=   r>   r  4  r  zEPermuteDims._PermuteDims_denestarg_ArrayContraction.<locals>.<lambda>r  c                 S   r  r  r=   r\   r=   r=   r>   rb   7  rc   c                    ra   r=   r=   r\   index_blocksr=   r>   rb   9  rc   c                 S   r  r=   r=   r~   r=   r=   r>   rb   :  r   c                    ra   r=   r=   r\   r  r=   r>   rb   ;  rc   c                    "   g | ]}t  fd d|D qS )c                 3       | ]} | V  qd S r2   r=   rg   new_index_perm_array_formr=   r>   r_   <  r   zQPermuteDims._PermuteDims_denestarg_ArrayContraction.<locals>.<listcomp>.<genexpr>rs   r\   r3  r=   r>   rb   <  r   c                 S   r  r=   r=   r~   r=   r=   r>   rb   >  r   c                    ra   r=   r=   r   )permutation_array_blocks_upr=   r>   rb   >  rc   )r3   r   r   r   r   r   r   r   r-   r
  r   rf   r   r   _push_indices_upr!  r   r   r,   )rM   r   r   r   r   contraction_indices_flat
image_formcounterr^   r*  currentrh   index_blocks_upindex_blocks_up_permutedsorting_keysnew_perm_image_formnew_index_blocksr   new_contraction_indicesnew_exprr&  r=   )r   r  r0  r   r4  r6  r>   r    sD   


$z3PermuteDims._PermuteDims_denestarg_ArrayContractionc                    s  j }fddtjD fddt D }tj|d  }g g tg }t|D ]J\}}| |krH g | }| || }	t	|	kr}t
 fddD }
| }t| t|
|< || g q3 ttt	}i }dgtt|  tt	|D ],}tfddt |  |d  D }t	|dkrqtt|}||kr|||< qg }g }|rt	|dkr| \}}|| n|d }||vrg }q||}||v r|| g }q|| |s|D ]}t|D ]\}}||||d t	|  < qq fd	dt|D fd
d|D fdd|D }dd |D }t t|fS )Nc                    s(   g | ]\}}t  j| D ]}|qqS r=   )rf   r   )r]   r^   r   rh   r  r=   r>   rb   D     ( z:PermuteDims._check_permutation_mapping.<locals>.<listcomp>c                    s   g | ]} |qS r=   r=   r\   r   r=   r>   rb   E  rc   r   c                    s   g | ]}|t   qS r=   minrg   )current_indicesr=   r>   rb   T  r   c                    s   g | ]} |  qS r=   r=   rg   )	index2argr&  r=   r>   rb   b  r   rX   r   c                    s*   g | ]\ } fd dt |D qS )c                    s   g | ]
}  |  qS r=   r=   rg   )cumulative_subranksr^   r&  r=   r>   rb     r   zEPermuteDims._check_permutation_mapping.<locals>.<listcomp>.<listcomp>re   )r]   r*  )rI  r&  r   r>   rb     s   * c                    ra   r=   r=   r\   )r   r=   r>   rb     rc   c                    ra   r=   r=   r\   )permutation_blocksr=   r>   rb     rc   c                 S   r  r=   r=   r~   r=   r=   r>   rb     r   )r   r   r   rf   r   r   r   r   r   rz   r  r   r,   r   r   nextiterpopitemr   r   )rM   r   r   r   permuted_indicesarg_candidate_indexinserted_arg_cand_indicesr^   idxarg_candidate_ranklocal_current_indicesr   args_positionsmapsru   elemlinescurrent_liner   vliner*  new_permutation_blocksnew_permutation2r=   )rI  rG  r   rH  r   r&  r   rJ  r>   _check_permutation_mappingA  sz   




*


z&PermuteDims._check_permutation_mappingc                    s   t |j}|j}|j}dgt t|  dd |D }dd |D }g }t|D ]F\}	}
d}tt d D ].||	   krd||	  d  k rdt| t	 fdd||	 D g|< d} nq6|rn|
||	  q(t| t	||jd	fS )
Nr   c                 S   rd   r=   rE  r\   r=   r=   r>   rb     rc   zAPermuteDims._check_if_there_are_closed_cycles.<locals>.<listcomp>c                 S   rd   r=   maxr\   r=   r=   r>   rb     rc   TrX   c                       g | ]}|   qS r=   r=   r   rI  rh   r=   r>   rb     r   F)r   )r   r   r   r   r   r   rf   rz   r   r,   r   r   r   )rM   r   r   r   r   r   
cyclic_min
cyclic_maxcyclic_keepr^   cycleflagr=   ra  r>   !_check_if_there_are_closed_cycles  s&   
$,z-PermuteDims._check_if_there_are_closed_cyclesc                 C   s    |  | j| j}|du r| S |S )z
        DEPRECATED.
        N)_nest_permutationr   r   )r;   retr=   r=   r>   nest_permutation  s   zPermuteDims.nest_permutationc                    s   t |trt| | S t |tr8j}tj|g|R  }t|  fdd|jD }t	t
|j g|R  S t |trItfdd|jD  S d S )Nc                    r1  )c                 3       | ]} |V  qd S r2   r=   rg   newpermutationr=   r>   r_     r   z;PermuteDims._nest_permutation.<locals>.<listcomp>.<genexpr>r5  r\   rl  r=   r>   rb     r   z1PermuteDims._nest_permutation.<locals>.<listcomp>c                    s   g | ]}t | qS r=   r   r   rD  r=   r>   rb     r  )r3   r   r   rg  r   r   '_convert_outer_indices_to_inner_indicesr,   r   r   r   r   r   
_array_addr   )rM   r   r   cycles	newcyclesnew_contr_indicesr=   )rm  r   r>   rh    s   


zPermuteDims._nest_permutationc                 C   s$   | j }t|dr| }t|| jS Nro   )r   rx   ro   r   r   r;   r   r=   r=   r>   ro        
zPermuteDims.as_explicitc                 C   sR   |d u r|d u s|d u rt dt|||S |d urt d|d ur't d|S )NzPermutation not definedz2index_order_new cannot be defined with permutationz2index_order_old cannot be defined with permutation)rj   r   "_get_permutation_from_index_orders)rM   r   r  r  dimr=   r=   r>   r     s   z+PermuteDims._get_permutation_from_argumentsc                    sj   t t||krtdt t |krtdt tt|t dkr*td fdd|D }|S )Nz*wrong number of indices in index_order_newz*wrong number of indices in index_order_oldr   z>index_order_new and index_order_old must have the same indicesc                       g | ]}  |qS r=   indexr\   r  r=   r>   rb     r  zBPermuteDims._get_permutation_from_index_orders.<locals>.<listcomp>)rz   r   rj   symmetric_difference)rM   r  r  rx  r   r=   r|  r>   rw    s   z.PermuteDims._get_permutation_from_index_orders)NNN)rC   rD   rE   rp   rL   r   rr   r   r   r   r	  r  r]  rg  rj  rh  ro   r   rw  r=   r=   r=   r>   r   {  s0    
I



0
D
	

r   c                   @   s   e Zd ZdZdd Zdd Zedd Zedd	 Ze	d
d Z
e	dd Zedd Zedd Zedd ZedefddZdd Zdd Zedd Zedd Zedd  Zd!d" Zd#S )$r   a  
    Class to represent the diagonal operator.

    Explanation
    ===========

    In a 2-dimensional array it returns the diagonal, this looks like the
    operation:

    `A_{ij} \rightarrow A_{ii}`

    The diagonal over axes 1 and 2 (the second and third) of the tensor product
    of two 2-dimensional arrays `A \otimes B` is

    `\Big[ A_{ab} B_{cd} \Big]_{abcd} \rightarrow \Big[ A_{ai} B_{id} \Big]_{adi}`

    In this last example the array expression has been reduced from
    4-dimensional to 3-dimensional. Notice that no contraction has occurred,
    rather there is a new index `i` for the diagonal, contraction would have
    reduced the array to 2 dimensions.

    Notice that the diagonalized out dimensions are added as new dimensions at
    the end of the indices.
    c                 O   s   t |}dd |D }|dd}t|}|d ur.| j|g|R i | | ||\}}nd }t|dkr8|S tj| |g|R  }||_t	||_
||_|rS| S |S )Nc                 S   s   g | ]}t t| qS r=   )r	   r  r\   r=   r=   r>   rb     r   z)ArrayDiagonal.__new__.<locals>.<listcomp>r   Fr   )r/   r   r   	_validate_get_positions_shaperz   r   rL   
_positions_get_subranksr   r   r   )rM   r   r   r   r   r1   	positionsrO   r=   r=   r>   rL     s"   
zArrayDiagonal.__new__c                 C   s  | j }| j}dd |D }t|dkrdd t|D }dd t|D }dd |D }t| }t|}|| }	g }
d}t|tt|t|}|D ]*}||v r[|
	|	||   qKt
|ttfrl|
	| |d7 }qK|
	|	||   qKt|
}t|dkrtt|g|R  |S t||S t
|tr| j|g|R  S t
|tr| j|g|R  S t
|tr| j|g|R  S t
|ttfr| |j|\}}t| S | j|g|R d	d
iS )Nc                 S   s   g | ]
}t |d kr|qS r  rz   r\   r=   r=   r>   rb     r   z/ArrayDiagonal._canonicalize.<locals>.<listcomp>r   c                 S   s&   i | ]\}}t |d kr|d |qS rX   r   r  r)  r=   r=   r>   r     r   z/ArrayDiagonal._canonicalize.<locals>.<dictcomp>c                 S   s"   i | ]\}}t |d kr||qS r  r  r)  r=   r=   r>   r     r   c                 S   s   g | ]
}t |d kr|qS r  r  r\   r=   r=   r>   rb   	  r   rX   r   F)r   r   rz   r   r   r   _push_indices_downr   rf   r   r3   r
   intr-   r   r   r   _ArrayDiagonal_denest_ArrayAdd#_ArrayDiagonal_denest_ArrayDiagonalr   !_ArrayDiagonal_denest_PermuteDimsr   r   r  r1   r   )r;   r   r   trivial_diagstrivial_posdiag_posdiagonal_indices_shortrank1rank2rank3inv_permutationcounter1indices_downr^   r   r  r1   r=   r=   r>   r     sD   





zArrayDiagonal._canonicalizec                    s   t |  |D ]@}t fdd|D rtdt fdd|D dkr(td|dd	s8t|dkr8td
tt|t|krFtdqd S )Nc                 3   s    | ]	}|t  kV  qd S r2   r  rg   r   r=   r>   r_   .  rw   z*ArrayDiagonal._validate.<locals>.<genexpr>z%index is larger than expression shapec                    s   h | ]} | qS r=   r=   rg   r   r=   r>   r   0  rc   z*ArrayDiagonal._validate.<locals>.<setcomp>rX   z-diagonalizing indices of different dimensionsallow_trivial_diagsFz%need at least two axes to diagonalizezaxis index cannot be repeated)r   r{   rj   rz   r   r   )r   r   r   r^   r=   r   r>   r~  (  s   zArrayDiagonal._validatec                    s    fdd|D S )Nc                    s.   g | ]} |d   dkrt dd |D qS )r   rX   c                 s   s    | ]}|V  qd S r2   r=   rg   r=   r=   r>   r_   9  s    zFArrayDiagonal._remove_trivial_dimensions.<locals>.<listcomp>.<genexpr>r5  r\   r   r=   r>   rb   9     . z<ArrayDiagonal._remove_trivial_dimensions.<locals>.<listcomp>r=   )r1   r   r=   r   r>   _remove_trivial_dimensions7     z(ArrayDiagonal._remove_trivial_dimensionsc                 C   rP   rQ   r  rT   r=   r=   r>   r   ;  rV   zArrayDiagonal.exprc                 C      | j dd  S rW   r  rT   r=   r=   r>   r   ?     zArrayDiagonal.diagonal_indicesc                    s   | j }dd |D }|  t| }t|}|| }dd t|D  d}d}t|D ]*}	||k rI||| krI|d7 }|d7 }||k rI||| ks7 |	  |7  < |d7 }q+t fdd|D }|| }
t| jg|
R  S )Nc                 S   r  r=   r=   r~   r=   r=   r>   rb   F  r   z*ArrayDiagonal._flatten.<locals>.<listcomp>c                 S      g | ]}d qS r  r=   r\   r=   r=   r>   rb   L  r'  r   rX   c                 3   &    | ]}t  fd d|D V  qdS )c                 3       | ]	} | | V  qd S r2   r=   rg   shiftsr=   r>   r_   U  rw   z3ArrayDiagonal._flatten.<locals>.<genexpr>.<genexpr>Nr5  r\   r  r=   r>   r_   U     $ z)ArrayDiagonal._flatten.<locals>.<genexpr>)r   r!  r   rz   rf   rs   r   r   )r   outer_diagonal_indicesinner_diagonal_indices	all_inner
total_rank
inner_rank
outer_rankr:  pointerr^   r   r=   r  r>   r   C  s&   
zArrayDiagonal._flattenc                       t  fdd|jD  S )Nc                       g | ]
}t |g R  qS r=   )r   r   r   r=   r>   rb   [  r   z@ArrayDiagonal._ArrayDiagonal_denest_ArrayAdd.<locals>.<listcomp>rp  r   rM   r   r   r=   r  r>   r  Y     z,ArrayDiagonal._ArrayDiagonal_denest_ArrayAddc                 G      | j |g|R  S r2   r   r  r=   r=   r>   r  ]  r  z1ArrayDiagonal._ArrayDiagonal_denest_ArrayDiagonalr   c           	         s   fdd D } fddt tD }fdd|D }dd tt|D fdd|D }t|fddt t|D }|| }ttjg|R  |S )	Nc                    r-  )c                    ry  r=   rD  rg   r  r=   r>   rb   c  r  zNArrayDiagonal._ArrayDiagonal_denest_PermuteDims.<locals>.<listcomp>.<listcomp>r=   r\   r  r=   r>   rb   c  r   zCArrayDiagonal._ArrayDiagonal_denest_PermuteDims.<locals>.<listcomp>c                    &   g | ] t  fd dD s qS )c                 3       | ]} |v V  qd S r2   r=   rg   r   r=   r>   r_   d  r   zMArrayDiagonal._ArrayDiagonal_denest_PermuteDims.<locals>.<listcomp>.<genexpr>r{   r]   r  r   r>   rb   d  r   c                    ry  r=   rD  r\   r  r=   r>   rb   e  r  c                 S   s   i | ]\}}||qS r=   r=   r)  r=   r=   r>   r   f  r  zCArrayDiagonal._ArrayDiagonal_denest_PermuteDims.<locals>.<dictcomp>c                    ra   r=   r=   r\   )remapr=   r>   rb   g  rc   c                    s   g | ]}|  qS r=   r=   r\   )shiftr=   r>   rb   i  rc   )rf   r   r   r  rz   r   r   r   )	rM   r   r   back_diagonal_indicesnondiagback_nondiagnew_permutation1diag_block_permr&  r=   )r   r   r  r  r>   r  a  s    z/ArrayDiagonal._ArrayDiagonal_denest_PermuteDimsc                        fdd}t ||S )Nc                    s   | t  jk r j|  S d S r2   )rz   r  r  rT   r=   r>   r  t  r   z<ArrayDiagonal._push_indices_down_nonstatic.<locals>.<lambda>r%   r;   rt   	transformr=   rT   r>   _push_indices_down_nonstatics  s   
z*ArrayDiagonal._push_indices_down_nonstaticc                    r  )Nc                    sD   t  jD ]\}}t|tr| |kst|tr| |v r|  S qd S r2   )r   r  r3   r  rs   r  r^   r*  rT   r=   r>   r  y  s
   $z;ArrayDiagonal._push_indices_up_nonstatic.<locals>.transformr  r  r=   rT   r>   _push_indices_up_nonstaticw  s   
z(ArrayDiagonal._push_indices_up_nonstaticc                    *   |  t||\ } fdd}t||S )Nc                    s   | t  k r
 |  S d S r2   r  r  r  r=   r>   r    r   z2ArrayDiagonal._push_indices_down.<locals>.<lambda>r  rf   r%   rM   r   rt   rankr1   r  r=   r  r>   r    s   
z ArrayDiagonal._push_indices_downc                    r  )Nc                    sF   t  D ]\}}t|tr| |kst|ttfr | |v r |  S qd S r2   )r   r3   r  rs   r	   r  r  r=   r>   r    s
   (z1ArrayDiagonal._push_indices_up.<locals>.transformr  r  r=   r  r>   r7    s   
zArrayDiagonal._push_indices_upc           
         sp   t  fddtD }|rt| nd\}}t fdd D }|r(t| nd\}}|| }	|| |	fS )Nc                 3   s2    | ]\ }t  fd dD s |fV  qdS )c                 3   r  r2   r=   rg   r   r=   r>   r_     r   z?ArrayDiagonal._get_positions_shape.<locals>.<genexpr>.<genexpr>Nr  r]   shpr  r   r>   r_     s   0 z5ArrayDiagonal._get_positions_shape.<locals>.<genexpr>)r=   r=   c                 3   s     | ]}| |d   fV  qdS )r   Nr=   r\   r   r=   r>   r_     rv   )rs   r   r|   )
rM   r1   r   data1pos1shp1data2pos2shp2r  r=   )r   r1   r>   r    s   z"ArrayDiagonal._get_positions_shapec                 C   *   | j }t|dr| }t|g| jR  S rt  )r   rx   ro   r   r   ru  r=   r=   r>   ro        
zArrayDiagonal.as_explicitN)rC   rD   rE   rp   rL   r   staticmethodr~  r  rr   r   r   r   r   r  r  r   r  r  r  r  r7  r  ro   r=   r=   r=   r>   r     s:    &






	



	r   c                   @   sH   e Zd Zdd Zedd Zedd Zedd Zd	d
 Zdd Z	dS )ArrayElementwiseApplyFuncc                 C   s<   t |tstd}t|||}t| ||}t||_|S Nd)r3   r   r   r   rL   r  r   )rM   functionelementr  rO   r=   r=   r>   rL     s   

z!ArrayElementwiseApplyFunc.__new__c                 C   rP   rQ   r  rT   r=   r=   r>   r    rV   z"ArrayElementwiseApplyFunc.functionc                 C   rP   rW   r  rT   r=   r=   r>   r     rV   zArrayElementwiseApplyFunc.exprc                 C   s   | j jS r2   r   r1   rT   r=   r=   r>   r1     s   zArrayElementwiseApplyFunc.shapec                 C   s@   t d}| |}||}t|trt|}|S t||}|S r  )r   r  diffr3   r   typer   )r;   r  r  fdiffr=   r=   r>   _get_function_fdiff  s   



z-ArrayElementwiseApplyFunc._get_function_fdiffc                 C   s$   | j }t|dr| }|| jS rt  )r   rx   ro   	applyfuncr  ru  r=   r=   r>   ro     rv  z%ArrayElementwiseApplyFunc.as_explicitN)
rC   rD   rE   rL   rr   r  r   r1   r  ro   r=   r=   r=   r>   r    s    




r  c                   @   sN  e Zd ZdZdd Zdd Zdd Zdd	 Zed
d Z	e
dd Ze
dd Ze
dd Zdd Zdd Zedd Zedd Zedd Zedd Ze
dd Ze
d d! Ze
d"d# Ze
d$d% Ze
dAd(d)Ze
d*d+ Zd,d- Zed.d/ Zed0d1 Zed2d3 Zed4d5 Zed6d7 Z d8d9 Z!d:d; Z"d<d= Z#d>d? Z$d@S )Br   zx
    This class is meant to represent contractions of arrays in a form easily
    processable by the code printers.
    c                    s   t   t|}|dd}tj| |g R  }t||_t|j|_ fddt	t
|jD }||_t|}| j|g R   |rPt fddt|D }||_|rY| S |S )Nr   Fc                    s(   i | ] t  fd dD r  qS )c                 3   s    | ]} |vV  qd S r2   r=   )r]   cindr   r=   r>   r_     r   z6ArrayContraction.__new__.<locals>.<dictcomp>.<genexpr>)ri   r  r   r   r>   r     rC  z,ArrayContraction.__new__.<locals>.<dictcomp>c                 3   s.    | ]\ }t  fd dD s|V  qdS )c                 3   r  r2   r=   rg   r   r=   r>   r_     r   z5ArrayContraction.__new__.<locals>.<genexpr>.<genexpr>Nr  r  r  r   r>   r_     s   , z+ArrayContraction.__new__.<locals>.<genexpr>)r&   r/   r   r   rL   r  r   r'   _mappingrf   r   _free_indices_to_positionr   r~  rs   r   r   r   )rM   r   r   r   r   rO   free_indices_to_positionr1   r=   r  r>   rL     s    
zArrayContraction.__new__c                    s   | j  | j}t|dkr S t tr| j g|R  S t ttfr,| j g|R  S t t	r:| j
 g|R  S t trW|  |\ }|  |\ }t|dkrW S t tre| j g|R  S t trs| j g|R  S  fdd|D }t|dkr S | j g|R ddiS )Nr   c                    s0   g | ]}t |d kst |d  d kr|qS r  )rz   r   r\   r  r=   r>   rb     r,  z2ArrayContraction._canonicalize.<locals>.<listcomp>r   F)r   r   rz   r3   r   )_ArrayContraction_denest_ArrayContractionr   r   "_ArrayContraction_denest_ZeroArrayr   $_ArrayContraction_denest_PermuteDimsr   _sort_fully_contracted_args_lower_contraction_to_addendsr   &_ArrayContraction_denest_ArrayDiagonalr   !_ArrayContraction_denest_ArrayAddr   )r;   r   r=   r  r>   r     s.   




zArrayContraction._canonicalizec                 C      |dkr| S t dNrX   zDProduct of N-dim arrays is not uniquely defined. Use another method.r   r;   otherr=   r=   r>   __mul__
     zArrayContraction.__mul__c                 C   r  r  r  r  r=   r=   r>   __rmul__  r  zArrayContraction.__rmul__c                    sD   t |   d u r
d S |D ]}t fdd|D dkrtdqd S )Nc                    s    h | ]} | d kr | qS r   r=   rg   r   r=   r>   r     r   z-ArrayContraction._validate.<locals>.<setcomp>rX   z+contracting indices of different dimensions)r   rz   rj   )r   r   r^   r=   r   r>   r~    s   zArrayContraction._validatec                 C   (   dd |D }|   t|}t||S )Nc                 S   r  r=   r=   r~   r=   r=   r>   rb   #  r   z7ArrayContraction._push_indices_down.<locals>.<listcomp>)r!  r*   r%   rM   r   rt   flattened_contraction_indicesr  r=   r=   r>   r  !     
z#ArrayContraction._push_indices_downc                 C   r  )Nc                 S   r  r=   r=   r~   r=   r=   r>   rb   *  r   z5ArrayContraction._push_indices_up.<locals>.<listcomp>)r!  r(   r%   r  r=   r=   r>   r7  (  r  z!ArrayContraction._push_indices_upc           
         sN  t |trt t |ts||fS |j}ttdg| g }dd |jD }tg  t	|D ]>\}}t
t|jD ]-t |j tsEq:tfdd|D rg| fdd|D   |  nq:|| q/t|t|krz||fS t|}tt fddt
|D fdd|D }td	d t|j|D  }	|	|fS )
Nr   c                 S      g | ]}g qS r=   r=   r\   r=   r=   r>   rb   8  r'  zBArrayContraction._lower_contraction_to_addends.<locals>.<listcomp>c                 3   s4    | ]}  |  ko d   k n  V  qdS )rX   Nr=   r   cumranksrh   r=   r>   r_   >  s   2 zAArrayContraction._lower_contraction_to_addends.<locals>.<genexpr>c                    r`  r=   r=   r   r  r=   r>   rb   ?  r   c                    s   g | ]
}| v r
d ndqS r  r=   r\   )	backshiftr=   r>   rb   G  r   c                    s$   g | ]}t  fd d|D qS )c                 3   s    | ]	}| |  V  qd S r2   r=   rg   r  r=   r>   r_   H  rw   zLArrayContraction._lower_contraction_to_addends.<locals>.<listcomp>.<genexpr>)r	   r   r\   r  r=   r>   rb   H  r  c                 S   s    g | ]\}}t |g|R  qS r=   r   )r]   r   contrr=   r=   r>   rb   I  s    )r3   r   r   r   r   r   r   r   r   r   rf   rz   ri   r   updater   r   r|   )
rM   r   r   r   contraction_indices_remainingcontraction_indices_argsr^   contraction_groupr  ri  r=   )r  r  rh   r  r>   r  /  s:   




z.ArrayContraction._lower_contraction_to_addendsc                    s  t | }| j}g }t|D ]\ }t|dkrq| }| jj|d  }g }g }|D ]H\}	}
|j|	 }|j}|	|\}}d|
 }|| d|jvsd|dkdu rV|jdksdt
 fddt|D rl|||
f q+|||
f q+t|dkr{q|D ]
\}}
t|j|_q}|dd | |dd  }|d \}}
|j|
 }|dd	 D ]'\}}
||j|
< | }|jdd|
 ksJ ||j|jd< || q|d	 \}}
||j|
< q|D ]}||ttddg q| S )
a`  
        Recognize multiple contractions and attempt at rewriting them as paired-contractions.

        This allows some contractions involving more than two indices to be
        rewritten as multiple contractions involving two indices, thus allowing
        the expression to be rewritten as a matrix multiplication line.

        Examples:

        * `A_ij b_j0 C_jk` ===> `A*DiagMatrix(b)*C`

        Care for:
        - matrix being diagonalized (i.e. `A_ii`)
        - vectors being diagonalized (i.e. `a_i0`)

        Multiple contractions can be split into matrix multiplications if
        not more than two arguments are non-diagonals or non-vectors.
        Vectors get diagonalized while diagonal matrices remain diagonal.
        The non-diagonal matrices can be at the beginning or at the end
        of the final matrix multiplication line.
           r   rX   T)rX   rX   c                 3   s$    | ]\}}| kr|v V  qd S r2   r=   )r]   lilindlother_arg_absr=   r>   r_     s   " z?ArrayContraction.split_multiple_contractions.<locals>.<genexpr>Nr   )_EditArrayContractionr   r   rz   get_mapping_for_indexr   r1   args_with_indr  get_absolute_ranger{   r   r   rt   get_new_contraction_indexr{  insert_after_ArgEr   to_array_contraction)r;   editorr   onearray_insertlinksr  current_dimensionnot_vectorsvectorsarg_indrel_indr   matabs_arg_startabs_arg_endother_arg_posrY  vectors_to_loopfirst_not_vector	new_indexlast_vecr=   r  r>   split_multiple_contractionsN  sV   





z,ArrayContraction.split_multiple_contractionsc                    s   t | jts| S | j| jj| j}g }| jjd d  }|D ]0}t|}|D ]fdd|D  |dd  D   fdd|D }q&|t	t
| qt||}tt| jjg|R  g|R  S )Nc                    s   g | ]} |v r|qS r=   r=   r   )rh   r=   r>   rb     r   zDArrayContraction.flatten_contraction_of_diagonal.<locals>.<listcomp>c                 S   r  r=   r=   )r]   r   r  r=   r=   r>   rb     r   c                    s   g | ]}| vr|qS r=   r=   r   )diagonal_withr=   r>   rb     r   )r3   r   r   r  r   r   r   r   r   r  r   r7  r   r   )r;   contraction_downrA  r   r^   r  r=   )r  rh   r>   flatten_contraction_of_diagonal  s,   z0ArrayContraction.flatten_contraction_of_diagonalc                 C   sL   i }dd |D }d}| D ]}||v r|d7 }||v s|||< |d7 }q|S )Nc                 S   r  r=   r=   r~   r=   r=   r>   rb     r   zFArrayContraction._get_free_indices_to_position_map.<locals>.<listcomp>r   rX   r=   )free_indicesr   r  r  r:  indr=   r=   r>   !_get_free_indices_to_position_map  s   
z2ArrayContraction._get_free_indices_to_position_mapc           
      C   s   | j }dd |D }|  t| }t|}|| }dd t|D }d}d}t|D ]*}	||k rI||| krI|d7 }|d7 }||k rI||| ks7||	  |7  < |d7 }q+|S )a  
        Get the mapping of indices at the positions before the contraction
        occurs.

        Examples
        ========

        >>> from sympy.tensor.array import tensorproduct, tensorcontraction
        >>> from sympy import MatrixSymbol
        >>> M = MatrixSymbol("M", 3, 3)
        >>> N = MatrixSymbol("N", 3, 3)
        >>> cg = tensorcontraction(tensorproduct(M, N), [1, 2])
        >>> cg._get_index_shifts(cg)
        [0, 2]

        Indeed, ``cg`` after the contraction has two dimensions, 0 and 1. They
        need to be shifted by 0 and 2 to get the corresponding positions before
        the contraction (that is, 0 and 3).
        c                 S   r  r=   r=   r~   r=   r=   r>   rb     r   z6ArrayContraction._get_index_shifts.<locals>.<listcomp>c                 S   r  r  r=   r\   r=   r=   r>   rb     r'  r   rX   )r   r!  r   rz   rf   )
r   inner_contraction_indicesr  r  r  r  r  r:  r  r^   r=   r=   r>   _get_index_shifts  s"   
z"ArrayContraction._get_index_shiftsc                    s$   t |  t fdd|D }|S )Nc                 3   r  )c                 3   r  r2   r=   rg   r  r=   r>   r_     rw   zUArrayContraction._convert_outer_indices_to_inner_indices.<locals>.<genexpr>.<genexpr>Nr5  r\   r  r=   r>   r_     r  zKArrayContraction._convert_outer_indices_to_inner_indices.<locals>.<genexpr>)r   r%  rs   )r   outer_contraction_indicesr=   r  r>   ro    s   
z8ArrayContraction._convert_outer_indices_to_inner_indicesc                 G   s2   | j }tj| g|R  }|| }t| jg|R  S r2   )r   r   ro  r   r   )r   r&  r$  r   r=   r=   r>   r     s   zArrayContraction._flattenc                 G   r  r2   r  rM   r   r   r=   r=   r>   r  	  r  z:ArrayContraction._ArrayContraction_denest_ArrayContractionc                    s.   dd |D   fddt |jD }t| S )Nc                 S   r  r=   r=   r~   r=   r=   r>   rb     r   zGArrayContraction._ArrayContraction_denest_ZeroArray.<locals>.<listcomp>c                    s   g | ]
\}}| vr|qS r=   r=   r)  r8  r=   r>   rb     r   )r   r1   r   )rM   r   r   r1   r=   r(  r>   r    s   z3ArrayContraction._ArrayContraction_denest_ZeroArrayc                    r  )Nc                    r  r=   r  r\   r  r=   r>   rb     r   zFArrayContraction._ArrayContraction_denest_ArrayAdd.<locals>.<listcomp>r  r'  r=   r  r>   r    r  z2ArrayContraction._ArrayContraction_denest_ArrayAddc                    sX   |j j}fdd|D   fdd|D }|  |}tt|jg R  t|S )Nc                    r1  )c                 3   rk  r2   r=   rg   rD  r=   r>   r_     r   SArrayContraction._ArrayContraction_denest_PermuteDims.<locals>.<listcomp>.<genexpr>r5  r\   rD  r=   r>   rb     r   zIArrayContraction._ArrayContraction_denest_PermuteDims.<locals>.<listcomp>c                    r  )c                 3   r  r2   r=   rg   r   r=   r>   r_     r   r)  r  r  )rA  r   r>   rb     r   )r   r
  r7  r   r   r   r,   )rM   r   r   r  	new_plistr=   )rA  r   r>   r    s   z5ArrayContraction._ArrayContraction_denest_PermuteDimsr   r   c                    s   t |j}||j|t|j}dd |D }g }|D ]3}|d d  }t|D ]\}  d u r0q't fdd|D rD|  d ||< q'|t	t
| qdd |D }	t||	}
tt|jg|R  g|
R  S )Nc                 S   s   g | ]	}d d |D qS )c                 S   s.   g | ]}t |ttfr|n|gD ]}|qqS r=   )r3   rs   r	   r]   rh   r   r=   r=   r>   rb   (  r  zVArrayContraction._ArrayContraction_denest_ArrayDiagonal.<locals>.<listcomp>.<listcomp>r=   r\   r=   r=   r>   rb   (  r   zKArrayContraction._ArrayContraction_denest_ArrayDiagonal.<locals>.<listcomp>c                 3       | ]}| v V  qd S r2   r=   r\   diag_indgrpr=   r>   r_   /  r   zJArrayContraction._ArrayContraction_denest_ArrayDiagonal.<locals>.<genexpr>c                 S   s   g | ]}|d ur|qS r2   r=   r\   r=   r=   r>   rb   4  r   )r   r   r  r   r   r   r{   r   r   r  r   r   r7  r   r   )rM   r   r   r   down_contraction_indicesrA  contr_indgrpr"  rh   new_diagonal_indices_downnew_diagonal_indicesr=   r-  r>   r  #  s*   

z7ArrayContraction._ArrayContraction_denest_ArrayDiagonalc                    s   j d u r	|fS ttdgj fddttjD dd |D   fddtjD tttjfddd	}fd
d|D }fdd|D }t	|fdd|D }t
|}t| |fS )Nr   c                    s&   g | ]}t t |  |d   qS r  )r   rf   r\   r+  r=   r>   rb   @  r   z@ArrayContraction._sort_fully_contracted_args.<locals>.<listcomp>c                 S   s   h | ]	}|D ]}|qqS r=   r=   r~   r=   r=   r>   r   A  r   z?ArrayContraction._sort_fully_contracted_args.<locals>.<setcomp>c              	      s8   g | ]\}}t  fd dt| |d  D qS )c                 3   r,  r2   r=   rg   r(  r=   r>   r_   B  r   JArrayContraction._sort_fully_contracted_args.<locals>.<listcomp>.<genexpr>rX   )ri   rf   r   )r8  r  r=   r>   rb   B  s   8 c                    s   |  rdt  j|  fS dS )Nr   r  )r   r   r  )r   fully_contractedr=   r>   r  C  r   z>ArrayContraction._sort_fully_contracted_args.<locals>.<lambda>r  c                    r  r=   r  r\   r  r=   r>   rb   D  r  c                    s   g | ]} | D ]}|qqS r=   r=   r~   r/  r=   r>   rb   E  r   c                    r1  )c                 3   r2  r2   r=   rg   index_permutation_array_formr=   r>   r_   G  r   r3  r5  r\   r5  r=   r>   rb   G  r   )r1   r   r   r   rf   rz   r   r   r  r-   r&   r   )rM   r   r   new_posr   new_index_blocks_flatrA  r=   )r8  r  r   r4  r0  r6  r>   r  ;  s   
 z,ArrayContraction._sort_fully_contracted_argsc                    s   | j   fdd| jD S )a  
        Return tuples containing the argument index and position within the
        argument of the index position.

        Examples
        ========

        >>> from sympy import MatrixSymbol
        >>> from sympy.abc import N
        >>> from sympy.tensor.array import tensorproduct, tensorcontraction
        >>> A = MatrixSymbol("A", N, N)
        >>> B = MatrixSymbol("B", N, N)

        >>> cg = tensorcontraction(tensorproduct(A, B), (1, 2))
        >>> cg._get_contraction_tuples()
        [[(0, 1), (1, 0)]]

        Notes
        =====

        Here the contraction pair `(1, 2)` meaning that the 2nd and 3rd indices
        of the tensor product `A\otimes B` are contracted, has been transformed
        into `(0, 1)` and `(1, 0)`, identifying the same indices in a different
        notation. `(0, 1)` is the second index (1) of the first argument (i.e.
                0 or `A`). `(1, 0)` is the first index (i.e. 0) of the second
        argument (i.e. 1 or `B`).
        c                    r-  )c                    ra   r=   r=   rg   mappingr=   r>   rb   h  rc   zGArrayContraction._get_contraction_tuples.<locals>.<listcomp>.<listcomp>r=   r\   r9  r=   r>   rb   h  r   z<ArrayContraction._get_contraction_tuples.<locals>.<listcomp>)r  r   rT   r=   r9  r>   _get_contraction_tuplesK  s   z(ArrayContraction._get_contraction_tuplesc                    s*   | j }dgtt|   fdd|D S )Nr   c                    r1  )c                 3   s     | ]\}} | | V  qd S r2   r=   r+  r   r=   r>   r_   o  rv   zYArrayContraction._contraction_tuples_to_contraction_indices.<locals>.<listcomp>.<genexpr>r5  r\   r   r=   r>   rb   o  r   zOArrayContraction._contraction_tuples_to_contraction_indices.<locals>.<listcomp>)r   r   r   )r   contraction_tuplesr   r=   r   r>   *_contraction_tuples_to_contraction_indicesj  s   z;ArrayContraction._contraction_tuples_to_contraction_indicesc                 C   s   | j d d  S r2   )_free_indicesrT   r=   r=   r>   r!  q  r  zArrayContraction.free_indicesc                 C   r   r2   )dictr  rT   r=   r=   r>   r  u  rV   z)ArrayContraction.free_indices_to_positionc                 C   rP   rQ   r  rT   r=   r=   r>   r   y  rV   zArrayContraction.exprc                 C   r  rW   r  rT   r=   r=   r>   r   }  r  z$ArrayContraction.contraction_indicesc                 C   s^   | j }t|tstd|j}i }d}t|D ]\}}t|D ]}||f||< |d7 }qq|S )Nz(only for contractions of tensor productsr   rX   )r   r3   r   r   r   r   rf   )r;   r   r   r:  r:  r^   r  rh   r=   r=   r>   "_contraction_indices_to_components  s   

z3ArrayContraction._contraction_indices_to_componentsc                    s   | j }t|ts
| S |j}tt|dd d}t| \ } fddt|D |  }fdd|D }t| }| 	||}t
|g|R  S )a  
        Sort arguments in the tensor product so that their order is lexicographical.

        Examples
        ========

        >>> from sympy.tensor.array.expressions.conv_matrix_to_array import convert_matrix_to_array
        >>> from sympy import MatrixSymbol
        >>> from sympy.abc import N
        >>> A = MatrixSymbol("A", N, N)
        >>> B = MatrixSymbol("B", N, N)
        >>> C = MatrixSymbol("C", N, N)
        >>> D = MatrixSymbol("D", N, N)

        >>> cg = convert_matrix_to_array(C*D*A*B)
        >>> cg
        ArrayContraction(ArrayTensorProduct(A, D, C, B), (0, 3), (1, 6), (2, 5))
        >>> cg.sort_args_by_name()
        ArrayContraction(ArrayTensorProduct(A, D, B, C), (0, 3), (1, 4), (2, 7))
        c                 S   s   t | d S rW   r   r  r=   r=   r>   r    s    z4ArrayContraction.sort_args_by_name.<locals>.<lambda>r  c                    s   i | ]
\}}|  |qS r=   rz  r   )
pos_sortedr=   r>   r     r   z6ArrayContraction.sort_args_by_name.<locals>.<dictcomp>c                    r-  )c                    s   g | ]
\}} | |fqS r=   r=   r+  reordering_mapr=   r>   rb     r   zAArrayContraction.sort_args_by_name.<locals>.<listcomp>.<listcomp>r=   r\   rB  r=   r>   rb     r   z6ArrayContraction.sort_args_by_name.<locals>.<listcomp>)r   r3   r   r   r  r   r|   r;  r   r=  r   )r;   r   r   sorted_datar$  r<  c_tprs  r=   )rA  rC  r>   sort_args_by_name  s   
z"ArrayContraction.sort_args_by_namec                 C   s    t | g| jg| jR  \}}|S )ao  
        Returns a dictionary of links between arguments in the tensor product
        being contracted.

        See the example for an explanation of the values.

        Examples
        ========

        >>> from sympy import MatrixSymbol
        >>> from sympy.abc import N
        >>> from sympy.tensor.array.expressions.conv_matrix_to_array import convert_matrix_to_array
        >>> A = MatrixSymbol("A", N, N)
        >>> B = MatrixSymbol("B", N, N)
        >>> C = MatrixSymbol("C", N, N)
        >>> D = MatrixSymbol("D", N, N)

        Matrix multiplications are pairwise contractions between neighboring
        matrices:

        `A_{ij} B_{jk} C_{kl} D_{lm}`

        >>> cg = convert_matrix_to_array(A*B*C*D)
        >>> cg
        ArrayContraction(ArrayTensorProduct(B, C, A, D), (0, 5), (1, 2), (3, 6))

        >>> cg._get_contraction_links()
        {0: {0: (2, 1), 1: (1, 0)}, 1: {0: (0, 1), 1: (3, 0)}, 2: {1: (0, 0)}, 3: {0: (1, 1)}}

        This dictionary is interpreted as follows: argument in position 0 (i.e.
        matrix `A`) has its second index (i.e. 1) contracted to `(1, 0)`, that
        is argument in position 1 (matrix `B`) on the first index slot of `B`,
        this is the contraction provided by the index `j` from `A`.

        The argument in position 1 (that is, matrix `B`) has two contractions,
        the ones provided by the indices `j` and `k`, respectively the first
        and second indices (0 and 1 in the sub-dict).  The link `(0, 1)` and
        `(2, 0)` respectively. `(0, 1)` is the index slot 1 (the 2nd) of
        argument in position 0 (that is, `A_{\ldot j}`), and so on.
        )r)   r   r   )r;   r   dlinksr=   r=   r>   r)     s   )z'ArrayContraction._get_contraction_linksc                 C   r  rt  )r   rx   ro   r   r   ru  r=   r=   r>   ro     r  zArrayContraction.as_explicitN)r   r   )%rC   rD   rE   rp   rL   r   r  r  r  r~  r   r  r7  r  r  r   r#  r%  ro  r   r  r  r  r  r  r  r;  r=  rr   r!  r  r   r   r@  rF  r)   ro   r=   r=   r=   r>   r     sf    #




d

&











%,r   c                   @   s@   e Zd ZdZdd Zedd Zedd Zdd	 Zd
d Z	dS )Reshapea  
    Reshape the dimensions of an array expression.

    Examples
    ========

    >>> from sympy.tensor.array.expressions import ArraySymbol, Reshape
    >>> A = ArraySymbol("A", (6,))
    >>> A.shape
    (6,)
    >>> Reshape(A, (3, 2)).shape
    (3, 2)

    Check the component-explicit forms:

    >>> A.as_explicit()
    [A[0], A[1], A[2], A[3], A[4], A[5]]
    >>> Reshape(A, (3, 2)).as_explicit()
    [[A[0], A[1]], [A[2], A[3]], [A[4], A[5]]]

    c                 C   s`   t |}t|tst| }tt|jt|dkrtdt	| ||}t
||_||_|S )NFzshape mismatch)r/   r3   r	   r   r   r   r1   rj   r   rL   rs   r   _expr)rM   r   r1   rO   r=   r=   r>   rL     s   

zReshape.__new__c                 C   r   r2   r   rT   r=   r=   r>   r1     r   zReshape.shapec                 C   r   r2   )rI  rT   r=   r=   r>   r     r   zReshape.exprc                 O   sL   | ddr| jj|i |}n| j}t|ttfr |j| j S t|| jS )Nr   T)	r   r   r   r3   r   r!   rm   r1   rH  )r;   r   r   r   r=   r=   r>   r     s   zReshape.doitc                 C   sR   | j }t|dr| }t|trddlm} ||}nt|tr#| S |j| j	 S )Nro   r   )Array)
r   rx   ro   r3   r   sympyrJ  r   rm   r1   )r;   eerJ  r=   r=   r>   ro     s   



zReshape.as_explicitN)
rC   rD   rE   rp   rL   rr   r1   r   r   ro   r=   r=   r=   r>   rH    s    

	rH  c                   @   sJ   e Zd ZU dZeee  ed< ddeeee   fddZdd Z	e	Z
dS )	r  al  
    The ``_ArgE`` object contains references to the array expression
    (``.element``) and a list containing the information about index
    contractions (``.indices``).

    Index contractions are numbered and contracted indices show the number of
    the contraction. Uncontracted indices have ``None`` value.

    For example:
    ``_ArgE(M, [None, 3])``
    This object means that expression ``M`` is part of an array contraction
    and has two indices, the first is not contracted (value ``None``),
    the second index is contracted to the 4th (i.e. number ``3``) group of the
    array contraction object.
    rt   Nc                 C   s4   || _ |d u rdd tt|D | _d S || _d S )Nc                 S   r  r2   r=   r\   r=   r=   r>   rb   :  r'  z"_ArgE.__init__.<locals>.<listcomp>)r  rf   r   rt   )r;   r  rt   r=   r=   r>   __init__7  s   
z_ArgE.__init__c                 C      d| j | jf S )Nz_ArgE(%s, %s))r  rt   rT   r=   r=   r>   __str__>     z_ArgE.__str__r2   )rC   rD   rE   rp   r   r   r  rG   rM  rO  __repr__r=   r=   r=   r>   r  %  s   
 r  c                   @   s6   e Zd ZdZdedefddZdd ZeZdd	 Zd
S )_IndPosz
    Index position, requiring two integers in the constructor:

    - arg: the position of the argument in the tensor product,
    - rel: the relative position of the index inside the argument.
    r   relc                 C   s   || _ || _d S r2   r   rS  )r;   r   rS  r=   r=   r>   rM  K  s   
z_IndPos.__init__c                 C   rN  )Nz_IndPos(%i, %i)rT  rT   r=   r=   r>   rO  O  rP  z_IndPos.__str__c                 c   s    | j | jgE d H  d S r2   rT  rT   r=   r=   r>   __iter__T  s   z_IndPos.__iter__N)	rC   rD   rE   rp   r  rM  rO  rQ  rU  r=   r=   r=   r>   rR  D  s    rR  c                   @   s   e Zd ZdZdejeeef fddZ	de
de
fddZd	d
 Zdd Zdd Zdd Zdeee  fddZdee fddZdeee  fddZdedefddZdedee
 fddZedd Zdd  Zd!e
d"e
fd#d$Zde
dejeef fd%d&Zde
dejeef fd'd(Zd)S )*r  a  
    Utility class to help manipulate array contraction objects.

    This class takes as input an ``ArrayContraction`` object and turns it into
    an editable object.

    The field ``args_with_ind`` of this class is a list of ``_ArgE`` objects
    which can be used to easily edit the contraction structure of the
    expression.

    Once editing is finished, the ``ArrayContraction`` object may be recreated
    by calling the ``.to_array_contraction()`` method.
    
base_arrayc                 C   s  t |trt|j}|j}|j}d}nNt |trRt |jtr6t|jj}|jj}t|jj|j}|jj}n+t |jt	rGi }|j}|j}g }ni }|j}|j}g }nt |t	r^|}g }d}nt
 t |t	rlt|j}n|g}dd |D }t|D ]\}}	|	D ]}
||
 \}}||| j|< qqz|| _t|| _d | _t|j}t|D ]\}}|D ]}
||
 \}}d| | j| j|< qqd S )Nr=   c                 S   rd   r=   )r  r   r=   r=   r>   rb     rc   z2_EditArrayContraction.__init__.<locals>.<listcomp>r   )r3   r   r'   r   r   r   r   r  r   r   r   r   r   r   rt   r  rz   number_of_contraction_indices_track_permutation)r;   rV  r:  r   r   diagonalizedr   r  r^   contraction_tuplerh   arg_posrel_posr*  r=   r=   r>   rM  g  sX   







z_EditArrayContraction.__init__r   new_argc                 C   s"   | j |}| j |d | d S rW   )r  r{  insert)r;   r   r]  posr=   r=   r>   r
    s   z"_EditArrayContraction.insert_afterc                 C   s   |  j d7  _ | j d S rW   )rW  rT   r=   r=   r>   r	    s   
z/_EditArrayContraction.get_new_contraction_indexc                    st   i  | j D ]} dd |jD  qtt D ]\}}| |< qt | _| j D ]} fdd|jD |_q*d S )Nc                 S   s   i | ]	}|d ur|dqS )Nr   r=   r\   r=   r=   r>   r     r   z9_EditArrayContraction.refresh_indices.<locals>.<dictcomp>c                    s   g | ]}  |d qS r2   )r   r\   updatesr=   r>   rb     r   z9_EditArrayContraction.refresh_indices.<locals>.<listcomp>)r  r  rt   r   r  rz   rW  )r;   arg_with_indr^   r*  r=   r`  r>   refresh_indices  s   



z%_EditArrayContraction.refresh_indicesc                 C   s   g }| j D ]}t|jdkr|| q|D ]}| j | qtdd |D }t| j dkr:| j t| d S ddlm	} ||| j d j
| j d _
d S )Nr   c                 S   r   r=   r  r\   r=   r=   r>   rb     r   z7_EditArrayContraction.merge_scalars.<locals>.<listcomp>)_a2m_tensor_product)r  rz   rt   r   remover   r   r  3sympy.tensor.array.expressions.conv_array_to_matrixre  r  )r;   scalarsrb  r^   scalarre  r=   r=   r>   merge_scalars  s   

z#_EditArrayContraction.merge_scalarsc                 C   s  d}t t}t }| jD ]
}|t|j q|d  }g }g }tg }d}	| jD ]p}d}
|jD ]S}|d u rC||	 |
d7 }
|	d7 }	q/|dkrHq/|d|  ||
  || dkrl||vrl||d |  || n||vr~||d |  || |
d7 }
q/dd |jD |_|t	dd |jD 7 }q(|| }t
|}dd | D }|   |   dd | jD }|  }tt| g|R  }t|g|R  }| jd urt
d	d | jD }t||}t||}|S )
Nr   rX   r   c                 S   s$   g | ]}|d ur|dkr|nd qS rQ   r=   r\   r=   r=   r>   rb     r  z>_EditArrayContraction.to_array_contraction.<locals>.<listcomp>c                 S   s    g | ]}|d u s|dk r|qS rQ   r=   r\   r=   r=   r>   rb     r   c                 S   s    g | ]}t |d krt|qS r  )rz   rs   )r]   rY  r=   r=   r>   rb     r   c                 S   r   r=   rd  r   r=   r=   r>   rb     r   c                 S   r  r=   r=   r~   r=   r=   r>   rb     r   )r   r   r   r  r  rt   r   r   r   rz   r-   valuesrj  rc  get_contraction_indicesr   r   r   rX  r   )r;   r:  diag_indicescount_index_freqrb  free_index_count	inv_perm1	inv_perm2donecounter4counter2r^   r   r   diag_indices_filteredr   r   r   expr2permutation2expr3r=   r=   r>   r    sX   








z*_EditArrayContraction.to_array_contractionrI   c                 C   sZ   dd t | jD }d}t| jD ]\}}|jD ]}|d ur%|| | |d7 }qq|S )Nc                 S   r  r=   r=   r\   r=   r=   r>   rb     r'  zA_EditArrayContraction.get_contraction_indices.<locals>.<listcomp>r   rX   )rf   rW  r   r  rt   r   )r;   r   current_positionr^   rb  rh   r=   r=   r>   rl    s   

z-_EditArrayContraction.get_contraction_indicesc                 C   sZ   || j kr	tdg }t| jD ]\}}t|jD ]\}}||kr)|t|| qq|S )Nz%index value exceeding the index range)rW  rj   r   r  rt   r   rR  )r;   r"  r  r^   rb  rh   r  r=   r=   r>   r    s   
z+_EditArrayContraction.get_mapping_for_indexc                 C   s\   dd t | jD }t| jD ]\}}t|jD ]\}}|d ur*|| t|| qq|S )Nc                 S   r  r=   r=   r\   r=   r=   r>   rb     r'  zP_EditArrayContraction.get_contraction_indices_to_ind_rel_pos.<locals>.<listcomp>)rf   rW  r   r  rt   r   rR  )r;   r   r^   rb  rh   r"  r=   r=   r>   &get_contraction_indices_to_ind_rel_pos  s   z<_EditArrayContraction.get_contraction_indices_to_ind_rel_posr{  c                 C   s&   d}| j D ]}||jv r|d7 }q|S )zJ
        Count the number of arguments that have the given index.
        r   rX   )r  rt   )r;   r{  r:  rb  r=   r=   r>   count_args_with_index  s   

z+_EditArrayContraction.count_args_with_indexc                    s    fdd| j D }|S )zA
        Get a list of arguments having the given index.
        c                    s   g | ]	} |j v r|qS r=   )rt   r\   rz  r=   r>   rb   -  r   z=_EditArrayContraction.get_args_with_index.<locals>.<listcomp>)r  )r;   r{  ri  r=   rz  r>   get_args_with_index)  s   z)_EditArrayContraction.get_args_with_indexc                 C   s2   t g }| jD ]}|dd |jD  qt|S )Nc                 S   s    h | ]}|d ur|dk r|qS rQ   r=   r\   r=   r=   r>   r   4  r   zC_EditArrayContraction.number_of_diagonal_indices.<locals>.<setcomp>)r   r  r  rt   rz   )r;   rn   r   r=   r=   r>   number_of_diagonal_indices0  s   
z0_EditArrayContraction.number_of_diagonal_indicesc                    s   g }g }d}d}| j D ]*}g }|jD ]}|d ur&|dk r%|| |d8 }q|| |d7 }q|| q|rAtdd |D nd  fdd|D }||g | _d S )Nr   r   rX   c                 S   s   g | ]
}|r
t |nd qS r  r^  r\   r=   r=   r>   rb   G  r   zA_EditArrayContraction.track_permutation_start.<locals>.<listcomp>c                    s   g | ]} | qS r=   r=   r\   max_indr=   r>   rb   H  rc   )r  rt   r   r_  rX  )r;   r   	perm_diagr:  rt  rb  permr^   r=   r~  r>   track_permutation_start7  s$   




z-_EditArrayContraction.track_permutation_startdestinationfrom_elementc                 C   s>   | j |}| j |}| j| | j|  | j| d S r2   )r  r{  rX  r   r   )r;   r  r  index_destinationindex_elementr=   r=   r>   track_permutation_mergeK  s   z-_EditArrayContraction.track_permutation_mergec                 C   sL   d}| j D ]}tdd |jD }||kr||| f  S ||7 }qtd)zw
        Return the range of the free indices of the arg as absolute positions
        among all free indices.
        r   c                 S   s   g | ]}|d u r|qS r2   r=   r\   r=   r=   r>   rb   X  r   zA_EditArrayContraction.get_absolute_free_range.<locals>.<listcomp>argument not foundr  rz   rt   ry   )r;   r   r:  rb  number_free_indicesr=   r=   r>   get_absolute_free_rangeQ  s   

z-_EditArrayContraction.get_absolute_free_rangec                 C   sB   d}| j D ]}t|j}||kr||| f  S ||7 }qtd)zc
        Return the absolute range of indices for arg, disregarding dummy
        indices.
        r   r  r  )r;   r   r:  rb  number_indicesr=   r=   r>   r  ^  s   


z(_EditArrayContraction.get_absolute_rangeN)rC   rD   rE   rp   rq   Unionr   r   r   rM  r  r
  r	  rc  rj  r  r   r  rl  rR  r  rz  r{  r|  rr   r}  r  r  r	   r  r  r=   r=   r=   r>   r  X  s&    9
C



 r  c                 C   s   t | ttfr	dS t | trt| jS t | tr|  S t | tr$| jS t | t	r6| j}|d u r2dS t|S t
| dr@t| jS dS )Nr  r   r1   r   )r3   r   r$   r   rz   r1   r!   r  r"   r#   rx   r  r=   r=   r>   r   l  s    






r   c                 C   s   t | tr	|  S t| S r2   )r3   r   r   r   r  r=   r=   r>   r     s   
r   c                 C   s   t | tr| jS t| gS r2   )r3   r   r   r   r  r=   r=   r>   r    s   

r  c                 C   s   t | dr| jS dS )Nr1   r=   )rx   r1   r  r=   r=   r>   r     s   
r   c                 C   s   t | tr	|  S | S r2   )r3   r   rj  r  r=   r=   r>   rj    s   
rj  c                  O      t | ddi|S Nr   T)r   r   r   r=   r=   r>   r        r   c                 O      t | g|R ddi|S r  )r   )r   r   r   r=   r=   r>   r        r   c                 O   r  r  )r   )r   r   r   r=   r=   r>   r     r  r   c                 K   s   t | |fddi|S r  rn  )r   r   r   r=   r=   r>   r     s   r   c                  O   r  r  )r   r  r=   r=   r>   rp    r  rp  c                 C   r@   r2   )r7   )r   rt   r=   r=   r>   rA     rB   rA   )dcollections.abcr4   r   r   r   	functoolsr   rk   r   rq   r   r   r   tDictr	   rF   sympy.core.numbersr
   sympy.core.relationalr   (sympy.functions.special.tensor_functionsr   sympy.core.basicr   sympy.core.containerssympy.core.exprr   sympy.core.functionr   r   sympy.core.mulr   sympy.core.singletonr   sympy.core.sortingr   sympy.core.symbolr   r   sympy.matrices.commonr   #sympy.matrices.expressions.diagonalr   "sympy.matrices.expressions.matexprr   "sympy.matrices.expressions.specialr   sympy.tensor.array.arrayopr   r   r   r   #sympy.tensor.array.dense_ndim_arrayr    sympy.tensor.array.ndim_arrayr!   sympy.tensor.indexedr"   r#   r$   $sympy.tensor.array.expressions.utilsr%   r&   r'   r(   r)   r*   r   r,    sympy.combinatorics.permutationsr-   sympy.core.sympifyr/   r0   rH   r7   r   r   r   r   r   r   r   r  r   rH  r  rR  r  r   r   r  r   rj  r   r   r   r   rp  rA   r=   r=   r=   r>   <module>   s     5/Z;  Y Q)    ?  