Repository: sympy/sympy

Issue:
Operations with MatrixSymbol should use the symbol, not the name
`MatrixSymbol`'s can be set with an `Symbol`, such as
```python
x = MatrixSymbol(Symbol('x'), 3, 4)
```
However, some lines inside `MatrixSymbol` then use the `name` string, and not the object provided:

```python
def _eval_subs(self, old, new):
    # only do substitutions in shape
    shape = Tuple(*self.shape)._subs(old, new)
    return MatrixSymbol(self.name, *shape)

def doit(self, **hints):
    if hints.get('deep', True):
        return type(self)(self.name, self.args[1].doit(**hints),
                self.args[2].doit(**hints))
    else:
        return self
```
This breaks some of my code, where I have a Symbol subclass which does not only depend on a name. I would therefore propose changing the `self.name` here to `self.args[0]`.

As an additional question, in the `IndexedBase` class we call this kind of symbol a `label` instead, and then extract the `name` as `label.name`. Wouldn't it be more consistent to do the same thing here?

I will make a PR for the first, and let me know if the second idea is a good one, then I can also add that.

Discussion:

Patch:
diff --git a/sympy/matrices/expressions/matexpr.py b/sympy/matrices/expressions/matexpr.py
index 41ce24f2d7..8bab8adedf 100644
--- a/sympy/matrices/expressions/matexpr.py
+++ b/sympy/matrices/expressions/matexpr.py
@@ -768,7 +768,7 @@ def name(self):
     def _eval_subs(self, old, new):
         # only do substitutions in shape
         shape = Tuple(*self.shape)._subs(old, new)
-        return MatrixSymbol(self.name, *shape)
+        return MatrixSymbol(self.args[0], *shape)
 
     def __call__(self, *args):
         raise TypeError("%s object is not callable" % self.__class__)
@@ -782,7 +782,7 @@ def free_symbols(self):
 
     def doit(self, **hints):
         if hints.get('deep', True):
-            return type(self)(self.name, self.args[1].doit(**hints),
+            return type(self)(self.args[0], self.args[1].doit(**hints),
                     self.args[2].doit(**hints))
         else:
             return self


Test patch:
diff --git a/sympy/matrices/expressions/tests/test_matexpr.py b/sympy/matrices/expressions/tests/test_matexpr.py
index 9fa4e1c806..0246a6ce24 100644
--- a/sympy/matrices/expressions/tests/test_matexpr.py
+++ b/sympy/matrices/expressions/tests/test_matexpr.py
@@ -1,5 +1,5 @@
 from sympy import (KroneckerDelta, diff, Piecewise, Sum, Dummy, factor,
-                   expand, zeros, gcd_terms, Eq)
+                   expand, zeros, gcd_terms, Eq, Symbol)
 
 from sympy.core import S, symbols, Add, Mul, SympifyError
 from sympy.core.compatibility import long
@@ -547,3 +547,13 @@ def test_exp():
 
 def test_invalid_args():
     raises(SympifyError, lambda: MatrixSymbol(1, 2, 'A'))
+
+def test_matrixsymbol_from_symbol():
+    # The label should be preserved during doit and subs
+    A_label = Symbol('A', complex=True)
+    A = MatrixSymbol(A_label, 2, 2)
+
+    A_1 = A.doit()
+    A_2 = A.subs(2, 3)
+    assert A_1.args == A.args
+    assert A_2.args[0] == A.args[0]