'Determine what intervals the expr, cond pairs affect.
1) If cond is True, then log it as default
1.1) Currently if cond can\'t be evaluated, throw NotImplementedError.
2) For each inequality, if previous cond defines part of the interval
update the new conds interval.
-  eg x < 1, x < 3 -> [oo,1],[1,3] instead of [oo,1],[oo,3]
3) Sort the intervals to make it easier to find correct exprs
Under normal use, we return the expr,cond pairs in increasing order
along the real axis corresponding to the symbol sym.  If targetcond
is given, we return a list of (lowerbound, upperbound) pairs for
this condition.'

def _sort_expr_cond(self, sym, a, b, targetcond=None):

    from sympy.solvers.inequalities import _solve_inequality
    default = None
    int_expr = []
    expr_cond = []
    or_cond = False
    or_intervals = []
    independent_expr_cond = []
    for (expr, cond) in self.args:
        if isinstance(cond, Or):
            for cond2 in sorted(cond.args, key=default_sort_key):
                expr_cond.append((expr, cond2))
        else:
            expr_cond.append((expr, cond))
        if (cond == True):
            break
    for (expr, cond) in expr_cond:
        if (cond == True):
            independent_expr_cond.append((expr, cond))
            default = self.func(*independent_expr_cond)
            break
        orig_cond = cond
        if (sym not in cond.free_symbols):
            independent_expr_cond.append((expr, cond))
            continue
        elif isinstance(cond, Equality):
            continue
        elif isinstance(cond, And):
            lower = S.NegativeInfinity
            upper = S.Infinity
            for cond2 in cond.args:
                if (sym not in [cond2.lts, cond2.gts]):
                    cond2 = _solve_inequality(cond2, sym)
                if (cond2.lts == sym):
                    upper = Min(cond2.gts, upper)
                elif (cond2.gts == sym):
                    lower = Max(cond2.lts, lower)
                else:
                    raise NotImplementedError('Unable    to    handle    interval    evaluation    of    expression.')
        else:
            if (sym not in [cond.lts, cond.gts]):
                cond = _solve_inequality(cond, sym)
            (lower, upper) = (cond.lts, cond.gts)
            if (cond.lts == sym):
                lower = S.NegativeInfinity
            elif (cond.gts == sym):
                upper = S.Infinity
            else:
                raise NotImplementedError('Unable    to    handle    interval    evaluation    of    expression.')
        (lower, upper) = (Max(a, lower), Min(b, upper))
        for n in range(len(int_expr)):
            if (self.__eval_cond((lower < int_expr[n][1])) and self.__eval_cond((lower >= int_expr[n][0]))):
                lower = int_expr[n][1]
            elif (len(int_expr[n][1].free_symbols) and self.__eval_cond((lower >= int_expr[n][0]))):
                if self.__eval_cond((lower == int_expr[n][0])):
                    lower = int_expr[n][1]
                else:
                    int_expr[n][1] = Min(lower, int_expr[n][1])
            elif (len(int_expr[n][0].free_symbols) and self.__eval_cond((upper == int_expr[n][1]))):
                upper = Min(upper, int_expr[n][0])
            elif (len(int_expr[n][1].free_symbols) and ((lower >= int_expr[n][0]) != True) and ((int_expr[n][1] == Min(lower, upper)) != True)):
                upper = Min(upper, int_expr[n][0])
            elif (self.__eval_cond((upper > int_expr[n][0])) and self.__eval_cond((upper <= int_expr[n][1]))):
                upper = int_expr[n][0]
            elif (len(int_expr[n][0].free_symbols) and self.__eval_cond((upper < int_expr[n][1]))):
                int_expr[n][0] = Max(upper, int_expr[n][0])
        if (self.__eval_cond((lower >= upper)) != True):
            int_expr.append([lower, upper, expr])
        if (orig_cond == targetcond):
            return [(lower, upper, None)]
        elif (isinstance(targetcond, Or) and (cond in targetcond.args)):
            or_cond = Or(or_cond, cond)
            or_intervals.append((lower, upper, None))
            if (or_cond == targetcond):
                or_intervals.sort(key=(lambda x: x[0]))
                return or_intervals
    int_expr.sort(key=(lambda x: (x[1].sort_key() if x[1].is_number else S.NegativeInfinity.sort_key())))
    int_expr.sort(key=(lambda x: (x[0].sort_key() if x[0].is_number else S.Infinity.sort_key())))
    for n in range(len(int_expr)):
        if (len(int_expr[n][0].free_symbols) or len(int_expr[n][1].free_symbols)):
            if (isinstance(int_expr[n][1], Min) or (int_expr[n][1] == b)):
                newval = Min(*int_expr[n][:(-1)])
                if ((n > 0) and (int_expr[n][0] == int_expr[(n - 1)][1])):
                    int_expr[(n - 1)][1] = newval
                int_expr[n][0] = newval
            else:
                newval = Max(*int_expr[n][:(-1)])
                if ((n < (len(int_expr) - 1)) and (int_expr[n][1] == int_expr[(n + 1)][0])):
                    int_expr[(n + 1)][0] = newval
                int_expr[n][1] = newval
    holes = []
    curr_low = a
    for (int_a, int_b, expr) in int_expr:
        if ((curr_low < int_a) == True):
            holes.append([curr_low, Min(b, int_a), default])
        elif ((curr_low >= int_a) != True):
            holes.append([curr_low, Min(b, int_a), default])
        curr_low = Min(b, int_b)
    if ((curr_low < b) == True):
        holes.append([Min(b, curr_low), b, default])
    elif ((curr_low >= b) != True):
        holes.append([Min(b, curr_low), b, default])
    if (holes and (default is not None)):
        int_expr.extend(holes)
        if (targetcond == True):
            return [(h[0], h[1], None) for h in holes]
    elif (holes and (default is None)):
        raise ValueError(('Called    interval    evaluation    over    piecewise    function    on    undefined    intervals    %s' % ',    '.join([str((h[0], h[1])) for h in holes])))
    return int_expr
