
On Sat, 15 May 2021 at 09:55, Steven D'Aprano <steve@pearwood.info> wrote:
On Sat, May 15, 2021 at 07:14:47AM -0000, Martin Teichmann wrote:
In general, doing symbolic math in Python is not very beautiful. [...] It could be fruitful to add syntax for symbolic math, but this is a whole new topic. Looking around there also seems to be not much out there, even dedicated languages like mathematica are honestly pretty ugly.
I think that is unavoidable.
Symbolic maths is a 2D format. It doesn't map easily to a line-based format like programming languages. Think of things like summation and integration. You need subscripts, superscripts and a two dimensional layout of expressions.
SymPy in particular has the property that it is implemented within Python and is (often) used from Python so for most users there is no separation between the user-language and the language of implementation and that constrains what it can provide syntactically. This is both a strength and a weakness. The strength is that power users can use a powerful programming language as part of symbolic manipulation and can build their own primitive routines, subclass the basic types etc. The weaknesses are things like not being able to make 1/2 be an exact rational. Of course SymPy is also a library rather than an application and is used as the backend for many different symbolic applications and has bindings to other languages so there are also users who use sympy from e.g. Julia or Octave which use the syntax from those languages so e.g. you can do something like 2x rather than 2*x in Julia. SymPy is also used internally as part of Sage which is an application that has a Python-like syntax but with changes like 1/2 being exact and 2^3 being the same as 2**3. There are also projects like Mathics which is a Python project based on SymPy that implements the Mathematica language. The issue with float and SymPy is not just about division of ints though because it's also very common for users to write things like 0.5*m*v**2 without realising that using 0.5 creates a float and that SymPy will treat that float differently from an exact rational. This is partly a problem of SymPy's own making and it can be at least partially solved in SymPy though. In an expression like 0.5*m where m is a SymPy expression __rmul__ will call sympify which converts the builtin float to SymPy's symbolic Float type. The majority of users would be better served if the sympify function would actually convert the float to an exact Rational and it would be possible to provide a mode that can do that like: import sympy sympy.init_session(auto_float_to_rational=True) SymPy already has a function that can do this and that can also undo the rounding errors caused in decimal to binary conversion for expressions like 0.1:
from sympy import nsimplify nsimplify(0.1) 1/10
Actually this function goes a bit too far so a more limited form of it should probably be used:
from math import e e 2.718281828459045 nsimplify(e) E nsimplify(2**0.5) sqrt(2)
So I don't think changes in Python core are needed for this use case as the basic issue can be fixed in SymPy itself. -- Oscar