Repository: sympy/sympy
File: sympy/assumptions/refine.py (Python)

Code before:
    """
    Handler for sin and cos functions.

    Examples
    ========

    >>> from sympy.assumptions.refine import refine_sin_cos
    >>> from sympy import Symbol, Q, sin, cos, pi
    >>> from sympy.abc import x, y
    >>> n = Symbol('n')
    >>> refine_sin_cos(cos(n*pi), Q.even(n))
    (-1)**n
    >>> refine_sin_cos(sin(n*pi/2), Q.odd(n) & Q.odd((n-1)/2))
    (-1)**(n/2 - 1/2)
    >>> refine_sin_cos(sin(x + n*pi/2), Q.odd(n))
    (-1)**(n/2 - 1/2)*cos(x)
    >>> refine_sin_cos(cos(x + n*pi/2), Q.even(n))
    (-1)**(n/2)*cos(x)
    >>> refine_sin_cos(cos(x + y + 2*n*pi), Q.integer(n))
    (-1)**(2*n)*cos(x + y)
    """
    from sympy.functions.elementary.trigonometric import sin, cos
    arg = expr.args[0]

    # The logic is to separate integer multiples of pi/2 to apply trigonometric reduction formulas.
    k_terms = [] # To store the integral multiples of pi/2.
    rem_terms = [] # To store the remaining terms in the expr.

    terms = arg.args if arg.is_Add else (arg,)
    for term in terms:
        # Extract coefficient of pi in each of the terms.
        pi_coeff = term.coeff(S.Pi)
        if pi_coeff:
            # We need integral coefficient of pi/2. `coeff` is the coefficient of pi/2.
            coeff = 2 * pi_coeff
            if ask(Q.integer(coeff), assumptions):
                k_terms.append(coeff)
            else:
                rem_terms.append(term)
        else:
            rem_terms.append(term)

    # Add all integral multiples of pi/2. As `sin(x) = cos(x-pi/2)`, we will solve things for `cos`.
    # This allows us to use the same logic for both by decreasing the `coeff` by 1.
    k = Add(*k_terms)
    if isinstance(expr, sin):
        k -= 1

    # Calculate the value of `rem` only if we can determine the parity of k.
    # We will use trigonometric identities for this. Odd multiples shift to sin while even preserve cos.
    if ask(Q.odd(k), assumptions):

Review comment (suggestion):
I think the name `integer_coeffs_of_pi_half` is a lot better than `k_terms`

Code after:
    """
    Handler for sin and cos functions.

    Examples
    ========

    >>> from sympy.assumptions.refine import refine_sin_cos
    >>> from sympy import Symbol, Q, sin, cos, pi
    >>> from sympy.abc import x, y
    >>> n = Symbol('n')
    >>> refine_sin_cos(cos(n*pi), Q.even(n))
    (-1)**n
    >>> refine_sin_cos(sin(n*pi/2), Q.odd(n) & Q.odd((n-1)/2))
    (-1)**(n/2 - 1/2)
    >>> refine_sin_cos(sin(x + n*pi/2), Q.odd(n))
    (-1)**(n/2 - 1/2)*cos(x)
    >>> refine_sin_cos(cos(x + n*pi/2), Q.even(n))
    (-1)**(n/2)*cos(x)
    >>> refine_sin_cos(cos(x + y + 2*n*pi), Q.integer(n))
    (-1)**(2*n)*cos(x + y)
    """
    from sympy.functions.elementary.trigonometric import sin, cos
    arg = expr.args[0]

    integer_coeffs_of_pi_half = []
    remaining_terms = []

    terms = arg.args if arg.is_Add else (arg,)
    for term in terms:
        coeff_of_pi = term.coeff(S.Pi)
        if coeff_of_pi and ask(Q.integer(2 * coeff_of_pi), assumptions):
            coeff_of_pi_half = 2 * coeff_of_pi
            integer_coeffs_of_pi_half.append(coeff_of_pi_half)
        else:
            remaining_terms.append(term)

    if not integer_coeffs_of_pi_half:
        return expr

    sum_of_parity_known_coeffs = 0
    sum_of_parity_unknown_coeffs = 0
    sum_of_parity_known_coeffs_is_even = True
    for coeff in integer_coeffs_of_pi_half:
        coeff_is_even = ask(Q.even(coeff), assumptions)
        if coeff_is_even is None:
            sum_of_parity_unknown_coeffs += coeff
        else:
            sum_of_parity_known_coeffs += coeff
            sum_of_parity_known_coeffs_is_even = (
                sum_of_parity_known_coeffs_is_even == coeff_is_even
            )