indexed symbols

33 views
Skip to first unread message

Thomas Ligon

unread,
Feb 11, 2021, 6:19:51 AM2/11/21
to sympy
I am writing code that needs symbols of which the number is not a priori known. To do that, I have used code like this:

    for ind in range(0,2*maxIter+1):
        strSym = 'a' + str(ind) + ' = symbols(\'a_' + str(ind) + '\')'
        exec(strSym, globals())

The code is not easy to read, and in Issue 20825 Oscar Benjamin suggested that I use indexed symbols:

"The solution to this in Python is to use lists or tuples or some other container rather than raw variables. For example:

x = symbols('x:10')"

Based on that, and 
I am trying to use indexed symbols.

a = symbols('a:2*maxIter+1')

The result is

 (a0*maxIter+1, a1*maxIter+1)

The problem is that symbols does not support variables after the colon, defeating the whole purpose of using indexed symbols to begin with.

Oscar Benjamin

unread,
Feb 11, 2021, 7:22:12 AM2/11/21
to sympy
On Thu, 11 Feb 2021 at 11:19, Thomas Ligon <thomas...@gmail.com> wrote:
>
> "The solution to this in Python is to use lists or tuples or some other container rather than raw variables. For example:
>
> x = symbols('x:10')"
>
> Based on that, and
> Core — SymPy 1.7.1 documentation
>
> a = symbols('a:2*maxIter+1')
>
> The result is
>
> (a0*maxIter+1, a1*maxIter+1)
>
> The problem is that symbols does not support variables after the colon, defeating the whole purpose of using indexed symbols to begin with.

You can use the features of the Python language to generate the string
as input to the symbols function:

>>> num_symbols = 10

This is using %-formatting of strings:

>>> 'x:%d' % num_symbols
'x:10'
>>> symbols('x:%d' % num_symbols)
(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9)

This is using f-strings:

>>> f'x:{num_symbols}'
'x:10'
>>> symbols(f'x:{num_symbols}')
(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9)

> I am trying to use indexed symbols.

Note that "indexed symbols" means something different in sympy e.g.:

>>> from sympy import IndexedBase
>>> x = IndexedBase('x')
>>> x
x
>>> x[0]
x[0]

IndexedBase represents a mathematical quantity that can be subscripted
but in a symbolic way. For example if I have some data points that I
refer to as x_1, x_2, etc. and I want to refer to x_i then I can use
IndexedBase and index it with a symbol.

Oscar

Aaron Meurer

unread,
Feb 11, 2021, 2:30:30 PM2/11/21
to sympy
Another option here is numbered_symbols(), which returns a generator
which produces any number of numbered symbols. It's also useful in
conjunction with the take() function:

>>> gen = numbered_symbols('a')
>>> n = 10
>>> take(gen, n)
[a0, a1, a2, a3, a4, a5, a6, a7, a8, a9]

In general, if you want to create symbols in complicated ways that
doesn't match the convenience methods of symbols(), you may be better
of generating them manually using the Symbol constructor and a list
comprehension or an explicit for loop:

>>> [Symbol("a%d" % i) for i in range(n)]
[a0, a1, a2, a3, a4, a5, a6, a7, a8, a9]

Aaron Meurer
> --
> You received this message because you are subscribed to the Google Groups "sympy" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to sympy+un...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/CAHVvXxRCL%3D2cQKoGTJjUos6onXEWAujitgDwZaY3Ohhn2ONmvA%40mail.gmail.com.

Thomas Ligon

unread,
Feb 14, 2021, 1:15:46 PM2/14/21
to sympy
Many thanks for the remarks. Together, I see the possibility to improve the readability (and maybe the performance) of my code in two ways:
1) If I can get rid of the exec statements, the code will be much easier to read.
2) By using two symbols for each variable, I can improve the readability and maybe the performance. Specifically, I want to define one symbol that is exactly the same on the LHS and the RHS of symbols, then a second symbol where the RHS is a LaTeX format.
For example
Sicj means S suffix i comma j. Sicj will be used in expressions and SicjL will be used (only) for printing.
Here are some code attempts:
    for ind in range(1,maxIter+1):
        for ind2 in range(1,maxIter+1):
            strSym = f'S{ind}c{ind2} = symbols(\'S{ind}c{ind2}\')'
            exec(strSym, globals())
            #strSym = f'S{ind}c{ind2}L = symbols(\'S_{{ind}\\,{ind2}}\')'
            strSym = 'S%dc%dL = symbols(\'S_{%d\\,%d}\')' % (ind,ind2,ind,ind2)
            exec(strSym, globals())
Remarks:
I didn't get any of the suggestions working for two indices. It looks like the colon in symbols always introduces one number which is always at the end of the expression.
As a result, I didn't find a way to eliminate the exec statements for symbols with two indices.
strSym = f'S{ind}c{ind2}L = symbols(\'S_{{ind}\\,{ind2}}\')'  leads to an error, and I didn't find a way to use { and } to refer to Python string manipulation and LaTeX string manipulation without getting a conflict. 
Reply all
Reply to author
Forward
0 new messages