docs: def merge_with(self, another, ubound=None, top_id=None):
          """
              This method merges a tree of the current :class:`ITotalizer`
              object, with a tree of another object and (if needed) increases a
              potential upper bound that can be imposed on the complete list of
              literals in the sum of an existing :class:`ITotalizer` object to a
              new value.
  
              :param another: another totalizer to merge with.
              :param ubound: a new upper bound.
              :param top_id: a new top variable identifier.
  
              :type another: :class:`ITotalizer`
              :type ubound: int
              :type top_id: integer or None
  
              The top identifier ``top_id`` applied only if it is greater than
              the one used in ``self``.
  
              This method creates additional clauses encoding the existing
              totalizer tree merged with another totalizer tree into *one* sum
              and updating the upper bound. As a result, it appends the new
              clauses to the list of clauses of :class:`.CNF` ``self.cnf``. The
              number of newly created clauses is stored in variable
              ``self.nof_new``.
  
              Also, if the upper bound is updated, a list of bounds ``self.rhs``
              gets increased and its length becomes ``ubound+1``. Otherwise, it
              is updated with new values.
  
              The method can be used in the following way:
  
              .. code-block:: python
  
                  >>> from pysat.card import ITotalizer
                  >>> with ITotalizer(lits=[1, 2], ubound=1) as t1:
                  ...     print t1.cnf.clauses
                  [[-2, 3], [-1, 3], [-1, -2, 4]]
                  ...     print t1.rhs
                  [3, 4]
                  ...
                  ...     t2 = ITotalizer(lits=[5, 6], ubound=1)
                  ...     print t1.cnf.clauses
                  [[-6, 7], [-5, 7], [-5, -6, 8]]
                  ...     print t1.rhs
                  [7, 8]
                  ...
                  ...     t1.merge_with(t2)
                  ...     print t1.cnf.clauses
                  [[-2, 3], [-1, 3], [-1, -2, 4], [-6, 7], [-5, 7], [-5, -6, 8], [-7, 9], [-8, 10], [-3, 9], [-4, 10], [-3, -7, 10]]
                  ...     print t1.cnf.clauses[-t1.nof_new:]
                  [[-6, 7], [-5, 7], [-5, -6, 8], [-7, 9], [-8, 10], [-3, 9], [-4, 10], [-3, -7, 10]]
                  ...     print t1.rhs
                  [9, 10]
                  ...
                  ...     t2.delete()
          """
  
          self.top_id = max(self.top_id, top_id if top_id != None else 0, another.top_id)
          self.ubound = max(self.ubound, ubound if ubound != None else 0, another.ubound)
  
          # extending the list of input literals
          self.lits.extend(another.lits)
  
          # saving default SIGINT handler
          def_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_DFL)
  
          # updating the object and adding more variables and clauses
          self.tobj, clauses, self.rhs, self.top_id = pycard.itot_mrg(self.tobj,
                  another.tobj, self.ubound, self.top_id)
  
          # recovering default SIGINT handler
          def_sigint_handler = signal.signal(signal.SIGINT, def_sigint_handler)
  
          # saving the result
          self.cnf.clauses.extend(another.cnf.clauses)
          self.cnf.clauses.extend(clauses)
          self.cnf.nv = self.top_id
  
          # for convenience, keeping the number of new clauses
          self.nof_new = len(another.cnf.clauses) + len(clauses)
  
          # memory deallocation should not be done for the merged tree
          another._merged = True