Replace `exp(I*pi)` with `-1` in SymPy expression - python

When using sympy to integrate an expression often there is exp(I*pi) somewhere in the result:
from sympy.functions import *
from sympy import *
init_printing(use_latex=False, use_unicode=False)
shift = Symbol('shift', real=True, positive=True)
x = Symbol('x', real=True, positive=True)
p = Symbol('p', real=True)
expr = integrate(exp(-p)/(p+shift), (p, x, oo))
expr
/ / / I*pi\ / I*pi\ \
| |log\(shift + x)*e / - Ei\(shift + x)*e / EulerGamma|
|(shift + x)*|---------------------------------------------- + ----------| - l
\ \ shift + x shift + x /
\
| shift
og(shift + x) - EulerGamma|*e
/
But it is known that exp(I*pi) == -1. And it is inconvenient to have complex numbers in expression that intended to be real. Is it possible to replace somehow exp(I*pi) with -1 in expression? I have tried simplify() and subs(exp(I*pi), -1). Neither the first nor the second helps.

The special printing directive is hiding what you really have. It isn't exp(I*pi) it is polar_exp(I*pi). If you print(expr) you will see this:
((shift + x)*((log((shift + x)*exp_polar(I*pi)) - Ei((shift +
x)*exp_polar(I*pi)))/(shift + x) + EulerGamma/(shift + x)) - log(shift
+ x) - EulerGamma)*exp(shift)
Replacing with .subs(exp_polar(I*pi), -1) will work...but you should read up about polar_lift and exp_polar to understand what it is telling you and what you should be aware of when making that replacement.

Related

How to integrate expressions with sympy?

I have a problem integrating an expression:
I need to integrate all terms regardless of the variable,
the expression: -x + 2 * (x - 1)
Expected result: -x**2/2 + 2 * ((x - 1)**2) / 2
the code I'm using:
from sympy import *
x = symbols('x')
expr = - x + factor(2 * (x - 1))
int_1 = integrate(expr)
print(int_1)
generated result: x**2/2 - 2*x
I'm a python beginner...
Thank you!
If you check your result you will find it is the same as the original equation, so the answer is right:
>>> eq = -x + factor(2 * (x - 1))
>>> integrate(eq).diff()
x - 2
>>> eq.expand()
x - 2
This means that the result you got differed from the expected results by a constant and such cases are considered correct in terms of indefinite integration.
It looks like you already learned about autoexpansion (thus the use of factor to keep the 2 from distributing). What you may not realize, however, is that once you pass an expression to a routine it is not required to keep your expression in factored form. It looks like you were expecting that the x - 1 would be treated like x. We can simulate that as
>>> integrate(-x)+integrate(2*y).subs(y,x-1)
-x**2/2 + (x - 1)**2
Using y to represent x - 1 is ok in this case since the results only differ by a constant:
>>> (integrate(x-1) - integrate(y).subs(y ,x-1)).is_constant()
True
It will not, however, be true for all functions of x.
The problem is that you didn't pass any integration limits (from and to), so the only possible answer was the integrated formula.
If for example you want to integrate from 0 to inf, you need to pass this instead
from sympy import *
x = symbols('x')
expr = - x + factor(2 * (x - 1))
int_1 = integrate(expr, (x,0, float('inf')))
print(int_1)
replace 0 and/or float('inf') by any numbers you want to evaluate.

Why doesn't SymPy simplify the expression?

I am just looking at the Python module SymPy and try, as a simple (useless) example the fit of a function f(x) by a function set g_i(x) in a given interval.
import sympy as sym
def functionFit(f, funcset, interval):
N = len(funcset) - 1
A = sym.zeros(N+1, N+1)
b = sym.zeros(N+1, 1)
x = sym.Symbol('x')
for i in range(N+1):
for j in range(i, N+1):
A[i,j] = sym.integrate(funcset[i]*funcset[j],
(x, interval[0], interval[1]))
A[j,i] = A[i,j]
b[i,0] = sym.integrate(funcset[i]*f, (x, interval[0], interval[1]))
c = A.LUsolve(b)
u = 0
for i in range(len(funcset)):
u += c[i,0]*funcset[i]
return u, c
x = sym.Symbol('x')
f = 10*sym.cos(x)+3*sym.sin(x)
fooset=(sym.sin(x), sym.cos(x))
interval = (1,2)
print("function to approximate:", f)
print("Basic functions:")
for foo in fooset:
print(" - ", foo)
u,c = functionFit(f, fooset, interval)
print()
print("simplified u:")
print(sym.simplify(u))
print()
print("simplified c:")
print(sym.simplify(c))
The result is the fit function u(x), to be returned, together with the coefficients by functionFit.
In my case
f(x) = 10 * sym.cos(x) + 3 * sym.sin(x)
and I want to fit it according to a linear combination of sin(x), cos(x).
So the coefficients should be 3 and 10.
The result is OK, but for u(x) I get
u(x) = (12*sin(2)**2*sin(4)*sin(x) + 3*sin(8)*sin(x) + 12*sin(2)*sin(x) + 40*sin(2)**2*sin(4)*cos(x) + 10*sin(8)*cos(x) + 40*sin(2)*cos(x))/(2*(sin(4) + 2*sin(2))) :
Function to approximate: 3*sin(x) + 10*cos(x)
Basic functions:
- sin(x)
- cos(x)
Simplified u: (12*sin(2)**2*sin(4)*sin(x) + 3*sin(8)*sin(x) + 12*sin(2)*sin(x) + 40*sin(2)**2*sin(4)*cos(x) + 10*sin(8)*cos(x) + 40*sin(2)*cos(x))/(2*(sin(4) + 2*sin(2)))
Simplified c: Matrix([[3], [10]])
which is indeed the same as 10 * cos(x) + 3 * sin(x).
However I wonder why it is not simplified to that expression. I tried several simplifying function available, but none of it gives the expected result.
Is there something wrong in my code or are my expectations to high?
Don't know if this is a solution for you, but I'd simply use the .evalf method of every Sympy expression
In [26]: u.simplify()
Out[26]: (12*sin(2)**2*sin(4)*sin(x) + 3*sin(8)*sin(x) + 12*sin(2)*sin(x) + 40*sin(2)**2*sin(4)*cos(x) + 10*sin(8)*cos(x) + 40*sin(2)*cos(x))/(2*(sin(4) + 2*sin(2)))
In [27]: u.evalf()
Out[27]: 3.0*sin(x) + 10.0*cos(x)
In [28]:

How to get all the possible forms x=p(x) of equation f(x)=0

x**3-2*x-5=0
To the following forms [x = p(x)] where p(x) is continuously differentiable:
x=5/(x**2-2)
x=(2*x+5)**(1/3)
x=(x**3-5)/2
Given an expression, such as expr = x**3-2*x-5, assumed to be zero, one can form an equation x = p(x) in many ways. The simplest is to add x to both sides: Eq(x, expr + x).
This prints as one would expect: pprint(Eq(x, expr + x)):
3
x = x - x - 5
A couple of more interesting rewrites:
Iteration for Newton method: Eq(x, simplify(x - expr/diff(expr, x)))
3
2⋅x + 5
x = ────────
2
3⋅x - 2
Isolating the leading term on one side and taking a root:
p = poly(expr)
Eq(x, (LM(p) - expr)**(1/degree(p)))
3 _________
x = ╲╱ 2⋅x + 5
This is rough solution only..
from sympy import *
import numpy as np
var('x')
expr=sympify('x**3-2*x-5')
p = poly(expr);
p1=factor(p-(p).coeff_monomial(1))
for i in p1.args:
if (poly(i).is_monomial):
z=(np.prod([j for j in p1.args if j!=i]))
p2=(-(p).coeff_monomial(1)/z)**(1/degree(i));
v=i.coeff(x)
if p2:print(p2)
elif v:
p2=(-z/v)
print(p2)
for i in (p.all_terms())[:-1]:
if i[1]:
p3= ((i[1]*x**i[0][0]-expr)/i[1])**(1/Integer(i[0][0])) ;print(p3);
'''o
5/(x**2 - 2)
(2*x + 5)**(1/3)
x**3/2 - 5/2
'''

How to do "inverse" substitution in sympy?

I need to find and substitute subexpression with a symbol, doing an "inverse" substitution of sorts.
Here is direct substitution example:
(simplify and collect added to make the resulting expression have the form that I need to work with)
In [1]: from sympy.abc import a, b, x, y, z
...: expr = (1 + b) * z + (1 + b) * y
...: z_expr = a / (1 + b) + x
...: subs_expr = expr.subs(z, z_expr).simplify().collect(1+b)
...: print(expr)
...: print(z_expr)
...: print(subs_expr)
y*(b + 1) + z*(b + 1)
a/(b + 1) + x
a + (b + 1)*(x + y)
Now I want to go back, and subs does not do anything:
In [2]: orig_expr = subs_expr.subs(z_expr, z)
...: print(orig_expr)
a + (b + 1)*(x + y)
How can I get back to y*(b + 1) + z*(b + 1)?
The substitution attempt fails because subs_expr does not actually contain z_expr in its expression tree. "Substitute for an expression that isn't there" is not really a well-defined goal. A well-defined goal would be "eliminate a using the relation z = z_expr". That can be done as follows:
var('orig_expr')
orig_expr = solve([orig_expr - subs_expr, z - z_expr], [orig_expr, a])[orig_expr]
Now orig_expr is equal to b*y + b*z + y + z

Fetch certain parts of sympy solution

I have a huge symbolic sympy expression on the form
expression = factor * (f1*a + f2*b + f3*c + f4*d + f5*e)
where all of the factors a through e all consists of several terms. I.e:
a = exp(2x) + exp(3x) + sin(Ix).
I want to create en array on the form
array = factor * [a,b,c,d,e]
But dont see a cleaver way to do this. I´ve tried to use the factor function, but it only gives me the expression on the form of "expression" above.
Until now i have used
print(expression)
and then done some brute force copy paste of the factors a through e. Since I am going to get expressions with way more terms than in this example, I want to do this without the copy paste routine. Any ideas?
Here's a simple example you can extrapolate for more terms
import sympy as sp
x = sp.var('x')
f1, f2 = sp.symbols('f1:3')
factor = sp.symbols('factor')
a = x**2 + sp.sin(x) + sp.exp(sp.I * x)
b = sp.log(x)/(x+1)**2
# example expression:
expression = (factor * (f1 * a + f2 * b)).expand()
print(expression)
# collect coefficients of f1 and f2
coeffs = sp.collect(expression.expand(),[f1,f2], evaluate=False)
print(coeffs)
# show the coefficients w/o the factor factor
[(coeffs[f]/factor).simplify() for f in (f1,f2)]
f1*factor*x**2 + f1*factor*exp(I*x) + f1*factor*sin(x) + f2*factor*log(x)/(x**2 + 2*x + 1)
{f2: factor*log(x)/(x**2 + 2*x + 1), f1: factor*x**2 + factor*exp(I*x) + factor*sin(x)}
[x**2 + exp(I*x) + sin(x), log(x)/(x**2 + 2*x + 1)]

Categories