Repository: sympy/sympy

Issue:
Sympy doesn't Integrate when expr contains asec / acsc 
```python3
>>> integrate(asin(x))
x*asin(x) + sqrt(1 - x**2)
>>> integrate(x*asin(x))
x**2*asin(x)/2 + x*sqrt(1 - x**2)/4 - asin(x)/4
>>> integrate(acos(x))
x*acos(x) - sqrt(1 - x**2)
>>> integrate(x*acos(x))
x**2*acos(x)/2 - x*sqrt(1 - x**2)/4 - acos(x)/4
>>> integrate(atan(x))
x*atan(x) - log(x**2 + 1)/2
>>> integrate(x*atan(x))
x**2*atan(x)/2 - x/2 + atan(x)/2
>>> integrate(asec(x)) # Secant inverse isn't evaluated
Integral(asec(x), x)
>>> integrate(x*asec(x)) # isn't evaluated
Integral(x*asec(x), x)
>>> integrate(acot(x))
x*acot(x) + log(x**2 + 1)/2
>>> integrate(x*acot(x))
x**2*acot(x)/2 + x/2 + acot(x)/2
>>> integrate(acsc(x)) # Cosecant inverse isn't evaluated
Integral(acsc(x), x)
>>> integrate(x*acsc(x)) # isn't evaluated
Integral(x*acsc(x), x)
>>>
```

Discussion:

Patch:
diff --git a/sympy/integrals/manualintegrate.py b/sympy/integrals/manualintegrate.py
index d1d61fb962..5c89088058 100644
--- a/sympy/integrals/manualintegrate.py
+++ b/sympy/integrals/manualintegrate.py
@@ -174,6 +174,9 @@ def manual_subs(expr, *args):
 # Method based on that on SIN, described in "Symbolic Integration: The
 # Stormy Decade"
 
+inverse_trig_functions = (sympy.atan, sympy.asin, sympy.acos, sympy.acot, sympy.acsc, sympy.asec)
+
+
 def find_substitutions(integrand, symbol, u_var):
     results = []
 
@@ -213,7 +216,7 @@ def test_subterm(u, u_diff):
 
     def possible_subterms(term):
         if isinstance(term, (TrigonometricFunction,
-                             sympy.asin, sympy.acos, sympy.atan,
+                             *inverse_trig_functions,
                              sympy.exp, sympy.log, sympy.Heaviside)):
             return [term.args[0]]
         elif isinstance(term, (sympy.chebyshevt, sympy.chebyshevu,
@@ -535,14 +538,14 @@ def pull_out_u_rl(integrand):
 
         return pull_out_u_rl
 
-    liate_rules = [pull_out_u(sympy.log), pull_out_u(sympy.atan, sympy.asin, sympy.acos),
+    liate_rules = [pull_out_u(sympy.log), pull_out_u(*inverse_trig_functions),
                    pull_out_algebraic, pull_out_u(sympy.sin, sympy.cos),
                    pull_out_u(sympy.exp)]
 
 
     dummy = sympy.Dummy("temporary")
     # we can integrate log(x) and atan(x) by setting dv = 1
-    if isinstance(integrand, (sympy.log, sympy.atan, sympy.asin, sympy.acos)):
+    if isinstance(integrand, (sympy.log, *inverse_trig_functions)):
         integrand = dummy * integrand
 
     for index, rule in enumerate(liate_rules):
@@ -1271,8 +1274,8 @@ def key(integral):
             return sympy.Number
         else:
             for cls in (sympy.Pow, sympy.Symbol, sympy.exp, sympy.log,
-                        sympy.Add, sympy.Mul, sympy.atan, sympy.asin,
-                        sympy.acos, sympy.Heaviside, OrthogonalPolynomial):
+                        sympy.Add, sympy.Mul, *inverse_trig_functions,
+                        sympy.Heaviside, OrthogonalPolynomial):
                 if isinstance(integrand, cls):
                     return cls
 
@@ -1312,7 +1315,8 @@ def _integral_is_subclass(integral):
                     integral_is_subclass(sympy.Mul, sympy.Pow),
                     cancel_rule),
                 condition(
-                    integral_is_subclass(sympy.Mul, sympy.log, sympy.atan, sympy.asin, sympy.acos),
+                    integral_is_subclass(sympy.Mul, sympy.log,
+                    *inverse_trig_functions),
                     parts_rule),
                 condition(
                     integral_is_subclass(sympy.Mul, sympy.Pow),
@@ -1430,6 +1434,8 @@ def eval_piecewise(substeps, integrand, symbol):
 @evaluates(TrigSubstitutionRule)
 def eval_trigsubstitution(theta, func, rewritten, substep, restriction, integrand, symbol):
     func = func.subs(sympy.sec(theta), 1/sympy.cos(theta))
+    func = func.subs(sympy.csc(theta), 1/sympy.sin(theta))
+    func = func.subs(sympy.cot(theta), 1/sympy.tan(theta))
 
     trig_function = list(func.find(TrigonometricFunction))
     assert len(trig_function) == 1


Test patch:
diff --git a/sympy/integrals/tests/test_manual.py b/sympy/integrals/tests/test_manual.py
index 58804c5f9f..a364bf4c70 100644
--- a/sympy/integrals/tests/test_manual.py
+++ b/sympy/integrals/tests/test_manual.py
@@ -5,7 +5,7 @@
                    Function, jacobi, gegenbauer, chebyshevt, chebyshevu,
                    legendre, hermite, laguerre, assoc_laguerre, uppergamma, li,
                    Ei, Ci, Si, Chi, Shi, fresnels, fresnelc, polylog, erfi,
-                   sinh, cosh, elliptic_f, elliptic_e)
+                   sinh, cosh, elliptic_f, elliptic_e ,asec, acsc, acot )
 from sympy.integrals.manualintegrate import (manualintegrate, find_substitutions,
     _parts_rule, integral_steps, contains_dont_know, manual_subs)
 from sympy.testing.pytest import raises, slow
@@ -160,6 +160,32 @@ def test_manualintegrate_inversetrig():
     assert manualintegrate(1/sqrt(-a + 4*x**2), x) == \
         Piecewise((asinh(2*x*sqrt(-1/a))/2, -a > 0), (acosh(2*x*sqrt(1/a))/2, -a < 0))
 
+    # From https://www.wikiwand.com/en/List_of_integrals_of_inverse_trigonometric_functions
+    # asin
+    assert manualintegrate(asin(x), x) == x*asin(x) + sqrt(1 - x**2)
+    assert manualintegrate(asin(a*x), x) == Piecewise(((a*x*asin(a*x) + sqrt(-a**2*x**2 + 1))/a, Ne(a, 0)), (0, True))
+    assert manualintegrate(x*asin(a*x), x) == -a*Integral(x**2/sqrt(-a**2*x**2 + 1), x)/2 + x**2*asin(a*x)/2
+    # acos
+    assert manualintegrate(acos(x), x) == x*acos(x) - sqrt(1 - x**2)
+    assert manualintegrate(acos(a*x), x) == Piecewise(((a*x*acos(a*x) - sqrt(-a**2*x**2 + 1))/a, Ne(a, 0)), (pi*x/2, True))
+    assert manualintegrate(x*acos(a*x), x) == a*Integral(x**2/sqrt(-a**2*x**2 + 1), x)/2 + x**2*acos(a*x)/2
+    # atan
+    assert manualintegrate(atan(x), x) == x*atan(x) - log(x**2 + 1)/2
+    assert manualintegrate(atan(a*x), x) == Piecewise(((a*x*atan(a*x) - log(a**2*x**2 + 1)/2)/a, Ne(a, 0)), (0, True))
+    assert manualintegrate(x*atan(a*x), x) == -a*(x/a**2 - atan(x/sqrt(a**(-2)))/(a**4*sqrt(a**(-2))))/2 + x**2*atan(a*x)/2
+    # acsc
+    assert manualintegrate(acsc(x), x) == x*acsc(x) + Integral(1/(x*sqrt(1 - 1/x**2)), x)
+    assert manualintegrate(acsc(a*x), x) == x*acsc(a*x) + Integral(1/(x*sqrt(1 - 1/(a**2*x**2))), x)/a
+    assert manualintegrate(x*acsc(a*x), x) == x**2*acsc(a*x)/2 + Integral(1/sqrt(1 - 1/(a**2*x**2)), x)/(2*a)
+    # asec
+    assert manualintegrate(asec(x), x) == x*asec(x) - Integral(1/(x*sqrt(1 - 1/x**2)), x)
+    assert manualintegrate(asec(a*x), x) == x*asec(a*x) - Integral(1/(x*sqrt(1 - 1/(a**2*x**2))), x)/a
+    assert manualintegrate(x*asec(a*x), x) == x**2*asec(a*x)/2 - Integral(1/sqrt(1 - 1/(a**2*x**2)), x)/(2*a)
+    # acot
+    assert manualintegrate(acot(x), x) == x*acot(x) + log(x**2 + 1)/2
+    assert manualintegrate(acot(a*x), x) == Piecewise(((a*x*acot(a*x) + log(a**2*x**2 + 1)/2)/a, Ne(a, 0)), (pi*x/2, True))
+    assert manualintegrate(x*acot(a*x), x) == a*(x/a**2 - atan(x/sqrt(a**(-2)))/(a**4*sqrt(a**(-2))))/2 + x**2*acot(a*x)/2
+
     # piecewise
     assert manualintegrate(1/sqrt(a-b*x**2), x) == \
         Piecewise((sqrt(a/b)*asin(x*sqrt(b/a))/sqrt(a), And(-b < 0, a > 0)),