Repository: sympy/sympy
File: sympy/concrete/summations.py (Python)

Code before:
        # Try shifting summation and check if the summand can be made
        # even wrt the origin.
        # Sum(f(n), (n, a, b)) => Sum(f(n + s), (n, a - s, b - s))
        shift = get_shift(denom)

        if shift and shift.is_Integer:

            numer = numer.shift(shift)
            denom = denom.shift(shift)

            if not is_even_function(numer, denom):
                return None

            if alternating:
                f = S.NegativeOne**i * (S.NegativeOne**shift * numer.as_expr() / denom.as_expr())
            else:
                f = numer.as_expr() / denom.as_expr()
            return eval_sum_residue(f, (i, a-shift, b-shift))

        elif a.is_Integer or b.is_Integer:
            return None

    if a is S.NegativeInfinity and b is not S.Infinity:
        a, b = -b, -a

    poles = get_poles(denom)
    if poles is None:
        return None
    int_roots, nonint_roots = poles

    if (a, b) == (S.NegativeInfinity, S.Infinity):
        if int_roots:
            return None

        residue_factor = get_residue_factor(numer, denom, alternating)
        residues = [residue(residue_factor, z, root) for root in nonint_roots]
        return -S.Pi * sum(residues)

    assert a.is_Integer and b is S.Infinity

    if int_roots:
        int_roots = [int(root) for root in int_roots]
        int_roots_max = max(int_roots)
        int_roots_min = min(int_roots)
        # Integer valued poles must be next to each other
        # and also symmetric from origin (because the function is even)
        if not len(int_roots) == int_roots_max - int_roots_min + 1:
            return None

        # Check whether the summation indices contain poles
        if a <= max(int_roots):

Review comment (suggestion):
This function is generally quite difficult to understand because it handles the conditions all over the place. This check for `a.is_Integer or b.is_Integer` is quite cryptic though. You have to study the whole function quite carefully to see what this means and what invariants it implies for the code below.

The previous code would guarantee that below here we have an even function. This check for integer here means that if we don't have an even function then the limits are `oo, -oo` because earlier code verified that `a` and `b` are integers or infinities and also swapped the limits to make them in order.

I think that it would be clearer to have the code here that handles that case like:
```
if (a, b) == (-oo, oo):
   ...
else:
   return None
```
More generally this whole function would be easier to understand if it just handled the cases clearly at the top like:
```
if a == -oo and b == oo:
    ...
elif a.is_Integer and b == oo:
   ...
elif ...
```
I don't suggest to rewrite everything here though.



Code after:
        shift = get_shift(denom)

        if not shift:
            return None

        if shift.is_Integer:
            numer = numer.shift(shift)
            denom = denom.shift(shift)
            if not is_even_function(numer, denom):
                return None

            if alternating:
                f = S.NegativeOne**i * (S.NegativeOne**shift * numer.as_expr() / denom.as_expr())
            else:
                f = numer.as_expr() / denom.as_expr()
            return eval_sum_residue(f, (i, a-shift, b-shift))
        elif not both_inf:
            return None  # can't make a shift that keeps limits integer

    if both_inf:  # even or not
        poles = get_poles(denom)
        if poles is None:
            return None
        int_roots, nonint_roots = poles
        if int_roots:
            return None

        return -S.Pi * sum(residues(numer, denom, alternating, nonint_roots))

    # handle even function with semi-infinite limits

    if a is S.NegativeInfinity:
        # this is ok for an even function and will be necessary
        # so the extraneous roots can be handled properly below
        a, b = -b, -a

    assert a.is_Integer and b is S.Infinity  # even function with limits (k, oo)

    poles = get_poles(denom)
    if poles is None:
        return None
    int_roots, nonint_roots = poles

    if int_roots:
        int_roots_max = max(int_roots)
        int_roots_min = min(int_roots)
        # Integer valued poles must be next to each other
        # and also symmetric from origin (because the function is even)
        if not len(int_roots) == int_roots_max - int_roots_min + 1:
            return None