Solve integral symbolically by isolating integrand in sympy
Question:
I was wondering why sympy won’t solve the following problem:
from sympy import *
ss = symbols('s', real = True)
a = symbols('a', real = True)
f = Function('f')
g = Function('g')
eq = Integral(a*g(ss) + f(ss),(ss,0,oo))
solve(eq, a)
The return is an empty solution list. I want to tell sympy enough stuff so that I get as a solution:
-1*Integral(f(ss),(ss,0,oo))/Integral(g(ss),(ss,0,oo))
That is, its safe to assume integrals converge, are real-valued and non-zero.
Is there any other assumption/function I can use to get the desired output?
Thanks
Answers:
Your assumption about the expected result is still inaccurate. For the equation to have a solution, Integral(g(ss),(ss,0,oo))
must be guaranteed to be real and non-zero, which is in no way implied by your equations, so no result is returned.
Further, it appears that if you want to solve equations involving an Integral
, you need to use doit
. Take a look below
from sympy import *
x = symbols('x', real = True)
a = symbols('a', real = True)
f = Function('f')
eq = a+Integral(f(x), (x, 0, oo))
print('Eq.1', solve(eq, a))
eq2 = Integral(a+f(x), (x, 0, oo))
print('Eq.2', solve(eq2.doit(), a))
eq3 = Integral(a+f(x), (x, 0, 1))
print('Eq.3', solve(eq3.doit(), a))
eq4 = Integral(a+2, (x, 0, 3))
print('Eq.4', solve(eq4, a))
print('Eq.4', solve(eq4.doit(), a))
Output:
Eq.1 [-Integral(f(x), (x, 0, oo))]
Eq.2 []
Eq.3 []
Eq.4 []
Eq.4 [-2]
Note that eq.1 is solvable, in the sense that you can move a
on one side of the equation since it is not inside a limit (integrals with infinite bounds are shorthand for the limit of an integral with the respective bound approaching infinity). However, eq.2 and eq.3 are not solvable, because the limit of a sum is equal to the sum of the limits only if they converge to a real number (and, in your case, there is no guarantee that they do).
Finally, eq.4 is trivially solvable, but you have to use doit
. In eq.1 you can get away without it.
That said, you can "overcome" the formalism, using expand
. Take a look below.
from sympy import *
x = symbols('x', real = True)
a = symbols('a', real = True)
f = Function('f')
g = Function('g')
eq5 = a+Integral(a+f(x), (x, 0, 1))
print('Eq.5', solve(eq5.expand().doit(), a))
eq6 = Integral(a+f(x), (x, 0, 1))
print('Eq.6', solve(eq6.expand().doit(), a))
eq7 = Integral(a*g(x)+f(x), (x, 0, oo))
print('Eq.7', solve(eq7.expand().doit(), a))
Output:
Eq.5 [-Integral(f(x), (x, 0, 1))/2]
Eq.6 [-Integral(f(x), (x, 0, 1))]
Eq.7 [-Integral(f(x), (x, 0, oo))/Integral(g(x), (x, 0, oo))]
This works because it allows certain operations, by playing fast and loose with the details. But, it still doesn’t work, when the results are plain-wrong (try to use oo
as the upper bound in eq.6 or eq.7).
This is your equation:
In [9]: eq
Out[9]:
∞
⌠
⎮ (a⋅g(s) + f(s)) ds
⌡
0
You would like to solve for a
to make this expression equal to zero. We can rearrange this expression to extract a
so that solve
understands how to isolate a
:
In [10]: eq.expand()
Out[10]:
∞
⌠
⎮ (a⋅g(s) + f(s)) ds
⌡
0
In [11]: eq.expand(force=True)
Out[11]:
∞ ∞
⌠ ⌠
⎮ a⋅g(s) ds + ⎮ f(s) ds
⌡ ⌡
0 0
In [12]: factor_terms(eq.expand(force=True))
Out[12]:
∞ ∞
⌠ ⌠
a⋅⎮ g(s) ds + ⎮ f(s) ds
⌡ ⌡
0 0
In [13]: solve(factor_terms(eq.expand(force=True)), a)
Out[13]:
⎡ ∞ ⎤
⎢ ⌠ ⎥
⎢-⎮ f(s) ds ⎥
⎢ ⌡ ⎥
⎢ 0 ⎥
⎢───────────⎥
⎢ ∞ ⎥
⎢ ⌠ ⎥
⎢ ⎮ g(s) ds ⎥
⎢ ⌡ ⎥
⎣ 0 ⎦
We have to use force=True
because expand
will not presume to know that an integral with an upper limit of oo
converges and splitting the integral into two integrals might turn a converging integral into a sum of non-converging integrals.
I was wondering why sympy won’t solve the following problem:
from sympy import *
ss = symbols('s', real = True)
a = symbols('a', real = True)
f = Function('f')
g = Function('g')
eq = Integral(a*g(ss) + f(ss),(ss,0,oo))
solve(eq, a)
The return is an empty solution list. I want to tell sympy enough stuff so that I get as a solution:
-1*Integral(f(ss),(ss,0,oo))/Integral(g(ss),(ss,0,oo))
That is, its safe to assume integrals converge, are real-valued and non-zero.
Is there any other assumption/function I can use to get the desired output?
Thanks
Your assumption about the expected result is still inaccurate. For the equation to have a solution, Integral(g(ss),(ss,0,oo))
must be guaranteed to be real and non-zero, which is in no way implied by your equations, so no result is returned.
Further, it appears that if you want to solve equations involving an Integral
, you need to use doit
. Take a look below
from sympy import *
x = symbols('x', real = True)
a = symbols('a', real = True)
f = Function('f')
eq = a+Integral(f(x), (x, 0, oo))
print('Eq.1', solve(eq, a))
eq2 = Integral(a+f(x), (x, 0, oo))
print('Eq.2', solve(eq2.doit(), a))
eq3 = Integral(a+f(x), (x, 0, 1))
print('Eq.3', solve(eq3.doit(), a))
eq4 = Integral(a+2, (x, 0, 3))
print('Eq.4', solve(eq4, a))
print('Eq.4', solve(eq4.doit(), a))
Output:
Eq.1 [-Integral(f(x), (x, 0, oo))]
Eq.2 []
Eq.3 []
Eq.4 []
Eq.4 [-2]
Note that eq.1 is solvable, in the sense that you can move a
on one side of the equation since it is not inside a limit (integrals with infinite bounds are shorthand for the limit of an integral with the respective bound approaching infinity). However, eq.2 and eq.3 are not solvable, because the limit of a sum is equal to the sum of the limits only if they converge to a real number (and, in your case, there is no guarantee that they do).
Finally, eq.4 is trivially solvable, but you have to use doit
. In eq.1 you can get away without it.
That said, you can "overcome" the formalism, using expand
. Take a look below.
from sympy import *
x = symbols('x', real = True)
a = symbols('a', real = True)
f = Function('f')
g = Function('g')
eq5 = a+Integral(a+f(x), (x, 0, 1))
print('Eq.5', solve(eq5.expand().doit(), a))
eq6 = Integral(a+f(x), (x, 0, 1))
print('Eq.6', solve(eq6.expand().doit(), a))
eq7 = Integral(a*g(x)+f(x), (x, 0, oo))
print('Eq.7', solve(eq7.expand().doit(), a))
Output:
Eq.5 [-Integral(f(x), (x, 0, 1))/2]
Eq.6 [-Integral(f(x), (x, 0, 1))]
Eq.7 [-Integral(f(x), (x, 0, oo))/Integral(g(x), (x, 0, oo))]
This works because it allows certain operations, by playing fast and loose with the details. But, it still doesn’t work, when the results are plain-wrong (try to use oo
as the upper bound in eq.6 or eq.7).
This is your equation:
In [9]: eq
Out[9]:
∞
⌠
⎮ (a⋅g(s) + f(s)) ds
⌡
0
You would like to solve for a
to make this expression equal to zero. We can rearrange this expression to extract a
so that solve
understands how to isolate a
:
In [10]: eq.expand()
Out[10]:
∞
⌠
⎮ (a⋅g(s) + f(s)) ds
⌡
0
In [11]: eq.expand(force=True)
Out[11]:
∞ ∞
⌠ ⌠
⎮ a⋅g(s) ds + ⎮ f(s) ds
⌡ ⌡
0 0
In [12]: factor_terms(eq.expand(force=True))
Out[12]:
∞ ∞
⌠ ⌠
a⋅⎮ g(s) ds + ⎮ f(s) ds
⌡ ⌡
0 0
In [13]: solve(factor_terms(eq.expand(force=True)), a)
Out[13]:
⎡ ∞ ⎤
⎢ ⌠ ⎥
⎢-⎮ f(s) ds ⎥
⎢ ⌡ ⎥
⎢ 0 ⎥
⎢───────────⎥
⎢ ∞ ⎥
⎢ ⌠ ⎥
⎢ ⎮ g(s) ds ⎥
⎢ ⌡ ⎥
⎣ 0 ⎦
We have to use force=True
because expand
will not presume to know that an integral with an upper limit of oo
converges and splitting the integral into two integrals might turn a converging integral into a sum of non-converging integrals.