Repository: sympy/sympy

Issue:
simplify(x**(1 / acos(I))) recursion error
```
>>> from sympy import *
>>> x = Symbol('x')
>>> e = x**(1 / acos(I))
>>> print(simplify(e))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/e/se/sympy/simplify/simplify.py", line 559, in simplify
    expr = bottom_up(expr, lambda w: getattr(w, 'normal', lambda: w)())
  File "/home/e/se/sympy/simplify/simplify.py", line 1077, in bottom_up
    rv = F(rv)
  File "/home/e/se/sympy/simplify/simplify.py", line 559, in <lambda>
    expr = bottom_up(expr, lambda w: getattr(w, 'normal', lambda: w)())
  File "/home/e/se/sympy/core/expr.py", line 2141, in normal
    n, d = self.as_numer_denom()
  File "/home/e/se/sympy/core/power.py", line 1322, in as_numer_denom
    return self.func(n, exp), self.func(d, exp)
  File "/home/e/se/sympy/core/cache.py", line 94, in wrapper
    retval = cfunc(*args, **kwargs)
  File "/home/e/se/sympy/core/power.py", line 283, in __new__
    if abs(e).is_infinite:
  File "/home/e/se/sympy/core/expr.py", line 167, in __abs__
    return Abs(self)
  File "/home/e/se/sympy/core/cache.py", line 94, in wrapper
    retval = cfunc(*args, **kwargs)
  File "/home/e/se/sympy/core/function.py", line 462, in __new__
    result = super(Function, cls).__new__(cls, *args, **options)
  File "/home/e/se/sympy/core/cache.py", line 94, in wrapper
    retval = cfunc(*args, **kwargs)
  File "/home/e/se/sympy/core/function.py", line 277, in __new__
    evaluated = cls.eval(*args)
  File "/home/e/se/sympy/functions/elementary/complexes.py", line 510, in eval
    return exp(re(exponent*z))
  File "/home/e/se/sympy/core/cache.py", line 94, in wrapper
    retval = cfunc(*args, **kwargs)
  File "/home/e/se/sympy/core/function.py", line 462, in __new__
    result = super(Function, cls).__new__(cls, *args, **options)
  File "/home/e/se/sympy/core/cache.py", line 94, in wrapper
    retval = cfunc(*args, **kwargs)
  File "/home/e/se/sympy/core/function.py", line 277, in __new__
    evaluated = cls.eval(*args)
  File "/home/e/se/sympy/functions/elementary/complexes.py", line 82, in eval
    real_imag = term.as_real_imag(ignore=arg)
  File "/home/e/se/sympy/core/mul.py", line 783, in as_real_imag
    r, i = a.as_real_imag()
  File "/home/e/se/sympy/functions/elementary/exponential.py", line 693, in as_real_imag
    abs = Abs(self.args[0].expand(deep, **hints))
  File "/home/e/se/sympy/core/cache.py", line 94, in wrapper
    retval = cfunc(*args, **kwargs)
  File "/home/e/se/sympy/core/function.py", line 462, in __new__
    result = super(Function, cls).__new__(cls, *args, **options)
  File "/home/e/se/sympy/core/cache.py", line 94, in wrapper
    retval = cfunc(*args, **kwargs)
  File "/home/e/se/sympy/core/function.py", line 277, in __new__
    evaluated = cls.eval(*args)
  File "/home/e/se/sympy/functions/elementary/complexes.py", line 510, in eval
    return exp(re(exponent*z))
  File "/home/e/se/sympy/core/cache.py", line 94, in wrapper
    retval = cfunc(*args, **kwargs)
  File "/home/e/se/sympy/core/function.py", line 462, in __new__
    result = super(Function, cls).__new__(cls, *args, **options)
  File "/home/e/se/sympy/core/cache.py", line 94, in wrapper
    retval = cfunc(*args, **kwargs)
  File "/home/e/se/sympy/core/function.py", line 277, in __new__
    evaluated = cls.eval(*args)

...

    retval = cfunc(*args, **kwargs)
RecursionError: maximum recursion depth exceeded while calling a Python object
```

Discussion:

Patch:
diff --git a/sympy/functions/elementary/trigonometric.py b/sympy/functions/elementary/trigonometric.py
index 0ff7c05402..513bfd0570 100644
--- a/sympy/functions/elementary/trigonometric.py
+++ b/sympy/functions/elementary/trigonometric.py
@@ -107,6 +107,7 @@ def _peeloff_pi(arg):
     (x, pi/2)
     >>> peel(x + 2*pi/3 + pi*y)
     (x + pi*y + pi/6, pi/2)
+
     """
     for a in Add.make_args(arg):
         if a is S.Pi:
@@ -159,6 +160,7 @@ def _pi_coeff(arg, cycles=1):
     2
     >>> coeff(2*Dummy(even=True)*pi)
     0
+
     """
     arg = sympify(arg)
     if arg is S.Pi:
@@ -241,6 +243,7 @@ class sin(TrigonometricFunction):
     .. [2] http://dlmf.nist.gov/4.14
     .. [3] http://functions.wolfram.com/ElementaryFunctions/Sin
     .. [4] http://mathworld.wolfram.com/TrigonometryAngles.html
+
     """
 
     def period(self, symbol=None):
@@ -515,6 +518,7 @@ class cos(TrigonometricFunction):
     .. [1] https://en.wikipedia.org/wiki/Trigonometric_functions
     .. [2] http://dlmf.nist.gov/4.14
     .. [3] http://functions.wolfram.com/ElementaryFunctions/Cos
+
     """
 
     def period(self, symbol=None):
@@ -936,6 +940,7 @@ class tan(TrigonometricFunction):
     .. [1] https://en.wikipedia.org/wiki/Trigonometric_functions
     .. [2] http://dlmf.nist.gov/4.14
     .. [3] http://functions.wolfram.com/ElementaryFunctions/Tan
+
     """
 
     def period(self, symbol=None):
@@ -1239,6 +1244,7 @@ class cot(TrigonometricFunction):
     .. [1] https://en.wikipedia.org/wiki/Trigonometric_functions
     .. [2] http://dlmf.nist.gov/4.14
     .. [3] http://functions.wolfram.com/ElementaryFunctions/Cot
+
     """
 
     def period(self, symbol=None):
@@ -1644,6 +1650,7 @@ class sec(ReciprocalTrigonometricFunction):
     .. [1] https://en.wikipedia.org/wiki/Trigonometric_functions
     .. [2] http://dlmf.nist.gov/4.14
     .. [3] http://functions.wolfram.com/ElementaryFunctions/Sec
+
     """
 
     _reciprocal_of = cos
@@ -1724,6 +1731,7 @@ class csc(ReciprocalTrigonometricFunction):
     .. [1] https://en.wikipedia.org/wiki/Trigonometric_functions
     .. [2] http://dlmf.nist.gov/4.14
     .. [3] http://functions.wolfram.com/ElementaryFunctions/Csc
+
     """
 
     _reciprocal_of = sin
@@ -1773,7 +1781,16 @@ def taylor_term(n, x, *previous_terms):
 
 
 class sinc(Function):
-    r"""Represents unnormalized sinc function
+    r"""
+    Represents an unnormalized sinc function:
+
+    .. math::
+
+        \operatorname{sinc}(x) =
+        \begin{cases}
+          \frac{\sin x}{x} & \qquad x \neq 0 \\
+          1 & \qquad x = 0
+        \end{cases}
 
     Examples
     ========
@@ -1875,9 +1892,11 @@ class asin(InverseTrigonometricFunction):
     Notes
     =====
 
-    asin(x) will evaluate automatically in the cases oo, -oo, 0, 1,
-    -1 and for some instances when the result is a rational multiple
-    of pi (see the eval class method).
+    ``asin(x)`` will evaluate automatically in the cases ``oo``, ``-oo``,
+    ``0``, ``1``, ``-1`` and for some instances when the result is a rational
+    multiple of pi (see the eval class method).
+
+    A purely imaginary argument will lead to an asinh expression.
 
     Examples
     ========
@@ -1900,6 +1919,7 @@ class asin(InverseTrigonometricFunction):
     .. [1] https://en.wikipedia.org/wiki/Inverse_trigonometric_functions
     .. [2] http://dlmf.nist.gov/4.23
     .. [3] http://functions.wolfram.com/ElementaryFunctions/ArcSin
+
     """
 
     def fdiff(self, argindex=1):
@@ -2057,11 +2077,14 @@ class acos(InverseTrigonometricFunction):
     =====
 
     ``acos(x)`` will evaluate automatically in the cases
-    ``oo``, ``-oo``, ``0``, ``1``, ``-1``.
+    ``oo``, ``-oo``, ``0``, ``1``, ``-1`` and for some instances when
+    the result is a rational multiple of pi (see the eval class method).
 
     ``acos(zoo)`` evaluates to ``zoo``
     (see note in :py:class`sympy.functions.elementary.trigonometric.asec`)
 
+    A purely imaginary argument will be rewritten to asinh.
+
     Examples
     ========
 
@@ -2085,6 +2108,7 @@ class acos(InverseTrigonometricFunction):
     .. [1] https://en.wikipedia.org/wiki/Inverse_trigonometric_functions
     .. [2] http://dlmf.nist.gov/4.23
     .. [3] http://functions.wolfram.com/ElementaryFunctions/ArcCos
+
     """
 
     def fdiff(self, argindex=1):
@@ -2135,6 +2159,10 @@ def eval(cls, arg):
             if arg in cst_table:
                 return cst_table[arg]
 
+        i_coeff = arg.as_coefficient(S.ImaginaryUnit)
+        if i_coeff is not None:
+            return pi/2 - asin(arg)
+
         if isinstance(arg, cos):
             ang = arg.args[0]
             if ang.is_comparable:
@@ -2229,8 +2257,9 @@ class atan(InverseTrigonometricFunction):
     Notes
     =====
 
-    atan(x) will evaluate automatically in the cases
-    oo, -oo, 0, 1, -1.
+    ``atan(x)`` will evaluate automatically in the cases
+    ``oo``, ``-oo``, ``0``, ``1``, ``-1`` and for some instances when the
+    result is a rational multiple of pi (see the eval class method).
 
     Examples
     ========
@@ -2255,6 +2284,7 @@ class atan(InverseTrigonometricFunction):
     .. [1] https://en.wikipedia.org/wiki/Inverse_trigonometric_functions
     .. [2] http://dlmf.nist.gov/4.23
     .. [3] http://functions.wolfram.com/ElementaryFunctions/ArcTan
+
     """
 
     def fdiff(self, argindex=1):
@@ -2418,6 +2448,7 @@ class acot(InverseTrigonometricFunction):
     .. [1] https://en.wikipedia.org/wiki/Inverse_trigonometric_functions
     .. [2] http://dlmf.nist.gov/4.23
     .. [3] http://functions.wolfram.com/ElementaryFunctions/ArcCot
+
     """
 
     def fdiff(self, argindex=1):
@@ -2579,18 +2610,18 @@ class asec(InverseTrigonometricFunction):
     it can be defined [4]_ as
 
     .. math::
-        sec^{-1}(z) = -i*(log(\sqrt{1 - z^2} + 1) / z)
+        \operatorname{sec^{-1}}(z) = -i\frac{\log\left(\sqrt{1 - z^2} + 1\right)}{z}
 
     At ``x = 0``, for positive branch cut, the limit evaluates to ``zoo``. For
     negative branch cut, the limit
 
     .. math::
-        \lim_{z \to 0}-i*(log(-\sqrt{1 - z^2} + 1) / z)
+        \lim_{z \to 0}-i\frac{\log\left(-\sqrt{1 - z^2} + 1\right)}{z}
 
-    simplifies to :math:`-i*log(z/2 + O(z^3))` which ultimately evaluates to
-    ``zoo``.
+    simplifies to :math:`-i\log\left(z/2 + O\left(z^3\right)\right)` which
+    ultimately evaluates to ``zoo``.
 
-    As ``asex(x)`` = ``asec(1/x)``, a similar argument can be given for
+    As ``asec(x)`` = ``asec(1/x)``, a similar argument can be given for
     ``acos(x)``.
 
     Examples
@@ -2615,6 +2646,7 @@ class asec(InverseTrigonometricFunction):
     .. [2] http://dlmf.nist.gov/4.23
     .. [3] http://functions.wolfram.com/ElementaryFunctions/ArcSec
     .. [4] http://reference.wolfram.com/language/ref/ArcSec.html
+
     """
 
     @classmethod
@@ -2699,8 +2731,8 @@ class acsc(InverseTrigonometricFunction):
     Notes
     =====
 
-    acsc(x) will evaluate automatically in the cases
-    oo, -oo, 0, 1, -1.
+    ``acsc(x)`` will evaluate automatically in the cases
+    ``oo``, ``-oo``, ``0``, ``1``, ``-1``.
 
     Examples
     ========
@@ -2723,6 +2755,7 @@ class acsc(InverseTrigonometricFunction):
     .. [1] https://en.wikipedia.org/wiki/Inverse_trigonometric_functions
     .. [2] http://dlmf.nist.gov/4.23
     .. [3] http://functions.wolfram.com/ElementaryFunctions/ArcCsc
+
     """
 
     @classmethod
@@ -2820,6 +2853,13 @@ class atan2(InverseTrigonometricFunction):
     Attention: Note the role reversal of both arguments. The `y`-coordinate
     is the first argument and the `x`-coordinate the second.
 
+    If either `x` or `y` is complex:
+
+    .. math::
+
+        \operatorname{atan2}(y, x) =
+            -i\log\left(\frac{x + iy}{\sqrt{x**2 + y**2}}\right)
+
     Examples
     ========
 
@@ -2891,6 +2931,7 @@ class atan2(InverseTrigonometricFunction):
     .. [1] https://en.wikipedia.org/wiki/Inverse_trigonometric_functions
     .. [2] https://en.wikipedia.org/wiki/Atan2
     .. [3] http://functions.wolfram.com/ElementaryFunctions/ArcTan2
+
     """
 
     @classmethod


Test patch:
diff --git a/sympy/functions/elementary/tests/test_trigonometric.py b/sympy/functions/elementary/tests/test_trigonometric.py
index 1edb173848..51f08d52f4 100644
--- a/sympy/functions/elementary/tests/test_trigonometric.py
+++ b/sympy/functions/elementary/tests/test_trigonometric.py
@@ -855,6 +855,8 @@ def test_acos():
     assert acos(sqrt(2)/2) == pi/4
     assert acos(-sqrt(2)/2) == (3*pi)/4
 
+    assert acos(2*I) == pi/2 - asin(2*I)
+
     assert acos(x).diff(x) == -1/sqrt(1 - x**2)
 
     assert acos(0.2).is_real is True
diff --git a/sympy/simplify/tests/test_simplify.py b/sympy/simplify/tests/test_simplify.py
index 23d8620ef4..34a550aa30 100644
--- a/sympy/simplify/tests/test_simplify.py
+++ b/sympy/simplify/tests/test_simplify.py
@@ -11,8 +11,8 @@
 from sympy.core.mul import _keep_coeff
 from sympy.core.expr import unchanged
 from sympy.simplify.simplify import nthroot, inversecombine
-from sympy.utilities.pytest import XFAIL, slow
-from sympy.core.compatibility import range
+from sympy.utilities.pytest import XFAIL, slow, raises
+from sympy.core.compatibility import range, PY3
 
 from sympy.abc import x, y, z, t, a, b, c, d, e, f, g, h, i, k
 
@@ -820,3 +820,19 @@ def test_issue_7971():
     z = Integral(x, (x, 1, 1))
     assert z != 0
     assert simplify(z) is S.Zero
+
+
+def test_issue_17141():
+    # Check that there is no RecursionError
+    assert simplify(x**(1 / acos(I))) == x**(2/(pi - 2*I*log(1 + sqrt(2))))
+    assert simplify(acos(-I)**2*acos(I)**2) == \
+           log(1 + sqrt(2))**4 + pi**2*log(1 + sqrt(2))**2/2 + pi**4/16
+    assert simplify(2**acos(I)**2) == 2**((pi - 2*I*log(1 + sqrt(2)))**2/4)
+
+    # However, for a complex number it still happens
+    if PY3:
+        raises(RecursionError, lambda: simplify(2**acos(I+1)**2))
+        raises(RecursionError, lambda: simplify((2**acos(I+1)**2).rewrite('log')))
+    else:
+        raises(RuntimeError, lambda: simplify(2**acos(I+1)**2))
+        raises(RuntimeError, lambda: simplify((2**acos(I+1)**2).rewrite('log')))