a
    SG5dS`                     @   s  d Z ddlmZ ddlmZ ddlmZ ddlmZm	Z	m
Z
mZ ddlmZmZ ddlmZmZ ddlmZ dd	lmZ dd
lmZ ddlmZmZ ddlmZ G dd deZG dd deZG dd deeZ G dd deZ!ee!e!dd Z"ee!edd Z"eee!dd Z"dS )a
  Module that defines indexed objects

The classes ``IndexedBase``, ``Indexed``, and ``Idx`` represent a
matrix element ``M[i, j]`` as in the following diagram::

       1) The Indexed class represents the entire indexed object.
                  |
               ___|___
              '       '
               M[i, j]
              /   \__\______
              |             |
              |             |
              |     2) The Idx class represents indices; each Idx can
              |        optionally contain information about its range.
              |
        3) IndexedBase represents the 'stem' of an indexed object, here `M`.
           The stem used by itself is usually taken to represent the entire
           array.

There can be any number of indices on an Indexed object.  No
transformation properties are implemented in these Base objects, but
implicit contraction of repeated indices is supported.

Note that the support for complicated (i.e. non-atomic) integer
expressions as indices is limited.  (This should be improved in
future releases.)

Examples
========

To express the above matrix element example you would write:

>>> from sympy import symbols, IndexedBase, Idx
>>> M = IndexedBase('M')
>>> i, j = symbols('i j', cls=Idx)
>>> M[i, j]
M[i, j]

Repeated indices in a product implies a summation, so to express a
matrix-vector product in terms of Indexed objects:

>>> x = IndexedBase('x')
>>> M[i, j]*x[j]
M[i, j]*x[j]

If the indexed objects will be converted to component based arrays, e.g.
with the code printers or the autowrap framework, you also need to provide
(symbolic or numerical) dimensions.  This can be done by passing an
optional shape parameter to IndexedBase upon construction:

>>> dim1, dim2 = symbols('dim1 dim2', integer=True)
>>> A = IndexedBase('A', shape=(dim1, 2*dim1, dim2))
>>> A.shape
(dim1, 2*dim1, dim2)
>>> A[i, j, 3].shape
(dim1, 2*dim1, dim2)

If an IndexedBase object has no shape information, it is assumed that the
array is as large as the ranges of its indices:

>>> n, m = symbols('n m', integer=True)
>>> i = Idx('i', m)
>>> j = Idx('j', n)
>>> M[i, j].shape
(m, n)
>>> M[i, j].ranges
[(0, m - 1), (0, n - 1)]

The above can be compared with the following:

>>> A[i, 2, j].shape
(dim1, 2*dim1, dim2)
>>> A[i, 2, j].ranges
[(0, m - 1), None, (0, n - 1)]

To analyze the structure of indexed expressions, you can use the methods
get_indices() and get_contraction_structure():

>>> from sympy.tensor import get_indices, get_contraction_structure
>>> get_indices(A[i, j, j])
({i}, {})
>>> get_contraction_structure(A[i, j, j])
{(j,): {A[i, j, j]}}

See the appropriate docstrings for a detailed explanation of the output.
    )Iterable)Number)	StdFactKB)ExprTuplesympifyS)_filter_assumptionsSymbol)
fuzzy_bool	fuzzy_not)_sympify)KroneckerDelta)dispatch)is_sequenceNotIterable)
filldedentc                   @   s   e Zd ZdS )IndexExceptionN)__name__
__module____qualname__ r   r   P/var/www/html/django/DPS/env/lib/python3.9/site-packages/sympy/tensor/indexed.pyr   x   s   r   c                       s   e Zd ZdZdZdZdZdZdd Z fddZ	e
dd Ze
d	d
 Zdd Ze
dd Ze
dd Ze
dd Ze
dd Ze
dd Ze
dd Zdd Ze
dd Ze
dd Z  ZS )Indexeda  Represents a mathematical object with indices.

    >>> from sympy import Indexed, IndexedBase, Idx, symbols
    >>> i, j = symbols('i j', cls=Idx)
    >>> Indexed('A', i, j)
    A[i, j]

    It is recommended that ``Indexed`` objects be created by indexing ``IndexedBase``:
    ``IndexedBase('A')[i, j]`` instead of ``Indexed(IndexedBase('A'), i, j)``.

    >>> A = IndexedBase('A')
    >>> a_ij = A[i, j]           # Prefer this,
    >>> b_ij = Indexed(A, i, j)  # over this.
    >>> a_ij == b_ij
    True

    Tc                 O   s  ddl m} ddlm} |s$tdt|ttfr<t|}n t	|ds\t|ts\t
tdttt|}t||tt|frtdd |D rt|d	kr||d  S || S t|}tj| |g|R i |}zt||j W n  ty   t|i  Y n0 |S )
Nr   	NDimArray
MatrixBasez!Indexed needs at least one index.__getitem__z
                The base can only be replaced with a string, Symbol,
                IndexedBase or an object with a method for getting
                items (i.e. an object with a `__getitem__` method).
                c                 s   s   | ]}|j V  qd S N)	is_number).0ir   r   r   	<genexpr>       z"Indexed.__new__.<locals>.<genexpr>   )sympy.tensor.array.ndim_arrayr   sympy.matrices.matricesr   r   
isinstancestrr
   IndexedBasehasattr	TypeErrorr   listmapr   r   r   alllenr   r   __new___set_assumptionsassumptions0AttributeError)clsbaseargskw_argsr   r   objr   r   r   r1      s(    
$zIndexed.__new__c                    s   t   tt| j  S r   super_hashable_contenttuplesortedr3   itemsself	__class__r   r   r<      s    zIndexed._hashable_contentc                 C   s   t | S r   )r)   r@   r   r   r   name   s    zIndexed.namec                 C   s   dS )z8Allow derivatives with respect to an ``Indexed`` object.Tr   r@   r   r   r   	_diff_wrt   s    zIndexed._diff_wrtc                 C   s   ddl m} t|trz|j| jkrzt| jt|jkrJd| |}t|t	j
}t| j|jD ]\}}|t||9 }q^|S t| j|rddlm} t|| j|g| jdd  R  S t| j|rt	jS t	jS d S )Nr   r   z'Different # of indices: d({!s})/d({!s}))derive_by_arrayr%   )r&   r   r(   r   r6   r0   indicesformatr   r   Onezipr   sympy.tensor.arrayrF   r7   r   hasNaNZero)rA   wrtr   msgresultZindex1index2rF   r   r   r   _eval_derivative   s"    "zIndexed._eval_derivativec                 C   s   dd | j  D S )Nc                 S   s   i | ]\}}|d ur||qS r   r   r!   kvr   r   r   
<dictcomp>   r$   z(Indexed.assumptions0.<locals>.<dictcomp>_assumptionsr?   r@   r   r   r   r3      s    zIndexed.assumptions0c                 C   s
   | j d S )aJ  Returns the ``IndexedBase`` of the ``Indexed`` object.

        Examples
        ========

        >>> from sympy import Indexed, IndexedBase, Idx, symbols
        >>> i, j = symbols('i j', cls=Idx)
        >>> Indexed('A', i, j).base
        A
        >>> B = IndexedBase('B')
        >>> B == B[i, j].base
        True

        r   r7   r@   r   r   r   r6      s    zIndexed.basec                 C   s   | j dd S )z
        Returns the indices of the ``Indexed`` object.

        Examples
        ========

        >>> from sympy import Indexed, Idx, symbols
        >>> i, j = symbols('i j', cls=Idx)
        >>> Indexed('A', i, j).indices
        (i, j)

        r%   NrZ   r@   r   r   r   rG      s    zIndexed.indicesc                 C   s   t | jd S )as  
        Returns the rank of the ``Indexed`` object.

        Examples
        ========

        >>> from sympy import Indexed, Idx, symbols
        >>> i, j, k, l, m = symbols('i:m', cls=Idx)
        >>> Indexed('A', i, j).rank
        2
        >>> q = Indexed('A', i, j, k, l, m)
        >>> q.rank
        5
        >>> q.rank == len(q.indices)
        True

        r%   )r0   r7   r@   r   r   r   rank   s    zIndexed.rankc              	   C   s   | j jr| j jS g }| jD ]v}t|dd}t|dd}d||fv rRttd|  z|| d }W n" ty   ttd|  Y n0 || qt| S )ab  Returns a list with dimensions of each index.

        Dimensions is a property of the array, not of the indices.  Still, if
        the ``IndexedBase`` does not define a shape attribute, it is assumed
        that the ranges of the indices correspond to the shape of the array.

        >>> from sympy import IndexedBase, Idx, symbols
        >>> n, m = symbols('n m', integer=True)
        >>> i = Idx('i', m)
        >>> j = Idx('j', m)
        >>> A = IndexedBase('A', shape=(n, n))
        >>> B = IndexedBase('B')
        >>> A[i, j].shape
        (n, n)
        >>> B[i, j].shape
        (m, m)
        upperNlowerz@
                    Range is not defined for all indices in: %sr%   zc
                    Shape cannot be inferred from Idx with
                    undefined range: %s)	r6   shaperG   getattrr   r   r,   appendr   )rA   sizesr"   r\   r]   sizer   r   r   r^     s$    
zIndexed.shapec                 C   sX   g }t  }| jD ]B}t|d|}t|d|}|||fvrH|||f q|d q|S )a  Returns a list of tuples with lower and upper range of each index.

        If an index does not define the data members upper and lower, the
        corresponding slot in the list contains ``None`` instead of a tuple.

        Examples
        ========

        >>> from sympy import Indexed,Idx, symbols
        >>> Indexed('A', Idx('i', 2), Idx('j', 4), Idx('k', 8)).ranges
        [(0, 1), (0, 3), (0, 7)]
        >>> Indexed('A', Idx('i', 3), Idx('j', 3), Idx('k', 3)).ranges
        [(0, 2), (0, 2), (0, 2)]
        >>> x, y, z = symbols('x y z', integer=True)
        >>> Indexed('A', x, y, z).ranges
        [None, None, None]

        r\   r]   N)objectrG   r_   r`   )rA   rangessentinelr"   r\   r]   r   r   r   rd   3  s    
zIndexed.rangesc                 C   s,   t t|j| j}d|| jd|f S )Nz%s[%s]z, )r-   r.   doprintrG   r6   join)rA   prG   r   r   r   	_sympystrR  s    zIndexed._sympystrc                 C   s2   | j j}dd | jD }|r*| h|B |B S |S d S )Nc                 S   s   h | ]}|j D ]}|qqS r   )free_symbols)r!   r"   fsr   r   r   	<setcomp>Y  s   z'Indexed.free_symbols.<locals>.<setcomp>)r6   rj   rG   )rA   Zbase_free_symbolsZindices_free_symbolsr   r   r   rj   V  s    zIndexed.free_symbolsc                 C   s    ddl m} |dddd | hS )Nr   )sympy_deprecation_warningz
        The expr_free_symbols property is deprecated. Use free_symbols to get
        the free symbols of an expression.
        z1.9zdeprecated-expr-free-symbols)deprecated_since_versionactive_deprecations_target)sympy.utilities.exceptionsrm   )rA   rm   r   r   r   expr_free_symbols`  s    zIndexed.expr_free_symbols)r   r   r   __doc__is_commutative
is_Indexed	is_symbolis_Atomr1   r<   propertyrD   rE   rS   r3   r6   rG   r[   r^   rd   ri   rj   rq   __classcell__r   r   rB   r   r   |   s:   






%

	r   c                       s   e Zd ZdZdZdZdZedd Zde	j
ddddZed	d
 Z fddZedd Zdd Zedd Zedd Zedd Zedd Zdd Z  ZS )r*   ah	  Represent the base or stem of an indexed object

    The IndexedBase class represent an array that contains elements. The main purpose
    of this class is to allow the convenient creation of objects of the Indexed
    class.  The __getitem__ method of IndexedBase returns an instance of
    Indexed.  Alone, without indices, the IndexedBase class can be used as a
    notation for e.g. matrix equations, resembling what you could do with the
    Symbol class.  But, the IndexedBase class adds functionality that is not
    available for Symbol instances:

      -  An IndexedBase object can optionally store shape information.  This can
         be used in to check array conformance and conditions for numpy
         broadcasting.  (TODO)
      -  An IndexedBase object implements syntactic sugar that allows easy symbolic
         representation of array operations, using implicit summation of
         repeated indices.
      -  The IndexedBase object symbolizes a mathematical structure equivalent
         to arrays, and is recognized as such for code generation and automatic
         compilation and wrapping.

    >>> from sympy.tensor import IndexedBase, Idx
    >>> from sympy import symbols
    >>> A = IndexedBase('A'); A
    A
    >>> type(A)
    <class 'sympy.tensor.indexed.IndexedBase'>

    When an IndexedBase object receives indices, it returns an array with named
    axes, represented by an Indexed object:

    >>> i, j = symbols('i j', integer=True)
    >>> A[i, j, 2]
    A[i, j, 2]
    >>> type(A[i, j, 2])
    <class 'sympy.tensor.indexed.Indexed'>

    The IndexedBase constructor takes an optional shape argument.  If given,
    it overrides any shape information in the indices. (But not the index
    ranges!)

    >>> m, n, o, p = symbols('m n o p', integer=True)
    >>> i = Idx('i', m)
    >>> j = Idx('j', n)
    >>> A[i, j].shape
    (m, n)
    >>> B = IndexedBase('B', shape=(o, p))
    >>> B[i, j].shape
    (o, p)

    Assumptions can be specified with keyword arguments the same way as for Symbol:

    >>> A_real = IndexedBase('A', real=True)
    >>> A_real.is_real
    True
    >>> A != A_real
    True

    Assumptions can also be inherited if a Symbol is used to initialize the IndexedBase:

    >>> I = symbols('I', integer=True)
    >>> C_inherit = IndexedBase(I)
    >>> C_explicit = IndexedBase('I', integer=True)
    >>> C_inherit == C_explicit
    True
    Tc                 C   s6   |  }t|dd}||d< t|| _|| j_dS )z?Set assumptions on obj, making sure to apply consistent values.commutativeTN)copyr   getr   rY   
_generator)r9   assumptionstmp_asm_copyrs   r   r   r   r2     s
    
zIndexedBase._set_assumptionsN)offsetstridesc          
      K   s   ddl m} ddlm} t|\}}t|tr@t|fi |}nBt|trV||}n,t|||frh|S t|t	rzt
|S t
|}t|rt| }n|d urt|}|d urt| ||}	nt| |}	||	_||	_||	_t||	_t|	| |	S )Nr   r   r   )r'   r   r&   r   r	   r(   r)   r
   _merger   r   r   r   r   r1   _shape_offset_strides_namer*   r2   )
r5   labelr^   r   r   r8   r   r   r}   r9   r   r   r   r1     s2    




zIndexedBase.__new__c                 C   s   | j S r   )r   r@   r   r   r   rD     s    zIndexedBase.namec                    s   t   tt| j  S r   r:   r@   rB   r   r   r<     s    zIndexedBase._hashable_contentc                 C   s   dd | j  D S )Nc                 S   s   i | ]\}}|d ur||qS r   r   rT   r   r   r   rW     r$   z,IndexedBase.assumptions0.<locals>.<dictcomp>rX   r@   r   r   r   r3     s    zIndexedBase.assumptions0c                 K   sp   t |r>| jr(t| jt|kr(tdt| g|R i |S | jrZt| jdkrZtdt| |fi |S d S )NzRank mismatch.r%   )r   r^   r0   r   r   )rA   rG   r8   r   r   r   r     s    zIndexedBase.__getitem__c                 C   s   | j S )aU  Returns the shape of the ``IndexedBase`` object.

        Examples
        ========

        >>> from sympy import IndexedBase, Idx
        >>> from sympy.abc import x, y
        >>> IndexedBase('A', shape=(x, y)).shape
        (x, y)

        Note: If the shape of the ``IndexedBase`` is specified, it will override
        any shape information given by the indices.

        >>> A = IndexedBase('A', shape=(x, y))
        >>> B = IndexedBase('B')
        >>> i = Idx('i', 2)
        >>> j = Idx('j', 1)
        >>> A[i, j].shape
        (x, y)
        >>> B[i, j].shape
        (2, 1)

        )r   r@   r   r   r   r^     s    zIndexedBase.shapec                 C   s   | j S )a  Returns the strided scheme for the ``IndexedBase`` object.

        Normally this is a tuple denoting the number of
        steps to take in the respective dimension when traversing
        an array. For code generation purposes strides='C' and
        strides='F' can also be used.

        strides='C' would mean that code printer would unroll
        in row-major order and 'F' means unroll in column major
        order.

        )r   r@   r   r   r   r     s    zIndexedBase.stridesc                 C   s   | j S )a]  Returns the offset for the ``IndexedBase`` object.

        This is the value added to the resulting index when the
        2D Indexed object is unrolled to a 1D form. Used in code
        generation.

        Examples
        ==========
        >>> from sympy.printing import ccode
        >>> from sympy.tensor import IndexedBase, Idx
        >>> from sympy import symbols
        >>> l, m, n, o = symbols('l m n o', integer=True)
        >>> A = IndexedBase('A', strides=(l, m, n), offset=o)
        >>> i, j, k = map(Idx, 'ijk')
        >>> ccode(A[i, j, k])
        'A[l*i + m*j + n*k + o]'

        )r   r@   r   r   r   r     s    zIndexedBase.offsetc                 C   s
   | j d S )zReturns the label of the ``IndexedBase`` object.

        Examples
        ========

        >>> from sympy import IndexedBase
        >>> from sympy.abc import x, y
        >>> IndexedBase('A', shape=(x, y)).label
        A

        r   rZ   r@   r   r   r   r   5  s    zIndexedBase.labelc                 C   s   | | jS r   rf   r   rA   rh   r   r   r   ri   D  s    zIndexedBase._sympystr)N)r   r   r   rr   rs   ru   rv   staticmethodr2   r   rN   r1   rw   rD   r<   r3   r   r^   r   r   r   ri   rx   r   r   rB   r   r*   m  s,   A
!





r*   c                   @   sv   e Zd ZdZdZdZdZdZdZdZ	dddZ
edd Zedd	 Zed
d Zdd Zedd Zedd ZdS )Idxa  Represents an integer index as an ``Integer`` or integer expression.

    There are a number of ways to create an ``Idx`` object.  The constructor
    takes two arguments:

    ``label``
        An integer or a symbol that labels the index.
    ``range``
        Optionally you can specify a range as either

        * ``Symbol`` or integer: This is interpreted as a dimension. Lower and
          upper bounds are set to ``0`` and ``range - 1``, respectively.
        * ``tuple``: The two elements are interpreted as the lower and upper
          bounds of the range, respectively.

    Note: bounds of the range are assumed to be either integer or infinite (oo
    and -oo are allowed to specify an unbounded range). If ``n`` is given as a
    bound, then ``n.is_integer`` must not return false.

    For convenience, if the label is given as a string it is automatically
    converted to an integer symbol.  (Note: this conversion is not done for
    range or dimension arguments.)

    Examples
    ========

    >>> from sympy import Idx, symbols, oo
    >>> n, i, L, U = symbols('n i L U', integer=True)

    If a string is given for the label an integer ``Symbol`` is created and the
    bounds are both ``None``:

    >>> idx = Idx('qwerty'); idx
    qwerty
    >>> idx.lower, idx.upper
    (None, None)

    Both upper and lower bounds can be specified:

    >>> idx = Idx(i, (L, U)); idx
    i
    >>> idx.lower, idx.upper
    (L, U)

    When only a single bound is given it is interpreted as the dimension
    and the lower bound defaults to 0:

    >>> idx = Idx(i, n); idx.lower, idx.upper
    (0, n - 1)
    >>> idx = Idx(i, 4); idx.lower, idx.upper
    (0, 3)
    >>> idx = Idx(i, oo); idx.lower, idx.upper
    (0, oo)

    TNc                 K   s>  t |trt|dd}ttt||f\}}|jrD|js@td|S |jsTtdnt	|rt
|dkr|ttdt
| |D ]*}|jdu r|tjur|tjurtdq|t| f}nTt |tr|tjurt|jrtd	|td
|d f}n|rttdn|f}tj| g|R i |}d|jd< d|jd< |S )NT)integerzIndex is not an integer number.z%Idx object requires an integer label.   zC
                    Idx range tuple must have length 2, but got %sFz#Idx object requires integer bounds.z)Idx object requires an integer dimension.r   r%   zc
                The range must be an ordered iterable or
                integer SymPy expression.finitereal)r(   r)   r
   r-   r.   r   	is_Number
is_integerr,   r   r0   
ValueErrorr   r   InfinityNegativeInfinityr   r   r   r1   rY   )r5   r   ranger8   boundr7   r9   r   r   r   r1     s>    





zIdx.__new__c                 C   s
   | j d S )aa  Returns the label (Integer or integer expression) of the Idx object.

        Examples
        ========

        >>> from sympy import Idx, Symbol
        >>> x = Symbol('x', integer=True)
        >>> Idx(x).label
        x
        >>> j = Symbol('j', integer=True)
        >>> Idx(j).label
        j
        >>> Idx(j + 1).label
        j + 1

        r   rZ   r@   r   r   r   r     s    z	Idx.labelc                 C   s*   z| j d d W S  ty$   Y dS 0 dS )zReturns the lower bound of the ``Idx``.

        Examples
        ========

        >>> from sympy import Idx
        >>> Idx('j', 2).lower
        0
        >>> Idx('j', 5).lower
        0
        >>> Idx('j').lower is None
        True

        r%   r   Nr7   
IndexErrorr@   r   r   r   r]     s    z	Idx.lowerc                 C   s*   z| j d d W S  ty$   Y dS 0 dS )zReturns the upper bound of the ``Idx``.

        Examples
        ========

        >>> from sympy import Idx
        >>> Idx('j', 2).upper
        1
        >>> Idx('j', 5).upper
        4
        >>> Idx('j').upper is None
        True

        r%   Nr   r@   r   r   r   r\     s    z	Idx.upperc                 C   s   | | jS r   r   r   r   r   r   ri     s    zIdx._sympystrc                 C   s   | j jr| j jS t| j S r   )r   	is_SymbolrD   r)   r@   r   r   r   rD     s    zIdx.namec                 C   s   | hS r   r   r@   r   r   r   rj     s    zIdx.free_symbols)N)r   r   r   rr   r   	is_finiteis_realru   rv   rE   r1   rw   r   r]   r\   ri   rD   rj   r   r   r   r   r   H  s&   8
'



r   c                 C   sd   |j d u r|n|j }|jd u r"|n|j}| jd urD| j|kdkrDdS | j d ur`| j |k dkr`dS d S NTFr\   r]   lhsrhsZother_upperZother_lowerr   r   r   _eval_is_ge  s    r   c                 C   sD   |}|}| j d ur$| j |kdkr$dS | jd ur@| j|k dkr@dS d S r   )r]   r\   r   r   r   r   r     s    c                 C   sD   | }| }|j d ur$|j |kdkr$dS |jd ur@|j|kdkr@dS d S r   r   r   r   r   r   r     s    N)#rr   collections.abcr   sympy.core.numbersr   Zsympy.core.assumptionsr   
sympy.corer   r   r   r   sympy.core.symbolr	   r
   Zsympy.core.logicr   r   sympy.core.sympifyr   (sympy.functions.special.tensor_functionsr   Zsympy.multipledispatchr   sympy.utilities.iterablesr   r   sympy.utilities.miscr   	Exceptionr   r   r*   r   r   r   r   r   r   <module>   s0   i r \ 2

