Solve integral symbolically by isolating integrand in sympy


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:


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?

Asked By: user191919



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


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


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

Answered By: Alex P

This is your equation:

In [9]: eq
⎮ (a⋅g(s) + f(s)) ds

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()
⎮ (a⋅g(s) + f(s)) ds

In [11]: eq.expand(force=True)
∞             ∞        
⌠             ⌠        
⎮ a⋅g(s) ds + ⎮ f(s) ds
⌡             ⌡        
0             0        

In [12]: factor_terms(eq.expand(force=True))
  ∞           ∞        
  ⌠           ⌠        
a⋅⎮ g(s) ds + ⎮ f(s) ds
  ⌡           ⌡        
  0           0        

In [13]: solve(factor_terms(eq.expand(force=True)), a)
⎡ ∞         ⎤
⎢ ⌠         ⎥
⎢-⎮ 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.

Answered By: Oscar Benjamin
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.