text: from __future__ import print_function, division
  
  from sympy.core.assumptions import StdFactKB
  from sympy.core.compatibility import string_types
  from .basic import Basic
  from .core import C
  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
  from sympy.utilities.exceptions import SymPyDeprecationWarning
  
  import string
  import re as _re
  
  
  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
  
      @property
      def _diff_wrt(self):
          """Allow derivatives wrt Symbols.
  
          Examples
          ========
  
              >>> from sympy import Symbol
              >>> x = Symbol('x')
              >>> x._diff_wrt
              True
          """
          return True
  
      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
  
          """
  
          if assumptions.get('zero', False):
              return S.Zero
          is_commutative = fuzzy_bool(assumptions.get('commutative', True))
          if is_commutative is None:
              raise ValueError(
                  '''Symbol commutativity must be True or False.''')
          assumptions['commutative'] = is_commutative
          for key in assumptions.keys():
              assumptions[key] = bool(assumptions[key])
          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
          obj._assumptions = StdFactKB(assumptions)
          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):
          return (self.name,) + tuple(sorted(self.assumptions0.items()))
  
      @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, **self.assumptions0)
  
      def __call__(self, *args):
          from .function import Function
          return Function(self.name)(*args)
  
      def as_real_imag(self, deep=True, **hints):
          if hints.get('ignore') == self:
              return None
          else:
              return (C.re(self), C.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 is_number(self):
          return False
  
      @property
      def free_symbols(self):
          return set([self])
  
  
  class Dummy(Symbol):
      """Dummy symbols are each unique, identified by an internal count index:
  
      >>> from sympy import Dummy
      >>> bool(Dummy("x") == Dummy("x")) == True
      False
  
      If a name is not supplied then a string value of the count index 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
  
      """
  
      _count = 0
  
      __slots__ = ['dummy_index']
  
      is_Dummy = True
  
      def __new__(cls, name=None, **assumptions):
          if name is None:
              name = "Dummy_" + str(Dummy._count)
  
          is_commutative = fuzzy_bool(assumptions.get('commutative', True))
          if is_commutative is None:
              raise ValueError(
                  '''Dummy's commutativity must be True or False.''')
          assumptions['commutative'] = is_commutative
          obj = Symbol.__xnew__(cls, name, **assumptions)
  
          Dummy._count += 1
          obj.dummy_index = Dummy._count
          return obj
  
      def __getstate__(self):
          return {'_assumptions': self._assumptions, 'dummy_index': self.dummy_index}
  
      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.
  
      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}
  
      """
  
      __slots__ = ['exclude', 'properties']
      is_Wild = True
  
      def __new__(cls, name, exclude=(), properties=(), **assumptions):
          exclude = tuple([sympify(x) for x in exclude])
          properties = tuple(properties)
          is_commutative = fuzzy_bool(assumptions.get('commutative', True))
          if is_commutative is None:
              raise ValueError(
                  '''Wild's commutativity must be True or False.''')
          assumptions['commutative'] = is_commutative
          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
  
      def __call__(self, *args, **kwargs):
          raise TypeError("'%s' object is not callable" % type(self).__name__)
  
  
  _range = _re.compile('([0-9]*:[0-9]+|[a-zA-Z]?:[a-zA-Z])')
  
  def symbols(names, **args):
      """
      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(set(['a', 'b', 'c']))
          set([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 continguous digits to the left are taken as the nonnegative
      starting value (or 0 if there are no digit 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('x(:1\,:2)')  # or '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 = ['\,', '\:', '\ ']
          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::
  
          >>> 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
  