8

I don't understand what indexed objects in sympy are for. The documentation didn't help me understand the concept much.

For instance :

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

What does this code do? What is M[i,j]?

All I understand is that an indexed object gives indices to individual sympy symbols .

I'm looking for a better explanation of indexed objects , along with it's relation to IndexedBase and idx

mjsxbo
  • 2,116
  • 3
  • 22
  • 34
  • In this case you could think of `M` as a 2D array and `i, j` would be row/column indices into that array. Therefore the result of `M[i, j]` would be a single value – Cory Kramer Jan 27 '18 at 18:51
  • @CoryKramer I see. So when we create M, what are the initial values of the elements? Also, why do we create such an object? What is the point of doing this? – mjsxbo Jan 27 '18 at 18:55

2 Answers2

11

One-line explanation: they represent a symbolic array of undetermined, possibly infinite, size.

Suppose you want to work with n symbols, how would you do that? Easy enough if n is a given number, like 10. But it's just n, an unspecified integer number. Formulas like that appear in mathematics all the time: "add or multiply (something) over the indices i=1, ..., n".

For example, suppose I have a function in n-dimensional space Rn, such as f(x) = 1/distance(x, 0). The distance is, of course, the square root of the sum of squares of coordinates. And maybe I want to find some partial derivative of f. How to express all of this in SymPy? Like this:

from sympy import *
x = IndexedBase('x')
j, k, n = symbols('j k n', cls=Idx)
f = 1/sqrt(Sum(x[k]**2, (k, 1, n)))
print(f.diff(x[j]))

This computes the derivative of f with respect to the coordinate x[j]. The answer is

-Sum(2*KroneckerDelta(j, k)*x[k], (k, 1, n))/(2*Sum(x[k]**2, (k, 1, n))**(3/2))

which is correct (although perhaps the numerator could be simplified if we assume that j is in the range 1..n).

In the above example, x[j] is the coordinate with index j. In your example, M[i, j] could be the entry of some matrix at position i, j.

  • M is the name of symbolic array, its class is IndexedBase
  • i and j are indices of that array, their class is Idx

The above are the classes that you would instantiate yourself. The class of M[i, j] is Indexed but you don't create those objects by using class name, M[i, j] simply does that.

Two recent questions with examples of working with indexed objects:

  • Could you also explain what the difference is between setting `cls=Idx` and just setting `integer=True`? The latter also seems to work, only that it displays nicer in sums and products while the former displays an ugly Idx(i). – nikozoe Jun 10 '22 at 10:46
2

Indexed is primarily used for two use-cases:

  1. Formulas with symbolic subscripts. For example, \sum_{i=1}^n a_i. You could just use Symbol('a_i'), but them the i is not symbolic and in any way related to Symbol('i'). So for instance, Sum(a_i, (i, 1, n)) will just give you n*a_i. Instead IndexedBase('a')[i] represents a different symbol for every value of i, and Sum(IndexedBase('a')[i], (i, 1, n)) effectively represents the above summation.

  2. N-d arrays. This is especially useful for code generation, because the SymPy code printers for languages like C or Fortran will print Indexed objects as array lookups automatically, for instance

    >>> a = IndexedBase('a')
    >>> i = Idx('i', (1, n))
    >>> ccode(a[i])
    'a[i]'
    >>> fcode(a[i])
    '      a(i)'
    

    This makes it very easy to write array-based code symbolically using SymPy and generate fast code that computes it.

asmeurer
  • 86,894
  • 26
  • 169
  • 240