Repository: sympy/sympy
File: sympy/assumptions/handlers/sets.py (Python)

Code before:
        return

    if ask(Q.imaginary(expr.base), assumptions):
        if ask(Q.integer(expr.exp), assumptions):
            odd = ask(Q.odd(expr.exp), assumptions)
            if odd is not None:
                return not odd
            return

    if ask(Q.imaginary(expr.exp), assumptions):
        imlog = ask(Q.imaginary(log(expr.base)), assumptions)
        if imlog is not None:
            # I**i -> real, log(I) is imag;
            # (2*I)**i -> complex, log(2*I) is not imag
            return imlog

    if ask(Q.real(expr.base), assumptions):
        if ask(Q.real(expr.exp), assumptions):
            if (expr.exp.is_Rational and
                    ask(Q.even(expr.exp.q), assumptions)):
                return ask(Q.nonnegative(expr.base), assumptions)
            base_is_zero = ask(Q.zero(expr.base), assumptions)
            if base_is_zero or ask(Q.integer(expr.exp), assumptions):
                is_not_real = fuzzy_and([base_is_zero,
                                ask(Q.negative(expr.exp), assumptions)])
                return fuzzy_not(is_not_real)
            elif ask(Q.positive(expr.base), assumptions):
                return True

@RealPredicate.register_many(cos, sin)
def _(expr, assumptions):
    if ask(Q.real(expr.args[0]), assumptions):
            return True

@RealPredicate.register(exp)
def _(expr, assumptions):
    return ask(
        Q.integer(expr.exp/I/pi) | Q.real(expr.exp), assumptions
    )

@RealPredicate.register(log)
def _(expr, assumptions):
    return ask(Q.positive(expr.args[0]), assumptions)

@RealPredicate.register_many(Determinant, MatrixElement, Trace)
def _(expr, assumptions):
    return ask(Q.real_elements(expr.args[0]), assumptions)


# ExtendedRealPredicate


Review comment (bug):
I think the flow of this logic is a bit confusing. I don't think `is_not_real` is the best name. Maybe this would benefit from some comments.

By the way, good catch with the bug!

Code after:
        return

    if ask(Q.imaginary(expr.base), assumptions):
        if ask(Q.integer(expr.exp), assumptions):
            odd = ask(Q.odd(expr.exp), assumptions)
            if odd is not None:
                return not odd
            return

    if ask(Q.imaginary(expr.exp), assumptions):
        imlog = ask(Q.imaginary(log(expr.base)), assumptions)
        if imlog is not None:
            # I**i -> real, log(I) is imag;
            # (2*I)**i -> complex, log(2*I) is not imag
            return imlog

    if ask(Q.real(expr.base), assumptions):
        if ask(Q.real(expr.exp), assumptions):
            if (expr.exp.is_Rational and
                    ask(Q.even(expr.exp.q), assumptions)):
                return ask(Q.nonnegative(expr.base), assumptions)
            base_is_zero = ask(Q.zero(expr.base), assumptions)
            if base_is_zero or ask(Q.integer(expr.exp), assumptions):
                # Division by zero : If the base is 0 and the exponent
                # is negative, ``expr`` evaluates to complex infinity.
                expr_is_complex_infinity = fuzzy_and([base_is_zero,
                                ask(Q.negative(expr.exp), assumptions)])
                return fuzzy_not(expr_is_complex_infinity)
            elif ask(Q.positive(expr.base), assumptions):
                return True

@RealPredicate.register_many(cos, sin)
def _(expr, assumptions):
    if ask(Q.real(expr.args[0]), assumptions):
            return True

@RealPredicate.register(exp)
def _(expr, assumptions):
    return ask(
        Q.integer(expr.exp/I/pi) | Q.real(expr.exp), assumptions
    )

@RealPredicate.register(log)
def _(expr, assumptions):
    return ask(Q.positive(expr.args[0]), assumptions)

@RealPredicate.register_many(Determinant, MatrixElement, Trace)
def _(expr, assumptions):
    return ask(Q.real_elements(expr.args[0]), assumptions)