class_docstr: Represents a piecewise function.
  
  Usage:
  
    Piecewise( (expr,cond), (expr,cond), ... )
      - Each argument is a 2-tuple defining an expression and condition
      - The conds are evaluated in turn returning the first that is True.
        If any of the evaluated conds are not explicitly False,
        e.g. ``x < 1``, the function is returned in symbolic form.
      - If the function is evaluated at a place where all conditions are False,
        nan will be returned.
      - Pairs where the cond is explicitly False, will be removed and no pair
        appearing after a True condition will ever be retained. If a single
        pair with a True condition remains, it will be returned, even when
        evaluation is False.
  
  Examples
  ========
  
  >>> from sympy import Piecewise, log, piecewise_fold
  >>> from sympy.abc import x, y
  >>> f = x**2
  >>> g = log(x)
  >>> p = Piecewise((0, x < -1), (f, x <= 1), (g, True))
  >>> p.subs(x,1)
  1
  >>> p.subs(x,5)
  log(5)
  
  Booleans can contain Piecewise elements:
  
  >>> cond = (x < y).subs(x, Piecewise((2, x < 0), (3, True))); cond
  Piecewise((2, x < 0), (3, True)) < y
  
  The folded version of this results in a Piecewise whose
  expressions are Booleans:
  
  >>> folded_cond = piecewise_fold(cond); folded_cond
  Piecewise((2 < y, x < 0), (3 < y, True))
  
  When a Boolean containing Piecewise (like cond) or a Piecewise
  with Boolean expressions (like folded_cond) is used as a condition,
  it is converted to an equivalent :class:`~.ITE` object:
  
  >>> Piecewise((1, folded_cond))
  Piecewise((1, ITE(x < 0, y > 2, y > 3)))
  
  When a condition is an ``ITE``, it will be converted to a simplified
  Boolean expression:
  
  >>> piecewise_fold(_)
  Piecewise((1, ((x >= 0) | (y > 2)) & ((y > 3) | (x < 0))))
  
  See Also
  ========
  
  piecewise_fold
  piecewise_exclusive
  ITE
docstr: Return a bool and a message (when bool is False), else a
  list of unique tuples, (a, b, e, i), where a and b
  are the lower and upper bounds in which the expression e of
  argument i in self is defined and $a < b$ (when involving
  numbers) or $a \le b$ when involving symbols.
  
  If there are any relationals not involving sym, or any
  relational cannot be solved for sym, the bool will be False
  a message be given as the second return value. The calling
  routine should have removed such relationals before calling
  this routine.
  
  The evaluated conditions will be returned as ranges.
  Discontinuous ranges will be returned separately with
  identical expressions. The first condition that evaluates to
  True will be returned as the last tuple with a, b = -oo, oo.
docstr_tok: ["Return","a","bool","and","a","message","(","when","bool","is","False",")",",","else","a","list","of","unique","tuples",",","(","a",",","b",",","e",",","i",")",",","where","a","and","b","are","the","lower","and","upper","bounds","in","which","the","expression","e","of","argument","i","in","self","is","defined","and","$","a","<","b","$","(","when","involving","numbers",")","or","$","a","\\le","b","$","when","involving","symbols",".","If","there","are","any","relationals","not","involving","sym",",","or","any","relational","can","not","be","solved","for","sym",",","the","bool","will","be","False","a","message","be","given","as","the","second","return","value",".","The","calling","routine","should","have","removed","such","relationals","before","calling","this","routine",".","The","evaluated","conditions","will","be","returned","as","ranges",".","Discontinuous","ranges","will","be","returned","separately","with","identical","expressions",".","The","first","condition","that","evaluates","to","True","will","be","returned","as","the","last","tuple","with","a",",","b","=","-oo",",","oo","."]
code: def _intervals(self, sym, err_on_Eq=False):
      r"""Return a bool and a message (when bool is False), else a
      list of unique tuples, (a, b, e, i), where a and b
      are the lower and upper bounds in which the expression e of
      argument i in self is defined and $a < b$ (when involving
      numbers) or $a \le b$ when involving symbols.
  
      If there are any relationals not involving sym, or any
      relational cannot be solved for sym, the bool will be False
      a message be given as the second return value. The calling
      routine should have removed such relationals before calling
      this routine.
  
      The evaluated conditions will be returned as ranges.
      Discontinuous ranges will be returned separately with
      identical expressions. The first condition that evaluates to
      True will be returned as the last tuple with a, b = -oo, oo.
      """
      from sympy.solvers.inequalities import _solve_inequality
  
      assert isinstance(self, Piecewise)
  
      def nonsymfail(cond):
          return False, filldedent(
              """
                  A condition not involving
                  %s appeared: %s"""
              % (sym, cond)
          )
  
      def _solve_relational(r):
          if sym not in r.free_symbols:
              return nonsymfail(r)
          try:
              rv = _solve_inequality(r, sym)
          except NotImplementedError:
              return False, "Unable to solve relational %s for %s." % (
                  r,
                  sym,
              )
          if isinstance(rv, Relational):
              free = rv.args[1].free_symbols
              if rv.args[0] != sym or sym in free:
                  return (
                      False,
                      "Unable to solve relational %s for %s."
                      % (r, sym),
                  )
              if rv.rel_op == "==":
                  # this equality has been affirmed to have the form
                  # Eq(sym, rhs) where rhs is sym-free; it represents
                  # a zero-width interval which will be ignored
                  # whether it is an isolated condition or contained
                  # within an And or an Or
                  rv = S.false
              elif rv.rel_op == "!=":
                  try:
                      rv = Or(sym < rv.rhs, sym > rv.rhs)
                  except TypeError:
                      # e.g. x != I ==> all real x satisfy
                      rv = S.true
          elif rv == (S.NegativeInfinity < sym) & (sym < S.Infinity):
              rv = S.true
          return True, rv
  
      args = list(self.args)
      # make self canonical wrt Relationals
      keys = self.atoms(Relational)
      reps = {}
      for r in keys:
          ok, s = _solve_relational(r)
          if ok != True:
              return False, ok
          reps[r] = s
      # process args individually so if any evaluate, their position
      # in the original Piecewise will be known
      args = [i.xreplace(reps) for i in self.args]
  
      # precondition args
      expr_cond = []
      default = idefault = None
      for i, (expr, cond) in enumerate(args):
          if cond is S.false:
              continue
          if cond is S.true:
              default = expr
              idefault = i
              break
          if isinstance(cond, Eq):
              # unanticipated condition, but it is here in case a
              # replacement caused an Eq to appear
              if err_on_Eq:
                  return False, "encountered Eq condition: %s" % cond
              continue  # zero width interval
  
          cond = to_cnf(cond)
          if isinstance(cond, And):
              cond = distribute_or_over_and(cond)
  
          if isinstance(cond, Or):
              expr_cond.extend(
                  [
                      (i, expr, o)
                      for o in cond.args
                      if not isinstance(o, Eq)
                  ]
              )
          elif cond is not S.false:
              expr_cond.append((i, expr, cond))
          elif cond is S.true:
              default = expr
              idefault = i
              break
  
      # determine intervals represented by conditions
      int_expr = []
      for iarg, expr, cond in expr_cond:
          if isinstance(cond, And):
              lower = S.NegativeInfinity
              upper = S.Infinity
              exclude = []
              for cond2 in cond.args:
                  if not isinstance(cond2, Relational):
                      return False, "expecting only Relationals"
                  if isinstance(cond2, Eq):
                      lower = upper  # ignore
                      if err_on_Eq:
                          return (
                              False,
                              "encountered secondary Eq condition",
                          )
                      break
                  elif isinstance(cond2, Ne):
                      l, r = cond2.args
                      if l == sym:
                          exclude.append(r)
                      elif r == sym:
                          exclude.append(l)
                      else:
                          return nonsymfail(cond2)
                      continue
                  elif cond2.lts == sym:
                      upper = Min(cond2.gts, upper)
                  elif cond2.gts == sym:
                      lower = Max(cond2.lts, lower)
                  else:
                      return nonsymfail(cond2)  # should never get here
              if exclude:
                  exclude = list(ordered(exclude))
                  newcond = []
                  for i, e in enumerate(exclude):
                      if e < lower == True or e > upper == True:
                          continue
                      if not newcond:
                          newcond.append((None, lower))  # add a primer
                      newcond.append((newcond[-1][1], e))
                  newcond.append((newcond[-1][1], upper))
                  newcond.pop(0)  # remove the primer
                  expr_cond.extend(
                      [
                          (iarg, expr, And(i[0] < sym, sym < i[1]))
                          for i in newcond
                      ]
                  )
                  continue
          elif isinstance(cond, Relational) and cond.rel_op != "!=":
              lower, upper = (
                  cond.lts,
                  cond.gts,
              )  # part 1: initialize with givens
              if cond.lts == sym:  # part 1a: expand the side ...
                  lower = (
                      S.NegativeInfinity
                  )  # e.g. x <= 0 ---> -oo <= 0
              elif cond.gts == sym:  # part 1a: ... that can be expanded
                  upper = S.Infinity  # e.g. x >= 0 --->  oo >= 0
              else:
                  return nonsymfail(cond)
          else:
              return False, "unrecognized condition: %s" % cond
  
          lower, upper = lower, Max(lower, upper)
          if err_on_Eq and lower == upper:
              return False, "encountered Eq condition"
          if (lower >= upper) is not S.true:
              int_expr.append((lower, upper, expr, iarg))
  
      if default is not None:
          int_expr.append(
              (S.NegativeInfinity, S.Infinity, default, idefault)
          )
  
      return True, list(uniq(int_expr))
  
imports: from sympy.core import S, Function, diff, Tuple, Dummy, Mul
  from sympy.core.basic import Basic, as_Basic
  from sympy.core.numbers import Rational, NumberSymbol, _illegal
  from sympy.core.parameters import global_parameters
  from sympy.core.relational import Lt, Gt, Eq, Ne, Relational, _canonical, _canonical_coeff
  from sympy.core.sorting import ordered
  from sympy.functions.elementary.miscellaneous import Max, Min
  from sympy.logic.boolalg import And, Boolean, distribute_and_over_or, Not, true, false, Or, ITE, simplify_logic, to_cnf, distribute_or_over_and
  from sympy.utilities.iterables import uniq, sift, common_prefix
  from sympy.utilities.misc import filldedent, func_name
  from itertools import product
label_desc: Use image node_id 15 for calling the Piecewise obj's underlying member method code with example usage: obj._intervals(sym, err_on_Eq) and returns: True,  list, False,  filldedent, True,  rv, nonsymfail, False,  ok, False,  str, False,  unknown, False,  unknown, False,  unknown, False,  unknown, False,  str, False,  str, nonsymfail, nonsymfail, nonsymfail