Manual Integrate cannot do (1/cos(x)) dx
When I run
import sympy as sp
from sympy.integrals.manualintegrate import integral_steps
x = sp.Symbol('x')
f = 1/sp.cos(x)
integral_steps(f, x)
I get DontKnowRule(integrand=1/cos(x), variable=x) even though this is simple integration of sec(x) which is already handled as this code
import sympy as sp
from sympy.integrals.manualintegrate import integral_steps
x = sp.Symbol('x')
f = sp.sec(x)
integral_steps(f, x).eval()
yield log(tan(x) + sec(x)).
I believe the problem is that the function rewrites_rule in manual integrate does not do what it's supposed to do.
def rewrites_rule(integral):
integrand, symbol = integral
if integrand.match(1/cos(symbol)):
rewritten = integrand.subs(1/cos(symbol), sec(symbol))
return RewriteRule(integrand, symbol, rewritten, integral_steps(rewritten, symbol))
The condition in this integral gives empty dictionary as there are no Wild variables to be matched so the RewriteRule is never executed. I think the issue can be easily fixed in many ways such as
- substituting (1/cos) everywhere without the condition
- checking integrand == 1/cos(symbol) directly
Not sure what is the best way to go but after discussion I can do a PR.
Thanks.
I would say the match logic is wrong. It should be checking if integrand.match(1/cos(symbol)) is not None.
Although I wonder if this function should just be deleted. It's called "rewrites_rule" but it just matches this one exact integral (and as noted, it isn't even doing it correctly). There's already other code that tries to substitute 1/cos(x) for sec(x). Why doesn't that work for this integral?
If we want to add a simple integrals table to manualintegrate, that's fine, but we should do so in a more compact format, and ideally that table should include more than just this one single integral.
Yes - I agree with you that even if the function worked properly it does not achieve anything beyond integrating 1/cos(x). I think at the very least it should be renamed.
I think it's probably better to not create a bigger table of integrals as the goal of manualintegrate is to describe the steps on how to do an integral manually by only relying on some very elementary antiderivatives rather than getting the final answer for all cases.
I am not yet too deep into the substitution part of the code but it doesn't seem to work well for similar cases that include these kind of substitutions. For example, it cannot integrate 1/(cos(x) + sec(x)) as well which can be solved by writing this as cos(x)/(1+cos^2(x)) and doing integration by parts. I will try to investigate why this doesn't work.
A table could be useful if it were large enough. However, that's also the goal of the ongoing project to integrate RUBI into SymPy (see https://github.com/sympy/rubi).
And as far as trig integrals go, we'd be better off teaching manualintegrate how to do Weierstrass substitution.
Weierstrass is great for proving equalities, too. But here is a ref and an example for when args of the trig functions are the same:
>>> integrand=sin(x)
>>> fu(integrate(integrand.rewrite(tan).subs(tan(x/2),t)*2/(1+t**2)).subs(t,tan(x/2)))
-1-cos(x)