'Checks for the convergence of a Sum.
We divide the study of convergence of infinite sums and products in
two parts.
First Part:
One part is the question whether all the terms are well defined, i.e.,
they are finite in a sum and also non-zero in a product. Zero
is the analogy of (minus) infinity in products as
:math:`e^{-\infty} = 0`.
Second Part:
The second part is the question of convergence after infinities,
and zeros in products, have been omitted assuming that their number
is finite. This means that we only consider the tail of the sum or
product, starting from some point after which all terms are well
defined.
For example, in a sum of the form:
.. math::
\sum_{1 \leq i < \infty} \frac{1}{n^2 + an + b}
where a and b are numbers. The routine will return true, even if there
are infinities in the term sequence (at most two). An analogous
product would be:
.. math::
\prod_{1 \leq i < \infty} e^{\frac{1}{n^2 + an + b}}
This is how convergence is interpreted. It is concerned with what
happens at the limit. Finding the bad terms is another independent
matter.
Note: It is responsibility of user to see that the sum or product
is well defined.
There are various tests employed to check the convergence like
divergence test, root test, integral test, alternating series test,
comparison tests, Dirichlet tests. It returns true if Sum is convergent
and false if divergent and NotImplementedError if it can not be checked.
References
.. [1] https://en.wikipedia.org/wiki/Convergence_tests
Examples
>>> from sympy import factorial, S, Sum, Symbol, oo
>>> n = Symbol(\'n\', integer=True)
>>> Sum(n/(n - 1), (n, 4, 7)).is_convergent()
True
>>> Sum(n/(2*n + 1), (n, 1, oo)).is_convergent()
False
>>> Sum(factorial(n)/5**n, (n, 1, oo)).is_convergent()
False
>>> Sum(1/n**(S(6)/5), (n, 1, oo)).is_convergent()
True
See Also
Sum.is_absolutely_convergent()
Product.is_convergent()'

def is_convergent(self):

    from sympy import Interval, Integral, Limit, log, symbols, Ge, Gt, simplify
    (p, q) = symbols('p    q', cls=Wild)
    sym = self.limits[0][0]
    lower_limit = self.limits[0][1]
    upper_limit = self.limits[0][2]
    sequence_term = self.function
    if (len(sequence_term.free_symbols) > 1):
        raise NotImplementedError('convergence    checking    for    more    than    one    symbol    containing    series    is    not    handled')
    if (lower_limit.is_finite and upper_limit.is_finite):
        return S.true
    if (lower_limit is S.NegativeInfinity):
        if (upper_limit is S.Infinity):
            return (Sum(sequence_term, (sym, 0, S.Infinity)).is_convergent() and Sum(sequence_term, (sym, S.NegativeInfinity, 0)).is_convergent())
        sequence_term = simplify(sequence_term.xreplace({sym: (- sym)}))
        lower_limit = (- upper_limit)
        upper_limit = S.Infinity
    interval = Interval(lower_limit, upper_limit)
    if sequence_term.is_Piecewise:
        for (func, cond) in sequence_term.args:
            if ((cond == True) or (cond.as_set().sup is S.Infinity)):
                s = Sum(func, (sym, lower_limit, upper_limit))
                return s.is_convergent()
        return S.true
    try:
        lim_val = limit(sequence_term, sym, upper_limit)
        if (lim_val.is_number and (lim_val is not S.Zero)):
            return S.false
    except NotImplementedError:
        pass
    try:
        lim_val_abs = limit(abs(sequence_term), sym, upper_limit)
        if (lim_val_abs.is_number and (lim_val_abs is not S.Zero)):
            return S.false
    except NotImplementedError:
        pass
    order = O(sequence_term, (sym, S.Infinity))
    p1_series_test = order.expr.match((sym ** p))
    if (p1_series_test is not None):
        if (p1_series_test[p] < (-1)):
            return S.true
        if (p1_series_test[p] > (-1)):
            return S.false
    p2_series_test = order.expr.match(((1 / sym) ** p))
    if (p2_series_test is not None):
        if (p2_series_test[p] > 1):
            return S.true
        if (p2_series_test[p] < 1):
            return S.false
    lim = Limit((abs(sequence_term) ** (1 / sym)), sym, S.Infinity)
    lim_evaluated = lim.doit()
    if lim_evaluated.is_number:
        if (lim_evaluated < 1):
            return S.true
        if (lim_evaluated > 1):
            return S.false
    dict_val = sequence_term.match((((-1) ** (sym + p)) * q))
    if ((not dict_val[p].has(sym)) and is_decreasing(dict_val[q], interval)):
        return S.true
    log_test = order.expr.match((1 / (log(sym) ** p)))
    if (log_test is not None):
        return S.false
    log_n_test = order.expr.match((1 / (sym * (log(sym) ** p))))
    if (log_n_test is not None):
        if (log_n_test[p] > 1):
            return S.true
        return S.false
    log_log_n_test = order.expr.match((1 / (sym * (log(sym) * (log(log(sym)) ** p)))))
    if (log_log_n_test is not None):
        if (log_log_n_test[p] > 1):
            return S.true
        return S.false
    n_log_test = order.expr.match((1 / ((sym ** p) * log(sym))))
    if (n_log_test is not None):
        if (n_log_test[p] > 1):
            return S.true
        return S.false
    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
    if order.expr.is_Mul:
        (a_n, b_n) = (order.expr.args[0], order.expr.args[1])
        m = Dummy('m', integer=True)
        def _dirichlet_test(g_n):
            try:
                ing_val = limit(Sum(g_n, (sym, interval.inf, m)).doit(), m, S.Infinity)
                if ing_val.is_finite:
                    return S.true
            except NotImplementedError:
                pass
        if is_decreasing(a_n, interval):
            dirich1 = _dirichlet_test(b_n)
            if (dirich1 is not None):
                return dirich1
        if is_decreasing(b_n, interval):
            dirich2 = _dirichlet_test(a_n)
            if (dirich2 is not None):
                return dirich2
    raise NotImplementedError(('The    algorithm    to    find    the    Sum    convergence    of    %s    is    not    yet    implemented' % sequence_term))
