Repository: sympy/sympy

Issue:
summation produces polar_exp in result
Because of the exp_polar in the result, the result cannot be evaluated. Is it suppose to give exp_polar or should the be replaced with exp?

```
>>> Sum(1/(3*i+1)**2,(i,0,oo)).n(4)
1.122
>>> Sum(1/(3*i+1)**2,(i,0,oo)).doit().n(4)
-0.1667*polylog(2, exp_polar(4*I*pi/3)) + 0.2887*I*polylog(2, exp_polar(4*I*pi/3
)) + 0.835 + 0.04551*I
>>> _.replace(exp_polar, exp).n(4)
1.122 - 3.22e-7*I
```


Discussion:

Patch:
diff --git a/sympy/core/basic.py b/sympy/core/basic.py
index a1bf92bde1..d4ca323e0d 100644
--- a/sympy/core/basic.py
+++ b/sympy/core/basic.py
@@ -1581,16 +1581,6 @@ def _eval_rewrite(self, pattern, rule, **hints):
                     return rewritten
         return self.func(*args)
 
-    def _eval_derivative_n_times(self, s, n):
-        # This is the default evaluator for derivatives (as called by `diff`
-        # and `Derivative`), it will attempt a loop to derive the expression
-        # `n` times by calling the corresponding `_eval_derivative` method,
-        # while leaving the derivative unevaluated if `n` is symbolic.  This
-        # method should be overridden if the object has a closed form for its
-        # symbolic n-th derivative.
-        from sympy import Derivative
-        return Derivative._helper_apply_n_times(self, s, n, lambda x, s: x._eval_derivative(s))
-
     def rewrite(self, *args, **hints):
         """ Rewrite functions in terms of other functions.
 
diff --git a/sympy/core/expr.py b/sympy/core/expr.py
index 3085a10279..c36d6f271d 100644
--- a/sympy/core/expr.py
+++ b/sympy/core/expr.py
@@ -3352,13 +3352,6 @@ def _eval_derivative(self, s):
             return S.One
         return S.Zero
 
-    def _eval_derivative_n_times(self, s, n):
-        from sympy import Piecewise, Eq
-        if self == s:
-            return Piecewise((self, Eq(n, 0)), (1, Eq(n, 1)), (0, True))
-        else:
-            return Piecewise((self, Eq(n, 0)), (0, True))
-
     def _eval_is_polynomial(self, syms):
         return True
 
diff --git a/sympy/core/function.py b/sympy/core/function.py
index 28d675fc77..01ac21ed38 100644
--- a/sympy/core/function.py
+++ b/sympy/core/function.py
@@ -1239,19 +1239,33 @@ def __new__(cls, expr, *variables, **kwargs):
                 obj = None
             else:
                 if isinstance(v, (collections.Iterable, Tuple, MatrixCommon, NDimArray)):
-                    # Treat derivatives by arrays/matrices as much as symbols.
+                    deriv_fun = derive_by_array
                     is_symbol = True
+                else:
+                    deriv_fun = lambda x, y: x._eval_derivative(y)
                 if not is_symbol:
                     new_v = Dummy('xi_%i' % i, dummy_index=hash(v))
                     expr = expr.xreplace({v: new_v})
                     old_v = v
                     v = new_v
-                # Evaluate the derivative `n` times.  If
-                # `_eval_derivative_n_times` is not overridden by the current
-                # object, the default in `Basic` will call a loop over
-                # `_eval_derivative`:
-                obj = expr._eval_derivative_n_times(v, count)
-                nderivs += count
+                obj = expr
+                if count.is_Integer:
+                    for i in range(count):
+                        obj2 = deriv_fun(obj, v)
+                        if obj == obj2:
+                            break
+                        obj = obj2
+                        nderivs += 1
+                elif obj.is_Derivative:
+                    dict_var_count = dict(obj.variable_count)
+                    if v in dict_var_count:
+                        dict_var_count[v] += count
+                    else:
+                        dict_var_count[v] = count
+                    obj = Derivative(obj.expr, *dict_var_count.items())
+                    nderivs += count
+                else:
+                    obj = None
                 if not is_symbol:
                     if obj is not None:
                         if not old_v.is_symbol and obj.is_Derivative:
@@ -1288,44 +1302,6 @@ def __new__(cls, expr, *variables, **kwargs):
             expr = factor_terms(signsimp(expr))
         return expr
 
-    @staticmethod
-    def _helper_apply_n_times(expr, s, n, func):
-        from sympy import Integer, Tuple, NDimArray
-        from sympy.matrices.common import MatrixCommon
-
-        # This `if` could be avoided with double dispatch, combinations of type
-        # requiring `derive_by_array`:
-        # 1. (array, array) ==> this is managed by the following `if`.
-        # 2. (array, scalar)
-        # 3. (scalar, array) ==> this is managed by the following `if`.
-        # 4. (scalar, scalar)
-        #
-        # Case 1. is handled by `_eval_derivative` of `NDimArray`.
-        # Case 4., i.e. pair (x=scalar, y=scalar) should be passed to
-        # x._eval_derivative(y).
-        if isinstance(s, (collections.Iterable, Tuple, MatrixCommon, NDimArray)):
-            from sympy import derive_by_array
-            func = derive_by_array
-
-        if isinstance(n, (int, Integer)):
-            obj = expr
-            for i in range(n):
-                obj2 = func(obj, s)
-                if obj == obj2:
-                    break
-                obj = obj2
-            return obj
-        elif expr.is_Derivative:
-            dict_var_count = dict(expr.variable_count)
-            if s in dict_var_count:
-                dict_var_count[s] += n
-            else:
-                dict_var_count[s] = n
-            from sympy import Derivative
-            return Derivative(expr.expr, *dict_var_count.items())
-        else:
-            return None
-
     @classmethod
     def _remove_derived_once(cls, v):
         return [i[0] if i[1] == 1 else i for i in v]
diff --git a/sympy/core/mul.py b/sympy/core/mul.py
index b399e9d7ae..29e6085ce3 100644
--- a/sympy/core/mul.py
+++ b/sympy/core/mul.py
@@ -902,44 +902,6 @@ def _eval_derivative(self, s):
                 terms.append(self.func(*(args[:i] + [d] + args[i + 1:])))
         return Add(*terms)
 
-    @cacheit
-    def _eval_derivative_n_times(self, s, n):
-        # https://en.wikipedia.org/wiki/General_Leibniz_rule#More_than_two_factors
-        from sympy import Integer, factorial, prod, Dummy, symbols, Sum
-        args = [arg for arg in self.args if arg.has(s)]
-        coeff_args = [arg for arg in self.args if arg not in args]
-        m = len(args)
-        if m == 1:
-            return args[0].diff((s, n))*Mul.fromiter(coeff_args)
-
-        if isinstance(n, (int, Integer)):
-            return super(Mul, self)._eval_derivative_n_times(s, n)
-
-            # Code not yet activated:
-            def sum_to_n(n, m):
-                if m == 1:
-                    yield (n,)
-                else:
-                    for x in range(n+1):
-                        for y in sum_to_n(n-x, m-1):
-                            yield (x,) + y
-            accum_sum = S.Zero
-            for kvals in sum_to_n(n, m):
-                part1 = factorial(n)/prod([factorial(k) for k in kvals])
-                part2 = prod([arg.diff((s, k)) for k, arg in zip(kvals, args)])
-                accum_sum += part1 * part2
-            return accum_sum * Mul.fromiter(coeff_args)
-
-        kvals = symbols("k1:%i" % m, cls=Dummy)
-        klast = n - sum(kvals)
-        result = Sum(
-            # better to use the multinomial?
-            factorial(n)/prod(map(factorial, kvals))/factorial(klast)*\
-            prod([args[t].diff((s, kvals[t])) for t in range(m-1)])*\
-            args[-1].diff((s, klast)),
-            *[(k, 0, n) for k in kvals])
-        return result*Mul.fromiter(coeff_args)
-
     def _eval_difference_delta(self, n, step):
         from sympy.series.limitseq import difference_delta as dd
         arg0 = self.args[0]
diff --git a/sympy/functions/special/polynomials.py b/sympy/functions/special/polynomials.py
index dffb250302..6c84b5da84 100644
--- a/sympy/functions/special/polynomials.py
+++ b/sympy/functions/special/polynomials.py
@@ -797,11 +797,12 @@ def eval(cls, n, x):
             elif x == S.Infinity:
                 return S.Infinity
         else:
-            # n is a given fixed integer, evaluate into polynomial;
-            # L_{-n}(x)  --->  L_{n-1}(x)
+            # n is a given fixed integer, evaluate into polynomial
             if n.is_negative:
-                n = -n - S.One
-            return cls._eval_at_order(n, x)
+                raise ValueError(
+                    "The index n must be nonnegative integer (got %r)" % n)
+            else:
+                return cls._eval_at_order(n, x)
 
     def fdiff(self, argindex=2):
         if argindex == 1:
diff --git a/sympy/functions/special/zeta_functions.py b/sympy/functions/special/zeta_functions.py
index 8e9737aaf6..2abda6d7c3 100644
--- a/sympy/functions/special/zeta_functions.py
+++ b/sympy/functions/special/zeta_functions.py
@@ -271,6 +271,7 @@ class polylog(Function):
 
     @classmethod
     def eval(cls, s, z):
+        s, z = sympify((s, z))
         if z == 1:
             return zeta(s)
         elif z == -1:
@@ -297,6 +298,11 @@ def eval(cls, s, z):
             return z/(1 - z)
         elif s == -1:
             return z/(1 - z)**2
+        # polylog is branched, but not over the unit disk
+        if z.is_polar:
+            from sympy.functions.elementary.complexes import Abs, unpolarify
+            if (Abs(z) <= S.One) == True:
+                return cls(s, unpolarify(z))
 
     def fdiff(self, argindex=1):
         s, z = self.args
diff --git a/sympy/tensor/array/ndim_array.py b/sympy/tensor/array/ndim_array.py
index b2c4135a76..e36f91ea19 100644
--- a/sympy/tensor/array/ndim_array.py
+++ b/sympy/tensor/array/ndim_array.py
@@ -227,13 +227,7 @@ def diff(self, *args):
         return Derivative(self.as_immutable(), *args, evaluate=True)
 
     def _eval_derivative(self, arg):
-        from sympy import derive_by_array
-        from sympy import Derivative, Tuple
-        from sympy.matrices.common import MatrixCommon
-        if isinstance(arg, (collections.Iterable, Tuple, MatrixCommon, NDimArray)):
-            return derive_by_array(self, arg)
-        else:
-            return self.applyfunc(lambda x: x.diff(arg))
+        return self.applyfunc(lambda x: x.diff(arg))
 
     def applyfunc(self, f):
         """Apply a function to each element of the N-dim array.


Test patch:
diff --git a/sympy/core/tests/test_diff.py b/sympy/core/tests/test_diff.py
index 5787454c72..74e3a45c30 100644
--- a/sympy/core/tests/test_diff.py
+++ b/sympy/core/tests/test_diff.py
@@ -1,5 +1,5 @@
 from sympy import Symbol, Rational, cos, sin, tan, cot, exp, log, Function, \
-    Derivative, Expr, symbols, pi, I, S, diff, Piecewise, Eq, ff, Sum
+    Derivative, Expr, symbols, pi, I, S, diff
 from sympy.utilities.pytest import raises
 
 
@@ -123,18 +123,3 @@ def test_diff_nth_derivative():
     # Currently not supported (cannot determine if `n > 1`):
     #assert expr3.subs(Derivative(f(x), x), y) == Derivative(y, (x, n-1))
     assert expr3 == Derivative(f(x), (x, n))
-
-    assert diff(x, (x, n)) == Piecewise((x, Eq(n, 0)), (1, Eq(n, 1)), (0, True))
-    assert diff(2*x, (x, n)) == 2*Piecewise((x, Eq(n, 0)), (1, Eq(n, 1)), (0, True))
-    # TODO: assert diff(x**2, (x, n)) == x**(2-n)*ff(2, n)
-    exprm = x*sin(x)
-    mul_diff = diff(exprm, (x, n))
-    assert isinstance(mul_diff, Sum)
-    for i in range(5):
-        assert mul_diff.subs(n, i).doit() == exprm.diff((x, i)).expand()
-
-    exprm2 = 2*y*x*sin(x)*cos(x)*log(x)*exp(x)
-    dex = exprm2.diff((x, n))
-    assert isinstance(dex/2/y, Sum)
-    for i in range(7):
-        assert dex.subs(n, i).doit().expand() == exprm2.diff((x, i)).expand()
diff --git a/sympy/core/tests/test_function.py b/sympy/core/tests/test_function.py
index 29546a7d72..aa5dfb12a5 100644
--- a/sympy/core/tests/test_function.py
+++ b/sympy/core/tests/test_function.py
@@ -1,7 +1,7 @@
 from sympy import (Lambda, Symbol, Function, Derivative, Subs, sqrt,
         log, exp, Rational, Float, sin, cos, acos, diff, I, re, im,
         E, expand, pi, O, Sum, S, polygamma, loggamma, expint,
-        Tuple, Dummy, Eq, Expr, symbols, nfloat, Piecewise)
+        Tuple, Dummy, Eq, Expr, symbols, nfloat)
 from sympy.utilities.pytest import XFAIL, raises
 from sympy.abc import t, w, x, y, z
 from sympy.core.function import PoleError, _mexpand
@@ -79,7 +79,7 @@ def test_derivative_linearity():
     assert diff(8*f(x), x) == 8*diff(f(x), x)
     assert diff(8*f(x), x) != 7*diff(f(x), x)
     assert diff(8*f(x)*x, x) == 8*f(x) + 8*x*diff(f(x), x)
-    assert diff(8*f(x)*y*x, x).expand() == 8*y*f(x) + 8*y*x*diff(f(x), x)
+    assert diff(8*f(x)*y*x, x) == 8*y*f(x) + 8*y*x*diff(f(x), x)
 
 
 def test_derivative_evaluate():
@@ -878,7 +878,7 @@ def test_order_could_be_zero():
     x, y = symbols('x, y')
     n = symbols('n', integer=True, nonnegative=True)
     m = symbols('m', integer=True, positive=True)
-    assert diff(y, (x, n)) == Piecewise((y, Eq(n, 0)), (0, True))
+    assert diff(y, (x, n)) == Derivative(y, (x, n))
     assert diff(y, (x, n + 1)) == S.Zero
     assert diff(y, (x, m)) == S.Zero
 
diff --git a/sympy/functions/special/tests/test_spec_polynomials.py b/sympy/functions/special/tests/test_spec_polynomials.py
index 0c0f6a3422..f67bb86020 100644
--- a/sympy/functions/special/tests/test_spec_polynomials.py
+++ b/sympy/functions/special/tests/test_spec_polynomials.py
@@ -91,6 +91,7 @@ def test_gegenbauer():
 
 
 def test_legendre():
+    raises(ValueError, lambda: legendre(-1, x))
     assert legendre(0, x) == 1
     assert legendre(1, x) == x
     assert legendre(2, x) == ((3*x**2 - 1)/2).expand()
@@ -106,10 +107,6 @@ def test_legendre():
     assert legendre(10, 0) != 0
     assert legendre(11, 0) == 0
 
-    assert legendre(-1, x) == 1
-    k = Symbol('k')
-    assert legendre(5 - k, x).subs(k, 2) == ((5*x**3 - 3*x)/2).expand()
-
     assert roots(legendre(4, x), x) == {
         sqrt(Rational(3, 7) - Rational(2, 35)*sqrt(30)): 1,
         -sqrt(Rational(3, 7) - Rational(2, 35)*sqrt(30)): 1,
@@ -163,12 +160,15 @@ def test_assoc_legendre():
 
     assert Plm(n, 0, x) == legendre(n, x)
 
+    raises(ValueError, lambda: Plm(-1, 0, x))
+    raises(ValueError, lambda: Plm(0, 1, x))
+
     assert conjugate(assoc_legendre(n, m, x)) == \
         assoc_legendre(n, conjugate(m), conjugate(x))
-    raises(ValueError, lambda: Plm(0, 1, x))
 
 
 def test_chebyshev():
+
     assert chebyshevt(0, x) == 1
     assert chebyshevt(1, x) == x
     assert chebyshevt(2, x) == 2*x**2 - 1
diff --git a/sympy/functions/special/tests/test_zeta_functions.py b/sympy/functions/special/tests/test_zeta_functions.py
index 6370cc55db..ab2ec9fef4 100644
--- a/sympy/functions/special/tests/test_zeta_functions.py
+++ b/sympy/functions/special/tests/test_zeta_functions.py
@@ -1,6 +1,6 @@
 from sympy import (Symbol, zeta, nan, Rational, Float, pi, dirichlet_eta, log,
                    zoo, expand_func, polylog, lerchphi, S, exp, sqrt, I,
-                   exp_polar, polar_lift, O, stieltjes, Abs)
+                   exp_polar, polar_lift, O, stieltjes, Abs, Sum)
 from sympy.utilities.randtest import (test_derivative_numerically as td,
                       random_complex_number as randcplx, verify_numerically as tn)
 
@@ -127,6 +127,8 @@ def test_polylog_expansion():
     assert polylog(s, 0) == 0
     assert polylog(s, 1) == zeta(s)
     assert polylog(s, -1) == -dirichlet_eta(s)
+    assert polylog(s, exp_polar(4*I*pi/3)) == polylog(s, exp(4*I*pi/3))
+    assert polylog(s, exp_polar(I*pi)/3) == polylog(s, exp(I*pi)/3)
 
     assert myexpand(polylog(1, z), -log(1 - z))
     assert myexpand(polylog(0, z), z/(1 - z))
@@ -135,6 +137,12 @@ def test_polylog_expansion():
     assert myexpand(polylog(-5, z), None)
 
 
+def test_issue_8404():
+    i = Symbol('i', integer=True)
+    assert Abs(Sum(1/(3*i + 1)**2, (i, 0, S.Infinity)).doit().n(4)
+        - 1.122) < 0.001
+
+
 def test_polylog_values():
     from sympy.utilities.randtest import verify_numerically as tn
     assert polylog(2, 2) == pi**2/4 - I*pi*log(2)
diff --git a/sympy/integrals/tests/test_integrals.py b/sympy/integrals/tests/test_integrals.py
index 2669b154e2..bdab321a8c 100644
--- a/sympy/integrals/tests/test_integrals.py
+++ b/sympy/integrals/tests/test_integrals.py
@@ -286,6 +286,10 @@ def test_transcendental_functions():
         -x + x*LambertW(2*x) + x/LambertW(2*x)
 
 
+def test_log_polylog():
+    assert integrate(log(1 - x)/x, (x, 0, 1)) == -pi**2/6
+
+
 def test_issue_3740():
     f = 4*log(x) - 2*log(x)**2
     fid = diff(integrate(f, x), x)