403Webshell
Server IP : 35.80.110.71  /  Your IP : 216.73.216.221
Web Server : Apache/2.4.58 (Ubuntu)
System : Linux ip-172-31-21-44 6.17.0-1019-aws #19~24.04.1-Ubuntu SMP Tue Jun 23 18:53:06 UTC 2026 x86_64
User : ubuntu ( 1000)
PHP Version : 8.3.31
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /lib/python3/dist-packages/sympy/tensor/__pycache__/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /lib/python3/dist-packages/sympy/tensor/__pycache__/tensor.cpython-312.pyc
�

M�Zd����dZddlmZddlmZddlmZddlmZddl	m
Z
mZddlm
Z
ddlZddlZdd	lmZmZdd
lmZddlmZmZmZmZddlmZmZmZmZmZm Z dd
l!m"Z"m#Z#ddl$m%Z%ddl&m'Z'm(Z(ddl)m*Z*m+Z+ddl,m-Z-ddl.m/Z/ddl0m1Z1ddl2m3Z3m4Z4m5Z5ddl6m7Z7m8Z8ddl9m:Z:d�Z;d�Z<d�Z=Gd�de*�Z>d�Z?Gd�de*�Z@e@�ZAGd�d �ZBeB�ZCGd!�d"e�ZDGd#�d$e�ZEd%�ZFGd&�d'e�ZGe8d(d)d*�+�d,��ZHe8d-d)d.�+�Gd/�d0e��ZIe8d1d)d2�+�dWd3��ZJGd4�d5e�ZKdWd6�ZLGd7�d8ee�ZMGd9�d:eMe-�ZNGd;�d<eM�ZOGd=�d>eMe-�ZPGd?�d@eM�ZQGdA�dBeK�ZRGdC�dDeO�ZSGdE�dFeE�ZTGdG�dHe�ZUdI�ZVdJ�ZWdK�ZXdL�ZYdM�ZZdN�Z[dO�Z\dP�Z]dQ�Z^dR�Z_dS�Z`dXdT�ZadU�ZbdV�Zcy)Ya�
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)�Tuple�Dict)�default_sort_key)�Symbol�symbols)�CantSympify�_sympify)�AssocOp)�
SYMPY_INTS)�eye)�sympy_deprecation_warning�SymPyDeprecationWarning�ignore_warnings)�memoize_property�
deprecated)�siftc�"�tdddd��y)Nz|
        The data attribute of TensorIndexType is deprecated. Use The
        replace_with_arrays() method instead.
        z1.4z deprecated-tensorindextype-attrs���deprecated_since_version�active_deprecations_target�
stacklevel�r"���5/usr/lib/python3/dist-packages/sympy/tensor/tensor.py�deprecate_datar2<s���	�"'�#E��r0c�"�tdddd��y)Nzn
        The Tensor.fun_eval() method is deprecated. Use
        Tensor.substitute_indices() instead.
        �1.5�deprecated-tensor-fun-evalr)r*r.r/r0r1�deprecate_fun_evalr6G����	�"'�#?��r0c�"�tdddd��y)Nzx
        Calling a tensor like Tensor(*indices) is deprecated. Use
        Tensor.substitute_indices() instead.
        r4r5r)r*r.r/r0r1�deprecate_callr9Sr7r0c��eZdZdZdd�Zed��Zed��Zed��Zd�Z	ed��Z
ed��Zed	��Zdd
�Z
d�Zd�Zd
�Zd�Zd�Zd�Zdd�Zd�Zy)�_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.
    c���||_||_||_||_t	|j�dt	|j�zz|_|jj
d���y)N�c��|dS�Nrr/��xs r1�<lambda>z*_IndexStructure.__init__.<locals>.<lambda>os
��A�a�D�r0��key)�free�dum�index_types�indices�len�	_ext_rank�sort)�selfrErFrGrH�canon_bps      r1�__init__z_IndexStructure.__init__isQ����	����&�������T�Y�Y��!�C����M�/�9������
�
�.�
�)r0c��tj|�\}}|D�cgc]}|j��}}tj|||�}t||||�Scc}w)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])
        )r;�_free_dum_from_indices�tensor_index_type�_replace_dummy_names)rHrErF�irGs     r1�from_indicesz_IndexStructure.from_indicesqs[��*$�:�:�G�D�	��c�4;�<�q�q�*�*�<��<�!�6�6�w��c�J���t�S�+�w�?�?��=s�Ac��g}|D]}|j|j��tj|||�}t||||�S�N)�extendrGr;�*generate_indices_from_free_dum_index_types)�
componentsrErFrG�	componentrHs      r1�from_components_free_dumz(_IndexStructure.from_components_free_dum�sQ����#�	6�I����y�4�4�5�	6�!�L�L�T�SV�Xc�d���t�S�+�w�?�?r0c�Z�t|�}|dk(r
|ddfggfSdgt|�z}i}g}t|�D]�\}}|j}|j}|j}	||f|vrp|||f\}
}|
r|	rtd||fz��d||<d||<n|	rd||<d||<ntd||fz��|	r|j
||f���|j
||f���|j|f|||f<��t|�D��cgc]\}}||s�||f��}}}|j�||fScc}}w)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)])
        �rTz2two equal contravariant indices in slots %d and %dFz.two equal covariant indices in slots %d and %d)rI�	enumerate�namerQ�is_up�
ValueError�appendrK)rH�nrE�
index_dictrFrS�indexr_�typ�contr�is_contr�poss            r1rPz&_IndexStructure._free_dum_from_indices�sp��0
��L����6��Q�Z��O�$�b�(�(��v�c�'�l�"���
���!�'�*�	9�H�A�u��:�:�D��)�)�C��K�K�E��c�{�j�(� *�D�#�;� 7�
��#���(�)]�`c�ef�_g�)g�h�h�$)��S�	�"'��Q���$)��S�	�"'��Q��(�)Y�\_�ab�[c�)c�d�d���J�J��3�x�(��J�J��Q�x�(�*/�+�+�q�.�
�D�#�;�'�3	9�6,5�W�+=�I�x�q�%��a����
�I��I��	�	���S�y���Js�<
D'�
D'c� �|jddS)z_
        Get a list of indices, creating new tensor indices to complete dummy indices.
        N)rH�rLs r1�get_indicesz_IndexStructure.get_indices�s���|�|�A��r0c�"�dgt|�dt|�zzz}|D]
\}}|||<�tj|�}|D]2\}}||}	||	�}
t|
|	d�||<t|
|	d�||<�4tj	|||�S)Nr=TF)rIr;� _get_generator_for_dummy_indices�TensorIndexrR)rErFrGrH�idxri�generate_dummy_name�pos1�pos2�typ1�indnames           r1rXz:_IndexStructure.generate_indices_from_free_dum_index_types�s����&�#�d�)�A�c�#�h�J�.�/���	�H�C���G�C�L�	�.�N�N�t�T���	>�J�D�$��t�$�D�)�$�/�G�'���t�<�G�D�M�'���u�=�G�D�M�		>��3�3�G�T�3�G�Gr0c	�L��tt��|D]�\}}|jjd�d|jj
k(s�<t
�|jt|jjd�d�dz��|j<���fd�}|S)N�_rr]c�^��t�|�}�|xxdz
cc<|jdz|zS�Nr]rw��str�
dummy_name�rQ�nd�cdts  �r1�dummy_name_genzH_IndexStructure._get_generator_for_dummy_indices.<locals>.dummy_name_gen��:����S�*�+�,�B��!�"�a�'�"�$�/�/�#�5��:�:r0)r	�intr_�splitrQr|�max)rE�indx�iposr�rs    @r1rnz0_IndexStructure._get_generator_for_dummy_indices�s�����#����	q�J�D�$��y�y���s�#�A�&�$�*@�*@�*K�*K�K�.1�#�d�6L�6L�2M�s�SW�S\�S\�Sb�Sb�cf�Sg�hi�Sj�Ok�no�Oo�.p��D�*�*�+�	q�	;�
�r0c�>�|jd���t|�}t|�t|�dt|�zzk(sJ�tj	|�}|D]<\}}||j
}||�}t
||d�||<t
||d�||<�>|S)Nc��|dSr?r/r@s r1rBz6_IndexStructure._replace_dummy_names.<locals>.<lambda>�s
��q��t�r0rCr=TF)rK�listrIr;rnrQro)	rHrErF�new_indicesrq�ipos1�ipos2rtrus	         r1rRz$_IndexStructure._replace_dummy_names�s������^��$��7�m���7�|�s�4�y�1�S��X�:�5�5�5�5�-�N�N�t�T���	C�L�E�5��u�%�7�7�D�)�$�/�G�!,�W�d�D�!A�K���!,�W�d�E�!B�K���		C�
�r0c�b�t|jd���}|D�cgc]}|d��	c}Scc}w)z-
        Get a list of free indices.
        c��|dS�Nr]r/r@s r1rBz2_IndexStructure.get_free_indices.<locals>.<lambda>
s
��q��t�r0rCr��sortedrE)rLrErSs   r1�get_free_indicesz _IndexStructure.get_free_indicess,��
�d�i�i�^�4��"�#���!��#�#��#s�,c�d�dj|j|j|j�S)Nz_IndexStructure({}, {}, {}))�formatrErFrGrks r1�__str__z_IndexStructure.__str__
s%��,�3�3�D�I�I�t�x�x��IY�IY�Z�Zr0c�"�|j�SrV)r�rks r1�__repr__z_IndexStructure.__repr__s���|�|�~�r0c�J�|jdd}|jd���|S)Nc��|dSr?r/r@s r1rBzD_IndexStructure._get_sorted_free_indices_for_canon.<locals>.<lambda>s
��q��t�r0rC)rErK)rL�sorted_frees  r1�"_get_sorted_free_indices_for_canonz2_IndexStructure._get_sorted_free_indices_for_canons&���i�i��l�����^��,��r0c�2�t|jd���S)Nc��|dSr?r/r@s r1rBzC_IndexStructure._get_sorted_dum_indices_for_canon.<locals>.<lambda>s
��a��d�r0rC)r�rFrks r1�!_get_sorted_dum_indices_for_canonz1_IndexStructure._get_sorted_dum_indices_for_canons���d�h�h�N�3�3r0c��|j�d}dg|jz}t|j�D]\}}||||�<�|Sr?)�indices_canon_argsrJr^rG)rL�permutationrGrS�its     r1�)_get_lexicographically_sorted_index_typesz9_IndexStructure._get_lexicographically_sorted_index_typessW���-�-�/��2���f�T�^�^�+���t�/�/�0�	-�E�A�r�*,�K��A��'�	-��r0c��|j�d}dg|jz}t|j�D]\}}||||�<�|Sr?)r�rJr^rH)rLr�rHrSr�s     r1�%_get_lexicographically_sorted_indicesz5_IndexStructure._get_lexicographically_sorted_indices"sT���-�-�/��2���&����'���t�|�|�,�	)�E�A�r�&(�G�K��N�#�	)��r0c�|�|j�D�cgc]}|d��	}}|j�}|j�}t|�}|j}t||z
dz�D�cgc]}dgdz��
}	}g}
dg|z}dg|z}t|�D]s}||}
||
||<||
||<|
|kr0||
}||||
jk(sJ�|
j||f��M|
|z
}t|d�\}}|r	||	|d<�l||	|d<�u|	D�cgc]
}t|���}	}t|
|	||�Scc}wcc}wcc}w)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
        rr=Nr])r�r�r�rIrJ�rangerQrb�divmod�tupler;)rL�g�is_canon_bprSr��lex_index_types�lex_indices�nfree�rankrFrErGrH�gi�ind�j�idum�covrAs                   r1�perm2tensorz_IndexStructure.perm2tensor)sw��&*�%L�%L�%N�O��q��t�O��O��H�H�J���@�@�B���K� ���~�~��!&��u��q�'8�!9�:�A��v�a�x�:��:����f�T�k���&��+���t��	%�A��1��B�,�R�0�K��N�$�R��G�A�J��E�z�!�"�o��"�1�~��R��)J�)J�J�J�J����S�!�H�%���J��"�1�a�L�	��c��#$�C��I�a�L�#$�C��I�a�L�	%�"%�%�A�u�Q�x�%��%��t�S�+�w�?�?��7P��
;��(&s�D/�+
D4�
D9c�h�ddlm}|j}dg|z||dzgz}d�}t|j	��D]
\}\}}|||<�t|j�}t|j�}	g}
d}g}g}
|j�D]�\}}|	||<|	dz||<|	dz
}	|j|}||k7r>|r|
j|�||dzg}|}|
j||j��n|j||dzg�|dz
}��|r|
j|�||�|
|
fS)z�
        Returns ``(g, dummies, msym, v)``, the entries of ``canonicalize``

        See ``canonicalize`` in ``tensor_can.py`` in combinatorics module.
        r)�_af_newNr]c��|�y|j}|tjd�k(ry|tjd�k(ryy)Nr=r���r])�symmetry�TensorSymmetry�fully_symmetric)�metric�syms  r1�metric_symmetry_to_msymzC_IndexStructure.indices_canon_args.<locals>.metric_symmetry_to_msym`sB���~���/�/�C��n�4�4�Q�7�7���n�4�4�R�8�8��r0r=)� sympy.combinatorics.permutationsr�rJr^r�rIrEr�rGrbr�rW)rLr�rcr�r�rSr�r�rir��dummies�prev�a�msymr�r�rfs                 r1r�z"_IndexStructure.indices_canon_argsSsS��	=��N�N��
�F�1�H��1�Q�3�x���	� )��)P�)P�)R�S�	�O�A�|��d��A�d�G�	��$�)�)�n����	�	�N���������� �B�B�D�
	�L�E�5��A�e�H��1�u�A�e�H�
��F�A��"�"�5�)�C��d�{���N�N�1�%��#��'�N�������3�C�J�J�?�@����#�s�Q�w��(��1�H�C�
	�
��N�N�1���q�z�7�D�(�(r0N�F��returnzlist[TensorIndex])�__name__�
__module__�__qualname__�__doc__rN�staticmethodrTr[rPrlrXrnrRr�r�r�r�r�r�r�r�r�r/r0r1r;r;_s����*��@��@�2�@��@��<��<�|��H��H����� �
��
�$�[���
4���(@�T4)r0r;c��g}d}|D]-}||k(r|ddxxdz
cc<�|}|j|dg��/g}|D]�\}}|jdvr
|j}n*tj|j|j�}|j|jj
|jj||f���|S)N���r]�rr])rb�comm�
TensorManager�get_commr��base�
generators)rY�numtypr��t�v�hrcr�s        r1�components_canon_argsr��s���
�F��D�
�%����9��2�J�q�M�Q��M��D��M�M�4��)�$�%�	�A��D���1��6�6�V���6�6�D� �)�)�!�&�&�!�&�&�9�D�	���!�*�*�/�/�1�:�:�#8�#8�!�T�B�C�D�
�Hr0c���eZdZUdZiZded<iZded<d�Zd�Ze	d��Z
d�Zd	�Zd
�Z
d�Zd�Zd
�Zd�Zd�Ze	d��Ze	d��Ze	d��Ze	dd��Ze	d��Ze	d��Ze	d��Zy)�_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.
    zdict[Any, Any]�_substitutions_dict�_substitutions_dict_tensmulc���|j|�}|�yddlm}t||�s|S|j	�dk(r|dS|j	�dk(rt|�dk(r|dS|S)Nr])�	NDimArrayrr/)�_get�arrayr��
isinstancer�rI)rLrD�datr�s    r1�__getitem__z$_TensorDataLazyEvaluator.__getitem__�sd���i�i��n���;��$��#�y�)��J��8�8�:��?��r�7�N�
�X�X�Z�1�_��S��Q���q�6�M��
r0c	���||jvr|j|St|t�ryt|t�r�t	|j�D�cgc]}|j��c}�}|jf|z}||jvr|j|S|j|�g}|j||j|j�St|t��rm|j}t|�dk(r�t|dj �dk(rgt	|dj�D�cgc]}|j��c}�}|dj df|z}||jvr|j|S|D�cgc]@}t|t"�s�t|t�r|j|�n|j$��B}}t'|D�cgc]}t|t"�r�|��c}�}t)d�|D��ryt+d�|D��rt-d��|j||j|j�}	||	zSt|t.��rZg}g}
|jD]|}t|t"�rH|j1|j$�|
j1|j2D�cgc]}|d��	c}��[|j1|�|
j1g��~t)d�|D��ryt+d�|D��rt-d��g}
dd	lm}t9||
�D]w\}}t|�d
kr|
j1|��&t;|�D��cic]\}}||��
}}}|j<D�cgc]}||��	}}|
j1|||���yt?d�|
�Sycc}wcc}wcc}wcc}wcc}wcc}}wcc}w)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``.
        Nr]rc3�$K�|]}|du���
y�wrVr/��.0rSs  r1�	<genexpr>z0_TensorDataLazyEvaluator._get.<locals>.<genexpr>������0��1��9�0���c3�$K�|]}|du���
y�wrVr/r�s  r1r�z0_TensorDataLazyEvaluator._get.<locals>.<genexpr>�r�r�zSMixing tensors with associated components data with tensors without components datac3�$K�|]}|du���
y�wrVr/r�s  r1r�z0_TensorDataLazyEvaluator._get.<locals>.<genexpr>r�r�c3�$K�|]}|du���
y�wrVr/r�s  r1r�z0_TensorDataLazyEvaluator._get.<locals>.<genexpr>r�r���permutedimsr=c��||zSrVr/)rA�ys  r1rBz/_TensorDataLazyEvaluator._get.<locals>.<lambda>s
��q��s�r0) r�r��
TensorHead�Tensorr�rlr`rZr��data_from_tensor�data_contract_dumrF�ext_rank�TensMul�argsrIrY�TensExpr�datar�all�anyra�TensAddrbrEr�r��zipr^�	free_argsr)rLrDrS�	signature�srch�
array_list�tensmul_args�	data_list�coeff�data_result�free_args_list�argrA�sum_listr�r�rr��
free_args_pos�axess                    r1r�z_TensorDataLazyEvaluator._get�s��� �$�*�*�*��+�+�C�0�0��c�:�&���c�6�"�����0A�B�1�q�w�w�B�C�I��M�M�#�i�/�D��t�7�7�7��7�7��=�=��/�/��4�5�J��)�)�*�c�g�g�s�|�|�L�L��c�7�#��8�8�L��<� �A�%�#�l�1�o�.H�.H�*I�Q�*N�"�L��O�4O�4O�4Q�"R�q�1�7�7�"R�S�	�$�Q��2�2�1�5�7�)�C���4�;�;�;��;�;�D�A�A�`l�I�[\�pz�{|�G�qH�Z��6�5J��.�.�q�1�PQ�PV�PV�V�I�I�I��\�Q���A�x�9P�!�Q�R�E��0�i�0�0���0�i�0�0� �"M�N�N��0�0��C�G�G�S�\�\�R�K���$�$��c�7�#��I��N��x�x�
.���c�8�,��$�$�S�X�X�.�"�)�)����*B�A�1�Q�4�*B�C��$�$�S�)�"�)�)�"�-�

.��0�i�0�0���0�i�0�0� �"M�N�N��H�*�#&�y�.�#A�
=���i��y�>�A�%��O�O�D�)�6?�	�6J�$K�d�a��Q��T�$K�M�$K�:=�-�-�H�3�M�#�.�H�D�H��O�O�K��d�$;�<�

=��*�H�5�5���oC��#S��
I��Q��+C�� %L��Hs6�O�6O�O
�/O
�O�-O�<O
�,
O�
Oc�\�ddlm}m}m}t	t||��}||�}||g|���S)Nr])�
tensorproduct�tensorcontraction�MutableDenseNDimArray)r�rrrr��map)�ndarray_listrFr�rrr�arrays�prodarrs        r1r�z*_TensorDataLazyEvaluator.data_contract_dums4��R�R��c�/��>�?����(�� ��/�3�/�/r0c�v�|�y|j||j�|j|jd�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_indicesrlrErF)rLr��tensmul�
tensorheads    r1�data_tensorhead_from_tensmulz5_TensorDataLazyEvaluator.data_tensorhead_from_tensmuls?���<���3�3�����!��L�L��K�K���	r0c��|j}|j�y|j|j|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)rZr�rrlrErF)rL�tensorrs   r1r�z)_TensorDataLazyEvaluator.data_from_tensor+sP���%�%�
��?�?�"���3�3��O�O���� ��K�K��J�J�	�	r0c���t|t�rtd��t|j�dk7rtd��|jd}|j|||�}||fS)Nzcannot assign data to TensAddr]z6cannot assign data to TensMul with multiple componentsr)r�r�rarIrYr)rLrDr�r�newdatas     r1�_assign_data_to_tensor_exprz4_TensorDataLazyEvaluator._assign_data_to_tensor_expr<sb���c�7�#��<�=�=��s�~�~��!�#��U�V�V��^�^�A�&�
��3�3�D�#�z�J���7�"�"r0c	��ddlm}ddlm}t	|t
�r#|j}|jj}n�t	|t�r0|j}|jdjj}nFt	|t�r6|jj}|jjj}D]�}|�|k(rdnd}|}	|}
tt|t|���}t|j!�dz
�D]/}||	|�}	t#||
||	zz
��rt%d��|	}
�1��y)Nr]r�)�Flattenrr�z'Component data symmetry structure error)r�r��
array.arrayopr r�r�r�r�r�r�rY�TensorIndexTyper�r�rr��orderr�ra)
rL�tensr�r�r r�r��gener�sign_change�data_swapped�	last_data�permute_axesrSs
             r1�_check_permutations_on_dataz4_TensorDataLazyEvaluator._check_permutations_on_dataFs��&�*��d�J�'��9�9�D����1�1�J�
��f�
%��9�9�D�����+�4�4�?�?�J�
��o�
.��;�;�#�#�D����-�-�8�8�J�
 �	)�E�!&�t���!4�"�2�K��L��I���E�5��;� 7�8�L��5�;�;�=��?�+�
)��*�<��F���w�y�;�|�+C�C�D�E�$�%N�O�O�(�	�
)�	)r0c���tj|�}|j||�t|tt
f�s|j
||�\}}t|t�rt|j|j�D]\\}}|j�tdj|���|jjs�C||jk7s�Std��||j|<y)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)zwrong dimension of ndarray)r��
parse_datar*r�r�r"rr��shaperGr�rar��dim�	is_numberr�)rLrD�valuer�r.�	indextypes      r1�__setitem__z$_TensorDataLazyEvaluator.__setitem__es���(�2�2�5�9���(�(��d�3�
�#�
�O�<�=��8�8��d�C�I�C���c�:�&�"%�d�j�j�#�/�/�"B�
C���Y��>�>�)�$�&@�@F��y�@Q�S�S� �}�}�.�.���)�-�-�'�$�%A�B�B�
C�)-�� � ��%r0c��|j|=yrV�r��rLrDs  r1�__delitem__z$_TensorDataLazyEvaluator.__delitem__�s���$�$�S�)r0c��||jvSrVr4r5s  r1�__contains__z%_TensorDataLazyEvaluator.__contains__�s���d�.�.�.�.r0c��||j|ddf<|j|�}||j|ddf<|j�}|j�}||z|j|ddf<||z|j|ddf<y)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)rLr�r��inverse_transpose�m�invts      r1�add_metric_dataz(_TensorDataLazyEvaluator.add_metric_data�s���"@D��(�(���t�);�<� �9�9�$�?��BS��(�(����)=�>�
�M�M�O�� �)�)�+��@A�D���(�(���u�)<�=�@D�q���(�(����)<�=r0c��ddlm}m}|j�}|j�}|dk(r||||�d||zf�}|S||||�||f�}|S)Nr]�rrr)r�rrr�)r�r�rirr�mdim�ddims       r1�_flip_index_by_metricz._TensorDataLazyEvaluator._flip_index_by_metric�sx��;��{�{�}���y�y�{���!�8�$������D��H�
��D���%������d���D��r0c�h�|j�j�}tj|�SrV)r;�invr�r,��ndarrayr=s  r1�inverse_matrixz'_TensorDataLazyEvaluator.inverse_matrix�s*������"�"�$��'�2�2�1�5�5r0c�|�|j�j�j}tj	|�SrV)r;rF�Tr�r,rGs  r1r:z1_TensorDataLazyEvaluator.inverse_transpose_matrix�s0������"�"�$�&�&��'�2�2�1�5�5r0c�<�t|�D]�\}}|js.|s,tj||jj
|�}�@|jr�M|s�Ptj|tj
|jj
�|�}��|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.
        )r^r`r�rDrQr�rI)r�rHrErF�inverserSr�s       r1rz8_TensorDataLazyEvaluator._correct_signature_from_indices�s���!��)�	�G�A�t��:�:�g�/�E�E�d�D�Lb�Lb�Lg�Lg�ij�k���Z�Z�G�/�E�E��,�;�;�D�<R�<R�<W�<W�X����		��r0c��ddlm}|jj�}|jD�cgc]}|d��	}}|jD�cgc]}|d��	}}tt
|��D]E}t|t
|��D]+}||||k(s�||||c||<||<||||f�}�E�G|Scc}wcc}w)Nr]r�r)r�r�r��copyrEr�rI)�old�newr��new_datarS�old_free�new_freer�s        r1�_sort_data_axesz(_TensorDataLazyEvaluator._sort_data_axes�s���&��8�8�=�=�?��"%�(�(�+�Q�A�a�D�+��+�"%�(�(�+�Q�A�a�D�+��+��s�8�}�%�	�A��1�c�(�m�,�
���A�;�(�1�+�-�/7��{�H�Q�K�,�H�Q�K��!��*�8�a��V�<�H��	
�	����,��+s�B7�B<c�D�����fd�}|�tj�<y)Nc�0��tj���SrV)r�rU)�new_tensmul�old_tensmuls��r1�sorted_compozJ_TensorDataLazyEvaluator.add_rearrange_tensmul_parts.<locals>.sorted_compo�s���+�;�;�K��U�Ur0)r�r�)rXrYrZs`` r1�add_rearrange_tensmul_partsz4_TensorDataLazyEvaluator.add_rearrange_tensmul_parts�s ���	V�EQ�N� �4�4�[�Ar0c��ddlm}t||�s6t|�dk(r t	|dd�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]�rr=r�__call__)r�rr�rI�hasattr)r�rs  r1r,z#_TensorDataLazyEvaluator.parse_data�sV��"	1��$� 5�6��4�y�A�~�'�$�q�'�:�">�,�T�!�W�d�1�g�>����-�T�2���r0Nr�)r�r�r�r�r��__annotations__r�r�r�r�r�rr�rr*r2r6r8r?rDrIr:rrUr[r,r/r0r1r�r��s����"+-���,�24���4�
�Q�f�0��0�� �"#�)�>-�>*�/�I�<����0�6��6��6��6�����(���� �S��S����r0r�c�P�eZdZdZd�Zd�Zed��Zd�Zd�Z	d�Z
d�Zd	�Zd
�Z
y)�_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�$�|j�yrV��
_comm_initrks r1rNz_TensorManager.__init__)s�����r0c�J�td�D�cgc]}i��c}|_td�D]&}d|jd|<d|j|d<�(d|jdd<d|jdd<d|jdd<dddd�|_dddd�|_ycc}w)N�rr]r=)rr]r=)r��_comm�_comm_symbols2i�_comm_i2symbol�rLrSs  r1rez_TensorManager._comm_init,s���"'��(�+�Q�b�+��
��q��	!�A� �D�J�J�q�M�!�� �D�J�J�q�M�!��	!���
�
�1�
�a����
�
�1�
�a����
�
�1�
�a��"#�q�A����!"�a�1�o����,s�	B c��|jSrV)rhrks r1r�z_TensorManager.comm7����z�z�r0c�$�||jvrtt|j�}|jji�d|j|d<d|jd|<||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)rirIrhrbrj)rLrSrcs   r1�comm_symbols2iz_TensorManager.comm_symbols2i;s���
�D�(�(�(��D�J�J��A��J�J���b�!� �D�J�J�q�M�!�� �D�J�J�q�M�!��&'�D� � ��#�%&�D����"��H��#�#�A�&�&r0c� �|j|S)zS
        Returns the symbol corresponding to the commutation group number.
        )rjrks  r1�
comm_i2symbolz_TensorManager.comm_i2symbolNs���"�"�1�%�%r0c��|dvrtd��||jvrrt|j�}|jj	i�d|j|d<d|jd|<||j|<||j
|<||jvrrt|j�}|jj	i�d|jd|<d|j|d<||j|<||j
|<|j|}|j|}||j||<||j||<y)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)
        )rr]Nz+`c` can assume only the values 0, 1 or NonerN)rarirIrhrbrj)rLrSr��crc�ni�njs       r1�set_commz_TensorManager.set_commTs?��d
�L� ��J�K�K��D�(�(�(��D�J�J��A��J�J���b�!� �D�J�J�q�M�!�� �D�J�J�q�M�!��&'�D� � ��#�%&�D����"��D�(�(�(��D�J�J��A��J�J���b�!� �D�J�J�q�M�!�� �D�J�J�q�M�!��&'�D� � ��#�%&�D����"�
�
!�
!�!�
$��
�
!�
!�!�
$����
�
�2��r����
�
�2��r�r0c�@�|D]\}}}|j|||��y)z�
        Set the commutation group numbers ``c`` for symbols ``i, j``.

        Parameters
        ==========

        args : sequence of ``(i, j, c)``
        N)rv)rLr�rSr�rss     r1�	set_commsz_TensorManager.set_comms�s)���	#�G�A�q�!��M�M�!�Q��"�	#r0c�`�|j|j||dk(s|dk(rd�Sd�S)z�
        Return the commutation parameter for commutation group numbers ``i, j``

        see ``_TensorManager.set_comm``
        rN)rh�get)rLrSr�s   r1r�z_TensorManager.get_comm�s3���z�z�!�}� � ���a��1��6�A�D�D�t�D�Dr0c�$�|j�y)z*
        Clear the TensorManager.
        Nrdrks r1�clearz_TensorManager.clear�s��	
���r0N)r�r�r�r�rNre�propertyr�rorqrvrxr�r|r/r0r1rbrbsF���&�	.�����'�&&�F�P
#�E�r0rbc�D�eZdZdZ		dd�Zed��Zed��Zed��Zed��Z	e
d��Ze
d	��Ze
d
��Z
d�Zd�Zd
�ZeZed��Zej&d��Zej(d��Zeddd��d��Zeddd��d��Zd�Zy)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)
    Nc	�F�d|vr|d}td|�d�dd��|}t|t�rt|�}|�t|�d}t|t�rt|�}|�td|jz�}nt|�}|�|}nt|�}t|�}t|t�rt|�}d	|vr;t
d
dd��|jd	�}	|	�|	dvrd	}n|	j}|	rd
}nd}tj|||||||�}
g|
_
|
S)N�	dummy_fmtzh
                The dummy_fmt keyword to TensorIndexType is deprecated. Use
                dummy_name=z instead.
                r4z$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)TFrr]r�r])r"r�r{rr_rr#rzr�__new__�_autogenerated)�clsr_r|r.�eps_dim�metric_symmetry�metric_name�kwargsr�r��objs           r1r�zTensorIndexType.__new__sS���&� ��{�+�I�%��%�;�'��*/�+Q�

�#�J��d�C� ��$�<�D����T��1��J��j�#�&��
�+�J��;���*�/�/�1�2�C��#�,�C��?��G��g�&�G�!�/�2���k�3�'� ��-�K��v��#��
*/�+N�
��Z�Z��)�F��!��0�0�"*�K�#)�+�+�K��&(�O�&'�O��m�m�C��z�3��+�[�:�� ����
r0c�4�|jdjSr?�r�r_rks r1r_zTensorIndexType.nameC����y�y��|� � � r0c�4�|jdjSr�r�rks r1r|zTensorIndexType.dummy_nameGr�r0c� �|jdS�Nr=�r�rks r1r.zTensorIndexType.dimK����y�y��|�r0c� �|jdS�Nrgr�rks r1r�zTensorIndexType.eps_dimOr�r0c��|jd}|jd}|�y|dk(rtjd�}n5|dk(rtjd�}n|dk(rtjd�}t	||gdz�S)Nr)�rr=r]r�r�)r�r��no_symmetryr�r�)rLr�r�r�s    r1r�zTensorIndexType.metricSs����)�)�A�,���i�i��l���"���a��%�1�1�!�4�H�
��
!�%�5�5�a�8�H�
��
"�%�5�5�b�9�H��+��v�a�x��:�:r0c�J�td|gdztjd��S)N�KDr=)r�r�r�rks r1�deltazTensorIndexType.deltacs"���$���q��.�*H�*H��*K�L�Lr0c��t|jttf�sytj|j�}t
d|g|jz|�S)N�Eps)r�r�r r
r�r�r�)rLr�s  r1�epsilonzTensorIndexType.epsilongsH���$�,�,��W�(=�>��!�1�1�4�<�<�-�@���%�$�����!4�h�?�?r0c��||_yrV)�_metric)rLrs  r1�
set_metriczTensorIndexType.set_metricns	����r0c�4�|j|jkSrV�r_�rL�others  r1�__lt__zTensorIndexType.__lt__qs���y�y�5�:�:�%�%r0c��|jSrVr�rks r1r�zTensorIndexType.__str__ts���y�y�r0c�r�t�tt�5t|cddd�S#1swYyxYwrV�r2r$r#�_tensor_data_substitution_dictrks r1r�zTensorIndexType.data{�.����
�4�
5�	8�1�$�7�	8�	8�	8���	-�6c���t�ddlm}tj	|�}|j�dkDrt
d��|j�dk(r||jjr)|jd}||jk7rt
d��|jd}|j||�}t|�D]\}}||||f<�|}|j\}}	||	k7rt
d��|jjr|j|k7rt
d��|t|<tj|j|�tt �5|j#�}
ddd�t%d|�}t%d	|�}tt �5tj	t'|��
||�_ddd�y#1swY�exYw#1swYyxYw)
Nr]r]r=z1data have to be of rank 1 (diagonal metric) or 2.rzDimension mismatchzNon-square matrix tensor.�i1�i2)r2r�rr�r,r�rar.r/r-�zerosr^r�r?r�r$r#�get_kronecker_deltaror!r�)
rLr�r�nda_dimr.�
newndarrayrS�val�dim1�dim2r�r�r�s
             r1r�zTensorIndexType.data�s�����	1�'�2�2�4�8���9�9�;��?��P�Q�Q��9�9�;�!���x�x�!�!��*�*�Q�-���d�h�h�&�$�%9�:�:��*�*�Q�-�C�.�4�4�S�#�>�J�#�D�/�
'���3�#&�
�1�a�4� �
'��D��Z�Z�
��d��4�<��8�9�9��8�8����x�x�4�� �!5�6�6�/3�&�t�,�&�6�6�t�{�{�D�I�
�4�
5�	/��,�,�.�E�	/�
��t�
$��
��t�
$��
�4�
5�	Q�":�"E�"E�c�$�i�"P�E�"�r�c�N��	Q�	Q�		/�	/��	Q�	Q�s�G�,G�G�G$c���t�tt�5|tvrt|=|jtvrt|j=ddd�y#1swYyxYwrV�r2r$r#r�r�rks r1r�zTensorIndexType.data��T����
�4�
5�	@��5�5�2�4�8��{�{�<�<�2�4�;�;�?�		@�	@�	@���3A�Az�
        The TensorIndexType.get_kronecker_delta() method is deprecated. Use
        the TensorIndexType.delta attribute instead.
        r4z"deprecated-tensorindextype-methodsr�c�P�ttd��}td|gdz|�}|S)Nr=r�)r�rr�)rL�sym2r�s   r1r�z#TensorIndexType.get_kronecker_delta�s-���5�a�8�9���4�$����4�0���r0z�
        The TensorIndexType.get_epsilon() method is deprecated. Use
        the TensorIndexType.epsilon attribute instead.
        c��t|jttf�syt	t|jd��}t
d|g|jz|�}|S)Nr]r�)r��_eps_dimr r
r�rr�)rLr�r�s   r1�get_epsilonzTensorIndexType.get_epsilon�sN���$�-�-�*�g�)>�?���4�T�]�]�A�F�G���U�T�F�4�=�=�$8�#�>���r0c��|tvrt|=d�}||jddf�||jddf�||jddf�||jddf�|j�}|tvrt|=yy)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�L�|tjvrtj|=yyrV)r�r�rCs r1�delete_tensmul_datazJTensorIndexType._components_data_full_destroy.<locals>.delete_tensmul_data�s%���4�P�P�P�2�N�N�s�S�Qr0TFN)r�r�r�)rLr�r�s   r1�_components_data_full_destroyz-TensorIndexType._components_data_full_destroy�s����1�1�.�t�4�	T�
	�T�[�[�$��5�6��T�[�[�$��6�7��T�[�[�%��6�7��T�[�[�%��7�8��(�(�*���2�2�.�u�5�3r0)NNNr]r�)r�r�r�r�r�r}r_r|r.r�r%r�r�r�r�r�r�r�r��setter�deleterr&r�r�r�r/r0r1r"r"�sY��C�J?C�/7�A�F�!��!��!��!����������
;��
;��M��M��@��@��&���H��8��8�

�[�[�"Q��"Q�H
�\�\�@��@��	�"'�#G�
����
�	�"'�#G�
����6r0r"c�Z�eZdZdZd
d�Zed��Zed��Zed��Zd�Z	d�Z
d�Zy	)roaq
    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)
    c�Z�t|t�rt|�}nmt|t�r|}nZ|durKdjt	|j
��}t|�}|j
j
|�ntd��t|�}tj||||�S�NTz_i{}�invalid name�r�r{rr�rIr�rbrarrr�)r�r_rQr`�name_symbols     r1r�zTensorIndex.__new__s����d�C� � ��,�K�
��f�
%��K�
�T�\��=�=��%6�%E�%E�!F�G�D� ��,�K��,�,�3�3�K�@��^�,�,������}�}�S�+�/@�%�H�Hr0c�4�|jdjSr?r�rks r1r_zTensorIndex.name)r�r0c� �|jdSr�r�rks r1rQzTensorIndex.tensor_index_type-r�r0c� �|jdSr�r�rks r1r`zTensorIndex.is_up1r�r0c�@�|j}|jsd|z}|S)Nz-%s)r_r`)rL�ss  r1�_printzTensorIndex._print5s ���I�I���z�z���	�A��r0c�d�|j|jf|j|jfkSrV)rQr_r�s  r1r�zTensorIndex.__lt__;s0���'�'����3��(�(�%�*�*�5�6�	7r0c�^�t|j|j|j�}|SrV)ror_rQr`�rL�t1s  r1�__neg__zTensorIndex.__neg__?s(��
����D�$:�$:��Z�Z��"���	r0N�T)r�r�r�r�r�r}r_rQr`r�r�r�r/r0r1roro�sY��0�b
I��!��!����������7�r0roc���t|t�r%t|d��D�cgc]}|j��}}nt	d��|D�cgc]}t||���}}t
|�dk(r|dS|Scc}wcc}w)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)
    T��seq�expecting a stringr]r)r�r{rr_rarorI)r�rfrAr�rS�tilists      r1�tensor_indicesr�Esw��$�!�S��$�Q�D�1�2��Q�V�V�2��2��-�.�.�+,�
-�a�k�!�S�!�
-�F�
-�
�6�{�a���a�y���M��
3��.s�A/�A4c��eZdZdZd�Zed��Zed��Zed��Ze	d��Z
e	d��Ze	d��Ze	d	��Z
y
)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��t|�dk(r	|d\}}nt|�dk(r|\}}ntd��t|t�st|�}t|t�st|�}t	j
|||fi|��S)Nr]rr=z:bsgs required, either two separate parameters or one tuple)rI�	TypeErrorr�rrr�)r�r��kw_argsr�r�s     r1r�zTensorSymmetry.__new__�s{���t�9��>�#�A�w��D�*�
��Y�!�^�#��D�*��X�Y�Y��$��&��$�<�D��*�e�,��
�+�J��}�}�S�$�
�>�g�>�>r0c� �|jdSr?r�rks r1r�zTensorSymmetry.base�r�r0c� �|jdSr�r�rks r1r�zTensorSymmetry.generators�r�r0c�:�|jdjdz
S)Nrr=)r��sizerks r1r�zTensorSymmetry.rank�s�����q�!�&�&��*�*r0c��|dkDrt|d�}t|�S|dkrt|d�}t|�S|dk(rgtd�gf}t�S)z�
        Returns a fully symmetric (antisymmetric if ``rank``<0)
        TensorSymmetry object for ``abs(rank)`` indices.
        rFTr])rr
r�)r�r��bsgss   r1r�zTensorSymmetry.fully_symmetric�sm���!�8�*�4��7�D�
�d�#�#�	�A�X�*�D�5�$�7�D��d�#�#��Q�Y���Q��(�)�D��d�#�#r0c��gtd�g}}|D]8}|dkDr
t|d�}n|dkrt|d�}n�)t||g|���\}}�: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]rFT)r
rrr�)r�r�r��sgsr	�bsgs2s      r1�direct_productzTensorSymmetry.direct_product�sr�� ��Q��(�c���	?�C��Q�w�/��U�;���q��/���d�;���+�D�#�>��>�I�D�#�	?��d�C�(�(r0c� �tt�S)zD
        Returns a monotorem symmetry of the Riemann tensor
        )r�r)r�s r1�riemannzTensorSymmetry.riemann�s��
�l�+�+r0c�4�tgt|dz�g�S)zM
        TensorSymmetry object for ``rank`` indices with no symmetry
        r])r�r
)r�r�s  r1r�zTensorSymmetry.no_symmetry�s��
�b�;�t�A�v�#6�"7�8�8r0N)r�r�r�r�r�r}r�r�r��classmethodr�r�r�r�r/r0r1r�r�bs���.�^
?����������+��+��$��$��)��)�6�,��,��9��9r0r�zf
    The tensorsymmetry() function is deprecated. Use the TensorSymmetry
    constructor instead.
    r4zdeprecated-tensorsymmetryr�c�F�ddlm}d�}|s#tt�t|d���St	|�dk(rt|dd|�rt|�S||d�\}}|ddD]}||�\}}t
||||�\}}� tt||��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.
    rrc���t|�dk(r|d}t|d�}|Std�|D��rt|�}t|�}|S|ddgk(rt}|St�)Nr]rc3�&K�|]	}|dk(���y�w)r]Nr/�r�rAs  r1r�z7tensorsymmetry.<locals>.tableau2bsgs.<locals>.<genexpr>s����%�a�1��6�%�s�r=)rIrr�r�NotImplementedError)r�rcr�s   r1�tableau2bsgsz$tensorsymmetry.<locals>.tableau2bsgsst���q�6�Q�;��!��A�*�1�a�0�D����%�1�%�%���F��.�q�1��
��	�q�!�f��#����*�)r0r]r=N)�sympy.combinatoricsr
r�rrIr�r)r�r
r�r�r�r��basex�sgsxs        r1�tensorsymmetryr��s���X0�� ��e�g�u�[��^�'<�=�=�
�4�y�A�~�*�T�!�W�Q�Z��=��d�#�#��T�!�W�%�I�D�#�
�!�"�X�@��"�1�o���t�'��c�5�$�?�	��c�@��%��c�*�+�+r0z5TensorType is deprecated. Use tensor_heads() instead.zdeprecated-tensortypec�X�eZdZdZdZd�Zed��Zed��Zed��Z	d�Z
d
d�Zy	)�
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�v�|jt|�k(sJ�tj|t	|�|fi|��}|SrV)r�rIrr�r)r�rGr�r�r�s     r1r�zTensorType.__new__Gs:���}�}��K� 0�0�0�0��m�m�C���!4�h�J�'�J���
r0c� �|jdSr?r�rks r1rGzTensorType.index_typesLr�r0c� �|jdSr�r�rks r1r�zTensorType.symmetryPr�r0c�D�tt|j�d���S)Nc��|jSrVr�r@s r1rBz"TensorType.types.<locals>.<lambda>Vs
��1�6�6�r0rC)r��setrGrks r1�typeszTensorType.typesTs���c�$�*�*�+�1A�B�Br0c�X�d|jD�cgc]
}t|���c}zScc}w)NzTensorType(%s))rGr{�rLrAs  r1r�zTensorType.__str__Xs%���D�4D�4D�#E�q�C��F�#E�F�F��#Es�'c	�\�t|t�r%t|d��D�cgc]}|j��}}nt	d��t|�dk(r%t
|d|j|j|�S|D�cgc]$}t
||j|j|���&c}Scc}wcc}w)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``
        Tr�r�r]r)	r�r{rr_rarIr�rGr�)rLr�r�rA�namesr_s      r1r^zTensorType.__call__[s����a���%,�Q�D�%9�:��Q�V�V�:�E�:��1�2�2��u�:��?��e�A�h��(8�(8�$�-�-��N�N�X]�^�PT�J�t�T�%5�%5�t�}�}�d�K�^�^��
;��_s�B$�8)B)N)r)r�r�r�r��is_commutativer�r}rGr�rr�r^r/r0r1r�r�/s]��� �N��
���������C��C�G�_r0r�zN
    The tensorhead() function is deprecated. Use tensor_heads() instead.
    zdeprecated-tensorheadc���|�"tt|��D�cgc]}dg��}}tt�5t	|�}ddd�t||||�Scc}w#1swY�xYw)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``
    Nr])r�rIr$r#r�r�)r_rfr�r�rSs     r1rrrsd��0�{�!�#�c�(�O�,�q��s�,��,�	�0�	1�#��c�"��#��d�C��d�+�+��-�#�#�s�
A�	A�A!c���eZdZdZdZdd�Zed��Zed��Zed��Z	ed��Z
d	�Zd
�Zd�Z
d�Zd
�Zed��Zej"d��Zej$d��Zd�Zd�Zy)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
    FNc�`�t|t�rt|�}nt|t�r|}ntd��|�tjt
|��}n|jt
|�k(sJ�tj||t|�|�}tj|�|_
|S)Nr�)r�r{rrar�r�rIr�rr�rr�ror�)r�r_rGr�r�r�r�s       r1r�zTensorHead.__new__s����d�C� � ��,�K�
��f�
%��K��^�,�,���%�1�1�#�k�2B�C�H��=�=�C��$4�4�4�4��m�m�C��e�[�.A�8�L�� �/�/��5����
r0c�4�|jdjSr?r�rks r1r_zTensorHead.namer�r0c�2�t|jd�Sr��r�r�rks r1rGzTensorHead.index_typess���D�I�I�a�L�!�!r0c� �|jdSr�r�rks r1r�zTensorHead.symmetryr�r0c�,�t|j�SrV)rIrGrks r1r�zTensorHead.rank s���4�#�#�$�$r0c�d�|j|jf|j|jfkSrV)r_rGr�s  r1r�zTensorHead.__lt__$s+���	�	�4�+�+�,��
�
�E�<M�<M�/N�N�Nr0c�Z�tj|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�)rLr��rs   r1�
commutes_withzTensorHead.commutes_with's#��
�"�"�4�9�9�e�j�j�9���r0c
��|j�ddj|jD�cgc]
}t|���c}��d�Scc}w)N�(�,�))r_�joinrGr{rs  r1r�zTensorHead._print0s2���)�)�S�X�X�t�?O�?O�.P�!�s�1�v�.P�%Q�R�R��.Ps�Ac��g}t||j�D]�\}}t|t�rn|j	�jdd�}|j
d�r!|jt|dd|d����h|jt||����|j|���||t|�dz
}t||fi|��}|j�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]NF�r`)r�rGr�r{�strip�replace�
startswithrbrorIr��doit)rLrHr��updated_indicesrprfrs       r1r^zTensorHead.__call__3s���>���G�T�%5�%5�6�		,�H�C���#�s�#��i�i�k�)�)�#�r�2���>�>�#�&�#�*�*�;�s�1�2�w��16�,8�9�$�*�*�;�s�C�+@�A��&�&�s�+�		,�	�7�3��#7�#8�9�9����o�9��9���{�{�}�r0c	��t�tt�5|j�t	d��ddlm}m}|jD�cgc]}|j��}}|j}|j�}|D] }||||�}||d|f|dz|dzf�}�"||tjzzcddd�Scc}w#1swYyxYw)NzNo power on abstract tensors.r]rArr=)r2r$r#r�rar�rrrGr�r�Half)	rLr�rrrw�metrics�marray�	marraydimr�s	         r1�__pow__zTensorHead.__pow__es�����
�4�
5�	.��y�y� � �!@�A�A�?�'+�'7�'7�8�!�q�v�v�8�G�8��Y�Y�F����
�I�!�
_��&�v�v�v�>��*�6�A�y�>�I�a�K�QZ�[\�Q\�C]�^��
_��e�a�f�f�n�-�	.�	.��9�		.�	.�s�.C�B=�AC�=C�Cc�r�t�tt�5t|cddd�S#1swYyxYwrVr�rks r1r�zTensorHead.dataur�r�c�r�t�tt�5|t|<ddd�y#1swYyxYwrVr��rLr�s  r1r�zTensorHead.data{�1����
�4�
5�	8�37�*�4�0�	8�	8�	8���
-�6c�8�t�|tvrt|=yyrV)r2r�rks r1r�zTensorHead.data�s�����1�1�.�t�4�2r0c��t�tt�5|jj	�cddd�S#1swYyxYwrV�r2r$r#r��__iter__rks r1r0zTensorHead.__iter__��6����
�4�
5�	(��9�9�%�%�'�	(�	(�	(��	�>�Ac�X�t�|jdk(ry|tvrt|=yy)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)r2r_r�rks r1r�z(TensorHead._components_data_full_destroy�s1��	���9�9����
�1�1�.�t�4�2r0r?)r�r�r�r�rr�r}r_rGr�r�r�rr�r^r'r�r�r�r0r�r/r0r1r�r��s���n�^�N��"�!��!��"��"������%��%�O��S�.�d.� �8��8�

�[�[�8��8�

�\�\�5��5�
(�
5r0r�c	��t|t�r%t|d��D�cgc]}|j��}}nt	d��|D�cgc]}t||||���}}t
|�dk(r|dS|Scc}wcc}w)z=
    Returns a sequence of TensorHeads from a string `s`
    Tr�r�r]r)r�r{rr_rar�rI)r�rGr�r�rArr_�thlists        r1�tensor_headsr6�s|���!�S��!(���!5�6�A����6��6��-�.�.�HM�
N��j��{�H�d�;�
N�F�
N�
�6�{�a���a�y���M��7��Os�A1�A6c�f�eZdZdZdZdZd�Zd�Zd�Zd�Z	d�Z
d	�Zd
�Zd�Z
d�Zd
�Zd�Zd�Zeed���Zeed���Zed��Zed&d��Zed'd��Zd�Zd�Zed��Zd�Zd�Zd�Zd�Z d�Z!ed��Z"ed��Z#ed��Z$ed ��Z%ed!��Z&d(d#�Z'd$�Z(d%�Z)y"))r�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�(�|tjzSrV)r�NegativeOnerks r1r�zTensExpr.__neg__�s���A�M�M�!�!r0c��t�rV�r�rks r1�__abs__zTensExpr.__abs__����!�!r0c�6�t||�j�SrV�r�r r�s  r1�__add__zTensExpr.__add__�s���t�U�#�(�(�*�*r0c�6�t||�j�SrVr?r�s  r1�__radd__zTensExpr.__radd__�����u�d�#�(�(�*�*r0c�8�t||�j�SrVr?r�s  r1�__sub__zTensExpr.__sub__�s���t�e�V�$�)�)�+�+r0c�8�t||�j�SrVr?r�s  r1�__rsub__zTensExpr.__rsub__�s���u�t�e�$�)�)�+�+r0c�6�t||�j�S)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�s  r1�__mul__zTensExpr.__mul__�s��.�t�U�#�(�(�*�*r0c�6�t||�j�SrVrIr�s  r1�__rmul__zTensExpr.__rmul__�rCr0c��t|�}t|t�rtd��t	|t
j|z�j�S�Nzcannot divide by a tensor)rr�r�rar�r�Oner r�s  r1�__truediv__zTensExpr.__truediv__�s?�������e�X�&��8�9�9��t�Q�U�U�5�[�)�.�.�0�0r0c��td��rN)rar�s  r1�__rtruediv__zTensExpr.__rtruediv__�s���4�5�5r0c	��t�tt�5|j�t	d��ddlm}m}|j}|j}|j�}|D]5}||||djj|�d|f|dz|dzf�}�7||tjzzcddd�S#1swYyxYw)NzNo power without ndarray data.r]rArr=)
r2r$r#r�rar�rrrEr�rQrr#)rLr�rrrEr%rBr�s        r1r'zTensExpr.__pow__s�����
�4�
5�	.��y�y� � �!A�B�B�?��9�9�D��Y�Y�F��;�;�=�D��
��*�!���1�I�/�/�4�4�����I��Q���Q��/���
��e�a�f�f�n�-�	.�	.�	.�s�BB;�;Cc��t�rVr;r�s  r1�__rpow__zTensExpr.__rpow__r=r0c��td���Nzabstract methodr;rks r1�nocoeffzTensExpr.nocoeff���"�"3�4�4r0c��td��rWr;rks r1rzTensExpr.coeffrYr0c��td��rWr;rks r1rlzTensExpr.get_indices!���!�"3�4�4r0c��td��rWr;rks r1r�zTensExpr.get_free_indices%r\r0c��td��rWr;�rL�repls  r1�_replace_indiceszTensExpr._replace_indices)r\r0c�4�t�|j|�SrV)r6�substitute_indices)rL�index_tupless  r1�fun_evalzTensExpr.fun_eval-s����&�t�&�&��5�5r0c�V�ddlm}t�tt�5d|j
cxkrdkr�ntd��|jjd}|j
dk(r|jjdnd}|j
dk(rPg|z}t|�D]<}|jg�t|�D]}||j|||f���>ndg|z}t|�D]
}||||<�||�cddd�Std��#1swYyxYw)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)�Matrixr=r]Nz-missing multidimensional reduction to matrix.)�sympy.matrices.densergr2r$r#r�r�r-r�rbr�)rLrg�rows�columns�mat_listrSr�s       r1�
get_matrixzTensExpr.get_matrix1s5��	0���
�4�
5�	E��4�9�9�!��!�*�C�E�E��y�y���q�)��04�	�	�Q��$�)�)�/�/�!�,�A���9�9��>�!�D�y�H�"�4�[�;�� ����+�!&�w��;�A�$�Q�K�.�.�t�A�q�D�z�:�;�;�
!%�v��}�H�"�4�[�.��&*�1�g����.��h�'�	E�	E� *�C�E�E�!	E�	E�s�C*D�D�D(c�J�|D�cgc]}|j|���c}Scc}wrV�re)�indices1�indices2rSs   r1�_get_indices_permutationz!TensExpr._get_indices_permutationMs��+3�4�a����q�!�4�4��4s� c�6�t|fi|��j�SrV)�_expandr )rL�hintss  r1�expandzTensExpr.expandQs���t�%�u�%�*�*�,�,r0c��|SrVr/�rLr�s  r1rszTensExpr._expandT����r0c��t�}|jD]2}t|t�s�|j	|j���4|SrV)rr�r�r��update�_get_free_indices_set�rL�indsetr	s   r1r{zTensExpr._get_free_indices_setWsB������9�9�	;�C��#�x�(��
�
�c�7�7�9�:�	;��
r0c��t�}|jD]2}t|t�s�|j	|j���4|SrV)rr�r�r�rz�_get_dummy_indices_setr|s   r1rzTensExpr._get_dummy_indices_set^sB������9�9�	<�C��#�x�(��
�
�c�8�8�:�;�	<��
r0c��t�}|jD]2}t|t�s�|j	|j���4|SrV)rr�r�r�rz�_get_indices_setr|s   r1r�zTensExpr._get_indices_setesB������9�9�	6�C��#�x�(��
�
�c�2�2�4�5�	6��
r0c�D���|j����fd���|d�S)Nc3���K�t|t�r|�vr||f��yyt|ttf�r3t	|j
�D]\}}�|||fz�Ed{����yy7��wrV�r�rorr�r^r�)�exprri�pr	�	dummy_set�recursors    ��r1r�z1TensExpr._iterate_dummy_indices.<locals>.recursorpsq������$��,��9�$���+�%�%��D�5�(�"3�4�'��	�	�2�7�F�A�s�'��S�!��X�6�6�6�7�5�6���AA,�!A*�"	A,r/)r)rLr�r�s @@r1�_iterate_dummy_indiceszTensExpr._iterate_dummy_indicesls%����/�/�1�	�	7���b�!�!r0c�D���|j����fd���|d�S)Nc3���K�t|t�r|�vr||f��yyt|ttf�r3t	|j
�D]\}}�|||fz�Ed{����yy7��wrVr�)r�rir�r	�free_setr�s    ��r1r�z0TensExpr._iterate_free_indices.<locals>.recursor~sq������$��,��8�#���+�%�$��D�5�(�"3�4�'��	�	�2�7�F�A�s�'��S�!��X�6�6�6�7�5�6�r�r/)r{)rLr�r�s @@r1�_iterate_free_indiceszTensExpr._iterate_free_indiceszs%����-�-�/��	7���b�!�!r0c� ���fd���|d�S)Nc3���K�t|t�r||f��yt|ttf�r3t	|j
�D]\}}�|||fz�Ed{����yy7��wrVr�)r�rir�r	r�s    �r1r�z+TensExpr._iterate_indices.<locals>.recursor�sd������$��,��S�k�!��D�5�(�"3�4�'��	�	�2�7�F�A�s�'��S�!��X�6�6�6�7�5�6�s�AA'�A%�	A'r/r/)rLr�s @r1�_iterate_indiceszTensExpr._iterate_indices�s���	7���b�!�!r0c��ddlm}m}m}||||�dd|zf�}t	t|��}|||dc|d<||<|||�S)Nr])rrr�r=r)r�rrr�r�r�)r�r�rir.rrr��permus        r1�!_contract_and_permute_with_metricz*TensExpr._contract_and_permute_with_metric�s]��	I�H�!�-���">��A�c�E�
�K���U�3�Z� ��$�S�z�5��8���a��%��*��5�%�(�(r0c	�j�ddlm}|D�cgc]}|j��}}g}g}|dd}	t|�D]�\}
}||	vr|	j	|�}d|	|<�!||	vrL|	j	|�}d|	|<|||<|j
r|j
|��`|j
|��r|	|
}
|
�td|�d|����d|	|
<|||
<|j
|
j
zs��|j
r|j
|
���|j
|
���tt|�t|�z�t|�krtd|�d|����|D]Q}||}||vrtd��||}tj|�}tj|||t|��}�S|D]<}||}||vrtd��||}tj|||t|��}�>|rtj||�}|||�}t|d�r|j!�dk(r|d}||fScc}w)	Nr]r�zincompatible indices: z and z!No metric provided to lower indexr�rr/)r�r�rQr^rer`rbrarIrr�rIr�r�rqr_r�)r��	free_ind1�	free_ind2�replacement_dictr�rS�index_types1�pos2up�pos2down�free2remainingrr�index1rs�index2ri�index_type_posr��metric_inverser�s                   r1� _match_indices_with_other_tensorz)TensExpr._match_indices_with_other_tensor�sh��&�5>�?���+�+�?��?�����"�1���%�i�0�	.�L�D�&���'�%�+�+�F�3��'+��t�$���w�.�(�%�+�+�V�G�4��'+��t�$�"(�	�$���<�<��M�M�$�'��O�O�D�)�'��-���>�$�)�U^�%_�`�`�'+��t�$�"(�	�$���<�<�&�,�,�.��|�|��
�
�d�+� ����-�/	.�2�s�9�~��I��.�/�#�i�.�@��)�Y�W�X�X��	k�C�)�#�.�N��%5�5� �!D�E�E�%�n�5�F�5�D�D�V�L�N��>�>�~�u�VY�[^�_h�[i�j�E�
	k��	c�C�)�#�.�N��%5�5� �!D�E�E�%�n�5�F��>�>�v�u�c�SV�W`�Sa�b�E�	c��"�;�;�I�y�Q�K���{�3�E��5�&�!�e�j�j�l�a�&7��"�I�E��%����s@s�H0Nc	��ddlm}|xsg}|j�D�cic].}|jr|jdn|jd|��0}}t|�D]3\}}t
|ttf�s�||vr	||||<�*||||<�5|j�D��	cic]\}}	|||	���}}}	|j�D]�\}}	t
|t�r#td�D�cgc]}|j��}
}n#|jD�cgc]}|j��}
}t|
�|	j�k7s't!d�t#|
|	j$�D��r��t'd|�d|
�d|	j$����|j)|�\}}	|j+|	|||�\}
}	|	Scc}wcc}	}wcc}wcc}w)	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]��Arrayrr=c3�HK�|]\}}|jr||k(nd���y�w)TN)r/)r�r�r�s   r1r�z/TensExpr.replace_with_arrays.<locals>.<genexpr>1	s1����?�-7�T�4����@D�t�|�$(�@)�?�s� "zshapes for tensor z expected to be z, replacement array shape is )r�r�r�r`r�r^r�rr�itemsr"r�r.rGrIr�r�r�r-ra�
_extract_datar�)rLr�rHr��k�remaprSrerr��expected_shape�
index_type�ret_indices�last_indicess              r1�replace_with_arrayszTensExpr.replace_with_arrays�s���D	!��-�R��BF�BW�BW�BY�Z�Q�a�g�g������A�F�F�1�I�:�q�8�Z��Z�!�'�*�	0�H�A�u��%�&�#��/��E�>�!&�u��G�A�J�"'���-��G�A�J�	0�GW�F\�F\�F^�_�]�V�U�F�E�%�L�0�_��_�.�3�3�5�
	"�M�F�E��&�/�2�6;�A�h�!?��&�*�*�!?��!?�CI�CU�CU�!V�Z�*�.�.�!V��!V��>�"�e�j�j�l�2�3�?�;>�~����<�?�<�!�7=�~��K�K�"!�"�"�
	"�"�/�/�0@�A���U�"�C�C�E�7�T_�aq�r���e����5[��`��
"@��!Vs�3F9�(F>�1G�G	c���ddlm}|j�}|j}|D��cgc]'\}}||d||jj
dz
f��)}}}|r	||g|���}|Scc}}w)Nr��Sumr])�sympy.concrete.summationsr�rlrFrQr.)	rLr��
index_symbolsr�rHrFrSr��sum_indicess	         r1�_check_add_SumzTensExpr._check_add_Sum=	s���1��"�"�$���h�h��<?�A�48�A�q�'�q�)�1��A�J�(�(�,�,�Q�.�0�A��A���t�*�k�*�D����	As�,A$c	��|j|jD�cgc]$}t|t�r|j	�n|��&c}�Scc}wrV)�funcr�r�r��_expand_partial_derivative)rLr�s  r1r�z#TensExpr._expand_partial_derivativeG	sW���t�y�y�"�Y�Y�(��"�!�X�.��0�0�2�45�6�(�)�	)��(s�)Ar��r`zdict[TensorIndex, TensorIndex]r�r�rV)*r�r�r�r��_op_priorityrr�r<r@rBrErGrJrLrPrRr'rUr}rrXrrlr�rarerlr�rqrursr{rr�r�r�r�r�r�r�r�r�r/r0r1r�r��sq���.�L��N�"�"�+�+�,�,�+�2+�1�6�.�&"���5���5���5���5��5��5��5��5��5��5�6�E�8�5��5�-������"��"��"��"��"��"��)��)��< ��< �|_�B�)r0r�c�X�eZdZdZd�Zed��Zed��Zd d�Zd!d�Z	e
d��Ze
d��Ze
d	��Z
d
�Zed��Zed��Zed
��Zd�Zd�Zd�Zd�Zd�Zd�Zd�Zd�Zd�Zd�Zd�Zed��Zej>d��Zej@d��Zd�Z!d�Z"d�Z#y)"r�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��|D�cgc]}|s�t|���}}tj|�}|jt��|st
jSt|�dk(r|dStj|g|��i|��Scc}w)NrCr]r)
rr��_tensAdd_flattenrKrr�ZerorIrr�)r�r�r�rAs    r1r�zTensAdd.__new__z	sx��%)�/��Q����/��/��'�'��-���	�	�&�	�'���6�6�M��t�9��>���7�N��}�}�S�3�4�3�7�3�3��0s
�B�
Bc�"�tjSrV�rrOrks r1rz
TensAdd.coeff�	����u�u�r0c��|SrVr/rks r1rXzTensAdd.nocoeff�	����r0c��|jSrV)�free_indicesrks r1r�zTensAdd.get_free_indices�	s��� � � r0c��|jD�cgc]%}t|t�r|j|�n|��'}}|j|�Scc}wrV)r�r�r�rar�)rLr`r	�newargss    r1razTensAdd._replace_indices�	sM��_c�_h�_h�i�X[��C��1J�3�'�'��-�PS�S�i��i��t�y�y�'�"�"��js�*A
c�p�t|jdt�r|jdjSyr?)r�r�r�r�rks r1r�zTensAdd.rank�	s+���d�i�i��l�H�-��9�9�Q�<�$�$�$�r0c�r�t|jdt�r|jdjSgSr?)r�r�r�rrks r1rzTensAdd.free_args�	s-���d�i�i��l�H�-��9�9�Q�<�)�)�)��Ir0c��t|jdt�r|jdj�St	�Sr?)r�r�r�r�rrks r1r�zTensAdd.free_indices�	s2���d�i�i��l�H�-��9�9�Q�<�0�0�2�2��5�Lr0c�<�|jdd�}|r*|jD�cgc]}|jdi|����}}n|j}|D�cgc]}|tjk7s�|��}}t|�dk(rtjSt|�dk(r|dStj|�tj|�}d�}|j|��|stjSt|�dk(r|dS|j|�}|Scc}wcc}w)N�deepTrr]c���t|t�sgggfSt|d�r:t|d�r.t|�}|j|j
|jfSgggfS)N�_index_structurerY)r�r�r_�get_index_structurerYrErF)r�rAs  r1�sort_keyzTensAdd.doit.<locals>.sort_key�	s[���a��*��2�r�z�!��q�,�-�'�!�\�2J�'��*���|�|�Q�V�V�Q�U�U�2�2��r�2�:�r0rCr/)rzr�r rr�rIr��_tensAdd_check�_tensAdd_collect_termsrKr�)rLrtr�r	r�r�r�s       r1r zTensAdd.doit�	s���y�y���&���15���;�#�H�C�H�H�%�u�%�;�D�;��9�9�D� $�5��s�a�f�f�}��5��5��t�9��>��6�6�M�
��Y�!�^���7�N�	���t�$��-�-�d�3��	�	
�	�	�h�	����6�6�M��t�9��>���7�N��d�i�i�����
��G<��
6s�D�D�(Dc���g}|D]N}t|ttf�r%|jt	|j
���>|j
|��P|D�cgc]}|js�|��}}|Scc}wrV)r�rr�rWr�r�rbr)r�r�rAs   r1r�zTensAdd._tensAdd_flatten�	sj��
���	�A��!�c�7�^�,�����a�f�f��&������		�
�(�a�����(��(����)s�A4�,A4c���dd�}||d��|ddD�cgc]
}||���}}t�fd�|D��std��ycc}w)Nc�h�t|t�rt|j��St�SrV)r�r�rr�r@s r1�get_indices_setz/TensAdd._tensAdd_check.<locals>.get_indices_set�	s'���!�X�&��1�-�-�/�0�0��5�Lr0rr]c3�(�K�|]	}|�k(���y�wrVr/)r�rA�indices0s  �r1r�z)TensAdd._tensAdd_check.<locals>.<genexpr>�	s�����7�Q�1��=�7�s�z&all tensors must have the same indices)rArr�zset[TensorIndex])r�ra)r�r�r	�list_indicesr�s    @r1r�zTensAdd._tensAdd_check�	s[���	�
#�4��7�+��8<�Q�R��A����,�A��A��7�,�7�7��E�F�F�8��Bs�A	c	���tt�}tj}t	|dt
�rt
|dj��}n
t
�}|D]}t	|t
�s|t
�k7rtd��||z
}�1|t
|j��k7rtd��||jj|j���|j�D��cgc]1\}}t|�dk7s�tt|�|�j���3}}}t	|t�rt|j �|z}|S|dk7r|g|z}|Scc}}w)Nrz
wrong valence)r	r�rr�r�r�rr�rarXrbrr�rr�r r�)r��
terms_dict�scalarsr�r	r�r�new_argss        r1r�zTensAdd._tensAdd_collect_terms�	sF��!��&�
��&�&���d�1�g�x�(��t�A�w�7�7�9�:�L��5�L��
	6�C��c�8�,��3�5�(�$�_�5�5��3�����s�3�#7�#7�#9�:�:� ��1�1�
�s�{�{�#�*�*�3�9�9�5�
	6�DN�CS�CS�CU�j�x�q�%�Y\�^c�Yd�hi�Yi�G�C��K��+�0�0�2�j��j��g�s�#��G�L�L�)�H�4�H�����\��y�8�+�H����ks�1E!�"E!c��g}|jD]/}|jt|�D�cgc]	}||vs�|��c}��1|Scc}wrV)r�rWrl)rLrHr	rSs    r1rlzTensAdd.get_indices
sJ�����9�9�	N�C��N�N�{�3�'7�L�!�1�G�;K�A�L�M�	N����Ms
�	A
�A
c
�`�t|jD�cgc]}t|fi|����c}�Scc}wrV)r�r�rs)rLrtrSs   r1rszTensAdd._expand
s)���d�i�i�@����,�e�,�@�A�A��@s�+c���t�|j}t|�}|D�cgc]}|j��c}|D�cgc]}|j��c}k7rt	d��||k(r|Stt||��}|jD�cgc](}|j|j|�j���*}}t|�j�}|Scc}wcc}wcc}w�Nzincompatible types)r9rr�rQrar�r�r�rcr�r )rLrHrrArdr��ress       r1r^zTensAdd.__call__
s������N�N�	��w�-��)0�1�A�A���1�S\�5]�a�a�6I�6I�5]�]��1�2�2��i���K��C�	�7�3�4��HL�	�	�R�1�V�Q�V�V�)�Q�)�)�<�8�=�=�
>�R��R��q�k��� ���
��2��5]��

Ss�C�C�-Cc��|j�}|jD�cgc]
}t|���}}t|�j	�}|Scc}w)zz
        Canonicalize using the Butler-Portugal algorithm for canonicalization
        under monoterm symmetries.
        )rur�rMr�r )rLr�rAr�r�s     r1rMzTensAdd.canon_bp
sF��
�{�{�}��%)�Y�Y�/�����/��/��t�n�!�!�#���
��0s�Ac��t|�}t|t�r+|jdk(rt	d�|j
D��St|t�r|j|jk7ryt|t�r-t|j
�t|j
�k7ryy||z
}t|t�s|dk(St|t�r|jdk(St	d�|j
D��S)Nrc3�:K�|]}|jdk(���y�w�rN�rr�s  r1r�z!TensAdd.equals.<locals>.<genexpr>+
s����7��q�w�w�!�|�7���FTc3�:K�|]}|jdk(���y�wr�r�r�s  r1r�z!TensAdd.equals.<locals>.<genexpr>;
s����8�A�1�7�7�a�<�8�r�)
rr�r�rr�r�r�r�r�r)rLr�r�s   r1�equalszTensAdd.equals(
s��������e�W�%�%�+�+��*:��7�T�Y�Y�7�7�7��e�X�&��y�y�E�J�J�&���e�W�%��4�9�9�~��U�Z�Z��0����5�L���!�X�&���6�M��!�W�%��w�w�!�|�#��8����8�8�8r0c�~�t�tt�5|j|cddd�S#1swYyxYwrV�r2r$r#r��rL�items  r1r�zTensAdd.__getitem__=
�1����
�4�
5�	#��9�9�T�?�	#�	#�	#���3�<c��|jD�cgc]}|j|���}}t|�j�}t	|�Scc}wrV)r��contract_deltar�r rM)rLr�rAr�r�s     r1r�zTensAdd.contract_deltaB
sE��15���;�A�� � ��'�;��;��T�N���!����{���<s�A
c��|jD�cgc]}t||���}}t|�j�}t	|�Scc}w)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
        )r��contract_metricr�r rM)rLr�rAr�r�s     r1r�zTensAdd.contract_metricG
sC��"04�y�y�9�!���1�%�9��9��T�N���!����{���:s�Ac��g}|jD]2}t|t�r|j|�}|j	|��4t|�j
�SrV)r�r�r�rcrbr�r �rLrdr�r	s    r1rczTensAdd.substitute_indices\
�X�����9�9�	!�C��#�x�(�,�c�,�,�l�;���O�O�C� �	!���!�&�&�(�(r0c��g}|j}|D]}|jt|���dj|�}|j	dd�}|S)Nz + z+ -z- )r�rbr{rr)rLr�r�rAr�s     r1r�zTensAdd._printd
sQ�����y�y���	�A�
�H�H�S��V��	��J�J�q�M��
�I�I�e�T�"���r0c	��ddlm}m}t|jD�cgc]'}t|t�r|j|�ng|f��)c}�\}}|D�cgc]
}||���}}|d}tdt|��D].}||}	||}
tj|	|�}||
|�||<�0|t||j
j��fScc}wcc}w)Nr)r�r�r])�sympy.tensor.arrayr�r�r�r�r�r�r�r�rIr�rq�sumr�r-)rLr�r�r�r	�args_indicesrrS�ref_indicesrHr�r�s            r1r�zTensAdd._extract_datam
s���9�"�@D�	�	�%
�9<�J�s�H�%�
���.�/�,.��9�
5�%
� ���f�%+�+�q�%��(�+��+�"�1�o���q�#�l�+�,�	8�A�"�1�o�G��1�I�E�!�:�:�7�K�P�K�#�E�;�7�F�1�I�		8�
�C������U�[�[�(A�B�B�B��%
��,s�,C�Cc��t�tt�5t|j	�cddd�S#1swYyxYwrV�r2r$r#r�rurks r1r�zTensAdd.data|
s8����
�4�
5�	A�1�$�+�+�-�@�	A�	A�	A�s	�;�Ac�r�t�tt�5|t|<ddd�y#1swYyxYwrVr�r*s  r1r�zTensAdd.data�
r+r,c�~�t�tt�5|tvrt|=ddd�y#1swYyxYwrVr�rks r1r�zTensAdd.data�
s7����
�4�
5�	9��5�5�2�4�8�	9�	9�	9�s�3�<c��t�|jstd��|jj�j	�S�Nz No iteration on abstract tensors)r2r�ra�flattenr0rks r1r0zTensAdd.__iter__�
s7�����y�y��?�@�@��y�y� � �"�+�+�-�-r0c�,�tj|�SrV)r�fromiter)rLr�s  r1�_eval_rewrite_as_Indexedz TensAdd._eval_rewrite_as_Indexed�
s���|�|�D�!�!r0c��g}|jD]`}t|t�r!|j|j	|���4|j
s�A|j|j
|���b|j|�SrV)r�r�r�rb�_eval_partial_derivative�	_diff_wrt�_eval_derivativer�)rLr��list_addendsr�s    r1r	z TensAdd._eval_partial_derivative�
sp�������	;�A��!�X�&��#�#�A�$>�$>�q�$A�B�����#�#�A�$6�$6�q�$9�:�	;��t�y�y�,�'�'r0Nr�r�)$r�r�r�r�r�r}rrXr�rar%r�rr�r r�r�r�r�rlrsr^rMr�r�r�r�rcr�r�r�r�r�r0rr	r/r0r1r�r�P	sM��'�R	4���������!�#�������������&�P�	��	��G��G�����8�B���9�*#�
�
�*)��
C��A��A�

�[�[�8��8�

�\�\�9��9�.�"�
(r0r�c�J�eZdZUdZdZdZded<dd�d�Zed��Z	ed	��Z
ed
��Zed��Zed��Z
ed
��Zed��Zed��Zed��Zed��Zed��Zed��Zed��Zd�Zed��Zd7d�Zdd�d�Zd�Zd�Zd�Zed��Zed��Zed��Z d�Z!d7d �Z"d!�Z#d"�Z$d#�Z%d$�Z&d8d%�Z'd8d&�Z(d9d'�Z)d(�Z*d)�Z+d*�Z,d+�Z-d,�Z.d-�Z/ed.��Z0e0jbd/��Z0e0jdd0��Z0d1�Z3d2�Z4d3�Z5d4�Z6d5�Z7d6�Z8y):r�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)

    FNztuple[TensorHead, Tuple]r��r�c�6�|j||�}tj||t|�fi|��}t	j
|�|_|jjdd|_|jjdd|_
|jj|_tj|_||_||_|g|_|j$t'|�k7rt)d��||_t,j/||j�|_|S)N�wrong number of indices)�_parse_indicesrr�rr;rTr�rE�_freerF�_dumrJrrO�_coeff�_nocoeff�
_component�_componentsr�rIrar�r��_build_index_map�
_index_map)r��tensor_headrHr�r�r�s      r1r�zTensor.__new__�
s����$�$�[�'�:���m�m�C��e�W�o�I��I��.�;�;�W�E����(�(�-�-�a�0��	��'�'�+�+�A�.����,�,�6�6��
��U�U��
����$���&�-������s�7�|�+��6�7�7�%����0�0��#�:N�:N�O����
r0c��|jSrV�rrks r1rEzTensor.free�
rmr0c��|jSrV�rrks r1rFz
Tensor.dum�
s���y�y�r0c��|jSrV�rJrks r1r�zTensor.ext_rank�
s���~�~�r0c��|jSrV�rrks r1rzTensor.coeff�
s���{�{�r0c��|jSrV)rrks r1rXzTensor.nocoeff�
s���}�}�r0c��|jSrV)rrks r1rZzTensor.component�
s�����r0c��|jSrV)rrks r1rYzTensor.components�
s�����r0c� �|jdSr?r�rks r1�headzTensor.head�
r�r0c� �|jdSr�r�rks r1rHzTensor.indices�
r�r0c�H�t|jj��SrV)rr�r�rks r1r�zTensor.free_indicess���4�(�(�9�9�;�<�<r0c�.�|jjSrV)r'rGrks r1rGzTensor.index_typess���y�y�$�$�$r0c�,�t|j�SrV)rIr�rks r1r�zTensor.ranks���4�$�$�%�%r0c�B�i}|D]}|j|�f||<�|SrVrn)rH�index_structure�	index_maprps    r1rzTensor._build_index_maps1���	��	3�C�%�m�m�C�0�2�I�c�N�	3��r0c�B�tj|g�\}}}}|dSr?)r��_tensMul_contract_indices)rLrtr�rHrErFs      r1r zTensor.doits&��#*�#D�#D�d�V�#L� ��g�t�S��A�w�r0c	��t|tttf�st	dt|�z��t|�}t
|�D]�\}}t|t�rt||j|d�||<�4t|t�rT|j�\}}|dk(r.t|t�rt||j|d�||<��td|z��t|t�r��t	d|�dt|�����|S)Nz"indices should be an array, got %sTr�Fzindex not understood: %szwrong type for index: z is )
r�r�r�rr��typer^rrorGr�as_coeff_Mulra)rrHrSrers�es      r1rzTensor._parse_indicess����'�E�4��#7�8��@�4��=�P�Q�Q��w�-��!�'�*�
	Y�H�A�u��%��(�(���0G�0G��0J�D�Q���
��E�3�'��)�)�+���1���7�z�!�V�4�!,�Q��0G�0G��0J�E�!R�G�A�J�$�%?�%�%G�H�H���{�3��E�4�PU�;� W�X�X�
	Y��r0c�F�|j�}|j|d|i�S�Nr��rl�_set_indices�rL�imr�rHs    r1�_set_new_index_structurezTensor._set_new_index_structure,�&���.�.�"�� �t� � �'�C�{�C�Cr0c��t|�|jk7rtd��|j|jd||��j�S)N�indices length mismatchrr)rIr�rar�r�r )rLr�rHr�s    r1r8zTensor._set_indices0sD���w�<�4�=�=�(��6�7�7��y�y����1��w�K�y�H�M�M�O�Or0c�Z�|jjD�chc]}|d��	c}Scc}wr?)r�rErks  r1r{zTensor._get_free_indices_set5s&��"�3�3�8�8�9���!��9�9��9s�(c���ttj|jj��}t|jd�D��chc]\}}||vs�|��c}}Scc}}wr�)r�	itertools�chainr�rFr^r��rL�	dummy_posrSrps    r1rzTensor._get_dummy_indices_set8sL���	����)>�)>�)B�)B�C�D�	�"+�D�I�I�a�L�"9�L���3�Q�)�^��L�L��Ls�A �A c�F�t|jdj�Sr�)rr�rks r1r�zTensor._get_indices_set<s���4�9�9�Q�<�$�$�%�%r0c�R�|jD��cgc]
\}}||df��c}}Scc}}wr?�rE)rLr�ris   r1�free_in_argszTensor.free_in_args?s$��.2�i�i�8�(�#�s��c�1�
�8�8��8s�#c�T�|jD��cgc]\}}||ddf��
c}}Scc}}wr?)rF)rL�p1�p2s   r1�dum_in_argszTensor.dum_in_argsCs&��-1�X�X�6�6�2�r��R��A��6�6��6s�$c�X�t|jD�cgc]}|d��	c}�Scc}wr?r�rs  r1rzTensor.free_argsG�#���T�Y�Y�/��q��t�/�0�0��/��'c��t|t�syt|t�r%|jj	|j�St
S)z�
        :param other:
        :return:
            0  commute
            1  anticommute
            None  neither commute nor anticommute
        r)r�r�r�rZrr�r�s  r1rzTensor.commutes_withKs:���%��*��
��v�
&��>�>�/�/����@�@�"�"r0c��t|||�S)z�
        Returns the tensor corresponding to the permutation ``g``.

        For further details, see the method in ``TIDS`` with the same name.
        �r��rLr�r�s   r1r�zTensor.perm2tensorYs���4��K�0�0r0c��|jr|S|j�}|jj�\}}}t	|j
g�}t
|||g|���}|dk(rtjS|j|d�}|S)NrT)
r�rur�r�r�rZrrr�r�)rLr�r�r�r�r��canrs        r1rMzTensor.canon_bpas�������K��{�{�}���0�0�C�C�E���7�D�!�4�>�>�"2�3���1�g�t�0�a�0���!�8��6�6�M��!�!�#�t�,���
r0c��|gSrVr/rks r1r�zTensor.splitms	���v�
r0c��|SrVr/rws  r1rszTensor._expandprxr0c��|SrVr/rks r1�sorted_componentszTensor.sorted_componentssrxr0c�2�t|jd�S)zN
        Get a list of indices, corresponding to those of the tensor.
        r]rrks r1rlzTensor.get_indicesvs���D�I�I�a�L�!�!r0c�6�|jj�S)zS
        Get a list of free indices, corresponding to those of the tensor.
        �r�r�rks r1r�zTensor.get_free_indices|s���$�$�5�5�7�7r0c�$�|j|�SrV��xreplacer_s  r1razTensor._replace_indices�s���}�}�T�"�"r0c�&�|tjfSrVr�rks r1�as_base_expzTensor.as_base_exp�s���Q�U�U�{�r0c�`�g}|jD]�}|D]w\}}|j|jk(s� |j|jk(s�:|j|jk(r|j	|�n|j	|��~|j	|���|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)
        )rHr_rQr`rbr')rLrdrHre�ind_old�ind_news      r1rczTensor.substitute_indices�s���$���\�\�
	&�E�$0�	
&� ����J�J�'�,�,�.�5�3J�3J�3:�3L�3L�4M��{�{�g�m�m�3����w�/�����x�0��	
&����u�%�
	&��t�y�y�'�"�"r0c���t�|j}t|�}|D�cgc]}|j��c}|D�cgc]}|j��c}k7rt	d��||k(r|S|j
tt
||���}t|D�chc]}|jr|n|��c}�t|�k7r|j|j�S|Scc}wcc}wcc}wr��r9rr�rQrarcr�rIr`r�r��rLrHrrAr�rSs      r1r^zTensor.__call__��������N�N�	��w�-��)0�1�A�A���1�S\�5]�a�a�6I�6I�5]�]��1�2�2��i���K�#�D�#�#�T�#�i��*A�%B�C���g�6��Q�W�W��1�"�$�6�7�3�w�<�G��1�6�6�1�6�6�?�"����2��5]��7��C�C�C$c��t�tt�5|jj	�cddd�S#1swYyxYwrVr/rks r1r0zTensor.__iter__�r1r2c�~�t�tt�5|j|cddd�S#1swYyxYwrVr�r�s  r1r�zTensor.__getitem__�r�r�c
�T�ddlm}|j�D];\}}t|t�s�|j
d|j
dk(s�7|}|}nt
|�d|����|j�D��cic]\}}|||���}}}||�}|j}|j}t|�dkDr-|D]}	|	|vs�td|z��|D�	cgc]	}	|	|vs�|	��}}	t|�dkDr�|j�}
|j�}i}|D]�\}
}||
|||<|
|fD]u}|
|j||jzs�#||
|j}|
|jrtj|�}|j|||t|��}�w��|j!|�j#�}tj%|g|t|��}|j'�}|j'�}|j)||||�Scc}}wcc}	w)Nr]r�rz not found in z'%s with contractions is not implemented)r�r�r�r�r�r�rarFrIr�rlr`rQr�rIr�r_r r�r�r�)rLr�r�r�r�r�r��dum1�dum2�pairrorpr`rJrKrir�r�r�s                   r1r�zTensor._extract_data�sE�� �$�*�*�,�	N�D�A�q��!�V�$������d�i�i��l�)B������		N��T�;K�L�M�M�5E�4J�4J�4L�M�D�A�q�A�u�Q�x�K�M��M��e����x�x���y�y���t�9�q�=��
a���t�#�-�.W�Z_�._�`�`�
a�
&*�>�T�T��-=�D�>�D�>��t�9�q�=��'�'�)�H��(�(�*�H��D��
j���B�&.�r�l�]��X�b�\�"���8�j�C���}�*�*�X�c�]�-@�-@�@�!1�(�3�-�2Q�2Q�!R��#�C�=�.�.�%=�%L�%L�V�%T�F� $� F� F�v�u�VY�[^�_g�[h� i��j�
j��N�N�4�(�-�-�/�E�,�>�>��w��c�RZ�m�\�E��)�)�+�	��*�*�,�	��4�4�U�I�y�Rb�c�c��?N��?s�8H�	H%�#H%c�r�t�tt�5t|cddd�S#1swYyxYwrVr�rks r1r�zTensor.data�r�r�c�r�t�tt�5|t|<ddd�y#1swYyxYwrVr�r*s  r1r�zTensor.data�s1����
�4�
5�	8�37�*�4�0�	8�	8�	8�r,c���t�tt�5|tvrt|=|jtvrt|j=ddd�y#1swYyxYwrVr�rks r1r�zTensor.data�r�r�c���|jD�cgc]
}t|���}}|j}|jdkDr!|j�ddj|��d�Sd|jzScc}w)Nrrz, rz%s)rHr{rZr�r_r)rLr�rHrZs    r1r�z
Tensor._prints^��'+�|�|�4��3�s�8�4��4��N�N�	��>�>�A�� )����	�	�'�0B�C�D��9�>�>�)�*��5s�A.c���|dk(r|jdk(St|�}t|t�s!|jrJ�t
j|k(Sd�}||�||�k(S)Nrc���|j�}|jt|j�tt	|j
��tt	|j��f}|SrV)rMrr�rYr�rErF)rLr�rs   r1�_get_compar_compz'Tensor.equals.<locals>._get_compar_compsK���
�
��A����%����-��&����.�)�5������+?�A�A��Hr0)rrr�r�rYrrO)rLr�rvs   r1r�z
Tensor.equalssb���A�:��:�:��?�"������%��*����&�&��5�5�E�>�!�	� ��%�)9�%�)@�@�@r0c��|j|k7r|St|j�dk7r|S|jtjd�k(rd}nP|jtjd�k(rd}n+|jtj
d�k(rd}nt�tj}|jd}|s||jz}|S||jz}|jd\}}||kr|}|S)Nrr�r]r=)
rZrIrEr�r�r�r�r�rrOrGr.rF)rLr��antisym�signrf�dp0�dp1s       r1r�zTensor.contract_metric s����>�>�Q���K��t�y�y�>�Q���K�
�:�:��7�7��;�;��G�
�Z�Z�>�9�9�!�<�
<��G�
�Z�Z�>�5�5�a�8�
8��G�%�%��u�u���m�m�A��������<�D�������<�D��x�x��{�H�C���S�y��u���r0c�$�|j|�SrV�r�)rLr�s  r1r�zTensor.contract_deltaBs���#�#�F�+�+r0c��ddlm}|j�D�cgc]}|jd��}}||jdg|���}|j	||�Scc}w)Nr)�Indexed)�sympy.tensor.indexedrrlr�r�)rLr$rHrrSr�r�s       r1rzTensor._eval_rewrite_as_IndexedEsY��0�,0�,<�,<�,>�?�q������?�
�?��t�y�y��|�4�m�4���"�"�4��7�7��@s�Ac���t|t�stjS|j|jk7rtjSdg}tt
|j�|j���D]�\}\}}|j|jk7rtd��|j}|j}tdt|�z||j��}|j|jk(r|j||�}	n%t|||�|j||��}	|j!|	���tj#|�j%�S)Nr]zindex types not compatible�d_r)r�r�rr�r'r^r�r�rQrar�ror{r`r�r�rbrr )
rLr��kronecker_delta_list�count�iself�iotherrQ�
tensor_metric�dummy�kroneckerdeltas
          r1r	zTensor._eval_partial_derivativeLsI���!�V�$��6�6�M��y�y�A�F�F�"��v�v�
�%&�3� �-6�c�$�:O�:O�:Q�ST�Se�Se�Sg�6h�,i�
@�(������*�*�f�.F�.F�F�$�%A�B�B�(-�(?�(?�%�$5�$<�$<�M�'��s�5�z�(9�;L�.3�k�k�;�E��{�{�f�l�l�2�):�)@�)@����)P��$�M�%��$?�$5�$;�$;�U�F�V�G�$L�N�'�)�/�/��?�
@� �#�#�$8�9�>�>�@�@r0r�r�r�)9r�r�r�r�rr�r`r�r}rErFr�rrXrZrYr'rHr�rGr�r�rr rr;r8r{rr�rHrLrrr�rMr�rsrYrlr�rararcr^r0r�r�r�r�r�r�r�r�r�rr	r/r0r1r�r��
sR��!�F�N���
"�"�:?��"������������������������� �� ����������=��=��%��%��&��&����������"D�27�P�
:�M�&��9��9��7��7��1��1�#�1�
����"�8�#�
�#�@�"(�#�
*d�X�8��8�

�[�[�8��8�
�\�\�@��@�+�A�  �D,�8�)Ar0r�c��eZdZdZej
ZdZd�Ze	d��Z
e	d��Ze	d��Ze	d��Z
e	d��Ze	d	��Zed
��Zed��Zed;d��Zed
��Zed��Zd�Zed��Zed��Zd�Zd�Zd�Ze	d��Ze	d��Ze	d��Ze	d��Ze	d��Z e	d��Z!d�Z"d�Z#d<d�Z$d=d�Z%d�Z&d �Z'd!�Z(d"�Z)d#�Z*d$�Z+d%�Z,d>d'�Z-d(�Z.d)�Z/d*�Z0d+�Z1d>d,�Z2d&d-�d.�Z3ed/��Z4d0�Z5d1�Z6d2�Z7e	d3��Z8e8jrd4��Z8e8jtd5��Z8d6�Z;ed7��Z<d8�Z=d9�Z>d:�Z?y)?r�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	�`�|jdd�}ttt|��}	|D�cgc]
}t	|���}}tt
j|��}g}|D]�}tt|��}|D�cgc]
}t|���}	}tt
j|	��}	tt	|��}
t|j|��dkDr)|
j||	�}tj||�}n|}|j|���|}|D��
cgc].}t|tt f�r|j"n|gD]}
|
���0}}}
tj%|d��\}}}}|D�
cgc]}
|
j&��}}
t)|||||��}t+j,|g|���}||_|dd|_||_|j4dd|_|j8dd|_|j4D�chc]}|d��	c}|_t|j4�|_t|j2j4�dt|j2j8�zz|_ tBjD|_#||_$|Scc}wcc}wcc}
}wcc}
wcc}w)Nr�Fr)�replace_indices�rMr=)%rzr�rrr�rrArB�get_dummy_indicesrI�intersection�unionr��_dedupe_indicesrbr�rr�r0rQr;r�r��_indices�_index_typesr�rErrFr�
_free_indices�_rankrJrrOr�_is_canon_bp)r�r�r�r�r	rEr��dum_thisr��	dum_other�	free_this�exclude�newargrSrHrFrGr-r�rAs                    r1r�zTensMul.__new__�ss���k�k�-��7���C��$�'�(��	�26�6�#� ��%�6��6��9�?�?�D�)�*�����
	#�C��,�S�1�2�H�7>�?�!�*�1�-�?�I�?��I�O�O�Y�7�8�I��,�S�1�2�I��8�(�(��.�/�!�3�#�/�/�$�	�:�� �0�0��g�>�����N�N�6�"�
	#���"�d�c�
�3��RU��8W�C�H�H�^a�]b�d�a��d��d��d�#*�#D�#D�T�[`�#D�#a� ��g�t�S�5<�<�q�q�*�*�<��<�)�$��[�'�T_�`�����s�*�T�*�����&�q�>���.���#�(�(��+��	�"�&�&�q�)���+.�8�8�4�a�Q�q�T�4�������M��	��C�0�0�5�5�6��3�s�?S�?S�?W�?W�;X�9X�X��
��U�U��
�&����
��K7��
@��e��
=��5s�J�?J�$3J �:J&�J+c��|jSrV)r�rks r1rBzTensMul.<lambda>�s���(9�(9�r0c��|jSrVrrks r1rBzTensMul.<lambda>��
�����r0c��|jSrVrrks r1rBzTensMul.<lambda>�s
���	�	�r0c��|jSrV�r�rks r1rBzTensMul.<lambda>�s���);�);�r0c��|jSrV)r�rks r1rBzTensMul.<lambda>�r�r0c��|jSrVr rks r1rBzTensMul.<lambda>�s
��T�^�^�r0c	���i}i}g}g}d}t|�D]�\}}t|�D]�\}}	t|	t�std��|	|vrp|j	|	�}
|j	|	�}|	j
r|j
|	||
||f�n|j
|	|
|||f�|j
|	�n-|	|vrtd|	z��|||	<|||	<|j
|	�|dz
}����|j�D��
cgc]	\}}
||
f��}}}
|j�D�cgc]}|j��}}|jd���||||fScc}
}wcc}w)Nrzexpected TensorIndexzRepeated index: %sr]c��|dSr�r/r@s r1rBz.TensMul._indices_to_free_dum.<locals>.<lambda>
s
��a��d�r0rC)r^r�ror��popr`rbrar��keysr_rK)r��	free2pos1�	free2pos2�
dummy_datarHrsrr�arg_indices�	index_posre�
other_pos1�
other_pos2rSr�rE�
free_namess                r1�_indices_to_free_dumzTensMul._indices_to_free_dum�s����	��	��
�����!*�<�!8�	��D�+�$-�k�$:�
� �	�5�!�%��5�#�$:�;�;��6�Y�&�!*����v�!6�J�!*����v�!6�J��{�{�"�)�)�5�$�
�D�*�*U�V�"�)�)�E�6�:�t�Z�QU�*V�W��N�N�5�)��i�'�$�%9�E�%A�B�B�'+�I�e�$�'+�I�e�$��N�N�5�)���	��%
�	�,&/�_�_�%6�7�6�A�q��A��7��7�&/�n�n�&6�7��a�f�f�7�
�7����N��+���j�*�4�4��	8��7s�E�)Ec�T�|D�����cgc]\}}}}}||f��c}}}}}Scc}}}}}wrVr/)r�rS�p1a�p1b�p2a�p2bs      r1�_dummy_data_to_dumzTensMul._dummy_data_to_dum	
s(��:D�E�E�6��3��S�#��c�
�E�E��Es�!c�*��|D�cgc]}i��}}|D�cgc]
}t|���}}tj|�\}}}}	tt���fd�}
|r�|	D]M\}}}
}}|j
}	|
|�}||vrn�t
||d�}||||<|||
|<|||<|||<�Ot||�D��cgc](\}}t|t�r|j|�n|��*}}}tj|	�}||||fScc}wcc}wcc}}w)Nc�^��t�|�}�|xxdz
cc<|jdz|zSryrzr}s  �r1r�z9TensMul._tensMul_contract_indices.<locals>.dummy_name_gen
r�r0T)rlr�r�r	r�rQror�r�r�rar�)r�r�rw�replacementsr	r�rHrEr�r�r��	old_index�pos1cov�
pos1contra�pos2cov�
pos2contrar�r|r�r`rFrs                     @r1r0z!TensMul._tensMul_contract_indices

sZ���$(�)�q��)��)�59�9�S��C�(�9��9�07�0L�0L�\�0Z�-���z�:��#���	;�
�GQ�

-�C�	�7�J���&�8�8�
��!/�
�!;�J�!��3���$�J�
�D�A��38��W�%�i�0�8=�v��Z�(�)��4�#(��� �',�f��
�#�

-�"%�T�<�!8�:��C��/9��h�.G��$�$�T�*�S�P�:�D�:��(�(��4���W�d�C�'�'��?*��:��,:s�	D�D
�:-Dc��g}|D]?}t|t�s�t|t�r�%|j|j��A|S)zq
        Get a list of ``Tensor`` objects having the same ``TIDS`` if multiplied
        by one another.
        )r�r�r�rWrY)r�rYr	s   r1�_get_components_from_argsz!TensMul._get_components_from_args0
sL���
��	.�C��c�8�,���#�w�'�����c�n�n�-�	.��r0c���|j�}d}t|�D]C\}}t|t�s�|}||jz
}t|j|||�||<�Eyr?)rlr^r�r�r�r�rZ)r�r-rH�ind_posrSr	�prev_poss       r1�_rebuild_tensors_listzTensMul._rebuild_tensors_list?
si��!�-�-�/������o�	G�F�A�s��c�8�,���H��s�|�|�#�G��S�]�]�G�H�W�,E�F�D��G�	Gr0c
��|j}|jdd�}|rw|jD�cgc]}|jdi|����}}	t	t|j|��}|j
|�}|jD�cgc]}||��	}}n|j}|D�cgc]}||jk7s�|��}}td�|D�cgc]}t|t�r�|��c}tj�}|D�cgc]}t|t�s�|��}}t|�dk(r|S||jk7r|g|z}|dk(rtjSt|�dk(r|dStj!|�\}}	}
}|	D�cgc]}|j"��}
}t%|
||
|	|��}|j&|�}|
|_||_t|j*j,�dt|j*j.�zz|_||_||_|Scc}wcc}wcc}wcc}wcc}wcc}w)	Nr�Tc��||zSrVr/)r��bs  r1rBzTensMul.doit.<locals>.<lambda>a
s
��A�a�C�r0rr]r�r=r/)r�rzr�r �dictr��_dedupe_indices_in_rule�identityrr�r�rrOrIr�r�r0rQr;r�r�r�rErFrJr)rLrtr�r�r	r��ruler�rrHrErFrSrGr-r�s                r1r zTensMul.doitK
s���'�'���y�y���&���15���;�#�H�C�H�H�%�u�%�;�D�;�
���D�I�I�t�,�-�D��/�/��5�D�%)�Y�Y�/��D��G�/�D�/��9�9�D�#�<��s�d�m�m�';��<��<��'��)_�#�Z�PS�U]�E^�#�)_�ab�af�af�g��#�A��z�#�x�'@��A��A��t�9��>��L��D�M�M�!��7�T�>�D��A�:��6�6�M��t�9��>���7�N�#*�#D�#D�T�#J� ��g�t�S�5<�<�q�q�*�*�<��<�)�$��[�'�T_�`���d�i�i����&���.����C�0�0�5�5�6��3�s�?S�?S�?W�?W�;X�9X�X��
���
�&����
��Y<��0��
=��*`��A�� =s5�H"�	H'�(H,�=H,�H1
�$H1
�H6�H6�	H;c�f�t|gtj|||���i|��j�SrV)r��%_get_tensors_from_components_free_dumr )rrYrErFr�s     r1�	from_datazTensMul.from_data
s2���u�o�w�L�L�Z�Y]�_b�c�o�gn�o�t�t�v�vr0c���tj|||�}|j�}|D�cgc]}d��}}d}t|�D](\}}|}	||jz
}t|||	|�||<�*|Scc}w)zv
        Get a list of ``Tensor`` objects by distributing ``free`` and ``dum`` indices on the ``components``.
        Nr)r;r[rlr^r�r�)
rYrErFr-rHrS�tensorsr�rZr�s
          r1r�z-TensMul._get_tensors_from_components_free_dum�
s���
*�B�B�:�t�UX�Y��!�-�-�/��!+�,�A�4�,��,���%�j�1�	F�L�A�y��H��y�~�~�%�G��	�7�8�G�+D�E�G�A�J�	F����-s�	A1c�F�|jD�chc]}|d��	c}Scc}wr?rGrks  r1r{zTensMul._get_free_indices_set�
s��"�i�i�(���!��(�(��(s�c���ttj|j��}t	|j
j
��D��chc]\}}||vs�|��c}}Scc}}wrV)rrArBrFr^r�rlrCs    r1rzTensMul._get_dummy_indices_set�
sN���	������2�3�	�"+�D�,A�,A�,M�,M�,O�"P�c���3�TU�Yb�Tb��c�c��cs�A!�A!c��t|j�D�cgc]}d��}}d}t|j�D]G\}}t	|t
�s�t|j�D]
}||||z<�||jz
}�I|Scc}wr?)r�r�r^r�r�r�)rLrS�
arg_offset�counterr	r�s      r1� _get_position_offset_for_indicesz(TensMul._get_position_offset_for_indices�
s���$)�$�-�-�$8�9�q�d�9�
�9�����	�	�*�	$�F�A�s��c�8�,���3�<�<�(�
2��*1�
�1�w�;�'�
2��s�|�|�#�G�	$����:s�	Bc�X�t|jD�cgc]}|d��	c}�Scc}wr?r�rs  r1rzTensMul.free_args�
rNrOc�8�|j|j�SrV)r�r�rks r1rYzTensMul.components�
s���-�-�d�i�i�8�8r0c��|j�}|j�}|jD��cgc]\}}||||z
||f��c}}Scc}}wrV)r��_get_indices_to_args_posrE)rLr��argposr�ris     r1rHzTensMul.free_in_args�
sN���:�:�<�
��.�.�0��JN�)�)�T�J�S�#��c�*�S�/�)�6�#�;�7�T�T��Ts�Ac��|jSrVr"rks r1rz
TensMul.coeff�
s���{�{�r0c	��|j|jD�cgc]}t|t�s�|��c}�j	�Scc}wrV)r�r�r�r�r )rLr�s  r1rXzTensMul.nocoeff�
s7���t�y�y�d�i�i�K��:�a��3J�1�K�L�Q�Q�S�S��Ks
�A�Ac	��|j�}|j�}|jD��cgc]\}}|||z
|||z
||||f��c}}Scc}}wrV)r�r�rF)rLr�r�rJrKs     r1rLzTensMul.dum_in_args�
sb���:�:�<�
��.�.�0��]a�]e�]e�f�SY�SU�WY��J�r�N�"�B�z�"�~�$5�v�b�z�6�"�:�N�f�f��fs�"Ac���|dk(r|jdk(St|�}t|t�s|jrJ�|j|k(S|j�|j�k(Sr?)rrr�r�rYrMr�s  r1r�zTensMul.equals�
s^���A�:��:�:��?�"������%��*����&�&��:�:��&�&��}�}��%�.�.�"2�2�2r0c��|jS)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�rks r1rlzTensMul.get_indices�
s��6�}�}�r0c�6�|jj�S)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\rks r1r�zTensMul.get_free_indices�
s��2�$�$�5�5�7�7r0c	��|j|jD�cgc]%}t|t�r|j	|�n|��'c}�Scc}wrV)r�r�r�r�ra)rLr`r	s   r1razTensMul._replace_indicessC���t�y�y�gk�gp�gp�q�`c��C��9R�3�/�/��5�X[�[�q�r�r��qs�*A	c��|jdk(r|gSg}d}|jD].}t|t�r|j||z�d}�*||z}�0|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�rb)rL�splitpr�r	s    r1r�z
TensMul.splitsb��0�9�9��?��6�M������9�9�	�C��#�v�&��
�
�c�#�g�&����s�
��	��
r0c�"�|jD�cgc]}t|fi|����}}|D�cgc]'}t|ttf�r|jn|f��)}}t	tj|�D�cgc]
}t|���c}�Scc}wcc}wcc}wrV)r�rsr�rr�rA�productr�)rLrtr	r��args1rSs      r1rszTensMul._expand,s���26���;�#���%�u�%�;��;�TX�Y�S�Z��c�7�^�<����3�&�H�Y��Y��!*�!2�!2�E�!:�<��G�Q�K�<�
�	
��<��Y��<s�B�,B�/Bc�j�ttj||j��j	�S)Nr)r�rr9r�r rks r1r�zTensMul.__neg__5s$���q�}�}�d��8I�8I�J�O�O�Q�Qr0c�~�t�tt�5|j|cddd�S#1swYyxYwrVr�r�s  r1r�zTensMul.__getitem__8r�r�c���t|j�}|jj�r.d}|dtj
k(r	|dd}||fS|d|d<||fSd}||fS)Nrrr]r)r�r�r�could_extract_minus_signrr9)rLr�rys   r1�!_get_args_for_traditional_printerz)TensMul._get_args_for_traditional_printer=sy���D�I�I����:�:�.�.�0��D��A�w�!�-�-�'��A�B�x��
�T�z�� ��7�(��Q���T�z���D��T�z�r0c	��|jD�cgc]}t|t�s�|��}}d}t|�dz
}t	|�D]�}t	||d�D]�}||dz
j||�}|dvr�"t
t||dz
jj�d���}t
t||jj�d���}	|||dz
jjf|	||jjfkDs��||||dz
c||dz
<||<|s��|}����||jz}
|
dk7r|
g|zS|Scc}w)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.
        r]r�r�c��|jSrVr�r@s r1rBz:TensMul._sort_args_for_sorted_components.<locals>.<lambda>^s
��PQ�PV�PV�r0rCc��|jSrVr�r@s r1rBz:TensMul._sort_args_for_sorted_components.<locals>.<lambda>_s
��a�f�f�r0)r�r�r�rIr�rr�rrZrGr_r)rLr	�cvryrcrSr�rsrt�typ2rs           r1� _sort_args_for_sorted_componentsz(TensMul._sort_args_for_sorted_componentsJs[��"�Y�Y�
D�c�*�S�(�*C�c�
D��
D�����G�a�K���q��	%�A��1�a��_�
%���q��s�G�)�)�"�Q�%�0���F�?���c�"�Q�q�S�'�"3�"3�"?�"?�@�FV�W���c�"�Q�%�/�/�"=�"=�>�DT�U���"�Q�q�S�'�+�+�0�0�1�T�2�a�5�?�?�;O�;O�4P�P�%'��U�B�q��s�G�N�B�q��s�G�R��U�� $�u��
%�	%��t�z�z�!���A�:��7�R�<���	��)Es
�E�Ec�J�t|j��j�S)zB
        Returns a tensor product with sorted components.
        )r�r�r rks r1rYzTensMul.sorted_componentsks!����=�=�?�@�E�E�G�Gr0Fc��t|||��S)z�
        Returns the tensor corresponding to the permutation ``g``

        For further details, see the method in ``TIDS`` with the same name.
        rrRrSs   r1r�zTensMul.perm2tensorqs���4���<�<r0c��|jr|S|j�}t|t�r|j	�S|j
s|S|j
�}|jj�\}}}t|j
�}t|||g|���}|dk(rtjS|j|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
        rT)r�rur�r�rMrYrYr�r�r�rrr�r�)	rLr�r�r�r�r�r�rU�tmuls	         r1rMzTensMul.canon_bpys���&����K��{�{�}���d�G�$��=�=�?�"�����K��"�"�$���-�-�@�@�B���7�D�!�!�,�,�/���1�g�t�0�a�0���!�8��6�6�M��}�}�S�$�'���r0c�(�|j|�}|SrVr})rLr�r�s   r1r�zTensMul.contract_delta�s��� � ��'���r0c���i}d}t|j�D]L\}}t|t�s�t|t�sJ�t|j�D]}|||<|dz
}��N|S)zU
        Get a dict mapping the index position to TensMul's argument number.
        rr])r^r�r�r�r�r�r�)rL�pos_map�pos_counter�arg_ir	rSs      r1r�z TensMul._get_indices_to_args_pos�sz������#�D�I�I�.�	!�J�E�3��c�8�,���c�6�*�*�*��3�<�<�(�
!��',���$��q� ��
!�		!��r0c
�	�|j�}||k7rt|�}t||�S|j�}t	|j
�}|jtjd�k(rd}nP|jtjd�k(rd}n+|jtjd�k(rd}nt�t|j
�D��cgc](\}}t|t�s�|j|k(s�'|��*}}}|s|Sd}	|jdd}
|j dd}t#�}|D�]}
|
|vr�	|D�cgc]}||d|
k(s�|��}}|
D�cgc]}||d|
k(s||d|
k(s�|��}}|s�M|j%|
�d||
<t'|�dk(r�|sF|\}}||d|
k(r|d}n|d}||d|
k(r|d}n|d}|
j)||f��n3|\}}||d|
k(r|d}|ddk(r|	}	n|d}|ddk(r|	}	||d|
k(r	|d}|	}	n|d}|
j)||f�n�t'|�dk(r�|s[|d\}}||||k(r|j*d}|	|j,z}	n�|||
k(r|}n|}|d\}}|j)||f�nj|d\}}||||k(r'|j*d}|	|j,z}	||kr4|	}	n0|||
k(r|}|dk(r|	}	n|}|d\}}|j)||f�|
D�cgc]	}||vs�|��}
}|D�cgc]	}||vs�|��}}��d}dgt'|�z}t/t'|��D]}||vr|dz
}�
|||<�|D��cgc]\}}|||vs�|||||z
f��}}}t|
�D���cgc].\}\}}|||vs�|||vs�||||z
||||z
f��0}
}}}|	t1|�j3�z}t|t4�s|St6j9|j:||
�}|j=|�Scc}}wcc}wcc}wcc}wcc}wcc}}wcc}}}w)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]r=rN)rurMr�r�r�r�r�r�r�r�r�r^r�r�rZrFrEr�addrIrbrGr.r�r�r r�r;r[rYr;)rLr�r�r�r�rxrSrA�gposryrFrE�elim�gposx�free1rm�dum10�dum11�p0rJrzr{rfr�r��shift�shiftsr�r:s                             r1r�zTensMul.contract_metric�sR��8�{�{�}���4�<��D�>�D�"�4��+�+��/�/�1���D�I�I���
�:�:��7�7��;�;��G�
�Z�Z�>�9�9�!�<�
<��G�
�Z�Z�>�5�5�a�8�
8��G�%�%�(��	�	�2�a�d�a��j��F�6K�PQ�P[�P[�_`�P`��a��a���K����h�h�q�k���y�y��|���u���Y	7�E���}�� $�?�1���!��
��(>�Q�?�E�?�"�W�!�g�a��d�m�u�&<���!��
�QV�@V�A�W�D�W����H�H�U�O��D��K��4�y�A�~��#'�L�E�5��u�Q�x�(�E�1�"�1�X��#�1�X���u�Q�x�(�E�1�"�1�X��#�1�X���J�J��B�x�(�#'�L�E�5��u�Q�x�(�E�1�"�1�X�� ��8�q�=�$(�5�D�#�1�X�� ��8�q�=�$(�5�D��u�Q�x�(�E�1�"�1�X�� $�u��#�1�X���J�J��B�x�(��T��a���#�A�w�H�C���s�|�w�s�|�3��m�m�A�.��#�C�G�G�|��#�3�<�5�0�!$�B�!$�B�!&�q����Q����S�"�I�.�#�A�w�H�C���s�|�w�s�|�3��m�m�A�.��#�C�G�G�|����9�$(�5�D�#�3�<�5�0�!$�B�"�a�x�(,�u��!$�B�!&�q����Q����S�"�I�.�!�3��Q�d�]�1�3�C�3�#�6�!�q��~�A�6�D�6�sY	7�x����S��Y����s�4�y�!�	�A��D�y���
����F�1�I�		�
?C�]�(�3��g�a�j�X\�F\��a�&����,�,�-�]��]�W`�ad�We�^�^���8�B�PR�ip�qs�it�}A�jA�FM�NP�FQ�Y]�F]��V�G�B�K�(�(�"�v�g�b�k�/B�*B�C�^��^��7�D�>�&�&�(�(���#�x�(��J�
�
5�
5�c�n�n�d�C�
P���+�+�B�/�/��ib��@��W��h4��6��^��^s`�Q�8Q�Q�Q�Q�'Q$�Q$�/	Q)�9Q)�	Q.�
Q.�Q3�$Q3�Q9�Q9� Q9c�F�|j�}|j|d|i�Sr6r7r9s    r1r;z TensMul._set_new_index_structureSr<r0rc�l�t|�|jk7rtd��t|j�dd}d}t|�D]Q\}}t
|t�s�t
|t�sJ�|j}|j||||z�||<||z
}�St|d|i�j�S)Nr>rr�)rIr�rar�r�r^r�r�r�r8r�r )	rLr�rHr�r�rirSr	r�s	         r1r8zTensMul._set_indicesWs����w�<�4�=�=�(��6�7�7��D�I�I��q�!������o�	�F�A�s��c�8�,���c�6�*�*�*��|�|�H�&�c�&�&���C��L�(A�B�D��G��8�O�C�
	���6�+�6�;�;�=�=r0c�X�|D]%}t|t�s�t|t�r�%J�yrV)r�r�r�)r�rErFr	s    r1�&_index_replacement_for_contract_metricz.TensMul._index_replacement_for_contract_metrices.���	+�C��c�8�,���c�6�*�*�*�	+r0c��g}|jD]2}t|t�r|j|�}|j	|��4t|�j
�SrV)r�r�r�rcrbr�r r�s    r1rczTensMul.substitute_indiceslr�r0c���t�|j}t|�}|D�cgc]}|j��c}|D�cgc]}|j��c}k7rt	d��||k(r|S|j
tt
||���}t|D�chc]}|jr|n|��c}�t|�k7r|j|j�S|Scc}wcc}wcc}wr�rfrgs      r1r^zTensMul.__call__trhric
�B�t|jD�cgc]$}t|t�s�|j	|���&c}�\}}ttj|jD�cgc]}t|t�r�|��c}tj�}tj|�\}}}	}
tj|
�}|j}|jd���|D�
cgc]}
|
d��	}}
||tj!|||�zfScc}wcc}wcc}
w)Nc��|dSr�r/r@s r1rBz'TensMul._extract_data.<locals>.<lambda>�s
���!��r0rCr)r�r�r�r�r�r�operator�mulrrOr�r�r�r�rKr�r�)rLr�r	r�rr�rrHrEr�r�rFr�rSr�s               r1r�zTensMul._extract_data�s���"�TX�T]�T]�${�S�ak�lo�qy�az�S�%6�%6�7G�%H�${�|���f��x�|�|����%Z�A�*�Q�PX�BY�a�%Z�\]�\a�\a�b��07�0L�0L�\�0Z�-���z�:��(�(��4���=�=���	�	�n�	�%�&*�+���!��+��+��U�#;�#M�#M�f�VY�[c�#d�d�d�d��%|��%Z��
,s�D�D�&D
�<D
�(Dc��t�tt�5t|j	�}ddd�|S#1swYSxYwrVr�)rLr�s  r1r�zTensMul.data�s>����
�4�
5�	@�0�����?�C�	@��
�	@��
�s	�<�Ac�,�t�td��)Nz9Not possible to set component data to a tensor expression�r2rar*s  r1r�zTensMul.data�s�����T�U�Ur0c�,�t�td��)Nz<Not possible to delete component data to a tensor expressionrrks r1r�zTensMul.data�s�����W�X�Xr0c���t�tt�5|j�t	d��|jj�cddd�S#1swYyxYwr)r2r$r#r�rar0rks r1r0zTensMul.__iter__�sL����
�4�
5�	(��y�y� � �!C�D�D��9�9�%�%�'�	(�	(�	(�s�1A�Ac�>�t|�}tt|��}tt|��}|j|�}t	|�dk(ry	|j|�|j|�|D�cgc]}|df��}}tj|�}i}|D]T}	|	|j�vr�||	j�}
|	j|
g|	jdd���}|||	<|||	<�Vt	|�dk(ry|j|�}|Scc}w)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

        rNr])
rr�r�r�rIrzr;rnr�rQr�r�ra)
rQr��dums_new�free_new�	conflictsrS�exclude_for_gen�genr`�d�newname�new_d�new_renameds
             r1r�zTensMul._dedupe_indices�s)���g�,���(��-�.���'��,�-���)�)�'�2�	��y�>�Q���	�
	���x� ����x� �.5�6��A�t�9�6��6��>�>��O�����	�A��r�T�Y�Y�[� ���!�-�-�.�G��A�F�F�7�0�Q�V�V�A�B�Z�0�E��D��G��v�D�!��H�
	��t�9��>���*�*�4�0�����7s�;Dc�z�|j�D��cic]\}}t|t�s�||��}}}|j�D��cic]\}}||j�vs�||��}}}t	|j��}i}|j
|�|j
|j��|j
|j��|j�D]G\}}	tj|	|�}
||	k(s|
�|	||<�)|
||<|j
t|
���I|Scc}}wcc}}w)zb
        rule: dict

        This applies TensMul._dedupe_indices on all values of rule.

        )
r�r�ror�rrlrz�valuesr�r�)rLr�r�r��index_rules�other_rulesr��newrulerPrQrs           r1r�zTensMul._dedupe_indices_in_rule�s��'+�j�j�l�Q�s�q��j��K�6P�q��s�Q��Q�&*�j�j�l�R�s�q��a�{�?O�?O�?Q�6Q�q��s�R��R��d�&�&�(�)�������{�#����{�'�'�)�*����{�)�)�+�,�#�)�)�+�	9�H�C��!�1�1�#�w�?�K��c�z�[�0�"����*�������{�;�7�8�
	9����R��Rs�D1�D1�D7�#D7c��ddlm}|j�D�cgc]}|jd��}}|D�cgc]}t	||�r|jdn|��!}}tj|�}|j||�Scc}wcc}w)Nrr�)r�r�rlr�r�rrr�)rLr�r�rSr�r	r�s       r1rz TensMul._eval_rewrite_as_Indexed�s|��1�,0�,<�,<�,>�?�q������?�
�?�HL�M��z�#�s�3�������<�M��M��|�|�D�!���"�"�4��7�7��@��Ms
�B�$Bc	��g}t|j�D]�\}}t|t�r|j	|�}n.|j
r|j
|�}ntj}|s�Y|jtj|jd||fz|j|dzdz����tj|�Sr�)
r^r�r�r�r	r
rrr�rbr�rr�)rLr��termsrSr	rs      r1r	z TensMul._eval_partial_derivative�s�������	�	�*�	Y�F�A�s��#�x�(��0�0��3���;�;��,�,�Q�/�A����A�����W�-�-�d�i�i���m�q�d�.B�T�Y�Y�q�ST�u�v�EV�.V�W�X�	Y�����&�&r0r�r�r�r�)@r�r�r�r�rrOr�r�r�r}rGrErFr�r�r�r�r�r�r0r�r�r r�r�r{rr�rrYrHrrXrLr�rlr�rar�rsr�r�r�r�rYr�rMr�r�r�r;r8r
rcr^r�r�r�r�r0r�r�rr	r/r0r1r�r�ys���%�L�u�u�H���-�^�9�:�K��+�,�D�
�)�
*�C��;�<�L��+�,�D��3�4�H��,5��,5�\�F��F�� (�� (�D�����	G��	G�0�h�w��w����� )�d�	��1��1��9��9��U��U�
�����T��T��g��g�
3��:8�6s�"�H
�R�#�
��BH�=�!�F�
�b0�HD�27�>��+��+�)�� e�����
�[�[�V��V�
�\�\�Y��Y�(��(��(�T�08�'r0r�c��eZdZdZd�Zed��Zed��Zed��Zed��Z	ed��Z
ed��Zd	�Zdd
�Z
d�Zd�Zy
)�
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	��t|t�sOt|t�std|z��|j|j
D�cgc]}t
||���c}�S|j�}|D�cic]}|j
d|��}}|j�D��cic]\}}|j||�|��}}}|j�D��cic]
\}}||vs�||��}}}t|�dk(r|S|D�cgc]}||j�vs�|��}	}t|�}tj|||�}
|	|
_|
Scc}wcc}wcc}}wcc}}wcc}w)Nz%s is not a tensor expressionr)r�r�r�r�r�r�r)r�r�rzrIr�rr�r�)r�r�r.r	�expr_free_indicesrS�name_translationrer0r�r�s           r1r�zTensorElement.__new__sK���$��'��d�H�-�� ?�$� F�G�G��4�9�9��	�	�R��}�S�)�<�R�S�S� �1�1�3��2C�D�Q�A�F�F�1�I�q�L�D��D�S\�Sb�Sb�Sd�e�<�5�%�%�)�)�%��7��>�e�	�e�6?�o�o�6G�f�l�e�U�5�Te�Ke�U�E�\�f�	�f��y�>�Q���K�#4�R�a�����AQ�8Q��R��R���O�	����s�D�)�4��(����
��S��D��e��f��Ss*�	E�4E
� E�E� E�<E�Ec�j�t|j��D��cgc]	\}}||f��c}}Scc}}wrV)r^r�)rLrSres   r1rEzTensorElement.free1s,��+4�T�5J�5J�5L�+M�N�x�q�%���
�N�N��Ns�/c��gSrVr/rks r1rFzTensorElement.dum5s	���	r0c� �|jdSr?��_argsrks r1r�zTensorElement.expr:����z�z�!�}�r0c� �|jdSr�r0rks r1r.zTensorElement.index_map>r2r0c�"�tjSrVr�rks r1rzTensorElement.coeffBr�r0c��|SrVr/rks r1rXzTensorElement.nocoeffFr�r0c��|jSrVr�rks r1r�zTensorElement.get_free_indicesJs���!�!�!r0c�$�|j|�SrVr^r_s  r1razTensorElement._replace_indicesMs���}�}�T�"�"r0c�"�|j�SrV)r�rks r1rlzTensorElement.get_indicesQs���$�$�&�&r0c����|jj|�\}}|j�t�fd�|D��}|D�cgc]	}|�vs�|��}}|j	|�}||fScc}w)Nc3�T�K�|]}�j|td�����!y�wrV)rz�slice)r�rSr.s  �r1r�z.TensorElement._extract_data.<locals>.<genexpr>Ws �����O�a�I�M�M�!�U�4�[�9�O�s�%()r�r�r.r�r�)rLr�r�r��slice_tuplerSr.s      @r1r�zTensorElement._extract_dataTsq���!�Y�Y�4�4�5E�F���U��N�N�	��O�;�O�O��"-�D�Q��)�1C�q�D��D��!�!�+�.���E�!�!��Es�	A)�A)Nr�)r�r�r�r�r�r}rErFr�r.rrXr�rarlr�r/r0r1r)r)s����6�$�O��O���������������������"�#�'�"r0r)c��eZdZdZdd�Zd�Zy)�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``

    Nc
��t|t�rt|�}nt|t�r|}ntd��|�g}|�tjt
|��}n|jt
|�k(sJ�|tjt
|��k7rtd��tj||t|�t|�t|�t|��}tj|�|_||_|S)Nr�z3Wild matching based on symmetry is not implemented.)r�r{rrar�r�rIr�r�rr�rrr�ror��unordered_indices)r�r_rGr�r�r@r�r�s        r1r�zWildTensorHead.__new__�s����d�C� � ��,�K�
��f�
%��K��^�,�,����K���%�1�1�#�k�2B�C�H��=�=�C��$4�4�4�4��~�1�1�#�k�2B�C�C�%�&[�\�\��m�m�C��e�[�.A�7�8�CT�V]�^b�Vc�el�m~�e�A�� �/�/��5��� 1����
r0c�<�t||fi|��}|j�SrV)�
WildTensorr )rLrHr�rs    r1r^zWildTensorHead.__call__�s���D�'�4�V�4���{�{�}�r0)NNrF)r�r�r�r�r�r^r/r0r1r>r>]s��6�n�2r0r>c�&�eZdZdZd�Zdd�Zdd�Zy)rBa�
    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��|jdd�}|jtk(r	t||fd|i|��S|jtk(r||�S|j||�}|D�cgc]}|j��}}|j|j|d|j|j��}tj||t|��}|j|_tj|�|_|jj dd|_|jj$dd|_|jj(|_t*j,|_||_||_|g|_|j6t9|�k7rt;d��||_|j?||j�|_ |Scc}w)Nr�F)r�r�r@r)!r�r�r�r��
_WildTensExprrrQr_r�r@rr�rr;rTr�rErrFrrJrrOrrrrr�rIrar�rr)r�rrHr�r�r�rGr�s        r1r�zWildTensor.__new__�s����k�k�-��7�����z�)�
��+�w�S�K�S�7�S�S�
�
�
��
.���(�(��$�$�[�'�:��8?�@��s�,�,�@��@�!�&�&�������!�!�)�;�;�'����m�m�C��e�W�o�>���#�#���.�;�;�W�E����(�(�-�-�a�0��	��'�'�+�+�A�.����,�,�6�6��
��U�U��
����$���&�-������s�7�|�+��6�7�7�%����-�-�g�s�7K�7K�L����
��1As�$GNc�p�t|t�s|td�k7ry|�i}n|j�}t	|j
�dkDr�t
|d�sy|j�}t	|�t	|j
�k7ry|jjr&|j|�}|�y|j|�nOtt	|��D]8}|j
|j||�}|�y|j|��:t|�||j<|S|||<|S)Nr]rr�)r�r�rrOrIrHr_r�rr@�_match_indices_ignoring_orderrzr��matchesrErZ)rLr��	repl_dictrP�expr_indicesr=rSs       r1rHzWildTensor.matches�s"���$��)�d�a��d�l�����I�!���(�I��t�|�|��q� ��4�!3�4���0�0�2�L��<� �C����$5�5�����0�0��6�6�t�<���9���$�$�Q�'��s�<�0�1�,�A����Q��/�/��Q��@�A��y�#�!�(�(��+�,�)6�d�(;�I�d�n�n�%�
��#�I�d�O��r0c��|�i}n|j�}d�}t|j|�}g}|j�}|dD]M}d}	|D]@}
|
|vr�|j	|
�}|��d}	|j|�|j
|
�n|	r�My|D�cgc]	}||vs�|��}}|dD]k}d}	|D]^}
|j	|
�}|��||j�vr||||k7ryd}	|j|�|j
|
�n|	r�ky|D�cgc]	}||vs�|��}}|dD]k}d}	|D]^}
|j	|
�}|��||j�vr||||k7ryd}	|j|�|j
|
�n|	r�kyt|�t|j�kry|Scc}wcc}w)z~
        Helper method for matches. Checks if the indices of self and expr
        match disregarding index ordering.
        Nc�@�t|t�r|jryyy)N�wild, updown�wild�nonwild)r��WildTensorIndex�
ignore_updown)r�s r1�siftkeyz9WildTensor._match_indices_ignoring_order.<locals>.siftkey,s���#��/��$�$�)�!� r0rOFTrNrM)	rOr'rHrlrHrzrbr�rI)
rLr�rIrPrR�indices_sifted�matched_indices�expr_indices_remainingr��matched_this_ind�e_indr=rSs
             r1rGz(WildTensor._match_indices_ignoring_order"sH��
���I�!���(�I�	!��d�l�l�G�4����!%�!1�!1�!3��!�)�,�	�C�$��/�
���O�+���K�K��&���=�'+�$��$�$�Q�'�#�*�*�5�1��
�$��	�.D�!`��q�P_�G_�!�!`��!`�!�&�)�	�C�$��/�
���K�K��&���=��t�y�~�~�/�/�Y��t�_�4D��#��4N�#�'+�$��$�$�Q�'�#�*�*�5�1��
�$��	�.D�!`��q�P_�G_�!�!`��!`�!�.�1�	�C�$��/�
���K�K��&���=��t�y�~�~�/�/�Y��t�_�4D��#��4N�#�'+�$��$�$�Q�'�#�*�*�5�1��
�$��	����#�d�l�l�"3�3�����C"a��"as�	G�$G�!	G
�+G
�NF)r�r�r�r�r�rHrGr/r0r1rBrB�s��"�F$�N"�HFr0rBc�6�eZdZdZdd�Zed��Zd�Zdd�Zy)	rPa
    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)
    c�r�t|t�rt|�}nmt|t�r|}nZ|durKdjt	|j
��}t|�}|j
j
|�ntd��t|�}t|�}tj|||||�Sr�r�)r�r_rQr`rQr�s      r1r�zWildTensorIndex.__new__�s����d�C� � ��,�K�
��f�
%��K�
�T�\��=�=��%6�%E�%E�!F�G�D� ��,�K��,�,�3�3�K�@��^�,�,������
�.�
��}�}�S�+�/@�%��W�Wr0c� �|jdSr�r�rks r1rQzWildTensorIndex.ignore_updown�r�r0c�t�t|j|j|j|j�}|SrV)rPr_rQr`rQr�s  r1r�zWildTensorIndex.__neg__�s0��
�T�Y�Y��(>�(>��Z�Z��$�"4�"4�6���	r0Nc���t|t�sy|j|jk7ry|js|j|jk7ry|�i}n|j�}|||<|SrV)r�rorQrQr`rO)rLr�rIrPs    r1rHzWildTensorIndex.matches�sh���$��,���!�!�T�%;�%;�;���!�!��z�z�T�Z�Z�'�����I�!���(�I��	�$���r0)TFrX)	r�r�r�r�r�r}rQr�rHr/r0r1rPrPjs,��"�FX� �����
r0rPc�d�eZdZdZd�Zd�Zd�Zd�Zd�Zd�Z	d�Z
d	�Zd
�Zd�Z
d�Zd
�Zd�Zd�Zy)rEa�
    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�H�t|t�std��||_y)Nz,_WildTensExpr expects a TensExpr as argument)r�r�r�r�)rLr�s  r1rNz_WildTensExpr.__init__�s���$��)��J�K�K���	r0c��|jjtt|jj	�|���SrV)r�rar�r�r�)rLrHs  r1r^z_WildTensExpr.__call__�s1���y�y�)�)�$�s�4�9�9�3M�3M�3O�QX�/Y�*Z�[�[r0c�Z�|j|jtjz�SrV)r�r�rr9rks r1r�z_WildTensExpr.__neg__�s���y�y����1�=�=�0�1�1r0c��t�rVr;rks r1r<z_WildTensExpr.__abs__�r=r0c���|j|jk7r%td|j�d|j����|j|j|jz�S�NzCannot add z to �r�r�r�r�s  r1r@z_WildTensExpr.__add__�sN���:�:����"��k�$�)�)��D�����E�F�F��y�y����5�:�:�-�.�.r0c���|j|jk7r%td|j�d|j����|j|j|jz�Srdrer�s  r1rBz_WildTensExpr.__radd__�sN���:�:����"��k�$�)�)��D�����E�F�F��y�y����D�I�I�-�.�.r0c��||zSrVr/r�s  r1rEz_WildTensExpr.__sub__�s����v��r0c��||zSrVr/r�s  r1rGz_WildTensExpr.__rsub__�s������r0c��t�rVr;r�s  r1rJz_WildTensExpr.__mul__�r=r0c��t�rVr;r�s  r1rLz_WildTensExpr.__rmul__�r=r0c��t�rVr;r�s  r1rPz_WildTensExpr.__truediv__�r=r0c��t�rVr;r�s  r1rRz_WildTensExpr.__rtruediv__�r=r0c��t�rVr;r�s  r1r'z_WildTensExpr.__pow__�r=r0c��t�rVr;r�s  r1rUz_WildTensExpr.__rpow__�r=r0N)r�r�r�r�rNr^r�r<r@rBrErGrJrLrPrRr'rUr/r0r1rErE�sN���&�
\�2�"�/�
/�
��"�"�"�"�"�"r0rEc�F�t|t�r|j�S|S)zt
    Butler-Portugal canonicalization. See ``tensor_can.py`` from the
    combinatorics module for the details.
    )r�r�rM)r�s r1rMrM�s��
�!�X���z�z�|���Hr0c�~�|s&tjtjggg�S|d}|ddD]}||z}�	|S)z
    product of tensors
    rr]N)r�r�rrO)r�r��txs   r1�
tensor_mulrrsN��
�� � �����B��3�3�	�!��A����e���
�b�D����Hr0c�D�t|jd���}|D�cgc]}|d��	c}\}}}}|tdd�z}|j||f||f||f||f�tdd�z}|j||f||f||f||f�tdd�z}	||z|	z}
|
Scc}w)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��|dSr�r/r@s r1rBz(riemann_cyclic_replace.<locals>.<lambda>s
��!�A�$�r0rCrr=rgr])r�rErrc)�t_rrErAr=rcr��q�t0r��t2�t3s           r1�riemann_cyclic_replacerzs����#�(�(��/�D� $�%�1�!�A�$�%�J�A�q�!�Q�	�X�a��^�	�B�

�
 �
 �!�A���!�u�a��U�A�a�5�
9�	9�(�1�a�.�	H�B�	�	�	��1��q��e�Q�q�E�1�Q�%�	8��!�Q��	G�B�	�b��2��B�
�I��&s�Bc
��|j�}t|ttf�r|g}n|j}|D�cgc]}|j���}}|D��cgc]}|D�cgc]
}t
|���c}��}}}|D�cgc]
}t|���}}t|�j�}	|	s|	St|	�Scc}wcc}wcc}}wcc}w)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
    )rur�r�r�r�r�rzrrr�r rM)
rxr�rA�a1r�rq�a2r��a3rys
          r1�riemann_cyclicr#s���$
����B��"�w��'�(��t���w�w��!�	"��!�'�'�)�	"�B�	"�<>�	?�q��
2�"�!�"�%�
2�	?�B�	?�"$�	%�Q�*�a�.�	%�B�	%�	�"��	�	�	�B�
��	���|���
#��
2��	?��	%s#�B6�	C�"B;�4C�C�;Cc���d�}|j}i}|jD]�}t|t�s�||vr�|j}g}t	t|��D]}|||us�|j
|��t|�dkDrtd|z��t|�dk(s��|||<��g}	g}
g}|jD�]A\}}
}}|||vr�||k(r|
j
|g��)|||}|||}||vr�>|j|�|j|
�k(rt�|||}||dk(r||fn||f\}}|	dd}|	D]�}|d|k(ra|d|k(rF|jt|��}|j
|�|
j
||d|d|z�n|j
|�n1|d|k(s�u|jd|�n|j
||g�|D�cgc]	}||vs�|��}	}||	�}	��Dg}|	D]}|D]}|j
|���|
D]}|D]}|j
|���t	t|��D�cgc]	}||vs�|��}}|	|
|fScc}wcc}w)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���d}|t|�k�rW||}|d}|d}d}|�r.d}t|dzt|��D�]}|t|�k\rn�||d|k(r0d}|j||dd�|d}|j|��O||d|k(r8d}t	||dd�|z||<||}||d}|j|���||d|k(r9d}|jt	||dd��|d}|j|���||d|k(s��d}||dd|z||<||}|d}|j|���|r��.|dz
}|t|�kr��W|S)Nrr�TFr])rIr�rWr��reversed)r�rSrA�xend�xstart�hitr�s       r1�_join_lineszget_lines.<locals>._join_linesKs���
���#�a�&�j��!��A��R�5�D��q�T�F��C�����q�1�u�c�!�f�-�!�A��C��F�{����t�A�w�$��"������1��a�b��*� ��u�����a�� ���t�A�w�&�(�"��'��!��Q�R��1�A�5��!���a�D��!"�1��a������a�� ���t�B�x�4�'�"������!�A�$�s��)�!4�5� ��u�����a�� ���t�B�x�6�)�"�� ��t�C�R�y�1�}��!���a�D��!"�1������a�� �9!��>
��F�A�I�#�a�&�j�J�r0r=z&at most two indices of type %s allowedr]Nr�r)
r�r�r�rGr�rIrbrarLrer��min�insert)�exr�r��	arguments�dtrsrGr�rS�lines�traces�traces1rrJ�c0�c1�ta0�ta1�b0�b1�lines1�linercrA�restr�s                          r1�	get_linesr�Ds���'�R���I�	�B�
�W�W�
���!�X�&����7���m�m�����s�;�'�(�	�A��1�~��+������	��q�6�A�:��E�
�R�S�S��q�6�Q�;��B�q�E�
�
�E�
�F��G��.�.�%#���B��B��R�=��"��
��8��M�M�2�$�����2������2����
�S�=���9�9�R�=�C�I�I�b�M�)�
&�%���2�����3�q�6�\�"�b���R����B��q����
	$�D��B�x�2�~���7�b�=��
�
�3�t�9�-�A��N�N�4�(��M�M�$�q�r�(�T�"�1�X�"5�6��K�K��O���a��B�����A�r�"��
	$�
�M�M�2�r�(�#�"�7�q�a�w�&6��7��7��E�"��K%#�L�D�����	�A��K�K��N�	������	�A��K�K��N�	���S��^�,�>�!���
�A�>�D�>��&�$����8��?s�%	I+�/I+�	I0� I0c�D�t|t�sy|j�S�Nr/)r�r�r��r�s r1r�r��s���a��"������r0c�D�t|t�sy|j�Sr�)r�r�rlr�s r1rlrl�s���a��"���=�=�?�r0c��t|t�sy|j�}|j�}|D�cgc]	}||vs�|��c}Scc}wr�)r�r�rlr�)r��indsrErSs    r1r�r��sB���a��"���=�=�?�D�����D��-�!�q��}�A�-�-��-s�	A�Ac�V�t|t�r|jStgggg�SrV)r�r�r�r;r�s r1r�r��s)���!�X���!�!�!��2�r�2�r�*�*r0c��t|t�rtjSt|t�r|j
St|t�rtd��|S)Nz3no coefficient associated to this tensor expression)r�r�rrOr�rr�rar�s r1�	get_coeffr��sC���!�V���u�u���!�W���w�w���!�X���N�O�O��Hr0c�H�t|t�r|j|�S|SrV)r�r�r�)r�r�s  r1r�r��s"���!�X��� � ��#�#��Hr0c��t|t�s|St|ttf�rHt	|�j||��}|j
||��}|dt|�dz
k7r|S|St��)z�
    Returns the tensor corresponding to the permutation ``g``

    For further details, see the method in ``TIDS`` with the same name.
    rr�r])	r�r�r�r�r�r�r;rIr�)r�r�r��nimr�s     r1r�r��sz���a��"���	�A���(�	)�!�!�$�0�0���0�L���(�(��+�(�F���R�5�C��F�Q�J���4�K��
�
�
�r0c�D�t|t�s|S|j|�SrV)r�r�rc)r�rds  r1rcrc�s$���a��"����1����.�.r0c�j�t|t�r|jdi|��S|jdi|��Sr�)r�r�rsru)r�r�s  r1rsrs�s4���$��!��t�|�|�%�f�%�%��t�{�{�$�V�$�$r0r?r�)dr��
__future__r�typingr�	functoolsr�mathr�abcrr�collectionsr	rrA�sympy.core.numbersr
rr�r
�sympy.combinatorics.tensor_canrrrr�
sympy.corerrrrrr�sympy.core.containersrr�sympy.core.sortingr�sympy.core.symbolrr�sympy.core.sympifyrr�sympy.core.operationsr�sympy.external.gmpyr �sympy.matricesr!�sympy.utilities.exceptionsr"r#r$�sympy.utilities.decoratorr%r&�sympy.utilities.iterablesr'r2r6r9r;r�r�r�rbr�r"ror�r�r�r�rr�r6r�r�r�r�r)r>rBrPrErMrrrzrr�r�rlr�r�r�r�r�rcrsr/r0r1�<module>r�sN���>#����#�#���2�+�4�4�8�8�-�/�-�4�)�*��9�9�C�*�	�	�	�h)�k�h)�V	
�&s�{�s�j":�!;��_�_�D� �
�k6�e�k6�\	Z�%�Z�z�:A9�U�A9�H��#�:�
�?,��?,�B�;�"�6��
;_��;_��
;_�|��#�6��,��,�0L5��L5�^�^)�t�S�^)�B
R(�h��R(�j
PA�X�PA�hG'�h��G'�TW"�H�W"�tS�Z�S�lu��u�nL�k�L�^B"�E�B"�J
�	
�
��Bu�p ��
.�+�
�
� �$/�%r0

Youez - 2016 - github.com/yon3zu
LinuXploit