text: from __future__ import print_function, division
  
  import itertools
  
  from sympy.core import S
  from sympy.core.containers import Tuple
  from sympy.core.function import _coeff_isneg
  from sympy.core.mod import Mod
  from sympy.core.mul import Mul
  from sympy.core.numbers import Rational
  from sympy.core.power import Pow
  from sympy.core.relational import Equality
  from sympy.core.symbol import Symbol
  from sympy.printing.precedence import PRECEDENCE, precedence, precedence_traditional
  from sympy.utilities import group
  from sympy.utilities.iterables import has_variety
  from sympy.core.sympify import SympifyError
  from sympy.core.compatibility import range
  from sympy.core.add import Add
  
  from sympy.printing.printer import Printer
  from sympy.printing.str import sstr
  from sympy.printing.conventions import requires_partial
  
  from .stringpict import prettyForm, stringPict
  from .pretty_symbology import xstr, hobj, vobj, xobj, xsym, pretty_symbol, \
      pretty_atom, pretty_use_unicode, pretty_try_use_unicode, greek_unicode, U, \
      annotated
  
  from sympy.utilities import default_sort_key
  
  # rename for usage from outside
  pprint_use_unicode = pretty_use_unicode
  pprint_try_use_unicode = pretty_try_use_unicode
  
  
  class PrettyPrinter(Printer):
      """Printer, which converts an expression into 2D ASCII-art figure."""
      printmethod = "_pretty"
  
      _default_settings = {
          "order": None,
          "full_prec": "auto",
          "use_unicode": None,
          "wrap_line": True,
          "num_columns": None,
          "use_unicode_sqrt_char": True,
      }
  
      def __init__(self, settings=None):
          Printer.__init__(self, settings)
          self.emptyPrinter = lambda x: prettyForm(xstr(x))
  
      @property
      def _use_unicode(self):
          if self._settings['use_unicode']:
              return True
          else:
              return pretty_use_unicode()
  
      def doprint(self, expr):
          return self._print(expr).render(**self._settings)
  
      # empty op so _print(stringPict) returns the same
      def _print_stringPict(self, e):
          return e
  
      def _print_basestring(self, e):
          return prettyForm(e)
  
      def _print_atan2(self, e):
          pform = prettyForm(*self._print_seq(e.args).parens())
          pform = prettyForm(*pform.left('atan2'))
          return pform
  
      def _print_Symbol(self, e):
          symb = pretty_symbol(e.name)
          return prettyForm(symb)
      _print_RandomSymbol = _print_Symbol
  
      def _print_Float(self, e):
          # we will use StrPrinter's Float printer, but we need to handle the
          # full_prec ourselves, according to the self._print_level
          full_prec = self._settings["full_prec"]
          if full_prec == "auto":
              full_prec = self._print_level == 1
          return prettyForm(sstr(e, full_prec=full_prec))
  
      def _print_Cross(self, e):
          vec1 = e._expr1
          vec2 = e._expr2
          pform = self._print(vec2)
          pform = prettyForm(*pform.left('('))
          pform = prettyForm(*pform.right(')'))
          pform = prettyForm(*pform.left(self._print(U('MULTIPLICATION SIGN'))))
          pform = prettyForm(*pform.left(')'))
          pform = prettyForm(*pform.left(self._print(vec1)))
          pform = prettyForm(*pform.left('('))
          return pform
  
      def _print_Curl(self, e):
          vec = e._expr
          pform = self._print(vec)
          pform = prettyForm(*pform.left('('))
          pform = prettyForm(*pform.right(')'))
          pform = prettyForm(*pform.left(self._print(U('MULTIPLICATION SIGN'))))
          pform = prettyForm(*pform.left(self._print(U('NABLA'))))
          return pform
  
      def _print_Divergence(self, e):
          vec = e._expr
          pform = self._print(vec)
          pform = prettyForm(*pform.left('('))
          pform = prettyForm(*pform.right(')'))
          pform = prettyForm(*pform.left(self._print(U('DOT OPERATOR'))))
          pform = prettyForm(*pform.left(self._print(U('NABLA'))))
          return pform
  
      def _print_Dot(self, e):
          vec1 = e._expr1
          vec2 = e._expr2
          pform = self._print(vec2)
          pform = prettyForm(*pform.left('('))
          pform = prettyForm(*pform.right(')'))
          pform = prettyForm(*pform.left(self._print(U('DOT OPERATOR'))))
          pform = prettyForm(*pform.left(')'))
          pform = prettyForm(*pform.left(self._print(vec1)))
          pform = prettyForm(*pform.left('('))
          return pform
  
      def _print_Gradient(self, e):
          func = e._expr
          pform = self._print(func)
          pform = prettyForm(*pform.left('('))
          pform = prettyForm(*pform.right(')'))
          pform = prettyForm(*pform.left(self._print(U('DOT OPERATOR'))))
          pform = prettyForm(*pform.left(self._print(U('NABLA'))))
          return pform
  
      def _print_Atom(self, e):
          try:
              # print atoms like Exp1 or Pi
              return prettyForm(pretty_atom(e.__class__.__name__))
          except KeyError:
              return self.emptyPrinter(e)
  
      # Infinity inherits from Number, so we have to override _print_XXX order
      _print_Infinity = _print_Atom
      _print_NegativeInfinity = _print_Atom
      _print_EmptySet = _print_Atom
      _print_Naturals = _print_Atom
      _print_Naturals0 = _print_Atom
      _print_Integers = _print_Atom
      _print_Complexes = _print_Atom
  
      def _print_Reals(self, e):
          if self._use_unicode:
              return self._print_Atom(e)
          else:
              inf_list = ['-oo', 'oo']
              return self._print_seq(inf_list, '(', ')')
  
      def _print_subfactorial(self, e):
          x = e.args[0]
          pform = self._print(x)
          # Add parentheses if needed
          if not ((x.is_Integer and x.is_nonnegative) or x.is_Symbol):
              pform = prettyForm(*pform.parens())
          pform = prettyForm(*pform.left('!'))
          return pform
  
      def _print_factorial(self, e):
          x = e.args[0]
          pform = self._print(x)
          # Add parentheses if needed
          if not ((x.is_Integer and x.is_nonnegative) or x.is_Symbol):
              pform = prettyForm(*pform.parens())
          pform = prettyForm(*pform.right('!'))
          return pform
  
      def _print_factorial2(self, e):
          x = e.args[0]
          pform = self._print(x)
          # Add parentheses if needed
          if not ((x.is_Integer and x.is_nonnegative) or x.is_Symbol):
              pform = prettyForm(*pform.parens())
          pform = prettyForm(*pform.right('!!'))
          return pform
  
      def _print_binomial(self, e):
          n, k = e.args
  
          n_pform = self._print(n)
          k_pform = self._print(k)
  
          bar = ' '*max(n_pform.width(), k_pform.width())
  
          pform = prettyForm(*k_pform.above(bar))
          pform = prettyForm(*pform.above(n_pform))
          pform = prettyForm(*pform.parens('(', ')'))
  
          pform.baseline = (pform.baseline + 1)//2
  
          return pform
  
      def _print_Relational(self, e):
          op = prettyForm(' ' + xsym(e.rel_op) + ' ')
  
          l = self._print(e.lhs)
          r = self._print(e.rhs)
          pform = prettyForm(*stringPict.next(l, op, r))
          return pform
  
      def _print_Not(self, e):
          from sympy import Equivalent, Implies
          if self._use_unicode:
              arg = e.args[0]
              pform = self._print(arg)
              if isinstance(arg, Equivalent):
                  return self._print_Equivalent(arg, altchar=u"\N{LEFT RIGHT DOUBLE ARROW WITH STROKE}")
              if isinstance(arg, Implies):
                  return self._print_Implies(arg, altchar=u"\N{RIGHTWARDS ARROW WITH STROKE}")
  
              if arg.is_Boolean and not arg.is_Not:
                  pform = prettyForm(*pform.parens())
  
              return prettyForm(*pform.left(u"\N{NOT SIGN}"))
          else:
              return self._print_Function(e)
  
      def __print_Boolean(self, e, char, sort=True):
          args = e.args
          if sort:
              args = sorted(e.args, key=default_sort_key)
          arg = args[0]
          pform = self._print(arg)
  
          if arg.is_Boolean and not arg.is_Not:
              pform = prettyForm(*pform.parens())
  
          for arg in args[1:]:
              pform_arg = self._print(arg)
  
              if arg.is_Boolean and not arg.is_Not:
                  pform_arg = prettyForm(*pform_arg.parens())
  
              pform = prettyForm(*pform.right(u' %s ' % char))
              pform = prettyForm(*pform.right(pform_arg))
  
          return pform
  
      def _print_And(self, e):
          if self._use_unicode:
              return self.__print_Boolean(e, u"\N{LOGICAL AND}")
          else:
              return self._print_Function(e, sort=True)
  
      def _print_Or(self, e):
          if self._use_unicode:
              return self.__print_Boolean(e, u"\N{LOGICAL OR}")
          else:
              return self._print_Function(e, sort=True)
  
      def _print_Xor(self, e):
          if self._use_unicode:
              return self.__print_Boolean(e, u"\N{XOR}")
          else:
              return self._print_Function(e, sort=True)
  
      def _print_Nand(self, e):
          if self._use_unicode:
              return self.__print_Boolean(e, u"\N{NAND}")
          else:
              return self._print_Function(e, sort=True)
  
      def _print_Nor(self, e):
          if self._use_unicode:
              return self.__print_Boolean(e, u"\N{NOR}")
          else:
              return self._print_Function(e, sort=True)
  
      def _print_Implies(self, e, altchar=None):
          if self._use_unicode:
              return self.__print_Boolean(e, altchar or u"\N{RIGHTWARDS ARROW}", sort=False)
          else:
              return self._print_Function(e)
  
      def _print_Equivalent(self, e, altchar=None):
          if self._use_unicode:
              return self.__print_Boolean(e, altchar or u"\N{LEFT RIGHT DOUBLE ARROW}")
          else:
              return self._print_Function(e, sort=True)
  
      def _print_conjugate(self, e):
          pform = self._print(e.args[0])
          return prettyForm( *pform.above( hobj('_', pform.width())) )
  
      def _print_Abs(self, e):
          pform = self._print(e.args[0])
          pform = prettyForm(*pform.parens('|', '|'))
          return pform
      _print_Determinant = _print_Abs
  
      def _print_floor(self, e):
          if self._use_unicode:
              pform = self._print(e.args[0])
              pform = prettyForm(*pform.parens('lfloor', 'rfloor'))
              return pform
          else:
              return self._print_Function(e)
  
      def _print_ceiling(self, e):
          if self._use_unicode:
              pform = self._print(e.args[0])
              pform = prettyForm(*pform.parens('lceil', 'rceil'))
              return pform
          else:
              return self._print_Function(e)
  
      def _print_Derivative(self, deriv):
          if requires_partial(deriv) and self._use_unicode:
              deriv_symbol = U('PARTIAL DIFFERENTIAL')
          else:
              deriv_symbol = r'd'
          x = None
          count_total_deriv = 0
  
          for sym, num in reversed(deriv.variable_count):
              s = self._print(sym)
              ds = prettyForm(*s.left(deriv_symbol))
              count_total_deriv += num
  
              if (not num.is_Integer) or (num > 1):
                  ds = ds**prettyForm(str(num))
  
              if x is None:
                  x = ds
              else:
                  x = prettyForm(*x.right(' '))
                  x = prettyForm(*x.right(ds))
  
          f = prettyForm(
              binding=prettyForm.FUNC, *self._print(deriv.expr).parens())
  
          pform = prettyForm(deriv_symbol)
  
          if (count_total_deriv > 1) != False:
              pform = pform**prettyForm(str(count_total_deriv))
  
          pform = prettyForm(*pform.below(stringPict.LINE, x))
          pform.baseline = pform.baseline + 1
          pform = prettyForm(*stringPict.next(pform, f))
          pform.binding = prettyForm.MUL
  
          return pform
  
      def _print_Cycle(self, dc):
          from sympy.combinatorics.permutations import Permutation, Cycle
          # for Empty Cycle
          if dc == Cycle():
              cyc = stringPict('')
              return prettyForm(*cyc.parens())
  
          dc_list = Permutation(dc.list()).cyclic_form
          # for Identity Cycle
          if dc_list == []:
              cyc = self._print(dc.size - 1)
              return prettyForm(*cyc.parens())
  
          cyc = stringPict('')
          for i in dc_list:
              l = self._print(str(tuple(i)).replace(',', ''))
              cyc = prettyForm(*cyc.right(l))
          return cyc
  
      def _print_PDF(self, pdf):
          lim = self._print(pdf.pdf.args[0])
          lim = prettyForm(*lim.right(', '))
          lim = prettyForm(*lim.right(self._print(pdf.domain[0])))
          lim = prettyForm(*lim.right(', '))
          lim = prettyForm(*lim.right(self._print(pdf.domain[1])))
          lim = prettyForm(*lim.parens())
  
          f = self._print(pdf.pdf.args[1])
          f = prettyForm(*f.right(', '))
          f = prettyForm(*f.right(lim))
          f = prettyForm(*f.parens())
  
          pform = prettyForm('PDF')
          pform = prettyForm(*pform.right(f))
          return pform
  
      def _print_Integral(self, integral):
          f = integral.function
  
          # Add parentheses if arg involves addition of terms and
          # create a pretty form for the argument
          prettyF = self._print(f)
          # XXX generalize parens
          if f.is_Add:
              prettyF = prettyForm(*prettyF.parens())
  
          # dx dy dz ...
          arg = prettyF
          for x in integral.limits:
              prettyArg = self._print(x[0])
              # XXX qparens (parens if needs-parens)
              if prettyArg.width() > 1:
                  prettyArg = prettyForm(*prettyArg.parens())
  
              arg = prettyForm(*arg.right(' d', prettyArg))
  
          # \int \int \int ...
          firstterm = True
          s = None
          for lim in integral.limits:
              x = lim[0]
              # Create bar based on the height of the argument
              h = arg.height()
              H = h + 2
  
              # XXX hack!
              ascii_mode = not self._use_unicode
              if ascii_mode:
                  H += 2
  
              vint = vobj('int', H)
  
              # Construct the pretty form with the integral sign and the argument
              pform = prettyForm(vint)
              pform.baseline = arg.baseline + (
                  H - h)//2    # covering the whole argument
  
              if len(lim) > 1:
                  # Create pretty forms for endpoints, if definite integral.
                  # Do not print empty endpoints.
                  if len(lim) == 2:
                      prettyA = prettyForm("")
                      prettyB = self._print(lim[1])
                  if len(lim) == 3:
                      prettyA = self._print(lim[1])
                      prettyB = self._print(lim[2])
  
                  if ascii_mode:  # XXX hack
                      # Add spacing so that endpoint can more easily be
                      # identified with the correct integral sign
                      spc = max(1, 3 - prettyB.width())
                      prettyB = prettyForm(*prettyB.left(' ' * spc))
  
                      spc = max(1, 4 - prettyA.width())
                      prettyA = prettyForm(*prettyA.right(' ' * spc))
  
                  pform = prettyForm(*pform.above(prettyB))
                  pform = prettyForm(*pform.below(prettyA))
  
              if not ascii_mode:  # XXX hack
                  pform = prettyForm(*pform.right(' '))
  
              if firstterm:
                  s = pform   # first term
                  firstterm = False
              else:
                  s = prettyForm(*s.left(pform))
  
          pform = prettyForm(*arg.left(s))
          pform.binding = prettyForm.MUL
          return pform
  
      def _print_Product(self, expr):
          func = expr.term
          pretty_func = self._print(func)
  
          horizontal_chr = xobj('_', 1)
          corner_chr = xobj('_', 1)
          vertical_chr = xobj('|', 1)
  
          if self._use_unicode:
              # use unicode corners
              horizontal_chr = xobj('-', 1)
              corner_chr = u'\N{BOX DRAWINGS LIGHT DOWN AND HORIZONTAL}'
  
          func_height = pretty_func.height()
  
          first = True
          max_upper = 0
          sign_height = 0
  
          for lim in expr.limits:
              width = (func_height + 2) * 5 // 3 - 2
              sign_lines = []
              sign_lines.append(corner_chr + (horizontal_chr*width) + corner_chr)
              for i in range(func_height + 1):
                  sign_lines.append(vertical_chr + (' '*width) + vertical_chr)
  
              pretty_sign = stringPict('')
              pretty_sign = prettyForm(*pretty_sign.stack(*sign_lines))
  
              pretty_upper = self._print(lim[2])
              pretty_lower = self._print(Equality(lim[0], lim[1]))
  
              max_upper = max(max_upper, pretty_upper.height())
  
              if first:
                  sign_height = pretty_sign.height()
  
              pretty_sign = prettyForm(*pretty_sign.above(pretty_upper))
              pretty_sign = prettyForm(*pretty_sign.below(pretty_lower))
  
              if first:
                  pretty_func.baseline = 0
                  first = False
  
              height = pretty_sign.height()
              padding = stringPict('')
              padding = prettyForm(*padding.stack(*[' ']*(height - 1)))
              pretty_sign = prettyForm(*pretty_sign.right(padding))
  
              pretty_func = prettyForm(*pretty_sign.right(pretty_func))
  
          pretty_func.baseline = max_upper + sign_height//2
          pretty_func.binding = prettyForm.MUL
          return pretty_func
  
      def _print_Sum(self, expr):
          ascii_mode = not self._use_unicode
  
          def asum(hrequired, lower, upper, use_ascii):
              def adjust(s, wid=None, how='<^>'):
                  if not wid or len(s) > wid:
                      return s
                  need = wid - len(s)
                  if how == '<^>' or how == "<" or how not in list('<^>'):
                      return s + ' '*need
                  half = need//2
                  lead = ' '*half
                  if how == ">":
                      return " "*need + s
                  return lead + s + ' '*(need - len(lead))
  
              h = max(hrequired, 2)
              d = h//2
              w = d + 1
              more = hrequired % 2
  
              lines = []
              if use_ascii:
                  lines.append("_"*(w) + ' ')
                  lines.append(r"\%s`" % (' '*(w - 1)))
                  for i in range(1, d):
                      lines.append('%s\\%s' % (' '*i, ' '*(w - i)))
                  if more:
                      lines.append('%s)%s' % (' '*(d), ' '*(w - d)))
                  for i in reversed(range(1, d)):
                      lines.append('%s/%s' % (' '*i, ' '*(w - i)))
                  lines.append("/" + "_"*(w - 1) + ',')
                  return d, h + more, lines, 0
              else:
                  w = w + more
                  d = d + more
                  vsum = vobj('sum', 4)
                  lines.append("_"*(w))
                  for i in range(0, d):
                      lines.append('%s%s%s' % (' '*i, vsum[2], ' '*(w - i - 1)))
                  for i in reversed(range(0, d)):
                      lines.append('%s%s%s' % (' '*i, vsum[4], ' '*(w - i - 1)))
                  lines.append(vsum[8]*(w))
                  return d, h + 2*more, lines, more
  
          f = expr.function
  
          prettyF = self._print(f)
  
          if f.is_Add:  # add parens
              prettyF = prettyForm(*prettyF.parens())
  
          H = prettyF.height() + 2
  
          # \sum \sum \sum ...
          first = True
          max_upper = 0
          sign_height = 0
  
          for lim in expr.limits:
              if len(lim) == 3:
                  prettyUpper = self._print(lim[2])
                  prettyLower = self._print(Equality(lim[0], lim[1]))
              elif len(lim) == 2:
                  prettyUpper = self._print("")
                  prettyLower = self._print(Equality(lim[0], lim[1]))
              elif len(lim) == 1:
                  prettyUpper = self._print("")
                  prettyLower = self._print(lim[0])
  
              max_upper = max(max_upper, prettyUpper.height())
  
              # Create sum sign based on the height of the argument
              d, h, slines, adjustment = asum(
                  H, prettyLower.width(), prettyUpper.width(), ascii_mode)
              prettySign = stringPict('')
              prettySign = prettyForm(*prettySign.stack(*slines))
  
              if first:
                  sign_height = prettySign.height()
  
              prettySign = prettyForm(*prettySign.above(prettyUpper))
              prettySign = prettyForm(*prettySign.below(prettyLower))
  
              if first:
                  # change F baseline so it centers on the sign
                  prettyF.baseline -= d - (prettyF.height()//2 -
                                           prettyF.baseline) - adjustment
                  first = False
  
              # put padding to the right
              pad = stringPict('')
              pad = prettyForm(*pad.stack(*[' ']*h))
              prettySign = prettyForm(*prettySign.right(pad))
              # put the present prettyF to the right
              prettyF = prettyForm(*prettySign.right(prettyF))
  
          prettyF.baseline = max_upper + sign_height//2
          prettyF.binding = prettyForm.MUL
          return prettyF
  
      def _print_Limit(self, l):
          e, z, z0, dir = l.args
  
          E = self._print(e)
          if precedence(e) <= PRECEDENCE["Mul"]:
              E = prettyForm(*E.parens('(', ')'))
          Lim = prettyForm('lim')
  
          LimArg = self._print(z)
          if self._use_unicode:
              LimArg = prettyForm(*LimArg.right(u'\N{BOX DRAWINGS LIGHT HORIZONTAL}\N{RIGHTWARDS ARROW}'))
          else:
              LimArg = prettyForm(*LimArg.right('->'))
          LimArg = prettyForm(*LimArg.right(self._print(z0)))
  
          if str(dir) == '+-' or z0 in (S.Infinity, S.NegativeInfinity):
              dir = ""
          else:
              if self._use_unicode:
                  dir = u'\N{SUPERSCRIPT PLUS SIGN}' if str(dir) == "+" else u'\N{SUPERSCRIPT MINUS}'
  
          LimArg = prettyForm(*LimArg.right(self._print(dir)))
  
          Lim = prettyForm(*Lim.below(LimArg))
          Lim = prettyForm(*Lim.right(E), binding=prettyForm.MUL)
  
          return Lim
  
      def _print_matrix_contents(self, e):
          """
          This method factors out what is essentially grid printing.
          """
          M = e   # matrix
          Ms = {}  # i,j -> pretty(M[i,j])
          for i in range(M.rows):
              for j in range(M.cols):
                  Ms[i, j] = self._print(M[i, j])
  
          # h- and v- spacers
          hsep = 2
          vsep = 1
  
          # max width for columns
          maxw = [-1] * M.cols
  
          for j in range(M.cols):
              maxw[j] = max([Ms[i, j].width() for i in range(M.rows)] or [0])
  
          # drawing result
          D = None
  
          for i in range(M.rows):
  
              D_row = None
              for j in range(M.cols):
                  s = Ms[i, j]
  
                  # reshape s to maxw
                  # XXX this should be generalized, and go to stringPict.reshape ?
                  assert s.width() <= maxw[j]
  
                  # hcenter it, +0.5 to the right                        2
                  # ( it's better to align formula starts for say 0 and r )
                  # XXX this is not good in all cases -- maybe introduce vbaseline?
                  wdelta = maxw[j] - s.width()
                  wleft = wdelta // 2
                  wright = wdelta - wleft
  
                  s = prettyForm(*s.right(' '*wright))
                  s = prettyForm(*s.left(' '*wleft))
  
                  # we don't need vcenter cells -- this is automatically done in
                  # a pretty way because when their baselines are taking into
                  # account in .right()
  
                  if D_row is None:
                      D_row = s   # first box in a row
                      continue
  
                  D_row = prettyForm(*D_row.right(' '*hsep))  # h-spacer
                  D_row = prettyForm(*D_row.right(s))
  
              if D is None:
                  D = D_row       # first row in a picture
                  continue
  
              # v-spacer
              for _ in range(vsep):
                  D = prettyForm(*D.below(' '))
  
              D = prettyForm(*D.below(D_row))
  
          if D is None:
              D = prettyForm('')  # Empty Matrix
  
          return D
  
      def _print_MatrixBase(self, e):
          D = self._print_matrix_contents(e)
          D.baseline = D.height()//2
          D = prettyForm(*D.parens('[', ']'))
          return D
      _print_ImmutableMatrix = _print_MatrixBase
      _print_Matrix = _print_MatrixBase
  
      def _print_TensorProduct(self, expr):
          # This should somehow share the code with _print_WedgeProduct:
          circled_times = "\u2297"
          return self._print_seq(expr.args, None, None, circled_times,
              parenthesize=lambda x: precedence_traditional(x) <= PRECEDENCE["Mul"])
  
      def _print_WedgeProduct(self, expr):
          # This should somehow share the code with _print_TensorProduct:
          wedge_symbol = u"\u2227"
          return self._print_seq(expr.args, None, None, wedge_symbol,
              parenthesize=lambda x: precedence_traditional(x) <= PRECEDENCE["Mul"])
  
      def _print_Trace(self, e):
          D = self._print(e.arg)
          D = prettyForm(*D.parens('(',')'))
          D.baseline = D.height()//2
          D = prettyForm(*D.left('\n'*(0) + 'tr'))
          return D
  
  
      def _print_MatrixElement(self, expr):
          from sympy.matrices import MatrixSymbol
          from sympy import Symbol
          if (isinstance(expr.parent, MatrixSymbol)
                  and expr.i.is_number and expr.j.is_number):
              return self._print(
                      Symbol(expr.parent.name + '_%d%d' % (expr.i, expr.j)))
          else:
              prettyFunc = self._print(expr.parent)
              prettyFunc = prettyForm(*prettyFunc.parens())
              prettyIndices = self._print_seq((expr.i, expr.j), delimiter=', '
                      ).parens(left='[', right=']')[0]
              pform = prettyForm(binding=prettyForm.FUNC,
                      *stringPict.next(prettyFunc, prettyIndices))
  
              # store pform parts so it can be reassembled e.g. when powered
              pform.prettyFunc = prettyFunc
              pform.prettyArgs = prettyIndices
  
              return pform
  
  
      def _print_MatrixSlice(self, m):
          # XXX works only for applied functions
          prettyFunc = self._print(m.parent)
          def ppslice(x):
              x = list(x)
              if x[2] == 1:
                  del x[2]
              if x[1] == x[0] + 1:
                  del x[1]
              if x[0] == 0:
                  x[0] = ''
              return prettyForm(*self._print_seq(x, delimiter=':'))
          prettyArgs = self._print_seq((ppslice(m.rowslice),
              ppslice(m.colslice)), delimiter=', ').parens(left='[', right=']')[0]
  
          pform = prettyForm(
              binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs))
  
          # store pform parts so it can be reassembled e.g. when powered
          pform.prettyFunc = prettyFunc
          pform.prettyArgs = prettyArgs
  
          return pform
  
      def _print_Transpose(self, expr):
          pform = self._print(expr.arg)
          from sympy.matrices import MatrixSymbol
          if not isinstance(expr.arg, MatrixSymbol):
              pform = prettyForm(*pform.parens())
          pform = pform**(prettyForm('T'))
          return pform
  
      def _print_Adjoint(self, expr):
          pform = self._print(expr.arg)
          if self._use_unicode:
              dag = prettyForm(u'\N{DAGGER}')
          else:
              dag = prettyForm('+')
          from sympy.matrices import MatrixSymbol
          if not isinstance(expr.arg, MatrixSymbol):
              pform = prettyForm(*pform.parens())
          pform = pform**dag
          return pform
  
      def _print_BlockMatrix(self, B):
          if B.blocks.shape == (1, 1):
              return self._print(B.blocks[0, 0])
          return self._print(B.blocks)
  
      def _print_MatAdd(self, expr):
          s = None
          for item in expr.args:
              pform = self._print(item)
              if s is None:
                  s = pform     # First element
              else:
                  coeff = item.as_coeff_mmul()[0]
                  if _coeff_isneg(S(coeff)):
                      s = prettyForm(*stringPict.next(s, ' '))
                      pform = self._print(item)
                  else:
                      s = prettyForm(*stringPict.next(s, ' + '))
                  s = prettyForm(*stringPict.next(s, pform))
  
          return s
  
      def _print_MatMul(self, expr):
          args = list(expr.args)
          from sympy import Add, MatAdd, HadamardProduct
          for i, a in enumerate(args):
              if (isinstance(a, (Add, MatAdd, HadamardProduct))
                      and len(expr.args) > 1):
                  args[i] = prettyForm(*self._print(a).parens())
              else:
                  args[i] = self._print(a)
  
          return prettyForm.__mul__(*args)
  
      def _print_DotProduct(self, expr):
          args = list(expr.args)
  
          for i, a in enumerate(args):
              args[i] = self._print(a)
          return prettyForm.__mul__(*args)
  
      def _print_MatPow(self, expr):
          pform = self._print(expr.base)
          from sympy.matrices import MatrixSymbol
          if not isinstance(expr.base, MatrixSymbol):
              pform = prettyForm(*pform.parens())
          pform = pform**(self._print(expr.exp))
          return pform
  
      def _print_HadamardProduct(self, expr):
          from sympy import MatAdd, MatMul
          if self._use_unicode:
              delim = pretty_atom('Ring')
          else:
              delim = '.*'
          return self._print_seq(expr.args, None, None, delim,
                  parenthesize=lambda x: isinstance(x, (MatAdd, MatMul)))
  
      def _print_KroneckerProduct(self, expr):
          from sympy import MatAdd, MatMul
          if self._use_unicode:
              delim = u' \N{N-ARY CIRCLED TIMES OPERATOR} '
          else:
              delim = ' x '
          return self._print_seq(expr.args, None, None, delim,
                  parenthesize=lambda x: isinstance(x, (MatAdd, MatMul)))
  
      _print_MatrixSymbol = _print_Symbol
  
      def _print_FunctionMatrix(self, X):
          D = self._print(X.lamda.expr)
          D = prettyForm(*D.parens('[', ']'))
          return D
  
      def _print_BasisDependent(self, expr):
          from sympy.vector import Vector
  
          if not self._use_unicode:
              raise NotImplementedError("ASCII pretty printing of BasisDependent is not implemented")
  
          if expr == expr.zero:
              return prettyForm(expr.zero._pretty_form)
          o1 = []
          vectstrs = []
          if isinstance(expr, Vector):
              items = expr.separate().items()
          else:
              items = [(0, expr)]
          for system, vect in items:
              inneritems = list(vect.components.items())
              inneritems.sort(key = lambda x: x[0].__str__())
              for k, v in inneritems:
                  #if the coef of the basis vector is 1
                  #we skip the 1
                  if v == 1:
                      o1.append(u"" +
                                k._pretty_form)
                  #Same for -1
                  elif v == -1:
                      o1.append(u"(-1) " +
                                k._pretty_form)
                  #For a general expr
                  else:
                      #We always wrap the measure numbers in
                      #parentheses
                      arg_str = self._print(
                          v).parens()[0]
  
                      o1.append(arg_str + ' ' + k._pretty_form)
                  vectstrs.append(k._pretty_form)
  
          #outstr = u("").join(o1)
          if o1[0].startswith(u" + "):
              o1[0] = o1[0][3:]
          elif o1[0].startswith(" "):
              o1[0] = o1[0][1:]
          #Fixing the newlines
          lengths = []
          strs = ['']
          flag = []
          for i, partstr in enumerate(o1):
              flag.append(0)
              # XXX: What is this hack?
              if '\n' in partstr:
                  tempstr = partstr
                  tempstr = tempstr.replace(vectstrs[i], '')
                  if u'\N{right parenthesis extension}' in tempstr:   # If scalar is a fraction
                      for paren in range(len(tempstr)):
                          flag[i] = 1
                          if tempstr[paren] == u'\N{right parenthesis extension}':
                              tempstr = tempstr[:paren] + u'\N{right parenthesis extension}'\
                                           + ' '  + vectstrs[i] + tempstr[paren + 1:]
                              break
                  elif u'\N{RIGHT PARENTHESIS LOWER HOOK}' in tempstr:
                      flag[i] = 1
                      tempstr = tempstr.replace(u'\N{RIGHT PARENTHESIS LOWER HOOK}',
                                          u'\N{RIGHT PARENTHESIS LOWER HOOK}'
                                          + ' ' + vectstrs[i])
                  else:
                      tempstr = tempstr.replace(u'\N{RIGHT PARENTHESIS UPPER HOOK}',
                                          u'\N{RIGHT PARENTHESIS UPPER HOOK}'
                                          + ' ' + vectstrs[i])
                  o1[i] = tempstr
  
          o1 = [x.split('\n') for x in o1]
          n_newlines = max([len(x) for x in o1])  # Width of part in its pretty form
  
          if 1 in flag:                           # If there was a fractional scalar
              for i, parts in enumerate(o1):
                  if len(parts) == 1:             # If part has no newline
                      parts.insert(0, ' ' * (len(parts[0])))
                      flag[i] = 1
  
          for i, parts in enumerate(o1):
              lengths.append(len(parts[flag[i]]))
              for j in range(n_newlines):
                  if j+1 <= len(parts):
                      if j >= len(strs):
                          strs.append(' ' * (sum(lengths[:-1]) +
                                             3*(len(lengths)-1)))
                      if j == flag[i]:
                          strs[flag[i]] += parts[flag[i]] + ' + '
                      else:
                          strs[j] += parts[j] + ' '*(lengths[-1] -
                                                     len(parts[j])+
                                                     3)
                  else:
                      if j >= len(strs):
                          strs.append(' ' * (sum(lengths[:-1]) +
                                             3*(len(lengths)-1)))
                      strs[j] += ' '*(lengths[-1]+3)
  
          return prettyForm(u'\n'.join([s[:-3] for s in strs]))
  
      def _print_NDimArray(self, expr):
          from sympy import ImmutableMatrix
  
          if expr.rank() == 0:
              return self._print(expr[()])
  
          level_str = [[]] + [[] for i in range(expr.rank())]
          shape_ranges = [list(range(i)) for i in expr.shape]
          for outer_i in itertools.product(*shape_ranges):
              level_str[-1].append(expr[outer_i])
              even = True
              for back_outer_i in range(expr.rank()-1, -1, -1):
                  if len(level_str[back_outer_i+1]) < expr.shape[back_outer_i]:
                      break
                  if even:
                      level_str[back_outer_i].append(level_str[back_outer_i+1])
                  else:
                      level_str[back_outer_i].append(ImmutableMatrix(level_str[back_outer_i+1]))
                      if len(level_str[back_outer_i + 1]) == 1:
                          level_str[back_outer_i][-1] = ImmutableMatrix([[level_str[back_outer_i][-1]]])
                  even = not even
                  level_str[back_outer_i+1] = []
  
          out_expr = level_str[0][0]
          if expr.rank() % 2 == 1:
              out_expr = ImmutableMatrix([out_expr])
  
          return self._print(out_expr)
  
      _print_ImmutableDenseNDimArray = _print_NDimArray
      _print_ImmutableSparseNDimArray = _print_NDimArray
      _print_MutableDenseNDimArray = _print_NDimArray
      _print_MutableSparseNDimArray = _print_NDimArray
  
      def _print_Tensor(self, expr):
          name = expr.args[0].name
          indices = expr.get_indices()
  
          center = stringPict(name)
          top = stringPict(" "*center.width())
          bot = stringPict(" "*center.width())
  
          no_top = True
          no_bot = True
  
          for i, index in enumerate(indices):
              indpic = self._print(index.args[0])
              if index.is_up:
                  no_top = False
                  top = stringPict(*top.right(indpic))
                  center = stringPict(*center.right(" "*indpic.width()))
                  bot = stringPict(*bot.right(" "*indpic.width()))
              else:
                  no_bot = False
                  bot = stringPict(*bot.right(indpic))
                  center = stringPict(*center.right(" "*indpic.width()))
                  top = stringPict(*top.right(" "*indpic.width()))
  
          pict = prettyForm(*center.above(top))
          pict = prettyForm(*pict.below(bot))
          return pict
  
      def _print_TensMul(self, expr):
          sign, args = expr._get_args_for_traditional_printer()
          args = [
              prettyForm(*self._print(i).parens()) if
              precedence_traditional(i) < PRECEDENCE["Mul"] else self._print(i)
              for i in args
          ]
          pform = prettyForm.__mul__(*args)
          if sign:
              return prettyForm(*pform.left(sign))
          else:
              return pform
  
      def _print_TensAdd(self, expr):
          args = [
              prettyForm(*self._print(i).parens()) if
              precedence_traditional(i) < PRECEDENCE["Mul"] else self._print(i)
              for i in expr.args
          ]
          return prettyForm.__add__(*args)
  
      def _print_TensorIndex(self, expr):
          sym = expr.args[0]
          if not expr.is_up:
              sym = -sym
          return self._print(sym)
  
      def _print_PartialDerivative(self, deriv):
          if self._use_unicode:
              deriv_symbol = U('PARTIAL DIFFERENTIAL')
          else:
              deriv_symbol = r'd'
          x = None
  
          for variable in reversed(deriv.variables):
              s = self._print(variable)
              ds = prettyForm(*s.left(deriv_symbol))
  
              if x is None:
                  x = ds
              else:
                  x = prettyForm(*x.right(' '))
                  x = prettyForm(*x.right(ds))
  
          f = prettyForm(
              binding=prettyForm.FUNC, *self._print(deriv.expr).parens())
  
          pform = prettyForm(deriv_symbol)
  
          pform = prettyForm(*pform.below(stringPict.LINE, x))
          pform.baseline = pform.baseline + 1
          pform = prettyForm(*stringPict.next(pform, f))
          pform.binding = prettyForm.MUL
  
          return pform
  
      def _print_Piecewise(self, pexpr):
  
          P = {}
          for n, ec in enumerate(pexpr.args):
              P[n, 0] = self._print(ec.expr)
              if ec.cond == True:
                  P[n, 1] = prettyForm('otherwise')
              else:
                  P[n, 1] = prettyForm(
                      *prettyForm('for ').right(self._print(ec.cond)))
          hsep = 2
          vsep = 1
          len_args = len(pexpr.args)
  
          # max widths
          maxw = [max([P[i, j].width() for i in range(len_args)])
                  for j in range(2)]
  
          # FIXME: Refactor this code and matrix into some tabular environment.
          # drawing result
          D = None
  
          for i in range(len_args):
              D_row = None
              for j in range(2):
                  p = P[i, j]
                  assert p.width() <= maxw[j]
  
                  wdelta = maxw[j] - p.width()
                  wleft = wdelta // 2
                  wright = wdelta - wleft
  
                  p = prettyForm(*p.right(' '*wright))
                  p = prettyForm(*p.left(' '*wleft))
  
                  if D_row is None:
                      D_row = p
                      continue
  
                  D_row = prettyForm(*D_row.right(' '*hsep))  # h-spacer
                  D_row = prettyForm(*D_row.right(p))
              if D is None:
                  D = D_row       # first row in a picture
                  continue
  
              # v-spacer
              for _ in range(vsep):
                  D = prettyForm(*D.below(' '))
  
              D = prettyForm(*D.below(D_row))
  
          D = prettyForm(*D.parens('{', ''))
          D.baseline = D.height()//2
          D.binding = prettyForm.OPEN
          return D
  
      def _print_ITE(self, ite):
          from sympy.functions.elementary.piecewise import Piecewise
          return self._print(ite.rewrite(Piecewise))
  
      def _hprint_vec(self, v):
          D = None
  
          for a in v:
              p = a
              if D is None:
                  D = p
              else:
                  D = prettyForm(*D.right(', '))
                  D = prettyForm(*D.right(p))
          if D is None:
              D = stringPict(' ')
  
          return D
  
      def _hprint_vseparator(self, p1, p2):
          tmp = prettyForm(*p1.right(p2))
          sep = stringPict(vobj('|', tmp.height()), baseline=tmp.baseline)
          return prettyForm(*p1.right(sep, p2))
  
      def _print_hyper(self, e):
          # FIXME refactor Matrix, Piecewise, and this into a tabular environment
          ap = [self._print(a) for a in e.ap]
          bq = [self._print(b) for b in e.bq]
  
          P = self._print(e.argument)
          P.baseline = P.height()//2
  
          # Drawing result - first create the ap, bq vectors
          D = None
          for v in [ap, bq]:
              D_row = self._hprint_vec(v)
              if D is None:
                  D = D_row       # first row in a picture
              else:
                  D = prettyForm(*D.below(' '))
                  D = prettyForm(*D.below(D_row))
  
          # make sure that the argument `z' is centred vertically
          D.baseline = D.height()//2
  
          # insert horizontal separator
          P = prettyForm(*P.left(' '))
          D = prettyForm(*D.right(' '))
  
          # insert separating `|`
          D = self._hprint_vseparator(D, P)
  
          # add parens
          D = prettyForm(*D.parens('(', ')'))
  
          # create the F symbol
          above = D.height()//2 - 1
          below = D.height() - above - 1
  
          sz, t, b, add, img = annotated('F')
          F = prettyForm('\n' * (above - t) + img + '\n' * (below - b),
                         baseline=above + sz)
          add = (sz + 1)//2
  
          F = prettyForm(*F.left(self._print(len(e.ap))))
          F = prettyForm(*F.right(self._print(len(e.bq))))
          F.baseline = above + add
  
          D = prettyForm(*F.right(' ', D))
  
          return D
  
      def _print_meijerg(self, e):
          # FIXME refactor Matrix, Piecewise, and this into a tabular environment
  
          v = {}
          v[(0, 0)] = [self._print(a) for a in e.an]
          v[(0, 1)] = [self._print(a) for a in e.aother]
          v[(1, 0)] = [self._print(b) for b in e.bm]
          v[(1, 1)] = [self._print(b) for b in e.bother]
  
          P = self._print(e.argument)
          P.baseline = P.height()//2
  
          vp = {}
          for idx in v:
              vp[idx] = self._hprint_vec(v[idx])
  
          for i in range(2):
              maxw = max(vp[(0, i)].width(), vp[(1, i)].width())
              for j in range(2):
                  s = vp[(j, i)]
                  left = (maxw - s.width()) // 2
                  right = maxw - left - s.width()
                  s = prettyForm(*s.left(' ' * left))
                  s = prettyForm(*s.right(' ' * right))
                  vp[(j, i)] = s
  
          D1 = prettyForm(*vp[(0, 0)].right('  ', vp[(0, 1)]))
          D1 = prettyForm(*D1.below(' '))
          D2 = prettyForm(*vp[(1, 0)].right('  ', vp[(1, 1)]))
          D = prettyForm(*D1.below(D2))
  
          # make sure that the argument `z' is centred vertically
          D.baseline = D.height()//2
  
          # insert horizontal separator
          P = prettyForm(*P.left(' '))
          D = prettyForm(*D.right(' '))
  
          # insert separating `|`
          D = self._hprint_vseparator(D, P)
  
          # add parens
          D = prettyForm(*D.parens('(', ')'))
  
          # create the G symbol
          above = D.height()//2 - 1
          below = D.height() - above - 1
  
          sz, t, b, add, img = annotated('G')
          F = prettyForm('\n' * (above - t) + img + '\n' * (below - b),
                         baseline=above + sz)
  
          pp = self._print(len(e.ap))
          pq = self._print(len(e.bq))
          pm = self._print(len(e.bm))
          pn = self._print(len(e.an))
  
          def adjust(p1, p2):
              diff = p1.width() - p2.width()
              if diff == 0:
                  return p1, p2
              elif diff > 0:
                  return p1, prettyForm(*p2.left(' '*diff))
              else:
                  return prettyForm(*p1.left(' '*-diff)), p2
          pp, pm = adjust(pp, pm)
          pq, pn = adjust(pq, pn)
          pu = prettyForm(*pm.right(', ', pn))
          pl = prettyForm(*pp.right(', ', pq))
  
          ht = F.baseline - above - 2
          if ht > 0:
              pu = prettyForm(*pu.below('\n'*ht))
          p = prettyForm(*pu.below(pl))
  
          F.baseline = above
          F = prettyForm(*F.right(p))
  
          F.baseline = above + add
  
          D = prettyForm(*F.right(' ', D))
  
          return D
  
      def _print_ExpBase(self, e):
          # TODO should exp_polar be printed differently?
          #      what about exp_polar(0), exp_polar(1)?
          base = prettyForm(pretty_atom('Exp1', 'e'))
          return base ** self._print(e.args[0])
  
      def _print_Function(self, e, sort=False, func_name=None):
          # optional argument func_name for supplying custom names
          # XXX works only for applied functions
          func = e.func
          args = e.args
          if sort:
              args = sorted(args, key=default_sort_key)
  
          if not func_name:
              func_name = func.__name__
  
          prettyFunc = self._print(Symbol(func_name))
          prettyArgs = prettyForm(*self._print_seq(args).parens())
  
          pform = prettyForm(
              binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs))
  
          # store pform parts so it can be reassembled e.g. when powered
          pform.prettyFunc = prettyFunc
          pform.prettyArgs = prettyArgs
  
          return pform
  
      @property
      def _special_function_classes(self):
          from sympy.functions.special.tensor_functions import KroneckerDelta
          from sympy.functions.special.gamma_functions import gamma, lowergamma
          from sympy.functions.special.beta_functions import beta
          from sympy.functions.special.delta_functions import DiracDelta
          from sympy.functions.special.error_functions import Chi
          return {KroneckerDelta: [greek_unicode['delta'], 'delta'],
                  gamma: [greek_unicode['Gamma'], 'Gamma'],
                  lowergamma: [greek_unicode['gamma'], 'gamma'],
                  beta: [greek_unicode['Beta'], 'B'],
                  DiracDelta: [greek_unicode['delta'], 'delta'],
                  Chi: ['Chi', 'Chi']}
  
      def _print_FunctionClass(self, expr):
          for cls in self._special_function_classes:
              if issubclass(expr, cls) and expr.__name__ == cls.__name__:
                  if self._use_unicode:
                      return prettyForm(self._special_function_classes[cls][0])
                  else:
                      return prettyForm(self._special_function_classes[cls][1])
          func_name = expr.__name__
          return prettyForm(pretty_symbol(func_name))
  
      def _print_GeometryEntity(self, expr):
          # GeometryEntity is based on Tuple but should not print like a Tuple
          return self.emptyPrinter(expr)
  
      def _print_Lambda(self, e):
          vars, expr = e.args
          if self._use_unicode:
              arrow = u" \N{RIGHTWARDS ARROW FROM BAR} "
          else:
              arrow = " -> "
          if len(vars) == 1:
              var_form = self._print(vars[0])
          else:
              var_form = self._print(tuple(vars))
  
          return prettyForm(*stringPict.next(var_form, arrow, self._print(expr)), binding=8)
  
      def _print_Order(self, expr):
          pform = self._print(expr.expr)
          if (expr.point and any(p != S.Zero for p in expr.point)) or \
             len(expr.variables) > 1:
              pform = prettyForm(*pform.right("; "))
              if len(expr.variables) > 1:
                  pform = prettyForm(*pform.right(self._print(expr.variables)))
              elif len(expr.variables):
                  pform = prettyForm(*pform.right(self._print(expr.variables[0])))
              if self._use_unicode:
                  pform = prettyForm(*pform.right(u" \N{RIGHTWARDS ARROW} "))
              else:
                  pform = prettyForm(*pform.right(" -> "))
              if len(expr.point) > 1:
                  pform = prettyForm(*pform.right(self._print(expr.point)))
              else:
                  pform = prettyForm(*pform.right(self._print(expr.point[0])))
          pform = prettyForm(*pform.parens())
          pform = prettyForm(*pform.left("O"))
          return pform
  
      def _print_SingularityFunction(self, e):
          if self._use_unicode:
              shift = self._print(e.args[0]-e.args[1])
              n = self._print(e.args[2])
              base = prettyForm("<")
              base = prettyForm(*base.right(shift))
              base = prettyForm(*base.right(">"))
              pform = base**n
              return pform
          else:
              n = self._print(e.args[2])
              shift = self._print(e.args[0]-e.args[1])
              base = self._print_seq(shift, "<", ">", ' ')
              return base**n
  
      def _print_beta(self, e):
          func_name = greek_unicode['Beta'] if self._use_unicode else 'B'
          return self._print_Function(e, func_name=func_name)
  
      def _print_gamma(self, e):
          func_name = greek_unicode['Gamma'] if self._use_unicode else 'Gamma'
          return self._print_Function(e, func_name=func_name)
  
      def _print_uppergamma(self, e):
          func_name = greek_unicode['Gamma'] if self._use_unicode else 'Gamma'
          return self._print_Function(e, func_name=func_name)
  
      def _print_lowergamma(self, e):
          func_name = greek_unicode['gamma'] if self._use_unicode else 'lowergamma'
          return self._print_Function(e, func_name=func_name)
  
      def _print_DiracDelta(self, e):
          if self._use_unicode:
              if len(e.args) == 2:
                  a = prettyForm(greek_unicode['delta'])
                  b = self._print(e.args[1])
                  b = prettyForm(*b.parens())
                  c = self._print(e.args[0])
                  c = prettyForm(*c.parens())
                  pform = a**b
                  pform = prettyForm(*pform.right(' '))
                  pform = prettyForm(*pform.right(c))
                  return pform
              pform = self._print(e.args[0])
              pform = prettyForm(*pform.parens())
              pform = prettyForm(*pform.left(greek_unicode['delta']))
              return pform
          else:
              return self._print_Function(e)
  
      def _print_expint(self, e):
          from sympy import Function
          if e.args[0].is_Integer and self._use_unicode:
              return self._print_Function(Function('E_%s' % e.args[0])(e.args[1]))
          return self._print_Function(e)
  
      def _print_Chi(self, e):
          # This needs a special case since otherwise it comes out as greek
          # letter chi...
          prettyFunc = prettyForm("Chi")
          prettyArgs = prettyForm(*self._print_seq(e.args).parens())
  
          pform = prettyForm(
              binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs))
  
          # store pform parts so it can be reassembled e.g. when powered
          pform.prettyFunc = prettyFunc
          pform.prettyArgs = prettyArgs
  
          return pform
  
      def _print_elliptic_e(self, e):
          pforma0 = self._print(e.args[0])
          if len(e.args) == 1:
              pform = pforma0
          else:
              pforma1 = self._print(e.args[1])
              pform = self._hprint_vseparator(pforma0, pforma1)
          pform = prettyForm(*pform.parens())
          pform = prettyForm(*pform.left('E'))
          return pform
  
      def _print_elliptic_k(self, e):
          pform = self._print(e.args[0])
          pform = prettyForm(*pform.parens())
          pform = prettyForm(*pform.left('K'))
          return pform
  
      def _print_elliptic_f(self, e):
          pforma0 = self._print(e.args[0])
          pforma1 = self._print(e.args[1])
          pform = self._hprint_vseparator(pforma0, pforma1)
          pform = prettyForm(*pform.parens())
          pform = prettyForm(*pform.left('F'))
          return pform
  
      def _print_elliptic_pi(self, e):
          name = greek_unicode['Pi'] if self._use_unicode else 'Pi'
          pforma0 = self._print(e.args[0])
          pforma1 = self._print(e.args[1])
          if len(e.args) == 2:
              pform = self._hprint_vseparator(pforma0, pforma1)
          else:
              pforma2 = self._print(e.args[2])
              pforma = self._hprint_vseparator(pforma1, pforma2)
              pforma = prettyForm(*pforma.left('; '))
              pform = prettyForm(*pforma.left(pforma0))
          pform = prettyForm(*pform.parens())
          pform = prettyForm(*pform.left(name))
          return pform
  
      def _print_GoldenRatio(self, expr):
          if self._use_unicode:
              return prettyForm(pretty_symbol('phi'))
          return self._print(Symbol("GoldenRatio"))
  
      def _print_EulerGamma(self, expr):
          if self._use_unicode:
              return prettyForm(pretty_symbol('gamma'))
          return self._print(Symbol("EulerGamma"))
  
      def _print_Mod(self, expr):
          pform = self._print(expr.args[0])
          if pform.binding > prettyForm.MUL:
              pform = prettyForm(*pform.parens())
          pform = prettyForm(*pform.right(' mod '))
          pform = prettyForm(*pform.right(self._print(expr.args[1])))
          pform.binding = prettyForm.OPEN
          return pform
  
      def _print_Add(self, expr, order=None):
          if self.order == 'none':
              terms = list(expr.args)
          else:
              terms = self._as_ordered_terms(expr, order=order)
          pforms, indices = [], []
  
          def pretty_negative(pform, index):
              """Prepend a minus sign to a pretty form. """
              #TODO: Move this code to prettyForm
              if index == 0:
                  if pform.height() > 1:
                      pform_neg = '- '
                  else:
                      pform_neg = '-'
              else:
                  pform_neg = ' - '
  
              if (pform.binding > prettyForm.NEG
                  or pform.binding == prettyForm.ADD):
                  p = stringPict(*pform.parens())
              else:
                  p = pform
              p = stringPict.next(pform_neg, p)
              # Lower the binding to NEG, even if it was higher. Otherwise, it
              # will print as a + ( - (b)), instead of a - (b).
              return prettyForm(binding=prettyForm.NEG, *p)
  
          for i, term in enumerate(terms):
              if term.is_Mul and _coeff_isneg(term):
                  coeff, other = term.as_coeff_mul(rational=False)
                  pform = self._print(Mul(-coeff, *other, evaluate=False))
                  pforms.append(pretty_negative(pform, i))
              elif term.is_Rational and term.q > 1:
                  pforms.append(None)
                  indices.append(i)
              elif term.is_Number and term < 0:
                  pform = self._print(-term)
                  pforms.append(pretty_negative(pform, i))
              elif term.is_Relational:
                  pforms.append(prettyForm(*self._print(term).parens()))
              else:
                  pforms.append(self._print(term))
  
          if indices:
              large = True
  
              for pform in pforms:
                  if pform is not None and pform.height() > 1:
                      break
              else:
                  large = False
  
              for i in indices:
                  term, negative = terms[i], False
  
                  if term < 0:
                      term, negative = -term, True
  
                  if large:
                      pform = prettyForm(str(term.p))/prettyForm(str(term.q))
                  else:
                      pform = self._print(term)
  
                  if negative:
                      pform = pretty_negative(pform, i)
  
                  pforms[i] = pform
  
          return prettyForm.__add__(*pforms)
  
      def _print_Mul(self, product):
          from sympy.physics.units import Quantity
          a = []  # items in the numerator
          b = []  # items that are in the denominator (if any)
  
          if self.order not in ('old', 'none'):
              args = product.as_ordered_factors()
          else:
              args = list(product.args)
  
          # If quantities are present append them at the back
          args = sorted(args, key=lambda x: isinstance(x, Quantity) or
                       (isinstance(x, Pow) and isinstance(x.base, Quantity)))
  
          # Gather terms for numerator/denominator
          for item in args:
              if item.is_commutative and item.is_Pow and item.exp.is_Rational and item.exp.is_negative:
                  if item.exp != -1:
                      b.append(Pow(item.base, -item.exp, evaluate=False))
                  else:
                      b.append(Pow(item.base, -item.exp))
              elif item.is_Rational and item is not S.Infinity:
                  if item.p != 1:
                      a.append( Rational(item.p) )
                  if item.q != 1:
                      b.append( Rational(item.q) )
              else:
                  a.append(item)
  
          from sympy import Integral, Piecewise, Product, Sum
  
          # Convert to pretty forms. Add parens to Add instances if there
          # is more than one term in the numer/denom
          for i in range(0, len(a)):
              if (a[i].is_Add and len(a) > 1) or (i != len(a) - 1 and
                      isinstance(a[i], (Integral, Piecewise, Product, Sum))):
                  a[i] = prettyForm(*self._print(a[i]).parens())
              elif a[i].is_Relational:
                  a[i] = prettyForm(*self._print(a[i]).parens())
              else:
                  a[i] = self._print(a[i])
  
          for i in range(0, len(b)):
              if (b[i].is_Add and len(b) > 1) or (i != len(b) - 1 and
                      isinstance(b[i], (Integral, Piecewise, Product, Sum))):
                  b[i] = prettyForm(*self._print(b[i]).parens())
              else:
                  b[i] = self._print(b[i])
  
          # Construct a pretty form
          if len(b) == 0:
              return prettyForm.__mul__(*a)
          else:
              if len(a) == 0:
                  a.append( self._print(S.One) )
              return prettyForm.__mul__(*a)/prettyForm.__mul__(*b)
  
      # A helper function for _print_Pow to print x**(1/n)
      def _print_nth_root(self, base, expt):
          bpretty = self._print(base)
  
          # In very simple cases, use a single-char root sign
          if (self._settings['use_unicode_sqrt_char'] and self._use_unicode
              and expt is S.Half and bpretty.height() == 1
              and (bpretty.width() == 1
                   or (base.is_Integer and base.is_nonnegative))):
              return prettyForm(*bpretty.left(u'\N{SQUARE ROOT}'))
  
          # Construct root sign, start with the \/ shape
          _zZ = xobj('/', 1)
          rootsign = xobj('\\', 1) + _zZ
          # Make exponent number to put above it
          if isinstance(expt, Rational):
              exp = str(expt.q)
              if exp == '2':
                  exp = ''
          else:
              exp = str(expt.args[0])
          exp = exp.ljust(2)
          if len(exp) > 2:
              rootsign = ' '*(len(exp) - 2) + rootsign
          # Stack the exponent
          rootsign = stringPict(exp + '\n' + rootsign)
          rootsign.baseline = 0
          # Diagonal: length is one less than height of base
          linelength = bpretty.height() - 1
          diagonal = stringPict('\n'.join(
              ' '*(linelength - i - 1) + _zZ + ' '*i
              for i in range(linelength)
          ))
          # Put baseline just below lowest line: next to exp
          diagonal.baseline = linelength - 1
          # Make the root symbol
          rootsign = prettyForm(*rootsign.right(diagonal))
          # Det the baseline to match contents to fix the height
          # but if the height of bpretty is one, the rootsign must be one higher
          rootsign.baseline = max(1, bpretty.baseline)
          #build result
          s = prettyForm(hobj('_', 2 + bpretty.width()))
          s = prettyForm(*bpretty.above(s))
          s = prettyForm(*s.left(rootsign))
          return s
  
      def _print_Pow(self, power):
          from sympy.simplify.simplify import fraction
          b, e = power.as_base_exp()
          if power.is_commutative:
              if e is S.NegativeOne:
                  return prettyForm("1")/self._print(b)
              n, d = fraction(e)
              if n is S.One and d.is_Atom and not e.is_Integer:
                  return self._print_nth_root(b, e)
              if e.is_Rational and e < 0:
                  return prettyForm("1")/self._print(Pow(b, -e, evaluate=False))
  
          if b.is_Relational:
              return prettyForm(*self._print(b).parens()).__pow__(self._print(e))
  
          return self._print(b)**self._print(e)
  
      def _print_UnevaluatedExpr(self, expr):
          return self._print(expr.args[0])
  
      def __print_numer_denom(self, p, q):
          if q == 1:
              if p < 0:
                  return prettyForm(str(p), binding=prettyForm.NEG)
              else:
                  return prettyForm(str(p))
          elif abs(p) >= 10 and abs(q) >= 10:
              # If more than one digit in numer and denom, print larger fraction
              if p < 0:
                  return prettyForm(str(p), binding=prettyForm.NEG)/prettyForm(str(q))
                  # Old printing method:
                  #pform = prettyForm(str(-p))/prettyForm(str(q))
                  #return prettyForm(binding=prettyForm.NEG, *pform.left('- '))
              else:
                  return prettyForm(str(p))/prettyForm(str(q))
          else:
              return None
  
      def _print_Rational(self, expr):
          result = self.__print_numer_denom(expr.p, expr.q)
  
          if result is not None:
              return result
          else:
              return self.emptyPrinter(expr)
  
      def _print_Fraction(self, expr):
          result = self.__print_numer_denom(expr.numerator, expr.denominator)
  
          if result is not None:
              return result
          else:
              return self.emptyPrinter(expr)
  
      def _print_ProductSet(self, p):
          if len(p.sets) > 1 and not has_variety(p.sets):
              from sympy import Pow
              return self._print(Pow(p.sets[0], len(p.sets), evaluate=False))
          else:
              prod_char = u"\N{MULTIPLICATION SIGN}" if self._use_unicode else 'x'
              return self._print_seq(p.sets, None, None, ' %s ' % prod_char,
                                     parenthesize=lambda set: set.is_Union or
                                     set.is_Intersection or set.is_ProductSet)
  
      def _print_FiniteSet(self, s):
          items = sorted(s.args, key=default_sort_key)
          return self._print_seq(items, '{', '}', ', ' )
  
      def _print_Range(self, s):
  
          if self._use_unicode:
              dots = u"\N{HORIZONTAL ELLIPSIS}"
          else:
              dots = '...'
  
          if s.start.is_infinite:
              printset = s.start, dots, s[-1] - s.step, s[-1]
          elif s.stop.is_infinite or len(s) > 4:
              it = iter(s)
              printset = next(it), next(it), dots, s[-1]
          else:
              printset = tuple(s)
  
          return self._print_seq(printset, '{', '}', ', ' )
  
      def _print_Interval(self, i):
          if i.start == i.end:
              return self._print_seq(i.args[:1], '{', '}')
  
          else:
              if i.left_open:
                  left = '('
              else:
                  left = '['
  
              if i.right_open:
                  right = ')'
              else:
                  right = ']'
  
              return self._print_seq(i.args[:2], left, right)
  
      def _print_AccumulationBounds(self, i):
          left = '<'
          right = '>'
  
          return self._print_seq(i.args[:2], left, right)
  
      def _print_Intersection(self, u):
  
          delimiter = ' %s ' % pretty_atom('Intersection', 'n')
  
          return self._print_seq(u.args, None, None, delimiter,
                                 parenthesize=lambda set: set.is_ProductSet or
                                 set.is_Union or set.is_Complement)
  
      def _print_Union(self, u):
  
          union_delimiter = ' %s ' % pretty_atom('Union', 'U')
  
          return self._print_seq(u.args, None, None, union_delimiter,
                                 parenthesize=lambda set: set.is_ProductSet or
                                 set.is_Intersection or set.is_Complement)
  
      def _print_SymmetricDifference(self, u):
          if not self._use_unicode:
              raise NotImplementedError("ASCII pretty printing of SymmetricDifference is not implemented")
  
          sym_delimeter = ' %s ' % pretty_atom('SymmetricDifference')
  
          return self._print_seq(u.args, None, None, sym_delimeter)
  
      def _print_Complement(self, u):
  
          delimiter = r' \ '
  
          return self._print_seq(u.args, None, None, delimiter,
               parenthesize=lambda set: set.is_ProductSet or set.is_Intersection
                                 or set.is_Union)
  
      def _print_ImageSet(self, ts):
          if self._use_unicode:
              inn = u"\N{SMALL ELEMENT OF}"
          else:
              inn = 'in'
          variables = ts.lamda.variables
          expr = self._print(ts.lamda.expr)
          bar = self._print("|")
          sets = [self._print(i) for i in ts.args[1:]]
          if len(sets) == 1:
              return self._print_seq((expr, bar, variables[0], inn, sets[0]), "{", "}", ' ')
          else:
              pargs = tuple(j for var, setv in zip(variables, sets) for j in (var, inn, setv, ","))
              return self._print_seq((expr, bar) + pargs[:-1], "{", "}", ' ')
  
      def _print_ConditionSet(self, ts):
          if self._use_unicode:
              inn = u"\N{SMALL ELEMENT OF}"
              # using _and because and is a keyword and it is bad practice to
              # overwrite them
              _and = u"\N{LOGICAL AND}"
          else:
              inn = 'in'
              _and = 'and'
  
          variables = self._print_seq(Tuple(ts.sym))
          try:
              cond = self._print(ts.condition.as_expr())
          except AttributeError:
              cond = self._print(ts.condition)
              if self._use_unicode:
                  cond = self._print_seq(cond, "(", ")")
  
          bar = self._print("|")
  
          if ts.base_set is S.UniversalSet:
              return self._print_seq((variables, bar, cond), "{", "}", ' ')
  
          base = self._print(ts.base_set)
          return self._print_seq((variables, bar, variables, inn,
                                  base, _and, cond), "{", "}", ' ')
  
      def _print_ComplexRegion(self, ts):
          if self._use_unicode:
              inn = u"\N{SMALL ELEMENT OF}"
          else:
              inn = 'in'
          variables = self._print_seq(ts.variables)
          expr = self._print(ts.expr)
          bar = self._print("|")
          prodsets = self._print(ts.sets)
  
          return self._print_seq((expr, bar, variables, inn, prodsets), "{", "}", ' ')
  
      def _print_Contains(self, e):
          var, set = e.args
          if self._use_unicode:
              el = u" \N{ELEMENT OF} "
              return prettyForm(*stringPict.next(self._print(var),
                                                 el, self._print(set)), binding=8)
          else:
              return prettyForm(sstr(e))
  
      def _print_FourierSeries(self, s):
          if self._use_unicode:
              dots = u"\N{HORIZONTAL ELLIPSIS}"
          else:
              dots = '...'
          return self._print_Add(s.truncate()) + self._print(dots)
  
      def _print_FormalPowerSeries(self, s):
          return self._print_Add(s.infinite)
  
      def _print_SetExpr(self, se):
          pretty_set = prettyForm(*self._print(se.set).parens())
          pretty_name = self._print(Symbol("SetExpr"))
          return prettyForm(*pretty_name.right(pretty_set))
  
      def _print_SeqFormula(self, s):
          if self._use_unicode:
              dots = u"\N{HORIZONTAL ELLIPSIS}"
          else:
              dots = '...'
  
          if s.start is S.NegativeInfinity:
              stop = s.stop
              printset = (dots, s.coeff(stop - 3), s.coeff(stop - 2),
                  s.coeff(stop - 1), s.coeff(stop))
          elif s.stop is S.Infinity or s.length > 4:
              printset = s[:4]
              printset.append(dots)
              printset = tuple(printset)
          else:
              printset = tuple(s)
          return self._print_list(printset)
  
      _print_SeqPer = _print_SeqFormula
      _print_SeqAdd = _print_SeqFormula
      _print_SeqMul = _print_SeqFormula
  
      def _print_seq(self, seq, left=None, right=None, delimiter=', ',
              parenthesize=lambda x: False):
          s = None
  
          for item in seq:
              pform = self._print(item)
  
              if parenthesize(item):
                  pform = prettyForm(*pform.parens())
              if s is None:
                  # first element
                  s = pform
              else:
                  s = prettyForm(*stringPict.next(s, delimiter))
                  s = prettyForm(*stringPict.next(s, pform))
  
          if s is None:
              s = stringPict('')
  
          s = prettyForm(*s.parens(left, right, ifascii_nougly=True))
          return s
  
      def join(self, delimiter, args):
          pform = None
  
          for arg in args:
              if pform is None:
                  pform = arg
              else:
                  pform = prettyForm(*pform.right(delimiter))
                  pform = prettyForm(*pform.right(arg))
  
          if pform is None:
              return prettyForm("")
          else:
              return pform
  
      def _print_list(self, l):
          return self._print_seq(l, '[', ']')
  
      def _print_tuple(self, t):
          if len(t) == 1:
              ptuple = prettyForm(*stringPict.next(self._print(t[0]), ','))
              return prettyForm(*ptuple.parens('(', ')', ifascii_nougly=True))
          else:
              return self._print_seq(t, '(', ')')
  
      def _print_Tuple(self, expr):
          return self._print_tuple(expr)
  
      def _print_dict(self, d):
          keys = sorted(d.keys(), key=default_sort_key)
          items = []
  
          for k in keys:
              K = self._print(k)
              V = self._print(d[k])
              s = prettyForm(*stringPict.next(K, ': ', V))
  
              items.append(s)
  
          return self._print_seq(items, '{', '}')
  
      def _print_Dict(self, d):
          return self._print_dict(d)
  
      def _print_set(self, s):
          if not s:
              return prettyForm('set()')
          items = sorted(s, key=default_sort_key)
          pretty = self._print_seq(items)
          pretty = prettyForm(*pretty.parens('{', '}', ifascii_nougly=True))
          return pretty
  
      def _print_frozenset(self, s):
          if not s:
              return prettyForm('frozenset()')
          items = sorted(s, key=default_sort_key)
          pretty = self._print_seq(items)
          pretty = prettyForm(*pretty.parens('{', '}', ifascii_nougly=True))
          pretty = prettyForm(*pretty.parens('(', ')', ifascii_nougly=True))
          pretty = prettyForm(*stringPict.next(type(s).__name__, pretty))
          return pretty
  
      def _print_PolyRing(self, ring):
          return prettyForm(sstr(ring))
  
      def _print_FracField(self, field):
          return prettyForm(sstr(field))
  
      def _print_FreeGroupElement(self, elm):
          return prettyForm(str(elm))
  
      def _print_PolyElement(self, poly):
          return prettyForm(sstr(poly))
  
      def _print_FracElement(self, frac):
          return prettyForm(sstr(frac))
  
      def _print_AlgebraicNumber(self, expr):
          if expr.is_aliased:
              return self._print(expr.as_poly().as_expr())
          else:
              return self._print(expr.as_expr())
  
      def _print_ComplexRootOf(self, expr):
          args = [self._print_Add(expr.expr, order='lex'), expr.index]
          pform = prettyForm(*self._print_seq(args).parens())
          pform = prettyForm(*pform.left('CRootOf'))
          return pform
  
      def _print_RootSum(self, expr):
          args = [self._print_Add(expr.expr, order='lex')]
  
          if expr.fun is not S.IdentityFunction:
              args.append(self._print(expr.fun))
  
          pform = prettyForm(*self._print_seq(args).parens())
          pform = prettyForm(*pform.left('RootSum'))
  
          return pform
  
      def _print_FiniteField(self, expr):
          if self._use_unicode:
              form = u'\N{DOUBLE-STRUCK CAPITAL Z}_%d'
          else:
              form = 'GF(%d)'
  
          return prettyForm(pretty_symbol(form % expr.mod))
  
      def _print_IntegerRing(self, expr):
          if self._use_unicode:
              return prettyForm(u'\N{DOUBLE-STRUCK CAPITAL Z}')
          else:
              return prettyForm('ZZ')
  
      def _print_RationalField(self, expr):
          if self._use_unicode:
              return prettyForm(u'\N{DOUBLE-STRUCK CAPITAL Q}')
          else:
              return prettyForm('QQ')
  
      def _print_RealField(self, domain):
          if self._use_unicode:
              prefix = u'\N{DOUBLE-STRUCK CAPITAL R}'
          else:
              prefix = 'RR'
  
          if domain.has_default_precision:
              return prettyForm(prefix)
          else:
              return self._print(pretty_symbol(prefix + "_" + str(domain.precision)))
  
      def _print_ComplexField(self, domain):
          if self._use_unicode:
              prefix = u'\N{DOUBLE-STRUCK CAPITAL C}'
          else:
              prefix = 'CC'
  
          if domain.has_default_precision:
              return prettyForm(prefix)
          else:
              return self._print(pretty_symbol(prefix + "_" + str(domain.precision)))
  
      def _print_PolynomialRing(self, expr):
          args = list(expr.symbols)
  
          if not expr.order.is_default:
              order = prettyForm(*prettyForm("order=").right(self._print(expr.order)))
              args.append(order)
  
          pform = self._print_seq(args, '[', ']')
          pform = prettyForm(*pform.left(self._print(expr.domain)))
  
          return pform
  
      def _print_FractionField(self, expr):
          args = list(expr.symbols)
  
          if not expr.order.is_default:
              order = prettyForm(*prettyForm("order=").right(self._print(expr.order)))
              args.append(order)
  
          pform = self._print_seq(args, '(', ')')
          pform = prettyForm(*pform.left(self._print(expr.domain)))
  
          return pform
  
      def _print_PolynomialRingBase(self, expr):
          g = expr.symbols
          if str(expr.order) != str(expr.default_order):
              g = g + ("order=" + str(expr.order),)
          pform = self._print_seq(g, '[', ']')
          pform = prettyForm(*pform.left(self._print(expr.domain)))
  
          return pform
  
      def _print_GroebnerBasis(self, basis):
          exprs = [ self._print_Add(arg, order=basis.order)
                    for arg in basis.exprs ]
          exprs = prettyForm(*self.join(", ", exprs).parens(left="[", right="]"))
  
          gens = [ self._print(gen) for gen in basis.gens ]
  
          domain = prettyForm(
              *prettyForm("domain=").right(self._print(basis.domain)))
          order = prettyForm(
              *prettyForm("order=").right(self._print(basis.order)))
  
          pform = self.join(", ", [exprs] + gens + [domain, order])
  
          pform = prettyForm(*pform.parens())
          pform = prettyForm(*pform.left(basis.__class__.__name__))
  
          return pform
  
      def _print_Subs(self, e):
          pform = self._print(e.expr)
          pform = prettyForm(*pform.parens())
  
          h = pform.height() if pform.height() > 1 else 2
          rvert = stringPict(vobj('|', h), baseline=pform.baseline)
          pform = prettyForm(*pform.right(rvert))
  
          b = pform.baseline
          pform.baseline = pform.height() - 1
          pform = prettyForm(*pform.right(self._print_seq([
              self._print_seq((self._print(v[0]), xsym('=='), self._print(v[1])),
                  delimiter='') for v in zip(e.variables, e.point) ])))
  
          pform.baseline = b
          return pform
  
      def _print_euler(self, e):
          pform = prettyForm("E")
          arg = self._print(e.args[0])
          pform_arg = prettyForm(" "*arg.width())
          pform_arg = prettyForm(*pform_arg.below(arg))
          pform = prettyForm(*pform.right(pform_arg))
          if len(e.args) == 1:
              return pform
          m, x = e.args
          # TODO: copy-pasted from _print_Function: can we do better?
          prettyFunc = pform
          prettyArgs = prettyForm(*self._print_seq([x]).parens())
          pform = prettyForm(
              binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs))
          pform.prettyFunc = prettyFunc
          pform.prettyArgs = prettyArgs
          return pform
  
      def _print_catalan(self, e):
          pform = prettyForm("C")
          arg = self._print(e.args[0])
          pform_arg = prettyForm(" "*arg.width())
          pform_arg = prettyForm(*pform_arg.below(arg))
          pform = prettyForm(*pform.right(pform_arg))
          return pform
  
      def _print_KroneckerDelta(self, e):
          pform = self._print(e.args[0])
          pform = prettyForm(*pform.right((prettyForm(','))))
          pform = prettyForm(*pform.right((self._print(e.args[1]))))
          if self._use_unicode:
              a = stringPict(pretty_symbol('delta'))
          else:
              a = stringPict('d')
          b = pform
          top = stringPict(*b.left(' '*a.width()))
          bot = stringPict(*a.right(' '*b.width()))
          return prettyForm(binding=prettyForm.POW, *bot.below(top))
  
      def _print_RandomDomain(self, d):
          if hasattr(d, 'as_boolean'):
              pform = self._print('Domain: ')
              pform = prettyForm(*pform.right(self._print(d.as_boolean())))
              return pform
          elif hasattr(d, 'set'):
              pform = self._print('Domain: ')
              pform = prettyForm(*pform.right(self._print(d.symbols)))
              pform = prettyForm(*pform.right(self._print(' in ')))
              pform = prettyForm(*pform.right(self._print(d.set)))
              return pform
          elif hasattr(d, 'symbols'):
              pform = self._print('Domain on ')
              pform = prettyForm(*pform.right(self._print(d.symbols)))
              return pform
          else:
              return self._print(None)
  
      def _print_DMP(self, p):
          try:
              if p.ring is not None:
                  # TODO incorporate order
                  return self._print(p.ring.to_sympy(p))
          except SympifyError:
              pass
          return self._print(repr(p))
  
      def _print_DMF(self, p):
          return self._print_DMP(p)
  
      def _print_Object(self, object):
          return self._print(pretty_symbol(object.name))
  
      def _print_Morphism(self, morphism):
          arrow = xsym("-->")
  
          domain = self._print(morphism.domain)
          codomain = self._print(morphism.codomain)
          tail = domain.right(arrow, codomain)[0]
  
          return prettyForm(tail)
  
      def _print_NamedMorphism(self, morphism):
          pretty_name = self._print(pretty_symbol(morphism.name))
          pretty_morphism = self._print_Morphism(morphism)
          return prettyForm(pretty_name.right(":", pretty_morphism)[0])
  
      def _print_IdentityMorphism(self, morphism):
          from sympy.categories import NamedMorphism
          return self._print_NamedMorphism(
              NamedMorphism(morphism.domain, morphism.codomain, "id"))
  
      def _print_CompositeMorphism(self, morphism):
  
          circle = xsym(".")
  
          # All components of the morphism have names and it is thus
          # possible to build the name of the composite.
          component_names_list = [pretty_symbol(component.name) for
                                  component in morphism.components]
          component_names_list.reverse()
          component_names = circle.join(component_names_list) + ":"
  
          pretty_name = self._print(component_names)
          pretty_morphism = self._print_Morphism(morphism)
          return prettyForm(pretty_name.right(pretty_morphism)[0])
  
      def _print_Category(self, category):
          return self._print(pretty_symbol(category.name))
  
      def _print_Diagram(self, diagram):
          if not diagram.premises:
              # This is an empty diagram.
              return self._print(S.EmptySet)
  
          pretty_result = self._print(diagram.premises)
          if diagram.conclusions:
              results_arrow = " %s " % xsym("==>")
  
              pretty_conclusions = self._print(diagram.conclusions)[0]
              pretty_result = pretty_result.right(
                  results_arrow, pretty_conclusions)
  
          return prettyForm(pretty_result[0])
  
      def _print_DiagramGrid(self, grid):
          from sympy.matrices import Matrix
          from sympy import Symbol
          matrix = Matrix([[grid[i, j] if grid[i, j] else Symbol(" ")
                            for j in range(grid.width)]
                           for i in range(grid.height)])
          return self._print_matrix_contents(matrix)
  
      def _print_FreeModuleElement(self, m):
          # Print as row vector for convenience, for now.
          return self._print_seq(m, '[', ']')
  
      def _print_SubModule(self, M):
          return self._print_seq(M.gens, '<', '>')
  
      def _print_FreeModule(self, M):
          return self._print(M.ring)**self._print(M.rank)
  
      def _print_ModuleImplementedIdeal(self, M):
          return self._print_seq([x for [x] in M._module.gens], '<', '>')
  
      def _print_QuotientRing(self, R):
          return self._print(R.ring) / self._print(R.base_ideal)
  
      def _print_QuotientRingElement(self, R):
          return self._print(R.data) + self._print(R.ring.base_ideal)
  
      def _print_QuotientModuleElement(self, m):
          return self._print(m.data) + self._print(m.module.killed_module)
  
      def _print_QuotientModule(self, M):
          return self._print(M.base) / self._print(M.killed_module)
  
      def _print_MatrixHomomorphism(self, h):
          matrix = self._print(h._sympy_matrix())
          matrix.baseline = matrix.height() // 2
          pform = prettyForm(*matrix.right(' : ', self._print(h.domain),
              ' %s> ' % hobj('-', 2), self._print(h.codomain)))
          return pform
  
      def _print_BaseScalarField(self, field):
          string = field._coord_sys._names[field._index]
          return self._print(pretty_symbol(string))
  
      def _print_BaseVectorField(self, field):
          s = U('PARTIAL DIFFERENTIAL') + '_' + field._coord_sys._names[field._index]
          return self._print(pretty_symbol(s))
  
      def _print_Differential(self, diff):
          field = diff._form_field
          if hasattr(field, '_coord_sys'):
              string = field._coord_sys._names[field._index]
              return self._print(u'\N{DOUBLE-STRUCK ITALIC SMALL D} ' + pretty_symbol(string))
          else:
              pform = self._print(field)
              pform = prettyForm(*pform.parens())
              return prettyForm(*pform.left(u"\N{DOUBLE-STRUCK ITALIC SMALL D}"))
  
      def _print_Tr(self, p):
          #TODO: Handle indices
          pform = self._print(p.args[0])
          pform = prettyForm(*pform.left('%s(' % (p.__class__.__name__)))
          pform = prettyForm(*pform.right(')'))
          return pform
  
      def _print_primenu(self, e):
          pform = self._print(e.args[0])
          pform = prettyForm(*pform.parens())
          if self._use_unicode:
              pform = prettyForm(*pform.left(greek_unicode['nu']))
          else:
              pform = prettyForm(*pform.left('nu'))
          return pform
  
      def _print_primeomega(self, e):
          pform = self._print(e.args[0])
          pform = prettyForm(*pform.parens())
          if self._use_unicode:
              pform = prettyForm(*pform.left(greek_unicode['Omega']))
          else:
              pform = prettyForm(*pform.left('Omega'))
          return pform
  
      def _print_Quantity(self, e):
          if e.name.name == 'degree':
              pform = self._print(u"\N{DEGREE SIGN}")
              return pform
          else:
              return self.emptyPrinter(e)
  
      def _print_AssignmentBase(self, e):
  
          op = prettyForm(' ' + xsym(e.op) + ' ')
  
          l = self._print(e.lhs)
          r = self._print(e.rhs)
          pform = prettyForm(*stringPict.next(l, op, r))
          return pform
  
  
  def pretty(expr, **settings):
      """Returns a string containing the prettified form of expr.
  
      For information on keyword arguments see pretty_print function.
  
      """
      pp = PrettyPrinter(settings)
  
      # XXX: this is an ugly hack, but at least it works
      use_unicode = pp._settings['use_unicode']
      uflag = pretty_use_unicode(use_unicode)
  
      try:
          return pp.doprint(expr)
      finally:
          pretty_use_unicode(uflag)
  
  
  def pretty_print(expr, wrap_line=True, num_columns=None, use_unicode=None,
                   full_prec="auto", order=None, use_unicode_sqrt_char=True):
      """Prints expr in pretty form.
  
      pprint is just a shortcut for this function.
  
      Parameters
      ==========
  
      expr : expression
          The expression to print.
  
      wrap_line : bool, optional (default=True)
          Line wrapping enabled/disabled.
  
      num_columns : int or None, optional (default=None)
          Number of columns before line breaking (default to None which reads
          the terminal width), useful when using SymPy without terminal.
  
      use_unicode : bool or None, optional (default=None)
          Use unicode characters, such as the Greek letter pi instead of
          the string pi.
  
      full_prec : bool or string, optional (default="auto")
          Use full precision.
  
      order : bool or string, optional (default=None)
          Set to 'none' for long expressions if slow; default is None.
  
      use_unicode_sqrt_char : bool, optional (default=True)
          Use compact single-character square root symbol (when unambiguous).
  
      """
      print(pretty(expr, wrap_line=wrap_line, num_columns=num_columns,
                   use_unicode=use_unicode, full_prec=full_prec, order=order,
                   use_unicode_sqrt_char=use_unicode_sqrt_char))
  
  pprint = pretty_print
  
  
  def pager_print(expr, **settings):
      """Prints expr using the pager, in pretty form.
  
      This invokes a pager command using pydoc. Lines are not wrapped
      automatically. This routine is meant to be used with a pager that allows
      sideways scrolling, like ``less -S``.
  
      Parameters are the same as for ``pretty_print``. If you wish to wrap lines,
      pass ``num_columns=None`` to auto-detect the width of the terminal.
  
      """
      from pydoc import pager
      from locale import getpreferredencoding
      if 'num_columns' not in settings:
          settings['num_columns'] = 500000  # disable line wrap
      pager(pretty(expr, **settings).encode(getpreferredencoding()))
  