Sympy - Rationalize all numeric values in expression? (Like Mathematica's Rationalize[])
Asked Answered
B

3

8

Is there a simple method to (attempt to) rationalize all numeric values in an expression within a given delta, much like Rationalize[] in Mathematica?

An example in Mathematica:

In[25]:= Rationalize[0.5 x^2 - 3.333333 x, 10^-4]
Out[25]= x^2/2-(10 x)/3

I see the nsimplify() function, but that seems like overkill.

Barabarabarabas answered 8/10, 2012 at 3:3 Comment(0)
O
7

I don't see how nsimplify is over kill. nsimplify does exactly what you want, because you can pass it a SymPy expression, and it will rationalize the terms in the expression

>>> print nsimplify(0.5*x**2 - 3.333333*x, tolerance=0.001, rational=True)
x**2/2 - 3333333*x/1000000

(the tolerance keyword doesn't seem to work, which I guess is a bug).

Odiliaodille answered 9/10, 2012 at 4:4 Comment(3)
Ah, I guess that rational flag does make it less overkill. I looked into the source, and I think tolerance isn't used because sympy.simplify.nsimplify() calls sympy.simplify._real_to_rational() if the rational flag is true, but does not pass any tolerance parameters. Perhaps I will play around with this to get what I want. Thank you!Barabarabarabas
If you're interested, I opened an issue for the tolerance thing: code.google.com/p/sympy/issues/detail?id=3428Odiliaodille
Awesome! I have added what I think might be the reason to your issue. I'd like to look more into it, but with work it's unfortunately not high priority (yet).Barabarabarabas
I
2

You can use Fraction.from_float:

>>> from fractions import Fraction
>>> Fraction.from_float(0.5)
Fraction(1, 2)

Even though it seems less smart than Mathematica:

>>> Fraction.from_float(3.33333333)
Fraction(7505999371444827, 2251799813685248)

It actually simply convert the float to its exact rational representation(so numbers that cannot be written exactly as floats wont be converted "correctly").

You can get more "human-readable" limiting the denominator:

>>> Fraction.from_float(3.333333333).limit_denominator(10)
Fraction(10, 3)

Even though it is trickier to understand which limit you should put to get the "correct" fraction, and it may happen that it is still impossible to obtain it due to the float representation.

If you have to stay with sympy than I don't think you can avoid using nsimplify, which seems written exactly for such purposes.

edit: from python2.7+ you can simply call Fraction(0.5) instead of using the from_float method.

Ingoing answered 8/10, 2012 at 7:5 Comment(2)
Hmm, did not realize that Python had that as a built-in module - thank you for that! I think I will play with nsimplify() as asmeurer pointed out along with implementing a simple tolerance feature using the limit_denominator() feature you pointed out.Barabarabarabas
The limit for the example above will just be 10**4.Odiliaodille
B
0

Since you are using Sympy, you also can access the pslq function from the mpmath module; this will make you able to find the most relevant linear relation between a rational number and 1:

>>> from mpmath import pslq, mpf
>>> from sympy import sympify
>>> l = pslq([ mpf('.3333333333333333333333', 1])
>>> -l[1]/sympify(l[0])
1/3
Braswell answered 25/11, 2015 at 16:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.