RobotLocomotion / drake

Model-based design and verification for robotics.
https://drake.mit.edu
Other
3.25k stars 1.25k forks source link

Conversion between SymPy and pydrake.symbolic.Polynomial #20995

Open AlexandreAmice opened 6 months ago

AlexandreAmice commented 6 months ago

Is your feature request related to a problem? Please describe. This is a followup to #20076. It would be nice to have first class support to convert between SymPy Polynomials and pydrake.symbolic.Polynomial.

Note that currently this is not possible. Consider the following code.

x_sympy = sympy.var("x")
x_drake = drake_sym.Variable("x")
x_drake_to_sympy = {x_drake.get_id(): x_sympy}
x_sympy_to_drake = {x_sympy: x_drake.get_id()}

drake_poly = drake_sym.Polynomial(x_drake**2 - 2 * x_drake + 1)
sympy_poly = drake_sym.to_sympy(
    drake_poly.ToExpression(), memo=x_drake_to_sympy
).as_poly()

The result is that sympy_poly has generators x and x**2. The reason for this is that drake_sym.to_sympy(drake_poly.ToExpression(), memo=x_drake_to_sympy) has in its expression tree:

Pow(Symbol('x'), Float('2.0', precision=53)

Since the exponent of x**2 is a Float and not an Integer, then Sympy cannot cast it to a polynomial properly.

Describe the solution you'd like Ideally we can write the above code as:

drake_poly = drake_sym.Polynomial(x_drake**2 - 2 * x_drake + 1)
sympy_poly = drake_sym.to_sympy(drake_poly, memo=x_drake_to_sympy)

and avoid all the casting back and forth between the expressions.

At the very least, drake's ExpressionKind::Pow should be converted to sympy's Pow(x, Integer(*)) rather than Pow(x, Float(*)) whenever possible.

jwnimmer-tri commented 6 months ago

+@AlexandreAmice would you like this assigned to you? If not that's fine -- you can re-assign over to @hongkai-dai for safekeeping.