Repository: sympy/sympy

Issue:
minpoly should not fail if there is handler for something that _separate_sq fails on
```
>>> e=exp(3*I*pi,evaluate=False);e
exp(3*I*pi)
>>> e.is_algebraic
True
>>> minpoly(e)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "sympy\polys\numberfields.py", line 656, in minimal_polynomial
    result = _minpoly_compose(ex, x, dom)
  File "sympy\polys\numberfields.py", line 541, in _minpoly_compose
    ex1 = _separate_sq(ex)
  File "sympy\polys\numberfields.py", line 135, in _separate_sq
    raise NotImplementedError
NotImplementedError  <------------ perhaps catch that error in case there is a handler later ? Not sure.
>>> sympy.polys.numberfields._minpoly_exp(e,x)
x + 1
```


Discussion:
sympy-bot: :white_check_mark:

Hi, I am the [SymPy bot](https://github.com/sympy/sympy-bot). I'm here to help you write a release notes entry. Please read the [guide on how to write release notes](https://github.com/sympy/sympy/wiki/Writing-Release-Notes).



Your release notes are in good order.

Here is what the release notes will look like:
* polys
  * minpoly no longer errors on unevaluate `exp` numbers (via import `_is_surd_sum`) ([#27075](https://github.com/sympy/sympy/pull/27075) by [@smichr](https://github.com/smichr))

This will be added to https://github.com/sympy/sympy/wiki/Release-Notes-for-1.14.

<details><summary>Click here to see the pull request description that was parsed.</summary>

    <!-- Your title above should be a short description of what
    was changed. Do not include the issue number in the title. -->

    #### References to other Issues or PRs
    <!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact
    format, e.g. "Fixes #1234" (see
    https://tinyurl.com/auto-closing for more information). Also, please
    write a comment on that issue linking back to this pull request once it is
    open. -->
    fixed #8353

    #### Brief description of what is fixed or changed


    #### Other comments


    #### Release Notes

    <!-- Write the release notes for this release below between the BEGIN and END
    statements. The basic format is a bulleted list with the name of the subpackage
    and the release note for this PR. For example:

    * solvers
      * Added a new solver for logarithmic equations.

    * functions
      * Fixed a bug with log of integers. Formerly, `log(-x)` incorrectly gave `-log(x)`.

    * physics.units
      * Corrected a semantical error in the conversion between volt and statvolt which
        reported the volt as being larger than the statvolt.

    or if no release note(s) should be included use:

    NO ENTRY

    See https://github.com/sympy/sympy/wiki/Writing-Release-Notes for more
    information on how to write release notes. The bot will check your release
    notes automatically to see if they are formatted correctly. -->

    <!-- BEGIN RELEASE NOTES -->
    * polys
      * minpoly no longer errors on unevaluate `exp` numbers (via import `_is_surd_sum`)
    <!-- END RELEASE NOTES -->


</details><p>

oscarbenjamin: I was going to say that I think it looks good but I'm confused about the failing doctest:
```python
In [6]: from sympy.simplify.simplify import nthroot

In [7]: nthroot(90 + 34*sqrt(7), 3)
Out[7]:
3 ____________
╲╱ 34⋅√7 + 90
```
On master it is:
```python
In [3]: nthroot(90 + 34*sqrt(7), 3)
Out[3]: √7 + 3
```
Both answers seem to be equivalent although the result in master is better.

More importantly how does the change here affect this?

Is there an exception being swallowed somewhere in `nthroot` or is `minpoly` returning an incorrect result somewhere?

Patch:
diff --git a/.mailmap b/.mailmap
index f0941bb917..3968c4c918 100644
--- a/.mailmap
+++ b/.mailmap
@@ -716,7 +716,6 @@ Islam Mansour <is3mansour@gmail.com>
 Islem BOUZENIA <fi_bouzenia@esi.dz> islem-esi <fi_bouzenia@esi.dz>
 Isuru Fernando <isuruf@gmail.com> <isuru.11@cse.mrt.ac.lk>
 Itay4 <31018228+Itay4@users.noreply.github.com>
-Ivan A. Melnikov <iv@altlinux.org>
 Ivan Petuhov <ivan@ostrovok.ru>
 Ivan Petukhov <satels@gmail.com>
 Ivan Tkachenko <me@ratijas.tk> ivan tkachenko <ratijas@users.noreply.github.com>
diff --git a/bin/mailmap_check.py b/bin/mailmap_check.py
index fef2e7703a..875d2fe653 100755
--- a/bin/mailmap_check.py
+++ b/bin/mailmap_check.py
@@ -230,6 +230,17 @@ def author_name(line):
 
 def get_authors_from_git():
     git_command = ["git", "log", "--topo-order", "--reverse", "--format=%aN <%aE>"]
+
+    parents = run(["git", "rev-list", "--no-walk", "--count", "HEAD^@"],
+                  stdout=PIPE, encoding='utf-8').stdout.strip()
+    if parents != '1':
+        # Skip the most recent commit. Used to ignore the merge commit created
+        # when this script runs in CI. If HEAD is a merge commit parents will
+        # typically be '2'. We use HEAD^2 rather than HEAD^1 to select the
+        # parent commit that is part of the PR rather than the parent commit
+        # that was the previous tip of master.
+        git_command.append("HEAD^"+parents)
+
     git_people = run(git_command, stdout=PIPE, encoding='utf-8').stdout.strip().split("\n")
 
     # remove duplicates, keeping the original order
diff --git a/sympy/matrices/matrixbase.py b/sympy/matrices/matrixbase.py
index 7080b19e8a..3dcdfc6c83 100644
--- a/sympy/matrices/matrixbase.py
+++ b/sympy/matrices/matrixbase.py
@@ -3895,15 +3895,9 @@ def make_explicit_row(row):
                     if isinstance(dat, (list, tuple)):
                         dat = [make_explicit_row(row) for row in dat]
 
-                if len(dat) == 0:
+                if dat in ([], [[]]):
                     rows = cols = 0
                     flat_list = []
-                elif all(raw(i) for i in dat) and len(dat[0]) == 0:
-                    if not all(len(i) == 0 for i in dat):
-                        raise ValueError('mismatched dimensions')
-                    rows = len(dat)
-                    cols = 0
-                    flat_list = []
                 elif not any(raw(i) or ismat(i) for i in dat):
                     # a column as a list of values
                     flat_list = [cls._sympify(i) for i in dat]
diff --git a/sympy/parsing/c/c_parser.py b/sympy/parsing/c/c_parser.py
index 2c385865d8..0c8cb74d05 100644
--- a/sympy/parsing/c/c_parser.py
+++ b/sympy/parsing/c/c_parser.py
@@ -180,7 +180,6 @@ def parse_str(self, source, flags):
             """
             file = tempfile.NamedTemporaryFile(mode = 'w+', suffix = '.cpp')
             file.write(source)
-            file.flush()
             file.seek(0)
             self.tu = self.index.parse(
                 file.name,
diff --git a/sympy/physics/wigner.py b/sympy/physics/wigner.py
index f55cd3abb8..75e4b52aea 100644
--- a/sympy/physics/wigner.py
+++ b/sympy/physics/wigner.py
@@ -323,16 +323,9 @@ def clebsch_gordan(j_1, j_2, j_3, m_1, m_2, m_3):
 
     - Jens Rasch (2009-03-24): initial version
     """
-    j_1 = sympify(j_1)
-    j_2 = sympify(j_2)
-    j_3 = sympify(j_3)
-    m_1 = sympify(m_1)
-    m_2 = sympify(m_2)
-    m_3 = sympify(m_3)
-
-    w = wigner_3j(j_1, j_2, j_3, m_1, m_2, -m_3)
-
-    return (-1) ** (j_1 - j_2 + m_3) * sqrt(2 * j_3 + 1) * w
+    res = (-1) ** sympify(j_1 - j_2 + m_3) * sqrt(2 * j_3 + 1) * \
+        wigner_3j(j_1, j_2, j_3, m_1, m_2, -m_3)
+    return res
 
 
 def _big_delta_coeff(aa, bb, cc, prec=None):
diff --git a/sympy/polys/numberfields/minpoly.py b/sympy/polys/numberfields/minpoly.py
index ac28ffb125..e5f556e6f8 100644
--- a/sympy/polys/numberfields/minpoly.py
+++ b/sympy/polys/numberfields/minpoly.py
@@ -86,11 +86,9 @@ def _choose_factor(factors, x, v, dom=QQ, prec=200, bound=5):
 
 
 def _is_sum_surds(p):
-    args = p.args if p.is_Add else [p]
-    for y in args:
-        if not ((y**2).is_Rational and y.is_extended_real):
-            return False
-    return True
+    return all(f.is_Rational or f.is_Pow and
+        f.base.is_Rational and (2*f.exp).is_Integer and f.is_extended_real
+        for t in Add.make_args(p) for f in Mul.make_args(t))
 
 
 def _separate_sq(p):
diff --git a/sympy/simplify/simplify.py b/sympy/simplify/simplify.py
index 4e8437c2e0..c3e904da2b 100644
--- a/sympy/simplify/simplify.py
+++ b/sympy/simplify/simplify.py
@@ -632,7 +632,6 @@ def done(e):
     # is it a purely rational function? Is there any trigonometric function?...
     # See also https://github.com/sympy/sympy/pull/185.
 
-
     # rationalize Floats
     floats = False
     if rational is not False and expr.has(Float):


Test patch:
diff --git a/sympy/matrices/tests/test_matrices.py b/sympy/matrices/tests/test_matrices.py
index a1925bdf56..c8a28ff1c2 100644
--- a/sympy/matrices/tests/test_matrices.py
+++ b/sympy/matrices/tests/test_matrices.py
@@ -749,10 +749,7 @@ def test_creation():
     with raises(IndexError):
         Matrix((1, 2))[3] = 5
 
-    assert Matrix() == Matrix([]) == Matrix(0, 0, [])
-    assert Matrix([[]]) == Matrix(1, 0, [])
-    assert Matrix([[], []]) == Matrix(2, 0, [])
-
+    assert Matrix() == Matrix([]) == Matrix([[]]) == Matrix(0, 0, [])
     # anything used to be allowed in a matrix
     with warns_deprecated_sympy():
         assert Matrix([[[1], (2,)]]).tolist() == [[[1], (2,)]]
@@ -2764,7 +2761,7 @@ def test_from_ndarray():
         lambda: Matrix(array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])))
     assert Matrix([array([1, 2]), array([3, 4])]) == Matrix([[1, 2], [3, 4]])
     assert Matrix([array([1, 2]), [3, 4]]) == Matrix([[1, 2], [3, 4]])
-    assert Matrix([array([]), array([])]) == Matrix(2, 0, []) != Matrix(0, 0, [])
+    assert Matrix([array([]), array([])]) == Matrix([])
 
 def test_17522_numpy():
     from sympy.matrices.common import _matrixify
diff --git a/sympy/matrices/tests/test_matrixbase.py b/sympy/matrices/tests/test_matrixbase.py
index 07055a7610..c059463e42 100644
--- a/sympy/matrices/tests/test_matrixbase.py
+++ b/sympy/matrices/tests/test_matrixbase.py
@@ -1506,10 +1506,7 @@ def test_creation():
     with raises(IndexError):
         Matrix((1, 2))[3] = 5
 
-    assert Matrix() == Matrix([]) == Matrix(0, 0, [])
-    assert Matrix([[]]) == Matrix(1, 0, [])
-    assert Matrix([[], []]) == Matrix(2, 0, [])
-
+    assert Matrix() == Matrix([]) == Matrix([[]]) == Matrix(0, 0, [])
     # anything used to be allowed in a matrix
     with warns_deprecated_sympy():
         assert Matrix([[[1], (2,)]]).tolist() == [[[1], (2,)]]
@@ -3460,7 +3457,7 @@ def test_from_ndarray():
         lambda: Matrix(array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])))
     assert Matrix([array([1, 2]), array([3, 4])]) == Matrix([[1, 2], [3, 4]])
     assert Matrix([array([1, 2]), [3, 4]]) == Matrix([[1, 2], [3, 4]])
-    assert Matrix([array([]), array([])]) == Matrix(2, 0, []) != Matrix([])
+    assert Matrix([array([]), array([])]) == Matrix([])
 
 
 def test_17522_numpy():
diff --git a/sympy/parsing/tests/test_custom_latex.py b/sympy/parsing/tests/test_custom_latex.py
index ae0fbb7af7..b9802823e4 100644
--- a/sympy/parsing/tests/test_custom_latex.py
+++ b/sympy/parsing/tests/test_custom_latex.py
@@ -30,7 +30,6 @@ def init_custom_parser(modification, transformer=None):
 
     with tempfile.NamedTemporaryFile() as f:
         f.write(bytes(latex_grammar, encoding="utf8"))
-        f.flush()
 
         parser = LarkLaTeXParser(grammar_file=f.name, transformer=transformer)
 
diff --git a/sympy/physics/tests/test_clebsch_gordan.py b/sympy/physics/tests/test_clebsch_gordan.py
index 906e62bb39..68bfa0ac94 100644
--- a/sympy/physics/tests/test_clebsch_gordan.py
+++ b/sympy/physics/tests/test_clebsch_gordan.py
@@ -8,7 +8,7 @@
 from sympy.matrices.dense import Matrix
 from sympy.physics.wigner import (clebsch_gordan, wigner_9j, wigner_6j, gaunt,
         real_gaunt, racah, dot_rot_grad_Ynm, wigner_3j, wigner_d_small, wigner_d)
-from sympy.testing.pytest import raises, skip
+from sympy.testing.pytest import raises
 
 # for test cases, refer : https://en.wikipedia.org/wiki/Table_of_Clebsch%E2%80%93Gordan_coefficients
 
@@ -55,14 +55,6 @@ def test_clebsch_gordan():
     assert clebsch_gordan(p, h, l, k, 1, l) == 1/sqrt(15)
 
 
-def test_clebsch_gordan_numpy():
-    try:
-        import numpy as np
-    except ImportError:
-        skip("numpy not installed")
-    assert clebsch_gordan(*np.zeros(6).astype(np.int64)) == 1
-
-
 def test_wigner():
     def tn(a, b):
         return (a - b).n(64) < S('1e-64')
diff --git a/sympy/polys/numberfields/tests/test_minpoly.py b/sympy/polys/numberfields/tests/test_minpoly.py
index a04f418cd2..792e5ad6e1 100644
--- a/sympy/polys/numberfields/tests/test_minpoly.py
+++ b/sympy/polys/numberfields/tests/test_minpoly.py
@@ -186,6 +186,12 @@ def test_issue_26903():
     assert minimal_polynomial(sqrt(2) - zero, x) == x**2 - 2
 
 
+def test_issue_8353():
+    assert minimal_polynomial(exp(3*I*pi, evaluate=False), x) == x + 1
+    assert minimal_polynomial(Pow(8, S(1)/3, evaluate=False), x
+        ) == x - 2
+
+
 def test_minimal_polynomial_issue_19732():
     # https://github.com/sympy/sympy/issues/19732
     expr = (-280898097948878450887044002323982963174671632174995451265117559518123750720061943079105185551006003416773064305074191140286225850817291393988597615/(-488144716373031204149459129212782509078221364279079444636386844223983756114492222145074506571622290776245390771587888364089507840000000*sqrt(238368341569)*sqrt(S(11918417078450)/63568729
diff --git a/sympy/stats/tests/test_stochastic_process.py b/sympy/stats/tests/test_stochastic_process.py
index 3e42ffc863..d3d373821d 100644
--- a/sympy/stats/tests/test_stochastic_process.py
+++ b/sympy/stats/tests/test_stochastic_process.py
@@ -85,7 +85,7 @@ def test_DiscreteMarkovChain():
     assert Y.number_of_states == ceiling((t-1)/2)
 
     # pass name and transition_probabilities
-    chains = [DiscreteMarkovChain("Y", trans_probs=Matrix([])),
+    chains = [DiscreteMarkovChain("Y", trans_probs=Matrix([[]])),
               DiscreteMarkovChain("Y", trans_probs=Matrix([[0, 1], [1, 0]])),
               DiscreteMarkovChain("Y", trans_probs=Matrix([[pi, 1-pi], [sym, 1-sym]]))]
     for Z in chains:
@@ -169,12 +169,12 @@ def test_DiscreteMarkovChain():
                                                             [Rational(-14, 75), Rational(1, 25), Rational(86, 75)]])
 
     # test for zero-sized matrix functionality
-    X = DiscreteMarkovChain('X', trans_probs=Matrix([]))
+    X = DiscreteMarkovChain('X', trans_probs=Matrix([[]]))
     assert X.number_of_states == 0
     assert X.stationary_distribution() == Matrix([[]])
     assert X.communication_classes() == []
-    assert X.canonical_form() == ([], Matrix([]))
-    assert X.decompose() == ([], Matrix([]), Matrix([]), Matrix([]))
+    assert X.canonical_form() == ([], Matrix([[]]))
+    assert X.decompose() == ([], Matrix([[]]), Matrix([[]]), Matrix([[]]))
     assert X.is_regular() == False
     assert X.is_ergodic() == False