docs: def merge(self, merge_func=None, merge_key=None, stash='active'):
          """
          Merge the states in a given stash.
  
          :param stash:       The stash (default: 'active')
          :param merge_func:  If provided, instead of using state.merge, call this function with
                              the states as the argument. Should return the merged state.
          :param merge_key:   If provided, should be a function that takes a state and returns a key that will compare
                              equal for all states that are allowed to be merged together, as a first aproximation.
                              By default: uses PC, callstack, and open file descriptors.
  
          :returns:           The simulation manager, for chaining.
          :rtype:             SimulationManager
          """
          self.prune(from_stash=stash)
          to_merge = self._fetch_states(stash=stash)
          not_to_merge = []
          if merge_key is None: merge_key = self._merge_key
  
          merge_groups = [ ]
          while to_merge:
              base_key = merge_key(to_merge[0])
              g, to_merge = self._filter_states(lambda s: base_key == merge_key(s), to_merge)
              if len(g) <= 1:
                  not_to_merge.extend(g)
              else:
                  merge_groups.append(g)
  
          for g in merge_groups:
              try:
                  m = self._merge_states(g) if merge_func is None else merge_func(*g)
                  not_to_merge.append(m)
              except SimMergeError:
                  l.warning("SimMergeError while merging %d states", len(g), exc_info=True)
                  not_to_merge.extend(g)
  
          self._clear_states(stash)
          self._store_states(stash, not_to_merge)
          return self