text: from __future__ import print_function, division
  
  from sympy.core.assumptions import StdFactKB, _assume_defined
  from sympy.core.compatibility import (string_types, range, is_sequence,
      ordered)
  from .basic import Basic
  from .sympify import sympify
  from .singleton import S
  from .expr import Expr, AtomicExpr
  from .cache import cacheit
  from .function import FunctionClass
  from sympy.core.logic import fuzzy_bool
  from sympy.logic.boolalg import Boolean
  from sympy.utilities.iterables import cartes, sift
  from sympy.core.containers import Tuple
  
  import string
  import re as _re
  import random
  
  
  def _filter_assumptions(kwargs):
      """Split the given dict into assumptions and non-assumptions.
      Keys are taken as assumptions if they correspond to an
      entry in ``_assume_defined``.
      """
      assumptions, nonassumptions = map(dict, sift(kwargs.items(),
          lambda i: i[0] in _assume_defined,
          binary=True))
      Symbol._sanitize(assumptions)
      return assumptions, nonassumptions
  
  def _symbol(s, matching_symbol=None, **assumptions):
      """Return s if s is a Symbol, else if s is a string, return either
      the matching_symbol if the names are the same or else a new symbol
      with the same assumptions as the matching symbol (or the
      assumptions as provided).
  
      Examples
      ========
  
      >>> from sympy import Symbol, Dummy
      >>> from sympy.core.symbol import _symbol
      >>> _symbol('y')
      y
      >>> _.is_real is None
      True
      >>> _symbol('y', real=True).is_real
      True
  
      >>> x = Symbol('x')
      >>> _symbol(x, real=True)
      x
      >>> _.is_real is None  # ignore attribute if s is a Symbol
      True
  
      Below, the variable sym has the name 'foo':
  
      >>> sym = Symbol('foo', real=True)
  
      Since 'x' is not the same as sym's name, a new symbol is created:
  
      >>> _symbol('x', sym).name
      'x'
  
      It will acquire any assumptions give:
  
      >>> _symbol('x', sym, real=False).is_real
      False
  
      Since 'foo' is the same as sym's name, sym is returned
  
      >>> _symbol('foo', sym)
      foo
  
      Any assumptions given are ignored:
  
      >>> _symbol('foo', sym, real=False).is_real
      True
  
      NB: the symbol here may not be the same as a symbol with the same
      name defined elsewhere as a result of different assumptions.
  
      See Also
      ========
  
      sympy.core.symbol.Symbol
  
      """
      if isinstance(s, string_types):
          if matching_symbol and matching_symbol.name == s:
              return matching_symbol
          return Symbol(s, **assumptions)
      elif isinstance(s, Symbol):
          return s
      else:
          raise ValueError('symbol must be string for symbol name or Symbol')
  
  
  def _uniquely_named_symbol(xname, exprs=(), compare=str, modify=None, **assumptions):
      """Return a symbol which, when printed, will have a name unique
      from any other already in the expressions given. The name is made
      unique by prepending underscores (default) but this can be
      customized with the keyword 'modify'.
  
      Parameters
      ==========
  
          xname : a string or a Symbol (when symbol xname <- str(xname))
          compare : a single arg function that takes a symbol and returns
              a string to be compared with xname (the default is the str
              function which indicates how the name will look when it
              is printed, e.g. this includes underscores that appear on
              Dummy symbols)
          modify : a single arg function that changes its string argument
              in some way (the default is to preppend underscores)
  
      Examples
      ========
  
      >>> from sympy.core.symbol import _uniquely_named_symbol as usym, Dummy
      >>> from sympy.abc import x
      >>> usym('x', x)
      _x
      """
      default = None
      if is_sequence(xname):
          xname, default = xname
      x = str(xname)
      if not exprs:
          return _symbol(x, default, **assumptions)
      if not is_sequence(exprs):
          exprs = [exprs]
      syms = set().union(*[e.free_symbols for e in exprs])
      if modify is None:
          modify = lambda s: '_' + s
      while any(x == compare(s) for s in syms):
          x = modify(x)
      return _symbol(x, default, **assumptions)
  
  
  class Symbol(AtomicExpr, Boolean):
      """
      Assumptions:
         commutative = True
  
      You can override the default assumptions in the constructor:
  
      >>> from sympy import symbols
      >>> A,B = symbols('A,B', commutative = False)
      >>> bool(A*B != B*A)
      True
      >>> bool(A*B*2 == 2*A*B) == True # multiplication by scalars is commutative
      True
  
      """
  
      is_comparable = False
  
      __slots__ = ['name']
  
      is_Symbol = True
      is_symbol = True
  
      @property
      def _diff_wrt(self):
          """Allow derivatives wrt Symbols.
  
          Examples
          ========
  
              >>> from sympy import Symbol
              >>> x = Symbol('x')
              >>> x._diff_wrt
              True
          """
          return True
  
      @staticmethod
      def _sanitize(assumptions, obj=None):
          """Remove None, covert values to bool, check commutativity *in place*.
          """
  
          # be strict about commutativity: cannot be None
          is_commutative = fuzzy_bool(assumptions.get('commutative', True))
          if is_commutative is None:
              whose = '%s ' % obj.__name__ if obj else ''
              raise ValueError(
                  '%scommutativity must be True or False.' % whose)
  
          # sanitize other assumptions so 1 -> True and 0 -> False
          for key in list(assumptions.keys()):
              from collections import defaultdict
              from sympy.utilities.exceptions import SymPyDeprecationWarning
              keymap = defaultdict(lambda: None)
              keymap.update({'bounded': 'finite', 'unbounded': 'infinite', 'infinitesimal': 'zero'})
              if keymap[key]:
                  SymPyDeprecationWarning(
                      feature="%s assumption" % key,
                      useinstead="%s" % keymap[key],
                      issue=8071,
                      deprecated_since_version="0.7.6").warn()
                  assumptions[keymap[key]] = assumptions[key]
                  assumptions.pop(key)
                  key = keymap[key]
  
              v = assumptions[key]
              if v is None:
                  assumptions.pop(key)
                  continue
              assumptions[key] = bool(v)
  
      def _merge(self, assumptions):
          base = self.assumptions0
          for k in set(assumptions) & set(base):
              if assumptions[k] != base[k]:
                  raise ValueError(filldedent('''
                      non-matching assumptions for %s: existing value
                      is %s and new value is %s''' % (
                      k, base[k], assumptions[k])))
          base.update(assumptions)
          return base
  
      def __new__(cls, name, **assumptions):
          """Symbols are identified by name and assumptions::
  
          >>> from sympy import Symbol
          >>> Symbol("x") == Symbol("x")
          True
          >>> Symbol("x", real=True) == Symbol("x", real=False)
          False
  
          """
          cls._sanitize(assumptions, cls)
          return Symbol.__xnew_cached_(cls, name, **assumptions)
  
      def __new_stage2__(cls, name, **assumptions):
          if not isinstance(name, string_types):
              raise TypeError("name should be a string, not %s" % repr(type(name)))
  
          obj = Expr.__new__(cls)
          obj.name = name
  
          # TODO: Issue #8873: Forcing the commutative assumption here means
          # later code such as ``srepr()`` cannot tell whether the user
          # specified ``commutative=True`` or omitted it.  To workaround this,
          # we keep a copy of the assumptions dict, then create the StdFactKB,
          # and finally overwrite its ``._generator`` with the dict copy.  This
          # is a bit of a hack because we assume StdFactKB merely copies the
          # given dict as ``._generator``, but future modification might, e.g.,
          # compute a minimal equivalent assumption set.
          tmp_asm_copy = assumptions.copy()
  
          # be strict about commutativity
          is_commutative = fuzzy_bool(assumptions.get('commutative', True))
          assumptions['commutative'] = is_commutative
          obj._assumptions = StdFactKB(assumptions)
          obj._assumptions._generator = tmp_asm_copy  # Issue #8873
          return obj
  
      __xnew__ = staticmethod(
          __new_stage2__)            # never cached (e.g. dummy)
      __xnew_cached_ = staticmethod(
          cacheit(__new_stage2__))   # symbols are always cached
  
      def __getnewargs__(self):
          return (self.name,)
  
      def __getstate__(self):
          return {'_assumptions': self._assumptions}
  
      def _hashable_content(self):
          # Note: user-specified assumptions not hashed, just derived ones
          return (self.name,) + tuple(sorted(self.assumptions0.items()))
  
      def _eval_subs(self, old, new):
          from sympy.core.power import Pow
          if old.is_Pow:
              return Pow(self, S.One, evaluate=False)._eval_subs(old, new)
  
      @property
      def assumptions0(self):
          return dict((key, value) for key, value
                  in self._assumptions.items() if value is not None)
  
      @cacheit
      def sort_key(self, order=None):
          return self.class_key(), (1, (str(self),)), S.One.sort_key(), S.One
  
      def as_dummy(self):
          return Dummy(self.name)
  
      def as_real_imag(self, deep=True, **hints):
          from sympy import im, re
          if hints.get('ignore') == self:
              return None
          else:
              return (re(self), im(self))
  
      def _sage_(self):
          import sage.all as sage
          return sage.var(self.name)
  
      def is_constant(self, *wrt, **flags):
          if not wrt:
              return False
          return not self in wrt
  
      @property
      def free_symbols(self):
          return {self}
  
      binary_symbols = free_symbols  # in this case, not always
  
      def as_set(self):
          return S.UniversalSet
  
  
  class Dummy(Symbol):
      """Dummy symbols are each unique, even if they have the same name:
  
      >>> from sympy import Dummy
      >>> Dummy("x") == Dummy("x")
      False
  
      If a name is not supplied then a string value of an internal count will be
      used. This is useful when a temporary variable is needed and the name
      of the variable used in the expression is not important.
  
      >>> Dummy() #doctest: +SKIP
      _Dummy_10
  
      """
  
      # In the rare event that a Dummy object needs to be recreated, both the
      # `name` and `dummy_index` should be passed.  This is used by `srepr` for
      # example:
      # >>> d1 = Dummy()
      # >>> d2 = eval(srepr(d1))
      # >>> d2 == d1
      # True
      #
      # If a new session is started between `srepr` and `eval`, there is a very
      # small chance that `d2` will be equal to a previously-created Dummy.
  
      _count = 0
      _prng = random.Random()
      _base_dummy_index = _prng.randint(10**6, 9*10**6)
  
      __slots__ = ['dummy_index']
  
      is_Dummy = True
  
      def __new__(cls, name=None, dummy_index=None, **assumptions):
          if dummy_index is not None:
              assert name is not None, "If you specify a dummy_index, you must also provide a name"
  
          if name is None:
              name = "Dummy_" + str(Dummy._count)
  
          if dummy_index is None:
              dummy_index = Dummy._base_dummy_index + Dummy._count
              Dummy._count += 1
  
          cls._sanitize(assumptions, cls)
          obj = Symbol.__xnew__(cls, name, **assumptions)
  
          obj.dummy_index = dummy_index
  
          return obj
  
      def __getstate__(self):
          return {'_assumptions': self._assumptions, 'dummy_index': self.dummy_index}
  
      @cacheit
      def sort_key(self, order=None):
          return self.class_key(), (
              2, (str(self), self.dummy_index)), S.One.sort_key(), S.One
  
      def _hashable_content(self):
          return Symbol._hashable_content(self) + (self.dummy_index,)
  
  
  class Wild(Symbol):
      """
      A Wild symbol matches anything, or anything
      without whatever is explicitly excluded.
  
      Parameters
      ==========
  
      name : str
          Name of the Wild instance.
      exclude : iterable, optional
          Instances in ``exclude`` will not be matched.
      properties : iterable of functions, optional
          Functions, each taking an expressions as input
          and returns a ``bool``. All functions in ``properties``
          need to return ``True`` in order for the Wild instance
          to match the expression.
  
      Examples
      ========
  
      >>> from sympy import Wild, WildFunction, cos, pi
      >>> from sympy.abc import x, y, z
      >>> a = Wild('a')
      >>> x.match(a)
      {a_: x}
      >>> pi.match(a)
      {a_: pi}
      >>> (3*x**2).match(a*x)
      {a_: 3*x}
      >>> cos(x).match(a)
      {a_: cos(x)}
      >>> b = Wild('b', exclude=[x])
      >>> (3*x**2).match(b*x)
      >>> b.match(a)
      {a_: b_}
      >>> A = WildFunction('A')
      >>> A.match(a)
      {a_: A_}
  
      Tips
      ====
  
      When using Wild, be sure to use the exclude
      keyword to make the pattern more precise.
      Without the exclude pattern, you may get matches
      that are technically correct, but not what you
      wanted. For example, using the above without
      exclude:
  
      >>> from sympy import symbols
      >>> a, b = symbols('a b', cls=Wild)
      >>> (2 + 3*y).match(a*x + b*y)
      {a_: 2/x, b_: 3}
  
      This is technically correct, because
      (2/x)*x + 3*y == 2 + 3*y, but you probably
      wanted it to not match at all. The issue is that
      you really didn't want a and b to include x and y,
      and the exclude parameter lets you specify exactly
      this.  With the exclude parameter, the pattern will
      not match.
  
      >>> a = Wild('a', exclude=[x, y])
      >>> b = Wild('b', exclude=[x, y])
      >>> (2 + 3*y).match(a*x + b*y)
  
      Exclude also helps remove ambiguity from matches.
  
      >>> E = 2*x**3*y*z
      >>> a, b = symbols('a b', cls=Wild)
      >>> E.match(a*b)
      {a_: 2*y*z, b_: x**3}
      >>> a = Wild('a', exclude=[x, y])
      >>> E.match(a*b)
      {a_: z, b_: 2*x**3*y}
      >>> a = Wild('a', exclude=[x, y, z])
      >>> E.match(a*b)
      {a_: 2, b_: x**3*y*z}
  
      Wild also accepts a ``properties`` parameter:
  
      >>> a = Wild('a', properties=[lambda k: k.is_Integer])
      >>> E.match(a*b)
      {a_: 2, b_: x**3*y*z}
  
      """
      is_Wild = True
  
      __slots__ = ['exclude', 'properties']
  
      def __new__(cls, name, exclude=(), properties=(), **assumptions):
          exclude = tuple([sympify(x) for x in exclude])
          properties = tuple(properties)
          cls._sanitize(assumptions, cls)
          return Wild.__xnew__(cls, name, exclude, properties, **assumptions)
  
      def __getnewargs__(self):
          return (self.name, self.exclude, self.properties)
  
      @staticmethod
      @cacheit
      def __xnew__(cls, name, exclude, properties, **assumptions):
          obj = Symbol.__xnew__(cls, name, **assumptions)
          obj.exclude = exclude
          obj.properties = properties
          return obj
  
      def _hashable_content(self):
          return super(Wild, self)._hashable_content() + (self.exclude, self.properties)
  
      # TODO add check against another Wild
      def matches(self, expr, repl_dict={}, old=False):
          if any(expr.has(x) for x in self.exclude):
              return None
          if any(not f(expr) for f in self.properties):
              return None
          repl_dict = repl_dict.copy()
          repl_dict[self] = expr
          return repl_dict
  
  
  _range = _re.compile('([0-9]*:[0-9]+|[a-zA-Z]?:[a-zA-Z])')
  
  def symbols(names, **args):
      r"""
      Transform strings into instances of :class:`Symbol` class.
  
      :func:`symbols` function returns a sequence of symbols with names taken
      from ``names`` argument, which can be a comma or whitespace delimited
      string, or a sequence of strings::
  
          >>> from sympy import symbols, Function
  
          >>> x, y, z = symbols('x,y,z')
          >>> a, b, c = symbols('a b c')
  
      The type of output is dependent on the properties of input arguments::
  
          >>> symbols('x')
          x
          >>> symbols('x,')
          (x,)
          >>> symbols('x,y')
          (x, y)
          >>> symbols(('a', 'b', 'c'))
          (a, b, c)
          >>> symbols(['a', 'b', 'c'])
          [a, b, c]
          >>> symbols({'a', 'b', 'c'})
          {a, b, c}
  
      If an iterable container is needed for a single symbol, set the ``seq``
      argument to ``True`` or terminate the symbol name with a comma::
  
          >>> symbols('x', seq=True)
          (x,)
  
      To reduce typing, range syntax is supported to create indexed symbols.
      Ranges are indicated by a colon and the type of range is determined by
      the character to the right of the colon. If the character is a digit
      then all contiguous digits to the left are taken as the nonnegative
      starting value (or 0 if there is no digit left of the colon) and all
      contiguous digits to the right are taken as 1 greater than the ending
      value::
  
          >>> symbols('x:10')
          (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9)
  
          >>> symbols('x5:10')
          (x5, x6, x7, x8, x9)
          >>> symbols('x5(:2)')
          (x50, x51)
  
          >>> symbols('x5:10,y:5')
          (x5, x6, x7, x8, x9, y0, y1, y2, y3, y4)
  
          >>> symbols(('x5:10', 'y:5'))
          ((x5, x6, x7, x8, x9), (y0, y1, y2, y3, y4))
  
      If the character to the right of the colon is a letter, then the single
      letter to the left (or 'a' if there is none) is taken as the start
      and all characters in the lexicographic range *through* the letter to
      the right are used as the range::
  
          >>> symbols('x:z')
          (x, y, z)
          >>> symbols('x:c')  # null range
          ()
          >>> symbols('x(:c)')
          (xa, xb, xc)
  
          >>> symbols(':c')
          (a, b, c)
  
          >>> symbols('a:d, x:z')
          (a, b, c, d, x, y, z)
  
          >>> symbols(('a:d', 'x:z'))
          ((a, b, c, d), (x, y, z))
  
      Multiple ranges are supported; contiguous numerical ranges should be
      separated by parentheses to disambiguate the ending number of one
      range from the starting number of the next::
  
          >>> symbols('x:2(1:3)')
          (x01, x02, x11, x12)
          >>> symbols(':3:2')  # parsing is from left to right
          (00, 01, 10, 11, 20, 21)
  
      Only one pair of parentheses surrounding ranges are removed, so to
      include parentheses around ranges, double them. And to include spaces,
      commas, or colons, escape them with a backslash::
  
          >>> symbols('x((a:b))')
          (x(a), x(b))
          >>> symbols(r'x(:1\,:2)')  # or r'x((:1)\,(:2))'
          (x(0,0), x(0,1))
  
      All newly created symbols have assumptions set according to ``args``::
  
          >>> a = symbols('a', integer=True)
          >>> a.is_integer
          True
  
          >>> x, y, z = symbols('x,y,z', real=True)
          >>> x.is_real and y.is_real and z.is_real
          True
  
      Despite its name, :func:`symbols` can create symbol-like objects like
      instances of Function or Wild classes. To achieve this, set ``cls``
      keyword argument to the desired type::
  
          >>> symbols('f,g,h', cls=Function)
          (f, g, h)
  
          >>> type(_[0])
          <class 'sympy.core.function.UndefinedFunction'>
  
      """
      result = []
  
      if isinstance(names, string_types):
          marker = 0
          literals = [r'\,', r'\:', r'\ ']
          for i in range(len(literals)):
              lit = literals.pop(0)
              if lit in names:
                  while chr(marker) in names:
                      marker += 1
                  lit_char = chr(marker)
                  marker += 1
                  names = names.replace(lit, lit_char)
                  literals.append((lit_char, lit[1:]))
          def literal(s):
              if literals:
                  for c, l in literals:
                      s = s.replace(c, l)
              return s
  
          names = names.strip()
          as_seq = names.endswith(',')
          if as_seq:
              names = names[:-1].rstrip()
          if not names:
              raise ValueError('no symbols given')
  
          # split on commas
          names = [n.strip() for n in names.split(',')]
          if not all(n for n in names):
              raise ValueError('missing symbol between commas')
          # split on spaces
          for i in range(len(names) - 1, -1, -1):
              names[i: i + 1] = names[i].split()
  
          cls = args.pop('cls', Symbol)
          seq = args.pop('seq', as_seq)
  
          for name in names:
              if not name:
                  raise ValueError('missing symbol')
  
              if ':' not in name:
                  symbol = cls(literal(name), **args)
                  result.append(symbol)
                  continue
  
              split = _range.split(name)
              # remove 1 layer of bounding parentheses around ranges
              for i in range(len(split) - 1):
                  if i and ':' in split[i] and split[i] != ':' and \
                          split[i - 1].endswith('(') and \
                          split[i + 1].startswith(')'):
                      split[i - 1] = split[i - 1][:-1]
                      split[i + 1] = split[i + 1][1:]
              for i, s in enumerate(split):
                  if ':' in s:
                      if s[-1].endswith(':'):
                          raise ValueError('missing end range')
                      a, b = s.split(':')
                      if b[-1] in string.digits:
                          a = 0 if not a else int(a)
                          b = int(b)
                          split[i] = [str(c) for c in range(a, b)]
                      else:
                          a = a or 'a'
                          split[i] = [string.ascii_letters[c] for c in range(
                              string.ascii_letters.index(a),
                              string.ascii_letters.index(b) + 1)]  # inclusive
                      if not split[i]:
                          break
                  else:
                      split[i] = [s]
              else:
                  seq = True
                  if len(split) == 1:
                      names = split[0]
                  else:
                      names = [''.join(s) for s in cartes(*split)]
                  if literals:
                      result.extend([cls(literal(s), **args) for s in names])
                  else:
                      result.extend([cls(s, **args) for s in names])
  
          if not seq and len(result) <= 1:
              if not result:
                  return ()
              return result[0]
  
          return tuple(result)
      else:
          for name in names:
              result.append(symbols(name, **args))
  
          return type(names)(result)
  
  
  def var(names, **args):
      """
      Create symbols and inject them into the global namespace.
  
      This calls :func:`symbols` with the same arguments and puts the results
      into the *global* namespace. It's recommended not to use :func:`var` in
      library code, where :func:`symbols` has to be used::
  
      Examples
      ========
  
      >>> from sympy import var
  
      >>> var('x')
      x
      >>> x
      x
  
      >>> var('a,ab,abc')
      (a, ab, abc)
      >>> abc
      abc
  
      >>> var('x,y', real=True)
      (x, y)
      >>> x.is_real and y.is_real
      True
  
      See :func:`symbol` documentation for more details on what kinds of
      arguments can be passed to :func:`var`.
  
      """
      def traverse(symbols, frame):
          """Recursively inject symbols to the global namespace. """
          for symbol in symbols:
              if isinstance(symbol, Basic):
                  frame.f_globals[symbol.name] = symbol
              elif isinstance(symbol, FunctionClass):
                  frame.f_globals[symbol.__name__] = symbol
              else:
                  traverse(symbol, frame)
  
      from inspect import currentframe
      frame = currentframe().f_back
  
      try:
          syms = symbols(names, **args)
  
          if syms is not None:
              if isinstance(syms, Basic):
                  frame.f_globals[syms.name] = syms
              elif isinstance(syms, FunctionClass):
                  frame.f_globals[syms.__name__] = syms
              else:
                  traverse(syms, frame)
      finally:
          del frame  # break cyclic dependencies as stated in inspect docs
  
      return syms
  
  def disambiguate(*iter):
      """
      Return a Tuple containing the passed expressions with symbols
      that appear the same when printed replaced with numerically
      subscripted symbols, and all Dummy symbols replaced with Symbols.
  
      Parameters
      ==========
  
      iter: list of symbols or expressions.
  
      Examples
      ========
  
      >>> from sympy.core.symbol import disambiguate
      >>> from sympy import Dummy, Symbol, Tuple
      >>> from sympy.abc import y
  
      >>> tup = Symbol('_x'), Dummy('x'), Dummy('x')
      >>> disambiguate(*tup)
      (x_2, x, x_1)
  
      >>> eqs = Tuple(Symbol('x')/y, Dummy('x')/y)
      >>> disambiguate(*eqs)
      (x_1/y, x/y)
  
      >>> ix = Symbol('x', integer=True)
      >>> vx = Symbol('x')
      >>> disambiguate(vx + ix)
      (x + x_1,)
  
      To make your own mapping of symbols to use, pass only the free symbols
      of the expressions and create a dictionary:
  
      >>> free = eqs.free_symbols
      >>> mapping = dict(zip(free, disambiguate(*free)))
      >>> eqs.xreplace(mapping)
      (x_1/y, x/y)
  
      """
      new_iter = Tuple(*iter)
      key = lambda x:tuple(sorted(x.assumptions0.items()))
      syms = ordered(new_iter.free_symbols, keys=key)
      mapping = {}
      for s in syms:
          mapping.setdefault(str(s).lstrip('_'), []).append(s)
      reps = {}
      for k in mapping:
          # the first or only symbol doesn't get subscripted but make
          # sure that it's a Symbol, not a Dummy
          mapk0 = Symbol("%s" % (k), **mapping[k][0].assumptions0)
          if mapping[k][0] != mapk0:
              reps[mapping[k][0]] = mapk0
          # the others get subscripts (and are made into Symbols)
          skip = 0
          for i in range(1, len(mapping[k])):
              while True:
                  name = "%s_%i" % (k, i + skip)
                  if name not in mapping:
                      break
                  skip += 1
              ki = mapping[k][i]
              reps[ki] = Symbol(name, **ki.assumptions0)
      return new_iter.xreplace(reps)
  