Sympy: There remains some terms which shuold be obviously vanished - python

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

Related

Python float operations give complex result

eq = (((1 - (2 * normal_rpm - s8) ** s1) * s2 * math.sin(normal_rpm ** s3 / s4) * (1 - math.sin((normal_rpm + s5) ** (2) + 5) + s6) / (s7))) + 0.67
is my formula for this variable, where the S variables are floats. this sometimes returns a result like this
(0.6806708980989302+0.008606807113252896j)
I cannot use this result in further math, I need a float, even if I have to round the answer a bit.
This is not a rounding problem, but you are raising a negative number to a fractional exponent (e.g. you're taking the square root of -5).
For example:
In [2]: (-5)**0.5
Out[2]: (1.3691967456605067e-16+2.23606797749979j)
If you cannot accept complex numbers as result then the only other logical way out is to raise an error when this happens (there is no real number that multiplied by itself gives, or gets near, -5).
If this is not expected you should double-check the formula or formulas preceding it because may be there is a typo, or may be there are some preconditions you need to check before applying this formula.

Computing Riemann-Liouville Integral using Sympy

New to calculus and not sure where this goes...
I'm trying to compute the Riemann-Liouville interpretation of the integral in Python using sympy. However the resulting integral when running my code between 0 and T contains T as a variable, which I do not want. What should I do to fix this?
Code:
def integral(f, order):
gamma_recip = 1/gamma(order)
T = sympy.Symbol('T')
r = sympy.Symbol('r')
eq = (T-r) ** order - 1
function_eq = eq * f(r)
integral = sympy.integrate(function_eq, (r, 0, T))
return integral
Equation:
Sample call as requested:
-0.333333333333333*T**3 + 0.0833333333333333*T**4.0
Function and order used:
def f(x):
return x**2
print(integral(f, 1.0))
Expected result:
r**3/3
Two issues:
you are using "T" as the integral limit so you will end up with that in the result; if you want "r" in the result, swap the use of T and r in your function
you didn't put parentheses around the order - 1 in your definition of eq; if you do you will (with your current code) get the expected T**3/3

Simplifying large coefficients in SymPy

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.

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

Order of operations and fast computation in Python

I am trying to optimize a Python code where the following mathematical function has to be evaluated many (many) times
from math import pow, pi
from scipy.special import gamma
def norm_spirals(a,k):
return pi*pow(abs(gamma(0.25+0.5*k+0.5j*a)/gamma(0.75+0.5*k+0.5j*a)),2)
I have already optimized as much as possible my code using cProfile and timeit. I also got rid of the call to the procedure and direcly embedded this calculation in the code. The last step of optimization I could think of, is to tune the order of the mathematical operations in order to accelerate the evaluation. The formula above is the fastest form that I have been able to obtain using timeit.
Would you think of another order of calculation for this formula that could be faster ?
Would you have any ideas of other optimizations I could use ?
Thank you in advance for your help !
Here are four simple transformations to speed-up your code:
1) Replace pow(x, 2) with x ** 2.0:
def norm_spirals(a,k):
return pi* abs(gamma(0.25+0.5*k+0.5j*a)/gamma(0.75+0.5*k+0.5j*a)) ** 2.0
2) Factor-out the common subexpression: 0.25+0.5*k+0.5j*a
def norm_spirals(a,k):
se = 0.25 + 0.5*k + 0.5j*a
return pi * abs(gamma(se)/gamma(se + 0.5)) ** 2.0
3) Localize the global lookups:
def norm_spirals(a,k, pi=pi, abs=abs, gamma=gamma):
se = 0.25 +0.5*k + 0.5j*a
return pi * abs(gamma(se)/gamma(se + 0.5)) ** 2.0
4) Replace the square operation with b * b. This is called strength reduction:
def norm_spirals(a,k, pi=pi, abs=abs, gamma=gamma):
se = 0.25 + 0.5*k + 0.5j * a
b = abs(gamma(se)/gamma(se + 0.5))
return b * b * pi
I get it 15% faster (python 2.7) by introducing a temp var and remove the call to pow:
def norm_spirals(a, k):
_ = 0.5 * k + 0.5j * a
return pi * abs(gamma(0.25 + _) / gamma(0.75 + _)) ** 2
For python 3 the gain was just 11%.
Disclaimer:
I didn't have scipy installed so for gamma I used
def gamma(a):
return a
So "15% faster" might be a bit misleading.
If norm_spirals() is invoked many times with the same arguments, then you can try memoization to cache the results and see if it makes a difference.

Categories