Repository: sympy/sympy

Issue:
Trace of MatAdd can fail with error: "mix of Matrix and Scalar symbols"
````
In [18]: X = Matrix([[1, 2], [3, 4]])

In [19]: q = MatAdd(X, 2*X)

In [20]: Trace(q).doit(deep=False)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-20-038504dfa7f5> in <module>()
----> 1 Trace(q).doit(deep=False)

/home/cbm/work/octsympy/octsympy.git/inst/sympy/matrices/expressions/trace.pyc in doit(self, **kwargs)
     42             arg = self.arg
     43         try:
---> 44             return arg._eval_trace()
     45         except (AttributeError, NotImplementedError):
     46             return Trace(arg)

/home/cbm/work/octsympy/octsympy.git/inst/sympy/matrices/expressions/matadd.pyc in _eval_trace(self)
     52     def _eval_trace(self):
     53         from trace import Trace
---> 54         return MatAdd(*[Trace(arg) for arg in self.args]).doit()
     55 
     56     def doit(self, **kwargs):

/home/cbm/work/octsympy/octsympy.git/inst/sympy/matrices/expressions/matadd.pyc in __new__(cls, *args, **kwargs)
     34         obj = Basic.__new__(cls, *args)
     35         if check:
---> 36             validate(*args)
     37         return obj
     38 

/home/cbm/work/octsympy/octsympy.git/inst/sympy/matrices/expressions/matadd.pyc in validate(*args)
     64 def validate(*args):
     65     if not all(arg.is_Matrix for arg in args):
---> 66         raise TypeError("Mix of Matrix and Scalar symbols")
     67 
     68     A = args[0]

TypeError: Mix of Matrix and Scalar symbols
````

I will look into this.

Discussion:
lokeshh: There needs to be little change in the summary.

Instead of 
> It has been fixed by evaluating trace(MatAdd(X, Y)) to
trace(Z) where Z is what we have after evaluating
MatAdd(X, Y).

it should be

> It has been fixed by evaluating trace(MatAdd(X, Y)) to
Add(trace(X), trace(Y)).



Patch:
diff --git a/sympy/matrices/expressions/matadd.py b/sympy/matrices/expressions/matadd.py
index 345615d763..92c75aeb47 100644
--- a/sympy/matrices/expressions/matadd.py
+++ b/sympy/matrices/expressions/matadd.py
@@ -50,8 +50,8 @@ def _eval_adjoint(self):
         return MatAdd(*[adjoint(arg) for arg in self.args]).doit()
 
     def _eval_trace(self):
-        from trace import Trace
-        return MatAdd(*[Trace(arg) for arg in self.args]).doit()
+        from .trace import trace
+        return Add(*[trace(arg) for arg in self.args]).doit()
 
     def doit(self, **kwargs):
         deep = kwargs.get('deep', True)


Test patch:
diff --git a/sympy/matrices/expressions/tests/test_matmul.py b/sympy/matrices/expressions/tests/test_matmul.py
index b0f6ca3598..58d48f027c 100644
--- a/sympy/matrices/expressions/tests/test_matmul.py
+++ b/sympy/matrices/expressions/tests/test_matmul.py
@@ -7,6 +7,7 @@
         MatMul, xxinv, any_zeros, unpack, only_squares)
 from sympy.strategies import null_safe
 from sympy import refine, Q
+from sympy.utilities.pytest import XFAIL
 
 n, m, l, k = symbols('n m l k', integer=True)
 A = MatrixSymbol('A', n, m)
@@ -99,6 +100,13 @@ def test_doit_deep_false_still_canonical():
             (2, C, Transpose(D*C)))
 
 
+@XFAIL
+def test_matmul_scalar_Matrix_doit():
+    # Issue 9053
+    X = Matrix([[1, 2], [3, 4]])
+    assert MatMul(2, X).doit() == 2*X
+
+
 def test_matmul_sympify():
     assert isinstance(MatMul(eye(1), eye(1)).args[0], Basic)
 
diff --git a/sympy/matrices/expressions/tests/test_trace.py b/sympy/matrices/expressions/tests/test_trace.py
index 55b13c5ca6..77a50adc4a 100644
--- a/sympy/matrices/expressions/tests/test_trace.py
+++ b/sympy/matrices/expressions/tests/test_trace.py
@@ -1,10 +1,10 @@
 from sympy.core import Lambda, S, symbols
 from sympy.concrete import Sum
 from sympy.functions import adjoint, conjugate, transpose
-from sympy.matrices import eye, Matrix, ShapeError
+from sympy.matrices import eye, Matrix, ShapeError, ImmutableMatrix
 from sympy.matrices.expressions import (
     Adjoint, Identity, FunctionMatrix, MatrixExpr, MatrixSymbol, Trace,
-    ZeroMatrix, trace, MatPow, MatAdd
+    ZeroMatrix, trace, MatPow, MatAdd, MatMul
 )
 from sympy.utilities.pytest import raises, XFAIL
 
@@ -30,7 +30,7 @@ def test_Trace():
     # Some easy simplifications
     assert trace(Identity(5)) == 5
     assert trace(ZeroMatrix(5, 5)) == 0
-    assert trace(2*A*B) == 2 * trace(A*B)
+    assert trace(2*A*B) == 2*Trace(A*B)
     assert trace(A.T) == trace(A)
 
     i, j = symbols('i j')
@@ -44,13 +44,27 @@ def test_Trace():
     assert str(trace(A)) == str(Trace(A).doit())
 
 
-def test_Trace_doit():
+def test_Trace_A_plus_B():
+    assert trace(A + B) == Trace(A) + Trace(B)
+    assert Trace(A + B).arg == MatAdd(A, B)
+    assert Trace(A + B).doit() == Trace(A) + Trace(B)
+
+
+def test_Trace_MatAdd_doit():
+    # See issue #9028
+    X = ImmutableMatrix([[1, 2, 3]]*3)
+    Y = MatrixSymbol('Y', 3, 3)
+    q = MatAdd(X, 2*X, Y, -3*Y)
+    assert Trace(q).arg == q
+    assert Trace(q).doit() == 18 - 2*Trace(Y)
+
+
+def test_Trace_MatPow_doit():
     X = Matrix([[1, 2], [3, 4]])
     assert Trace(X).doit() == 5
     q = MatPow(X, 2)
     assert Trace(q).arg == q
     assert Trace(q).doit() == 29
-    assert Trace(q).doit(deep=False).arg == q
 
 
 def test_Trace_MutableMatrix_plus():
@@ -60,11 +74,22 @@ def test_Trace_MutableMatrix_plus():
 
 
 @XFAIL
-def test_Trace_MatAdd_doit():
-    # FIXME: Issue #9028.
+def test_Trace_doit_deep_False():
     X = Matrix([[1, 2], [3, 4]])
+    q = MatPow(X, 2)
+    assert Trace(q).doit(deep=False).arg == q
     q = MatAdd(X, 2*X)
     assert Trace(q).doit(deep=False).arg == q
+    q = MatMul(X, 2*X)
+    assert Trace(q).doit(deep=False).arg == q
+
+
+@XFAIL
+def test_trace_constant_factor():
+    # Issue 9052: LHS gives Trace(MatMul(A))
+    assert trace(2*A) == 2*Trace(A)
+    X = ImmutableMatrix([[1, 2], [3, 4]])
+    assert trace(MatMul(2, X)) == 10
 
 
 @XFAIL