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

Code before:
    It should be discerned from :func:`~.refine` which, when applied to a
    proposition, simplifies the argument to symbolic ``Boolean`` instead of
    Python built-in ``True``, ``False`` or ``None``.

    **Syntax**

        * ask(proposition)
            Evaluate the *proposition* in global assumption context.

        * ask(proposition, assumptions)
            Evaluate the *proposition* with respect to *assumptions* in
            global assumption context.

    Parameters
    ==========

    proposition : Boolean
        Proposition which will be evaluated to boolean value. If this is
        not ``AppliedPredicate``, it will be wrapped by ``Q.is_true``.

    assumptions : Boolean, optional
        Local assumptions to evaluate the *proposition*.

    context : AssumptionsContext, optional
        Default assumptions to evaluate the *proposition*. By default,
        this is ``sympy.assumptions.global_assumptions`` variable.

    Returns
    =======

    ``True``, ``False``, or ``None``

    Raises
    ======

    TypeError : *proposition* or *assumptions* is not valid logical expression.

    ValueError : assumptions are inconsistent.

    Examples
    ========

    >>> from sympy import ask, Q, pi
    >>> from sympy.abc import x, y
    >>> ask(Q.rational(pi))
    False
    >>> ask(Q.even(x*y), Q.even(x) & Q.integer(y))
    True
    >>> ask(Q.prime(4*x), Q.integer(x))
    False


Review comment (suggestion):
Let's add a simple docstring string here which notes what normalizations are done. The important thing is to note the final normalized form, i.e., all inequalities and equalities will be represented using `Q.le`, `Q.lt`, `Q.eq`, and `Q.ne` only. 

Code after:
    return expr

def _normalize_relations(expr):
    def _filter(e):
        return isinstance(e, (Gt, Ge, Lt, Le, Eq, Ne))

    def _replace(e):
        a, b = e.args
        if isinstance(e, Gt):
            return Q.lt(b, a)
        elif isinstance(e, Ge):
            return Q.le(b, a)
        elif isinstance(e, Lt):
            return Q.lt(a, b)
        elif isinstance(e, Le):
            return Q.le(a, b)
        elif isinstance(e, Eq):
            return Q.eq(a, b)
        elif isinstance(e, Ne):
            return Q.ne(a, b)
        return e

    return expr.replace(_filter, _replace)


def _normalize_expr(expr):
    expr = _normalize_relations(expr)
    expr = _normalize_applied_predicates(expr)
    return expr

def ask(proposition, assumptions=True, context=global_assumptions):
    """
    Function to evaluate the proposition with assumptions.

    Explanation
    ===========

    This function evaluates the proposition to ``True`` or ``False`` if
    the truth value can be determined. If not, it returns ``None``.

    It should be discerned from :func:`~.refine` which, when applied to a
    proposition, simplifies the argument to symbolic ``Boolean`` instead of
    Python built-in ``True``, ``False`` or ``None``.

    **Syntax**

        * ask(proposition)
            Evaluate the *proposition* in global assumption context.

        * ask(proposition, assumptions)
            Evaluate the *proposition* with respect to *assumptions* in