Repository: sympy/sympy

Issue:
factor gives an invalid expression
This was reported on the mailing list a while back

```
In [29]: h = 2*x*(-2*x + Abs(x))*(x**2 - 1)/Abs(x**2 - 1) + (x/Abs(x) - 2)*Abs(x**2 - 1)

In [30]: print(factor(h))
(x - 1)*(x**4 - 6*x**3*Abs(x) + x**3 - 6*x**2*Abs(x) + x**2 + 2*x*Abs(x) - x + 2*Abs(x))/(Abs(x)*Abs(x**2 - 1))

In [31]: h.subs(x, 2)
Out[31]: -11

In [32]: factor(h).subs(x, 2)
Out[32]: -53/3
```

Discussion:
asmeurer: All the Travis builds are erroring with "No output has been received in the last 10 minutes, this potentially indicates a stalled build or something wrong with the build itself." I'm guessing this means there is a nontrivial performance hit here. 
smichr: > nontrivial performance hit

:-)  not really, just a garden-variety infinite loop that I have to watch out for

Patch:
diff --git a/data/TeXmacs/bin/tm_sympy b/data/TeXmacs/bin/tm_sympy
index 659818d21b..a801156f3f 100755
--- a/data/TeXmacs/bin/tm_sympy
+++ b/data/TeXmacs/bin/tm_sympy
@@ -69,7 +69,7 @@ _greek = 'alpha beta gamma delta epsilon zeta eta '  \
          'sigma tau upsilon phi chi psi omega'
 
 for _symbol in _greek.split(' '):
-    exec("%s = Symbol('%s')" % (_symbol, _symbol))
+    exec "%s = Symbol('%s')" % (_symbol, _symbol)
 
 del _symbol
 """
diff --git a/sympy/core/logic.py b/sympy/core/logic.py
index d12bee1562..077f277c76 100644
--- a/sympy/core/logic.py
+++ b/sympy/core/logic.py
@@ -64,23 +64,11 @@ def fuzzy_bool(x):
     """Return True, False or None according to x.
 
     Whereas bool(x) returns True or False, fuzzy_bool allows
-    for the None value and non-false values (which become None), too.
-
-    Examples
-    ========
-
-    >>> from sympy.core.logic import fuzzy_bool
-    >>> from sympy.abc import x
-    >>> fuzzy_bool(x), fuzzy_bool(None)
-    (None, None)
-    >>> bool(x), bool(None)
-    (True, False)
-
+    for the None value.
     """
     if x is None:
         return None
-    if x in (True, False):
-        return bool(x)
+    return bool(x)
 
 
 def fuzzy_and(args):
diff --git a/sympy/core/mul.py b/sympy/core/mul.py
index 2a0e6090e4..30a51adb8e 100644
--- a/sympy/core/mul.py
+++ b/sympy/core/mul.py
@@ -368,17 +368,17 @@ def flatten(cls, seq):
 
         # gather exponents of common bases...
         def _gather(c_powers):
-            new_c_powers = []
             common_b = {}  # b:e
             for b, e in c_powers:
                 co = e.as_coeff_Mul()
-                common_b.setdefault(b, {}).setdefault(co[1], []).append(co[0])
+                common_b.setdefault(b, {}).setdefault(
+                    co[1], []).append(co[0])
             for b, d in common_b.items():
                 for di, li in d.items():
                     d[di] = Add(*li)
+            new_c_powers = []
             for b, e in common_b.items():
-                for t, c in e.items():
-                    new_c_powers.append((b, c*t))
+                new_c_powers.extend([(b, c*t) for t, c in e.items()])
             return new_c_powers
 
         # in c_powers
@@ -402,14 +402,45 @@ def _gather(c_powers):
 
         #  0             1
         # x  -> 1       x  -> x
-        for b, e in c_powers:
-            if e is S.One:
-                if b.is_Number:
-                    coeff *= b
-                else:
-                    c_part.append(b)
-            elif e is not S.Zero:
-                c_part.append(Pow(b, e))
+
+        # this should only need to run twice; if it fails because
+        # it needs to be run more times, perhaps this should be
+        # changed to a "while True" loop -- the only reason it
+        # isn't such now is to allow a less-than-perfect result to
+        # be obtained rather than raising an error or entering an
+        # infinite loop
+        for i in range(2):
+            new_c_powers = []
+            changed = False
+            for b, e in c_powers:
+                if e.is_zero:
+                    continue
+                if e is S.One:
+                    if b.is_Number:
+                        coeff *= b
+                        continue
+                    p = b
+                if e is not S.One:
+                    p = Pow(b, e)
+                    # check to make sure that the base doesn't change
+                    # after exponentiation; to allow for unevaluated
+                    # Pow, we only do so if b is not already a Pow
+                    if p.is_Pow and not b.is_Pow:
+                        bi = b
+                        b, e = p.as_base_exp()
+                        if b != bi:
+                            changed = True
+                c_part.append(p)
+                new_c_powers.append((b, e))
+            # there might have been a change, but unless the base
+            # matches some other base, there is nothing to do
+            if changed and len(set(
+                    b for b, e in new_c_powers)) != len(new_c_powers):
+                # start over again
+                c_part = []
+                c_powers = _gather(new_c_powers)
+            else:
+                break
 
         #  x    x     x
         # 2  * 3  -> 6
diff --git a/sympy/polys/polyutils.py b/sympy/polys/polyutils.py
index 0e74704deb..28f9876313 100644
--- a/sympy/polys/polyutils.py
+++ b/sympy/polys/polyutils.py
@@ -262,7 +262,7 @@ def _is_coeff(factor):
                     else:
                         base, exp = decompose_power_rat(factor)
 
-                    elements[base] = exp
+                    elements[base] = elements.setdefault(base, 0) + exp
                     gens.add(base)
 
             terms.append((coeff, elements))
diff --git a/sympy/sets/sets.py b/sympy/sets/sets.py
index 3b0ba18a62..684df72095 100644
--- a/sympy/sets/sets.py
+++ b/sympy/sets/sets.py
@@ -1063,8 +1063,8 @@ def _eval_imageset(self, f):
         else:
             return imageset(f, Interval(self.start, sing[0],
                                         self.left_open, True)) + \
-                Union(*[imageset(f, Interval(sing[i], sing[i + 1], True, True))
-                        for i in range(0, len(sing) - 1)]) + \
+                Union(*[imageset(f, Interval(sing[i], sing[i + 1]), True, True)
+                        for i in range(1, len(sing) - 1)]) + \
                 imageset(f, Interval(sing[-1], self.end, True, self.right_open))
 
     @property
@@ -1396,7 +1396,7 @@ def flatten(arg):
         args = flatten(args)
 
         if len(args) == 0:
-            return S.EmptySet
+            raise TypeError("Intersection expected at least one argument")
 
         # args can't be ordered for Partition see issue #9608
         if 'Partition' not in [type(a).__name__ for a in args]:
@@ -1435,72 +1435,6 @@ def __iter__(self):
 
         raise ValueError("None of the constituent sets are iterable")
 
-    @staticmethod
-    def _handle_finite_sets(args):
-        from sympy.core.logic import fuzzy_and, fuzzy_bool
-        from sympy.core.compatibility import zip_longest
-
-        new_args = []
-        fs_args = []
-        for s in args:
-            if s.is_FiniteSet:
-                fs_args.append(s)
-            else:
-                new_args.append(s)
-        if not fs_args:
-            return
-        s = fs_args[0]
-        fs_args = fs_args[1:]
-        res = []
-        unk = []
-        for x in s:
-            c = fuzzy_and(fuzzy_bool(o.contains(x))
-                for o in fs_args + new_args)
-            if c:
-                res.append(x)
-            elif c is None:
-                unk.append(x)
-            else:
-                pass  # drop arg
-        res = FiniteSet(
-            *res, evaluate=False) if res else S.EmptySet
-        if unk:
-            symbolic_s_list = [x for x in s if x.has(Symbol)]
-            non_symbolic_s = s - FiniteSet(
-                *symbolic_s_list, evaluate=False)
-            while fs_args:
-                v = fs_args.pop()
-                if all(i == j for i, j in zip_longest(
-                        symbolic_s_list,
-                        (x for x in v if x.has(Symbol)))):
-                    # all the symbolic elements of `v` are the same
-                    # as in `s` so remove the non-symbol containing
-                    # expressions from `unk`, since they cannot be
-                    # contained
-                    for x in non_symbolic_s:
-                        if x in unk:
-                            unk.remove(x)
-                else:
-                    # if only a subset of elements in `s` are
-                    # contained in `v` then remove them from `v`
-                    # and add this as a new arg
-                    contained = [x for x in symbolic_s_list
-                        if v.contains(x) == True]
-                    if contained != symbolic_s_list:
-                        new_args.append(
-                            v - FiniteSet(
-                            *contained, evaluate=False))
-                    else:
-                        pass  # for coverage
-
-            other_sets = Intersection(*new_args)
-            if not other_sets:
-                return S.EmptySet  # b/c we use evaluate=False below
-            res += Intersection(
-                FiniteSet(*unk),
-                other_sets, evaluate=False)
-        return res
-
     @staticmethod
     def reduce(args):
         """
@@ -1518,10 +1452,52 @@ def reduce(args):
         if any(s.is_EmptySet for s in args):
             return S.EmptySet
 
-        # Handle Finite sets
-        rv = Intersection._handle_finite_sets(args)
-        if rv is not None:
-            return rv
+        for s in args:
+            if s.is_FiniteSet:
+                # see which elements of the FiniteSet occur within
+                # all other sets in the intersection
+                other_args = [a for a in args if a != s]
+                res = FiniteSet(*[x for x in s if all(
+                    o.contains(x) == True for o in other_args)])
+                unk = [x for x in s if any(
+                    o.contains(x) not in (True, False) for o in other_args)]
+                if unk:
+                    new_other = []
+                    del_other = []
+                    for ival, val in enumerate(other_args):
+                        if val.is_FiniteSet:
+                            # collect expressions having symbols
+                            # from `val` and `s`
+                            symbol_in_val = [x for x in val if x.has(Symbol)]
+                            symbol_in_s = [x for x in s if x.has(Symbol)]
+                            del_other.append(ival)
+                            # if expression with symbols are same in `s` and `val`
+                            # then remove the non-symbol containing expressions
+                            # from `unk`, since they can not be contained
+                            if symbol_in_s == symbol_in_val:
+                                syms = FiniteSet(*symbol_in_s, evaluate=False)
+                                non_symbol_in_s = s - syms
+                                s = syms
+                                for x in non_symbol_in_s:
+                                    if x in unk:
+                                        unk.remove(x)
+                            else:
+                                fin = FiniteSet(*
+                                    [x for x in symbol_in_s
+                                    if val.contains(x) == True],
+                                    evaluate=False)
+                                if s != fin:
+                                    val = val - fin
+                                    new_other.append(val)
+
+                    for i in reversed(del_other):
+                        other_args.pop(i)
+                    other_sets = Intersection(*(other_args + new_other))
+                    if other_sets.is_EmptySet:
+                        return EmptySet()
+                    res += Intersection(
+                        s.func(*unk), other_sets, evaluate=False)
+                return res
 
         # If any of the sets are unions, return a Union of Intersections
         for s in args:
@@ -1813,7 +1789,7 @@ def _intersect(self, other):
         """
         if isinstance(other, self.__class__):
             return self.__class__(*(self._elements & other._elements))
-        return self.__class__(*[el for el in self if el in other])
+        return self.__class__(el for el in self if el in other)
 
     def _complement(self, other):
         if isinstance(other, Interval):


Test patch:
diff --git a/sympy/core/tests/test_expr.py b/sympy/core/tests/test_expr.py
index 49b3d5e614..5313766db9 100644
--- a/sympy/core/tests/test_expr.py
+++ b/sympy/core/tests/test_expr.py
@@ -1686,7 +1686,13 @@ def test_issue_6325():
     e.diff(t, 2) == ans
     assert diff(e, t, 2, simplify=False) != ans
 
+
 def test_issue_7426():
     f1 = a % c
     f2 = x % z
     assert f1.equals(f2) == False
+
+
+def test_issue_10161():
+    x = symbols('x', real=True)
+    assert x*abs(x)*abs(x) == x**3
diff --git a/sympy/polys/tests/test_polyutils.py b/sympy/polys/tests/test_polyutils.py
index 2ea39b7b7a..7b27d42f14 100644
--- a/sympy/polys/tests/test_polyutils.py
+++ b/sympy/polys/tests/test_polyutils.py
@@ -1,6 +1,7 @@
 """Tests for useful utilities for higher level polynomial classes. """
 
-from sympy import S, Integer, sin, cos, sqrt, symbols, pi, Eq, Integral, exp
+from sympy import (S, Integer, sin, cos, sqrt, symbols, pi,
+    Eq, Integral, exp, Mul)
 from sympy.utilities.pytest import raises
 
 from sympy.polys.polyutils import (
@@ -269,6 +270,8 @@ def test__parallel_dict_from_expr_no_gens():
     assert parallel_dict_from_expr([x*y, 2*z, Integer(3)]) == \
         ([{(1, 1, 0): Integer(
             1)}, {(0, 0, 1): Integer(2)}, {(0, 0, 0): Integer(3)}], (x, y, z))
+    assert parallel_dict_from_expr((Mul(x, x**2, evaluate=False),)) == \
+        ([{(3,): 1}], (x,))
 
 
 def test_parallel_dict_from_expr():
diff --git a/sympy/sets/tests/test_sets.py b/sympy/sets/tests/test_sets.py
index cc9065d56c..03386b8984 100644
--- a/sympy/sets/tests/test_sets.py
+++ b/sympy/sets/tests/test_sets.py
@@ -222,7 +222,6 @@ def test_intersect():
     assert Interval(0, 2).intersect(Union(Interval(0, 1), Interval(2, 3))) == \
         Union(Interval(0, 1), Interval(2, 2))
 
-    assert FiniteSet(1, 2)._intersect((1, 2, 3)) == FiniteSet(1, 2)
     assert FiniteSet(1, 2, x).intersect(FiniteSet(x)) == FiniteSet(x)
     assert FiniteSet('ham', 'eggs').intersect(FiniteSet('ham')) == \
         FiniteSet('ham')
@@ -920,7 +919,7 @@ def test_issue_Symbol_inter():
     assert Intersection(FiniteSet(m, n, x), FiniteSet(m, z), r) == \
         Intersection(r, FiniteSet(m, z), FiniteSet(n, x))
     assert Intersection(FiniteSet(m, n, 3), FiniteSet(m, n, x), r) == \
-        Intersection(r, FiniteSet(3, m, n), evaluate=False)
+        Intersection(r, FiniteSet(x), FiniteSet(3, m, n), evaluate=False)
     assert Intersection(FiniteSet(m, n, 3), FiniteSet(m, n, 2, 3), r) == \
         Union(FiniteSet(3), Intersection(r, FiniteSet(m, n)))
     assert Intersection(r, FiniteSet(mat, 2, n), FiniteSet(0, mat, n)) == \
@@ -929,10 +928,3 @@ def test_issue_Symbol_inter():
         Intersection(r, FiniteSet(sin(x), cos(x)))
     assert Intersection(FiniteSet(x**2, 1, sin(x)), FiniteSet(x**2, 2, sin(x)), r) == \
         Intersection(r, FiniteSet(x**2, sin(x)))
-
-
-def test_issue_10113():
-    f = x**2/(x**2 - 4)
-    assert imageset(x, f, S.Reals) == Union(Interval(-oo, 0), Interval(1, oo, True, True))
-    assert imageset(x, f, Interval(-2, 2)) == Interval(-oo, 0)
-    assert imageset(x, f, Interval(-2, 3)) == Union(Interval(-oo, 0), Interval(S(9)/5, oo))