Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I replace floats with rationals in a sympy expression?

Tags:

python

sympy

I have an expression from a sympy calculation:

sqrt(pi)*(0.333333333333333*a + 0.333333333333333*b - 2.66666666666667*c**2)

where a,b,c are symbols, and would like to parse it so that the floats are replaced with rationals like in

sqrt(pi)*(1/3*a + 1/3*b - 8/3*c**2)

I know how to do one by hand,

In[24] Rational(str(0.333333333333333)).limit_denominator(1000)

Out[24]: 1/3

but do not quite know how to go about parsing the atoms and picking only the ones that are floats, and substituting back the rational number approximation.

What is the smartest way of doing these substitutions in the expression?

like image 641
acortis Avatar asked Jan 08 '14 19:01

acortis


People also ask

How can I substitute SymPy?

The subs() function in SymPy replaces all occurrences of the first parameter with the second. Substitution is the basic operations that must be performed in a mathematical expression. In this way, we can use subs() function in sympy.

What is SymPy Rational?

SymPy has the numeric types Rational and RealNumber . The Rational class represents a rational number as a pair of two integers: the numerator and the denominator, so Rational(1,2) represents 1/2 , Rational(5,2) represents 5/2 and so on.

Are floats Rational?

A float is a rational number expressed in floating-point format, usually to base 10 or decimal.

How do you evaluate an expression in SymPy?

evalf() function and subs() function from sympy is used to evaluate algebraic expressions. Example 1: In this example, we import symbols from sympy package. An expression is created and evalf() function is used to evaluate the expression.


2 Answers

Use nsimplify:

>>> print(nsimplify(sqrt(pi)*(0.333333333333333*a + 0.333333333333333*b - 2.66666666666667*c**2)))
sqrt(pi)*(a/3 + b/3 - 8*c**2/3)
like image 76
asmeurer Avatar answered Oct 23 '22 12:10

asmeurer


After a bit of fiddling, I think I have found a way to do it, but I am not sure that it will cover all the corner cases. At any rate here it is. Any suggestions for improvement?

import sympy
def rationalize_coeffs(expr):
    for i in expr.atoms(sympy.Float):
        r = sympy.Rational(str(i)).limit_denominator(1000)
        expr = expr.subs(i, r)
    return expr    

if __name__=='__main__':
    # given a sympy expression expr
    x,y,z = sympy.symbols('x y z')
    # expr_orig = 2/57.*x + 3./4.*y + 3./4.*z
    expr = 0.0350877192982456*x + 0.75*y + 0.75*z

    print rationalize_coeffs(expr)
like image 37
acortis Avatar answered Oct 23 '22 12:10

acortis