Repository: sympy/sympy

Issue:
bug with MatrixSymbol and subs()
This session illustrates the bug:

In [1]: import sympy
In [2]: sympy.__version__
Out[2]: '1.0'
In [3]: from sympy import *
In [4]: A=MatrixSymbol('A',1,3)
In [5]: B=MatrixSymbol('B',1,3)
In [6]: C=MatrixSymbol('C',1,3)
In [7]: E=A-B
In [8]: F=C[0,0]
In [9]: F.subs(C,E)
Out[9]: (-1)*B + A[0, 0]

The output should be 
Out[9]: (-1)*B[0, 0] + A[0, 0]
or
Out[9]: ((-1)*B + A)[0, 0]


Discussion:

Patch:
diff --git a/sympy/printing/ccode.py b/sympy/printing/ccode.py
index e3914f5ff9..6bc940a321 100644
--- a/sympy/printing/ccode.py
+++ b/sympy/printing/ccode.py
@@ -18,7 +18,7 @@
 from sympy.core.decorators import deprecated
 from sympy.codegen.ast import Assignment
 from sympy.printing.codeprinter import CodePrinter
-from sympy.printing.precedence import precedence
+from sympy.printing.precedence import precedence, PRECEDENCE
 from sympy.sets.fancysets import Range
 
 # dictionary mapping sympy function to (argument_conditions, C_function).
@@ -244,8 +244,8 @@ def _print_ITE(self, expr):
         return self._print(_piecewise)
 
     def _print_MatrixElement(self, expr):
-        return "{0}[{1}]".format(expr.parent, expr.j +
-                expr.i*expr.parent.shape[1])
+        return "{0}[{1}]".format(self.parenthesize(expr.parent, PRECEDENCE["Atom"],
+            strict=True), expr.j + expr.i*expr.parent.shape[1])
 
     def _print_Symbol(self, expr):
         name = super(C89CodePrinter, self)._print_Symbol(expr)
diff --git a/sympy/printing/dot.py b/sympy/printing/dot.py
index d4b9e07f58..05fb11f6f5 100644
--- a/sympy/printing/dot.py
+++ b/sympy/printing/dot.py
@@ -98,7 +98,7 @@ def dotedges(expr, atom=lambda x: not isinstance(x, Basic), pos=(), repeat=True)
         if repeat:
             expr_str += '_%s' % str(pos)
             arg_strs = [arg_str + '_%s' % str(pos + (i,)) for i, arg_str in enumerate(arg_strs)]
-        return ['"%s" -> "%s";'%(expr_str, arg_str) for arg_str in arg_strs]
+        return ['"%s" -> "%s";' % (expr_str, arg_str) for arg_str in arg_strs]
 
 template = \
 """digraph{
diff --git a/sympy/printing/fcode.py b/sympy/printing/fcode.py
index 0e3e8a6182..70f7541764 100644
--- a/sympy/printing/fcode.py
+++ b/sympy/printing/fcode.py
@@ -29,7 +29,7 @@
 from sympy.codegen.ast import Assignment
 from sympy.codegen.ffunctions import isign, dsign, cmplx, merge, literal_dp
 from sympy.printing.codeprinter import CodePrinter
-from sympy.printing.precedence import precedence
+from sympy.printing.precedence import precedence, PRECEDENCE
 
 known_functions = {
     "sin": "sin",
@@ -185,7 +185,8 @@ def _print_Piecewise(self, expr):
                                       "standards earlier than Fortran95.")
 
     def _print_MatrixElement(self, expr):
-        return "{0}({1}, {2})".format(expr.parent, expr.i + 1, expr.j + 1)
+        return "{0}({1}, {2})".format(self.parenthesize(expr.parent,
+                PRECEDENCE["Atom"], strict=True), expr.i + 1, expr.j + 1)
 
     def _print_Add(self, expr):
         # purpose: print complex numbers nicely in Fortran.
diff --git a/sympy/printing/jscode.py b/sympy/printing/jscode.py
index 30ed1d31eb..95e715f92a 100644
--- a/sympy/printing/jscode.py
+++ b/sympy/printing/jscode.py
@@ -12,7 +12,7 @@
 from sympy.core import S
 from sympy.codegen.ast import Assignment
 from sympy.printing.codeprinter import CodePrinter
-from sympy.printing.precedence import precedence
+from sympy.printing.precedence import precedence, PRECEDENCE
 from sympy.core.compatibility import string_types, range
 
 
@@ -160,8 +160,9 @@ def _print_Piecewise(self, expr):
             return ": ".join(ecpairs) + last_line + " ".join([")"*len(ecpairs)])
 
     def _print_MatrixElement(self, expr):
-        return "{0}[{1}]".format(expr.parent, expr.j +
-                expr.i*expr.parent.shape[1])
+        return "{0}[{1}]".format(self.parenthesize(expr.parent,
+            PRECEDENCE["Atom"], strict=True),
+            expr.j + expr.i*expr.parent.shape[1])
 
     def indent_code(self, code):
         """Accepts a string of code or a list of code lines"""
diff --git a/sympy/printing/julia.py b/sympy/printing/julia.py
index 815f7094ec..a895b61a7a 100644
--- a/sympy/printing/julia.py
+++ b/sympy/printing/julia.py
@@ -14,7 +14,7 @@
 from sympy.core.compatibility import string_types, range
 from sympy.core.mul import _keep_coeff
 from sympy.printing.codeprinter import CodePrinter, Assignment
-from sympy.printing.precedence import precedence
+from sympy.printing.precedence import precedence, PRECEDENCE
 from re import search
 
 # List of known functions.  First, those that have the same name in
@@ -363,7 +363,8 @@ def _print_SparseMatrix(self, A):
 
 
     def _print_MatrixElement(self, expr):
-        return self._print(expr.parent) + '[%s,%s]'%(expr.i+1, expr.j+1)
+        return self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) \
+            + '[%s,%s]' % (expr.i + 1, expr.j + 1)
 
 
     def _print_MatrixSlice(self, expr):
diff --git a/sympy/printing/latex.py b/sympy/printing/latex.py
index e3f418051f..477d434be9 100644
--- a/sympy/printing/latex.py
+++ b/sympy/printing/latex.py
@@ -1361,7 +1361,8 @@ def _print_MatrixBase(self, expr):
                            = _print_MatrixBase
 
     def _print_MatrixElement(self, expr):
-        return self._print(expr.parent) + '_{%s, %s}'%(expr.i, expr.j)
+        return self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) \
+            + '_{%s, %s}' % (expr.i, expr.j)
 
     def _print_MatrixSlice(self, expr):
         def latexslice(x):
diff --git a/sympy/printing/octave.py b/sympy/printing/octave.py
index 4c0887a3ad..0be218d6a2 100644
--- a/sympy/printing/octave.py
+++ b/sympy/printing/octave.py
@@ -16,7 +16,7 @@
 from sympy.core.mul import _keep_coeff
 from sympy.codegen.ast import Assignment
 from sympy.printing.codeprinter import CodePrinter
-from sympy.printing.precedence import precedence
+from sympy.printing.precedence import precedence, PRECEDENCE
 from re import search
 
 # List of known functions.  First, those that have the same name in
@@ -345,7 +345,8 @@ def _print_SparseMatrix(self, A):
 
 
     def _print_MatrixElement(self, expr):
-        return self._print(expr.parent) + '(%s, %s)'%(expr.i+1, expr.j+1)
+        return self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) \
+            + '(%s, %s)' % (expr.i + 1, expr.j + 1)
 
 
     def _print_MatrixSlice(self, expr):
diff --git a/sympy/printing/pretty/pretty.py b/sympy/printing/pretty/pretty.py
index adde0dd2e4..8270512e5e 100644
--- a/sympy/printing/pretty/pretty.py
+++ b/sympy/printing/pretty/pretty.py
@@ -689,9 +689,10 @@ def _print_MatrixElement(self, expr):
         if (isinstance(expr.parent, MatrixSymbol)
                 and expr.i.is_number and expr.j.is_number):
             return self._print(
-                    Symbol(expr.parent.name + '_%d%d'%(expr.i, expr.j)))
+                    Symbol(expr.parent.name + '_%d%d' % (expr.i, expr.j)))
         else:
             prettyFunc = self._print(expr.parent)
+            prettyFunc = prettyForm(*prettyFunc.parens())
             prettyIndices = self._print_seq((expr.i, expr.j), delimiter=', '
                     ).parens(left='[', right=']')[0]
             pform = prettyForm(binding=prettyForm.FUNC,
diff --git a/sympy/printing/rcode.py b/sympy/printing/rcode.py
index 8de4811548..a22aa4a0b5 100644
--- a/sympy/printing/rcode.py
+++ b/sympy/printing/rcode.py
@@ -14,7 +14,7 @@
 from sympy.core.compatibility import string_types, range
 from sympy.codegen.ast import Assignment
 from sympy.printing.codeprinter import CodePrinter
-from sympy.printing.precedence import precedence
+from sympy.printing.precedence import precedence, PRECEDENCE
 from sympy.sets.fancysets import Range
 
 # dictionary mapping sympy function to (argument_conditions, C_function).
@@ -226,8 +226,8 @@ def _print_ITE(self, expr):
         return self._print(_piecewise)
 
     def _print_MatrixElement(self, expr):
-        return "{0}[{1}]".format(expr.parent, expr.j +
-                expr.i*expr.parent.shape[1])
+        return "{0}[{1}]".format(self.parenthesize(expr.parent, PRECEDENCE["Atom"],
+            strict=True), expr.j + expr.i*expr.parent.shape[1])
 
     def _print_Symbol(self, expr):
         name = super(RCodePrinter, self)._print_Symbol(expr)
diff --git a/sympy/printing/str.py b/sympy/printing/str.py
index 98dba347f7..3a31e54ced 100644
--- a/sympy/printing/str.py
+++ b/sympy/printing/str.py
@@ -237,7 +237,8 @@ def _print_MatrixBase(self, expr):
         _print_MatrixBase
 
     def _print_MatrixElement(self, expr):
-        return self._print(expr.parent) + '[%s, %s]'%(expr.i, expr.j)
+        return self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) \
+            + '[%s, %s]' % (expr.i, expr.j)
 
     def _print_MatrixSlice(self, expr):
         def strslice(x):


Test patch:
diff --git a/sympy/printing/pretty/tests/test_pretty.py b/sympy/printing/pretty/tests/test_pretty.py
index 684eb8a1c2..458831e95c 100644
--- a/sympy/printing/pretty/tests/test_pretty.py
+++ b/sympy/printing/pretty/tests/test_pretty.py
@@ -5827,3 +5827,26 @@ def test_issue_10472():
 ⎝⎣0  0⎦  ⎣0⎦⎠\
 """)
     assert upretty(M) == ucode_str
+
+
+def test_MatrixElement_printing():
+    # test cases for issue #11821
+    A = MatrixSymbol("A", 1, 3)
+    B = MatrixSymbol("B", 1, 3)
+    C = MatrixSymbol("C", 1, 3)
+
+    ascii_str1 = "A_00"
+    ucode_str1 = u("A₀₀")
+    assert pretty(A[0, 0])  == ascii_str1
+    assert upretty(A[0, 0]) == ucode_str1
+
+    ascii_str1 = "3*A_00"
+    ucode_str1 = u("3⋅A₀₀")
+    assert pretty(3*A[0, 0])  == ascii_str1
+    assert upretty(3*A[0, 0]) == ucode_str1
+
+    ascii_str1 = "(-B + A)[0, 0]"
+    ucode_str1 = u("(-B + A)[0, 0]")
+    F = C[0, 0].subs(C, A - B)
+    assert pretty(F)  == ascii_str1
+    assert upretty(F) == ucode_str1
diff --git a/sympy/printing/tests/test_ccode.py b/sympy/printing/tests/test_ccode.py
index 605f38d42f..465d73488b 100644
--- a/sympy/printing/tests/test_ccode.py
+++ b/sympy/printing/tests/test_ccode.py
@@ -588,6 +588,20 @@ def test_get_math_macros():
     assert macros[exp(1)] == 'M_E'
     assert macros[1/Sqrt(2)] == 'M_SQRT1_2'
 
+
+def test_MatrixElement_printing():
+    # test cases for issue #11821
+    A = MatrixSymbol("A", 1, 3)
+    B = MatrixSymbol("B", 1, 3)
+    C = MatrixSymbol("C", 1, 3)
+
+    assert(ccode(A[0, 0]) == "A[0]")
+    assert(ccode(3 * A[0, 0]) == "3*A[0]")
+
+    F = C[0, 0].subs(C, A - B)
+    assert(ccode(F) == "((-1)*B + A)[0]")
+
+
 def test_subclass_CCodePrinter():
     # issue gh-12687
     class MySubClass(CCodePrinter):
diff --git a/sympy/printing/tests/test_conventions.py b/sympy/printing/tests/test_conventions.py
index d2eeedf5dc..6f758772ff 100644
--- a/sympy/printing/tests/test_conventions.py
+++ b/sympy/printing/tests/test_conventions.py
@@ -31,6 +31,7 @@ def test_super_sub():
     assert split_super_sub("alpha_11_11") == ("alpha", [], ["11", "11"])
     assert split_super_sub("") == ("", [], [])
 
+
 def test_requires_partial():
     x, y, z, t, nu = symbols('x y z t nu')
     n = symbols('n', integer=True)
diff --git a/sympy/printing/tests/test_fcode.py b/sympy/printing/tests/test_fcode.py
index 746fe02a32..63688d0d72 100644
--- a/sympy/printing/tests/test_fcode.py
+++ b/sympy/printing/tests/test_fcode.py
@@ -685,3 +685,16 @@ def test_fcode_For():
     assert sol == ("      do x = 0, 10, 2\n"
                    "         y = x*y\n"
                    "      end do")
+
+
+def test_MatrixElement_printing():
+    # test cases for issue #11821
+    A = MatrixSymbol("A", 1, 3)
+    B = MatrixSymbol("B", 1, 3)
+    C = MatrixSymbol("C", 1, 3)
+
+    assert(fcode(A[0, 0]) == "      A(1, 1)")
+    assert(fcode(3 * A[0, 0]) == "      3*A(1, 1)")
+
+    F = C[0, 0].subs(C, A - B)
+    assert(fcode(F) == "      ((-1)*B + A)(1, 1)")
diff --git a/sympy/printing/tests/test_jscode.py b/sympy/printing/tests/test_jscode.py
index e40f38eb6d..ac1f498320 100644
--- a/sympy/printing/tests/test_jscode.py
+++ b/sympy/printing/tests/test_jscode.py
@@ -364,3 +364,16 @@ def test_Matrix_printing():
         "M[6] = 2*q[4]/q[1];\n"
         "M[7] = Math.sqrt(q[0]) + 4;\n"
         "M[8] = 0;")
+
+
+def test_MatrixElement_printing():
+    # test cases for issue #11821
+    A = MatrixSymbol("A", 1, 3)
+    B = MatrixSymbol("B", 1, 3)
+    C = MatrixSymbol("C", 1, 3)
+
+    assert(jscode(A[0, 0]) == "A[0]")
+    assert(jscode(3 * A[0, 0]) == "3*A[0]")
+
+    F = C[0, 0].subs(C, A - B)
+    assert(jscode(F) == "((-1)*B + A)[0]")
diff --git a/sympy/printing/tests/test_julia.py b/sympy/printing/tests/test_julia.py
index cf6a7ff72f..123f354b4c 100644
--- a/sympy/printing/tests/test_julia.py
+++ b/sympy/printing/tests/test_julia.py
@@ -285,7 +285,7 @@ def test_julia_matrix_elements():
     assert julia_code(A[0, 0]**2 + A[0, 1] + A[0, 2]) == "x.^2 + x.*y + 2"
     A = MatrixSymbol('AA', 1, 3)
     assert julia_code(A) == "AA"
-    assert julia_code(A[0,0]**2 + sin(A[0,1]) + A[0,2]) == \
+    assert julia_code(A[0, 0]**2 + sin(A[0,1]) + A[0,2]) == \
            "sin(AA[1,2]) + AA[1,1].^2 + AA[1,3]"
     assert julia_code(sum(A)) == "AA[1,1] + AA[1,2] + AA[1,3]"
 
@@ -362,3 +362,16 @@ def test_specfun():
     assert julia_code(hankel2(n, x)) == 'hankelh2(n, x)'
     assert julia_code(jn(n, x)) == 'sqrt(2)*sqrt(pi)*sqrt(1./x).*besselj(n + 1/2, x)/2'
     assert julia_code(yn(n, x)) == 'sqrt(2)*sqrt(pi)*sqrt(1./x).*bessely(n + 1/2, x)/2'
+
+
+def test_MatrixElement_printing():
+    # test cases for issue #11821
+    A = MatrixSymbol("A", 1, 3)
+    B = MatrixSymbol("B", 1, 3)
+    C = MatrixSymbol("C", 1, 3)
+
+    assert(julia_code(A[0, 0]) == "A[1,1]")
+    assert(julia_code(3 * A[0, 0]) == "3*A[1,1]")
+
+    F = C[0, 0].subs(C, A - B)
+    assert(julia_code(F) == "((-1)*B + A)[1,1]")
diff --git a/sympy/printing/tests/test_latex.py b/sympy/printing/tests/test_latex.py
index e285f86449..a6e13e5319 100644
--- a/sympy/printing/tests/test_latex.py
+++ b/sympy/printing/tests/test_latex.py
@@ -35,6 +35,7 @@
 from sympy.core.trace import Tr
 from sympy.core.compatibility import range
 from sympy.combinatorics.permutations import Cycle, Permutation
+from sympy import MatrixSymbol
 
 x, y, z, t, a, b = symbols('x y z t a b')
 k, m, n = symbols('k m n', integer=True)
@@ -1593,3 +1594,16 @@ def test_latex_UnevaluatedExpr():
     assert latex(he**2) == r"\left(\frac{1}{x}\right)^{2}"
     assert latex(he + 1) == r"1 + \frac{1}{x}"
     assert latex(x*he) == r"x \frac{1}{x}"
+
+
+def test_MatrixElement_printing():
+    # test cases for issue #11821
+    A = MatrixSymbol("A", 1, 3)
+    B = MatrixSymbol("B", 1, 3)
+    C = MatrixSymbol("C", 1, 3)
+
+    assert latex(A[0, 0]) == r"A_{0, 0}"
+    assert latex(3 * A[0, 0]) == r"3 A_{0, 0}"
+
+    F = C[0, 0].subs(C, A - B)
+    assert latex(F) == r"\left(-1 B + A\right)_{0, 0}"
diff --git a/sympy/printing/tests/test_octave.py b/sympy/printing/tests/test_octave.py
index a5471c357d..c5d0d93085 100644
--- a/sympy/printing/tests/test_octave.py
+++ b/sympy/printing/tests/test_octave.py
@@ -288,7 +288,7 @@ def test_octave_matrix_elements():
     assert mcode(A[0, 0]**2 + A[0, 1] + A[0, 2]) == "x.^2 + x.*y + 2"
     A = MatrixSymbol('AA', 1, 3)
     assert mcode(A) == "AA"
-    assert mcode(A[0,0]**2 + sin(A[0,1]) + A[0,2]) == \
+    assert mcode(A[0, 0]**2 + sin(A[0,1]) + A[0,2]) == \
            "sin(AA(1, 2)) + AA(1, 1).^2 + AA(1, 3)"
     assert mcode(sum(A)) == "AA(1, 1) + AA(1, 2) + AA(1, 3)"
 
@@ -377,3 +377,16 @@ def test_specfun():
     assert octave_code(yn(n, x)) == 'sqrt(2)*sqrt(pi)*sqrt(1./x).*bessely(n + 1/2, x)/2'
     assert octave_code(LambertW(x)) == 'lambertw(x)'
     assert octave_code(LambertW(x, n)) == 'lambertw(n, x)'
+
+
+def test_MatrixElement_printing():
+    # test cases for issue #11821
+    A = MatrixSymbol("A", 1, 3)
+    B = MatrixSymbol("B", 1, 3)
+    C = MatrixSymbol("C", 1, 3)
+
+    assert mcode(A[0, 0]) == "A(1, 1)"
+    assert mcode(3 * A[0, 0]) == "3*A(1, 1)"
+
+    F = C[0, 0].subs(C, A - B)
+    assert mcode(F) == "((-1)*B + A)(1, 1)"
diff --git a/sympy/printing/tests/test_rcode.py b/sympy/printing/tests/test_rcode.py
index b234b650b1..f622d07f32 100644
--- a/sympy/printing/tests/test_rcode.py
+++ b/sympy/printing/tests/test_rcode.py
@@ -469,3 +469,16 @@ def test_rcode_For():
     assert sol == ("for (x = 0; x < 10; x += 2) {\n"
                    "   y *= x;\n"
                    "}")
+
+
+def test_MatrixElement_printing():
+    # test cases for issue #11821
+    A = MatrixSymbol("A", 1, 3)
+    B = MatrixSymbol("B", 1, 3)
+    C = MatrixSymbol("C", 1, 3)
+
+    assert(rcode(A[0, 0]) == "A[0]")
+    assert(rcode(3 * A[0, 0]) == "3*A[0]")
+
+    F = C[0, 0].subs(C, A - B)
+    assert(rcode(F) == "((-1)*B + A)[0]")
diff --git a/sympy/printing/tests/test_str.py b/sympy/printing/tests/test_str.py
index de697f5430..d297790204 100644
--- a/sympy/printing/tests/test_str.py
+++ b/sympy/printing/tests/test_str.py
@@ -17,6 +17,7 @@
 
 from sympy.printing import sstr, sstrrepr, StrPrinter
 from sympy.core.trace import Tr
+from sympy import MatrixSymbol
 
 x, y, z, w = symbols('x,y,z,w')
 d = Dummy('d')
@@ -757,3 +758,16 @@ def test_UnevaluatedExpr():
     a, b = symbols("a b")
     expr1 = 2*UnevaluatedExpr(a+b)
     assert str(expr1) == "2*(a + b)"
+
+
+def test_MatrixElement_printing():
+    # test cases for issue #11821
+    A = MatrixSymbol("A", 1, 3)
+    B = MatrixSymbol("B", 1, 3)
+    C = MatrixSymbol("C", 1, 3)
+
+    assert(str(A[0, 0]) == "A[0, 0]")
+    assert(str(3 * A[0, 0]) == "3*A[0, 0]")
+
+    F = C[0, 0].subs(C, A - B)
+    assert str(F) == "((-1)*B + A)[0, 0]"
diff --git a/sympy/utilities/pytest.py b/sympy/utilities/pytest.py
index f2ab9e7d3b..9f96d169d9 100644
--- a/sympy/utilities/pytest.py
+++ b/sympy/utilities/pytest.py
@@ -147,7 +147,6 @@ def func_wrapper():
             func()
 
         func_wrapper = functools.update_wrapper(func_wrapper, func)
-        func_wrapper.__wrapped__ = func
         return func_wrapper
 
 else: