'Return True if self is constant, False if not, or None if
the constancy could not be determined conclusively.
If an expression has no free symbols then it is a constant. If
there are free symbols it is possible that the expression is a
constant, perhaps (but not necessarily) zero. To test such
expressions, two strategies are tried:
1) numerical evaluation at two random points. If two such evaluations
give two different values and the values have a precision greater than
1 then self is not constant. If the evaluations agree or could not be
obtained with any precision, no decision is made. The numerical testing
is done only if ``wrt`` is different than the free symbols.
2) differentiation with respect to variables in \'wrt\' (or all free
symbols if omitted) to see if the expression is constant or not. This
will not always lead to an expression that is zero even though an
expression is constant (see added test in test_expr.py). If
all derivatives are zero then self is constant with respect to the
given symbols.
If neither evaluation nor differentiation can prove the expression is
constant, None is returned unless two numerical values happened to be
the same and the flag ``failing_number`` is True -- in that case the
numerical value will be returned.
If flag simplify=False is passed, self will not be simplified;
the default is True since self should be simplified before testing.
Examples
>>> from sympy import cos, sin, Sum, S, pi
>>> from sympy.abc import a, n, x, y
>>> x.is_constant()
False
>>> S(2).is_constant()
True
>>> Sum(x, (x, 1, 10)).is_constant()
True
>>> Sum(x, (x, 1, n)).is_constant()
False
>>> Sum(x, (x, 1, n)).is_constant(y)
True
>>> Sum(x, (x, 1, n)).is_constant(n)
False
>>> Sum(x, (x, 1, n)).is_constant(x)
True
>>> eq = a*cos(x)**2 + a*sin(x)**2 - a
>>> eq.is_constant()
True
>>> eq.subs({x: pi, a: 2}) == eq.subs({x: pi, a: 3}) == 0
True
>>> (0**x).is_constant()
False
>>> x.is_constant()
False
>>> (x**x).is_constant()
False
>>> one = cos(x)**2 + sin(x)**2
>>> one.is_constant()
True
>>> ((one - 1)**(x + 1)).is_constant() in (True, False) # could be 0 or 1
True'

def is_constant(self, *wrt, **flags):

    simplify = flags.get('simplify', True)
    free = self.free_symbols
    if (self.is_number or (not free)):
        assert (not free)
        return True
    wrt = set(wrt)
    if (wrt and (not (wrt & free))):
        return True
    wrt = (wrt or free)
    expr = self
    if simplify:
        expr = expr.simplify()
    if expr.is_zero:
        return True
    failing_number = None
    if (wrt == free):
        try:
            a = expr.subs(list(zip(free, ([0] * len(free)))), simultaneous=True)
            if (a is S.NaN):
                a = expr._random(None, 0, 0, 0, 0)
        except ZeroDivisionError:
            a = None
        if ((a is not None) and (a is not S.NaN)):
            try:
                b = expr.subs(list(zip(free, ([1] * len(free)))), simultaneous=True)
                if (b is S.NaN):
                    b = expr._random(None, 1, 0, 1, 0)
            except ZeroDivisionError:
                b = None
            if ((b is not None) and (b is not S.NaN) and (b.equals(a) is False)):
                return False
            b = expr._random(None, (-1), 0, 1, 0)
            if ((b is not None) and (b is not S.NaN) and (b.equals(a) is False)):
                return False
            b = expr._random()
            if ((b is not None) and (b is not S.NaN)):
                if (b.equals(a) is False):
                    return False
                failing_number = (a if a.is_number else b)
    for w in wrt:
        deriv = expr.diff(w)
        if simplify:
            deriv = deriv.simplify()
        if (deriv != 0):
            if (not pure_complex(deriv, or_real=True)):
                if flags.get('failing_number', False):
                    return failing_number
                elif deriv.free_symbols:
                    return None
            return False
    return True
