Reputation: 210
I think it's good that SymPy returns log(x) when integrating 1/x, instead of log(abs(x)). This keeps it simple and lets the user worry about the signs.
However, there are situations where it leads to the wrong answer. For example,
from sympy import *
x = Symbol('x')
integrate(cos(x)**2/sin(x), x)
results in
log(cos(x) - 1)/2 - log(cos(x) + 1)/2 + cos(x)
while it should (clearly?) be
log(1 - cos(x))/2 - log(1 + cos(x))/2 + cos(x)
Is there a workaround that will yield the second answer?
Upvotes: 1
Views: 968
Reputation:
The absence of abs
is not just to "keep it simple". As the SymPy lead developer wrote,
SymPy doesn't return
log(abs(x))
forintegrate(1/x)
because it isn't valid for complex numbers. Instead, the answer is correct up to an integration constant (which may be complex). All SymPy operations assume that variables are complex by default.
The rest of the linked issue is also relevant to your question. From a certain point of view, log(cos(x) - 1)
: is as valid as log(1 - cos(x))
in the result of integration: the difference between these two expressions is I*pi
, which is absorbed by the constant of integration. Besides, cos(x)
could be greater than 1 for complex x, like cos(I) = 1.54...
That said, the following is a way to force the constant term in logs to be nonnegative.
def fix_logs(expr):
replacements = {}
for a in expr.atoms(log):
if a.args[0].as_coeff_add()[0].is_negative:
replacements[a] = log(-a.args[0]) + log(-1)
return expr.xreplace(replacements)
Here is how it works:
rv = integrate(cos(x)**2/sin(x), x)
rv2 = fix_logs(rv)
rv3 = Add(*fix_logs(rv2).as_coeff_add(x)[1])
Here rv, rv2, and rv3 are:
log(cos(x) - 1)/2 - log(cos(x) + 1)/2 + cos(x)
log(-cos(x) + 1)/2 - log(cos(x) + 1)/2 + cos(x) + I*pi/2
log(-cos(x) + 1)/2 - log(cos(x) + 1)/2 + cos(x)
The function fix_logs
does not remove the log(-1) part because it could be important: x*log(x-1)
becomes x*(log(1-x) + I*pi/2)
where the constant cannot be simply dropped. But if desired, the additive constant can be removed as shown in the calculation of rv3
.
Reference for as_coeff_add
method
Upvotes: 2