Repository: sympy/sympy

Issue:
Subs._eval_derivative doubles derivatives
This issue appears in the computation of higher derivatives with respect to functions.
```
>>> x = symbols('x')
>>> f = symbols('f', cls=Function)
>>> e = Subs(Derivative(f(x), x), (x,), (x,))
>>> e._eval_derivative(x)
2*Derivative(f(x), x, x)
```
Apparently, the derivative is computed in both of the two parts of the returned sum:
```
        return self.func(self.expr.diff(s), self.variables, self.point).doit() \
            + Add(*[ Subs(point.diff(s) * self.expr.diff(arg),
                    self.variables, self.point).doit() for arg,
                    point in zip(self.variables, self.point) ])
```


Discussion:

Patch:
diff --git a/sympy/core/function.py b/sympy/core/function.py
index 2d33d96b94..1b8005e1d2 100644
--- a/sympy/core/function.py
+++ b/sympy/core/function.py
@@ -1738,10 +1738,10 @@ def _eval_subs(self, old, new):
     def _eval_derivative(self, s):
         if s not in self.free_symbols:
             return S.Zero
-        return self.func(self.expr.diff(s), self.variables, self.point).doit() \
-            + Add(*[ Subs(point.diff(s) * self.expr.diff(arg),
-                    self.variables, self.point).doit() for arg,
-                    point in zip(self.variables, self.point) ])
+        return Add((Subs(self.expr.diff(s), self.variables, self.point).doit()
+            if s not in self.variables else S.Zero),
+            *[p.diff(s) * Subs(self.expr.diff(v), self.variables,
+            self.point).doit() for v, p in zip(self.variables, self.point)])
 
     def _eval_nseries(self, x, n, logx):
         if x in self.point:


Test patch:
diff --git a/sympy/core/tests/test_function.py b/sympy/core/tests/test_function.py
index d1fdd97ef8..0288a80c46 100644
--- a/sympy/core/tests/test_function.py
+++ b/sympy/core/tests/test_function.py
@@ -698,6 +698,7 @@ def test_mexpand():
     assert _mexpand(1) is S.One
     assert _mexpand(x*(x + 1)**2) == (x*(x + 1)**2).expand()
 
+
 def test_issue_8469():
     # This should not take forever to run
     N = 40
@@ -708,6 +709,7 @@ def g(w, theta):
     import functools
     expr = functools.reduce(g,ws)
 
+
 def test_should_evalf():
     # This should not take forever to run (see #8506)
     assert isinstance(sin((1.0 + 1.0*I)**10000 + 1), sin)
@@ -805,9 +807,24 @@ def test_Derivative_as_finite_difference():
     ref2 = f(xm, ym) + f(xp, yp) - f(xp, ym) - f(xm, yp)
     assert (d2fdxdy.as_finite_difference() - ref2).simplify() == 0
 
+
 def test_issue_11159():
     # Tests Application._eval_subs
     expr1 = E
     expr0 = expr1 * expr1
     expr1 = expr0.subs(expr1,expr0)
     assert expr0 == expr1
+
+
+def test_issue_12005():
+    e1 = Subs(Derivative(f(x), x), (x,), (x,))
+    assert e1.diff(x) == Derivative(f(x), x, x)
+    e2 = Subs(Derivative(f(x), x), (x,), (x**2 + 1,))
+    assert e2.diff(x) == 2*x*Subs(Derivative(f(x), x, x), (x,), (x**2 + 1,))
+    e3 = Subs(Derivative(f(x) + y**2 - y, y), (y,), (y**2,))
+    assert e3.diff(y) == 4*y
+    e4 = Subs(Derivative(f(x + y), y), (y,), (x**2))
+    assert e4.diff(y) == S.Zero
+    e5 = Subs(Derivative(f(x), x), (y, z), (y, z))
+    assert e5.diff(x) == Derivative(f(x), x, x)
+    assert f(g(x)).diff(g(x), g(x)) == Subs(Derivative(f(y), y, y), (y,), (g(x),))