Repository: sympy/sympy

Issue:
integrate throws error for rational functions involving I
Relatively simple integrals such as
```python
x = symbols('x')
f = diff(1/(x**2+x+I),x)
integrate(f,x)
```
fail with the error
```
sympy.polys.polyerrors.PolynomialDivisionFailed: couldn't reduce degree in a polynomial division algorithm when dividing [EX(-2), EX(-1)] by [EX(-(-15 + 8*I)*(15 + 8*I)/289)]. This can happen when it's not possible to detect zero in the coefficient domain. The domain of computation is EX. You may want to use a different simplification algorithm. Note that in general it's not possible to guarantee to detect zero in this domain.
```
The best workaround I have found so far is
```python
c = symbols('c',complex=True)
integrate(f.subs(I,c),x).subs(c,I)
```
but ``integrate(f,x,manual=True)`` also works.

Discussion:

Patch:
diff --git a/sympy/calculus/util.py b/sympy/calculus/util.py
index 7174d92c28..c81b77fe5e 100644
--- a/sympy/calculus/util.py
+++ b/sympy/calculus/util.py
@@ -1338,10 +1338,9 @@ def __pow__(self, other):
                                 return AccumBounds(0, real_root(self.max, den))
                     return AccumBounds(real_root(self.min, den),
                                        real_root(self.max, den))
-                if den!=1:
-                    num_pow = self**num
-                    return num_pow**(1 / den)
-            return AccumBounds(-oo, oo)
+                num_pow = self**num
+                return num_pow**(1 / den)
+            return Pow(self, other, evaluate=False)
 
         return NotImplemented
 
diff --git a/sympy/combinatorics/perm_groups.py b/sympy/combinatorics/perm_groups.py
index c25e15c5d7..085005fcb3 100644
--- a/sympy/combinatorics/perm_groups.py
+++ b/sympy/combinatorics/perm_groups.py
@@ -2567,92 +2567,6 @@ def minimal_block(self, points):
         new_reps = {}
         return [new_reps.setdefault(r, i) for i, r in enumerate(parents)]
 
-    def conjugacy_class(self, x):
-        r"""Return the conjugacy class of an element in the group.
-
-        The conjugacy class of an element ``g`` in a group ``G`` is the set of
-        elements ``x`` in ``G`` that are conjugate with ``g``, i.e. for which
-
-            ``g = xax^{-1}``
-
-        for some ``a`` in ``G``.
-
-        Note that conjugacy is an equivalence relation, and therefore that
-        conjugacy classes are partitions of ``G``. For a list of all the
-        conjugacy classes of the group, use the conjugacy_classes() method.
-
-        In a permutation group, each conjugacy class corresponds to a particular
-        `cycle structure': for example, in ``S_3``, the conjugacy classes are:
-
-            * the identity class, ``{()}``
-            * all transpositions, ``{(1 2), (1 3), (2 3)}``
-            * all 3-cycles, ``{(1 2 3), (1 3 2)}``
-
-        Examples
-        ========
-
-        >>> from sympy.combinatorics.permutations import Permutation
-        >>> from sympy.combinatorics.named_groups import SymmetricGroup
-        >>> S3 = SymmetricGroup(3)
-        >>> S3.conjugacy_class(Permutation(0, 1, 2))
-        {(0 1 2), (0 2 1)}
-
-        Notes
-        =====
-
-        This procedure computes the conjugacy class directly by finding the
-        orbit of the element under conjugation in G. This algorithm is only
-        feasible for permutation groups of relatively small order, but is like
-        the orbit() function itself in that respect.
-        """
-        # Ref: "Computing the conjugacy classes of finite groups"; Butler, G.
-        # Groups '93 Galway/St Andrews; edited by Campbell, C. M.
-        new_class = set([x])
-        last_iteration = new_class
-
-        while len(last_iteration) > 0:
-            this_iteration = set()
-
-            for y in last_iteration:
-                for s in self.generators:
-                    conjugated = s * y * (~s)
-                    if conjugated not in new_class:
-                        this_iteration.add(conjugated)
-
-            new_class.update(last_iteration)
-            last_iteration = this_iteration
-
-        return new_class
-
-
-    def conjugacy_classes(self):
-        r"""Return the conjugacy classes of the group.
-
-        As described in the documentation for the .conjugacy_class() function,
-        conjugacy is an equivalence relation on a group G which partitions the
-        set of elements. This method returns a list of all these conjugacy
-        classes of G.
-
-        Examples
-        ========
-
-        >>> from sympy.combinatorics import SymmetricGroup
-        >>> SymmetricGroup(3).conjugacy_classes()
-        [{(2)}, {(0 1 2), (0 2 1)}, {(0 2), (1 2), (2)(0 1)}]
-
-        """
-        identity = _af_new(list(range(self.degree)))
-        known_elements = set([identity])
-        classes = [known_elements.copy()]
-
-        for x in self.generate():
-            if x not in known_elements:
-                new_class = self.conjugacy_class(x)
-                classes.append(new_class)
-                known_elements.update(new_class)
-
-        return classes
-
     def normal_closure(self, other, k=10):
         r"""Return the normal closure of a subgroup/set of permutations.
 
diff --git a/sympy/polys/domains/expressiondomain.py b/sympy/polys/domains/expressiondomain.py
index d770ac25dc..9d3c88bddb 100644
--- a/sympy/polys/domains/expressiondomain.py
+++ b/sympy/polys/domains/expressiondomain.py
@@ -9,6 +9,9 @@
 from sympy.polys.polyutils import PicklableWithSlots
 from sympy.utilities import public
 
+eflags = dict(deep=False, mul=True, power_exp=False, power_base=False,
+              basic=False, multinomial=False, log=False)
+
 @public
 class ExpressionDomain(Field, CharacteristicZero, SimpleDomain):
     """A class for arbitrary expressions. """
@@ -45,7 +48,7 @@ def denom(f):
             return f.__class__(f.ex.as_numer_denom()[1])
 
         def simplify(f, ex):
-            return f.__class__(ex.cancel())
+            return f.__class__(ex.cancel().expand(**eflags))
 
         def __abs__(f):
             return f.__class__(abs(f.ex))
@@ -200,7 +203,7 @@ def is_positive(self, a):
 
     def is_negative(self, a):
         """Returns True if ``a`` is negative. """
-        return a.ex.as_coeff_mul()[0].is_negative
+        return a.ex.could_extract_minus_sign()
 
     def is_nonpositive(self, a):
         """Returns True if ``a`` is non-positive. """
diff --git a/sympy/polys/polytools.py b/sympy/polys/polytools.py
index af1db9115e..1f15d8d98c 100644
--- a/sympy/polys/polytools.py
+++ b/sympy/polys/polytools.py
@@ -6593,7 +6593,7 @@ def cancel(f, *gens, **args):
     Examples
     ========
 
-    >>> from sympy import cancel, sqrt, Symbol, together
+    >>> from sympy import cancel, sqrt, Symbol
     >>> from sympy.abc import x
     >>> A = Symbol('A', commutative=False)
 
@@ -6601,14 +6601,6 @@ def cancel(f, *gens, **args):
     (2*x + 2)/(x - 1)
     >>> cancel((sqrt(3) + sqrt(15)*A)/(sqrt(2) + sqrt(10)*A))
     sqrt(6)/2
-
-    Note: due to automatic distribution of Rationals, a sum divided by an integer
-    will appear as a sum. To recover a rational form use `together` on the result:
-
-    >>> cancel(x/2 + 1)
-    x/2 + 1
-    >>> together(_)
-    (x + 2)/2
     """
     from sympy.core.exprtools import factor_terms
     from sympy.functions.elementary.piecewise import Piecewise


Test patch:
diff --git a/sympy/calculus/tests/test_util.py b/sympy/calculus/tests/test_util.py
index 5035cceb4e..a3d34a6169 100644
--- a/sympy/calculus/tests/test_util.py
+++ b/sympy/calculus/tests/test_util.py
@@ -452,14 +452,14 @@ def test_AccumBounds_pow():
     assert AccumBounds(-1, 2)**oo == AccumBounds(-oo, oo)
     assert AccumBounds(-2, S.Half)**oo == AccumBounds(-oo, oo)
 
-    assert AccumBounds(1, 2)**x == Pow(AccumBounds(1, 2), x)
+    assert AccumBounds(1, 2)**x == Pow(AccumBounds(1, 2), x, evaluate=False)
 
     assert AccumBounds(2, 3)**(-oo) is S.Zero
     assert AccumBounds(0, 2)**(-oo) == AccumBounds(0, oo)
     assert AccumBounds(-1, 2)**(-oo) == AccumBounds(-oo, oo)
 
     assert (tan(x)**sin(2*x)).subs(x, AccumBounds(0, pi/2)) == \
-        Pow(AccumBounds(-oo, oo), AccumBounds(0, 1))
+        Pow(AccumBounds(-oo, oo), AccumBounds(0, 1), evaluate=False)
 
 
 def test_comparison_AccumBounds():
diff --git a/sympy/combinatorics/tests/test_perm_groups.py b/sympy/combinatorics/tests/test_perm_groups.py
index ad6eaa941f..8deda10723 100644
--- a/sympy/combinatorics/tests/test_perm_groups.py
+++ b/sympy/combinatorics/tests/test_perm_groups.py
@@ -1097,22 +1097,3 @@ def test_is_symmetric():
     a = Permutation(0, 1, 2, 3)
     b = Permutation(0, 3)(1, 2)
     assert PermutationGroup(a, b).is_symmetric == False
-
-def test_conjugacy_class():
-    S = SymmetricGroup(4)
-    x = Permutation(1, 2, 3)
-    C = set([Permutation(0, 1, 2, size = 4), Permutation(0, 1, 3),
-             Permutation(0, 2, 1, size = 4), Permutation(0, 2, 3),
-             Permutation(0, 3, 1), Permutation(0, 3, 2),
-             Permutation(1, 2, 3), Permutation(1, 3, 2)])
-    assert S.conjugacy_class(x) == C
-
-def test_conjugacy_classes():
-    S = SymmetricGroup(3)
-    expected = [set([Permutation(size = 3)]),
-         set([Permutation(0, 1, size = 3), Permutation(0, 2), Permutation(1, 2)]),
-         set([Permutation(0, 1, 2), Permutation(0, 2, 1)])]
-    computed = S.conjugacy_classes()
-
-    assert len(expected) == len(computed)
-    assert all(e in computed for e in expected)
diff --git a/sympy/functions/combinatorial/tests/test_comb_factorials.py b/sympy/functions/combinatorial/tests/test_comb_factorials.py
index 54f3e89a2b..09e62d05dd 100644
--- a/sympy/functions/combinatorial/tests/test_comb_factorials.py
+++ b/sympy/functions/combinatorial/tests/test_comb_factorials.py
@@ -147,9 +147,7 @@ def test_ff_eval_apply():
     for i in range(100):
         x = -500 + 500 * random.random()
         k = -500 + 500 * random.random()
-        a = mpmath_ff(x, k)
-        b = ff(x, k)
-        assert (abs(a - b) < abs(a) * 10**(-15))
+        assert (abs(mpmath_ff(x, k) - ff(x, k)) < 10**(-15))
 
 
 def test_rf_ff_eval_hiprec():
diff --git a/sympy/functions/elementary/tests/test_piecewise.py b/sympy/functions/elementary/tests/test_piecewise.py
index fd609c9f71..17b0bacf32 100644
--- a/sympy/functions/elementary/tests/test_piecewise.py
+++ b/sympy/functions/elementary/tests/test_piecewise.py
@@ -2,7 +2,7 @@
     adjoint, And, Basic, conjugate, diff, expand, Eq, Function, I, ITE,
     Integral, integrate, Interval, KroneckerDelta, lambdify, log, Max, Min,
     oo, Or, pi, Piecewise, piecewise_fold, Rational, solve, symbols, transpose,
-    cos, sin, exp, Abs, Ne, Not, Symbol, S, sqrt, Sum, Tuple, zoo, Float,
+    cos, sin, exp, Abs, Ne, Not, Symbol, S, sqrt, Sum, Tuple, zoo,
     DiracDelta, Heaviside, Add, Mul, factorial, Ge, Contains)
 from sympy.core.expr import unchanged
 from sympy.functions.elementary.piecewise import Undefined, ExprCondPair
@@ -1345,9 +1345,3 @@ def test_identical_conds_issue():
     # Result is quite big, so not really important here (and should ideally be
     # simpler). Should not give an exception though.
     density(u1 + u2)
-
-
-def test_issue_7370():
-    f = Piecewise((1, x <= 2400))
-    v = integrate(f, (x, 0, Float("252.4", 30)))
-    assert str(v) == '252.400000000000000000000000000'
diff --git a/sympy/integrals/tests/test_integrals.py b/sympy/integrals/tests/test_integrals.py
index 0179054d6e..2970b2cb7d 100644
--- a/sympy/integrals/tests/test_integrals.py
+++ b/sympy/integrals/tests/test_integrals.py
@@ -1648,3 +1648,7 @@ def test_issue_2975():
     C = Symbol('C')
     y = Symbol('y')
     assert integrate(1/(y**2+C)**(S(3)/2), (y, -w/2, w/2)) == w/(C**(S(3)/2)*sqrt(1 + w**2/(4*C)))
+
+def test_issue_17841():
+    f = diff(1/(x**2+x+I), x)
+    assert integrate(f, x) == 1/(x**2 + x + I)
diff --git a/sympy/series/tests/test_limits.py b/sympy/series/tests/test_limits.py
index a001378e8a..93eb22b3d8 100644
--- a/sympy/series/tests/test_limits.py
+++ b/sympy/series/tests/test_limits.py
@@ -608,6 +608,3 @@ def test_issue_17671():
 
 def test_issue_18306():
     assert limit(sin(sqrt(x))/sqrt(sin(x)), x, 0, '+') == 1
-
-def test_issue_18442():
-    assert limit(tan(x)**(2**(sqrt(pi))), x, oo, dir='-') == AccumBounds(-oo, oo)