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

Code before:
    (-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):
        rem = Add(*rem_terms)
        return ((-1)**((k + 1) / 2)) * sin(rem)
    elif ask(Q.even(k), assumptions):
        rem = Add(*rem_terms)
        return ((-1)**(k / 2)) * cos(rem)
    # Best to leave the expression as is.
    return expr

handlers_dict: dict[str, Callable[[Basic, Boolean | bool], Expr]] = {
    'Abs': refine_abs,
    'Pow': refine_Pow,
    'atan2': refine_atan2,
    're': refine_re,
    'im': refine_im,
    'arg': refine_arg,

Review comment (suggestion):
I think this would be more readable if there was only one if statement. If you didn't know, python is smart enough that if `condition_a()` were to evaluate false, `condition_b()` would never be called:
```python
if condition_a() and condition_b():
```

Code after:
    (-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
            )

    if sum_of_parity_known_coeffs == 0:
        return expr

    # Treat sin as a phase-shifted cosine so a single logic path can handle both.
    if isinstance(expr, sin):
        k = sum_of_parity_known_coeffs - 1
        k_is_even = not sum_of_parity_known_coeffs_is_even
    else:
        k = sum_of_parity_known_coeffs
        k_is_even = sum_of_parity_known_coeffs_is_even

    # If k is even:
    #    `cos(rem + k*pi/2)` -> `(-1)^(k/2) * cos(rem)`
    #