class_docstr: Has methods to ``enumerate`` and ``count`` the partitions of a multiset.
  
  This implements a refactored and extended version of Knuth's algorithm
  7.1.2.5M [AOCP]_."
  
  The enumeration methods of this class are generators and return
  data structures which can be interpreted by the same visitor
  functions used for the output of ``multiset_partitions_taocp``.
  
  Examples
  ========
  
  >>> from sympy.utilities.enumerative import MultisetPartitionTraverser
  >>> m = MultisetPartitionTraverser()
  >>> m.count_partitions([4,4,4,2])
  127750
  >>> m.count_partitions([3,3,3])
  686
  
  See Also
  ========
  
  multiset_partitions_taocp
  sympy.utilities.iterables.multiset_partitions
  
  References
  ==========
  
  .. [AOCP] Algorithm 7.1.2.5M in Volume 4A, Combinatoral Algorithms,
         Part 1, of The Art of Computer Programming, by Donald Knuth.
  
  .. [Factorisatio] On a Problem of Oppenheim concerning
         "Factorisatio Numerorum" E. R. Canfield, Paul Erdos, Carl
         Pomerance, JOURNAL OF NUMBER THEORY, Vol. 17, No. 1. August
         1983.  See section 7 for a description of an algorithm
         similar to Knuth's.
  
  .. [Yorgey] Generating Multiset Partitions, Brent Yorgey, The
         Monad.Reader, Issue 8, September 2007.
docstr: Enumerate the partitions of a multiset with
  ``lb < num(parts) <= ub``.
  
  In particular, if partitions with exactly ``k`` parts are
  desired, call with ``(multiplicities, k - 1, k)``.  This
  method generalizes enum_all, enum_small, and enum_large.
  
  Examples
  ========
  
  >>> from sympy.utilities.enumerative import list_visitor
  >>> from sympy.utilities.enumerative import MultisetPartitionTraverser
  >>> m = MultisetPartitionTraverser()
  >>> states = m.enum_range([2,2], 1, 2)
  >>> list(list_visitor(state, 'ab') for state in states)
  [[['a', 'a', 'b'], ['b']],
  [['a', 'a'], ['b', 'b']],
  [['a', 'b', 'b'], ['a']],
  [['a', 'b'], ['a', 'b']]]
docstr_tok: ["Enumerate","the","partitions","of","a","multiset","with","``","lb","<","num","(","parts",")","<","=","ub","``",".","In","particular",",","if","partitions","with","exactly","``","k","``","parts","are","desired",",","call","with","``","(","multiplicities",",","k","-","1",",","k",")","``",".","This","method","generalizes","enum_all",",","enum_small",",","and","enum_large",".","Examples","========",">",">",">","from","sympy.utilities.enumerative","import","list_visitor",">",">",">","from","sympy.utilities.enumerative","import","MultisetPartitionTraverser",">",">",">","m","=","MultisetPartitionTraverser","(",")",">",">",">","states","=","m.enum_range","(","[","2,2","]",",","1",",","2",")",">",">",">","list","(","list_visitor","(","state",",","'ab","'",")","for","state","in","states",")","[","[","[","'","a","'",",","'","a","'",",","'","b","'","]",",","[","'","b","'","]","]",",","[","[","'","a","'",",","'","a","'","]",",","[","'","b","'",",","'","b","'","]","]",",","[","[","'","a","'",",","'","b","'",",","'","b","'","]",",","[","'","a","'","]","]",",","[","[","'","a","'",",","'","b","'","]",",","[","'","a","'",",","'","b","'","]","]","]"]
code: def enum_range(self, multiplicities, lb, ub):
      """Enumerate the partitions of a multiset with
      ``lb < num(parts) <= ub``.
  
      In particular, if partitions with exactly ``k`` parts are
      desired, call with ``(multiplicities, k - 1, k)``.  This
      method generalizes enum_all, enum_small, and enum_large.
  
      Examples
      ========
  
      >>> from sympy.utilities.enumerative import list_visitor
      >>> from sympy.utilities.enumerative import MultisetPartitionTraverser
      >>> m = MultisetPartitionTraverser()
      >>> states = m.enum_range([2,2], 1, 2)
      >>> list(list_visitor(state, 'ab') for state in states)
      [[['a', 'a', 'b'], ['b']],
      [['a', 'a'], ['b', 'b']],
      [['a', 'b', 'b'], ['a']],
      [['a', 'b'], ['a', 'b']]]
  
      """
      # combine the constraints of the _large and _small
      # enumerations.
      self.discarded = 0
      if ub <= 0 or lb >= sum(multiplicities):
          return
      self._initialize_enumeration(multiplicities)
      self.decrement_part_large(self.top_part(), 0, lb)
      while True:
          good_partition = True
          while self.spread_part_multiplicity():
              self.db_trace("spread 1")
              if not self.decrement_part_large(self.top_part(), 0, lb):
                  # Failure here - possible in range case?
                  self.db_trace("  Discarding (large cons)")
                  self.discarded += 1
                  good_partition = False
                  break
              elif self.lpart >= ub:
                  self.discarded += 1
                  good_partition = False
                  self.db_trace("  Discarding small cons")
                  self.lpart = ub - 2
                  break
  
          # M4  Visit a partition
          if good_partition:
              state = [self.f, self.lpart, self.pstack]
              yield state
  
          # M5 (Decrease v)
          while not self.decrement_part_range(self.top_part(), lb, ub):
              self.db_trace("Failed decrement, going to backtrack")
              # M6 (Backtrack)
              if self.lpart == 0:
                  return
              self.lpart -= 1
              self.db_trace("Backtracked to")
          self.db_trace("decrement ok, about to expand")
  
label_desc: Use image node_id 13 for calling the MultisetPartitionTraverser obj's underlying member method code with example usage: obj.enum_range(multiplicities, lb, ub) without return types