Repository: sympy/sympy

Issue:
Regression in Matrix indexing with SymPy 1.2
On SymPy 1.1:

```
moorepants@garuda:sympy((sympy-1.1))$ ipython
Python 3.5.5 | packaged by conda-forge | (default, Apr  6 2018, 13:41:05) 
Type 'copyright', 'credits' or 'license' for more information
IPython 6.4.0 -- An enhanced Interactive Python. Type '?' for help.

In [3]: import sympy as sm

In [4]: t = sm.symbols('t')

In [7]: A = sm.Matrix([sm.Function('F')(t), sm.Function('G')(t)])

In [9]: type(A)
Out[9]: sympy.matrices.dense.MutableDenseMatrix

In [10]: type(A.diff(t))
Out[10]: sympy.matrices.dense.MutableDenseMatrix

In [11]: type(A.diff(t)[:])
Out[11]: list
```

On SymPy 1.2:

```
moorepants@garuda:sympy(master)$ ipython
Python 3.5.5 | packaged by conda-forge | (default, Apr  6 2018, 13:41:05) 
Type 'copyright', 'credits' or 'license' for more information
IPython 6.4.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import sympy as sm

In [2]: t = sm.symbols('t')

In [3]: A = sm.Matrix([sm.Function('F')(t), sm.Function('G')(t)])

In [4]: type(A.diff(t))
Out[4]: sympy.matrices.immutable.ImmutableDenseMatrix

In [5]: type(A.diff(t)[:])
Out[5]: tuple

```

MutableDenseMatrix indexing outputs a list now instead of a tuple.

Reported at PyDy here: https://github.com/pydy/pydy/issues/395

Discussion:

Patch:
diff --git a/doc/src/modules/physics/mechanics/examples/rollingdisc_example_lagrange.rst b/doc/src/modules/physics/mechanics/examples/rollingdisc_example_lagrange.rst
index a5a19c15b3..b5d532782f 100644
--- a/doc/src/modules/physics/mechanics/examples/rollingdisc_example_lagrange.rst
+++ b/doc/src/modules/physics/mechanics/examples/rollingdisc_example_lagrange.rst
@@ -56,14 +56,12 @@ accelerations(q double dots) with the ``rhs`` method. ::
   >>> q = [q1, q2, q3]
   >>> l = LagrangesMethod(Lag, q)
   >>> le = l.form_lagranges_equations()
-  >>> le = le.simplify()
-  >>> le
+  >>> le.simplify(); le
   Matrix([
   [m*r**2*(6*sin(q2)*q3'' + 5*sin(2*q2)*q1'*q2' + 6*cos(q2)*q2'*q3' - 5*cos(2*q2)*q1''/2 + 7*q1''/2)/4],
   [                      m*r*(4*g*sin(q2) - 5*r*sin(2*q2)*q1'**2/2 - 6*r*cos(q2)*q1'*q3' + 5*r*q2'')/4],
   [                                                 3*m*r**2*(sin(q2)*q1'' + cos(q2)*q1'*q2' + q3'')/2]])
-  >>> lrhs = l.rhs().simplify()
-  >>> lrhs
+  >>> lrhs = l.rhs(); lrhs.simplify(); lrhs
   Matrix([
   [                                                          q1'],
   [                                                          q2'],
diff --git a/sympy/matrices/matrices.py b/sympy/matrices/matrices.py
index 1d749498bd..f5eab5615e 100644
--- a/sympy/matrices/matrices.py
+++ b/sympy/matrices/matrices.py
@@ -1709,7 +1709,11 @@ def diff(self, *args, **kwargs):
         # XXX this should be handled here rather than in Derivative
         from sympy import Derivative
         kwargs.setdefault('evaluate', True)
-        return Derivative(self, *args, **kwargs)
+        deriv = Derivative(self, *args, evaluate=True)
+        if not isinstance(self, Basic):
+            return deriv.as_mutable()
+        else:
+            return deriv
 
     def _eval_derivative(self, arg):
         return self.applyfunc(lambda x: x.diff(arg))


Test patch:
diff --git a/sympy/matrices/tests/test_matrices.py b/sympy/matrices/tests/test_matrices.py
index 8b4a27abb7..d82aeeb017 100644
--- a/sympy/matrices/tests/test_matrices.py
+++ b/sympy/matrices/tests/test_matrices.py
@@ -1931,6 +1931,7 @@ def test_limit():
 
 def test_diff():
     A = MutableDenseMatrix(((1, 4, x), (y, 2, 4), (10, 5, x**2 + 1)))
+    assert isinstance(A.diff(x), type(A))
     assert A.diff(x) == MutableDenseMatrix(((0, 0, 1), (0, 0, 0), (0, 0, 2*x)))
     assert A.diff(y) == MutableDenseMatrix(((0, 0, 0), (1, 0, 0), (0, 0, 0)))
 
@@ -1938,12 +1939,16 @@ def test_diff():
     assert diff(A, y) == MutableDenseMatrix(((0, 0, 0), (1, 0, 0), (0, 0, 0)))
 
     A_imm = A.as_immutable()
+    assert isinstance(A_imm.diff(x), type(A_imm))
     assert A_imm.diff(x) == ImmutableDenseMatrix(((0, 0, 1), (0, 0, 0), (0, 0, 2*x)))
     assert A_imm.diff(y) == ImmutableDenseMatrix(((0, 0, 0), (1, 0, 0), (0, 0, 0)))
 
     assert diff(A_imm, x) == ImmutableDenseMatrix(((0, 0, 1), (0, 0, 0), (0, 0, 2*x)))
     assert diff(A_imm, y) == ImmutableDenseMatrix(((0, 0, 0), (1, 0, 0), (0, 0, 0)))
 
+
+def test_diff_by_matrix():
+
     # Derive matrix by matrix:
 
     A = MutableDenseMatrix([[x, y], [z, t]])
diff --git a/sympy/physics/mechanics/tests/test_lagrange.py b/sympy/physics/mechanics/tests/test_lagrange.py
index 8cc3e2c23e..038c23fea5 100644
--- a/sympy/physics/mechanics/tests/test_lagrange.py
+++ b/sympy/physics/mechanics/tests/test_lagrange.py
@@ -216,11 +216,11 @@ def test_rolling_disc():
     q3 = Function('q3')
     l = LagrangesMethod(Lag, q)
     l.form_lagranges_equations()
-    RHS = l.rhs().as_mutable()
+    RHS = l.rhs()
     RHS.simplify()
     t = symbols('t')
 
-    assert tuple(l.mass_matrix[3:6]) == (0, 5*m*r**2/4, 0)
+    assert (l.mass_matrix[3:6] == [0, 5*m*r**2/4, 0])
     assert RHS[4].simplify() == (
         (-8*g*sin(q2(t)) + r*(5*sin(2*q2(t))*Derivative(q1(t), t) +
         12*cos(q2(t))*Derivative(q3(t), t))*Derivative(q1(t), t))/(10*r))