docs: def _subs(self, substitutions, default, simplify):
          """
          Return an expression where all subterms equal to a key expression are
          substituted by the corresponding value expression using a mapping of:
          {expr->expr to substitute.}
          """
          # track the new list of unchanged args or replaced args through
          # a substitution
          new_arguments = []
          changed_something = False
  
          # shortcut for basic logic True or False
          if self is self.TRUE or self is self.FALSE:
              return self
  
          # if the expression has no elements, e.g. is empty, do not apply
          # substitions
          if not self.args:
              return default
  
          # iterate the subexpressions: either plain symbols or a subexpressions
          for arg in self.args:
              # collect substitutions for exact matches
              # break as soon as we have a match
              for expr, substitution in substitutions.items():
                  if arg == expr:
                      new_arguments.append(substitution)
                      changed_something = True
                      break
  
              # this will execute only if we did not break out of the
              # loop, e.g. if we did not change anything and did not
              # collect any substitutions
              else:
                  # recursively call _subs on each arg to see if we get a
                  # substituted arg
                  new_arg = arg._subs(substitutions, default, simplify)
                  if new_arg is None:
                      # if we did not collect a substitution for this arg,
                      # keep the arg as-is, it is not replaced by anything
                      new_arguments.append(arg)
                  else:
                      # otherwise, we add the substitution for this arg instead
                      new_arguments.append(new_arg)
                      changed_something = True
  
          if not changed_something:
              return
  
          # here we did some substitution: we return a new expression
          # built from the new_arguments
          newexpr = self.__class__(*new_arguments)
          return newexpr.simplify() if simplify else newexpr