Repository: sympy/sympy

Issue:
Singular matrix gives wrong result with negative powers
```python
In [3]: m = Matrix([[1, 1], [2, 2]])

In [4]: m**(-1)
---------------------------------------------------------------------------
ValueError: Matrix det == 0; not invertible.

In [5]: ;var N
Out[5]: N

In [6]: (m**N).subs(N, -1)
Out[6]: 
⎡zoo  zoo⎤
⎢        ⎥
⎣zoo  zoo⎦

In [7]: (m**N)
Out[7]: 
⎡     N    N       N    N⎤
⎢  2⋅0    3       0    3 ⎥
⎢  ──── + ──    - ── + ──⎥
⎢   3     3       3    3 ⎥
⎢                        ⎥
⎢     N      N   N      N⎥
⎢  2⋅0    2⋅3   0    2⋅3 ⎥
⎢- ──── + ────  ── + ────⎥
⎣   3      3    3     3  ⎦

```


Discussion:

Patch:
diff --git a/sympy/matrices/matrices.py b/sympy/matrices/matrices.py
index 71026d1297..f7fdc18c84 100644
--- a/sympy/matrices/matrices.py
+++ b/sympy/matrices/matrices.py
@@ -1547,6 +1547,10 @@ def _matrix_pow_by_jordan_blocks(self, num):
         def jordan_cell_power(jc, n):
             N = jc.shape[0]
             l = jc[0, 0]
+            if l == 0 and (n < N - 1) != False:
+                raise ValueError("Matrix det == 0; not invertible")
+            elif l == 0 and N > 1 and n % 1 != 0:
+                raise ValueError("Non-integer power cannot be evaluated")
             for i in range(N):
                 for j in range(N-i):
                     bn = binomial(n, i)
@@ -1581,7 +1585,12 @@ def _matrix_pow_by_recursion(self, num):
     def __pow__(self, num):
         if not self.is_square:
             raise NonSquareMatrixError()
-        if isinstance(num, (int, Integer)):
+        num = sympify(num)
+        # Conditions to include Integers and Integer valued Floats (eg: 10.0, 26.0, etc.,).
+        # n = int(num) in _matrix_pow_by_recursion() can only work correctly
+        # with integer valued numbers.
+        # Other floats are thus handled by _matrix_pow_by_jordan_blocks().
+        if num.is_Number and num % 1 == 0:
             if (self.rows == 1):
                 return self._new([[self[0]**num]])
             # When certain conditions are met,
@@ -1590,10 +1599,10 @@ def __pow__(self, num):
             elif self.rows == 2 and num > 100000:
                 try:
                     return self._matrix_pow_by_jordan_blocks(num)
-                except AttributeError:
-                    return self._matrix_pow_by_recursion(num)
+                except ValueError:
+                    pass
             return self._matrix_pow_by_recursion(num)
-        elif isinstance(num, (Expr, float)):
+        elif isinstance(num, Expr):
             return self._matrix_pow_by_jordan_blocks(num)
         else:
             raise TypeError(


Test patch:
diff --git a/sympy/matrices/tests/test_matrices.py b/sympy/matrices/tests/test_matrices.py
index 933f9ec514..9cbd526e85 100644
--- a/sympy/matrices/tests/test_matrices.py
+++ b/sympy/matrices/tests/test_matrices.py
@@ -224,6 +224,28 @@ def test_power():
     m = Matrix([[3, 0, 0, 0, -3], [0, -3, -3, 0, 3], [0, 3, 0, 3, 0], [0, 0, 3, 0, 3], [3, 0, 0, 3, 0]])
     raises(AttributeError, lambda: m._matrix_pow_by_jordan_blocks(10))
 
+    # test issue 11964
+    raises(ValueError, lambda: Matrix([[1, 1], [3, 3]])._matrix_pow_by_jordan_blocks(-10))
+    A = Matrix([[0, 1, 0], [0, 0, 1], [0, 0, 0]])  # Nilpotent jordan block size 3
+    assert A**10.0 == Matrix([[0, 0, 0], [0, 0, 0], [0, 0, 0]])
+    raises(ValueError, lambda: A**2.1)
+    raises(ValueError, lambda: A**(S(3)/2))
+    A = Matrix([[8, 1], [3, 2]])
+    assert A**10.0 == Matrix([[1760744107, 272388050], [817164150, 126415807]])
+    A = Matrix([[0, 0, 1], [0, 0, 1], [0, 0, 1]])  # Nilpotent jordan block size 1
+    assert A**10.2 == Matrix([[0, 0, 1], [0, 0, 1], [0, 0, 1]])
+    A = Matrix([[0, 1, 0], [0, 0, 1], [0, 0, 1]])  # Nilpotent jordan block size 2
+    assert A**10.0 == Matrix([[0, 0, 1], [0, 0, 1], [0, 0, 1]])
+    n = Symbol('n', integer=True)
+    raises(ValueError, lambda: A**n)
+    n = Symbol('n', integer=True, nonnegative=True)
+    raises(ValueError, lambda: A**n)
+    assert A**(n + 2) == Matrix([[0, 0, 1], [0, 0, 1], [0, 0, 1]])
+    raises(ValueError, lambda: A**(S(3)/2))
+    A = Matrix([[0, 0, 1], [3, 0, 1], [4, 3, 1]])
+    assert A**5.0 == Matrix([[168,  72,  89], [291, 144, 161], [572, 267, 329]])
+    assert A**5.0 == A**5
+
 
 def test_creation():
     raises(ValueError, lambda: Matrix(5, 5, range(20)))