Repository: sympy/sympy

Issue:
`Determinant.doit()` should allow a recurisve call to `doit()` by calling `doit(deep=True)`
Considering:
```python
>>> import sympy as sy
>>> sy.__version__
'1.11.1'
>>> A = sy.eye(2, 2)
>>> B = sy.eye(2, 2)
>>> AB = sy.MatMul(A, B)
>>> detAB = sy.Determinant(AB)
>>> detAB.doit()
Determinant(Matrix([
[1, 0],
[0, 1]]))**2
```

I would expect `detAB.doit()` to return 1 instead of a squared determinant of the identity matrix.
The reason is, that the determinat does not call `doit()` recursivly.
A recursive call (as shown below) would lead to the expected result.
```python
>>> sy.Determinant(AB.doit()).doit()
1
```

The behaviour of  [`Determinant.doit()`](https://github.com/sympy/sympy/blob/26f7bdbe3f860e7b4492e102edec2d6b429b5aaf/sympy/matrices/expressions/determinant.py#L45) is unexpected, since most other matrix expression perform a recursive call by default:

- [`Inverse.doit()`](https://github.com/sympy/sympy/blob/26f7bdbe3f860e7b4492e102edec2d6b429b5aaf/sympy/matrices/expressions/inverse.py#L66)
- [`Trace.doit()`](https://github.com/sympy/sympy/blob/26f7bdbe3f860e7b4492e102edec2d6b429b5aaf/sympy/matrices/expressions/trace.py#L106)
- ...



Would be nice, if the current version:
```python
class Determinant(Expr):
    ...
    def doit(self, expand=False, **hints):
        try:
            return self.arg._eval_determinant()
        except (AttributeError, NotImplementedError):
            return self
```

could be replaced by something like this:

```python
class Determinant(Expr):
    ...
    def doit(self, **hints):
        arg = self.arg
        if hints.get('deep', True) and isinstance(arg, Basic):
            arg = arg.doit(**hints)
        _eval_determinant = getattr(arg, '_eval_determinant', None)
        if _eval_determinant is not None:
            result = _eval_determinant()
            return result if result is not None else Determinant(arg)
        else:
            return Determinant(arg)
```
This is inspired by [`Transpose.doit()`](https://github.com/sympy/sympy/blob/26f7bdbe3f860e7b4492e102edec2d6b429b5aaf/sympy/matrices/expressions/transpose.py#L33) 

Discussion:

Patch:
diff --git a/.mailmap b/.mailmap
index df8403a474..34f1bdd506 100644
--- a/.mailmap
+++ b/.mailmap
@@ -919,6 +919,7 @@ Matthew Wardrop <matthew.wardrop@airbnb.com>
 Matthias Bussonnier <bussonniermatthias@gmail.com>
 Matthias Geier <Matthias.Geier@gmail.com>
 Matthias Köppe <mkoeppe@math.ucdavis.edu> Matthias Koeppe <mkoeppe@math.ucdavis.edu>
+Matthias Rettl <matthias.rettl@stud.unileoben.ac.at>
 Matthias Toews <mat.toews@googlemail.com>
 Mauro Garavello <mauro.garavello@unimib.it>
 Max Hutchinson <maxhutch@gmail.com>
diff --git a/sympy/matrices/expressions/determinant.py b/sympy/matrices/expressions/determinant.py
index db40424b17..a4c435a5de 100644
--- a/sympy/matrices/expressions/determinant.py
+++ b/sympy/matrices/expressions/determinant.py
@@ -40,11 +40,17 @@ def arg(self):
     def kind(self):
         return self.arg.kind.element_kind
 
-    def doit(self, expand=False, **hints):
-        try:
-            return self.arg._eval_determinant()
-        except (AttributeError, NotImplementedError):
-            return self
+    def doit(self, **hints):
+        arg = self.arg
+        if hints.get('deep', True):
+            arg = arg.doit(**hints)
+
+        result = arg._eval_determinant()
+        if result is not None:
+            return result
+
+        return self
+
 
 def det(matexpr):
     """ Matrix Determinant


Test patch:
diff --git a/sympy/matrices/expressions/tests/test_determinant.py b/sympy/matrices/expressions/tests/test_determinant.py
index a4b10ca67c..d1a66c728f 100644
--- a/sympy/matrices/expressions/tests/test_determinant.py
+++ b/sympy/matrices/expressions/tests/test_determinant.py
@@ -3,7 +3,7 @@
 from sympy.matrices.expressions import (
     Identity, MatrixExpr, MatrixSymbol, Determinant,
     det, per, ZeroMatrix, Transpose,
-    Permanent
+    Permanent, MatMul
 )
 from sympy.matrices.expressions.special import OneMatrix
 from sympy.testing.pytest import raises
@@ -28,6 +28,7 @@ def test_det():
 
     assert Determinant(A).arg is A
 
+
 def test_eval_determinant():
     assert det(Identity(n)) == 1
     assert det(ZeroMatrix(n, n)) == 0
@@ -35,6 +36,7 @@ def test_eval_determinant():
     assert det(OneMatrix(1, 1)) == 1
     assert det(OneMatrix(2, 2)) == 0
     assert det(Transpose(A)) == det(A)
+    assert Determinant(MatMul(eye(2), eye(2))).doit(deep=True) == 1
 
 
 def test_refine():
@@ -51,6 +53,7 @@ def test_commutative():
     assert det_b.is_commutative
     assert det_a * det_b == det_b * det_a
 
+
 def test_permanent():
     assert isinstance(Permanent(A), Permanent)
     assert not isinstance(Permanent(A), MatrixExpr)