Repository: sympy/sympy

Issue:
is_decreasing(), is_increasing() and strictly functions should have `Symbol` as argument to them
`is_decreasing()`, `is_increasing()`, `is_strictly_increasing()` and `is_strictly_decreasing()` should have `x` or Symbol for as their parameter.
Because of this it will be able to deal expressions like
```
>>> is_decreasing(n + x, n, Interval(1, oo))    # here x is taken as Symbol
True
```
Also we have
```
>>> is_decreasing(1, Interval(1, 2))
AttributeError                            Traceback (most recent call last)
<ipython-input-37-9dfd81c0bb7d> in <module>()
----> 1 is_decreasing(1, Interval(1, oo))

/home/gxyd/Public/sympy/sympy/calculus/singularities.py in is_decreasing(f, interval)
    120 
    121     """
--> 122     if len(f.free_symbols) > 1:
    123         raise NotImplementedError('is_decreasing has not yet been implemented '
    124                                   'for multivariate expressions')

AttributeError: 'int' object has no attribute 'free_symbols'
```

Discussion:
leosartaj: This doesn't work ``is_increasing(1, x)``. Similarly for the others. This can be fixed by adding a ``sympify`` call.
leosartaj: The ``symbol`` argument can be made a ``kwarg``. So that it is not necessary to write symbol for univariate functions.

This should work

```
>>> is_increasing(x)
True
```
leosartaj: Some examples for multivariate functions can be added in the docstrings.
gxyd: @leosartaj thank you very much for all the points you made. I was though waiting for @aktech to get on to verify. But now you have seen that's really nice.
gxyd: @leosartaj @aktech i think this is ready for review.
leosartaj: Please do not update the PR, when someone is reviewing. It gets confusing. :smile:
gxyd: I have updated the error message. And addressed other comments.
leosartaj: You can use tools like flake8 to catch issues with indentation and such.
leosartaj: This looks good, +1 to merge if tests pass.

Patch:
diff --git a/doc/src/modules/polys/index.rst b/doc/src/modules/polys/index.rst
index d7249b538d..be212828af 100644
--- a/doc/src/modules/polys/index.rst
+++ b/doc/src/modules/polys/index.rst
@@ -25,5 +25,4 @@ Contents
     reference.rst
     agca.rst
     internals.rst
-    ringseries.rst
     literature.rst
diff --git a/doc/src/modules/polys/internals.rst b/doc/src/modules/polys/internals.rst
index 46c53d7532..b4a2f2ca7f 100644
--- a/doc/src/modules/polys/internals.rst
+++ b/doc/src/modules/polys/internals.rst
@@ -751,6 +751,29 @@ Modular GCD
 .. autofunction:: modgcd_multivariate
 .. autofunction:: func_field_modgcd
 
+Manipulation of power series
+****************************************************************************
+.. currentmodule:: sympy.polys.ring_series
+
+Functions in this module carry the prefix ``rs_``, standing for "ring series".
+They manipulate finite power series in the sparse representation provided
+by ``polys.ring.ring``.
+
+
+.. autofunction:: rs_trunc
+.. autofunction:: rs_mul
+.. autofunction:: rs_square
+.. autofunction:: rs_pow
+.. autofunction:: rs_series_inversion
+.. autofunction:: rs_series_from_list
+.. autofunction:: rs_integrate
+.. autofunction:: rs_log
+.. autofunction:: rs_exp
+.. autofunction:: rs_newton
+.. autofunction:: rs_hadamard_exp
+.. autofunction:: rs_compose_add
+
+
 Undocumented
 ============
 
diff --git a/doc/src/modules/polys/ringseries.rst b/doc/src/modules/polys/ringseries.rst
deleted file mode 100644
index 4a810a2687..0000000000
--- a/doc/src/modules/polys/ringseries.rst
+++ /dev/null
@@ -1,215 +0,0 @@
-.. _polys-ringseries:
-
-=====================================
-Series Manipulation using Polynomials
-=====================================
-
-Any finite Taylor series, for all practical purposes is, in fact a polynomial.
-This module makes use of the efficient representation and operations of sparse
-polynomials for very fast multivariate series manipulations. Typical speedups
-compared to SymPy's ``series`` method are in the range 20-100, with the gap
-widening as the series being handled gets larger.
-
-All the functions expand any given series on some ring specified by the user.
-Thus, the coefficients of the calculated series depend on the ring being used.
-For example::
-
-    >>> from sympy.polys import ring, QQ, RR
-    >>> from sympy.polys.ring_series import rs_sin
-    >>> R, x, y = ring('x, y', QQ)
-    >>> rs_sin(x*y, x, 5)
-    -1/6*x**3*y**3 + x*y
-
-``QQ`` stands for the Rational domain. Here all coefficients are rationals. It
-is recommended to use ``QQ`` with ring series as it automatically chooses the
-fastest Rational type.
-
-Similarly, if a Real domain is used::
-
-    >>> R, x, y = ring('x, y', RR)
-    >>> rs_sin(x*y, x, 5)
-    -0.166666666666667*x**3*y**3 + x*y
-
-Though the definition of a polynomial limits the use of Polynomial module to
-Taylor series, we extend it to allow Laurent and even Puiseux series (with
-fractional exponents)::
-
-    >>> from sympy.polys.ring_series import rs_cos, rs_tan
-    >>> R, x, y = ring('x, y', QQ)
-
-    >>> rs_cos(x + x*y, x, 3)/x**3
-    -1/2*x**(-1)*y**2 - x**(-1)*y - 1/2*x**(-1) + x**(-3)
-
-    >>> rs_tan(x**QQ(2, 5)*y**QQ(1, 2), x, 2)
-    1/3*x**(6/5)*y**(3/2) + x**(2/5)*y**(1/2)
-
-By default, ``PolyElement`` did not allow non-natural numbers as exponents. It
-converted a fraction to an integer and raised an error on getting negative
-exponents. The goal of the ``ring series`` module is fast series expansion, and
-not to use the ``polys`` module. The reason we use it as our backend is simply
-because it implements a sparse representation and most of the basic functions
-that we need. However, this default behaviour of ``polys`` was limiting for
-``ring series``.
-
-Note that there is no such constraint (in having rational exponents) in the
-data-structure used by ``polys``- ``dict``. Sparse polynomials
-(``PolyElement``) use the Python dict to store a polynomial term by term, where
-a tuple of exponents is the key and the coefficient of that term is the value.
-There is no reason why we can't have rational values in the ``dict`` so as to
-support rational exponents.
-
-So the approach we took was to modify sparse ``polys`` to allow non-natural
-exponents. And it turned out to be quite simple. We only had to delete the
-conversion to ``int`` of exponents in the ``__pow__`` method of
-``PolyElement``. So::
-
-    >>> x**QQ(3, 4)
-    x**(3/4)
-
-and not ``1`` as was the case earlier.
-
-Though this change violates the definition of a polynomial, it doesn't break
-anything yet.  Ideally, we shouldn't modify ``polys`` in any way. But to have
-all the ``series`` capabilities we want, no other simple way was found. If need
-be, we can separate the modified part of ``polys`` from core ``polys``. It
-would be great if any other elegant solution is found.
-
-All series returned by the functions of this module are instances of the
-``PolyElement`` class. To use them with other SymPy types, convert them  to
-``Expr``::
-
-    >>> from sympy.polys.ring_series import rs_exp
-    >>> from sympy.abc import a, b, c
-    >>> series = rs_exp(x, x, 5)
-    >>> a + series.as_expr()
-    a + x**4/24 + x**3/6 + x**2/2 + x + 1
-
-rs_series
-=========
-
-Direct use of elementary ring series functions does give more control, but is
-limiting at the same time. Creating an appropriate ring for the desired series
-expansion and knowing which ring series function to call, are things not
-everyone might be familiar with.
-
-`rs\_series` is a function that takes an arbitrary ``Expr`` and returns its
-expansion by calling the appropriate ring series functions. The returned series
-is a polynomial over the simplest (almost) possible ring that does the job. It
-recursively builds the ring as it parses the given expression, adding
-generators to the ring when it needs them. Some examples::
-
-    >>> rs_series(sin(a + b), a, 5) # doctest: +SKIP
-    1/24*sin(b)*a**4 - 1/2*sin(b)*a**2 + sin(b) - 1/6*cos(b)*a**3 + cos(b)*a
-
-    >>> rs_series(sin(exp(a*b) + cos(a + c)), a, 2) # doctest: +SKIP
-    -sin(c)*cos(cos(c) + 1)*a + cos(cos(c) + 1)*a*b + sin(cos(c) + 1)
-
-    >>> rs_series(sin(a + b)*cos(a + c)*tan(a**2 + b), a, 2) # doctest: +SKIP
-    cos(b)*cos(c)*tan(b)*a - sin(b)*sin(c)*tan(b)*a + sin(b)*cos(c)*tan(b)
-
-It can expand complicated multivariate expressions involving multiple functions
-and most importantly, it does so blazingly fast::
-
-    >>> %timeit ((sin(a) + cos(a))**10).series(a, 0, 5) # doctest: +SKIP
-    1 loops, best of 3: 1.33 s per loop
-
-    >>> %timeit rs_series((sin(a) + cos(a))**10, a, 5) # doctest: +SKIP
-    100 loops, best of 3: 4.13 ms per loop
-
-`rs\_series` is over 300 times faster. Given an expression to expand, there is
-some fixed overhead to parse it. Thus, for larger orders, the speed
-improvement becomes more prominent::
-
-    >>> %timeit rs_series((sin(a) + cos(a))**10, a, 100) # doctest: +SKIP
-    10 loops, best of 3: 32.8 ms per loop
-
-To figure out the right ring for a given expression, `rs\_series` uses the
-``sring`` function, which in turn uses other functions of ``polys``. As
-explained above, non-natural exponents are not allowed. But the restriction is
-on exponents and not generators. So, ``polys`` allows all sorts of symbolic
-terms as generators to make sure that the exponent is a natural number::
-
-    >>> from sympy.polys.rings import sring
-    >>> R, expr = sring(1/a**3 + a**QQ(3, 7)); R
-    Polynomial ring in 1/a, a**(1/7) over ZZ with lex order
-
-In the above example, `1/a` and `a**(1/7)` will be treated as completely
-different atoms. For all practical purposes, we could let `b = 1/a` and `c =
-a**(1/7)` and do the manipulations. Effectively, expressions involving `1/a`
-and `a**(1/7)` (and their powers) will never simplify::
-
-    >>> expr*R(1/a) # doctest: +SKIP
-    (1/a)**2 + (1/a)*(a**(1/7))**3
-
-This leads to similar issues with manipulating Laurent and Puiseux series as
-faced earlier. Fortunately, this time we have an elegant solution and are able
-to isolate the ``series`` and ``polys`` behaviour from one another. We
-introduce a boolean flag ``series`` in the list of allowed ``Options`` for
-polynomials (see :class:`sympy.polys.polyoptions.Options`). Thus, when we want
-``sring`` to allow rational exponents we supply a ``series=True`` flag to
-``sring``.
-
-Contribute
-==========
-
-`rs\_series` is not fully implemented yet. As of now, it supports only
-multivariate Taylor expansions of expressions involving ``sin``, ``cos``,
-``exp`` and ``tan``. Adding the remaining functions is not at all difficult and
-they will be gradually added. If you are interested in helping, read the
-comments in ``ring_series.py``. Currently, it does not support Puiseux series
-(though the elementary functions do). This is expected to be fixed soon.
-
-You can also add more functions to ``ring_series.py``. Only elementary
-functions are supported currently. The long term goal is to replace SymPy's
-current ``series`` method with ``rs_series``.
-
-Manipulation of power series
-****************************************************************************
-.. currentmodule:: sympy.polys.ring_series
-
-Functions in this module carry the prefix ``rs_``, standing for "ring series".
-They manipulate finite power series in the sparse representation provided
-by ``polys.ring.ring``.
-
-**Elementary functions**
-
-.. autofunction:: rs_log
-.. autofunction:: rs_LambertW
-.. autofunction:: rs_exp
-.. autofunction:: rs_atan
-.. autofunction:: rs_asin
-.. autofunction:: rs_tan
-.. autofunction:: rs_cot
-.. autofunction:: rs_sin
-.. autofunction:: rs_cos
-.. autofunction:: rs_cos_sin
-.. autofunction:: rs_atanh
-.. autofunction:: rs_sinh
-.. autofunction:: rs_cosh
-.. autofunction:: rs_tanh
-.. autofunction:: rs_hadamard_exp
-
-**Operations**
-
-.. autofunction:: rs_mul
-.. autofunction:: rs_square
-.. autofunction:: rs_pow
-.. autofunction:: rs_series_inversion
-.. autofunction:: rs_series_reversion
-.. autofunction:: rs_nth_root
-.. autofunction:: rs_trunc
-.. autofunction:: rs_subs
-.. autofunction:: rs_diff
-.. autofunction:: rs_integrate
-.. autofunction:: rs_newton
-.. autofunction:: rs_compose_add
-
-**Utility functions**
-
-.. autofunction:: rs_is_puiseux
-.. autofunction:: rs_puiseux
-.. autofunction:: rs_puiseux2
-.. autofunction:: rs_series_from_list
-.. autofunction:: rs_fun
-.. autofunction:: mul_xin
-.. autofunction:: pow_xin
diff --git a/sympy/calculus/singularities.py b/sympy/calculus/singularities.py
index 5ae0d11aee..b1ac1031dc 100644
--- a/sympy/calculus/singularities.py
+++ b/sympy/calculus/singularities.py
@@ -1,3 +1,4 @@
+from sympy.core.sympify import sympify
 from sympy.solvers.solveset import solveset
 from sympy.simplify import simplify
 from sympy import S
@@ -38,7 +39,7 @@ def singularities(expr, sym):
 ###########################################################################
 
 
-def is_increasing(f, interval=S.Reals):
+def is_increasing(f, interval=S.Reals, symbol=None):
     """
     Returns if a function is increasing or not, in the given
     ``Interval``.
@@ -47,7 +48,7 @@ def is_increasing(f, interval=S.Reals):
     ========
 
     >>> from sympy import is_increasing
-    >>> from sympy.abc import x
+    >>> from sympy.abc import x, y
     >>> from sympy import S, Interval, oo
     >>> is_increasing(x**3 - 3*x**2 + 4*x, S.Reals)
     True
@@ -57,18 +58,27 @@ def is_increasing(f, interval=S.Reals):
     False
     >>> is_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval(-2, 3))
     False
+    >>> is_increasing(x**2 + y, Interval(1, 2), x)
+    True
 
     """
-    if len(f.free_symbols) > 1:
-        raise NotImplementedError('is_increasing has not yet been implemented '
-                                  'for multivariate expressions')
-    symbol = f.free_symbols.pop()
+    f = sympify(f)
+    free_sym = f.free_symbols
+
+    if symbol is None:
+        if len(free_sym) > 1:
+            raise NotImplementedError('is_increasing has not yet been implemented '
+                                        'for all multivariate expressions')
+        if len(free_sym) == 0:
+            return True
+        symbol = free_sym.pop()
+
     df = f.diff(symbol)
     df_nonneg_interval = solveset(df >= 0, symbol, domain=S.Reals)
     return interval.is_subset(df_nonneg_interval)
 
 
-def is_strictly_increasing(f, interval=S.Reals):
+def is_strictly_increasing(f, interval=S.Reals, symbol=None):
     """
     Returns if a function is strictly increasing or not, in the given
     ``Interval``.
@@ -77,7 +87,7 @@ def is_strictly_increasing(f, interval=S.Reals):
     ========
 
     >>> from sympy import is_strictly_increasing
-    >>> from sympy.abc import x
+    >>> from sympy.abc import x, y
     >>> from sympy import Interval, oo
     >>> is_strictly_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval.Ropen(-oo, -2))
     True
@@ -87,18 +97,27 @@ def is_strictly_increasing(f, interval=S.Reals):
     False
     >>> is_strictly_increasing(-x**2, Interval(0, oo))
     False
+    >>> is_strictly_increasing(-x**2 + y, Interval(-oo, 0), x)
+    False
 
     """
-    if len(f.free_symbols) > 1:
-        raise NotImplementedError('is_strictly_increasing has not yet been '
-                                  'implemented for multivariate expressions')
-    symbol = f.free_symbols.pop()
+    f = sympify(f)
+    free_sym = f.free_symbols
+
+    if symbol is None:
+        if len(free_sym) > 1:
+            raise NotImplementedError('is_strictly_increasing has not yet been implemented '
+                                        'for all multivariate expressions')
+        elif len(free_sym) == 0:
+            return False
+        symbol = free_sym.pop()
+
     df = f.diff(symbol)
     df_pos_interval = solveset(df > 0, symbol, domain=S.Reals)
     return interval.is_subset(df_pos_interval)
 
 
-def is_decreasing(f, interval=S.Reals):
+def is_decreasing(f, interval=S.Reals, symbol=None):
     """
     Returns if a function is decreasing or not, in the given
     ``Interval``.
@@ -107,7 +126,7 @@ def is_decreasing(f, interval=S.Reals):
     ========
 
     >>> from sympy import is_decreasing
-    >>> from sympy.abc import x
+    >>> from sympy.abc import x, y
     >>> from sympy import S, Interval, oo
     >>> is_decreasing(1/(x**2 - 3*x), Interval.open(1.5, 3))
     True
@@ -117,48 +136,66 @@ def is_decreasing(f, interval=S.Reals):
     False
     >>> is_decreasing(-x**2, Interval(-oo, 0))
     False
+    >>> is_decreasing(-x**2 + y, Interval(-oo, 0), x)
+    False
 
     """
-    if len(f.free_symbols) > 1:
-        raise NotImplementedError('is_decreasing has not yet been implemented '
-                                  'for multivariate expressions')
-    symbol = f.free_symbols.pop()
+    f = sympify(f)
+    free_sym = f.free_symbols
+
+    if symbol is None:
+        if len(free_sym) > 1:
+            raise NotImplementedError('is_decreasing has not yet been implemented '
+                                        'for all multivariate expressions')
+        elif len(free_sym) == 0:
+            return True
+        symbol = free_sym.pop()
+
     df = f.diff(symbol)
     df_nonpos_interval = solveset(df <= 0, symbol, domain=S.Reals)
     return interval.is_subset(df_nonpos_interval)
 
 
-def is_strictly_decreasing(f, interval=S.Reals):
+def is_strictly_decreasing(f, interval=S.Reals, symbol=None):
     """
-    Returns if a function is decreasing or not, in the given
+    Returns if a function is strictly decreasing or not, in the given
     ``Interval``.
 
     Examples
     ========
 
-    >>> from sympy import is_decreasing
-    >>> from sympy.abc import x
+    >>> from sympy import is_strictly_decreasing
+    >>> from sympy.abc import x, y
     >>> from sympy import S, Interval, oo
-    >>> is_decreasing(1/(x**2 - 3*x), Interval.open(1.5, 3))
+    >>> is_strictly_decreasing(1/(x**2 - 3*x), Interval.open(1.5, 3))
     True
-    >>> is_decreasing(1/(x**2 - 3*x), Interval.Lopen(3, oo))
+    >>> is_strictly_decreasing(1/(x**2 - 3*x), Interval.Lopen(3, oo))
     True
-    >>> is_decreasing(1/(x**2 - 3*x), Interval.Ropen(-oo, S(3)/2))
+    >>> is_strictly_decreasing(1/(x**2 - 3*x), Interval.Ropen(-oo, S(3)/2))
     False
-    >>> is_decreasing(-x**2, Interval(-oo, 0))
+    >>> is_strictly_decreasing(-x**2, Interval(-oo, 0))
+    False
+    >>> is_strictly_decreasing(-x**2 + y, Interval(-oo, 0), x)
     False
 
     """
-    if len(f.free_symbols) > 1:
-        raise NotImplementedError('is_strictly_decreasing has not yet been '
-                                  'implemented for multivariate expressions')
-    symbol = f.free_symbols.pop()
+    f = sympify(f)
+    free_sym = f.free_symbols
+
+    if symbol is None:
+        if len(free_sym) > 1:
+            raise NotImplementedError('is_strictly_decreasing has not yet been implemented '
+                                        'for all multivariate expressions')
+        elif len(free_sym) == 0:
+            return False
+        symbol = free_sym.pop()
+
     df = f.diff(symbol)
     df_neg_interval = solveset(df < 0, symbol, domain=S.Reals)
     return interval.is_subset(df_neg_interval)
 
 
-def is_monotonic(f, interval=S.Reals):
+def is_monotonic(f, interval=S.Reals, symbol=None):
     """
     Returns if a function is monotonic or not, in the given
     ``Interval``.
@@ -167,7 +204,7 @@ def is_monotonic(f, interval=S.Reals):
     ========
 
     >>> from sympy import is_monotonic
-    >>> from sympy.abc import x
+    >>> from sympy.abc import x, y
     >>> from sympy import S, Interval, oo
     >>> is_monotonic(1/(x**2 - 3*x), Interval.open(1.5, 3))
     True
@@ -177,13 +214,19 @@ def is_monotonic(f, interval=S.Reals):
     True
     >>> is_monotonic(-x**2, S.Reals)
     False
+    >>> is_monotonic(x**2 + y + 1, Interval(1, 2), x)
+    True
 
     """
     from sympy.core.logic import fuzzy_or
-    if len(f.free_symbols) > 1:
+    f = sympify(f)
+    free_sym = f.free_symbols
+
+    if symbol is None and len(free_sym) > 1:
         raise NotImplementedError('is_monotonic has not yet been '
-                                  'implemented for multivariate expressions')
-    inc = is_increasing(f, interval)
-    dec = is_decreasing(f, interval)
+                                'for all multivariate expressions')
+
+    inc = is_increasing(f, interval, symbol)
+    dec = is_decreasing(f, interval, symbol)
 
     return fuzzy_or([inc, dec])
diff --git a/sympy/polys/ring_series.py b/sympy/polys/ring_series.py
index 0de3d8f6b8..166a936325 100644
--- a/sympy/polys/ring_series.py
+++ b/sympy/polys/ring_series.py
@@ -1,46 +1,3 @@
-"""Power series evaluation and manipulation using sparse Polynomials
-
-Implementing a new function
----------------------------
-
-There are a few things to be kept in mind when adding a new function here::
-
-    - The implementation should work on all possible input domains/rings.
-      Special cases include the ``EX`` ring and a constant term in the series
-      to be expanded. There can be two types of constant terms in the series:
-
-        + A constant value or symbol.
-        + A term of a multivariate series not involving the generator, with
-          respect to which the series is to expanded.
-
-      Strictly speaking, a generator of a ring should not be considered a
-      constant. However, for series expansion both the cases need similar
-      treatment (as the user doesn't care about inner details), i.e, use an
-      addition formula to separate the constant part and the variable part (see
-      rs_sin for reference).
-
-    - All the algorithms used here are primarily designed to work for Taylor
-      series (number of iterations in the algo equals the required order).
-      Hence, it becomes tricky to get the series of the right order if a
-      Puiseux series is input. Use rs_puiseux? in your function if your
-      algorithm is not designed to handle fractional powers.
-
-Extending rs_series
--------------------
-
-To make a function work with rs_series you need to do two things::
-
-    - Many sure it works with a constant term (as explained above).
-    - If the series contains constant terms, you might need to extend its ring.
-      You do so by adding the new terms to the rings as generators.
-      ``PolyRing.compose`` and ``PolyRing.add_gens`` are two functions that do
-      so and need to be called every time you expand a series containing a
-      constant term.
-
-Look at rs_sin and rs_series for further reference.
-
-"""
-
 from sympy.polys.domains import QQ, EX
 from sympy.polys.rings import PolyElement, ring, sring
 from sympy.polys.polyerrors import DomainError
@@ -57,7 +14,7 @@
 
 def _invert_monoms(p1):
     """
-    Compute ``x**n * p1(1/x)`` for a univariate polynomial ``p1`` in ``x``.
+    Compute ``x**n * p1(1/x)`` for a univariate polynomial ``p1`` in x.
 
     Examples
     ========
@@ -122,9 +79,8 @@ def rs_trunc(p1, x, prec):
 
 def rs_is_puiseux(p, x):
     """
-    Test if ``p`` is Puiseux series in ``x``.
-
-    Raise an exception if it has a negative power in ``x``.
+    Test if `p` is Puiseux series in `x`; raise an exception if it has
+    negative powers in `x`.
 
     Examples
     ========
@@ -147,9 +103,9 @@ def rs_is_puiseux(p, x):
 
 def rs_puiseux(f, p, x, prec):
     """
-    Return the puiseux series for `f(p, x, prec)`.
+    Return the puiseux series for `f(p, x, prec)`
 
-    To be used when function ``f`` is implemented only for regular series.
+    To be used when function`f` is implemented only for regular series
 
     Examples
     ========
@@ -186,9 +142,9 @@ def rs_puiseux(f, p, x, prec):
 
 def rs_puiseux2(f, p, q, x, prec):
     """
-    Return the puiseux series for `f(p, q, x, prec)`.
+    Return the puiseux series for `f(p, q, x, prec)`
 
-    To be used when function ``f`` is implemented only for regular series.
+    To be used when function `f` is implemented only for regular series
     """
     index = p.ring.gens.index(x)
     n = 1
@@ -211,7 +167,7 @@ def rs_puiseux2(f, p, q, x, prec):
 
 def rs_mul(p1, p2, x, prec):
     """
-    Return the product of the given two series, modulo ``O(x**prec)``.
+    Return the product of the given two series, modulo ``O(x**prec)``
 
     ``x`` is the series variable or its position in the generators.
 
@@ -357,9 +313,13 @@ def rs_pow(p1, n, x, prec):
 
 def rs_subs(p, rules, x, prec):
     """
-    Substitution with truncation according to the mapping in ``rules``.
+    Substitution with truncation according to the mapping in `rules`.
+    Returns a series with precision `prec` in the generator `x`
 
-    Return a series with precision ``prec`` in the generator ``x``
+      p:     input polynomial
+      rules: dict with substitution mappings
+      x:     variable in which the series truncation is done
+      prec:  order of the truncation
 
     Note that substitutions are not done one after the other
 
@@ -378,13 +338,6 @@ def rs_subs(p, rules, x, prec):
     >>> rs_subs(rs_subs(p, {x: x+ y}, x, 3), {y: x+ 2*y}, x, 3)
     5*x**2 + 12*x*y + 8*y**2
 
-    Parameters
-    ----------
-    p : :class:`PolyElement` Input series.
-    rules : :class:`dict` with substitution mappings.
-    x : :class:`PolyElement` in which the series truncation is to be done.
-    prec : :class:`Integer` order of the series after truncation.
-
     Examples
     ========
 
@@ -479,7 +432,7 @@ def _check_series_var(p, x, name):
 
 def _series_inversion1(p, x, prec):
     """
-    Univariate series inversion ``1/p`` modulo ``O(x**prec)``.
+    Univariate series inversion ``1/p`` modulo ``O(x**prec)``
 
     The Newton method is used.
 
@@ -525,7 +478,7 @@ def _series_inversion1(p, x, prec):
 
 def rs_series_inversion(p, x, prec):
     """
-    Multivariate series inversion ``1/p`` modulo ``O(x**prec)``.
+    Multivariate series inversion ``1/p`` modulo ``O(x**prec)``
 
     Examples
     ========
@@ -562,7 +515,7 @@ def rs_series_inversion(p, x, prec):
     return r
 
 def _coefficient_t(p, t):
-    """Coefficient of `x\_i**j` in p, where ``t`` = (i, j)"""
+    """Coefficient of `x_i**j` in p, where t = (i, j)"""
     i, j = t
     R = p.ring
     expv1 = [0]*R.ngens
@@ -576,35 +529,35 @@ def _coefficient_t(p, t):
 
 def rs_series_reversion(p, x, n, y):
     """
-    Reversion of a series.
+    Reversion of a series
 
-    ``p`` is a series with ``O(x**n)`` of the form `p = a*x + f(x)`
-    where `a` is a number different from 0.
+    p is a series with O(x**n) of the form p = a*x + f(x)
+    where `a` is a number different from 0
 
-    `f(x) = sum( a\_k*x\_k, k in range(2, n))`
+    f(x) = sum( a_k*x_k, k in range(2, n))
 
-      a_k : Can depend polynomially on other variables, not indicated.
-      x : Variable with name x.
-      y : Variable with name y.
+      a_k can depend polynomially on other variables, not indicated.
+      x: variable with name x
+      y: variable with name y
 
-    Solve `p = y`, that is, given `a*x + f(x) - y = 0`,
+    Solve p = y, that is, given a*x + f(x) - y = 0,
     find the solution x = r(y) up to O(y**n)
 
     Algorithm:
 
-    If `r\_i` is the solution at order i, then:
-    `a*r\_i + f(r\_i) - y = O(y**(i + 1))`
+    If r_i is the solution at order i, then:
+    a*r_i + f(r_i) - y = O(y**(i + 1))
 
     and if r_(i + 1) is the solution at order i + 1, then:
-    `a*r\_(i + 1) + f(r\_(i + 1)) - y = O(y**(i + 2))`
+    a*r_(i + 1) + f(r_(i + 1)) - y = O(y**(i + 2))
 
     We have, r_(i + 1) = r_i + e, such that,
-    `a*e + f(r\_i) = O(y**(i + 2))`
-    or `e = -f(r\_i)/a`
+    a*e + f(r_i) = O(y**(i + 2))
+    or e = -f(r_i)/a
 
     So we use the recursion relation:
-    `r\_(i + 1) = r\_i - f(r\_i)/a`
-    with the boundary condition: `r\_1 = y`
+    r_(i + 1) = r_i -f(r_i)/a
+    with the boundary condition: r_1 = y
 
     Examples
     ========
@@ -641,13 +594,12 @@ def rs_series_reversion(p, x, n, y):
 
 def rs_series_from_list(p, c, x, prec, concur=1):
     """
-    Return a series `sum c[n]*p**n` modulo `O(x**prec)`.
-
-    It reduces the number of multiplications by summing concurrently.
+    Return a series ``sum c[n]*p**n`` modulo ``O(x**prec)``
 
-    `ax = [1, p, p**2, .., p**(J - 1)]`
-    `s = sum(c[i]*ax[i]` for i in `range(r, (r + 1)*J))*p**((K - 1)*J)`
-    with `K >= (n + 1)/J`
+    It reduces the number of multiplications by summing concurrently
+    ``ax = [1, p, p**2, .., p**(J - 1)]``
+    ``s = sum(c[i]*ax[i] for i in range(r, (r + 1)*J)) * p**((K - 1)*J)``
+    with ``K >= (n + 1)/J``
 
     Examples
     ========
@@ -727,11 +679,9 @@ def rs_series_from_list(p, c, x, prec, concur=1):
 
 def rs_diff(p, x):
     """
-    Return partial derivative of ``p`` with respect to ``x``.
+    Computes partial derivative of p with respect to x
 
-    Parameters
-    ----------
-    x : :class:`PolyElement` with respect to which ``p`` is differentiated.
+      `x`: variable with respect to which p is differentiated,
 
     Examples
     ========
@@ -758,11 +708,7 @@ def rs_diff(p, x):
 
 def rs_integrate(p, x):
     """
-    Integrate ``p`` with respect to ``x``.
-
-    Parameters
-    ----------
-    x : :class:`PolyElement` with respect to which ``p`` is integrated.
+    Integrate ``p`` with respect to ``x``
 
     Examples
     ========
@@ -789,23 +735,21 @@ def rs_integrate(p, x):
 
 def rs_fun(p, f, *args):
     """
-    Function of a multivariate series computed by substitution.
-
-    The case with f method name is used to compute `rs\_tan` and `rs\_nth\_root`
-    of a multivariate series:
+    Function of a multivariate series computed by substitution
 
-        `rs\_fun(p, tan, iv, prec)`
+      p: multivariate series
+      f: method name or function
+      args[:-2] arguments of f, apart from the first one
+      args[-2] = iv: names of the series variables
+      args[-1] = prec: list of the precisions of the series variables
 
-        tan series is first computed for a dummy variable _x,
-        i.e, `rs\_tan(\_x, iv, prec)`. Then we substitute _x with p to get the
-        desired series
+    The case with f method name is used to compute rs_tan and rs_nth_root
+    of a multivariate series:
 
-    Parameters
-    ----------
-    p : :class:`PolyElement` The multivariate series to be expanded.
-    f : `ring\_series` function to be applied on `p`.
-    args[-2] : :class:`PolyElement` with respect to which, the series is to be expanded.
-    args[-1] : Required order of the expanded series.
+      rs_fun(p, tan, iv, prec)
+      tan series is first computed for a dummy variable _x,
+      ie, rs_tan(_x, iv, prec). Then we substitute _x with p to get the
+      desired series
 
     Examples
     ========
@@ -844,9 +788,9 @@ def rs_fun(p, f, *args):
 
 def mul_xin(p, i, n):
     """
-    Return `p*x_i**n`.
+    Computes p*x_i**n
 
-    `x\_i` is the ith variable in ``p``.
+    x_i is the ith variable in p
     """
     R = p.ring
     q = R(0)
@@ -877,7 +821,13 @@ def pow_xin(p, i, n):
 
 def _nth_root1(p, n, x, prec):
     """
-    Univariate series expansion of the nth root of ``p``.
+    Univariate series expansion of the nth root of p
+
+    While passing p, make sure that it is of the form `1 + f(x)`.
+
+      n (integer): compute p**(1/n)
+      x: name of the series variable
+      prec: precision of the series
 
     The Newton method is used.
     """
@@ -912,13 +862,11 @@ def _nth_root1(p, n, x, prec):
 
 def rs_nth_root(p, n, x, prec):
     """
-    Multivariate series expansion of the nth root of ``p``.
+    Multivariate series expansion of the nth root of p
 
-    Parameters
-    ----------
-    n : `p**(1/n)` is returned.
-    x : :class:`PolyElement`
-    prec : Order of the expanded series.
+      n(integer): compute p**(1/n)
+      x: variable name
+      prec: precision of the series
 
     Notes
     =====
@@ -968,14 +916,14 @@ def rs_nth_root(p, n, x, prec):
                 c_expr = c.as_expr()
                 const = R(c_expr**(QQ(1, n)))
             except ValueError:
-                raise DomainError("The given series can't be expanded in "
-                    "this domain.")
+                    raise DomainError("The given series can't be expanded in "
+                                      "this domain.")
         else:
             try:                              # RealElement doesn't support
                 const = R(c**Rational(1, n))  # exponentiation with mpq object
             except ValueError:                # as exponent
-                raise DomainError("The given series can't be expanded in "
-                    "this domain.")
+                    raise DomainError("The given series can't be expanded in "
+                                      "this domain.")
         res = rs_nth_root(p/c, n, x, prec)*const
     else:
         res = _nth_root1(p, n, x, prec)
@@ -986,12 +934,12 @@ def rs_nth_root(p, n, x, prec):
 
 def rs_log(p, x, prec):
     """
-    The Logarithm of ``p`` modulo ``O(x**prec)``.
+    The Logarithm of ``p`` modulo ``O(x**prec)``
 
     Notes
     =====
 
-    Truncation of ``integral dx p**-1*d p/dx`` is used.
+    truncation of ``integral dx p**-1*d p/dx`` is used.
 
     Examples
     ========
@@ -1025,13 +973,13 @@ def rs_log(p, x, prec):
                     const = R(log(c_expr))
                 except ValueError:
                     raise DomainError("The given series can't be expanded in "
-                        "this domain.")
+                                      "this domain.")
             else:
                 try:
                     const = R(log(c))
                 except ValueError:
                     raise DomainError("The given series can't be expanded in "
-                        "this domain.")
+                                      "this domain.")
 
         dlog = p.diff(x)
         dlog = rs_mul(dlog, _series_inversion1(p, x, prec), x, prec - 1)
@@ -1041,7 +989,7 @@ def rs_log(p, x, prec):
 
 def rs_LambertW(p, x, prec):
     """
-    Calculate the series expansion of the principal branch of the Lambert W
+    Calculates the series expansion of the principal branch of the Lambert W
     function.
 
     Examples
@@ -1079,7 +1027,7 @@ def rs_LambertW(p, x, prec):
         raise NotImplementedError
 
 def _exp1(p, x, prec):
-    """Helper function for `rs\_exp`. """
+    """Helper function for ``rs_exp`` """
     R = p.ring
     p1 = R(1)
     for precx in _giant_steps(prec):
@@ -1124,8 +1072,8 @@ def rs_exp(p, x, prec):
             try:
                 const = R(exp(c))
             except ValueError:
-                raise DomainError("The given series can't be expanded in "
-                    "this domain.")
+                    raise DomainError("The given series can't be expanded in "
+                                      "this domain.")
         p1 = p - c
 
     # Makes use of sympy fuctions to evaluate the values of the cos/sin
@@ -1148,7 +1096,7 @@ def rs_exp(p, x, prec):
 
 def _atan(p, iv, prec):
     """
-    Expansion using formula.
+    Expansion using formula
 
     Faster on very small and univariate series.
     """
@@ -1166,7 +1114,7 @@ def rs_atan(p, x, prec):
     """
     The arctangent of a series
 
-    Return the series expansion of the atan of ``p``, about 0.
+    Returns the series expansion of the atan of p, about 0.
 
     Examples
     ========
@@ -1198,14 +1146,14 @@ def rs_atan(p, x, prec):
                 c_expr = c.as_expr()
                 const = R(atan(c_expr))
             except ValueError:
-                raise DomainError("The given series can't be expanded in "
-                    "this domain.")
+                    raise DomainError("The given series can't be expanded in "
+                                      "this domain.")
         else:
             try:
                 const = R(atan(c))
             except ValueError:
-                raise DomainError("The given series can't be expanded in "
-                    "this domain.")
+                    raise DomainError("The given series can't be expanded in "
+                                      "this domain.")
 
     # Instead of using a closed form formula, we differentiate atan(p) to get
     # `1/(1+p**2) * dp`, whose series expansion is much easier to calculate.
@@ -1220,7 +1168,7 @@ def rs_asin(p, x, prec):
     """
     Arcsine of a series
 
-    Return the series expansion of the asin of ``p``, about 0.
+    Returns the series expansion of the asin of p, about 0.
 
     Examples
     ========
@@ -1263,9 +1211,9 @@ def rs_asin(p, x, prec):
 
 def _tan1(p, x, prec):
     """
-    Helper function of `rs\_tan`.
+    Helper function of ``rs_tan``
 
-    Return the series expansion of tan of a univariate series using Newton's
+    Returns the series expansion of tan of a univariate series using Newton's
     method. It takes advantage of the fact that series expansion of atan is
     easier than that of tan.
 
@@ -1284,9 +1232,9 @@ def _tan1(p, x, prec):
 
 def rs_tan(p, x, prec):
     """
-    Tangent of a series.
+    Tangent of a series
 
-    Return the series expansion of the tan of ``p``, about 0.
+    Returns the series expansion of the tan of p, about 0.
 
     Examples
     ========
@@ -1301,7 +1249,7 @@ def rs_tan(p, x, prec):
    See Also
    ========
 
-   _tan1, tan
+   tan
    """
     if rs_is_puiseux(p, x):
         r = rs_puiseux(rs_tan, p, x, prec)
@@ -1327,8 +1275,8 @@ def rs_tan(p, x, prec):
             try:
                 const = R(tan(c))
             except ValueError:
-                raise DomainError("The given series can't be expanded in "
-                    "this domain.")
+                    raise DomainError("The given series can't be expanded in "
+                                      "this domain.")
         p1 = p - c
 
     # Makes use of sympy fuctions to evaluate the values of the cos/sin
@@ -1346,7 +1294,7 @@ def rs_cot(p, x, prec):
     """
     Cotangent of a series
 
-    Return the series expansion of the cot of ``p``, about 0.
+    Returns the series expansion of the cot of p, about 0.
 
     Examples
     ========
@@ -1382,7 +1330,7 @@ def rs_sin(p, x, prec):
     """
     Sine of a series
 
-    Return the series expansion of the sin of ``p``, about 0.
+    Returns the series expansion of the sin of p, about 0.
 
     Examples
     ========
@@ -1425,8 +1373,8 @@ def rs_sin(p, x, prec):
             try:
                 t1, t2 = R(sin(c)), R(cos(c))
             except ValueError:
-                raise DomainError("The given series can't be expanded in "
-                    "this domain.")
+                    raise DomainError("The given series can't be expanded in "
+                                      "this domain.")
         p1 = p - c
 
     # Makes use of sympy cos, sin fuctions to evaluate the values of the
@@ -1452,7 +1400,7 @@ def rs_cos(p, x, prec):
     """
     Cosine of a series
 
-    Return the series expansion of the cos of ``p``, about 0.
+    Returns the series expansion of the cos of p, about 0.
 
     Examples
     ========
@@ -1492,8 +1440,8 @@ def rs_cos(p, x, prec):
             try:
                 t1, t2 = R(sin(c)), R(cos(c))
             except ValueError:
-                raise DomainError("The given series can't be expanded in "
-                    "this domain.")
+                    raise DomainError("The given series can't be expanded in "
+                                      "this domain.")
         p1 = p - c
 
     # Makes use of sympy cos, sin fuctions to evaluate the values of the
@@ -1523,8 +1471,7 @@ def rs_cos(p, x, prec):
 
 def rs_cos_sin(p, x, prec):
     """
-    Return the tuple `(rs\_cos(p, x, prec)`, `rs\_sin(p, x, prec))`.
-
+    Returns the tuple (rs_cos(p, x, prec), rs_sin(p, x, prec))
     Is faster than calling rs_cos and rs_sin separately
     """
     if rs_is_puiseux(p, x):
@@ -1554,7 +1501,7 @@ def rs_atanh(p, x, prec):
     """
     Hyperbolic arctangent of a series
 
-    Return the series expansion of the atanh of ``p``, about 0.
+    Returns the series expansion of the atanh of p, about 0.
 
     Examples
     ========
@@ -1586,14 +1533,14 @@ def rs_atanh(p, x, prec):
                 c_expr = c.as_expr()
                 const = R(atanh(c_expr))
             except ValueError:
-                raise DomainError("The given series can't be expanded in "
-                    "this domain.")
+                    raise DomainError("The given series can't be expanded in "
+                                      "this domain.")
         else:
             try:
                 const = R(atanh(c))
             except ValueError:
-                raise DomainError("The given series can't be expanded in "
-                    "this domain.")
+                    raise DomainError("The given series can't be expanded in "
+                                      "this domain.")
 
     # Instead of using a closed form formula, we differentiate atanh(p) to get
     # `1/(1-p**2) * dp`, whose series expansion is much easier to calculate.
@@ -1608,7 +1555,7 @@ def rs_sinh(p, x, prec):
     """
     Hyperbolic sine of a series
 
-    Return the series expansion of the sinh of ``p``, about 0.
+    Returns the series expansion of the sinh of p, about 0.
 
     Examples
     ========
@@ -1635,7 +1582,7 @@ def rs_cosh(p, x, prec):
     """
     Hyperbolic cosine of a series
 
-    Return the series expansion of the cosh of ``p``, about 0.
+    Returns the series expansion of the cosh of p, about 0.
 
     Examples
     ========
@@ -1660,9 +1607,9 @@ def rs_cosh(p, x, prec):
 
 def _tanh(p, x, prec):
     """
-    Helper function of `rs\_tanh`
+    Helper function of ``rs_tanh``
 
-    Return the series expansion of tanh of a univariate series using Newton's
+    Returns the series expansion of tanh of a univariate series using Newton's
     method. It takes advantage of the fact that series expansion of atanh is
     easier than that of tanh.
 
@@ -1683,7 +1630,7 @@ def rs_tanh(p, x, prec):
     """
     Hyperbolic tangent of a series
 
-    Return the series expansion of the tanh of ``p``, about 0.
+    Returns the series expansion of the tanh of p, about 0.
 
     Examples
     ========
@@ -1715,14 +1662,14 @@ def rs_tanh(p, x, prec):
                 c_expr = c.as_expr()
                 const = R(tanh(c_expr))
             except ValueError:
-                raise DomainError("The given series can't be expanded in "
-                    "this domain.")
+                    raise DomainError("The given series can't be expanded in "
+                                      "this domain.")
         else:
             try:
                 const = R(tanh(c))
             except ValueError:
-                raise DomainError("The given series can't be expanded in "
-                    "this domain.")
+                    raise DomainError("The given series can't be expanded in "
+                                      "this domain.")
         p1 = p - c
         t1 = rs_tanh(p1, x, prec)
         t = rs_series_inversion(1 + const*t1, x, prec)
@@ -1875,20 +1822,6 @@ def _rs_series(expr, series_rs, a, prec):
             raise NotImplementedError
         R1, series = sring(arg, domain=QQ, expand=False)
         series_inner = _rs_series(arg, series, a, prec)
-
-        # Why do we need to compose these three rings?
-        #
-        # We want to use a simple domain (like ``QQ`` or ``RR``) but they don't
-        # support symbolic coefficients. We need a ring that for example lets
-        # us have `sin(1)` and `cos(1)` as coefficients if we are expanding
-        # `sin(x + 1)`. The ``EX`` domain allows all symbolic coefficients, but
-        # that makes it very complex and hence slow.
-        #
-        # To solve this problem, we add only those symbolic elements as
-        # generators to our ring, that we need. Here, series_inner might
-        # involve terms like `sin(4)`, `exp(a)`, etc, which are not there in
-        # R1 or R. Hence, we compose these three rings to create one that has
-        # the generators of all three.
         R = R.compose(R1).compose(series_inner.ring)
         series_inner = series_inner.set_ring(R)
         series = eval(_convert_func[str(expr.func)])(series_inner,
@@ -1941,7 +1874,7 @@ def _rs_series(expr, series_rs, a, prec):
         raise NotImplementedError
 
 def rs_series(expr, a, prec):
-    """Return the series expansion of an expression about 0.
+    """Return the series expansion of an expression about 0
 
     Parameters
     ----------
diff --git a/sympy/polys/rings.py b/sympy/polys/rings.py
index cb9df6dfc7..7544bc5d01 100644
--- a/sympy/polys/rings.py
+++ b/sympy/polys/rings.py
@@ -509,7 +509,6 @@ def drop_to_ground(self, *gens):
             return self.clone(symbols=symbols, domain=self.drop(*gens))
 
     def compose(self, other):
-        """Add the generators of ``other`` to ``self``"""
         if self != other:
             syms = set(self.symbols).union(set(other.symbols))
             return self.clone(symbols=list(syms))
@@ -517,7 +516,6 @@ def compose(self, other):
             return self
 
     def add_gens(self, symbols):
-        """Add the elements of ``symbols`` as generators to ``self``"""
         syms = set(self.symbols).union(set(symbols))
         return self.clone(symbols=list(syms))
 


Test patch:
diff --git a/sympy/calculus/tests/test_singularities.py b/sympy/calculus/tests/test_singularities.py
index b4d2056315..65d30d263b 100644
--- a/sympy/calculus/tests/test_singularities.py
+++ b/sympy/calculus/tests/test_singularities.py
@@ -7,8 +7,9 @@
 
 from sympy.utilities.pytest import XFAIL
 
-x = Symbol('x')
-
+from sympy.abc import x, y
+a = Symbol('a', negative=True)
+b = Symbol('b', positive=True)
 
 def test_singularities():
     x = Symbol('x', real=True)
@@ -30,6 +31,9 @@ def test_is_increasing():
     assert is_increasing(-x**2, Interval(-oo, 0))
     assert is_increasing(-x**2, Interval(0, oo)) is False
     assert is_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval(-2, 3)) is False
+    assert is_increasing(x**2 + y, Interval(1, oo), x) is True
+    assert is_increasing(-x**2*a, Interval(1, oo), x) is True
+    assert is_increasing(1) is True
 
 
 def test_is_strictly_increasing():
@@ -37,6 +41,7 @@ def test_is_strictly_increasing():
     assert is_strictly_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval.Lopen(3, oo))
     assert is_strictly_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval.open(-2, 3)) is False
     assert is_strictly_increasing(-x**2, Interval(0, oo)) is False
+    assert is_strictly_decreasing(1) is False
 
 
 def test_is_decreasing():
@@ -44,13 +49,15 @@ def test_is_decreasing():
     assert is_decreasing(1/(x**2 - 3*x), Interval.Lopen(3, oo))
     assert is_decreasing(1/(x**2 - 3*x), Interval.Ropen(-oo, S(3)/2)) is False
     assert is_decreasing(-x**2, Interval(-oo, 0)) is False
+    assert is_decreasing(-x**2*b, Interval(-oo, 0), x) is False
 
 
 def test_is_strictly_decreasing():
-    assert is_decreasing(1/(x**2 - 3*x), Interval.open(1.5, 3))
-    assert is_decreasing(1/(x**2 - 3*x), Interval.Lopen(3, oo))
-    assert is_decreasing(1/(x**2 - 3*x), Interval.Ropen(-oo, S(3)/2)) is False
-    assert is_decreasing(-x**2, Interval(-oo, 0)) is False
+    assert is_strictly_decreasing(1/(x**2 - 3*x), Interval.open(1.5, 3))
+    assert is_strictly_decreasing(1/(x**2 - 3*x), Interval.Lopen(3, oo))
+    assert is_strictly_decreasing(1/(x**2 - 3*x), Interval.Ropen(-oo, S(3)/2)) is False
+    assert is_strictly_decreasing(-x**2, Interval(-oo, 0)) is False
+    assert is_strictly_decreasing(1) is False
 
 
 def test_is_monotonic():
@@ -58,3 +65,4 @@ def test_is_monotonic():
     assert is_monotonic(1/(x**2 - 3*x), Interval.Lopen(3, oo))
     assert is_monotonic(x**3 - 3*x**2 + 4*x, S.Reals)
     assert is_monotonic(-x**2, S.Reals) is False
+    assert is_monotonic(x**2 + y + 1, Interval(1, 2), x) is True