[docs]defshape(self):"""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.tensor.indexed import IndexedBase, Idx >>> from sympy import 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) """fromsympy.utilities.miscimportfilldedentifself.base.shape:returnself.base.shapetry:returnTuple(*[i.upper-i.lower+1foriinself.indices])exceptAttributeError:raiseIndexException(filldedent(""" Range is not defined for all indices in: %s"""%self))exceptTypeError:raiseIndexException(filldedent(""" Shape cannot be inferred from Idx with undefined range: %s"""%self))

[docs]classIndexedBase(Expr):"""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) """is_commutative=Falsedef__new__(cls,label,shape=None,**kw_args):ifnotisinstance(label,(basestring,Symbol)):raiseTypeError("Base label should be a string or Symbol.")label=sympify(label)obj=Expr.__new__(cls,label,**kw_args)ifis_sequence(shape):obj._shape=Tuple(*shape)else:obj._shape=sympify(shape)returnobj@property

def_hashable_content(self):returnExpr._hashable_content(self)+(self._shape,)def__getitem__(self,indices,**kw_args):ifis_sequence(indices):# Special case needed because M[*my_tuple] is a syntax error.ifself.shapeandlen(self.shape)!=len(indices):raiseIndexException("Rank mismatch.")returnIndexed(self,*indices,**kw_args)else:ifself.shapeandlen(self.shape)!=1:raiseIndexException("Rank mismatch.")returnIndexed(self,indices,**kw_args)@property

[docs]classIdx(Expr):"""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: the Idx constructor is rather pedantic in that it only accepts integer arguments. The only exception is that you can use oo and -oo to specify an unbounded range. For all other cases, both label and bounds must be declared as integers, e.g. if n is given as an argument then n.is_integer must return True. 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.tensor import IndexedBase, Idx >>> from sympy import 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) The label can be a literal integer instead of a string/Symbol: >>> idx = Idx(2, n); idx.lower, idx.upper (0, n - 1) >>> idx.label 2 """is_integer=Truedef__new__(cls,label,range=None,**kw_args):fromsympy.utilities.miscimportfilldedentifisinstance(label,basestring):label=Symbol(label,integer=True)label,range=map(sympify,(label,range))ifnotlabel.is_integer:raiseTypeError("Idx object requires an integer label.")elifis_sequence(range):iflen(range)!=2:raiseValueError(filldedent(""" Idx range tuple must have length 2, but got %s"""%len(range)))forboundinrange:ifnot(bound.is_integerorabs(bound)isS.Infinity):raiseTypeError("Idx object requires integer bounds.")args=label,Tuple(*range)elifisinstance(range,Expr):ifnot(range.is_integerorrangeisS.Infinity):raiseTypeError("Idx object requires an integer dimension.")args=label,Tuple(0,range-1)elifrange:raiseTypeError(filldedent(""" The range must be an ordered iterable or integer SymPy expression."""))else:args=label,obj=Expr.__new__(cls,*args,**kw_args)returnobj@property