Repository: sympy/sympy

Issue:
solveset(sin(y), y, Interval(0, pi)) is wrong
```
In [5]: solveset(sin(y), y, Interval(0, pi))
Out[5]: {2⋅n⋅π | n ∊ ℤ} ∪ {2⋅n⋅π + π | n ∊ ℤ}
```

It isn't intersecting the domain `Interval(0, pi)`. 

@smichr 


Discussion:
maurogaravello: This corrects also the #12466.
maurogaravello: Seems good for me.
smichr: @maurogaravello , would you be willing to take a look at the commits that come after your last review?
maurogaravello: I am thinking about the changes. A first impression is that making the integral test more robust is necessary. It seems to me that `assert Sum(-ln(n)/n**3, (n, 1, oo)).is_convergent() is S.true` gives a failure. The sum is clearly convergent, but `-ln(n)/n**3` is not decreasing when `n` is big. 
Mathematically speaking, the correct assumption should be the decreasing of abs(-ln(n)/n**3). 
I tried to implement this check some days ago, but sympy seems not to be able to do in all situations.

So a possibility for `Sum(expr, (n, 1, oo)).is_convergent()` could be: checking if expr is decreasing (if it is positive) or checking if -expr is decreasing (if it is negative)
smichr: > but -ln(n)/n**3 is not decreasing when n is big.

True: it is increasing to 0. That is the purpose of the two tests (which essentially test `abs(f(x))`. If `f(x)` is increasing towards zero past its last maxima then `-f(x)` is *decreasing* towards 0 past the same maxima.
maurogaravello: Sorry. I did not see line 494. 
I agree with your proposal. 

smichr: Do you want to cherry pick to your branch? I would send you a pr, but I can't right now.
smichr: > remove NotImplementedError from singularities

I wonder if singularities should raise an error if anything but a finite set of expressions is obtained.
maurogaravello: No problem with the PR. Your solution is better than mine.

Should I delete my PR?
smichr: > Should I delete my PR?

I prefer to attribute your work to you. If you hadn't done what you did I don't know if I would have done what I did. If it's too much of a hassle we can just keep the changes here.
smichr: Test is split 4 needs some debugging:

```
6149____________ sympy/integrals/tests/test_integrals.py:test_diff_wrt _____________

6150  File "/home/travis/virtualenv/python2.7.9/lib/python2.7/site-packages/sympy/integrals/tests/test_integrals.py", line 107, in test_diff_wrt

6151    assert integrate(t + 1, (t, 0, 1)) == S(3)/2

6152  File "/home/travis/virtualenv/python2.7.9/lib/python2.7/site-packages/sympy/integrals/integrals.py", line 1295, in integrate

6153    risch=risch, manual=manual)

6154  File "/home/travis/virtualenv/python2.7.9/lib/python2.7/site-packages/sympy/integrals/integrals.py", line 553, in doit

6155    evalued = Add(*others)._eval_interval(x, a, b)

6156  File "/home/travis/virtualenv/python2.7.9/lib/python2.7/site-packages/sympy/core/expr.py", line 818, in _eval_interval

6157    _singularities = singularities(self, x, include_removable=False)

6158  File "/home/travis/virtualenv/python2.7.9/lib/python2.7/site-packages/sympy/calculus/singularities.py", line 69, in singularities

6159    for d in denoms(expression, symbol):

6160  File "/home/travis/virtualenv/python2.7.9/lib/python2.7/site-packages/sympy/solvers/solvers.py", line 127, in denoms

6161    if any(s in free for s in symbols):

6162TypeError: 'Test' object is not iterable

```

`Test` is created for the purpose of the test in the suite. I'm not sure why it is being asked to iterate.
smichr: And `sets` tests appear to be hanging. Also `sympy/combinatorics/tests/test_partitions.py`?
kshitij10496: > I wonder if singularities should raise an error if anything but a finite set of expressions is obtained.

I think this will restrict the use of this functionality(`singularity`) to non-trigonometric/non-periodic functions. For example, expressions with countably infinite number of disconitnuites such as`1/cos(x)` wouldn't be correctly computed by this method in the future.
What do you think about this ?

smichr: > What do you think about this ?

I'm open to suggestions. I guess the easiest thing to do is just return the sympy-state-of-the-art solveset solution for the singularities and the user will make up their own mind about what to do with them. Any idea why that rational restriction was there in the first place?
smichr: When tests pass, I will commit unless I hear something more from @parsoyaarihant . I removed changes to `singularities` except for the note suggested (I believe) by @kshitij10496 

Patch:
diff --git a/sympy/calculus/singularities.py b/sympy/calculus/singularities.py
index a9f2b4dcfb..f72010733d 100644
--- a/sympy/calculus/singularities.py
+++ b/sympy/calculus/singularities.py
@@ -44,6 +44,12 @@ def singularities(expression, symbol):
     >>> singularities(1/(y**3 + 1), y)
     {-1, 1/2 - sqrt(3)*I/2, 1/2 + sqrt(3)*I/2}
 
+    Notes
+    =====
+
+    This function does not find nonisolated singularities
+    nor does it find branch points of the expression.
+
     References
     ==========
 
@@ -58,6 +64,7 @@ def singularities(expression, symbol):
     else:
         return solveset(simplify(1 / expression), symbol)
 
+
 ###########################################################################
 ###################### DIFFERENTIAL CALCULUS METHODS ######################
 ###########################################################################
@@ -67,22 +74,23 @@ def monotonicity_helper(expression, predicate, interval=S.Reals, symbol=None):
     """
     Helper function for functions checking function monotonicity.
 
-    It returns whether the interval in which function's derivative
-    satisfies given predicate is superset of given interval.
+    It returns a boolean indicating whether the interval in which
+    the function's derivative satisfies given predicate is a superset
+    of the given interval.
     """
     expression = sympify(expression)
+    free = expression.free_symbols
 
     if symbol is None:
-        free_variables = expression.free_symbols
-        if len(free_variables) > 1:
+        if len(free) > 1:
             raise NotImplementedError(
                 'The function has not yet been implemented'
                 ' for all multivariate expressions.'
             )
-        symbol = next(iter(free_variables)) if len(free_variables) == 1 else Symbol('x')
 
-    derivative = expression.diff(symbol)
-    predicate_interval = solveset(predicate(derivative), symbol, S.Reals)
+    x = symbol or (free.pop() if free else Symbol('x'))
+    derivative = expression.diff(x)
+    predicate_interval = solveset(predicate(derivative), x, S.Reals)
     return interval.is_subset(predicate_interval)
 
 
@@ -208,11 +216,13 @@ def is_monotonic(expression, interval=S.Reals, symbol=None):
     """
     expression = sympify(expression)
 
-    if symbol is None and len(expression.free_symbols) > 1:
+    free = expression.free_symbols
+    if symbol is None and len(free) > 1:
         raise NotImplementedError(
             'is_monotonic has not yet been implemented'
             ' for all multivariate expressions.'
         )
 
-    return is_increasing(expression, interval, symbol) or \
-        is_decreasing(expression, interval, symbol)
+    x = symbol or (free.pop() if free else Symbol('x'))
+    turning_points = solveset(expression.diff(x), x, interval)
+    return interval.intersection(turning_points) is S.EmptySet
diff --git a/sympy/calculus/util.py b/sympy/calculus/util.py
index 38117027fd..674f066284 100644
--- a/sympy/calculus/util.py
+++ b/sympy/calculus/util.py
@@ -13,12 +13,14 @@
 
 def continuous_domain(f, symbol, domain):
     """
-    Returns the intervals in the given domain for which the function is continuous.
+    Returns the intervals in the given domain for which the function
+    is continuous.
     This method is limited by the ability to determine the various
     singularities and discontinuities of the given function.
 
     Examples
     ========
+
     >>> from sympy import Symbol, S, tan, log, pi, sqrt
     >>> from sympy.sets import Interval
     >>> from sympy.calculus.util import continuous_domain
@@ -196,8 +198,7 @@ def not_empty_in(finset_intersection, *syms):
     # TODO: handle transcendental functions
     # TODO: handle multivariate functions
     if len(syms) == 0:
-        raise ValueError("A Symbol or a tuple of symbols must be given "
-                         "as the third parameter")
+        raise ValueError("One or more symbols must be given in syms.")
 
     if finset_intersection.is_EmptySet:
         return EmptySet()
diff --git a/sympy/concrete/summations.py b/sympy/concrete/summations.py
index 372487664c..ab1c77e66e 100644
--- a/sympy/concrete/summations.py
+++ b/sympy/concrete/summations.py
@@ -13,11 +13,12 @@
 from sympy.functions.elementary.piecewise import Piecewise
 from sympy.logic.boolalg import And
 from sympy.polys import apart, PolynomialError
-from sympy.solvers import solve
 from sympy.series.limits import limit
 from sympy.series.order import O
+from sympy.sets.sets import FiniteSet
+from sympy.solvers import solve
+from sympy.solvers.solveset import solveset
 from sympy.core.compatibility import range
-from sympy.tensor.indexed import Idx
 
 
 class Sum(AddWithLimits, ExprWithIntLimits):
@@ -483,14 +484,22 @@ def is_convergent(self):
             return S.false
 
         ### ------------- integral test -------------- ###
-        if is_decreasing(sequence_term, interval):
-            integral_val = Integral(sequence_term, (sym, lower_limit, upper_limit))
-            try:
-                integral_val_evaluated = integral_val.doit()
-                if integral_val_evaluated.is_number:
-                    return S(integral_val_evaluated.is_finite)
-            except NotImplementedError:
-                pass
+        maxima = solveset(sequence_term.diff(sym), sym, interval)
+        if not maxima:
+            check_interval = interval
+        elif isinstance(maxima, FiniteSet) and maxima.sup.is_number:
+            check_interval = Interval(maxima.sup, interval.sup)
+            if (
+                    is_decreasing(sequence_term, check_interval) or
+                    is_decreasing(-sequence_term, check_interval)):
+                integral_val = Integral(
+                    sequence_term, (sym, lower_limit, upper_limit))
+                try:
+                    integral_val_evaluated = integral_val.doit()
+                    if integral_val_evaluated.is_number:
+                        return S(integral_val_evaluated.is_finite)
+                except NotImplementedError:
+                    pass
 
         ### -------------- Dirichlet tests -------------- ###
         if order.expr.is_Mul:
diff --git a/sympy/core/expr.py b/sympy/core/expr.py
index 798872cd39..0daf2adb5d 100644
--- a/sympy/core/expr.py
+++ b/sympy/core/expr.py
@@ -1746,10 +1746,10 @@ def as_base_exp(self):
     def as_coeff_mul(self, *deps, **kwargs):
         """Return the tuple (c, args) where self is written as a Mul, ``m``.
 
-        c should be a Rational multiplied by any terms of the Mul that are
+        c should be a Rational multiplied by any factors of the Mul that are
         independent of deps.
 
-        args should be a tuple of all other terms of m; args is empty
+        args should be a tuple of all other factors of m; args is empty
         if self is a Number or if self is independent of deps (when given).
 
         This should be used when you don't know if self is a Mul or not but
diff --git a/sympy/sets/sets.py b/sympy/sets/sets.py
index ab88ed7d7c..9b6958d428 100644
--- a/sympy/sets/sets.py
+++ b/sympy/sets/sets.py
@@ -717,30 +717,9 @@ def _boundary(self):
 
     @property
     def is_iterable(self):
-        """
-        A property method which tests whether a set is iterable or not.
-        Returns True if set is iterable, otherwise returns False.
-
-        Examples
-        ========
-
-        >>> from sympy import FiniteSet, Interval, ProductSet
-        >>> I = Interval(0, 1)
-        >>> A = FiniteSet(1, 2, 3, 4, 5)
-        >>> I.is_iterable
-        False
-        >>> A.is_iterable
-        True
-
-        """
         return all(set.is_iterable for set in self.sets)
 
     def __iter__(self):
-        """
-        A method which implements is_iterable property method.
-        If self.is_iterable returns True (both constituent sets are iterable),
-        then return the Cartesian Product. Otherwise, raise TypeError.
-        """
         if self.is_iterable:
             return product(*self.sets)
         else:
diff --git a/sympy/solvers/inequalities.py b/sympy/solvers/inequalities.py
index 43abe000df..70412019e6 100644
--- a/sympy/solvers/inequalities.py
+++ b/sympy/solvers/inequalities.py
@@ -481,16 +481,15 @@ def solve_univariate_inequality(expr, gen, relational=True, domain=S.Reals, cont
                 domain = Interval(0, period, False, True)
 
         if rv is None:
-            singularities = []
-            for d in denoms(e):
-                singularities.extend(solvify(d, gen, domain))
-            if not continuous:
-                domain = continuous_domain(e, gen, domain)
             solns = solvify(e, gen, domain)
-
             if solns is None:
                 raise NotImplementedError(filldedent('''The inequality cannot be
                     solved using solve_univariate_inequality.'''))
+            singularities = []
+            for d in denoms(expr, gen):
+                singularities.extend(solvify(d, gen, domain))
+            if not continuous:
+                domain = continuous_domain(e, gen, domain)
 
             include_x = expr.func(0, 0)
 
@@ -510,63 +509,68 @@ def valid(x):
                         return expr.func(v, 0)
                     return S.false
 
-            start = domain.inf
-            sol_sets = [S.EmptySet]
             try:
-                discontinuities = domain.boundary - FiniteSet(domain.inf, domain.sup)
-                critical_points = set(solns + singularities + list(discontinuities))
+                discontinuities = set(domain.boundary -
+                    FiniteSet(domain.inf, domain.sup))
+                # remove points that are not between inf and sup of domain
+                critical_points = FiniteSet(*(solns + singularities + list(
+                    discontinuities))).intersection(
+                    Interval(domain.inf, domain.sup,
+                    domain.inf not in domain, domain.sup not in domain))
                 reals = _nsort(critical_points, separated=True)[0]
-
             except NotImplementedError:
                 raise NotImplementedError('sorting of these roots is not supported')
 
+            sol_sets = [S.EmptySet]
+
+            start = domain.inf
             if valid(start) and start.is_finite:
                 sol_sets.append(FiniteSet(start))
 
             for x in reals:
                 end = x
 
-                if end in [S.NegativeInfinity, S.Infinity]:
-                    if valid(S(0)):
-                        sol_sets.append(Interval(start, S.Infinity, True, True))
-                        break
-
-                pt = ((start + end)/2 if start is not S.NegativeInfinity else
-                    (end/2 if end.is_positive else
-                    (2*end if end.is_negative else
-                    end - 1)))
-                if valid(pt):
+                if valid(_pt(start, end)):
                     sol_sets.append(Interval(start, end, True, True))
 
                 if x in singularities:
                     singularities.remove(x)
-                elif include_x:
-                    sol_sets.append(FiniteSet(x))
+                else:
+                    if x in discontinuities:
+                        discontinuities.remove(x)
+                        _valid = valid(x)
+                    else:  # it's a solution
+                        _valid = include_x
+                    if _valid:
+                        sol_sets.append(FiniteSet(x))
 
                 start = end
 
             end = domain.sup
+            if valid(end) and end.is_finite:
+                sol_sets.append(FiniteSet(end))
 
-            # in case start == -oo then there were no solutions so we just
-            # check a point between -oo and oo (e.g. 0) else pick a point
-            # past the last solution (which is start after the end of the
-            # for-loop above
-            pt = (0 if start is S.NegativeInfinity else
-                (start/2 if start.is_negative else
-                (2*start if start.is_positive else
-                start + 1)))
-
-            if pt >= end:
-                pt = (start + end)/2
-
-            if valid(pt):
-                sol_sets.append(Interval(start, end, True, True))
+            if valid(_pt(start, end)):
+                sol_sets.append(Interval.open(start, end))
 
             rv = Union(*sol_sets).subs(gen, _gen)
 
     return rv if not relational else rv.as_relational(_gen)
 
 
+def _pt(start, end):
+    """Return a point between start and end"""
+    if start.is_infinite and end.is_infinite:
+        pt = S.Zero
+    elif end.is_infinite:
+        pt = start + 1
+    elif start.is_infinite:
+        pt = end - 1
+    else:
+        pt = (start + end)/2
+    return pt
+
+
 def _solve_inequality(ie, s):
     """ A hacky replacement for solve, since the latter only works for
         univariate inequalities. """
diff --git a/sympy/solvers/solvers.py b/sympy/solvers/solvers.py
index 4d005c7014..e83053a9d3 100644
--- a/sympy/solvers/solvers.py
+++ b/sympy/solvers/solvers.py
@@ -77,10 +77,10 @@ def _simple_dens(f, symbols):
     return dens
 
 
-def denoms(eq, symbols=None):
+def denoms(eq, *symbols):
     """Return (recursively) set of all denominators that appear in eq
-    that contain any symbol in iterable ``symbols``; if ``symbols`` is
-    None (default) then all denominators will be returned.
+    that contain any symbol in ``symbols``; if ``symbols`` are not
+    provided then all denominators will be returned.
 
     Examples
     ========
@@ -100,6 +100,12 @@ def denoms(eq, symbols=None):
 
     >>> denoms(x/2 + y/z)
     {2, z}
+
+    If `symbols` are provided then only denominators containing
+    those symbols will be returned
+
+    >>> denoms(1/x + 1/y + 1/z, y, z)
+    {y, z}
     """
 
     pot = preorder_traversal(eq)
@@ -112,6 +118,9 @@ def denoms(eq, symbols=None):
             dens.add(d)
     if not symbols:
         return dens
+    elif len(symbols) == 1:
+        if iterable(symbols[0]):
+            symbols = symbols[0]
     rv = []
     for d in dens:
         free = d.free_symbols
diff --git a/sympy/solvers/solveset.py b/sympy/solvers/solveset.py
index 13fdb2c223..fbe224f23f 100644
--- a/sympy/solvers/solveset.py
+++ b/sympy/solvers/solveset.py
@@ -44,16 +44,16 @@ def _invert(f_x, y, x, domain=S.Complexes):
     the set of function ``{h_1(y), h_2(y), ..., h_n(y)}``.
     Here, ``y`` is not necessarily a symbol.
 
-    The ``set_h`` contains the functions along with the information
-    about their domain in which they are valid, through set
-    operations. For instance, if ``y = Abs(x) - n``, is inverted
-    in the real domain, then, the ``set_h`` doesn't simply return
-    `{-n, n}`, as the nature of `n` is unknown; rather it will return:
+    The ``set_h`` contains the functions, along with the information
+    about the domain in which they are valid, through set
+    operations. For instance, if ``y = Abs(x) - n`` is inverted
+    in the real domain, then ``set_h`` is not simply
+    `{-n, n}` as the nature of `n` is unknown; rather, it is:
     `Intersection([0, oo) {n}) U Intersection((-oo, 0], {-n})`
 
-    By default, the complex domain is used but note that inverting even
-    seemingly simple functions like ``exp(x)`` can give very different
-    result in the complex domain than are obtained in the real domain.
+    By default, the complex domain is used which means that inverting even
+    seemingly simple functions like ``exp(x)`` will give very different
+    results from those obtained in the real domain.
     (In the case of ``exp(x)``, the inversion via ``log`` is multi-valued
     in the complex domain, having infinitely many branches.)
 
@@ -166,21 +166,22 @@ def _invert_real(f, g_ys, symbol):
             res = imageset(Lambda(n, real_root(n, expo)), g_ys)
             if expo.is_rational:
                 numer, denom = expo.as_numer_denom()
-                if numer == S.One or numer == - S.One:
+                if numer is S.One or numer is S.NegativeOne:
                     if denom % 2 == 0:
-                        base_positive = solveset(base>=0, symbol, S.Reals)
-                        res = imageset(Lambda(n, real_root(n, expo)), g_ys.intersect(Interval.Ropen(S(0), S.Infinity)))
-                        inversion = _invert_real(base, res, symbol)
-                        return (inversion[0], inversion[1].intersect(base_positive))
+                        base_positive = solveset(base >= 0, symbol, S.Reals)
+                        res = imageset(Lambda(n, real_root(n, expo)
+                            ), g_ys.intersect(
+                            Interval.Ropen(S.Zero, S.Infinity)))
+                        _inv, _set = _invert_real(base, res, symbol)
+                        return (_inv, _set.intersect(base_positive))
                     else:
                         return _invert_real(base, res, symbol)
-                else:
-                    if numer % 2 == 0:
+                elif numer % 2 == 0:
                         n = Dummy('n')
                         neg_res = imageset(Lambda(n, -n), res)
                         return _invert_real(base, res + neg_res, symbol)
-                    else:
-                        return _invert_real(base, res, symbol)
+                else:
+                    return _invert_real(base, res, symbol)
             else:
                 if not base.is_positive:
                     raise ValueError("x**w where w is irrational is not "
@@ -312,10 +313,14 @@ def _is_finite_with_finite_vars(f, domain=S.Complexes):
     """
     def assumptions(s):
         A = s.assumptions0
-        if A.get('finite', None) is None:
-            A['finite'] = True
-        A.setdefault('complex', True)
-        A.setdefault('real', domain.is_subset(S.Reals))
+        A.setdefault('finite', A.get('finite', True))
+        if domain.is_subset(S.Reals):
+            # if this gets set it will make complex=True, too
+            A.setdefault('real', True)
+        else:
+            # don't change 'real' because being complex implies
+            # nothing about being real
+            A.setdefault('complex', True)
         return A
 
     reps = {s: Dummy(**assumptions(s)) for s in f.free_symbols}
@@ -519,7 +524,7 @@ def _solve_radical(f, symbol, solveset_solver):
     eq, cov = unrad(f)
     if not cov:
         result = solveset_solver(eq, symbol) - \
-            Union(*[solveset_solver(g, symbol) for g in denoms(f, [symbol])])
+            Union(*[solveset_solver(g, symbol) for g in denoms(f, symbol)])
     else:
         y, yeq = cov
         if not solveset_solver(y - I, y):
@@ -909,8 +914,7 @@ def solveset(f, symbol=None, domain=S.Complexes):
                 setting domain=S.Reals'''))
         try:
             result = solve_univariate_inequality(
-            f, symbol, relational=False) - _invalid_solutions(
-            f, symbol, domain)
+            f, symbol, domain=domain, relational=False)
         except NotImplementedError:
             result = ConditionSet(symbol, f, domain)
         return result
@@ -918,13 +922,6 @@ def solveset(f, symbol=None, domain=S.Complexes):
     return _solveset(f, symbol, domain, _check=True)
 
 
-def _invalid_solutions(f, symbol, domain):
-    bad = S.EmptySet
-    for d in denoms(f):
-        bad += _solveset(d, symbol, domain, _check=False)
-    return bad
-
-
 def solveset_real(f, symbol):
     return solveset(f, symbol, S.Reals)
 


Test patch:
diff --git a/sympy/calculus/tests/test_singularities.py b/sympy/calculus/tests/test_singularities.py
index 2524cc0b81..45e827d2c8 100644
--- a/sympy/calculus/tests/test_singularities.py
+++ b/sympy/calculus/tests/test_singularities.py
@@ -26,8 +26,8 @@ def test_singularities():
 def test_singularities_non_rational():
     x = Symbol('x', real=True)
 
-    assert singularities(exp(1/x), x) == (0)
-    assert singularities(log((x - 2)**2), x) == (2)
+    assert singularities(exp(1/x), x) == FiniteSet(0)
+    assert singularities(log((x - 2)**2), x) == FiniteSet(2)
 
 
 def test_is_increasing():
@@ -73,6 +73,7 @@ def test_is_strictly_decreasing():
         1/(x**2 - 3*x), Interval.Ropen(-oo, S(3)/2))
     assert not is_strictly_decreasing(-x**2, Interval(-oo, 0))
     assert not is_strictly_decreasing(1)
+    assert is_strictly_decreasing(1/(x**2 - 3*x), Interval.open(1.5, 3))
 
 
 def test_is_monotonic():
@@ -82,8 +83,3 @@ def test_is_monotonic():
     assert is_monotonic(x**3 - 3*x**2 + 4*x, S.Reals)
     assert not is_monotonic(-x**2, S.Reals)
     assert is_monotonic(x**2 + y + 1, Interval(1, 2), x)
-
-
-@XFAIL
-def test_strictly_decreasing():
-    assert is_strictly_decreasing(1/(x**2 - 3*x), Interval.open(1.5, 3))
diff --git a/sympy/concrete/tests/test_sums_products.py b/sympy/concrete/tests/test_sums_products.py
index 1e3a811413..98a9cb7aa1 100644
--- a/sympy/concrete/tests/test_sums_products.py
+++ b/sympy/concrete/tests/test_sums_products.py
@@ -963,6 +963,15 @@ def test_is_convergent():
     assert Sum(f, (n, -oo, oo)).is_convergent() is S.false
     assert Sum(f, (n, -oo, 1)).is_convergent() is S.true
 
+    # integral test
+
+    assert Sum(log(n)/n**3, (n, 1, oo)).is_convergent() is S.true
+    assert Sum(-log(n)/n**3, (n, 1, oo)).is_convergent() is S.true
+    # the following function has maxima located at (x, y) =
+    # (1.2, 0.43), (3.0, -0.25) and (6.8, 0.050)
+    eq = (x - 2)*(x**2 - 6*x + 4)*exp(-x)
+    assert Sum(eq, (x, 1, oo)).is_convergent() is S.true
+
 
 def test_is_absolutely_convergent():
     assert Sum((-1)**n, (n, 1, oo)).is_absolutely_convergent() is S.false
@@ -972,8 +981,6 @@ def test_is_absolutely_convergent():
 @XFAIL
 def test_convergent_failing():
     assert Sum(sin(n)/n**3, (n, 1, oo)).is_convergent() is S.true
-    assert Sum(ln(n)/n**3, (n, 1, oo)).is_convergent() is S.true
-    # is_decreasing is not handling "is_decreasing(1)", so raises error
 
     # dirichlet tests
     assert Sum(sin(n)/n, (n, 1, oo)).is_convergent() is S.true
diff --git a/sympy/core/tests/test_expr.py b/sympy/core/tests/test_expr.py
index 1b15447a8d..66d2520867 100644
--- a/sympy/core/tests/test_expr.py
+++ b/sympy/core/tests/test_expr.py
@@ -1444,7 +1444,10 @@ def test_sort_key_atomic_expr():
     assert sorted([-m, s], key=lambda arg: arg.sort_key()) == [-m, s]
 
 
-def test_issue_4199():
+def test_eval_interval():
+    assert exp(x)._eval_interval(*Tuple(x, 0, 1)) == exp(1) - exp(0)
+
+    # issue 4199
     # first subs and limit gives NaN
     a = x/y
     assert a._eval_interval(x, S(0), oo)._eval_interval(y, oo, S(0)) is S.NaN
diff --git a/sympy/integrals/tests/test_integrals.py b/sympy/integrals/tests/test_integrals.py
index fb3bd88998..a72512aefe 100644
--- a/sympy/integrals/tests/test_integrals.py
+++ b/sympy/integrals/tests/test_integrals.py
@@ -1021,7 +1021,6 @@ def test_issue_4487():
     assert simplify(integrate(exp(-x)*x**y, x)) == lowergamma(y + 1, x)
 
 
-@XFAIL
 def test_issue_4215():
     x = Symbol("x")
     assert integrate(1/(x**2), (x, -1, 1)) == oo
diff --git a/sympy/solvers/tests/test_inequalities.py b/sympy/solvers/tests/test_inequalities.py
index 14722d7306..5663d4cc8c 100644
--- a/sympy/solvers/tests/test_inequalities.py
+++ b/sympy/solvers/tests/test_inequalities.py
@@ -294,19 +294,19 @@ def test_solve_univariate_inequality():
 def test_trig_inequalities():
     # all the inequalities are solved in a periodic interval.
     assert isolve(sin(x) < S.Half, x, relational=False) == \
-        Union(Interval(0, pi/6, False, True), Interval(5*pi/6, 2*pi, True, True))
+        Union(Interval(0, pi/6, False, True), Interval(5*pi/6, 2*pi, True, False))
     assert isolve(sin(x) > S.Half, x, relational=False) == \
         Interval(pi/6, 5*pi/6, True, True)
     assert isolve(cos(x) < S.Zero, x, relational=False) == \
         Interval(pi/2, 3*pi/2, True, True)
     assert isolve(cos(x) >= S.Zero, x, relational=False) == \
-        Union(Interval(0, pi/2), Interval(3*pi/2, 2*pi, False, True))
+        Union(Interval(0, pi/2), Interval(3*pi/2, 2*pi))
 
     assert isolve(tan(x) < S.One, x, relational=False) == \
-        Union(Interval(0, pi/4, False, True), Interval(pi/2, pi, True, True))
+        Union(Interval.Ropen(0, pi/4), Interval.Lopen(pi/2, pi))
 
     assert isolve(sin(x) <= S.Zero, x, relational=False) == \
-        Union(FiniteSet(S(0)), Interval(pi, 2*pi, False, True))
+        Union(FiniteSet(S(0)), Interval(pi, 2*pi))
 
     assert isolve(sin(x) <= S(1), x, relational=False) == S.Reals
     assert isolve(cos(x) < S(-2), x, relational=False) == S.EmptySet
@@ -320,11 +320,6 @@ def test_issue_9954():
     assert isolve(x**2 < 0, x, relational=False) == S.EmptySet
     assert isolve(x**2 < 0, x, relational=True) == S.EmptySet.as_relational(x)
 
-def test_issue_12429():
-    eq = solveset(log(x)/x<=0,x,S.Reals)
-    sol = Interval(0, 1, True)
-    assert eq == sol
-
 
 @XFAIL
 def test_slow_general_univariate():
@@ -367,9 +362,16 @@ def test_issue_10268():
     assert solve(log(x) < 1000) == And(S(0) < x, x < exp(1000))
 
 
-
 @XFAIL
 def test_isolve_Sets():
     n = Dummy('n')
     assert isolve(Abs(x) <= n, x, relational=False) == \
-        Piecewise((S.EmptySet, n<S(0)), (Interval(-n, n), True))
+        Piecewise((S.EmptySet, n < 0), (Interval(-n, n), True))
+
+
+def test_issue_10671_12466():
+    assert solveset(sin(y), y, Interval(0, pi)) == FiniteSet(0, pi)
+    i = Interval(1, 10)
+    assert solveset((1/x).diff(x) < 0, x, i) == i
+    assert solveset((log(x - 6)/x) <= 0, x, S.Reals) == \
+        Interval.Lopen(6, 7)
diff --git a/sympy/solvers/tests/test_solvers.py b/sympy/solvers/tests/test_solvers.py
index 2c837f701d..a4fd893efa 100644
--- a/sympy/solvers/tests/test_solvers.py
+++ b/sympy/solvers/tests/test_solvers.py
@@ -12,7 +12,7 @@
 from sympy.solvers import solve_linear_system, solve_linear_system_LU, \
     solve_undetermined_coeffs
 from sympy.solvers.solvers import _invert, unrad, checksol, posify, _ispow, \
-    det_quick, det_perm, det_minor, _simple_dens, check_assumptions
+    det_quick, det_perm, det_minor, _simple_dens, check_assumptions, denoms
 
 from sympy.physics.units import cm
 from sympy.polys.rootoftools import CRootOf
@@ -1863,3 +1863,12 @@ def test_issue_12448():
 
     assert sfun[fun[0]].xreplace(reps).count_ops() == \
         ssym[sym[0]].count_ops()
+
+
+def test_denoms():
+    assert denoms(x/2 + 1/y) == set([2, y])
+    assert denoms(x/2 + 1/y, y) == set([y])
+    assert denoms(x/2 + 1/y, [y]) == set([y])
+    assert denoms(1/x + 1/y + 1/z, [x, y]) == set([x, y])
+    assert denoms(1/x + 1/y + 1/z, x, y) == set([x, y])
+    assert denoms(1/x + 1/y + 1/z, set([x, y])) == set([x, y])
diff --git a/sympy/solvers/tests/test_solveset.py b/sympy/solvers/tests/test_solveset.py
index 190ec371df..b54b661612 100644
--- a/sympy/solvers/tests/test_solveset.py
+++ b/sympy/solvers/tests/test_solveset.py
@@ -25,7 +25,9 @@
 from sympy.solvers.solveset import (
     solveset_real, domain_check, solveset_complex, linear_eq_to_matrix,
     linsolve, _is_function_class_equation, invert_real, invert_complex,
-    solveset, solve_decomposition, substitution, nonlinsolve, solvify)
+    solveset, solve_decomposition, substitution, nonlinsolve, solvify,
+    _is_finite_with_finite_vars)
+
 
 a = Symbol('a', real=True)
 b = Symbol('b', real=True)
@@ -1529,8 +1531,45 @@ def test_issue_11534():
     assert solveset(eq, x, S.Reals) == soln
     assert solveset(eq2, x, S.Reals) == soln
 
+
+def test_issue_10477():
+    assert solveset((x**2 + 4*x - 3)/x < 2, x, S.Reals) == \
+        Union(Interval.open(-oo, -3), Interval.open(0, 1))
+
+
+def test_issue_10671():
+    assert solveset(sin(y), y, Interval(0, pi)) == FiniteSet(0, pi)
+    i = Interval(1, 10)
+    assert solveset((1/x).diff(x) < 0, x, i) == i
+
+
+def test_issue_11064():
+    eq = x + sqrt(x**2 - 5)
+    assert solveset(eq > 0, x, S.Reals) == \
+        Interval(sqrt(5), oo)
+    assert solveset(eq < 0, x, S.Reals) == \
+        Interval(-oo, -sqrt(5))
+    assert solveset(eq > sqrt(5), x, S.Reals) == \
+        Interval.Lopen(sqrt(5), oo)
+
+
 def test_issue_12478():
-    expr = sqrt(x - 2) + 2
-    soln = solveset_real(expr, x)
+    eq = sqrt(x - 2) + 2
+    soln = solveset_real(eq, x)
+    assert soln is S.EmptySet
+    assert solveset(eq < 0, x, S.Reals) is S.EmptySet
+    assert solveset(eq > 0, x, S.Reals) == Interval(2, oo)
+
+
+def test_issue_12429():
+    eq = solveset(log(x)/x <= 0, x, S.Reals)
+    sol = Interval.Lopen(0, 1)
+    assert eq == sol
+
 
-    assert soln == S.EmptySet
+def test__is_finite_with_finite_vars():
+    f = _is_finite_with_finite_vars
+    # issue 12482
+    assert all(f(1/x) is None for x in (
+        Dummy(), Dummy(real=True), Dummy(complex=True)))
+    assert f(1/Dummy(real=False)) is True  # b/c it's finite but not 0