Repository: sympy/sympy

Issue:
Elementwise Mod for matrices
Given a matrix, say, `A = Matrix([-1, 1, 2])`, we can perform some elementwise operations, like 
```
>>> Abs(A)
Matrix([ [1], [1], [2]])
```
Should the same be allowed for  `Mod`? Current behavior: 
```
>>> Mod(A, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/ubuntu/sympy/sympy/core/function.py", line 441, in __new__
    result = super(Function, cls).__new__(cls, *args, **options)
  File "/home/ubuntu/sympy/sympy/core/function.py", line 250, in __new__
    evaluated = cls.eval(*args)
  File "/home/ubuntu/sympy/sympy/core/mod.py", line 91, in eval
    rv = doit(p, q)
  File "/home/ubuntu/sympy/sympy/core/mod.py", line 77, in doit
    d -= abs(q)
  File "/home/ubuntu/sympy/sympy/core/decorators.py", line 132, in binary_op_wrapper
    return func(self, other)
  File "/home/ubuntu/sympy/sympy/matrices/common.py", line 2112, in __sub__
    return self + (-a)
  File "/home/ubuntu/sympy/sympy/core/decorators.py", line 132, in binary_op_wrapper
    return func(self, other)
  File "/home/ubuntu/sympy/sympy/matrices/common.py", line 1968, in __add__
    raise TypeError('cannot add %s and %s' % (type(self), type(other)))
TypeError: cannot add <class 'sympy.matrices.immutable.ImmutableDenseMatrix'> and <class 'sympy.core.numbers.Integer'>
```

Sure, there is `applyfunc` method that works, but applying `Mod` elementwise is a natural thing to do, as there isn't another interpretation for it (like there is for `exp`). At the very least it shouldn't throw that error. 

Based on a [Stack Overflow post](https://stackoverflow.com/questions/49245271/sympy-matrix-m-modulo-n-how)

Discussion:

Patch:
diff --git a/sympy/matrices/common.py b/sympy/matrices/common.py
index 54c418e01f..e8597ca98a 100644
--- a/sympy/matrices/common.py
+++ b/sympy/matrices/common.py
@@ -1938,6 +1938,10 @@ def _eval_scalar_mul(self, other):
     def _eval_scalar_rmul(self, other):
         return self._new(self.rows, self.cols, lambda i, j: other*self[i,j])
 
+    def _eval_Mod(self, other):
+        from sympy import Mod
+        return self._new(self.rows, self.cols, lambda i, j: Mod(self[i, j], other))
+
     # python arithmetic functions
     def __abs__(self):
         """Returns a new matrix with entry-wise absolute values."""


Test patch:
diff --git a/sympy/matrices/tests/test_matrices.py b/sympy/matrices/tests/test_matrices.py
index 702bdf92e8..c6d54d59e5 100644
--- a/sympy/matrices/tests/test_matrices.py
+++ b/sympy/matrices/tests/test_matrices.py
@@ -3082,3 +3082,11 @@ def test_deprecated():
         P, Jcells = m.jordan_cells()
         assert Jcells[1] == Matrix(1, 1, [2])
         assert Jcells[0] == Matrix(2, 2, [2, 1, 0, 2])
+
+def test_issue_14489():
+    from sympy import Mod
+    A = Matrix([-1, 1, 2])
+    B = Matrix([10, 20, -15])
+
+    assert Mod(A, 3) == Matrix([2, 1, 2])
+    assert Mod(B, 4) == Matrix([2, 0, 1])