o
    oh                    @  sp  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
mZ ddlmZ ddlZddlZdd	lmZmZ dd
lmZ ddlmZmZmZmZ ddlmZmZmZmZmZm Z  ddl!m"Z" ddl#m$Z$m%Z% ddl&m'Z' ddl(m)Z)m*Z* ddl+m,Z,m-Z- ddl.m/Z/ ddl0m1Z1 ddl2m3Z3 ddl4m5Z5m6Z6m7Z7 ddl8m9Z9m:Z: ddl;m<Z< dd Z=dd Z>dd Z?G dd de,Z@d d! ZAG d"d# d#e,ZBeB ZCG d$d% d%ZDeD ZEG d&d' d'eZFG d(d) d)eZGd*d+ ZHG d,d- d-eZIe:d.d/d0d1d2d3 ZJe:d4d/d5d1G d6d7 d7eZKe:d8d/d9d1drd:d;ZLG d<d= d=eZMdrd>d?ZNG d@dA dAeeZOG dBdC dCeOe/ZPG dDdE dEeOZQG dFdG dGeOe/ZRG dHdI dIeOZSG dJdK dKeMZTG dLdM dMeQZUG dNdO dOeGZVG dPdQ dQeZWdRdS ZXdTdU ZYdVdW ZZdXdY Z[dZd[ Z\d\d] Z]d^d_ Z^d`da Z_dbdc Z`ddde Zadfdg ZbdsdidjZcdkdl Zddmdn Zedodp ZfdqefegiejgeO< dS )ta  
This module defines tensors with abstract index notation.

The abstract index notation has been first formalized by Penrose.

Tensor indices are formal objects, with a tensor type; there is no
notion of index range, it is only possible to assign the dimension,
used to trace the Kronecker delta; the dimension can be a Symbol.

The Einstein summation convention is used.
The covariant indices are indicated with a minus sign in front of the index.

For instance the tensor ``t = p(a)*A(b,c)*q(-c)`` has the index ``c``
contracted.

A tensor expression ``t`` can be called; called with its
indices in sorted order it is equal to itself:
in the above example ``t(a, b) == t``;
one can call ``t`` with different indices; ``t(c, d) == p(c)*A(d,a)*q(-a)``.

The contracted indices are dummy indices, internally they have no name,
the indices being represented by a graph-like structure.

Tensors are put in canonical form using ``canon_bp``, which uses
the Butler-Portugal algorithm for canonicalization using the monoterm
symmetries of the tensors.

If there is a (anti)symmetric metric, the indices can be raised and
lowered when the tensor is put in canonical form.
    )annotations)Any)reduce)prod)abstractmethodABC)defaultdictN)IntegerRationalPermutation)get_symmetric_group_sgsbsgs_direct_productcanonicalizeriemann_bsgs)BasicExprsympifyAddMulS)clear_cache)TupleDict)default_sort_key)Symbolsymbols)CantSympify_sympify)AssocOp)
SYMPY_INTS)eye)sympy_deprecation_warningSymPyDeprecationWarningignore_warnings)memoize_property
deprecated)siftc                   C     t ddddd d S )Nz|
        The data attribute of TensorIndexType is deprecated. Use The
        replace_with_arrays() method instead.
        z1.4z deprecated-tensorindextype-attrs   deprecated_since_versionactive_deprecations_target
stacklevelr"    r/   r/   g/var/www/html/construction_image-detection-poc/venv/lib/python3.10/site-packages/sympy/tensor/tensor.pydeprecate_data=      
r1   c                   C  r(   )Nzn
        The Tensor.fun_eval() method is deprecated. Use
        Tensor.substitute_indices() instead.
        1.5deprecated-tensor-fun-evalr)   r*   r.   r/   r/   r/   r0   deprecate_fun_evalH   r2   r5   c                   C  r(   )Nzx
        Calling a tensor like Tensor(*indices) is deprecated. Use
        Tensor.substitute_indices() instead.
        r3   r4   r)   r*   r.   r/   r/   r/   r0   deprecate_callT   r2   r6   c                   @  s   e Zd ZdZd(ddZedd Zedd Zed	d
 Zdd Z	edd Z
edd Zedd Zd)ddZdd Zdd Zdd Zdd Zdd  Zd!d" Zd(d#d$Zd%d& Zd'S )*_IndexStructurea  
    This class handles the indices (free and dummy ones). It contains the
    algorithms to manage the dummy indices replacements and contractions of
    free indices under multiplications of tensor expressions, as well as stuff
    related to canonicalization sorting, getting the permutation of the
    expression and so on. It also includes tools to get the ``TensorIndex``
    objects corresponding to the given index structure.
    Fc                 C  sH   || _ || _|| _|| _t| j dt| j  | _| jjdd d d S )N   c                 S     | d S Nr   r/   xr/   r/   r0   <lambda>p       z*_IndexStructure.__init__.<locals>.<lambda>key)freedumindex_typesindiceslen	_ext_ranksort)selfrA   rB   rC   rD   canon_bpr/   r/   r0   __init__j   s   z_IndexStructure.__init__c                  G  s8   t j|  \}}dd | D }t | ||} t |||| S )a  
        Create a new ``_IndexStructure`` object from a list of ``indices``.

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

        ``indices``     ``TensorIndex`` objects, the indices. Contractions are
                        detected upon construction.

        Examples
        ========

        >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, _IndexStructure
        >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
        >>> m0, m1, m2, m3 = tensor_indices('m0,m1,m2,m3', Lorentz)
        >>> _IndexStructure.from_indices(m0, m1, -m1, m3)
        _IndexStructure([(m0, 0), (m3, 3)], [(1, 2)], [Lorentz, Lorentz, Lorentz, Lorentz])
        c                 S     g | ]}|j qS r/   tensor_index_type.0ir/   r/   r0   
<listcomp>       z0_IndexStructure.from_indices.<locals>.<listcomp>)r7   _free_dum_from_indices_replace_dummy_names)rD   rA   rB   rC   r/   r/   r0   from_indicesr   s   z_IndexStructure.from_indicesc                 C  s6   g }| D ]}| |j qt|||}t||||S N)extendrC   r7   *generate_indices_from_free_dum_index_types)
componentsrA   rB   rC   	componentrD   r/   r/   r0   from_components_free_dum   s
   z(_IndexStructure.from_components_free_dumc                    s$  t | }|dkr| d dfgg fS dgt |   i }g }t| D ]^\}}|j}|j}|j}||f|v ru|||f \}	}
|	rP|rGtd|
|f d |
< d |< n|r[d |
< d |< ntd|
|f |rm|||
f q ||
|f q |j|f|||f< q  fddt| D      |fS )	a  
        Convert ``indices`` into ``free``, ``dum`` for single component tensor.

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

        ``free``     list of tuples ``(index, pos, 0)``,
                     where ``pos`` is the position of index in
                     the list of indices formed by the component tensors

        ``dum``      list of tuples ``(pos_contr, pos_cov, 0, 0)``

        Examples
        ========

        >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices,             _IndexStructure
        >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
        >>> m0, m1, m2, m3 = tensor_indices('m0,m1,m2,m3', Lorentz)
        >>> _IndexStructure._free_dum_from_indices(m0, m1, -m1, m3)
        ([(m0, 0), (m3, 3)], [(1, 2)])
           r   Tz2two equal contravariant indices in slots %d and %dFz.two equal covariant indices in slots %d and %dc                   s    g | ]\}} | r||fqS r/   r/   rO   rP   indexrA   r/   r0   rQ           z:_IndexStructure._free_dum_from_indices.<locals>.<listcomp>)rE   	enumeratenamerM   is_up
ValueErrorappendrG   )rD   n
index_dictrB   rP   r^   rb   typcontris_contrposr/   r_   r0   rS      s8   

z&_IndexStructure._free_dum_from_indicesc                 C  s   | j dd S )z_
        Get a list of indices, creating new tensor indices to complete dummy indices.
        NrD   rH   r/   r/   r0   get_indices      z_IndexStructure.get_indicesc                 C  s   d gt | dt |   }| D ]\}}|||< qt| }|D ]\}}|| }	||	}
t|
|	d||< t|
|	d||< qt|| |S )Nr8   TF)rE   r7    _get_generator_for_dummy_indicesTensorIndexrT   )rA   rB   rC   rD   idxrk   generate_dummy_namepos1pos2typ1indnamer/   r/   r0   rX      s   

z:_IndexStructure.generate_indices_from_free_dum_index_typesc                   sh   t t | D ]%\}}|jdd |jjkr+t |j t|jdd d  |j< q fdd}|S )N_r   r\   c                   *   t  |  } |   d7  < | jd | S Nr\   rx   str
dummy_namerM   ndcdtr/   r0   dummy_name_gen      zH_IndexStructure._get_generator_for_dummy_indices.<locals>.dummy_name_gen)r   intrb   splitrM   r}   max)rA   indxiposr   r/   r   r0   rp      s   *z0_IndexStructure._get_generator_for_dummy_indicesc           	      C  s   |j dd d t| }t| t|dt|  ksJ t|}|D ]\}}|| j}||}t||d||< t||d||< q#|S )Nc                 S  r9   r:   r/   r;   r/   r/   r0   r=      r>   z6_IndexStructure._replace_dummy_names.<locals>.<lambda>r?   r8   TF)rG   listrE   r7   rp   rM   rq   )	rD   rA   rB   new_indicesrs   ipos1ipos2rv   rw   r/   r/   r0   rT      s    

z$_IndexStructure._replace_dummy_namesreturnlist[TensorIndex]c                 C  s    t | jdd d}dd |D S )z-
        Get a list of free indices.
        c                 S  r9   Nr\   r/   r;   r/   r/   r0   r=     r>   z2_IndexStructure.get_free_indices.<locals>.<lambda>r?   c                 S     g | ]}|d  qS r   r/   rN   r/   r/   r0   rQ         z4_IndexStructure.get_free_indices.<locals>.<listcomp>sortedrA   )rH   rA   r/   r/   r0   get_free_indices  s   z _IndexStructure.get_free_indicesc                 C  s   d | j| j| jS )Nz_IndexStructure({}, {}, {}))formatrA   rB   rC   rm   r/   r/   r0   __str__     z_IndexStructure.__str__c                 C     |   S rV   )r   rm   r/   r/   r0   __repr__     z_IndexStructure.__repr__c                 C  s"   | j d d  }|jdd d |S )Nc                 S  r9   r:   r/   r;   r/   r/   r0   r=     r>   zD_IndexStructure._get_sorted_free_indices_for_canon.<locals>.<lambda>r?   )rA   rG   )rH   sorted_freer/   r/   r0   "_get_sorted_free_indices_for_canon  s   z2_IndexStructure._get_sorted_free_indices_for_canonc                 C  s   t | jdd dS )Nc                 S  r9   r:   r/   r;   r/   r/   r0   r=     r>   zC_IndexStructure._get_sorted_dum_indices_for_canon.<locals>.<lambda>r?   )r   rB   rm   r/   r/   r0   !_get_sorted_dum_indices_for_canon     z1_IndexStructure._get_sorted_dum_indices_for_canonc                 C  <   |   d }d g| j }t| jD ]
\}}||||< q|S r:   )indices_canon_argsrF   ra   rC   )rH   permutationrC   rP   itr/   r/   r0   )_get_lexicographically_sorted_index_types  
   z9_IndexStructure._get_lexicographically_sorted_index_typesc                 C  r   r:   )r   rF   ra   rD   )rH   r   rD   rP   r   r/   r/   r0   %_get_lexicographically_sorted_indices#  r   z5_IndexStructure._get_lexicographically_sorted_indicesc                 C  s  dd |   D }|  }|  }t|}| j}dd t|| d D }g }	dg| }
dg| }t|D ]G}|| }|| |
|< || ||< ||k rb|| }|
| || jksZJ |	||f q5|| }t|d\}}|rv||| d< q5||| d< q5dd |D }t	|	||
|S )	at  
        Returns a ``_IndexStructure`` instance corresponding to the permutation ``g``.

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

        ``g``  permutation corresponding to the tensor in the representation
        used in canonicalization

        ``is_canon_bp``   if True, then ``g`` is the permutation
        corresponding to the canonical form of the tensor
        c                 S  r   r   r/   rN   r/   r/   r0   rQ   7  r   z/_IndexStructure.perm2tensor.<locals>.<listcomp>c                 S  s   g | ]}d gd qS Nr8   r/   rN   r/   r/   r0   rQ   <      r8   Nr\   r   c                 S     g | ]}t |qS r/   )tuplerO   r<   r/   r/   r0   rQ   P  r   )
r   r   r   rE   rF   rangerM   re   divmodr7   )rH   gis_canon_bpr   lex_index_typeslex_indicesnfreerankrB   rA   rC   rD   rP   giindjidumcovr/   r/   r0   perm2tensor*  s0   

z_IndexStructure.perm2tensorc                 C  s  ddl m} | j}dg| ||d g }dd }t|  D ]
\}\}}|||< qt| j}t| j}	g }
d}g }g }|  D ]@\}}|	||< |	d ||< |	d7 }	| j| }||krr|ra|
	| ||d g}|}|	||j
 n	|||d g |d7 }q?|r|
	| |||
|fS )z
        Returns ``(g, dummies, msym, v)``, the entries of ``canonicalize``

        See ``canonicalize`` in ``tensor_can.py`` in combinatorics module.
        r   )_af_newNr\   c                 S  s:   | d u rd S | j }|tdkrdS |tdkrdS d S )Nr8   r   r\   )symmetryTensorSymmetryfully_symmetric)metricsymr/   r/   r0   metric_symmetry_to_msyma  s   zC_IndexStructure.indices_canon_args.<locals>.metric_symmetry_to_msymr8   ) sympy.combinatorics.permutationsr   rF   ra   r   rE   rA   r   rC   re   r   rW   )rH   r   rf   r   r   rP   r   r   rk   r   dummiesprevamsymr   r   rh   r/   r/   r0   r   T  s8   






z"_IndexStructure.indices_canon_argsNFr   r   )__name__
__module____qualname____doc__rJ   staticmethodrU   r[   rS   rn   rX   rp   rT   r   r   r   r   r   r   r   r   r   r/   r/   r/   r0   r7   `   s2    
	


>




*r7   c                 C  s   g }d }| D ]}||kr|d d  d7  < q|}| |dg qg }|D ]"\}}|jdv r2|j}nt|j|j}| |jj|jj||f q%|S )Nr\   r   r\   )re   commTensorManagerget_commr   base
generators)rY   numtypr   tvhrf   r   r/   r/   r0   components_canon_args  s   
r   c                   @  s   e Zd ZU dZi Zded< i Zded< d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e	dd Ze	dd Ze	dd  Ze	d+d"d#Ze	d$d% Ze	d&d' Ze	d(d) Zd*S ),_TensorDataLazyEvaluatora  
    EXPERIMENTAL: do not rely on this class, it may change without deprecation
    warnings in future versions of SymPy.

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

    This object contains the logic to associate components data to a tensor
    expression. Components data are set via the ``.data`` property of tensor
    expressions, is stored inside this class as a mapping between the tensor
    expression and the ``ndarray``.

    Computations are executed lazily: whereas the tensor expressions can have
    contractions, tensor products, and additions, components data are not
    computed until they are accessed by reading the ``.data`` property
    associated to the tensor expression.
    zdict[Any, Any]_substitutions_dict_substitutions_dict_tensmulc                 C  sh   |  |}|d u rd S ddlm} t||s|S | dkr"|d S | dkr2t|dkr2|d S |S )Nr\   )	NDimArrayr   r/   )_getarrayr   
isinstancer   rE   )rH   r@   datr   r/   r/   r0   __getitem__  s   

z$_TensorDataLazyEvaluator.__getitem__c                   sz  |j v r
j | S t|trdS t|tr@tdd | D }|jf| }|jv r1j| S |g}	||j
|jS t|tr|j}t|dkrxt|d jdkrxtdd |d  D }|d jd f| }|jv rxj| S fdd|D }tdd |D }td	d
 |D rdS tdd
 |D rtd	||j
|j}|| S t|tr;g }g }	|jD ]#}
t|
tr||
j |	dd |
jD  q||
 |	g  qtdd
 |D rdS tdd
 |D rtdg }ddlm} t||	D ].\}}t|dk r|| qdd t|D   fdd|jD }|||| qtdd |S dS )a]  
        Retrieve ``data`` associated with ``key``.

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

        This algorithm looks into ``self._substitutions_dict`` for all
        ``TensorHead`` in the ``TensExpr`` (or just ``TensorHead`` if key is a
        TensorHead instance). It reconstructs the components data that the
        tensor expression should have by performing on components data the
        operations that correspond to the abstract tensor operations applied.

        Metric tensor is handled in a different manner: it is pre-computed in
        ``self._substitutions_dict_tensmul``.
        Nc                 S  rK   r/   rc   rN   r/   r/   r0   rQ     rR   z1_TensorDataLazyEvaluator._get.<locals>.<listcomp>r\   r   c                 S  rK   r/   r   rN   r/   r/   r0   rQ     rR   c                   s0   g | ]}t |trt |tr |n|jqS r/   )r   TensExprTensordata_from_tensordatarN   rm   r/   r0   rQ        0 c                 S     g | ]	}t |ts|qS r/   r   r   rN   r/   r/   r0   rQ         c                 s      | ]}|d u V  qd S rV   r/   rN   r/   r/   r0   	<genexpr>      z0_TensorDataLazyEvaluator._get.<locals>.<genexpr>c                 s  r   rV   r/   rN   r/   r/   r0   r     r   zSMixing tensors with associated components data with tensors without components datac                 S  r   r   r/   r   r/   r/   r0   rQ     r   c                 s  r   rV   r/   rN   r/   r/   r0   r     r   c                 s  r   rV   r/   rN   r/   r/   r0   r     r   permutedimsr8   c                 S  s   i | ]\}}||qS r/   r/   )rO   r<   yr/   r/   r0   
<dictcomp>  r   z1_TensorDataLazyEvaluator._get.<locals>.<dictcomp>c                      g | ]} | qS r/   r/   rO   arg)free_args_posr/   r0   rQ     r   c                 S  s   | | S rV   r/   )r<   r   r/   r/   r0   r=     r>   z/_TensorDataLazyEvaluator._get.<locals>.<lambda>)r   r   
TensorHeadr   r   rn   rZ   r   r   data_contract_dumrB   ext_rankTensMulargsrE   rY   r   allanyrd   TensAddr   re   r   rA   r   r   zipra   	free_argsr   )rH   r@   	signaturesrch
array_listtensmul_args	data_listcoeffdata_resultfree_args_listr   sum_listr   r   r   axesr/   )r   rH   r0   r     sb   











z_TensorDataLazyEvaluator._getc                 C  s:   ddl m}m}m} tt|| }|| }||g|R  S )Nr\   )tensorproducttensorcontractionMutableDenseNDimArray)r   r  r  r  r   map)ndarray_listrB   r   r  r  r  arraysprodarrr/   r/   r0   r     s   z*_TensorDataLazyEvaluator.data_contract_dumc                 C  s&   |du rdS |  || |j|jdS )z
        This method is used when assigning components data to a ``TensMul``
        object, it converts components data to a fully contravariant ndarray,
        which is then stored according to the ``TensorHead`` key.
        NT)_correct_signature_from_indicesrn   rA   rB   )rH   r   tensmul
tensorheadr/   r/   r0   data_tensorhead_from_tensmul  s   z5_TensorDataLazyEvaluator.data_tensorhead_from_tensmulc                 C  s.   |j }|jdu r
dS | |j| |j|jS )z
        This method corrects the components data to the right signature
        (covariant/contravariant) using the metric associated with each
        ``TensorIndexType``.
        N)rZ   r   r  rn   rA   rB   )rH   tensorr  r/   r/   r0   r   ,  s   
z)_TensorDataLazyEvaluator.data_from_tensorc                 C  sH   t |tr	tdt|jdkrtd|jd }| |||}||fS )Nzcannot assign data to TensAddr\   z6cannot assign data to TensMul with multiple componentsr   )r   r   rd   rE   rY   r  )rH   r@   r   r  newdatar/   r/   r0   _assign_data_to_tensor_expr=  s   

z4_TensorDataLazyEvaluator._assign_data_to_tensor_exprc                 C  s   ddl m} ddlm} t|tr|j}|jj}nt|t	r)|j}|j
d jj}nt|tr7|jj}|jjj}|D ]9}|||krCdnd}|}	|}
tt|t|}t| d D ]}||	|}	t||
||	  rotd|	}
qZq9d S )Nr\   r   )Flattenr   r   z'Component data symmetry structure error)r   r   array.arrayopr  r   r   r   r   r   r   rY   TensorIndexTyper   r   r  r   orderr   rd   )rH   tensr   r   r  r   r   genersign_changedata_swapped	last_datapermute_axesrP   r/   r/   r0   _check_permutations_on_dataG  s.   





z4_TensorDataLazyEvaluator._check_permutations_on_datac                 C  s   t |}| || t|ttfs| ||\}}t|trEt|j|j	D ]\}}|j
du r6td||jjs;q&||jkrDtdq&|| j|< dS )aS  
        Set the components data of a tensor object/expression.

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

        Components data are transformed to the all-contravariant form and stored
        with the corresponding ``TensorHead`` object. If a ``TensorHead`` object
        cannot be uniquely identified, it will raise an error.
        NzMindex type {} has no components data associated (needed to raise/lower index)zwrong dimension of ndarray)r   
parse_datar#  r   r   r  r  r   shaperC   r   rd   r   dim	is_numberr   )rH   r@   valuer   r&  	indextyper/   r/   r0   __setitem__f  s    



z$_TensorDataLazyEvaluator.__setitem__c                 C  s   | j |= d S rV   r   rH   r@   r/   r/   r0   __delitem__     z$_TensorDataLazyEvaluator.__delitem__c                 C  s
   || j v S rV   r+  r,  r/   r/   r0   __contains__     
z%_TensorDataLazyEvaluator.__contains__c                 C  sf   || j |ddf< | |}|| j |ddf< | }| }|| | j |ddf< || | j |ddf< dS )a  
        Assign data to the ``metric`` tensor. The metric tensor behaves in an
        anomalous way when raising and lowering indices.

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

        A fully covariant metric is the inverse transpose of the fully
        contravariant metric (it is meant matrix inverse). If the metric is
        symmetric, the transpose is not necessary and mixed
        covariant/contravariant metrics are Kronecker deltas.
        TFN)r   inverse_transpose_matrixtomatrix)rH   r   r   inverse_transposeminvtr/   r/   r0   add_metric_data  s   
z(_TensorDataLazyEvaluator.add_metric_datac                 C  s\   ddl m}m} | }|  }|dkr"|||| d|| f} | S ||| |||f} | S )Nr\   r  r  r   )r   r  r  r   )r   r   rk   r  r  mdimddimr/   r/   r0   _flip_index_by_metric  s(   
z._TensorDataLazyEvaluator._flip_index_by_metricc                 C  s   |    }t|S rV   )r2  invr   r$  ndarrayr4  r/   r/   r0   inverse_matrix  s   
z'_TensorDataLazyEvaluator.inverse_matrixc                 C  s   |    j}t|S rV   )r2  r;  Tr   r$  r<  r/   r/   r0   r1    s   
z1_TensorDataLazyEvaluator.inverse_transpose_matrixFc                 C  sV   t |D ]$\}}|js|st| |jj|} q|js(|r(t| t|jj|} q| S )z
        Utility function to correct the values inside the components data
        ndarray according to whether indices are covariant or contravariant.

        It uses the metric matrix to lower values of covariant indices.
        )ra   rc   r   r:  rM   r   r>  )r   rD   rA   rB   inverserP   r   r/   r/   r0   r    s   


z8_TensorDataLazyEvaluator._correct_signature_from_indicesc                 C  s   ddl m} | j }dd | jD }dd |jD }tt|D ]*}t|t|D ] }|| || krJ|| || ||< ||< ||||f} nq*q!|S )Nr\   r   c                 S  r   r   r/   rN   r/   r/   r0   rQ     r   z<_TensorDataLazyEvaluator._sort_data_axes.<locals>.<listcomp>c                 S  r   r   r/   rN   r/   r/   r0   rQ     r   )r   r   r   copyrA   r   rE   )oldnewr   new_dataold_freenew_freerP   r   r/   r/   r0   _sort_data_axes  s   
z(_TensorDataLazyEvaluator._sort_data_axesc                   s    fdd}| t j < d S )Nc                     s   t  S rV   )r   rG  r/   new_tensmulold_tensmulr/   r0   sorted_compo  r.  zJ_TensorDataLazyEvaluator.add_rearrange_tensmul_parts.<locals>.sorted_compo)r   r   )rI  rJ  rK  r/   rH  r0   add_rearrange_tensmul_parts  s   z4_TensorDataLazyEvaluator.add_rearrange_tensmul_partsc                 C  sR   ddl m} t| |s't| dkr#t| d dr#|| d | d } | S || } | S )a  
        Transform ``data`` to array. The parameter ``data`` may
        contain data in various formats, e.g. nested lists, SymPy ``Matrix``,
        and so on.

        Examples
        ========

        >>> from sympy.tensor.tensor import _TensorDataLazyEvaluator
        >>> _TensorDataLazyEvaluator.parse_data([1, 3, -6, 12])
        [1, 3, -6, 12]

        >>> _TensorDataLazyEvaluator.parse_data([[1, 2], [4, 7]])
        [[1, 2], [4, 7]]
        r\   r  r8   r   __call__)r   r  r   rE   hasattr)r   r  r/   r/   r0   r$    s   
z#_TensorDataLazyEvaluator.parse_dataNr   )r   r   r   r   r   __annotations__r   r   r   r   r   r  r   r  r#  r*  r-  r/  r6  r:  r>  r1  r  rG  rL  r$  r/   r/   r/   r0   r     s<   
 S






r   c                   @  s\   e Zd ZdZd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S )_TensorManagera  
    Class to manage tensor properties.

    Notes
    =====

    Tensors belong to tensor commutation groups; each group has a label
    ``comm``; there are predefined labels:

    ``0``   tensors commuting with any other tensor

    ``1``   tensors anticommuting among themselves

    ``2``   tensors not commuting, apart with those with ``comm=0``

    Other groups can be defined using ``set_comm``; tensors in those
    groups commute with those with ``comm=0``; by default they
    do not commute with any other group.
    c                 C  s   |    d S rV   
_comm_initrm   r/   r/   r0   rJ   *  r.  z_TensorManager.__init__c                 C  s   dd t dD | _t dD ]}d| jd |< d| j| d< qd| jd d< d | jd d< d | jd d< dddd| _dddd| _d S )Nc                 S     g | ]}i qS r/   r/   rN   r/   r/   r0   rQ   .      z-_TensorManager._comm_init.<locals>.<listcomp>   r   r\   r8   )r   r\   r8   )r   _comm_comm_symbols2i_comm_i2symbolrH   rP   r/   r/   r0   rS  -  s   z_TensorManager._comm_initc                 C     | j S rV   )rW  rm   r/   r/   r0   r   8     z_TensorManager.commc                 C  s^   || j vr*t| j}| ji  d| j| d< d| jd |< || j |< || j|< |S | j | S )z
        Get the commutation group number corresponding to ``i``.

        ``i`` can be a symbol or a number or a string.

        If ``i`` is not already defined its commutation group number
        is set.
        r   )rX  rE   rW  re   rY  )rH   rP   rf   r/   r/   r0   comm_symbols2i<  s   
	



z_TensorManager.comm_symbols2ic                 C  s
   | j | S )zS
        Returns the symbol corresponding to the commutation group number.
        )rY  rZ  r/   r/   r0   comm_i2symbolO     
z_TensorManager.comm_i2symbolc                 C  s   |dvrt dt|}t|}|| jvr8t| j}| ji  d| j| d< d| jd |< || j|< || j|< || jvr`t| j}| ji  d| jd |< d| j| d< || j|< || j|< | j| }| j| }|| j| |< || j| |< 	 t  dS )a  
        Set the commutation parameter ``c`` for commutation groups ``i, j``.

        Parameters
        ==========

        i, j : symbols representing commutation groups

        c  :  group commutation number

        Notes
        =====

        ``i, j`` can be symbols, strings or numbers,
        apart from ``0, 1`` and ``2`` which are reserved respectively
        for commuting, anticommuting tensors and tensors not commuting
        with any other group apart with the commuting tensors.
        For the remaining cases, use this method to set the commutation rules;
        by default ``c=None``.

        The group commutation number ``c`` is assigned in correspondence
        to the group commutation symbols; it can be

        0        commuting

        1        anticommuting

        None     no commutation property

        Examples
        ========

        ``G`` and ``GH`` do not commute with themselves and commute with
        each other; A is commuting.

        >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorHead, TensorManager, TensorSymmetry
        >>> Lorentz = TensorIndexType('Lorentz')
        >>> i0,i1,i2,i3,i4 = tensor_indices('i0:5', Lorentz)
        >>> A = TensorHead('A', [Lorentz])
        >>> G = TensorHead('G', [Lorentz], TensorSymmetry.no_symmetry(1), 'Gcomm')
        >>> GH = TensorHead('GH', [Lorentz], TensorSymmetry.no_symmetry(1), 'GHcomm')
        >>> TensorManager.set_comm('Gcomm', 'GHcomm', 0)
        >>> (GH(i1)*G(i0)).canon_bp()
        G(i0)*GH(i1)
        >>> (G(i1)*G(i0)).canon_bp()
        G(i1)*G(i0)
        >>> (G(i1)*A(i0)).canon_bp()
        A(i0)*G(i1)
        )r   r\   Nz+`c` can assume only the values 0, 1 or Noner   N)rd   r   rX  rE   rW  re   rY  r   )rH   rP   r   crf   ninjr/   r/   r0   set_commU  s0   2










z_TensorManager.set_commc                 G  s"   |D ]\}}}|  ||| qdS )z
        Set the commutation group numbers ``c`` for symbols ``i, j``.

        Parameters
        ==========

        args : sequence of ``(i, j, c)``
        N)rc  )rH   r   rP   r   r`  r/   r/   r0   	set_comms  s   	z_TensorManager.set_commsc                 C  s(   | j | ||dks|dkrdS dS )z
        Return the commutation parameter for commutation group numbers ``i, j``

        see ``_TensorManager.set_comm``
        r   N)rW  get)rH   rP   r   r/   r/   r0   r     s   (z_TensorManager.get_commc                 C  s   |    dS )z*
        Clear the TensorManager.
        NrR  rm   r/   r/   r0   clear  s   z_TensorManager.clearN)r   r   r   r   rJ   rS  propertyr   r]  r^  rc  rd  r   rf  r/   r/   r/   r0   rQ    s    
SrQ  c                   @  s   e Zd ZdZ		d*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dd Zdd Zdd ZeZedd Zejdd Zejdd Zedd d!d"d#d$ Zed%d d!d"d&d' Zd(d) ZdS )+r  aH	  
    A TensorIndexType is characterized by its name and its metric.

    Parameters
    ==========

    name : name of the tensor type
    dummy_name : name of the head of dummy indices
    dim : dimension, it can be a symbol or an integer or ``None``
    eps_dim : dimension of the epsilon tensor
    metric_symmetry : integer that denotes metric symmetry or ``None`` for no metric
    metric_name : string with the name of the metric tensor

    Attributes
    ==========

    ``metric`` : the metric tensor
    ``delta`` : ``Kronecker delta``
    ``epsilon`` : the ``Levi-Civita epsilon`` tensor
    ``data`` : (deprecated) a property to add ``ndarray`` values, to work in a specified basis.

    Notes
    =====

    The possible values of the ``metric_symmetry`` parameter are:

        ``1``   :   metric tensor is fully symmetric
        ``0``   :   metric tensor possesses no index symmetry
        ``-1``  :   metric tensor is fully antisymmetric
        ``None``:   there is no metric tensor (metric equals to ``None``)

    The metric is assumed to be symmetric by default. It can also be set
    to a custom tensor by the ``.set_metric()`` method.

    If there is a metric the metric is used to raise and lower indices.

    In the case of non-symmetric metric, the following raising and
    lowering conventions will be adopted:

    ``psi(a) = g(a, b)*psi(-b); chi(-a) = chi(b)*g(-b, -a)``

    From these it is easy to find:

    ``g(-a, b) = delta(-a, b)``

    where ``delta(-a, b) = delta(b, -a)`` is the ``Kronecker delta``
    (see ``TensorIndex`` for the conventions on indices).
    For antisymmetric metrics there is also the following equality:

    ``g(a, -b) = -delta(a, -b)``

    If there is no metric it is not possible to raise or lower indices;
    e.g. the index of the defining representation of ``SU(N)``
    is 'covariant' and the conjugate representation is
    'contravariant'; for ``N > 2`` they are linearly independent.

    ``eps_dim`` is by default equal to ``dim``, if the latter is an integer;
    else it can be assigned (for use in naive dimensional regularization);
    if ``eps_dim`` is not an integer ``epsilon`` is ``None``.

    Examples
    ========

    >>> from sympy.tensor.tensor import TensorIndexType
    >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
    >>> Lorentz.metric
    metric(Lorentz,Lorentz)
    Nr\   r   c              	   K  s  d|v r|d }t d| dddd |}t|trt|}|d u r(t|d }t|tr1t|}|d u r=td|j }nt|}|d u rH|}nt|}t|}t|trYt|}d	|v r~td
ddd |d	}	|	d ur~|	dv rtd	}n|	j}|	r|d}nd}t	| ||||||}
g |
_
|
S )N	dummy_fmtzh
                The dummy_fmt keyword to TensorIndexType is deprecated. Use
                dummy_name=z instead.
                r3   z$deprecated-tensorindextype-dummy-fmtr+   r,   r   dim_r   z
                The 'metric' keyword argument to TensorIndexType is
                deprecated. Use the 'metric_symmetry' keyword argument or the
                TensorIndexType.set_metric() method instead.
                z!deprecated-tensorindextype-metric)TFr   r\   r   r\   )r"   r   r|   r   rb   r   r#   re  r   __new___autogenerated)clsrb   r}   r&  eps_dimmetric_symmetrymetric_namekwargsrh  r   objr/   r/   r0   rk    sX   



	zTensorIndexType.__new__c                 C     | j d jS r:   r   rb   rm   r/   r/   r0   rb   O     zTensorIndexType.namec                 C  rs  r   rt  rm   r/   r/   r0   r}   S  ru  zTensorIndexType.dummy_namec                 C  
   | j d S r   r   rm   r/   r/   r0   r&  W     
zTensorIndexType.dimc                 C  rv  NrV  rw  rm   r/   r/   r0   rn  [  rx  zTensorIndexType.eps_dimc                 C  sl   | j d }| j d }|d u rd S |dkrtd}n|dkr$td}n	|dkr-td}t|| gd |S )Nr)      r   r8   r\   r   r   )r   r   no_symmetryr   r   )rH   ro  rp  r   r/   r/   r0   r   _  s   


zTensorIndexType.metricc                 C  s   t d| gd tdS )NKDr8   )r   r   r   rm   r/   r/   r0   deltao  s   zTensorIndexType.deltac                 C  s6   t | jttfs
d S t| j }td| g| j |S )NEps)r   rn  r    r	   r   r   r   )rH   r   r/   r/   r0   epsilons  s   zTensorIndexType.epsilonc                 C  s
   || _ d S rV   )_metric)rH   r  r/   r/   r0   
set_metricz  r0  zTensorIndexType.set_metricc                 C  s   | j |j k S rV   rb   rH   otherr/   r/   r0   __lt__}  r.  zTensorIndexType.__lt__c                 C  r[  rV   r  rm   r/   r/   r0   r        zTensorIndexType.__str__c                 C  :   t   tt t|  W  d    S 1 sw   Y  d S rV   r1   r$   r#   _tensor_data_substitution_dictrm   r/   r/   r0   r        
$zTensorIndexType.datac                 C  sl  t   ddlm} t|}| dkrtd| dkrL| jjr0|j	d }|| jkr0td|j	d }|
||}t|D ]
\}}||||f< q?|}|j	\}}	||	krYtd| jjrf| j|krftd|t| < t| j| tt |  }
W d    n1 sw   Y  td| }td	| }tt tt||
|| _W d    d S 1 sw   Y  d S )
Nr\   rM  r8   z1data have to be of rank 1 (diagonal metric) or 2.r   zDimension mismatchzNon-square matrix tensor.i1i2)r1   r   r  r   r$  r   rd   r&  r'  r%  zerosra   r  r6  r   r$   r#   get_kronecker_deltarq   r!   r   )rH   r   r  nda_dimr&  
newndarrayrP   valdim1dim2r}  r  r  r/   r/   r0   r     s>   










"c                 C  d   t   tt! | tv rt| = | jtv r t| j= W d    d S W d    d S 1 s+w   Y  d S rV   r1   r$   r#   r  r   rm   r/   r/   r0   r        


"z
        The TensorIndexType.get_kronecker_delta() method is deprecated. Use
        the TensorIndexType.delta attribute instead.
        r3   z"deprecated-tensorindextype-methodsri  c                 C  s"   t td}td| gd |}|S )Nr8   r|  )r   r   r   )rH   sym2r}  r/   r/   r0   r    s   	z#TensorIndexType.get_kronecker_deltaz
        The TensorIndexType.get_epsilon() method is deprecated. Use
        the TensorIndexType.epsilon attribute instead.
        c                 C  s<   t | jttfs
d S tt| jd}td| g| j |}|S )Nr\   r~  )r   _eps_dimr    r	   r   r   r   )rH   r   r  r/   r/   r0   get_epsilon  s
   	zTensorIndexType.get_epsilonc                 C  st   | t v rt | = dd }|| jddf || jddf || jddf || jddf |  }|t v r8t |= dS dS )z
        EXPERIMENTAL: do not rely on this API method.

        This destroys components data associated to the ``TensorIndexType``, if
        any, specifically:

        * metric tensor data
        * Kronecker tensor data
        c                 S  s   | t jv rt j| = d S d S rV   )r  r   r?   r/   r/   r0   delete_tensmul_data  s   
zJTensorIndexType._components_data_full_destroy.<locals>.delete_tensmul_dataTFN)r  r   r  )rH   r  r}  r/   r/   r0   _components_data_full_destroy  s   

z-TensorIndexType._components_data_full_destroy)NNNr\   r   )r   r   r   r   rk  rg  rb   r}   r&  rn  r%   r   r}  r  r  r  r   r   r   setterdeleterr&   r  r  r  r/   r/   r/   r0   r    sT    E
C








$


r  c                   @  sV   e Zd ZdZdddZedd Zedd Zed	d
 Zdd Z	dd Z
dd ZdS )rq   aq  
    Represents a tensor index

    Parameters
    ==========

    name : name of the index, or ``True`` if you want it to be automatically assigned
    tensor_index_type : ``TensorIndexType`` of the index
    is_up :  flag for contravariant index (is_up=True by default)

    Attributes
    ==========

    ``name``
    ``tensor_index_type``
    ``is_up``

    Notes
    =====

    Tensor indices are contracted with the Einstein summation convention.

    An index can be in contravariant or in covariant form; in the latter
    case it is represented prepending a ``-`` to the index name. Adding
    ``-`` to a covariant (is_up=False) index makes it contravariant.

    Dummy indices have a name with head given by
    ``tensor_inde_type.dummy_name`` with underscore and a number.

    Similar to ``symbols`` multiple contravariant indices can be created
    at once using ``tensor_indices(s, typ)``, where ``s`` is a string
    of names.


    Examples
    ========

    >>> from sympy.tensor.tensor import TensorIndexType, TensorIndex, TensorHead, tensor_indices
    >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
    >>> mu = TensorIndex('mu', Lorentz, is_up=False)
    >>> nu, rho = tensor_indices('nu, rho', Lorentz)
    >>> A = TensorHead('A', [Lorentz, Lorentz])
    >>> A(mu, nu)
    A(-mu, nu)
    >>> A(-mu, -rho)
    A(mu, -rho)
    >>> A(mu, -mu)
    A(-L_0, L_0)
    Tc                 C  sr   t |tr
t|}n#t |tr|}n|du r)dt|j}t|}|j| ntdt|}t	
| |||S NTz_i{}invalid namer   r|   r   r   rE   rl  re   rd   r   r   rk  )rm  rb   rM   rc   name_symbolr/   r/   r0   rk  &  s   


zTensorIndex.__new__c                 C  rs  r:   rt  rm   r/   r/   r0   rb   5  ru  zTensorIndex.namec                 C  rv  r   rw  rm   r/   r/   r0   rM   9  rx  zTensorIndex.tensor_index_typec                 C  rv  r   rw  rm   r/   r/   r0   rc   =  rx  zTensorIndex.is_upc                 C  s   | j }| js
d| }|S )Nz-%s)rb   rc   )rH   sr/   r/   r0   _printA  s   zTensorIndex._printc                 C     | j | jf|j |jfk S rV   )rM   rb   r  r/   r/   r0   r  G  s   

zTensorIndex.__lt__c                 C  s   t | j| j| j }|S rV   )rq   rb   rM   rc   rH   t1r/   r/   r0   __neg__K  s   
zTensorIndex.__neg__NT)r   r   r   r   rk  rg  rb   rM   rc   r  r  r  r/   r/   r/   r0   rq     s    
1


rq   c                   sT   t | trdd t| ddD }ntd fdd|D }t|dkr(|d S |S )	a  
    Returns list of tensor indices given their names and their types.

    Parameters
    ==========

    s : string of comma separated names of indices

    typ : ``TensorIndexType`` of the indices

    Examples
    ========

    >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices
    >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
    >>> a, b, c, d = tensor_indices('a,b,c,d', Lorentz)
    c                 S  rK   r/   r  r   r/   r/   r0   rQ   d  rR   z"tensor_indices.<locals>.<listcomp>Tseqexpecting a stringc                      g | ]}t | qS r/   )rq   rN   rh   r/   r0   rQ   h  r   r\   r   r   r|   r   rd   rE   )r  rh   r   tilistr/   r  r0   tensor_indicesQ  s   
r  c                   @  sl   e Zd Z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dS )r   a  
    Monoterm symmetry of a tensor (i.e. any symmetric or anti-symmetric
    index permutation). For the relevant terminology see ``tensor_can.py``
    section of the combinatorics module.

    Parameters
    ==========

    bsgs : tuple ``(base, sgs)`` BSGS of the symmetry of the tensor

    Attributes
    ==========

    ``base`` : base of the BSGS
    ``generators`` : generators of the BSGS
    ``rank`` : rank of the tensor

    Notes
    =====

    A tensor can have an arbitrary monoterm symmetry provided by its BSGS.
    Multiterm symmetries, like the cyclic symmetry of the Riemann tensor
    (i.e., Bianchi identity), are not covered. See combinatorics module for
    information on how to generate BSGS for a general index permutation group.
    Simple symmetries can be generated using built-in methods.

    See Also
    ========

    sympy.combinatorics.tensor_can.get_symmetric_group_sgs

    Examples
    ========

    Define a symmetric tensor of rank 2

    >>> from sympy.tensor.tensor import TensorIndexType, TensorSymmetry, get_symmetric_group_sgs, TensorHead
    >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
    >>> sym = TensorSymmetry(get_symmetric_group_sgs(2))
    >>> T = TensorHead('T', [Lorentz]*2, sym)

    Note, that the same can also be done using built-in TensorSymmetry methods

    >>> sym2 = TensorSymmetry.fully_symmetric(2)
    >>> sym == sym2
    True
    c                 O  sr   t |dkr|d \}}nt |dkr|\}}ntdt|ts%t| }t|ts.t| }tj| ||fi |S )Nr\   r   r8   z:bsgs required, either two separate parameters or one tuple)rE   	TypeErrorr   r   r   rk  )rm  r   kw_argsr   r   r/   r/   r0   rk    s   


zTensorSymmetry.__new__c                 C  rv  r:   rw  rm   r/   r/   r0   r     rx  zTensorSymmetry.basec                 C  rv  r   rw  rm   r/   r/   r0   r     rx  zTensorSymmetry.generatorsc                 C  s   | j d jd S )Nr   r8   )r   sizerm   r/   r/   r0   r        zTensorSymmetry.rankc                 C  sT   |dkrt |d}t|S |dk rt | d}t|S |dkr&g tdgf}t|S )z
        Returns a fully symmetric (antisymmetric if ``rank``<0)
        TensorSymmetry object for ``abs(rank)`` indices.
        r   FTr\   )r   r   r   )rm  r   bsgsr/   r/   r0   r     s   
zTensorSymmetry.fully_symmetricc                 G  sf   g t dg}}|D ]#}|dkrt|d}n|dk r!t| d}nq
t||g|R  \}}q
t||S )a  
        Returns a TensorSymmetry object that is being a direct product of
        fully (anti-)symmetric index permutation groups.

        Notes
        =====

        Some examples for different values of ``(*args)``:
        ``(1)``         vector, equivalent to ``TensorSymmetry.fully_symmetric(1)``
        ``(2)``         tensor with 2 symmetric indices, equivalent to ``.fully_symmetric(2)``
        ``(-2)``        tensor with 2 antisymmetric indices, equivalent to ``.fully_symmetric(-2)``
        ``(2, -2)``     tensor with the first 2 indices commuting and the last 2 anticommuting
        ``(1, 1, 1)``   tensor with 3 indices without any symmetry
        r\   r   FT)r   r   r   r   )rm  r   r   sgsr   bsgs2r/   r/   r0   direct_product  s   
zTensorSymmetry.direct_productc                 C  s   t tS )zD
        Returns a monotorem symmetry of the Riemann tensor
        )r   r   rm  r/   r/   r0   riemann  s   zTensorSymmetry.riemannc                 C  s   t g t|d gS )zM
        TensorSymmetry object for ``rank`` indices with no symmetry
        r\   )r   r   )rm  r   r/   r/   r0   r{    s   zTensorSymmetry.no_symmetryN)r   r   r   r   rk  rg  r   r   r   classmethodr   r  r  r{  r/   r/   r/   r0   r   n  s"    /





r   zf
    The tensorsymmetry() function is deprecated. Use the TensorSymmetry
    constructor instead.
    r3   zdeprecated-tensorsymmetryri  c                  G  s   ddl m} dd }| stt t|dS t| dkr)t| d d |r)t| S || d \}}| dd D ]}||\}}t||||\}}q7tt||S )ay  
    Returns a ``TensorSymmetry`` object. This method is deprecated, use
    ``TensorSymmetry.direct_product()`` or ``.riemann()`` instead.

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

    One can represent a tensor with any monoterm slot symmetry group
    using a BSGS.

    ``args`` can be a BSGS
    ``args[0]``    base
    ``args[1]``    sgs

    Usually tensors are in (direct products of) representations
    of the symmetric group;
    ``args`` can be a list of lists representing the shapes of Young tableaux

    Notes
    =====

    For instance:
    ``[[1]]``       vector
    ``[[1]*n]``     symmetric tensor of rank ``n``
    ``[[n]]``       antisymmetric tensor of rank ``n``
    ``[[2, 2]]``    monoterm slot symmetry of the Riemann tensor
    ``[[1],[1]]``   vector*vector
    ``[[2],[1],[1]`` (antisymmetric tensor)*vector*vector

    Notice that with the shape ``[2, 2]`` we associate only the monoterm
    symmetries of the Riemann tensor; this is an abuse of notation,
    since the shape ``[2, 2]`` corresponds usually to the irreducible
    representation characterized by the monoterm symmetries and by the
    cyclic symmetry.
    r   r   c                 S  s`   t | dkr| d }t|d}|S tdd | D r$t | }t|}|S | ddgkr.t}|S t)Nr\   r   c                 s  s    | ]}|d kV  qdS )r\   Nr/   r   r/   r/   r0   r   &  r   z7tensorsymmetry.<locals>.tableau2bsgs.<locals>.<genexpr>r8   )rE   r   r   r   NotImplementedError)r   rf   r  r/   r/   r0   tableau2bsgs   s   

z$tensorsymmetry.<locals>.tableau2bsgsr\   r8   N)sympy.combinatoricsr   r   r   rE   r   r   )r   r   r  r   r  r   basexsgsxr/   r/   r0   tensorsymmetry  s   ,r  z5TensorType is deprecated. Use tensor_heads() instead.zdeprecated-tensortypec                   @  sR   e 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ddZdS )
TensorTypeaa  
    Class of tensor types. Deprecated, use tensor_heads() instead.

    Parameters
    ==========

    index_types : list of ``TensorIndexType`` of the tensor indices
    symmetry : ``TensorSymmetry`` of the tensor

    Attributes
    ==========

    ``index_types``
    ``symmetry``
    ``types`` : list of ``TensorIndexType`` without repetitions
    Fc                 K  s0   |j t|ks	J tj| t| |fi |}|S rV   )r   rE   r   rk  r   )rm  rC   r   r  rr  r/   r/   r0   rk  S  s   zTensorType.__new__c                 C  rv  r:   rw  rm   r/   r/   r0   rC   X  rx  zTensorType.index_typesc                 C  rv  r   rw  rm   r/   r/   r0   r   \  rx  zTensorType.symmetryc                 C  s   t t| jdd dS )Nc                 S  r[  rV   r  r;   r/   r/   r0   r=   b      z"TensorType.types.<locals>.<lambda>r?   )r   setrC   rm   r/   r/   r0   types`     zTensorType.typesc                 C  s   ddd | j D  S )NzTensorType(%s)c                 S  r   r/   r|   r   r/   r/   r0   rQ   e  r   z&TensorType.__str__.<locals>.<listcomp>)rC   rm   r/   r/   r0   r   d  r   zTensorType.__str__r   c                   s`   t |trdd t|ddD }ntdt|dkr&t|d jj S  fdd|D S )	z
        Return a TensorHead object or a list of TensorHead objects.

        Parameters
        ==========

        s : name or string of names.

        comm : Commutation group.

        see ``_TensorManager.set_comm``
        c                 S  rK   r/   r  r   r/   r/   r0   rQ   u  rR   z'TensorType.__call__.<locals>.<listcomp>Tr  r  r\   r   c                   s   g | ]}t |jj qS r/   )r   rC   r   rO   rb   r   rH   r/   r0   rQ   {      )r   r|   r   rd   rE   r   rC   r   )rH   r  r   namesr/   r  r0   rN  g  s   
zTensorType.__call__Nr   )r   r   r   r   is_commutativerk  rg  rC   r   r  r   rN  r/   r/   r/   r0   r  ;  s    


r  zN
    The tensorhead() function is deprecated. Use tensor_heads() instead.
    zdeprecated-tensorheadc                 C  s\   |du rdd t t|D }tt t| }W d   n1 s"w   Y  t| |||S )ao  
    Function generating tensorhead(s). This method is deprecated,
    use TensorHead constructor or tensor_heads() instead.

    Parameters
    ==========

    name : name or sequence of names (as in ``symbols``)

    typ :  index types

    sym :  same as ``*args`` in ``tensorsymmetry``

    comm : commutation group number
    see ``_TensorManager.set_comm``
    Nc                 S  s   g | ]}d gqS r\   r/   rN   r/   r/   r0   rQ     rR   ztensorhead.<locals>.<listcomp>)r   rE   r$   r#   r  r   )rb   rh   r   r   r/   r/   r0   r  ~  s   

r  c                   @  s   e Zd ZdZdZd#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dd Zdd Zdd Zdd Zedd Zejdd Zejdd Zdd  Zd!d" ZdS )$r   at  
    Tensor head of the tensor.

    Parameters
    ==========

    name : name of the tensor
    index_types : list of TensorIndexType
    symmetry : TensorSymmetry of the tensor
    comm : commutation group number

    Attributes
    ==========

    ``name``
    ``index_types``
    ``rank`` : total number of indices
    ``symmetry``
    ``comm`` : commutation group

    Notes
    =====

    Similar to ``symbols`` multiple TensorHeads can be created using
    ``tensorhead(s, typ, sym=None, comm=0)`` function, where ``s``
    is the string of names and ``sym`` is the monoterm tensor symmetry
    (see ``tensorsymmetry``).

    A ``TensorHead`` belongs to a commutation group, defined by a
    symbol on number ``comm`` (see ``_TensorManager.set_comm``);
    tensors in a commutation group have the same commutation properties;
    by default ``comm`` is ``0``, the group of the commuting tensors.

    Examples
    ========

    Define a fully antisymmetric tensor of rank 2:

    >>> from sympy.tensor.tensor import TensorIndexType, TensorHead, TensorSymmetry
    >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
    >>> asym2 = TensorSymmetry.fully_symmetric(-2)
    >>> A = TensorHead('A', [Lorentz, Lorentz], asym2)

    Examples with ndarray values, the components data assigned to the
    ``TensorHead`` object are assumed to be in a fully-contravariant
    representation. In case it is necessary to assign components data which
    represents the values of a non-fully covariant tensor, see the other
    examples.

    >>> from sympy.tensor.tensor import tensor_indices
    >>> from sympy import diag
    >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
    >>> i0, i1 = tensor_indices('i0:2', Lorentz)

    Specify a replacement dictionary to keep track of the arrays to use for
    replacements in the tensorial expression. The ``TensorIndexType`` is
    associated to the metric used for contractions (in fully covariant form):

    >>> repl = {Lorentz: diag(1, -1, -1, -1)}

    Let's see some examples of working with components with the electromagnetic
    tensor:

    >>> from sympy import symbols
    >>> Ex, Ey, Ez, Bx, By, Bz = symbols('E_x E_y E_z B_x B_y B_z')
    >>> c = symbols('c', positive=True)

    Let's define `F`, an antisymmetric tensor:

    >>> F = TensorHead('F', [Lorentz, Lorentz], asym2)

    Let's update the dictionary to contain the matrix to use in the
    replacements:

    >>> repl.update({F(-i0, -i1): [
    ... [0, Ex/c, Ey/c, Ez/c],
    ... [-Ex/c, 0, -Bz, By],
    ... [-Ey/c, Bz, 0, -Bx],
    ... [-Ez/c, -By, Bx, 0]]})

    Now it is possible to retrieve the contravariant form of the Electromagnetic
    tensor:

    >>> F(i0, i1).replace_with_arrays(repl, [i0, i1])
    [[0, -E_x/c, -E_y/c, -E_z/c], [E_x/c, 0, -B_z, B_y], [E_y/c, B_z, 0, -B_x], [E_z/c, -B_y, B_x, 0]]

    and the mixed contravariant-covariant form:

    >>> F(i0, -i1).replace_with_arrays(repl, [i0, -i1])
    [[0, E_x/c, E_y/c, E_z/c], [E_x/c, 0, B_z, -B_y], [E_y/c, -B_z, 0, B_x], [E_z/c, B_y, -B_x, 0]]

    Energy-momentum of a particle may be represented as:

    >>> from sympy import symbols
    >>> P = TensorHead('P', [Lorentz], TensorSymmetry.no_symmetry(1))
    >>> E, px, py, pz = symbols('E p_x p_y p_z', positive=True)
    >>> repl.update({P(i0): [E, px, py, pz]})

    The contravariant and covariant components are, respectively:

    >>> P(i0).replace_with_arrays(repl, [i0])
    [E, p_x, p_y, p_z]
    >>> P(-i0).replace_with_arrays(repl, [-i0])
    [E, -p_x, -p_y, -p_z]

    The contraction of a 1-index tensor by itself:

    >>> expr = P(i0)*P(-i0)
    >>> expr.replace_with_arrays(repl, [])
    E**2 - p_x**2 - p_y**2 - p_z**2
    FNr   c                 C  st   t |tr
t|}nt |tr|}ntd|d u r"tt|}n	|jt|ks+J t	| |t
| |t|}|S )Nr  )r   r|   r   rd   r   r{  rE   r   r   rk  r   r   )rm  rb   rC   r   r   r  rr  r/   r/   r0   rk    s   


zTensorHead.__new__c                 C  rs  r:   rt  rm   r/   r/   r0   rb     ru  zTensorHead.namec                 C     t | jd S r   r   r   rm   r/   r/   r0   rC   #     zTensorHead.index_typesc                 C  rv  r   rw  rm   r/   r/   r0   r   '  rx  zTensorHead.symmetryc                 C  s   t | jd S ry  )r   r]  r   rm   r/   r/   r0   r   +  r  zTensorHead.commc                 C  
   t | jS rV   )rE   rC   rm   r/   r/   r0   r   /  rx  zTensorHead.rankc                 C  r  rV   )rb   rC   r  r/   r/   r0   r  3     zTensorHead.__lt__c                 C  s   t | j|j}|S )z
        Returns ``0`` if ``self`` and ``other`` commute, ``1`` if they anticommute.

        Returns ``None`` if ``self`` and ``other`` neither commute nor anticommute.
        )r   r   r   )rH   r  rr/   r/   r0   commutes_with6  s   zTensorHead.commutes_withc                 C  s    d| j ddd | jD f S )N%s(%s),c                 S  r   r/   r  r   r/   r/   r0   rQ   @  r   z%TensorHead._print.<locals>.<listcomp>)rb   joinrC   rm   r/   r/   r0   r  ?  s    zTensorHead._printc                 O  s   g }t || jD ]3\}}t|tr6| dd}|dr-|t|dd |dd q|t|| q|| q||t	|d 7 }t
| |fi |}| S )a  
        Returns a tensor with indices.

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

        There is a special behavior in case of indices denoted by ``True``,
        they are considered auto-matrix indices, their slots are automatically
        filled, and confer to the tensor the behavior of a matrix or vector
        upon multiplication with another tensor containing auto-matrix indices
        of the same ``TensorIndexType``. This means indices get summed over the
        same way as in matrix multiplication. For matrix behavior, define two
        auto-matrix indices, for vector behavior define just one.

        Indices can also be strings, in which case the attribute
        ``index_types`` is used to convert them to proper ``TensorIndex``.

        Examples
        ========

        >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorSymmetry, TensorHead
        >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
        >>> a, b = tensor_indices('a,b', Lorentz)
        >>> A = TensorHead('A', [Lorentz]*2, TensorSymmetry.no_symmetry(2))
        >>> t = A(a, -b)
        >>> t
        A(a, -b)

          -r\   NFr   )r   rC   r   r|   stripreplace
startswithre   rq   rE   r   doit)rH   rD   r  updated_indicesrr   rh   r  r/   r/   r0   rN  B  s   


zTensorHead.__call__c                 C  s   t   ttH | jd u rtdddlm}m} dd | jD }| j}|	 }|D ]}||||}||d|f|d |d f}q*||t
j  W  d    S 1 sRw   Y  d S )NzNo power on abstract tensors.r\   r7  c                 S  rK   r/   )r   rO   rx   r/   r/   r0   rQ   z  rR   z&TensorHead.__pow__.<locals>.<listcomp>r   r8   )r1   r$   r#   r   rd   r   r  r  rC   r   r   Half)rH   r  r  r  metricsmarray	marraydimr   r/   r/   r0   __pow__t  s   

$zTensorHead.__pow__c                 C  r  rV   r  rm   r/   r/   r0   r     r  zTensorHead.datac                 C  <   t   tt |t| < W d    d S 1 sw   Y  d S rV   r  rH   r   r/   r/   r0   r        

"c                 C  s   t   | tv rt| = d S d S rV   )r1   r  rm   r/   r/   r0   r     s   
c                 C  <   t   tt | j W  d    S 1 sw   Y  d S rV   r1   r$   r#   r   __iter__rm   r/   r/   r0   r       
$zTensorHead.__iter__c                 C  s*   t   | jdkr
dS | tv rt| = dS dS )z
        EXPERIMENTAL: do not rely on this API method.

        Destroy components data associated to the ``TensorHead`` object, this
        checks for attached components data, and destroys components data too.
        r|  N)r1   rb   r  rm   r/   r/   r0   r    s   	

z(TensorHead._components_data_full_destroyr:   )r   r   r   r   r  rk  rg  rb   rC   r   r   r   r  r  r  rN  r  r   r  r  r  r  r/   r/   r/   r0   r     s6    o





	2


r   c                   sX   t | trdd t| ddD }ntd fdd|D }t|dkr*|d S |S )	z=
    Returns a sequence of TensorHeads from a string `s`
    c                 S  rK   r/   r  r   r/   r/   r0   rQ     rR   z tensor_heads.<locals>.<listcomp>Tr  r  c                   s   g | ]	}t | qS r/   )r   r  r   rC   r   r/   r0   rQ     r   r\   r   r  )r  rC   r   r   r  thlistr/   r  r0   tensor_heads  s   
r  c                   @  sZ  e Zd ZdZdZdZdd Zdd Zdd	 Zd
d Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zeedd Zeedd Zed d! ZedKd$d%ZedLd(d)Zd*d+ Zd,d- Zed.d/ Zd0d1 Zd2d3 Zd4d5 Zd6d7 Z d8d9 Z!ed:d; Z"ed<d= Z#ed>d? Z$ed@dA Z%edBdC Z&dMdEdFZ'dGdH Z(dIdJ Z)dDS )Nr   a  
    Abstract base class for tensor expressions

    Notes
    =====

    A tensor expression is an expression formed by tensors;
    currently the sums of tensors are distributed.

    A ``TensExpr`` can be a ``TensAdd`` or a ``TensMul``.

    ``TensMul`` objects are formed by products of component tensors,
    and include a coefficient, which is a SymPy expression.


    In the internal representation contracted indices are represented
    by ``(ipos1, ipos2, icomp1, icomp2)``, where ``icomp1`` is the position
    of the component tensor with contravariant index, ``ipos1`` is the
    slot which the index occupies in that component tensor.

    Contracted indices are therefore nameless in the internal representation.
    g      (@Fc                 C  s
   | t j S rV   )r   NegativeOnerm   r/   r/   r0   r    r0  zTensExpr.__neg__c                 C     t rV   r  rm   r/   r/   r0   __abs__     zTensExpr.__abs__c                 C     t | | S rV   r   r  r  r/   r/   r0   __add__     zTensExpr.__add__c                 C     t ||  S rV   r  r  r/   r/   r0   __radd__  r  zTensExpr.__radd__c                 C  s   t | |  S rV   r  r  r/   r/   r0   __sub__     zTensExpr.__sub__c                 C  s   t ||   S rV   r  r  r/   r/   r0   __rsub__  r  zTensExpr.__rsub__c                 C  r  )a  
        Multiply two tensors using Einstein summation convention.

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

        If the two tensors have an index in common, one contravariant
        and the other covariant, in their product the indices are summed

        Examples
        ========

        >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads
        >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
        >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz)
        >>> g = Lorentz.metric
        >>> p, q = tensor_heads('p,q', [Lorentz])
        >>> t1 = p(m0)
        >>> t2 = q(-m0)
        >>> t1*t2
        p(L_0)*q(-L_0)
        r   r  r  r/   r/   r0   __mul__  s   zTensExpr.__mul__c                 C  r  rV   r  r  r/   r/   r0   __rmul__  r  zTensExpr.__rmul__c                 C  s.   t |}t|trtdt| tj|  S Nzcannot divide by a tensor)r   r   r   rd   r   r   Oner  r  r/   r/   r0   __truediv__  s   
zTensExpr.__truediv__c                 C     t dr  )rd   r  r/   r/   r0   __rtruediv__  r   zTensExpr.__rtruediv__c                 C  s   t   ttE | jd u rtdddlm}m} | j}| j}|	 }|D ]}||||d j
j|d|f|d |d f}q%||tj  W  d    S 1 sOw   Y  d S )NzNo power without ndarray data.r\   r7  r   r8   )r1   r$   r#   r   rd   r   r  r  rA   r   rM   r   r  )rH   r  r  r  rA   r  r8  r   r/   r/   r0   r    s&   


$zTensExpr.__pow__c                 C  r  rV   r  r  r/   r/   r0   __rpow__#  r  zTensExpr.__rpow__c                 C  r  Nzabstract methodr  rm   r/   r/   r0   nocoeff&     zTensExpr.nocoeffc                 C  r  r  r  rm   r/   r/   r0   r  +  r	  zTensExpr.coeffc                 C  r  r  r  rm   r/   r/   r0   rn   0     zTensExpr.get_indicesr   r   c                 C  r  r  r  rm   r/   r/   r0   r   4  r
  zTensExpr.get_free_indicesrepldict[TensorIndex, TensorIndex]c                 C  r  r  r  rH   r  r/   r/   r0   _replace_indices8  r
  zTensExpr._replace_indicesc                 G  s   t   | j| S rV   )r5   substitute_indices)rH   index_tuplesr/   r/   r0   fun_eval<  s   
zTensExpr.fun_evalc                 C  s  ddl m} t  ttm d| j  k rdkrvn t
d| jjd }| jdkr/| jjd nd}| jdkrYg | }t|D ]}|	g  t|D ]}|| 	| ||f  qIq>ndg| }t|D ]}| | ||< qb||W  d   S t
d1 s}w   Y  dS )z
        DEPRECATED: do not use.

        Returns ndarray components data as a matrix, if components data are
        available and ndarray dimension does not exceed 2.
        r   )Matrixr8   r\   Nz-missing multidimensional reduction to matrix.)sympy.matrices.denser  r1   r$   r#   r   r   r%  r   re   r  )rH   r  rowscolumnsmat_listrP   r   r/   r/   r0   
get_matrix@  s4   



zTensExpr.get_matrixc                   s    fdd|D S )Nc                      g | ]}  |qS r/   r^   rN   indices1r/   r0   rQ   ^  r   z5TensExpr._get_indices_permutation.<locals>.<listcomp>r/   )r  indices2r/   r  r0   _get_indices_permutation\  s   z!TensExpr._get_indices_permutationc                 K  s   t | fi | S rV   )_expandr  rH   hintsr/   r/   r0   expand`  r   zTensExpr.expandc                 K     | S rV   r/   rH   rq  r/   r/   r0   r  c  r  zTensExpr._expandc                 C  .   t  }| jD ]}t|tr||  q|S rV   )r  r   r   r   update_get_free_indices_setrH   indsetr   r/   r/   r0   r&  f     

zTensExpr._get_free_indices_setc                 C  r$  rV   )r  r   r   r   r%  _get_dummy_indices_setr'  r/   r/   r0   r*  m  r)  zTensExpr._get_dummy_indices_setc                 C  r$  rV   )r  r   r   r   r%  _get_indices_setr'  r/   r/   r0   r+  t  r)  zTensExpr._get_indices_setc                       |     fdd| dS )Nc                 3  f    t | tr|  v r| |fV  d S d S t | ttfr/t| jD ]\}}|||f E d H  qd S d S rV   r   rq   r   r   ra   r   exprrk   pr   	dummy_setrecursorr/   r0   r4       
z1TensExpr._iterate_dummy_indices.<locals>.recursorr/   )r*  rm   r/   r2  r0   _iterate_dummy_indices{     
zTensExpr._iterate_dummy_indicesc                   r,  )Nc                 3  r-  rV   r.  r/  free_setr4  r/   r0   r4    r5  z0TensExpr._iterate_free_indices.<locals>.recursorr/   )r&  rm   r/   r8  r0   _iterate_free_indices  r7  zTensExpr._iterate_free_indicesc                   s    fdd  | dS )Nc                 3  sZ    t | tr| |fV  d S t | ttfr)t| jD ]\}} |||f E d H  qd S d S rV   r.  r/  r4  r/   r0   r4    s   
z+TensExpr._iterate_indices.<locals>.recursorr/   r/   rm   r/   r;  r0   _iterate_indices  s   
zTensExpr._iterate_indicesc                 C  s\   ddl m}m}m} ||| |dd| f}tt|}|| |d |d< ||< |||S )Nr\   )r  r  r   r8   r   )r   r  r  r   r   r   )r   r   rk   r&  r  r  r   permur/   r/   r0   !_contract_and_permute_with_metric  s
   
z*TensExpr._contract_and_permute_with_metricc                 C  s  ddl m} dd |D }g }g }|d d  }t|D ]`\}	}
|
|v r-||
}d ||< q|
 |v rO||
 }d ||< |
||< |
jrI|| q|| q||	 }|d u r_td||f d ||	< |
||	< |
j|jA r{|
jrv||	 q||	 qtt|t|@ t|k rtd||f |D ]!}|| }||vrtd|| }t	
|}t|| |t|} q|D ]}|| }||vrtd|| }t|| |t|} q|rt||}|| |} t| dr|  dkr| d	 } || fS )
Nr\   r   c                 S  rK   r/   rL   rN   r/   r/   r0   rQ     rR   z=TensExpr._match_indices_with_other_tensor.<locals>.<listcomp>zincompatible indices: %s and %sz!No metric provided to lower indexr   r   r/   )r   r   ra   r^   rc   re   rd   rE   r  r   r>  r   r>  r  rO  r   )r   	free_ind1	free_ind2replacement_dictr   index_types1pos2uppos2downfree2remainingrt   index1ru   index2rk   index_type_posr   metric_inverser   r/   r/   r0    _match_indices_with_other_tensor  s`   




z)TensExpr._match_indices_with_other_tensorNc           
        s*  ddl m  |p	g }dd |  D }t|D ]\}}t|ttfr5||v r-|| ||< q||   ||< q fdd| D }| D ]<\}ttrZfddt	dD }nd	d j
D }t|| kswtd
d t||jD std||jf qE| |\}}| ||||\}	}|S )aA  
        Replace the tensorial expressions with arrays. The final array will
        correspond to the N-dimensional array with indices arranged according
        to ``indices``.

        Parameters
        ==========

        replacement_dict
            dictionary containing the replacement rules for tensors.
        indices
            the index order with respect to which the array is read. The
            original index order will be used if no value is passed.

        Examples
        ========

        >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices
        >>> from sympy.tensor.tensor import TensorHead
        >>> from sympy import symbols, diag

        >>> L = TensorIndexType("L")
        >>> i, j = tensor_indices("i j", L)
        >>> A = TensorHead("A", [L])
        >>> A(i).replace_with_arrays({A(i): [1, 2]}, [i])
        [1, 2]

        Since 'indices' is optional, we can also call replace_with_arrays by
        this way if no specific index order is needed:

        >>> A(i).replace_with_arrays({A(i): [1, 2]})
        [1, 2]

        >>> expr = A(i)*A(j)
        >>> expr.replace_with_arrays({A(i): [1, 2]})
        [[1, 2], [2, 4]]

        For contractions, specify the metric of the ``TensorIndexType``, which
        in this case is ``L``, in its covariant form:

        >>> expr = A(i)*A(-i)
        >>> expr.replace_with_arrays({A(i): [1, 2], L: diag(1, -1)})
        -3

        Symmetrization of an array:

        >>> H = TensorHead("H", [L, L])
        >>> a, b, c, d = symbols("a b c d")
        >>> expr = H(i, j)/2 + H(j, i)/2
        >>> expr.replace_with_arrays({H(i, j): [[a, b], [c, d]]})
        [[a, b/2 + c/2], [b/2 + c/2, d]]

        Anti-symmetrization of an array:

        >>> expr = H(i, j)/2 - H(j, i)/2
        >>> repl = {H(i, j): [[a, b], [c, d]]}
        >>> expr.replace_with_arrays(repl)
        [[0, b/2 - c/2], [-b/2 + c/2, 0]]

        The same expression can be read as the transpose by inverting ``i`` and
        ``j``:

        >>> expr.replace_with_arrays(repl, [j, i])
        [[0, -b/2 + c/2], [b/2 - c/2, 0]]
        r\   Arrayc                 S  s*   i | ]}|j r|jd  n|jd   |qS r   )rc   r   )rO   kr/   r/   r0   r   0	  s   * z0TensExpr.replace_with_arrays.<locals>.<dictcomp>c                      i | ]	\}}| |qS r/   r/   )rO   r  r   rK  r/   r0   r   8	  r   c                   s   g | ]} j qS r/   r&  rN   )r  r/   r0   rQ   =	  rR   z0TensExpr.replace_with_arrays.<locals>.<listcomp>r8   c                 S  rK   r/   rO  )rO   
index_typer/   r/   r0   rQ   ?	  rR   c                 s  s&    | ]\}}|j r||knd V  qdS )TN)r'  )rO   r  r  r/   r/   r0   r   @	  s    


z/TensExpr.replace_with_arrays.<locals>.<genexpr>zEshapes for tensor %s expected to be %s, replacement array shape is %s)r   rL  r   ra   r   r   r   itemsr  r   rC   rE   r   r   r   r%  rd   _extract_datarJ  )
rH   rA  rD   remaprP   r^   r   expected_shaperet_indiceslast_indicesr/   )rL  r  r0   replace_with_arrays  s8   B
zTensExpr.replace_with_arraysc                   sF   ddl m} |  | j} fdd|D }|r!||g|R  }|S )Nr   Sumc                   s*   g | ]\}} | d | j jd fqS r   )rM   r&  )rO   rP   r   index_symbolsrD   r/   r0   rQ   P	  s
    z+TensExpr._check_add_Sum.<locals>.<listcomp>)sympy.concrete.summationsrY  rn   rB   )rH   r0  r[  rY  rB   sum_indicesr/   rZ  r0   _check_add_SumL	  s   zTensExpr._check_add_Sumc                 C  s   | j dd | jD  S )Nc                 S  s"   g | ]}t |tr| n|qS r/   )r   r   _expand_partial_derivativerO   r   r/   r/   r0   rQ   Y	  s    
z7TensExpr._expand_partial_derivative.<locals>.<listcomp>funcr   rm   r/   r/   r0   r_  V	  s   
z#TensExpr._expand_partial_derivativer   r  r  r   r   rV   )*r   r   r   r   _op_priorityr  r  r  r  r  r  r  r  r   r  r  r  r  rg  r   r  r  rn   r   r  r  r  r   r  r!  r  r&  r*  r+  r6  r:  r<  r>  rJ  rW  r^  r_  r/   r/   r/   r0   r     sd    






	

>a
r   c                   @  s,  e Zd ZdZdd Zedd Zedd Zd@d
dZdAddZ	e
dd Ze
dd Ze
dd Zdd Zedd Ze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/d0 Zd1d2 Zd3d4 Zed5d6 Zejd7d6 Zej d8d6 Zd9d: Z!d;d< Z"d=d> Z#d?S )Br   a  
    Sum of tensors.

    Parameters
    ==========

    free_args : list of the free indices

    Attributes
    ==========

    ``args`` : tuple of addends
    ``rank`` : rank of the tensor
    ``free_args`` : list of the free indices in sorted order

    Examples
    ========

    >>> from sympy.tensor.tensor import TensorIndexType, tensor_heads, tensor_indices
    >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
    >>> a, b = tensor_indices('a,b', Lorentz)
    >>> p, q = tensor_heads('p,q', [Lorentz])
    >>> t = p(a) + q(a); t
    p(a) + q(a)

    Examples with components data added to the tensor expression:

    >>> from sympy import symbols, diag
    >>> x, y, z, t = symbols("x y z t")
    >>> repl = {}
    >>> repl[Lorentz] = diag(1, -1, -1, -1)
    >>> repl[p(a)] = [1, 2, 3, 4]
    >>> repl[q(a)] = [x, y, z, t]

    The following are: 2**2 - 3**2 - 2**2 - 7**2 ==> -58

    >>> expr = p(a) + q(a)
    >>> expr.replace_with_arrays(repl, [a])
    [x + 1, y + 2, z + 3, t + 4]
    c                 O  sZ   dd |D }t |}|jtd |stjS t|dkr!|d S tj| g|R i |S )Nc                 S  s   g | ]}|rt |qS r/   )r   r   r/   r/   r0   rQ   	      z#TensAdd.__new__.<locals>.<listcomp>r?   r\   r   )	r   _tensAdd_flattenrG   r   r   ZerorE   r   rk  )rm  r   r  r/   r/   r0   rk  	  s   
zTensAdd.__new__c                 C     t jS rV   r   r  rm   r/   r/   r0   r  	  r\  zTensAdd.coeffc                 C  r"  rV   r/   rm   r/   r/   r0   r  	     zTensAdd.nocoeffr   r   c                 C  r[  rV   )free_indicesrm   r/   r/   r0   r   	  r  zTensAdd.get_free_indicesr  r  r   c                   s    fdd| j D }| j| S )Nc                   $   g | ]}t |tr| n|qS r/   r   r   r  r   r  r/   r0   rQ   	     $ z,TensAdd._replace_indices.<locals>.<listcomp>)r   rb  )rH   r  newargsr/   rn  r0   r  	  s   
zTensAdd._replace_indicesc                 C  s    t | jd tr| jd jS dS r:   )r   r   r   r   rm   r/   r/   r0   r   	     zTensAdd.rankc                 C  s    t | jd tr| jd jS g S r:   )r   r   r   r   rm   r/   r/   r0   r   	  rq  zTensAdd.free_argsc                 C  s$   t | jd tr| jd  S t S r:   )r   r   r   r   r  rm   r/   r/   r0   rk  	  s   zTensAdd.free_indicesc                   s     dd}|r fdd| jD }n| j}dd |D }t|dkr&tjS t|dkr0|d S t| t|}dd	 }|j|d
 |sItjS t|dkrS|d S | j	| }|S )NdeepTc                      g | ]
}|j d i  qS r/   r  r   r   r/   r0   rQ   	      z TensAdd.doit.<locals>.<listcomp>c                 S  s   g | ]	}|t jkr|qS r/   )r   rg  r   r/   r/   r0   rQ   	  r   r   r\   c                 S  sJ   t | ts
g g g fS t| dr t| dr t| }| j|j|jfS g g g fS )N_index_structurerY   )r   r   rO  get_index_structurerY   rA   rB   )r   r<   r/   r/   r0   sort_key	  s   


zTensAdd.doit.<locals>.sort_keyr?   )
re  r   rE   r   rg  r   _tensAdd_check_tensAdd_collect_termsrG   rb  )rH   r   rr  r   rz  rr  r/   rv  r0   r  	  s&   


zTensAdd.doitc                 C  sJ   g }| D ]}t |ttfr|t|j q|| qdd |D } | S )Nc                 S  s   g | ]}|j r|qS r/   r  r   r/   r/   r0   rQ   	  r   z,TensAdd._tensAdd_flatten.<locals>.<listcomp>)r   r   r   rW   r   r   re   )r   r   r<   r/   r/   r0   rf  	  s   zTensAdd._tensAdd_flattenc                   sR   ddd  | d  fdd	| d
d  D }t fdd|D s'tdd S )Nr<   r   r   set[TensorIndex]c                 S  s   t | trt|  S t S rV   )r   r   r  r   r;   r/   r/   r0   get_indices_set	  s   
z/TensAdd._tensAdd_check.<locals>.get_indices_setr   c                      g | ]} |qS r/   r/   r   )r  r/   r0   rQ   	  r   z*TensAdd._tensAdd_check.<locals>.<listcomp>r\   c                 3  s    | ]}| kV  qd S rV   r/   r   )indices0r/   r0   r   	  r   z)TensAdd._tensAdd_check.<locals>.<genexpr>z&all tensors must have the same indices)r<   r   r   r~  )r   rd   )r   list_indicesr/   )r  r  r0   r{  	  s   
zTensAdd._tensAdd_checkc                 C  s   t t}tj}t| d trt| d  }nt }| D ]*}t|ts1|t kr,td||7 }q|t| kr=td||j	 
|j qdd | D }t|tr^t|j| }|S |dkrg|g| }|S )Nr   zwrong valencec                 S  s.   g | ]\}}t | d krtt | | qS r   )r   r   r  )rO   r   r  r/   r/   r0   rQ   
  s   . z2TensAdd._tensAdd_collect_terms.<locals>.<listcomp>)r   r   r   rg  r   r   r  r   rd   r  re   r  rQ  r   r   )r   
terms_dictscalarsrk  r   new_argsr/   r/   r0   r|  	  s*   



zTensAdd._tensAdd_collect_termsc                   s0   g  | j D ]}  fddt|D  q S )Nc                      g | ]}| vr|qS r/   r/   rN   rl   r/   r0   rQ   
  re  z'TensAdd.get_indices.<locals>.<listcomp>)r   rW   rn   )rH   r   r/   rl   r0   rn   
  s   
zTensAdd.get_indicesc                   s   t  fdd| jD  S )Nc                      g | ]
}t |fi  qS r/   r  rN   rv  r/   r0   rQ   
  rw  z#TensAdd._expand.<locals>.<listcomp>)r   r   r  r/   rv  r0   r  
  r  zTensAdd._expandc                   sv   t   | j}t|}dd |D dd |D krtd||kr"| S tt||  fdd| jD }t|  }|S )Nc                 S  rK   r/   rL   r   r/   r/   r0   rQ   $
  rR   z$TensAdd.__call__.<locals>.<listcomp>incompatible typesc                   s   g | ]}|j |j  j qS r/   )rb  r  r   r   r  r/   r0   rQ   )
  r  )r6   r   r   rd   r   r   r   r  )rH   rD   r   r   resr/   r  r0   rN   
  s   zTensAdd.__call__c                 C  s(   |   }dd |jD }t|  }|S )zz
        Canonicalize using the Butler-Portugal algorithm for canonicalization
        under monoterm symmetries.
        c                 S  r   r/   rI   r   r/   r/   r0   rQ   3
  r   z$TensAdd.canon_bp.<locals>.<listcomp>)r!  r   r   r  )rH   r0  r   r  r/   r/   r0   rI   -
  s   zTensAdd.canon_bpc                 C  s   t |}t|tr|jdkrtdd | jD S t|tr%| j|jkr%dS t|tr8t	| jt	|jkr6dS dS | | }t|tsE|dkS t|trO|jdkS tdd |jD S )Nr   c                 s      | ]}|j d kV  qdS r   Nr}  r   r/   r/   r0   r   :
      z!TensAdd.equals.<locals>.<genexpr>FTc                 s  r  r  r}  r   r/   r/   r0   r   J
  r  )
r   r   r   r  r   r   r   r   r   r  )rH   r  r   r/   r/   r0   equals7
  s    




zTensAdd.equalsc                 C  <   t   tt | j| W  d    S 1 sw   Y  d S rV   r1   r$   r#   r   rH   itemr/   r/   r0   r   L
  r  zTensAdd.__getitem__c                   (    fdd| j D }t|  }t|S )Nc                   s   g | ]}|  qS r/   )contract_deltar   r}  r/   r0   rQ   R
  r   z*TensAdd.contract_delta.<locals>.<listcomp>r   r   r  rI   )rH   r}  r   r   r/   r  r0   r  Q
  s   zTensAdd.contract_deltac                   r  )a1  
        Raise or lower indices with the metric ``g``.

        Parameters
        ==========

        g :  metric

        contract_all : if True, eliminate all ``g`` which are contracted

        Notes
        =====

        see the ``TensorIndexType`` docstring for the contraction conventions
        c                   r  r/   contract_metricr   r   r/   r0   rQ   g
  r   z+TensAdd.contract_metric.<locals>.<listcomp>r  )rH   r   r   r   r/   r  r0   r  V
  s   zTensAdd.contract_metricc                 G  :   g }| j D ]}t|tr|j| }|| qt|  S rV   )r   r   r   r  re   r   r  rH   r  r  r   r/   r/   r0   r  k
     


zTensAdd.substitute_indicesc                 C  s<   g }| j }|D ]	}|t| qd|}|dd}|S )Nz + z+ -z- )r   re   r|   r  r  )rH   r   r   r<   r  r/   r/   r0   r  s
  s   
zTensAdd._printc           
        s   ddl m m} tfdd| jD  \}} fdd|D }|d }tdt|D ]}|| }|| }t||}	|||	||< q*|t	| j
|j fS )Nr   )rL  r   c                   s(   g | ]}t |tr| ng |fqS r/   r   r   rR  r   rA  r/   r0   rQ   ~
  s
    
z)TensAdd._extract_data.<locals>.<listcomp>c                   r  r/   r/   rN   rK  r/   r0   rQ   
  r   r\   )sympy.tensor.arrayrL  r   r   r   r   rE   r   r  sumr  r%  )
rH   rA  r   args_indicesr  ref_indicesrP   rD   r   r   r/   )rL  rA  r0   rR  |
  s   zTensAdd._extract_datac                 C  s>   t   tt t|   W  d    S 1 sw   Y  d S rV   r1   r$   r#   r  r!  rm   r/   r/   r0   r   
  s   

$zTensAdd.datac                 C  r  rV   r  r  r/   r/   r0   r   
  r  c                 C  sR   t   tt | tv rt| = W d    d S W d    d S 1 s"w   Y  d S rV   r  rm   r/   r/   r0   r   
  s   
"c                 C  s"   t   | js
td| j  S Nz No iteration on abstract tensors)r1   r   rd   flattenr  rm   r/   r/   r0   r  
  s   zTensAdd.__iter__c                 O  s
   t |S rV   )r   fromiter)rH   r   rq  r/   r/   r0   _eval_rewrite_as_Indexed
  r0  z TensAdd._eval_rewrite_as_Indexedc                 C  sL   g }| j D ]}t|tr||| q|jr ||| q| j| S rV   )r   r   r   re   _eval_partial_derivative	_diff_wrt_eval_derivativerb  )rH   r  list_addendsr   r/   r/   r0   r  
  s   


z TensAdd._eval_partial_derivativeNr   rc  )$r   r   r   r   rk  rg  r  r  r   r  r%   r   r   rk  r  r   rf  r{  r|  rn   r  rN  rI   r  r   r  r  r  r  rR  r   r  r  r  r  r  r/   r/   r/   r0   r   _	  sT    )






(



	


r   c                   @  s(  e Zd ZU dZdZdZded< dd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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dpd'd(Zddd)d*Zd+d, Zd-d. Zd/d0 Zed1d2 Zed3d4 Zed5d6 Z d7d8 Z!dpd9d:Z"d;d< Z#d=d> Z$d?d@ Z%dAdB Z&dqdEdFZ'dqdGdHZ(drdLdMZ)dNdO Z*dPdQ Z+dRdS Z,dsdTdUZ-dsdVdWZ.dXdY Z/dZd[ Z0d\d] Z1d^d_ Z2ed`da Z3e3j4dbda Z3e3j5dcda Z3ddde Z6dfdg Z7dhdi Z8djdk Z9dldm Z:dndo Z;dS )tr   a  
    Base tensor class, i.e. this represents a tensor, the single unit to be
    put into an expression.

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

    This object is usually created from a ``TensorHead``, by attaching indices
    to it. Indices preceded by a minus sign are considered contravariant,
    otherwise covariant.

    Examples
    ========

    >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorHead
    >>> Lorentz = TensorIndexType("Lorentz", dummy_name="L")
    >>> mu, nu = tensor_indices('mu nu', Lorentz)
    >>> A = TensorHead("A", [Lorentz, Lorentz])
    >>> A(mu, -nu)
    A(mu, -nu)
    >>> A(mu, -mu)
    A(L_0, -L_0)

    It is also possible to use symbols instead of inidices (appropriate indices
    are then generated automatically).

    >>> from sympy import Symbol
    >>> x = Symbol('x')
    >>> A(x, mu)
    A(x, mu)
    >>> A(x, -x)
    A(L_0, -L_0)

    FNztuple[TensorHead, Tuple]r   r   c                K  s   |  ||}tj| |t| fi |}tj| |_|jjd d  |_|jj	d d  |_
|jj|_tj|_||_||_|g|_|jt|krItd||_t||j|_|S )Nwrong number of indices)_parse_indicesr   rk  r   r7   rU   rx  rA   _freerB   _dumrF   r   r  _coeff_nocoeff
_component_componentsr   rE   rd   r   r   _build_index_map
_index_map)rm  tensor_headrD   r   r  rr  r/   r/   r0   rk  
  s   
zTensor.__new__c                 C  r[  rV   r  rm   r/   r/   r0   rA   
  r\  zTensor.freec                 C  r[  rV   r  rm   r/   r/   r0   rB   
  r\  z
Tensor.dumc                 C  r[  rV   rF   rm   r/   r/   r0   r   
  r\  zTensor.ext_rankc                 C  r[  rV   r  rm   r/   r/   r0   r  
  r\  zTensor.coeffc                 C  r[  rV   )r  rm   r/   r/   r0   r  
  r\  zTensor.nocoeffc                 C  r[  rV   )r  rm   r/   r/   r0   rZ     r\  zTensor.componentc                 C  r[  rV   )r  rm   r/   r/   r0   rY     r\  zTensor.componentsc                 C  rv  r:   rw  rm   r/   r/   r0   head
  rx  zTensor.headc                 C  rv  r   rw  rm   r/   r/   r0   rD     rx  zTensor.indicesc                 C  s   t | j S rV   )r  rx  r   rm   r/   r/   r0   rk    r  zTensor.free_indicesc                 C  s   | j jS rV   )r  rC   rm   r/   r/   r0   rC     r
  zTensor.index_typesc                 C  r  rV   )rE   rk  rm   r/   r/   r0   r     rx  zTensor.rankc                 C  s"   i }| D ]
}|  |f||< q|S rV   r  )rD   index_structure	index_maprr   r/   r/   r0   r    s   zTensor._build_index_mapc                 K  s   t | g\}}}}|d S r:   )r   _tensMul_contract_indices)rH   r   r   rD   rA   rB   r/   r/   r0   r  %  s   zTensor.doitc                 C  s   t |tttfstdt| t|}t|D ]J\}}t |tr-t|| j	| d||< qt |t
rS| \}}|dkrMt |trMt|| j	| d||< qtd| t |tsbtd|t|f q|S )Nz"indices should be an array, got %sTr   Fzindex not understood: %szwrong type for index: %s is %s)r   r   r   r   r  typera   r   rq   rC   r   as_coeff_Mulrd   )r  rD   rP   r^   r`  er/   r/   r0   r  )  s   


zTensor._parse_indicesc                 C     |  }| j|d|iS Nr   rn   _set_indicesrH   imr   rD   r/   r/   r0   _set_new_index_structure;     zTensor._set_new_index_structurec                O  s0   t || jkrtd| j| jd ||d S )Nindices length mismatchr   r  )rE   r   rd   rb  r   r  )rH   r   rD   r  r/   r/   r0   r  ?  s   zTensor._set_indicesc                 C  s   dd | j jD S )Nc                 S     h | ]}|d  qS r   r/   rN   r/   r/   r0   	<setcomp>E  r   z/Tensor._get_free_indices_set.<locals>.<setcomp>)rx  rA   rm   r/   r/   r0   r&  D  r   zTensor._get_free_indices_setc                   s.   t tj| jj   fddt| jd D S )Nc                      h | ]
\}}| v r|qS r/   r/   rO   rP   rr   	dummy_posr/   r0   r  I  rw  z0Tensor._get_dummy_indices_set.<locals>.<setcomp>r\   )r  	itertoolschainrx  rB   ra   r   rm   r/   r  r0   r*  G  s   zTensor._get_dummy_indices_setc                 C  s   t | jd jS r   )r  r   rm   r/   r/   r0   r+  K  r  zTensor._get_indices_setc                 C     dd | j D S )Nc                 S  s   g | ]	\}}||d fqS r   r/   rO   r   rk   r/   r/   r0   rQ   P  r   z'Tensor.free_in_args.<locals>.<listcomp>r_   rm   r/   r/   r0   free_in_argsN  r  zTensor.free_in_argsc                 C  r  )Nc                 S  s   g | ]
\}}||d d fqS r   r/   rO   p1p2r/   r/   r0   rQ   T  rw  z&Tensor.dum_in_args.<locals>.<listcomp>)rB   rm   r/   r/   r0   dum_in_argsR  r  zTensor.dum_in_argsc                 C     t dd | jD S )Nc                 S  r   r   r/   r   r/   r/   r0   rQ   X  r   z$Tensor.free_args.<locals>.<listcomp>r   rm   r/   r/   r0   r   V     zTensor.free_argsc                 C  s*   t |tsdS t |tr| j|jS tS )z
        :param other:
        :return:
            0  commute
            1  anticommute
            None  neither commute nor anticommute
        r   )r   r   r   rZ   r  r  r  r/   r/   r0   r  Z  s
   

zTensor.commutes_withc                 C  s   t | ||S )z
        Returns the tensor corresponding to the permutation ``g``.

        For further details, see the method in ``TIDS`` with the same name.
        r   rH   r   r   r/   r/   r0   r   h  s   zTensor.perm2tensorc                 C  s`   | j r| S |  }|j \}}}t|jg}t|||g|R  }|dkr(tjS | 	|d}|S )Nr   T)
r   r!  rx  r   r   rZ   r   r   rg  r   )rH   r0  r   r   r   r   canr  r/   r/   r0   rI   p  s   zTensor.canon_bpc                 C  s   | gS rV   r/   rm   r/   r/   r0   r   |  r  zTensor.splitc                 K  r"  rV   r/   r#  r/   r/   r0   r    r  zTensor._expandc                 C  r"  rV   r/   rm   r/   r/   r0   sorted_components  r  zTensor.sorted_componentsr   r   c                 C  r  )zN
        Get a list of indices, corresponding to those of the tensor.
        r\   r  rm   r/   r/   r0   rn     ro   zTensor.get_indicesc                 C  
   | j  S )zS
        Get a list of free indices, corresponding to those of the tensor.
        rx  r   rm   r/   r/   r0   r     r_  zTensor.get_free_indicesr  r  r   c                 C  
   |  |S rV   xreplacer  r/   r/   r0   r    s   
zTensor._replace_indicesc                 C  s
   | t jfS rV   ri  rm   r/   r/   r0   as_base_exp  r0  zTensor.as_base_expc                 G  sr   g }| j D ].}|D ]$\}}|j|jkr-|j|jkr-|j|jkr%|| n||   nq	|| q| j| S )a  
        Return a tensor with free indices substituted according to ``index_tuples``.

        ``index_types`` list of tuples ``(old_index, new_index)``.

        Examples
        ========

        >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads, TensorSymmetry
        >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
        >>> i, j, k, l = tensor_indices('i,j,k,l', Lorentz)
        >>> A, B = tensor_heads('A,B', [Lorentz]*2, TensorSymmetry.fully_symmetric(2))
        >>> t = A(i, k)*B(-k, -j); t
        A(i, L_0)*B(-L_0, -j)
        >>> t.substitute_indices((i, k),(-j, l))
        A(k, L_0)*B(-L_0, l)
        )rD   rb   rM   rc   re   r  )rH   r  rD   r^   ind_oldind_newr/   r/   r0   r    s   


zTensor.substitute_indicesc           
        s   | j }|jj}|j}d}| h}||krV| }|D ]8}|D ]3 |  fddtd|D }d ||  }tt	fdd|D }	|
|||	  qq||ks|S )zl
        Return a list giving all possible permutations of self that are allowed by its symmetries.
        Nc                   r  r/   )applyrN   )genr/   r0   rQ     r   z1Tensor._get_symmetrized_forms.<locals>.<listcomp>r   r   c                   r   r/   r/   rN   )indsr/   r0   rQ     r   )rZ   r   r   r   rA  rn   r   r  dictr   addr  )
rH   compgensr   	old_perms	new_permsr  persignind_mapr/   )r  r  r0   _get_symmetrized_forms  s"   
zTensor._get_symmetrized_formsc                 C  s   t |}|d u ri }n| }| |kr|S t|tsd S | j|jkr$d S | D ]}| j|||d}|d ur?|| |  S q(d S )N)rB  )r   rA  r   r   r  r  _matchesr%  )rH   r0  	repl_dictrB  new_exprr4  r/   r/   r0   matches  s"   

zTensor.matchesc           	      C  s   t |}|du ri }n| }| |kr|S t|tsdS | j|jkr$dS |  }| }t|t|kr6dS tt|D ]-}|| }||| }|du rP dS | |	 v rd||   || krd dS |
| q<|S )zD
        This does not account for index symmetries of expr
        N)r   rA  r   r   r  rn   rE   r   r  keysr%  )	rH   r0  r  rB  	s_indices	e_indicesrP   s_indr4  r/   r/   r0   r    s.   
"zTensor._matchesc                 G     t   | j}t|}dd |D dd |D krtd||kr"| S | jtt|| }tdd |D t|kr?|j|j S |S )Nc                 S  rK   r/   rL   r   r/   r/   r0   rQ     rR   z#Tensor.__call__.<locals>.<listcomp>r  c                 S     h | ]
}|j r	|n| qS r/   r   rN   r/   r/   r0   r    rw  z"Tensor.__call__.<locals>.<setcomp>	r6   r   r   rd   r  r   rE   rb  r   rH   rD   r   r   r/   r/   r0   rN       zTensor.__call__c                 C  r  rV   r  rm   r/   r/   r0   r    r  zTensor.__iter__c                 C  r  rV   r  r  r/   r/   r0   r   $  r  zTensor.__getitem__c              	     s  ddl m  | D ]\}}t|tr#|jd | jd kr#|}|} n	q
td| |f  fdd| D } |}| j}|jtdkr_D ]}||vrUt	d| qIfdd	|D }t|dkr| 
 }|
 }	i }
|D ]9\}}|	|  |
|	| < ||fD ]'}|| j|	| jA r||| j }|| jrt|}| |||t|	}qqq||
 }t|g|t|	}|  }| }| ||||S )
Nr\   rK  r   z%s not found in %sc                   rN  r/   r/   rO   rM  r   rK  r/   r0   r   4  r   z(Tensor._extract_data.<locals>.<dictcomp>z'%s with contractions is not implementedc                   r  r/   r/   )rO   pair)dum2r/   r0   rQ   @  re  z(Tensor._extract_data.<locals>.<listcomp>)r   rL  rQ  r   r   r   rd   rB   rE   r  rn   rc   rM   r   r>  r>  r  r  r   r   rJ  )rH   rA  rM  r   r  r   dum1r  r  r  r  r  r  rk   r   r?  r@  r/   )rL  r  r0   rR  )  sJ   

zTensor._extract_datac                 C  r  rV   r  rm   r/   r/   r0   r   U  r  zTensor.datac                 C  r  rV   r  r  r/   r/   r0   r   [  s   

"c                 C  r  rV   r  rm   r/   r/   r0   r   b  r  c                 C  s>   dd | j D }| j}|jdkrd|jd|f S d|j S )Nc                 S  r   r/   r  rO   r   r/   r/   r0   rQ   l  r   z!Tensor._print.<locals>.<listcomp>r   r  z, z%s)rD   rZ   r   rb   r  )rH   rD   rZ   r/   r/   r0   r  k  s
   

zTensor._printc                 C  sP   |dkr	| j dkS t|}t|ts| jrJ tj|kS dd }|| ||kS )Nr   c                 S  s4   |   }|jt|jtt|jtt|jf}|S rV   )rI   r  r   rY   r   rA   rB   )rH   r   r  r/   r/   r0   _get_compar_comp{  s
   z'Tensor.equals.<locals>._get_compar_comp)r  r   r   r   rY   r   r  )rH   r  r
  r/   r/   r0   r  s  s   



zTensor.equalsc                 C  s   | j |kr| S t| jdkr| S |jtdkrd}n|jtdkr&d}n|jtdkr1d }nttj	}|j
d }|sD||j }|S ||j }| jd \}}||k rW| }|S )Nr   r   r\   r8   )rZ   rE   rA   r   r   r   r{  r  r   r  rC   r&  rB   )rH   r   antisymr  rh   dp0dp1r/   r/   r0   r    s*   




zTensor.contract_metricc                 C  r  rV   r  )rH   r   r/   r/   r0   r    r0  zTensor.contract_deltac                 K  s@   ddl m} dd |  D }||jd g|R  }| ||S )Nr   )Indexedc                 S     g | ]}|j d  qS r   rw  rN   r/   r/   r0   rQ     r   z3Tensor._eval_rewrite_as_Indexed.<locals>.<listcomp>)sympy.tensor.indexedr  rn   r   r^  )rH   r  rD   rq  r  r[  r0  r/   r/   r0   r    s   zTensor._eval_rewrite_as_Indexedc           
      C  s   t |tstjS | j|jkrtjS dg}tt|  | D ]C\}\}}|j|jkr/t	d|j}|j
}tdt| ||jd}|j|jkrO||| }	nt||||| | }	||	 qt| S )Nr\   zindex types not compatibled_r   )r   r   r   rg  r  ra   r   r   rM   rd   r   rq   r|   rc   r}  r   re   r  r  )
rH   r  kronecker_delta_listcountiselfiotherrM   tensor_metricdummykroneckerdeltar/   r/   r0   r    s*   
	"
zTensor._eval_partial_derivativer   r   rc  NF)<r   r   r   r   r  rx  rP  rk  rg  rA   rB   r   r  r  rZ   rY   r  rD   rk  rC   r   r   r  r  r  r  r  r&  r*  r+  r  r  r   r  r   rI   r   r  r  rn   r   r  r  r  r  r  r  rN  r  r   rR  r   r  r  r  r  r  r  r  r  r/   r/   r/   r0   r   
  s   
 #





















 

%,


"r   c                   @  s>  e Zd ZdZejZ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dpddZedd Zedd Zdd Zedd Ze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e	d+d, Z e	d-d. Z!d/d0 Z"d1d2 Z#dqd5d6Z$drd:d;Z%d<d= Z&d>d? Z'd@dA Z(dBdC Z)dDdE Z*dFdG Z+dHdI Z,dsdKdLZ-dMdN Z.dOdP Z/dQdR Z0dSdT Z1dsdUdVZ2dJdWdXdYZ3edZd[ Z4d\d] Z5d^d_ Z6d`da Z7e	dbdc Z8e8j9dddc Z8e8j:dedc Z8dfdg Z;edhdi Z<djdk Z=dldm Z>dndo Z?dS )tr   a  
    Product of tensors.

    Parameters
    ==========

    coeff : SymPy coefficient of the tensor
    args

    Attributes
    ==========

    ``components`` : list of ``TensorHead`` of the component tensors
    ``types`` : list of nonrepeated ``TensorIndexType``
    ``free`` : list of ``(ind, ipos, icomp)``, see Notes
    ``dum`` : list of ``(ipos1, ipos2, icomp1, icomp2)``, see Notes
    ``ext_rank`` : rank of the tensor counting the dummy indices
    ``rank`` : rank of the tensor
    ``coeff`` : SymPy coefficient of the tensor
    ``free_args`` : list of the free indices in sorted order
    ``is_canon_bp`` : ``True`` if the tensor in in canonical form

    Notes
    =====

    ``args[0]``   list of ``TensorHead`` of the component tensors.

    ``args[1]``   list of ``(ind, ipos, icomp)``
    where ``ind`` is a free index, ``ipos`` is the slot position
    of ``ind`` in the ``icomp``-th component tensor.

    ``args[2]`` list of tuples representing dummy indices.
    ``(ipos1, ipos2, icomp1, icomp2)`` indicates that the contravariant
    dummy index is the ``ipos1``-th slot position in the ``icomp1``-th
    component tensor; the corresponding covariant index is
    in the ``ipos2`` slot position in the ``icomp2``-th component tensor.

    Nc                 O  s  | dd}ttt|}	 dd |D }ttj| }g }|D ]9}tt|}dd |D }ttj| }tt|}	t	|
|dkrR|	||}
t||
}n|}|| q |}dd |D }tj|dd\}}}}d	d |D }t|||||d
}tj| g|R  }||_|d d  |_||_|jd d  |_|jd d  |_dd |jD |_t	|j|_t	|jjdt	|jj  |_tj|_||_ |S )Nr   Fc                 S  r   r/   r   r   r/   r/   r0   rQ     r   z#TensMul.__new__.<locals>.<listcomp>c                 S  r   r/   )get_dummy_indicesr`  r/   r/   r0   rQ     r   r   c                 S  s0   g | ]}t |ttfr|jn|gD ]}|qqS r/   )r   r   r   r   )rO   r   rP   r/   r/   r0   rQ   !  r   )replace_indicesc                 S  rK   r/   rL   rN   r/   r/   r0   rQ   &  rR   r  c                 S  r  r   r/   r   r/   r/   r0   r  /  r   z"TensMul.__new__.<locals>.<setcomp>r8   )!re  r   r  r   r  r  r  r  r   rE   intersectionunionr   _dedupe_indicesre   r  r7   r   rk  _indices_index_typesrx  rA   r  rB   r  _free_indices_rankrF   r   r  r  _is_canon_bp)rm  r   r  r   rA   rp  r   dum_this	dum_other	free_thisexcludenewargrD   rB   rC   r  rr  r/   r/   r0   rk    sB   zTensMul.__new__c                 C  r[  rV   )r!  rm   r/   r/   r0   r=   6  r  zTensMul.<lambda>c                 C  r[  rV   r  rm   r/   r/   r0   r=   7  r  c                 C  r[  rV   r  rm   r/   r/   r0   r=   8  r  c                 C  r[  rV   r"  rm   r/   r/   r0   r=   9  r  c                 C  r[  rV   )r#  rm   r/   r/   r0   r=   :  r  c                 C  r[  rV   r  rm   r/   r/   r0   r=   ;  r  c              	   C  s  i }i }g }g }d}t | D ]]\}}|D ]V}t|tstd| |v rO|| }	|| }
|jr>||||	||
f n|| |	||
|f || n||v rYtd| |||< |||< || |d7 }qqt|	 }dd |
 D }|jdd d	 ||||fS )
Nr   zexpected TensorIndexzRepeated index: %sr\   c                 S  rK   r/   r  rN   r/   r/   r0   rQ   g  rR   z0TensMul._indices_to_free_dum.<locals>.<listcomp>c                 S  r9   ry  r/   r;   r/   r/   r0   r=   i  r>   z.TensMul._indices_to_free_dum.<locals>.<lambda>r?   )ra   r   rq   r  poprc   re   rd   r   rQ  r  rG   )r  	free2pos1	free2pos2
dummy_datarD   ru   rt   arg_indicesr^   
other_pos1
other_pos2rA   
free_namesr/   r/   r0   _indices_to_free_dum=  s6   



zTensMul._indices_to_free_dumc                 C  s   dd | D S )Nc                 S  s   g | ]\}}}}}||fqS r/   r/   )rO   rP   p1ap1bp2ap2br/   r/   r0   rQ   n  r  z.TensMul._dummy_data_to_dum.<locals>.<listcomp>r/   )r.  r/   r/   r0   _dummy_data_to_duml  r  zTensMul._dummy_data_to_dumTc                   s   dd | D }dd | D }t |\}}}}tt  fdd}|rb|D ]2\}	}
}}}|	j}	 ||}||vr9nq0t||d}|||
 |	< | || |	 < |||< | ||< q%dd t| |D } t |}| |||fS )Nc                 S  rT  r/   r/   r  r/   r/   r0   rQ   r  rU  z5TensMul._tensMul_contract_indices.<locals>.<listcomp>c                 S  r   r/   )rn   r   r/   r/   r0   rQ   v  r   c                   ry   rz   r{   r~   r   r/   r0   r   {  r   z9TensMul._tensMul_contract_indices.<locals>.dummy_name_genTc                 S  s(   g | ]\}}t |tr||n|qS r/   rm  )rO   r   r  r/   r/   r0   rQ     s    )r   r3  r   r   rM   rq   r   r8  )r   r  replacementsr  rD   rA   r2  r.  r   	old_indexpos1cov
pos1contrapos2cov
pos2contrarP  r}   r  rB   r/   r   r0   r  p  s.   
z!TensMul._tensMul_contract_indicesc                 C  s6   g }| D ]}t |tsqt |trq||j q|S )zq
        Get a list of ``Tensor`` objects having the same ``TIDS`` if multiplied
        by one another.
        )r   r   r   rW   rY   )r   rY   r   r/   r/   r0   _get_components_from_args  s   

z!TensMul._get_components_from_argsc                 C  sT   |  }d}t| D ]\}}t|tsq
|}||j7 }t|j||| | |< q
d S r:   )rn   ra   r   r   r   r   rZ   )r   r  rD   ind_posrP   r   prev_posr/   r/   r0   _rebuild_tensors_list  s   

zTensMul._rebuild_tensors_listc                   sZ  j } dd}|r. fddjD }	 ttj|fddjD }nj}fdd|D }tdd d	d |D tj}d
d |D }t	|dkrW|S |j
kra|g| }|dkrhtjS t	|dkrr|d S t|\}}}}dd |D }	t|||	||d}
j| }|	|_|
|_t	|jjdt	|jj  |_||_||_ |S )Nrr  Tc                   rs  rt  ru  r   rv  r/   r0   rQ     rw  z TensMul.doit.<locals>.<listcomp>c                   r   r/   r/   r`  )ruler/   r0   rQ     r   c                   s   g | ]	}| j kr|qS r/   )identityr   rm   r/   r0   rQ     r   c                 S  s   | | S rV   r/   )r   br/   r/   r0   r=     r>   zTensMul.doit.<locals>.<lambda>c                 S  r   r/   r   r   r/   r/   r0   rQ     r   c                 S     g | ]	}t |tr|qS r/   r   r   r/   r/   r0   rQ     r   r   r\   c                 S  rK   r/   rL   rN   r/   r/   r0   rQ     rR   r  r8   )r$  re  r   r  r   _dedupe_indices_in_ruler   r   r  rE   rD  rg  r   r  r7   rb  r!  rx  rA   rB   rF   r  )rH   r   r   rr  r   r  rD   rA   rB   rC   r  rr  r/   )r   rC  rH   r0   r    s<   



zTensMul.doitc                 K  s$   t | gt |||R i | S rV   )r   %_get_tensors_from_components_free_dumr  )r  rY   rA   rB   r  r/   r/   r0   	from_data  s   $zTensMul.from_datac           
      C  sb   t | ||}| }dd | D }d}t| D ]\}}|}	||j7 }t|||	| ||< q|S )zv
        Get a list of ``Tensor`` objects by distributing ``free`` and ``dum`` indices on the ``components``.
        c                 S     g | ]}d qS rV   r/   rN   r/   r/   r0   rQ     rU  zATensMul._get_tensors_from_components_free_dum.<locals>.<listcomp>r   )r7   r[   rn   ra   r   r   )
rY   rA   rB   r  rD   tensorsr@  rP   rZ   rA  r/   r/   r0   rH    s   
z-TensMul._get_tensors_from_components_free_dumc                 C  r  )Nc                 S  r  r   r/   rN   r/   r/   r0   r    r   z0TensMul._get_free_indices_set.<locals>.<setcomp>r_   rm   r/   r/   r0   r&    r  zTensMul._get_free_indices_setc                   s,   t tj| j   fddt| j D S )Nc                   r  r/   r/   r  r  r/   r0   r    rw  z1TensMul._get_dummy_indices_set.<locals>.<setcomp>)r  r  r  rB   ra   rx  rn   rm   r/   r  r0   r*    s   zTensMul._get_dummy_indices_setc                 C  sZ   dd t | jD }d}| jD ]}t|tsqt |jD ]}|||| < q||j7 }q|S )Nc                 S  rJ  rV   r/   rN   r/   r/   r0   rQ     rU  z<TensMul._get_position_offset_for_indices.<locals>.<listcomp>r   )r   r   r   r   r   )rH   
arg_offsetcounterr   r   r/   r/   r0    _get_position_offset_for_indices  s   

z(TensMul._get_position_offset_for_indicesc                 C  r  )Nc                 S  r   r   r/   r   r/   r/   r0   rQ     r   z%TensMul.free_args.<locals>.<listcomp>r   rm   r/   r/   r0   r   	  r  zTensMul.free_argsc                 C  s   |  | jS rV   )r?  r   rm   r/   r/   r0   rY     ru  zTensMul.componentsc                   &   |    |   fdd| jD S )Nc                   s&   g | ]\}}|| |  | fqS r/   r/   r  rL  argposr/   r0   rQ        & z(TensMul.free_in_args.<locals>.<listcomp>)rN  _get_indices_to_args_posrA   rm   r/   rP  r0   r       zTensMul.free_in_argsc                 C  r[  rV   r  rm   r/   r/   r0   r    s   zTensMul.coeffc                 C  s   | j dd | jD   S )Nc                 S  rF  r/   r   )rO   r   r/   r/   r0   rQ     r   z#TensMul.nocoeff.<locals>.<listcomp>)rb  r   r  rm   r/   r/   r0   r    s   zTensMul.nocoeffc                   rO  )Nc                   s4   g | ]\}}| |  | |  | | fqS r/   r/   r  rP  r/   r0   rQ   $  s   4 z'TensMul.dum_in_args.<locals>.<listcomp>)rN  rS  rB   rm   r/   rP  r0   r     rT  zTensMul.dum_in_argsc                 C  sH   |dkr	| j dkS t|}t|ts| jrJ | j |kS |  | kS r:   )r  r   r   r   rY   rI   r  r/   r/   r0   r  &  s   



zTensMul.equalsc                 C  r[  )a+  
        Returns the list of indices of the tensor.

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

        The indices are listed in the order in which they appear in the
        component tensors.
        The dummy indices are given a name which does not collide with
        the names of the free indices.

        Examples
        ========

        >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads
        >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
        >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz)
        >>> g = Lorentz.metric
        >>> p, q = tensor_heads('p,q', [Lorentz])
        >>> t = p(m1)*g(m0,m2)
        >>> t.get_indices()
        [m1, m0, m2]
        >>> t2 = p(m1)*g(-m1, m2)
        >>> t2.get_indices()
        [L_0, -L_0, m2]
        )r   rm   r/   r/   r0   rn   0  s   zTensMul.get_indicesr   r   c                 C  r  )a  
        Returns the list of free indices of the tensor.

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

        The indices are listed in the order in which they appear in the
        component tensors.

        Examples
        ========

        >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads
        >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
        >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz)
        >>> g = Lorentz.metric
        >>> p, q = tensor_heads('p,q', [Lorentz])
        >>> t = p(m1)*g(m0,m2)
        >>> t.get_free_indices()
        [m1, m0, m2]
        >>> t2 = p(m1)*g(-m1, m2)
        >>> t2.get_free_indices()
        [m2]
        r  rm   r/   r/   r0   r   M  s   
zTensMul.get_free_indicesr  r  r   c                   s   | j  fdd| jD  S )Nc                   rl  r/   rm  r   rn  r/   r0   rQ   i  ro  z,TensMul._replace_indices.<locals>.<listcomp>ra  r  r/   rn  r0   r  h  s   zTensMul._replace_indicesc                 C  sN   | j dkr| gS g }d}| j D ]}t|tr |||  d}q||9 }q|S )a  
        Returns a list of tensors, whose product is ``self``.

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

        Dummy indices contracted among different tensor components
        become free indices with the same name as the one used to
        represent the dummy indices.

        Examples
        ========

        >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads, TensorSymmetry
        >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
        >>> a, b, c, d = tensor_indices('a,b,c,d', Lorentz)
        >>> A, B = tensor_heads('A,B', [Lorentz]*2, TensorSymmetry.fully_symmetric(2))
        >>> t = A(a,b)*B(-b,c)
        >>> t
        A(a, L_0)*B(-L_0, c)
        >>> t.split()
        [A(a, L_0), B(-L_0, c)]
        r/   r\   )r   r   r   re   )rH   splitpr  r   r/   r/   r0   r   k  s   



zTensMul.splitc                   s:    fdd| j D }dd |D }tdd tj| D  S )Nc                   r  r/   r  r   rv  r/   r0   rQ     rw  z#TensMul._expand.<locals>.<listcomp>c                 S  s&   g | ]}t |ttfr|jn|fqS r/   )r   r   r   r   r   r/   r/   r0   rQ     rR  c                 S     g | ]}t | qS r/   )r   rN   r/   r/   r0   rQ     s    )r   r   r  product)rH   r   r   args1r/   rv  r0   r    s
   zTensMul._expandc                 C  s   t tj| | jd S )Nr  )r   r   r  r$  r  rm   r/   r/   r0   r    s   zTensMul.__neg__c                 C  r  rV   r  r  r/   r/   r0   r     r  zTensMul.__getitem__c                 C  s\   t | j}| j r(d}|d tjkr|dd  }||fS |d  |d< ||fS d}||fS )Nr  r   r\   r  )r   r   r  could_extract_minus_signr   r  )rH   r   r  r/   r/   r0   !_get_args_for_traditional_printer  s   

z)TensMul._get_args_for_traditional_printerc           
      C  s  dd | j D }d}t|d }t|D ]a}t||dD ]X}||d  || }|dvr.qtt||d  jjdd d}tt|| jjd	d d}|||d  jjf||| jjfkrt|| ||d  ||d < ||< |rt| }qq|| j	 }	|	dkr|	g| S |S )
z
        Returns the ``args`` sorted according to the components commutation
        properties.

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

        The sorting is done taking into account the commutation group
        of the component tensors.
        c                 S  rF  r/   r   r   r/   r/   r0   rQ     r   z<TensMul._sort_args_for_sorted_components.<locals>.<listcomp>r\   r   r   c                 S  r[  rV   r  r;   r/   r/   r0   r=     r  z:TensMul._sort_args_for_sorted_components.<locals>.<lambda>r?   c                 S  r[  rV   r  r;   r/   r/   r0   r=     r  )
r   rE   r   r  r   r  rZ   rC   rb   r  )
rH   cvr  rf   rP   r   r`  rv   typ2r  r/   r/   r0    _sort_args_for_sorted_components  s(    $"

z(TensMul._sort_args_for_sorted_componentsc                 C  s   t |    S )zB
        Returns a tensor product with sorted components.
        )r   r]  r  rm   r/   r/   r0   r    s   zTensMul.sorted_componentsFc                 C  s   t | ||dS )z
        Returns the tensor corresponding to the permutation ``g``

        For further details, see the method in ``TIDS`` with the same name.
        r  r  r  r/   r/   r0   r     s   zTensMul.perm2tensorc           	      C  s   | j r| S |  }t|tr| S |js|S | }|j \}}}t	|j}t
|||g|R  }|dkr9tjS ||d}|S )a  
        Canonicalize using the Butler-Portugal algorithm for canonicalization
        under monoterm symmetries.

        Examples
        ========

        >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorHead, TensorSymmetry
        >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
        >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz)
        >>> A = TensorHead('A', [Lorentz]*2, TensorSymmetry.fully_symmetric(-2))
        >>> t = A(m0,-m1)*A(m1,-m0)
        >>> t.canon_bp()
        -A(L_0, L_1)*A(-L_0, -L_1)
        >>> t = A(m0,-m1)*A(m1,-m2)*A(m2,-m0)
        >>> t.canon_bp()
        0
        r   T)r$  r!  r   r   rI   rY   r  rx  r   r   r   r   rg  r   )	rH   r0  r   r   r   r   r   r  tmulr/   r/   r0   rI     s   

zTensMul.canon_bpc                 C  s   |  |}|S rV   r  )rH   r}  r   r/   r/   r0   r    s   
zTensMul.contract_deltac                 C  sZ   i }d}t | jD ]!\}}t|tsq	t|tsJ t|jD ]
}|||< |d7 }qq	|S )zU
        Get a dict mapping the index position to TensMul's argument number.
        r   r\   )ra   r   r   r   r   r   r   )rH   pos_mappos_counterarg_ir   rP   r/   r/   r0   rS    s   

z TensMul._get_indices_to_args_posc                   s  |   }| |krt|}t|S |  t| j}jtdkr%d}njtdkr0d}njt	dkr;d}nt
fddt| jD }|sM| S d}| jdd }| jdd }t |D ]4v rjqbfdd|D fd	d|D   sqb d|< t dkr|s \}	}
|	d  kr|	d }n|	d }|
d  kr|
d }n|
d }|||f nĈ \}	}
|	d  kr|	d }|	d dkr| }n|	d }|	d dkr| }|
d  kr|
d }| }n|
d }|||f nt dkr|sB d \}}| | kr(jd }||j }n]| kr2|}n|}d \}}|||f nC d \}}| | krdjd }||j }||k rc| }n!| krv|}|dkru| }n|}d \}}|||f  fd
d|D }fdd|D }qbd}dgt| tt|D ]}|v r|d7 }q||< qfdd|D }fdd|D }|t|   }t|ts|S t|j||}||S )a  
        Raise or lower indices with the metric ``g``.

        Parameters
        ==========

        g : metric

        Notes
        =====

        See the ``TensorIndexType`` docstring for the contraction conventions.

        Examples
        ========

        >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads
        >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
        >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz)
        >>> g = Lorentz.metric
        >>> p, q = tensor_heads('p,q', [Lorentz])
        >>> t = p(m0)*q(m1)*g(-m0, -m1)
        >>> t.canon_bp()
        metric(L_0, L_1)*p(-L_0)*q(-L_1)
        >>> t.contract_metric(g).canon_bp()
        p(L_0)*q(-L_0)
        r   r\   r8   r   Nc                   s(   g | ]\}}t |tr|j kr|qS r/   )r   r   rZ   )rO   rP   r<   r  r/   r0   rQ   @  s   ( z+TensMul.contract_metric.<locals>.<listcomp>c                   s    g | ]}|d    kr|qS r  r/   r   gposxr_  r/   r0   rQ   M  r`   c                   s0   g | ]}|d    ks|d   kr|qS r   r/   r   rb  r/   r0   rQ   N  r   c                   r  r/   r/   r   )r  r/   r0   rQ     re  c                   r  r/   r/   r   )free1r/   r0   rQ     re  c                   s0   g | ]\}}|  vr|||   fqS r/   r/   )rO   r   r1  elimr_  shiftsr/   r0   rQ     r   c                   sH   g | ] \}}|  vr|  vr||   ||   fqS r/   r/   )rO   p0r  re  r/   r0   rQ     s   H )r!  rI   r  rS  r   r   r   r   r   r{  r  ra   rB   rA   r  r  rE   re   rC   r&  r   r   r  r   r   r7   r[   rY   r  )rH   r   r0  r   r  gposr  rB   rA   dum10dum11rh  r  r  r  rh   r   r1  shiftrP   r  r  r/   )r  rf  rd  r   rc  r_  rg  r0   r    s   












zTensMul.contract_metricc                 C  r  r  r  r  r/   r/   r0   r    r  z TensMul._set_new_index_structurer  c          	      O  s   t || jkrtdt| jd d  }d}t|D ]%\}}t|ts$qt|ts+J |j}|j	||||   ||< ||7 }qt
|d|i S )Nr  r   r   )rE   r   rd   r   r   ra   r   r   r   r  r   r  )	rH   r   rD   r  r   rk   rP   r   r   r/   r/   r0   r    s   

zTensMul._set_indicesc                 C  s(   | D ]}t |ts
qt |tsJ qd S rV   )r   r   r   )r   rA   rB   r   r/   r/   r0   &_index_replacement_for_contract_metric  s
   
z.TensMul._index_replacement_for_contract_metricc                 G  r  rV   )r   r   r   r  re   r   r  r  r/   r/   r0   r    r  zTensMul.substitute_indicesc                 G  r   )Nc                 S  rK   r/   rL   r   r/   r/   r0   rQ     rR   z$TensMul.__call__.<locals>.<listcomp>r  c                 S  r  r/   r   rN   r/   r/   r0   r    rw  z#TensMul.__call__.<locals>.<setcomp>r  r  r/   r/   r0   rN    r  zTensMul.__call__c                   s   t  fdd| jD  \}}ttjdd | jD tj}t|\}}}}t	|}	| j
}
|jdd d dd |D }||t||	|
 fS )Nc                   s    g | ]}t |tr| qS r/   r  r   r  r/   r0   rQ     r`   z)TensMul._extract_data.<locals>.<listcomp>c                 S  r   r/   r   r`  r/   r/   r0   rQ     r   c                 S  r9   r   r/   r;   r/   r/   r0   r=     r>   z'TensMul._extract_data.<locals>.<lambda>r?   c                 S  r   r   r/   rN   r/   r/   r0   rQ     r   )r   r   r   operatormulr   r  r   r3  r8  r   rG   r   r   )rH   rA  r  r  r  rD   rA   r2  r.  rB   r   rk  r/   r  r0   rR    s   
zTensMul._extract_datac                 C  s@   t   tt t|   }W d    |S 1 sw   Y  |S rV   r  )rH   r   r/   r/   r0   r     s   

zTensMul.datac                 C     t   td)Nz9Not possible to set component data to a tensor expressionr1   rd   r  r/   r/   r0   r        c                 C  rp  )Nz<Not possible to delete component data to a tensor expressionrq  rm   r/   r/   r0   r     rr  c                 C  sN   t   tt | jd u rtd| j W  d    S 1 s w   Y  d S r  )r1   r$   r#   r   rd   r  rm   r/   r/   r0   r    s   

$zTensMul.__iter__c                 C  s   t |}t t| }t t| }||}t|dkrdS 	 || || dd |D }t|}i }|D ]'}| | v rBq8||j	}	|j
|	g|jdd R  }
|
||< |
 || < q8t|dkrhdS | |}|S )z
        exclude: set
        new: TensExpr

        If ``new`` has any dummy indices that are in ``exclude``, return a version
        of new with those indices replaced. If no replacements are needed,
        return None

        r   Nc                 S  s   g | ]}|d fqS rV   r/   rN   r/   r/   r0   rQ   #  r   z+TensMul._dedupe_indices.<locals>.<listcomp>r\   )r  r  r   r  rE   r%  r7   rp   r  rM   rb  r   r  )rC  r(  dums_newfree_new	conflictsexclude_for_genr  r  dnewnamenew_dnew_renamedr/   r/   r0   r  	  s.   





zTensMul._dedupe_indicesc                   s   dd |  D   fdd|  D }t|  }i }|  |   |   |  D ]"\}}t||}||ksE|du rJ|||< q3|||< |t| q3|S )zb
        rule: dict

        This applies TensMul._dedupe_indices on all values of rule.

        c                 S  s    i | ]\}}t |tr||qS r/   )r   rq   r  r/   r/   r0   r   ;  r`   z3TensMul._dedupe_indices_in_rule.<locals>.<dictcomp>c                   s"   i | ]\}}|   vr||qS r/   r  r  index_rulesr/   r0   r   <  s   " N)rQ  r  rn   r%  r  valuesr   r  )rH   rC  other_rulesr(  newrulerB  rC  rz  r/   r|  r0   rG  4  s   

zTensMul._dedupe_indices_in_rulec                   sF   ddl m  dd |  D } fdd|D }t|}| ||S )Nr   rX  c                 S  r  r   rw  rN   r/   r/   r0   rQ   N  r   z4TensMul._eval_rewrite_as_Indexed.<locals>.<listcomp>c                   s$   g | ]}t | r|jd  n|qS r   )r   r   r   rX  r/   r0   rQ   O  ro  )r\  rY  rn   r   r  r^  )rH   r   rq  r[  r0  r/   rX  r0   r  L  s
   
z TensMul._eval_rewrite_as_Indexedc              	   C  s   g }t | jD ]6\}}t|tr||}n|jr||}ntj}|r=|	t
| jd | |f | j|d d    qt|S r   )ra   r   r   r   r  r  r  r   rg  re   r   r  r   )rH   r  termsrP   r   rw  r/   r/   r0   r  S  s   
2
z TensMul._eval_partial_derivativer  r   rc  r   )@r   r   r   r   r   r  rD  rx  rk  rg  rC   rA   rB   rk  r   r   r   r3  r8  r  r?  rB  r  rI  rH  r&  r*  rN  r   rY   r  r  r  r  r  rn   r   r  r   r  r  r   rZ  r]  r  r   rI   r  rS  r  r  r  rm  r  rN  rR  r   r  r  r  r  rG  r  r  r/   r/   r/   r0   r     s    &/
.
"

4










$	!
# 
%





*r   c                   @  s   e Zd Z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dddZdd Zdd ZdS )TensorElementa  
    Tensor with evaluated components.

    Examples
    ========

    >>> from sympy.tensor.tensor import TensorIndexType, TensorHead, TensorSymmetry
    >>> from sympy import symbols
    >>> L = TensorIndexType("L")
    >>> i, j, k = symbols("i j k")
    >>> A = TensorHead("A", [L, L], TensorSymmetry.fully_symmetric(2))
    >>> A(i, j).get_free_indices()
    [i, j]

    If we want to set component ``i`` to a specific value, use the
    ``TensorElement`` class:

    >>> from sympy.tensor.tensor import TensorElement
    >>> te = TensorElement(A(i, j), {i: 2})

    As index ``i`` has been accessed (``{i: 2}`` is the evaluation of its 3rd
    element), the free indices will only contain ``j``:

    >>> te.get_free_indices()
    [j]
    c                   s   t |tst |tstd| |jfdd|jD  S |  dd  D fdd D  fdd D tdkrF|S fd	d D }t	t
| |}||_|S )
Nz%s is not a tensor expressionc                   r  r/   )r  r   r  r/   r0   rQ     r   z)TensorElement.__new__.<locals>.<listcomp>c                 S  s   i | ]}|j d  |qS r   rw  rN   r/   r/   r0   r     re  z)TensorElement.__new__.<locals>.<dictcomp>c                   s   i | ]\}}  |||qS r/   )re  rO   r^   r(  )name_translationr/   r0   r     r  c                   s   i | ]\}}| v r||qS r/   r/   r  )expr_free_indicesr/   r0   r     r  r   c                   s   g | ]
}|   vr|qS r/   r{  rN   r  r/   r0   rQ     rw  )r   r   r   r  rb  r   r   rQ  rE   r   rk  r"  )rm  r0  r  rk  rr  r/   )r  r  r  r0   rk    s   

zTensorElement.__new__c                 C  s   dd t |  D S )Nc                 S  s   g | ]\}}||fqS r/   r/   r]   r/   r/   r0   rQ     re  z&TensorElement.free.<locals>.<listcomp>)ra   r   rm   r/   r/   r0   rA     r  zTensorElement.freec                 C  s   g S rV   r/   rm   r/   r/   r0   rB     s   zTensorElement.dumc                 C  rv  r:   _argsrm   r/   r/   r0   r0    rx  zTensorElement.exprc                 C  rv  r   r  rm   r/   r/   r0   r    rx  zTensorElement.index_mapc                 C  rh  rV   ri  rm   r/   r/   r0   r    r\  zTensorElement.coeffc                 C  r"  rV   r/   rm   r/   r/   r0   r    rj  zTensorElement.nocoeffc                 C  r[  rV   r*  rm   r/   r/   r0   r     r  zTensorElement.get_free_indicesr  r  r   r   c                 C  r  rV   r  r  r/   r/   r0   r    rx  zTensorElement._replace_indicesc                 C  r   rV   r  rm   r/   r/   r0   rn     r   zTensorElement.get_indicesc                   sP   | j |\}}| j t fdd|D } fdd|D }||}||fS )Nc                 3  s     | ]}  |td V  qd S rV   )re  slicerN   r  r/   r0   r     s    z.TensorElement._extract_data.<locals>.<genexpr>c                   r  r/   r/   rN   r  r/   r0   rQ     re  z/TensorElement._extract_data.<locals>.<listcomp>)r0  rR  r  r   r   )rH   rA  rU  r   slice_tupler/   r  r0   rR    s   
zTensorElement._extract_dataNrc  )r   r   r   r   rk  rg  rA   rB   r0  r  r  r  r   r  rn   rR  r/   r/   r/   r0   r  f  s&    






r  c                   @  s.   e Zd ZdZdddZedd Zd	d
 ZdS )WildTensorHeada  
    A wild object that is used to create ``WildTensor`` instances

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

    Examples
    ========
    >>> from sympy.tensor.tensor import TensorHead, TensorIndex, WildTensorHead, TensorIndexType
    >>> R3 = TensorIndexType('R3', dim=3)
    >>> p = TensorIndex('p', R3)
    >>> q = TensorIndex('q', R3)

    A WildTensorHead can be created without specifying a ``TensorIndexType``

    >>> W = WildTensorHead("W")

    Calling it with a ``TensorIndex`` creates a ``WildTensor`` instance.

    >>> type(W(p))
    <class 'sympy.tensor.tensor.WildTensor'>

    The ``TensorIndexType`` is automatically detected from the index that is passed

    >>> W(p).component
    W(R3)

    Calling it with no indices returns an object that can match tensors with any number of indices.

    >>> K = TensorHead('K', [R3])
    >>> Q = TensorHead('Q', [R3, R3])
    >>> W().matches(K(p))
    {W: K(p)}
    >>> W().matches(Q(p,q))
    {W: Q(p, q)}

    If you want to ignore the order of indices while matching, pass ``unordered_indices=True``.

    >>> U = WildTensorHead("U", unordered_indices=True)
    >>> W(p,q).matches(Q(q,p))
    >>> U(p,q).matches(Q(q,p))
    {U(R3,R3): _WildTensExpr(Q(q, p))}

    Parameters
    ==========
    name : name of the tensor
    unordered_indices : whether the order of the indices matters for matching
        (default: False)

    See also
    ========
    ``WildTensor``
    ``TensorHead``

    Nr   Fc              	   C  s   t |tr
t|}nt |tr|}ntd|d u rg }|d u r(tt|}n	|jt|ks1J |tt|kr>tdt	
| |t| t|t|t|}|S )Nr  z3Wild matching based on symmetry is not implemented.)r   r|   r   rd   r   r{  rE   r   r  r   rk  r   r   )rm  rb   rC   r   r   unordered_indicesr  rr  r/   r/   r0   rk    s   


$zWildTensorHead.__new__c                 C  rv  )Nr)   rw  rm   r/   r/   r0   r    rx  z WildTensorHead.unordered_indicesc                 O  s   t | |fi |}| S rV   )
WildTensorr  )rH   rD   rq  r  r/   r/   r0   rN    s   zWildTensorHead.__call__)NNr   F)r   r   r   r   rk  rg  r  rN  r/   r/   r/   r0   r    s    
7
r  c                   @  s,   e Zd ZdZdd Zd
ddZd
dd	ZdS )r  a  
    A wild object which matches ``Tensor`` instances

    Explanation
    ===========
    This is instantiated by attaching indices to a ``WildTensorHead`` instance.

    Examples
    ========
    >>> from sympy.tensor.tensor import TensorHead, TensorIndex, WildTensorHead, TensorIndexType
    >>> W = WildTensorHead("W")
    >>> R3 = TensorIndexType('R3', dim=3)
    >>> p = TensorIndex('p', R3)
    >>> q = TensorIndex('q', R3)
    >>> K = TensorHead('K', [R3])
    >>> Q = TensorHead('Q', [R3, R3])

    Matching also takes the indices into account
    >>> W(p).matches(K(p))
    {W(R3): _WildTensExpr(K(p))}
    >>> W(p).matches(K(q))
    >>> W(p).matches(K(-p))

    If you want to match objects with any number of indices, just use a ``WildTensor`` with no indices.
    >>> W().matches(K(p))
    {W: K(p)}
    >>> W().matches(Q(p,q))
    {W: Q(p, q)}

    See Also
    ========
    ``WildTensorHead``
    ``Tensor``

    c                 K  s  | dd}|jtkr	 t||fd|i|S |jtkr || S | ||}dd |D }|j|j|d |j|jd}t	
| |t| }|j|_tj| |_|jjd d  |_|jjd d  |_|jj|_tj|_||_||_|g|_|jt|kr}td||_|||j|_|S )Nr   Fc                 S  rK   r/   rL   r	  r/   r/   r0   rQ   H  rR   z&WildTensor.__new__.<locals>.<listcomp>)r   r   r  r  ) r+  rb  r   r   _WildTensExprr  rb   r   r  r   rk  r   r7   rU   rx  rA   r  rB   r  rF   r   r  r  r  r  r  r   rE   rd   r   r  r  )rm  r  rD   r  r   rC   rr  r/   r/   r0   rk  <  s<   


zWildTensor.__new__NFc                 C  s   t |ts|tdkrd S |d u ri }n| }t| jdkrrt|ds&d S | }t|t| jkr5d S | jj	rJ| 
|}|d u rDd S || ntt|D ]}| j| || }|d u rc d S || qPt||| j< |S ||| < |S )Nr\   r   r   )r   r   r   rA  rE   rD   rO  r   r  r  _match_indices_ignoring_orderr%  r   r  r  rZ   )rH   r0  r  rB  expr_indicesr4  rP   r/   r/   r0   r  c  s2   

zWildTensor.matchesc                   s  |du ri }n|  }dd }t| j|}g  | }|d D ]*}d}|D ]}	|	 v r,q%||	}
|
durCd}||
  |	  nq%|sI dS q fdd|D }|d	 D ]:}d}|D ].}	||	}
|
dur| | v r}||   |
| kr}  dS d}||
  |	  nq]|s dS qW fd
d|D }|d D ]:}d}|D ].}	||	}
|
dur| | v r||   |
| kr  dS d}||
  |	  nq|s dS qt t| jk rdS |S )z~
        Helper method for matches. Checks if the indices of self and expr
        match disregarding index ordering.
        Nc                 S  s   t | tr| jr
dS dS dS )Nwild, updownwildnonwild)r   WildTensorIndexignore_updown)r   r/   r/   r0   siftkey  s
   
z9WildTensor._match_indices_ignoring_order.<locals>.siftkeyr  FTc                   r  r/   r/   rN   matched_indicesr/   r0   rQ     re  z<WildTensor._match_indices_ignoring_order.<locals>.<listcomp>r  c                   r  r/   r/   rN   r  r/   r0   rQ     re  r  )	rA  r'   rD   rn   r  r%  re   r  rE   )rH   r0  r  rB  r  indices_siftedexpr_indices_remainingr   matched_this_inde_indr4  r/   r  r0   r    sr   	



"


"

z(WildTensor._match_indices_ignoring_orderr  )r   r   r   r   rk  r  r  r/   r/   r/   r0   r    s
    #
'$r  c                   @  s8   e Zd ZdZdddZedd Zdd	 ZdddZd
S )r  a  
    A wild object that matches TensorIndex instances.

    Examples
    ========
    >>> from sympy.tensor.tensor import TensorIndex, TensorIndexType, WildTensorIndex
    >>> R3 = TensorIndexType('R3', dim=3)
    >>> p = TensorIndex("p", R3)

    By default, covariant indices only match with covariant indices (and
    similarly for contravariant)

    >>> q = WildTensorIndex("q", R3)
    >>> (q).matches(p)
    {q: p}
    >>> (q).matches(-p)

    If you want matching to ignore whether the index is co/contra-variant, set
    ignore_updown=True

    >>> r = WildTensorIndex("r", R3, ignore_updown=True)
    >>> (r).matches(-p)
    {r: -p}
    >>> (r).matches(p)
    {r: p}

    Parameters
    ==========
    name : name of the index (string), or ``True`` if you want it to be
        automatically assigned
    tensor_index_type : ``TensorIndexType`` of the index
    is_up :  flag for contravariant index (is_up=True by default)
    ignore_updown : bool, Whether this should match both co- and contra-variant
        indices (default:False)
    TFc                 C  s|   t |tr
t|}n#t |tr|}n|du r)dt|j}t|}|j| ntdt|}t|}t	
| ||||S r  r  )rm  rb   rM   rc   r  r  r/   r/   r0   rk    s   


zWildTensorIndex.__new__c                 C  rv  ry  rw  rm   r/   r/   r0   r    rx  zWildTensorIndex.ignore_updownc                 C  s   t | j| j| j | j}|S rV   )r  rb   rM   rc   r  r  r/   r/   r0   r    s   

zWildTensorIndex.__neg__Nc                 C  sV   t |tsd S | j|jkrd S | js| j|jkrd S |d u r!i }n| }||| < |S rV   )r   rq   rM   r  rc   rA  )rH   r0  r  rB  r/   r/   r0   r    s   
zWildTensorIndex.matches)TFr  )	r   r   r   r   rk  rg  r  r  r  r/   r/   r/   r0   r    s    
#
r  c                   @  s   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd ZdS )r  a  
    INTERNAL USE ONLY

    This is an object that helps with replacement of WildTensors in expressions.
    When this object is set as the tensor_head of a WildTensor, it replaces the
    WildTensor by a TensExpr (passed when initializing this object).

    Examples
    ========
    >>> from sympy.tensor.tensor import WildTensorHead, TensorIndex, TensorHead, TensorIndexType
    >>> W = WildTensorHead("W")
    >>> R3 = TensorIndexType('R3', dim=3)
    >>> p = TensorIndex('p', R3)
    >>> q = TensorIndex('q', R3)
    >>> K = TensorHead('K', [R3])
    >>> print( ( K(p) ).replace( W(p), W(q)*W(-q)*W(p) ) )
    K(R_0)*K(-R_0)*K(p)

    c                 C  s   t |ts	td|| _d S )Nz,_WildTensExpr expects a TensExpr as argument)r   r   r  r0  )rH   r0  r/   r/   r0   rJ   2  s   

z_WildTensExpr.__init__c                 G  s   | j tt| j  |S rV   )r0  r  r  r   r   )rH   rD   r/   r/   r0   rN  7  s   z_WildTensExpr.__call__c                 C  s   |  | jtj S rV   )rb  r0  r   r  rm   r/   r/   r0   r  :  r   z_WildTensExpr.__neg__c                 C  r  rV   r  rm   r/   r/   r0   r  =  r  z_WildTensExpr.__abs__c                 C  s6   |j | j krtd| j  d|j  |  | j|j S NzCannot add z to rb  r  r0  r  r/   r/   r0   r  @     z_WildTensExpr.__add__c                 C  s6   |j | j krtd| j  d|j  |  |j| j S r  r  r  r/   r/   r0   r  E  r  z_WildTensExpr.__radd__c                 C  s
   | |  S rV   r/   r  r/   r/   r0   r  J  r0  z_WildTensExpr.__sub__c                 C  s
   ||   S rV   r/   r  r/   r/   r0   r  M  r0  z_WildTensExpr.__rsub__c                 C  r  rV   r  r  r/   r/   r0   r  P  r  z_WildTensExpr.__mul__c                 C  r  rV   r  r  r/   r/   r0   r   S  r  z_WildTensExpr.__rmul__c                 C  r  rV   r  r  r/   r/   r0   r  V  r  z_WildTensExpr.__truediv__c                 C  r  rV   r  r  r/   r/   r0   r  Y  r  z_WildTensExpr.__rtruediv__c                 C  r  rV   r  r  r/   r/   r0   r  \  r  z_WildTensExpr.__pow__c                 C  r  rV   r  r  r/   r/   r0   r  _  r  z_WildTensExpr.__rpow__N)r   r   r   r   rJ   rN  r  r  r  r  r  r  r  r   r  r  r  r  r/   r/   r/   r0   r    s     r  c                 C  s   t | tr	|  S | S )zt
    Butler-Portugal canonicalization. See ``tensor_can.py`` from the
    combinatorics module for the details.
    )r   r   rI   )r1  r/   r/   r0   rI   c  s   
rI   c                  G  s<   | st tjg g g S | d }| dd D ]}|| }q|S )z
    product of tensors
    r   r\   N)r   rI  r   r  )r   r   txr/   r/   r0   
tensor_mulm  s   
r  c           
      C  s   t | jdd d}dd |D \}}}}| tdd }| ||f||f||f||f tdd }| ||f||f||f||ftdd }|| | }	|	S )	z
    replace Riemann tensor with an equivalent expression

    ``R(m,n,p,q) -> 2/3*R(m,n,p,q) - 1/3*R(m,q,n,p) + 1/3*R(m,p,n,q)``

    c                 S  r9   r   r/   r;   r/   r/   r0   r=     r>   z(riemann_cyclic_replace.<locals>.<lambda>r?   c                 S  r   r   r/   r   r/   r/   r0   rQ     r   z*riemann_cyclic_replace.<locals>.<listcomp>r8   rV  r\   )r   rA   r
   r  )
t_rrA   r4  rf   r1  qt0r  t2t3r/   r/   r0   riemann_cyclic_replacey  s   ,*r  c                 C  sj   |   } t| ttfr| g}n| j}dd |D }dd |D }dd |D }t|  }|s1|S t|S )aJ  
    Replace each Riemann tensor with an equivalent expression
    satisfying the cyclic identity.

    This trick is discussed in the reference guide to Cadabra.

    Examples
    ========

    >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorHead, riemann_cyclic, TensorSymmetry
    >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
    >>> i, j, k, l = tensor_indices('i,j,k,l', Lorentz)
    >>> R = TensorHead('R', [Lorentz]*4, TensorSymmetry.riemann())
    >>> t = R(i,j,k,l)*(R(-i,-j,-k,-l) - 2*R(-i,-k,-j,-l))
    >>> riemann_cyclic(t)
    0
    c                 S  s   g | ]}|  qS r/   )r   r   r/   r/   r0   rQ     r   z"riemann_cyclic.<locals>.<listcomp>c                 S  s   g | ]	}d d |D qS )c                 S  r   r/   )r  )rO   r  r/   r/   r0   rQ     r   z-riemann_cyclic.<locals>.<listcomp>.<listcomp>r/   )rO   r   r/   r/   r0   rQ     r   c                 S  rV  r/   )r  )rO   r   r/   r/   r0   rQ     r   )r!  r   r   r   r   r   r  rI   )r  r   a1a2a3r  r/   r/   r0   riemann_cyclic  s   r  c                   s^  dd }| j }i }| j D ]<}t|tsq||v rq|j}g }tt|D ]}|| |u r1|| q$t|dkr>td| t|dkrH|||< qg }	g }
g | jD ]\}}}}|| |vr_qR||krj|
|g qR|||  }|||  }||vr{qR|	||	|krt
|||  }||d kr||fn||f\}}|	dd }|	D ]?}|d |kr|d |kr|	t|}| |
||d |d|   n||  n|d |kr|d|  nq|||g fd	d
|D }	||	}	qRg  |	D ]}|D ]} | qq|
D ]}|D ]} | qq fdd
tt|D  |	|
 fS )z
    Returns ``(lines, traces, rest)`` for an index type,
    where ``lines`` is the list of list of positions of a matrix line,
    ``traces`` is the list of list of traced matrix lines,
    ``rest`` is the rest of the elements of the tensor.
    c                 S  s  d}|t | k r| | }|d }|d }d}|rd}t|d t | D ]}|t | kr- n| | d |krLd}|| | dd   |d }| | q#| | d |krtd}t| | dd  | | |< | | }| | d }| | q#| | d |krd}|t| | d d  |d }| | q#| | d |krd}| | d d | | |< | | }|d }| | q#q#|s|d7 }|t | k s| S )Nr   r   TFr\   )rE   r   rW   r+  reversed)r   rP   r<   xendxstarthitr   r/   r/   r0   _join_lines  sT   



%zget_lines.<locals>._join_linesr8   z&at most two indices of type %s allowedr\   Nr   r   c                   r  r/   r/   r   )traces1r/   r0   rQ     re  zget_lines.<locals>.<listcomp>c                   r  r/   r/   r   )restr/   r0   rQ     re  )r   r   r   rC   r   rE   re   rd   r  r^   r  mininsert)exrP  r  	argumentsdtr`  rC   r   rP   linestracesrh  r  c0c1ta0ta1b0b1lines1linerf   r   r/   )r  r  r0   	get_lines  s~   )


 
 


r  c                 C     t | tsdS |  S Nr/   )r   r   r   r   r/   r/   r0   r   !     
r   c                 C  r  r  )r   r   rn   r  r/   r/   r0   rn   '  r  rn   c                   s0   t | tsdS |  }|    fdd|D S )Nr/   c                   r  r/   r/   rN   r_   r/   r0   rQ   1  re  z%get_dummy_indices.<locals>.<listcomp>)r   r   rn   r   )r   r  r/   r_   r0   r  ,  s
   
r  c                 C  s   t | tr| jS tg g g g S rV   )r   r   rx  r7   r  r/   r/   r0   ry  3  s   
ry  c                 C  s6   t | trtjS t | tr| jS t | trtd| S )Nz3no coefficient associated to this tensor expression)r   r   r   r  r   r  r   rd   r  r/   r/   r0   	get_coeff9  s   


r  c                 C  s   t | tr
| |S | S rV   )r   r   r  )r   r   r/   r/   r0   r  B  s   

r  Fc                 C  s`   t | ts| S t | ttfr-t| j||d}| j||d}|d t|d kr+| S |S t )z
    Returns the tensor corresponding to the permutation ``g``

    For further details, see the method in ``TIDS`` with the same name.
    r  r   r\   )	r   r   r   r   ry  r   r  rE   r  )r   r   r   nimr  r/   r/   r0   r   H  s   
r   c                 G  s   t | ts| S | j| S rV   )r   r   r  )r   r  r/   r/   r0   r  Z  s   

r  c                 K  s*   t | tr| jdi |S | jdi |S r  )r   r   r  r!  )r0  rq  r/   r/   r0   r  `  s   
r  c                   s    fdd}|S )Nc                   s2   t ttti  }tdd | jD r|| j S | S )Nc                 s  s    | ]}t |tV  qd S rV   r   r`  r/   r/   r0   r   j  r  z<get_postprocessor.<locals>._postprocessor.<locals>.<genexpr>)r   r   r   r   r   r   )r0  
tens_classr  r/   r0   _postprocessorh  s   
z)get_postprocessor.<locals>._postprocessorr/   )rm  r  r/   r  r0   get_postprocessorg  s   r  r   r:   r   )hr   
__future__r   typingr   	functoolsr   mathr   abcr   r   collectionsr   rn  r  sympy.core.numbersr	   r
   r  r   sympy.combinatorics.tensor_canr   r   r   r   
sympy.corer   r   r   r   r   r   sympy.core.cacher   sympy.core.containersr   r   sympy.core.sortingr   sympy.core.symbolr   r   sympy.core.sympifyr   r   sympy.core.operationsr   sympy.external.gmpyr    sympy.matricesr!   sympy.utilities.exceptionsr"   r#   r$   sympy.utilities.decoratorr%   r&   sympy.utilities.iterablesr'   r1   r5   r6   r7   r   r   r  rQ  r   r  rq   r  r   r  r  r  r   r  r   r   r   r   r  r  r  r  r  rI   r  r  r  r  r   rn   r  ry  r  r  r   r  r  r  "_constructor_postprocessor_mappingr/   r/   r/   r0   <module>   s       -  w .  0] 
A>  
   $  W    ,       ZX 8OE
!x	

