Simplifying large coefficients in SymPy - python

I use SymPy for symbolic calculations in Python and get e.g. an expression like
Z = 2.02416176758139e+229 / (2.42579446609411e+232 * s + 9.8784848517664e+231)
Is there a function in SymPy (e.g. in sympy.simplify?) to get something like
Z = 2.024 / (2425.8 * s + 987.8)

The intent of your request can be met by allowing cancellation:
>>> 1/(1/Z)
1/(1198.41926912424*second + 488.028427864731)
or
>>> factor(Z)
0.00083443251102827/(1.0*second + 0.407226786516346)
But there is no built-in method of accessing the exponent in an exponential form.

Related

Solving algebra equations in python

I'm new to programming and I'm having a hard time solving this equation using Python.
I would like for the system to give me the value for X.
((X-5)/(2) + (X/4) + (X-12)/(3))
Sympy looks promising, especially section 3.2.4, "Equation Solving".
Assuming your right hand side of equation is some given value or expression:
import sympy as sym
x = sym.Symbol("x")
RHS = 13
LHS = (x - 5)/2 + x/4 + (x - 12)/3
eqn = LHS - RHS
soln = sym.solve(eqn, x)
print(soln)
This yields the solution x = 18. Replace RHS with your own value or expression. If there is nothing, simply put RHS to be 0; which gives the solution x = 6.
If you want to solve your equation step by step, you are still going to need SymPy:
https://docs.sympy.org/latest/install.html

Sympy: There remains some terms which shuold be obviously vanished

I want to calculate derivative of a function using following code.
import sympy
pi = sympy.symbols("pi")
class H(sympy.Function):
nargs = 1
def fdiff(self, argindex=1):
x = self.args[0]
return - sympy.functions.exp(-sympy.Pow(x, 2) / 2) / sympy.sqrt(2 * pi)
def G(a):
return (
(a + 1) * H(1 / sympy.sqrt(a))
- sympy.sqrt(a / (2 * pi)) * sympy.functions.exp(-1 / (2 * a))
)
x = sympy.symbols("x")
sympy.simplify(sympy.diff(G(x), x))
It is expected to be G'(x) = H(1 / sqrt(x)), but I got
Out[1]: H(1/sqrt(x)) - sqrt(2)*sqrt(x/pi)*exp(-1/(2*x))/(4*x) - sqrt(2)*sqrt(x/pi)*exp(-1/(2*x))/(4*x**2) + sqrt(2)*exp(-1/(2*x))/(4*sqrt(pi)*sqrt(x)) + sqrt(2)*exp(-1/(2*x))/(4*sqrt(pi)*x**(3/2))
The remaining terms should obviously be 0 when seen by human eye.
Then I tried to change two pis in the definition of H and G to sympy.pi, which returns H(1 / sqrt(x)) as I expected.
Why my first code returns some extra terms?
SymPy has built in rules which allow certain transformations to happen (automatically, sometimes) or to be prohibited (by default). When you defined pi as a Symbol, you created a generic symbol with the only assumption being that it is commutative. But the number pi is that and it is positive. That assumption allows something like sqrt(x/y) to automatically rewrite as sqrt(y)*sqrt(x)/y if y is positive:
>>> sqrt(x/y)
sqrt(x/y)
>>> sqrt(x/3)
sqrt(3)*sqrt(x)/3
If you take your last expression and substitution a positive value for the symbol pi you will get that rewrite and then the cancelling terms will cancel.
>>> print(sympy.simplify(sympy.diff(G(x), x))).subs(pi, 3)
H(1/sqrt(x))
As Johan points out, it is better in this case to just use SymPy's S.Pi:
>>> S.Pi.n(3)
3.14

Obtaining coefficients of complex expressions in sympy

I have a relatively simple complex sympy expression which one can easily read the coefficients off of the variables. However coeff function does not appear to be working correctly
import sympy as sp
a,b = sp.symbols("a, b")
expr = 2640.0*a - 4.5*(1 + 1j)*(264.0*a + 264.0*b) - 4.5*(+1 - 1j)*(264.0*a + 264.0*b)
print(expr.coeff(a))
> 2640.00000000000
print(sp.simplify(expr))
> 264.0*a - 2376.0*b
I would expect the output of expr.coeff(a) to return 264.0 but it clearly isnt? Any help is appreciated.
coeff gives coefficients of the expression at the top level. If you use expand before looking for the coefficient then you will get the mathematical (not expression-dependent-literal) coefficient. If you know the expression is linear in the symbol of interest, you could also differentiate once:
>>> expr.diff(a)
264.000000000000
>>> expr.expand().coeff(a)
264.000000000000
Poly automatically expands expressions and allows queries for monomials, too:
>>> Poly(expr).coeff_monomial(a)
264.000000000000
Your first expression has 2640.0 as the coefficient of a. As you can see, the coefficient becomes zero only after simplifying it. Indeed, if you print the coefficient after simplifying the expression, you get 264.0
import sympy as sp
a,b = sp.symbols("a, b")
expr = 2640.0*a - 4.5*(1 + 1j)*(264.0*a + 264.0*b) - 4.5*(+1 - 1j)*(264.0*a + 264.0*b)
print(expr.coeff(a))
# 2640.00000000000
print(sp.simplify(expr))
# 264.0*a - 2376.0*b
print(sp.simplify(expr).coeff(a)) # <--- Simplified expression
# 264.000000000000

Sympy's subs limitations

I am working with some long equations but not really complex, and I wanted to use sympy to simplify and "factorize" them. But I have encountered a few problems. Here is a list of some minimal examples:
Problem 1: symmetry
from sympy import *
from __future__ import division
a = symbols('a')
b = symbols('b')
expr = 1/12*b + 1
expr.subs(1/12*b, a)
expr.subs(b*1/12, a)
The first line gives the expected result (ie. a+1) while in the second one there is no substitution.
Problem 2: factorized expressions
Some parts of the expression are factorized and when I expand the expression they get simplified, thus making the substitution impossible. For example
(((x+1)**2-x).expand()).subs(x**2+2*x, y+1)
will give x^2+x+1 and what I am looking for is y+2-x.
Question
Is there a way to solve these problems ? Or maybe I should use another symbolic mathematical tool ? Any suggestions are welcomed.
There is a major gotcha in SymPy, which is that, because of the way Python works, number/number gives a floating point (or does integer division if you use Python 2 and don't from __future__ import division).
In the first case and in your original expression, Python evaluates 1/12*b from left to right. 1/12 is evaluated by Python to give 0.08333333333333333, which is then multiplied by b. In the second case, b*1 is evaluated as b. Then b/12 is evaluated by SymPy (because b is a SymPy object), to give Rational(1, 12)*b.
Due to the inexact nature of floating point numbers, SymPy does not see the float 0.08333333333333333 as equal to the rational 1/12.
There is some more discussion of this issue here. As a workaround, you should avoid direct integer/integer without wrapping it somehow, so that SymPy can create a rational. The following will all create a rational:
b/12
Rational(1, 12)*b
S(1)/12*b
For (((x+1)**2-x).expand()).subs(x**2+2*x, y+1) the issue is that x**2 + 2*x does not appear exactly in the expression, which is x**2 + x + 1. SymPy generally only replaces things that it sees exactly.
It seems you don't mind adding and subtracting an x to make the replacement work. So I would suggest doing instead (((x+1)**2-x).expand()).subs(x**2, y+1 - 2*x). By only substituting a single term (x**2), the substitution will always work, and the 2*x will cancel out to leave whatever x term remains (in this case, -x).
Here's a possible solution to your problems:
from sympy import *
a = symbols('a')
b = symbols('b')
expr = 1 / 12 * b + 1
print(expr.subs((1 / 12) * b, a))
print(expr.subs(b * (1 / 12), a))
x = symbols('x')
y = symbols('y')
expr = ((x + 1)**2 - x).expand()
print(expr.subs(x**2 + x, y - x + 1))
Regarding problem 1, note that 1/12*b and b*1/12 are not the same thing in sympy. The first is a floating number mutliplied by a symbol, whereas the second is an exact symbolic expression (you can check it out by a simple print statement). Since expr contains 1/12*b, it is not surprising that the second subs does not work.
Regarding problem 2, the subs rule you provide is ambiguous. In particular the substitution rule implies that equation x**2+2*x==y+1. However, this equation has many interpretations, e.g,
x**2 == y + 1 - 2*x (this is the one you consider),
x**2 + x == y + 1 - x,
x == (y + 1 - x**2)/2,
For this reason, I consider sympy refusing to perform a substitution is actually a correct approach.
If it is the first interpretation you want, it is better to explicitly provide it in the subs rule, i.e.,
(((x+1)**2-x).expand()).subs(x**2, -2*x + y + 1)
-x + y + 2

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

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?
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)
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)

Categories