Have you considered using the JAX library's trick of decorating functions to provide automatic symbols?

For example, your problem could be done in current Python with an appropriately-coded library:

@symbolic def f(x, a, b, c): return a * x ** 2 + b * x + c

sentinel = Sentinel()

solve(f(sentinel, 1, 0, -1 / 2), solve_for=sentinel)

The idea is that f(sentinel) would produce the expression graph by propagating tracer objects throughout the tree. Then, solve would identify the appropriate tracer to be solved.

JAX uses this trick to accomplish three tasks: JIT compilation of mathematical expressions, automatic calculation of gradients and related functions, and automatic generation of vectorized versions of functions.

To be fair, JAX's design is brilliant. I don't fault the SymPy people for not coming up with it, but the problem that you're trying to solved could be done with a better-designed SymPy. You don't need new syntax.

Neil On Wednesday, May 19, 2021 at 2:39:18 AM UTC-4 Martin Teichmann wrote:

Hi list,

as you might have noticed, I am trying to improve the syntax and semantics for symbolic math in Python. Until now, I have to say, my ideas were not that well received, but I learned from the discussion and maybe this time I come up with something people like.

To frame the problem, let us try to solve the equation x ** 2 == 1/2 using sympy:

from sympy import Eq, solve, symbols, S x = symbols("x") solve(Eq(x**2, S(1)/2))

[-sqrt(2)/2, sqrt(2)/2]

that worked well, but actually we would like to write the last line simply as

solve(x**2 == 1/2)

as you might notice, this is fully legal Python syntax. Unfortunately the semantics is such that sympy has no way to determine what is actually going on, this is why they invented all those helper functions shown above.

My idea is now to start at the line above, "x = symbols('x')". I propose a new syntax, "symbolic x", which tells the parser that x is a symbolic variable, and expressions should not be executed, but handed over as such to the calling functions. To stay with the example, the code would look like this (this is fake, I did not prototype this yet):

from sympy import solve symbolic x solve(x**2 == 1/2)

[-sqrt(2)/2, sqrt(2)/2]

Now to the details. The scope that "symbolic" acts on should be the same as the scope of "global". Note that "symbolic x" is currently illegal syntax, so we would not even need to make "symbolic" a keyword.

Expressions that contain a symbolic variable are not executed, but instead the expression should be given to the function as a tuple, so in the example above, solve would be given ('==', ('**', ('x', 2)), ('/', 1, 2)). If that looks like LISP to you, then you are not completely wrong. The boundaries of expressions are function calls, assignments, getitems and getattrs, as they can be overloaded much easier by other means. To give an example with gory details (again, this is fake):

symbolic x d = {"a" : 5} c = 7 # not symbolic! print(c * x + d["a"])

('+', ('*', 7, 'x'), 5)

Maybe we would want to have a new class "expressiontuple" which simply acts as a pretty-printer, then the last lines would become

print(x + d["a"])

7 * x + 5

What sympy does with this tuple would be fully at its discretion.

I think that other libraries could also benefit from this proposal. As an example, in a numerics library (numpy? scipy?) one could improve numerical integration as in

symbolic x integrate(sin(x), x, 0, pi)

then the integrator could even compile the expression to machine code for faster integration.

numpy could also compile expressions to machine code, making it even faster than it is now, as in

symbolic x f = compile(5 * x + 7 * y, (x, y)) f(matrix_a, matrix_b)

Let's see how well this proposal fares.

Cheers

Martin _______________________________________________ Python-ideas mailing list -- python...@python.org To unsubscribe send an email to python-id...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python...@python.org/message/ZMUV4OUDU... https://mail.python.org/archives/list/python-ideas@python.org/message/ZMUV4OUDUX3NSROM2KRUIQKSIBUCZOCD/ Code of Conduct: http://python.org/psf/codeofconduct/