Repository: sympy/sympy

Issue:
real_root formula doesn't work with lambdify
```
In [203]: real_root((log(x/(x-2))), 3)
Out[203]:
⎛⎧                ⎛  x  ⎞    ⎞
⎜⎪   1     for arg⎜─────⎟ ≠ 0⎟
⎜⎪                ⎝x - 2⎠    ⎟     ____________
⎜⎪                           ⎟    ╱    ⎛  x  ⎞
⎜⎨    2/3         ⎛  x  ⎞    ⎟⋅3 ╱  log⎜─────⎟
⎜⎪(-1)     for log⎜─────⎟ < 0⎟ ╲╱      ⎝x - 2⎠
⎜⎪                ⎝x - 2⎠    ⎟
⎜⎪                           ⎟
⎝⎩   1         otherwise     ⎠

In [204]: real_root((log(x/(x-2))), 3).subs(x, -1)
Out[204]:
 3 ________
-╲╱ log(3)

In [205]: lambdify(x, real_root((log(x/(x-2))), 3), 'numpy')(np.array(-1))
/Users/aaronmeurer/anaconda3/lib/python3.5/site-packages/numpy/__init__.py:1: RuntimeWarning: invalid value encountered in double_scalars
  """
Out[205]: (nan+nan*j)
```

See http://stackoverflow.com/a/38707315/161801.


Discussion:

Patch:
diff --git a/sympy/functions/elementary/miscellaneous.py b/sympy/functions/elementary/miscellaneous.py
index eed59707b3..dd922e4b5c 100644
--- a/sympy/functions/elementary/miscellaneous.py
+++ b/sympy/functions/elementary/miscellaneous.py
@@ -7,17 +7,18 @@
 from sympy.core.function import (Application, Lambda,
     ArgumentIndexError)
 from sympy.core.expr import Expr
+from sympy.core.mod import Mod
 from sympy.core.mul import Mul
 from sympy.core.numbers import Rational
 from sympy.core.power import Pow
-from sympy.core.relational import Equality, Relational
+from sympy.core.relational import Eq, Relational
 from sympy.core.singleton import Singleton
 from sympy.core.symbol import Dummy
 from sympy.core.rules import Transform
 from sympy.core.compatibility import as_int, with_metaclass, range
 from sympy.core.logic import fuzzy_and, fuzzy_or, _torf
 from sympy.functions.elementary.integers import floor
-from sympy.logic.boolalg import And
+from sympy.logic.boolalg import And, Or
 
 def _minmax_as_Piecewise(op, *args):
     # helper for Min/Max rewrite as Piecewise
@@ -180,7 +181,7 @@ def cbrt(arg):
 
 def root(arg, n, k=0):
     """root(x, n, k) -> Returns the k-th n-th root of x, defaulting to the
-    principle root (k=0).
+    principal root (k=0).
 
 
     Examples
@@ -230,7 +231,7 @@ def root(arg, n, k=0):
     >>> root(-8, 3)
     2*(-1)**(1/3)
 
-    The real_root function can be used to either make the principle
+    The real_root function can be used to either make the principal
     result real (or simply to return the real root directly):
 
     >>> from sympy import real_root
@@ -271,7 +272,7 @@ def root(arg, n, k=0):
 def real_root(arg, n=None):
     """Return the real nth-root of arg if possible. If n is omitted then
     all instances of (-n)**(1/odd) will be changed to -n**(1/odd); this
-    will only create a real root of a principle root -- the presence of
+    will only create a real root of a principal root -- the presence of
     other factors may cause the result to not be real.
 
     Examples
@@ -287,7 +288,7 @@ def real_root(arg, n=None):
     >>> real_root(_)
     -2
 
-    If one creates a non-principle root and applies real_root, the
+    If one creates a non-principal root and applies real_root, the
     result will not be real (so use with caution):
 
     >>> root(-8, 3, 2)
@@ -303,24 +304,15 @@ def real_root(arg, n=None):
     sympy.core.power.integer_nthroot
     root, sqrt
     """
-    from sympy import im, Piecewise
+    from sympy.functions.elementary.complexes import Abs, im, sign
+    from sympy.functions.elementary.piecewise import Piecewise
     if n is not None:
-        try:
-            n = as_int(n)
-            arg = sympify(arg)
-            if arg.is_positive or arg.is_negative:
-                rv = root(arg, n)
-            else:
-                raise ValueError
-        except ValueError:
-            return root(arg, n)*Piecewise(
-                (S.One, ~Equality(im(arg), 0)),
-                (Pow(S.NegativeOne, S.One/n)**(2*floor(n/2)), And(
-                    Equality(n % 2, 1),
-                    arg < 0)),
-                (S.One, True))
-    else:
-        rv = sympify(arg)
+        return Piecewise(
+            (root(arg, n), Or(Eq(n, S.One), Eq(n, S.NegativeOne))),
+            (sign(arg)*root(Abs(arg), n), And(Eq(im(arg), S.Zero),
+                Eq(Mod(n, 2), S.One))),
+            (root(arg, n), True))
+    rv = sympify(arg)
     n1pow = Transform(lambda x: -(-x.base)**x.exp,
                       lambda x:
                       x.is_Pow and


Test patch:
diff --git a/sympy/functions/elementary/tests/test_miscellaneous.py b/sympy/functions/elementary/tests/test_miscellaneous.py
index 3e691645bd..bdfbb02c60 100644
--- a/sympy/functions/elementary/tests/test_miscellaneous.py
+++ b/sympy/functions/elementary/tests/test_miscellaneous.py
@@ -1,4 +1,5 @@
 import itertools as it
+import warnings
 
 from sympy.core.function import Function
 from sympy.core.numbers import I, oo, Rational
@@ -7,11 +8,13 @@
 from sympy.functions.elementary.miscellaneous import (sqrt, cbrt, root, Min,
                                                       Max, real_root)
 from sympy.functions.elementary.trigonometric import cos, sin
+from sympy.functions.elementary.exponential import log
 from sympy.functions.elementary.integers import floor, ceiling
 from sympy.functions.special.delta_functions import Heaviside
 
-from sympy.utilities.pytest import raises
-
+from sympy.utilities.lambdify import lambdify
+from sympy.utilities.pytest import raises, skip
+from sympy.external import import_module
 
 def test_Min():
     from sympy.abc import x, y, z
@@ -335,6 +338,20 @@ def test_real_root():
     assert g.subs(dict(x=I, n=2)) == sqrt(I)
 
 
+def test_issue_11463():
+    numpy = import_module('numpy')
+    if not numpy:
+        skip("numpy not installed.")
+    x = Symbol('x')
+    f = lambdify(x, real_root((log(x/(x-2))), 3), 'numpy')
+    # numpy.select evaluates all options before considering conditions,
+    # so it raises a warning about root of negative number which does
+    # not affect the outcome. This warning is suppressed here
+    with warnings.catch_warnings():
+        warnings.simplefilter("ignore")
+        assert f(numpy.array(-1)) < -1
+
+
 def test_rewrite_MaxMin_as_Heaviside():
     from sympy.abc import x
     assert Max(0, x).rewrite(Heaviside) == x*Heaviside(x)
diff --git a/sympy/solvers/tests/test_solveset.py b/sympy/solvers/tests/test_solveset.py
index 11fa29fbbf..b1734df3e2 100644
--- a/sympy/solvers/tests/test_solveset.py
+++ b/sympy/solvers/tests/test_solveset.py
@@ -5,7 +5,7 @@
     Ne)
 from sympy.core.singleton import S
 from sympy.core.symbol import (Dummy, Symbol, symbols)
-from sympy.functions.elementary.complexes import (Abs, arg, im, re)
+from sympy.functions.elementary.complexes import (Abs, arg, im, re, sign)
 from sympy.functions.elementary.exponential import (LambertW, exp, log)
 from sympy.functions.elementary.hyperbolic import (HyperbolicFunction,
     atanh, sinh, tanh)
@@ -1535,8 +1535,8 @@ def test_issue_9557():
 def test_issue_9778():
     assert solveset(x**3 + 1, x, S.Reals) == FiniteSet(-1)
     assert solveset(x**(S(3)/5) + 1, x, S.Reals) == S.EmptySet
-    assert solveset(x**3 + y, x, S.Reals) == Intersection(Interval(-oo, oo), \
-        FiniteSet((-y)**(S(1)/3)*Piecewise((1, Ne(-im(y), 0)), ((-1)**(S(2)/3), -y < 0), (1, True))))
+    assert solveset(x**3 + y, x, S.Reals) == \
+        FiniteSet(-Abs(y)**(S(1)/3)*sign(y))
 
 
 @XFAIL