#latex_ex.py

from __future__ import with_statement

import sys
#if sys.version.find('Stackless') >= 0:
#    sys.path.append('/usr/lib/python2.5/site-packages')

import types
import StringIO

from sympy.core import S, C, Basic, Symbol
from sympy.core.function import _coeff_isneg
from sympy.printing.printer import Printer
from sympy.simplify import fraction
import re as regrep

import sympy.galgebra.GA
#import sympy.galgebra.OGA
import numpy

from sympy.core.compatibility import cmp_to_key
from sympy.utilities import default_sort_key

from sympy.printing.latex import accepted_latex_functions
from sympy.printing.preview import preview


def debug(txt):
    sys.stderr.write(txt + '\n')
    return


def len_cmp(str1, str2):
    return(len(str2) - len(str1))


def process_equals(xstr):
    eq1 = xstr.find('=')
    eq2 = xstr.rfind('=')
    if eq1 == eq2:
        return(xstr)
    xstr = xstr[:eq1] + xstr[eq2:]
    return(xstr)


class LatexPrinter(Printer):
    r"""
    A printer class which converts an expression into its LaTeX equivalent.
    This class extends the LatexPrinter class currently in sympy in the
    following ways:

        1.  Variable and function names can now encode multiple Greek symbols,
            number, Greek, and roman super and subscripts and accents plus bold
            math in an alphanumeric ASCII string consisting of ``[A-Za-z0-9_]``
            symbols

            a)  Accents and bold math are implemented in reverse notation. For
                example if you wished the LaTeX output to be ``\bm{\hat{\sigma}}``
                you would give the variable the name sigmahatbm.

            b)  Subscripts are denoted by a single underscore and superscripts
                by a double underscore so that ``A_{\rho\beta}^{25}`` would be
                input as A_rhobeta__25.

        2.  Some standard function names have been improved such as asin is now
            denoted by sin^{-1} and log by ln.

        3.  Several LaTeX formats for multivectors are available:

            a)  Print multivector on one line

            b)  Print each grade of multivector on one line

            c)  Print each base of multivector on one line

        4.  A LaTeX output for numpy arrays containing sympy expressions is
            implemented for up to a three dimensional array.

        5.  LaTeX formatting for raw LaTeX, eqnarray, and array is available
            in simple output strings.

            a)  The delimiter for raw LaTeX input is '%'.  The raw input starts
                on the line where '%' is first encountered and continues until
                the next line where '%' is encountered. It does not matter where
                '%' is in the line.

            b)  The delimiter for eqnarray input is '@'. The rules are the same
                as for raw input except that '=' in the first line is replaced
                be '&=&' and '\begin{eqnarray*}' is added before the first line
                and '\end{eqnarray*}' to after the last line in the group of
                lines.

            c)  The delimiter for array input is '#'. The rules are the same
                as for raw input except that '\begin{equation*}' is added before
                the first line and '\end{equation*}' to after the last line in
                the group of lines.

        6.  Additional formats for partial derivatives:

            a)  Same as sympy latex module

            b)  Use subscript notation with partial symbol to indicate which
                variable the differentiation is with respect to.  Symbol is of
                form \partial_{differentiation variable}
    """

    #printmethod ='_latex_ex'
    sym_fmt = 0
    fct_fmt = 0
    pdiff_fmt = 0
    mv_fmt = 0
    str_fmt = 1
    LaTeX_flg = False

    mode = ('_', '^')

    fmt_dict = {'sym': 0, 'fct': 0, 'pdiff': 0, 'mv': 0, 'str': 1}

    fct_dict = {'sin': 'sin', 'cos': 'cos', 'tan': 'tan', 'cot': 'cot',
                'asin': 'Sin^{-1}', 'acos': 'Cos^{-1}',
                'atan': 'Tan^{-1}', 'acot': 'Cot^{-1}',
                'sinh': 'sinh', 'cosh': 'cosh', 'tanh': 'tanh', 'coth': 'coth',
                'asinh': 'Sinh^{-1}', 'acosh': 'Cosh^{-1}',
                'atanh': 'Tanh^{-1}', 'acoth': 'Coth^{-1}',
                'sqrt': 'sqrt', 'exp': 'exp', 'log': 'ln'}

    fct_dict_keys = fct_dict.keys()

    greek_keys = sorted(
        ('alpha', 'beta', 'gamma', 'delta', 'varepsilon', 'epsilon', 'zeta',
         'vartheta', 'theta', 'iota', 'kappa', 'lambda', 'mu', 'nu', 'xi',
         'varpi', 'pi', 'rho', 'varrho', 'varsigma', 'sigma', 'tau', 'upsilon',
         'varphi', 'phi', 'chi', 'psi', 'omega', 'Gamma', 'Delta', 'Theta',
         'Lambda', 'Xi', 'Pi', 'Sigma', 'Upsilon', 'Phi', 'Psi', 'Omega', 'partial',
                         'nabla', 'eta'), key=cmp_to_key(len_cmp))

    accent_keys = sorted(
        ('hat', 'check', 'dot', 'breve', 'acute', 'ddot', 'grave', 'tilde',
         'mathring', 'bar', 'vec', 'bm', 'prm', 'abs'), key=cmp_to_key(len_cmp))

    greek_cnt = 0
    greek_dict = {}
    accent_cnt = 0
    accent_dict = {}

    preamble = '\\documentclass[10pt,letter,fleqn]{report}\n' \
               '\\pagestyle{empty}\n' \
               '\\usepackage[latin1]{inputenc}\n' \
               '\\usepackage[dvips,landscape,top=1cm,nohead,nofoot]{geometry}\n' \
               '\\usepackage{amsmath}\n' \
               '\\usepackage{bm}\n' \
               '\\usepackage{amsfonts}\n' \
               '\\usepackage{amssymb}\n' \
               '\\setlength{\\parindent}{0pt}\n' \
               '\\newcommand{\\bfrac}[2]{\\displaystyle\\frac{#1}{#2}}\n' \
               '\\newcommand{\\lp}{\\left (}\n' \
               '\\newcommand{\\rp}{\\right )}\n' \
               '\\newcommand{\\half}{\\frac{1}{2}}\n' \
               '\\newcommand{\\llt}{\\left <}\n' \
               '\\newcommand{\\rgt}{\\right >}\n' \
               '\\newcommand{\\abs}[1]{\\left |{#1}\\right | }\n' \
               '\\newcommand{\\pdiff}[2]{\\bfrac{\\partial {#1}}{\\partial {#2}}}\n' \
               '\\newcommand{\\lbrc}{\\left \\{}\n' \
               '\\newcommand{\\rbrc}{\\right \\}}\n' \
               '\\newcommand{\\W}{\\wedge}\n' \
               "\\newcommand{\\prm}[1]{{#1}'}\n" \
               '\\newcommand{\\ddt}[1]{\\bfrac{d{#1}}{dt}}\n' \
               '\\newcommand{\\R}{\\dagger}\n' \
               '\\begin{document}\n'

    @staticmethod
    def latex_bases():
        """
        Generate LaTeX strings for multivector bases
        """
        if isinstance(sympy.galgebra.GA.MV.basislabel_lst, types.IntType):
            sys.stderr.write(
                'MV.setup() must be executed before LatexPrinter.format()!\n')
            sys.exit(1)
        LatexPrinter.latexbasis_lst = [['']]
        for grades in sympy.galgebra.GA.MV.basislabel_lst[1:]:
            grades_lst = []
            for grade in grades:
                grade_lst = []
                for base in grade:
                    latex_base = LatexPrinter.extended_symbol(base)
                    grade_lst.append(latex_base)
                grades_lst.append(grade_lst)
            LatexPrinter.latexbasis_lst.append(grades_lst)
        return

    @staticmethod
    def build_base(igrade, iblade, bld_flg):
        if igrade == 0:
            return('')
        base_lst = LatexPrinter.latexbasis_lst[igrade][iblade]
        if len(base_lst) == 1:
            return(base_lst[0])
        base_str = ''
        for base in base_lst[:-1]:
            if bld_flg:
                base_str += base + '\\W '
            else:
                base_str += base
        base_str += base_lst[-1]
        return(base_str)

    @staticmethod
    def format(sym=0, fct=0, pdiff=0, mv=0):
        LatexPrinter.LaTeX_flg = True
        LatexPrinter.fmt_dict['sym'] = sym
        LatexPrinter.fmt_dict['fct'] = fct
        LatexPrinter.fmt_dict['pdiff'] = pdiff
        LatexPrinter.fmt_dict['mv'] = mv
        LatexPrinter.fmt_dict['str'] = 1
        if sympy.galgebra.GA.MV.is_setup:
            LatexPrinter.latex_bases()
        LatexPrinter.redirect()
        return

    @staticmethod
    def str_basic(in_str):
        if not LatexPrinter.LaTeX_flg:
            return(str(in_str))
        Basic.__str__ = LatexPrinter.Basic__str__
        out_str = str(in_str)
        Basic.__str__ = LaTeX
        return(out_str)

    @staticmethod
    def redirect():
        LatexPrinter.Basic__str__ = Basic.__str__
        LatexPrinter.MV__str__ = sympy.galgebra.GA.MV.__str__
        LatexPrinter.stdout = sys.stdout
        sys.stdout = StringIO.StringIO()
        Basic.__str__ = LaTeX
        sympy.galgebra.GA.MV.__str__ = LaTeX
        return

    @staticmethod
    def restore():
        LatexPrinter_stdout = sys.stdout
        LatexPrinter_Basic__str__ = Basic.__str__
        LatexPrinter_MV__str__ = sympy.galgebra.GA.MV.__str__

        sys.stdout = LatexPrinter.stdout
        Basic.__str__ = LatexPrinter.Basic__str__
        sympy.galgebra.GA.MV.__str__ = LatexPrinter.MV__str__

        LatexPrinter.stdout = LatexPrinter_stdout
        LatexPrinter.Basic__str__ = LatexPrinter_Basic__str__
        LatexPrinter.MV__str__ = LatexPrinter_MV__str__
        return

    @staticmethod
    def format_str(fmt='0 0 0 0'):
        fmt_lst = fmt.split()
        if '=' not in fmt:
            LatexPrinter.fmt_dict['sym'] = int(fmt_lst[0])
            LatexPrinter.fmt_dict['fct'] = int(fmt_lst[1])
            LatexPrinter.fmt_dict['pdiff'] = int(fmt_lst[2])
            LatexPrinter.fmt_dict['mv'] = int(fmt_lst[3])
        else:
            for fmt in fmt_lst:
                x = fmt.split('=')
                LatexPrinter.fmt_dict[x[0]] = int(x[1])

        if LatexPrinter.LaTeX_flg is False:
            if sympy.galgebra.GA.MV.is_setup:
                LatexPrinter.latex_bases()
            LatexPrinter.redirect()
            LatexPrinter.LaTeX_flg = True
        return

    @staticmethod
    def append_body(xstr):
        if LatexPrinter.body_flg:
            LatexPrinter.body += xstr
            return('')
        else:
            return(xstr[:-1])

    @staticmethod
    def tokenize_greek(name_str):
        for sym in LatexPrinter.greek_keys:
            isym = name_str.find(sym)
            if isym > -1:
                keystr = '@' + str(LatexPrinter.greek_cnt)
                LatexPrinter.greek_cnt += 1
                LatexPrinter.greek_dict[keystr] = sym
                name_str = name_str.replace(sym, keystr)
        return(name_str)

    @staticmethod
    def tokenize_accents(name_str):
        for sym in LatexPrinter.accent_keys:
            if name_str.find(sym) > -1:
                keystr = '#' + str(LatexPrinter.accent_cnt) + '#'
                LatexPrinter.accent_cnt += 1
                LatexPrinter.accent_dict[keystr] = '\\' + sym
                name_str = name_str.replace(sym, keystr)
        return(name_str)

    @staticmethod
    def replace_greek_tokens(name_str):
        if name_str.find('@') == -1:
            return(name_str)
        for token in LatexPrinter.greek_dict.keys():
            name_str = name_str.replace(
                token, '{\\' + LatexPrinter.greek_dict[token] + '}')
        LatexPrinter.greek_cnt = 0
        LatexPrinter.greek_dict = {}
        return(name_str)

    @staticmethod
    def replace_accent_tokens(name_str):
        tmp_lst = name_str.split('#')
        name_str = tmp_lst[0]
        if len(tmp_lst) == 1:
            return(name_str)
        for x in tmp_lst[1:]:
            if x != '':
                name_str = '{}' + LatexPrinter.accent_dict[
                    '#' + x + '#'] + '{' + name_str + '}'
        LatexPrinter.accent_cnt = 0
        LatexPrinter.accent_dict = {}
        return(name_str)

    @staticmethod
    def extended_symbol(name_str):
        name_str = LatexPrinter.tokenize_greek(name_str)
        tmp_lst = name_str.split('_')
        subsup_str = ''
        sym_str = tmp_lst[0]
        sym_str = LatexPrinter.tokenize_accents(sym_str)
        sym_str = LatexPrinter.replace_accent_tokens(sym_str)
        if len(tmp_lst) > 1:
            imode = 0
            for x in tmp_lst[1:]:
                if x == '':
                    imode = (imode + 1) % 2
                else:
                    subsup_str += LatexPrinter.mode[imode] + '{' + x + '}'
                    #subsup_str += LatexPrinter.mode[imode]+x+' '
                    imode = (imode + 1) % 2
        name_str = sym_str + subsup_str
        name_str = LatexPrinter.replace_greek_tokens(name_str)
        return(name_str)

    def coefficient(self, coef, first_flg):
        if isinstance(coef, C.AssocOp) and isinstance(-coef, C.AssocOp):
            coef_str = r"\lp %s\rp " % self._print(coef)
        else:
            coef_str = self._print(coef)
        if first_flg:
            first_flg = False
            if coef_str[0] == '+':
                coef_str = coef_str[1:]
        else:
            if coef_str[0] != '-':
                if coef_str[0] != '+':
                    coef_str = '+' + coef_str
        if coef_str in ('1', '+1', '-1'):
            if coef_str == '1':
                coef_str = ''
            else:
                coef_str = coef_str[0]
        return(coef_str, first_flg)

    def __init__(self, inline=True):
        Printer.__init__(self)
        self._inline = inline

    def doprint(self, expr):
        tex = Printer.doprint(self, expr)
        xstr = ''

        if self._inline:
            if LatexPrinter.fmt_dict['fct'] == 1:
                xstr = r"%s" % tex
            else:
                xstr = r"$%s$" % tex
        else:
            xstr = r"\begin{equation*}%s\end{equation*}" % tex
        return(xstr)

    def _needs_brackets(self, expr):
        return not ((expr.is_Integer and expr.is_nonnegative) or expr.is_Atom)

    def _do_exponent(self, expr, exp):
        if exp is not None:
            return r"\left(%s\right)^{%s}" % (expr, exp)
        else:
            return expr

    def _print_Add(self, expr):
        tex = str(self._print(expr.args[0]))

        for term in expr.args[1:]:
            if _coeff_isneg(term):
                tex += r" %s" % self._print(term)
            else:
                tex += r" + %s" % self._print(term)

        return tex

    def _print_Mul(self, expr):
        coeff, tail = expr.as_coeff_Mul()

        if coeff.is_negative:
            coeff = -coeff
            tex = "- "
        else:
            tex = ""

        numer, denom = fraction(tail)

        def convert(terms):
            product = []

            if not terms.is_Mul:
                return str(self._print(terms))
            else:
                for term in terms.args:
                    pretty = self._print(term)

                    if term.is_Add:
                        product.append(r"\left(%s\right)" % pretty)
                    else:
                        product.append(str(pretty))

                return r" ".join(product)

        if denom is S.One:
            if coeff is not S.One:
                tex += str(self._print(coeff)) + " "

            if numer.is_Add:
                tex += r"\left(%s\right)" % convert(numer)
            else:
                tex += r"%s" % convert(numer)
        else:
            if numer is S.One:
                if coeff.is_Integer:
                    numer *= coeff.p
                elif coeff.is_Rational:
                    if coeff.p != 1:
                        numer *= coeff.p

                    denom *= coeff.q
                elif coeff is not S.One:
                    tex += str(self._print(coeff)) + " "
            else:
                if coeff.is_Rational and coeff.p == 1:
                    denom *= coeff.q
                elif coeff is not S.One:
                    tex += str(self._print(coeff)) + " "

            tex += r"\frac{%s}{%s}" % \
                (convert(numer), convert(denom))

        return tex

    def _print_Pow(self, expr):
        if expr.exp.is_Rational and expr.exp.q == 2:
            base, exp = self._print(expr.base), abs(expr.exp.p)

            if exp == 1:
                tex = r"\sqrt{%s}" % base
            else:
                tex = r"\sqrt[%s]{%s}" % (exp, base)

            if expr.exp.is_negative:
                return r"\frac{1}{%s}" % tex
            else:
                return tex
        else:
            if expr.base.is_Function:
                return self._print(expr.base, self._print(expr.exp))
            else:
                if expr.exp == S.NegativeOne:
                    #solves issue 1030
                    #As Mul always simplify 1/x to x**-1
                    #The objective is achieved with this hack
                    #first we get the latex for -1 * expr,
                    #which is a Mul expression
                    tex = self._print(S.NegativeOne * expr).strip()
                    #the result comes with a minus and a space, so we remove
                    if tex[:1] == "-":
                        return tex[1:].strip()
                if self._needs_brackets(expr.base):
                    tex = r"\left(%s\right)^{%s}"
                else:
                    tex = r"{%s}^{%s}"

                return tex % (self._print(expr.base),
                              self._print(expr.exp))

    def _print_Derivative(self, expr):
        dim = len(expr.variables)

        if dim == 1:
            if LatexPrinter.fmt_dict['pdiff'] == 1:
                tex = r'\partial_{%s}' % self._print(expr.variables[0])
            else:
                tex = r"\frac{\partial}{\partial %s}" % self._print(
                    expr.variables[0])
        else:
            multiplicity, i, tex = [], 1, ""
            current = expr.variables[0]
            for symbol in expr.variables[1:]:
                if symbol == current:
                    i = i + 1
                else:
                    multiplicity.append((current, i))
                    current, i = symbol, 1
            else:
                multiplicity.append((current, i))

            if LatexPrinter.fmt_dict['pdiff'] == 1:
                for x, i in multiplicity:
                    if i == 1:
                        tex += r"\partial_{%s}" % self._print(x)
                    else:
                        tex += r"\partial^{%s}_{%s}" % (i, self._print(x))
            else:
                for x, i in multiplicity:
                    if i == 1:
                        tex += r"\partial %s" % self._print(x)
                    else:
                        tex += r"\partial^{%s} %s" % (i, self._print(x))

                tex = r"\frac{\partial^{%s}}{%s} " % (dim, tex)

        if isinstance(expr.expr, C.AssocOp):
            return r"%s\left(%s\right)" % (tex, self._print(expr.expr))
        else:
            return r"%s %s" % (tex, self._print(expr.expr))

    def _print_Integral(self, expr):
        tex, symbols = "", []

        for symbol, limits in reversed(expr.limits):
            tex += r"\int"

            if limits is not None:
                if not self._inline:
                    tex += r"\limits"

                tex += "_{%s}^{%s}" % (self._print(limits[0]),
                                       self._print(limits[1]))

            symbols.insert(0, "d%s" % self._print(symbol))

        return r"%s %s\,%s" % (tex,
            str(self._print(expr.function)), " ".join(symbols))

    def _print_Limit(self, expr):
        tex = r"\lim_{%s \to %s}" % (self._print(expr.var),
                                     self._print(expr.varlim))

        if isinstance(expr.expr, C.AssocOp):
            return r"%s\left(%s\right)" % (tex, self._print(expr.expr))
        else:
            return r"%s %s" % (tex, self._print(expr.expr))

    def _print_Function(self, expr, exp=None):
        func = expr.func.__name__

        if hasattr(self, '_print_' + func):
            return getattr(self, '_print_' + func)(expr, exp)
        else:
            args = [ str(self._print(arg)) for arg in expr.args ]

            if LatexPrinter.fmt_dict['fct'] == 1:
                if func in LatexPrinter.fct_dict_keys:
                    if exp is not None:
                        if func in accepted_latex_functions:
                            name = r"\%s^{%s}" % (
                                LatexPrinter.fct_dict[func], exp)
                        else:
                            name = r"\operatorname{%s}^{%s}" % (
                                LatexPrinter.fct_dict[func], exp)
                    else:
                        if LatexPrinter.fct_dict[func] in accepted_latex_functions:
                            name = r"\%s" % LatexPrinter.fct_dict[func]
                        else:
                            name = r"\operatorname{%s}" % LatexPrinter.fct_dict[func]
                    name += r"\left(%s\right)" % ",".join(args)
                    return name
                else:
                    func = self.print_Symbol_name(func)
                    if exp is not None:
                        name = r"{%s}^{%s}" % (func, exp)
                    else:
                        name = r"{%s}" % func
                    return name
            else:
                if exp is not None:
                    if func in accepted_latex_functions:
                        name = r"\%s^{%s}" % (func, exp)
                    else:
                        name = r"\operatorname{%s}^{%s}" % (func, exp)
                else:
                    if func in accepted_latex_functions:
                        name = r"\%s" % func
                    else:
                        name = r"\operatorname{%s}" % func
                return name + r"\left(%s\right)" % ",".join(args)

    def _print_floor(self, expr, exp=None):
        tex = r"\lfloor{%s}\rfloor" % self._print(expr.args[0])

        if exp is not None:
            return r"%s^{%s}" % (tex, exp)
        else:
            return tex

    def _print_ceiling(self, expr, exp=None):
        tex = r"\lceil{%s}\rceil" % self._print(expr.args[0])

        if exp is not None:
            return r"%s^{%s}" % (tex, exp)
        else:
            return tex

    def _print_abs(self, expr, exp=None):
        tex = r"\lvert{%s}\rvert" % self._print(expr.args[0])

        if exp is not None:
            return r"%s^{%s}" % (tex, exp)
        else:
            return tex

    def _print_re(self, expr, exp=None):
        if self._needs_brackets(expr.args[0]):
            tex = r"\Re\left(%s\right)" % self._print(expr.args[0])
        else:
            tex = r"\Re{%s}" % self._print(expr.args[0])

        return self._do_exponent(tex, exp)

    def _print_im(self, expr, exp=None):
        if self._needs_brackets(expr.args[0]):
            tex = r"\Im\left(%s\right)" % self._print(expr.args[0])
        else:
            tex = r"\Im{%s}" % self._print(expr.args[0])

        return self._do_exponent(tex, exp)

    def _print_conjugate(self, expr, exp=None):
        tex = r"\overline{%s}" % self._print(expr.args[0])

        if exp is not None:
            return r"%s^{%s}" % (tex, exp)
        else:
            return tex

    def _print_exp(self, expr, exp=None):
        tex = r"{e}^{%s}" % self._print(expr.args[0])
        return self._do_exponent(tex, exp)

    def _print_gamma(self, expr, exp=None):
        tex = r"\left(%s\right)" % self._print(expr.args[0])

        if exp is not None:
            return r"\Gamma^{%s}%s" % (exp, tex)
        else:
            return r"\Gamma%s" % tex

    def _print_factorial(self, expr, exp=None):
        x = expr.args[0]
        if self._needs_brackets(x):
            tex = r"\left(%s\right)!" % self._print(x)
        else:
            tex = self._print(x) + "!"

        if exp is not None:
            return r"%s^{%s}" % (tex, exp)
        else:
            return tex

    def _print_factorial(self, expr, exp=None):
        x = expr.args[0]
        if self._needs_brackets(x):
            tex = r"!\left(%s\right)" % self._print(x)
        else:
            tex = "!" + self._print(x)

        if exp is not None:
            return r"%s^{%s}" % (tex, exp)
        else:
            return tex

    def _print_binomial(self, expr, exp=None):
        tex = r"{{%s}\choose{%s}}" % (self._print(expr[0]),
                                      self._print(expr[1]))

        if exp is not None:
            return r"%s^{%s}" % (tex, exp)
        else:
            return tex

    def _print_RisingFactorial(self, expr, exp=None):
        tex = r"{\left(%s\right)}^{\left(%s\right)}" % \
            (self._print(expr[0]), self._print(expr[1]))

        return self._do_exponent(tex, exp)

    def _print_FallingFactorial(self, expr, exp=None):
        tex = r"{\left(%s\right)}_{\left(%s\right)}" % \
            (self._print(expr[0]), self._print(expr[1]))

        return self._do_exponent(tex, exp)

    def _print_Rational(self, expr):
        if expr.q != 1:
            sign = ""
            p = expr.p
            if expr.p < 0:
                sign = "- "
                p = -p
            return r"%s\frac{%d}{%d}" % (sign, p, expr.q)
        else:
            return self._print(expr.p)

    def _print_Infinity(self, expr):
        return r"\infty"

    def _print_NegativeInfinity(self, expr):
        return r"-\infty"

    def _print_ComplexInfinity(self, expr):
        return r"\tilde{\infty}"

    def _print_ImaginaryUnit(self, expr):
        return r"\mathbf{\imath}"

    def _print_NaN(self, expr):
        return r"\bot"

    def _print_Pi(self, expr):
        return r"\pi"

    def _print_Exp1(self, expr):
        return r"e"

    def _print_EulerGamma(self, expr):
        return r"\gamma"

    def _print_Order(self, expr):
        return r"\\mathcal{O}\left(%s\right)" % \
            self._print(expr.args[0])

    @staticmethod
    def print_Symbol_name(name_str):
        if len(name_str) == 1:
            return (name_str)
        if LatexPrinter.fmt_dict['sym'] == 1:
            return LatexPrinter.extended_symbol(name_str)
        else:
            return(name_str)

        #convert trailing digits to subscript
            m = regrep.match('(^[a-zA-Z]+)([0-9]+)$', name_str)
            if m is not None:
                name, sub = m.groups()
                tex = self._print_Symbol(Symbol(name))
                tex = "%s_{%s}" % (tex, sub)
                return tex

            # insert braces to expresions containing '_' or '^'
            m = regrep.match(
                '(^[a-zA-Z0-9]+)([_\^]{1})([a-zA-Z0-9]+)$', name_str)
            if m is not None:
                name, sep, rest = m.groups()
                tex = self._print_Symbol(Symbol(name))
                tex = "%s%s{%s}" % (tex, sep, rest)
                return tex

            greek = set([ 'alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta',
                          'eta', 'theta', 'iota', 'kappa', 'lambda', 'mu', 'nu',
                          'xi', 'omicron', 'pi', 'rho', 'sigma', 'tau', 'upsilon',
                          'phi', 'chi', 'psi', 'omega' ])

            other = set( ['aleph', 'beth', 'daleth', 'gimel', 'ell', 'eth',
                          'hbar', 'hslash', 'mho' ])

            if name_str.lower() in greek:
                return "\\" + name_str
            elif name_str in other:
                return "\\" + name_str
            else:
                return name_str

    def _print_Symbol(self, expr):
        return LatexPrinter.print_Symbol_name(expr.name)

    def _print_str(self, expr):
        if LatexPrinter.fmt_dict['str'] > 0:
            expr = expr.replace('^', '{\\wedge}')
            expr = expr.replace('|', '{\\cdot}')
            expr = expr.replace('__', '^')
        return(expr)

    def _print_ndarray(self, expr):
        shape = numpy.shape(expr)
        ndim = len(shape)
        expr_str = ''

        if ndim == 1:
            expr_str += '#\\left [ \\begin{array}{' + shape[0]*'c' + '}  \n'
            for col in expr:
                expr_str += self._print(col) + ' & '
            expr_str = expr_str[:-2] + '\n\\end{array}\\right ]#\n'
            return(expr_str)

        if ndim == 2:
            expr_str += '#\\left [ \\begin{array}{' + shape[1]*'c' + '}  \n'
            for row in expr[:-1]:
                for xij in row[:-1]:
                    expr_str += self._print(xij) + ' & '
                expr_str += self._print(row[-1]) + ' \\\\ \n'
            for xij in expr[-1][:-1]:
                expr_str += self._print(xij) + ' & '
            expr_str += self._print(
                expr[-1][-1]) + '\n \\end{array} \\right ] #\n'
            return(expr_str)

        if ndim == 3:
            expr_str = '#\\left \\{ \\begin{array}{' + shape[0]*'c' + '} \n'
            for x in expr[:-1]:
                xstr = self._print(x).replace('#', '')
                expr_str += xstr + ' , & '
            xstr = self._print(expr[-1]).replace('#', '')
            expr_str += xstr + '\n\\end{array} \\right \\}#\n'
        return(expr_str)

    def _print_MV(self, expr):
        igrade = 0
        MV_str = ''
        line_lst = []
        for grade in expr.mv:
            if not isinstance(grade, types.IntType):
                ibase = 0
                for base in grade:
                    if base != 0:
                        tmp = Symbol('XYZW')
                        base_str = str(base*tmp)
                        if base_str[0] != '-':
                            base_str = '+' + base_str
                        base_str = base_str.replace('- ', '-')
                        if base_str[1:5] == 'XYZW':
                            base_str = base_str.replace('XYZW', '')
                        else:
                            base_str = base_str.replace('XYZW', '1')
                        MV_str += base_str + LatexPrinter.build_base(
                            igrade, ibase, expr.bladeflg)
                        if LatexPrinter.fmt_dict['mv'] == 3:
                            line_lst.append(MV_str)
                            MV_str = ''
                    ibase += 1
                if LatexPrinter.fmt_dict['mv'] == 2:
                    if MV_str != '':
                        line_lst.append(MV_str)
                        MV_str = ''
            igrade += 1
        n_lines = len(line_lst)
        if MV_str == '':
            if n_lines > 0 and line_lst[0][0] == '+':
                line_lst[0] = line_lst[0][1:]
        else:
            if MV_str[0] == '+':
                MV_str = MV_str[1:]
        if n_lines == 1:
            MV_str = line_lst[0]
            n_lines = 0
        if LatexPrinter.fmt_dict['mv'] >= 2:
            MV_str = '@' + line_lst[0] + ' \\\\ \n'
            for line in line_lst[1:-1]:
                MV_str += '& ' + line + ' \\\\ \n'
            MV_str += '& ' + line_lst[-1] + '@\n'
        if MV_str == '':
            MV_str = '0'
        if expr.name != '':
            MV_str = LatexPrinter.extended_symbol(expr.name) + ' = ' + MV_str
        return(MV_str)

    def _print_OMV(self, expr):
        igrade = 0
        MV_str = ''
        line_lst = []
        for grade in expr.mv:
            if not isinstance(grade, None):
                ibase = 0
                for base in grade:
                    if base != 0:
                        tmp = Symbol('XYZW')
                        base_str = str(base*tmp)
                        if base_str[0] != '-':
                            base_str = '+' + base_str
                        base_str = base_str.replace('- ', '-')
                        if base_str[1:5] == 'XYZW':
                            base_str = base_str.replace('XYZW', '')
                        else:
                            base_str = base_str.replace('XYZW', '1')
                        MV_str += base_str + LatexPrinter.build_base(
                            igrade, ibase, expr.bladeflg)
                        if LatexPrinter.fmt_dict['mv'] == 3:
                            line_lst.append(MV_str)
                            MV_str = ''
                    ibase += 1
                if LatexPrinter.fmt_dict['mv'] == 2:
                    if MV_str != '':
                        line_lst.append(MV_str)
                        MV_str = ''
            igrade += 1
        n_lines = len(line_lst)
        if MV_str == '':
            if n_lines > 0 and line_lst[0][0] == '+':
                line_lst[0] = line_lst[0][1:]
        else:
            if MV_str[0] == '+':
                MV_str = MV_str[1:]
        if n_lines == 1:
            MV_str = line_lst[0]
            n_lines = 0
        if LatexPrinter.fmt_dict['mv'] >= 2:
            MV_str = '@' + line_lst[0] + ' \\\\ \n'
            for line in line_lst[1:-1]:
                MV_str += '& ' + line + ' \\\\ \n'
            MV_str += '& ' + line_lst[-1] + '@\n'
        if MV_str == '':
            MV_str = '0'
        if expr.name != '':
            MV_str = LatexPrinter.extended_symbol(expr.name) + ' = ' + MV_str
        return(MV_str)

    def _print_Relational(self, expr):
        charmap = {
            "==": "=",
            "<": "<",
            "<=": r"\leq",
            "!=": r"\neq",
        }

        return "%s %s %s" % (self._print(expr.lhs),
            charmap[expr.rel_op], self._print(expr.rhs))

    def _print_Matrix(self, expr):
        lines = []

        for line in range(expr.lines):  # horrible, should be 'rows'
            lines.append(" & ".join([ self._print(i) for i in expr[line, :] ]))

        if self._inline:
            tex = r"\left(\begin{smallmatrix}%s\end{smallmatrix}\right)"
        else:
            tex = r"\begin{pmatrix}%s\end{pmatrix}"

        return tex % r"\\".join(lines)

    def _print_tuple(self, expr):
        return r"\begin{pmatrix}%s\end{pmatrix}" % \
            r", & ".join([ self._print(i) for i in expr ])

    def _print_list(self, expr):
        return r"\begin{bmatrix}%s\end{bmatrix}" % \
            r", & ".join([ self._print(i) for i in expr ])

    def _print_dict(self, expr):
        items = []

        keys = expr.keys()
        keys.sort(key=default_sort_key)
        for key in keys:
            val = expr[key]
            items.append("%s : %s" % (self._print(key), self._print(val)))

        return r"\begin{Bmatrix}%s\end{Bmatrix}" % r", & ".join(items)

    def _print_DiracDelta(self, expr):
        if len(expr.args) == 1 or expr.args[1] == 0:
            tex = r"\delta\left(%s\right)" % self._print(expr.args[0])
        else:
            tex = r"\delta^{\left( %s \right)}\left( %s \right)" % (
                self._print(expr.args[1]), self._print(expr.args[0]))
        return tex


def LaTeX(expr, inline=True):
    """
    Convert the given expression to LaTeX representation.

    You can specify how the generated code will be delimited.
    If the 'inline' keyword is set then inline LaTeX $ $ will
    be used. Otherwise the resulting code will be enclosed in
    'equation*' environment (remember to import 'amsmath').

    >>> from sympy import Rational
    >>> from sympy.abc import tau, mu, x, y
    >>> from sympy.galgebra.latex_ex import LaTeX

    >>> LaTeX((2*tau)**Rational(7,2))
    '$8 \\\\sqrt{2} \\\\sqrt[7]{\\\\tau}$'

    >>> LaTeX((2*mu)**Rational(7,2), inline=False)
    '\\\\begin{equation*}8 \\\\sqrt{2} \\\\sqrt[7]{\\\\mu}\\\\end{equation*}'

    Besides all Basic based expressions, you can recursively
    convert Python containers (lists, tuples and dicts) and
    also SymPy matrices:

    >>> LaTeX([2/x, y])
    '$\\\\begin{bmatrix}\\\\frac{2}{x}, & y\\\\end{bmatrix}$'

    The extended latex printer will also append the output to a
    string (LatexPrinter.body) that will be processed by xdvi()
    for immediate display one xdvi() is called.
    """
    xstr = LatexPrinter(inline).doprint(expr)
    return (xstr)


def print_LaTeX(expr):
    """Prints LaTeX representation of the given expression."""
    print LaTeX(expr)


def Format(fmt='1 1 1 1'):
    LatexPrinter.format_str(fmt)
    return


def xdvi(filename='tmplatex.tex', debug=False):
    """
    Post processes LaTeX output (see comments below), adds preamble and
    postscript, generates tex file, inputs file to latex, displays resulting
    dvi file with xdvi or yap.
    """
    if not LatexPrinter.LaTeX_flg:
        return
    body = sys.stdout.getvalue()
    LatexPrinter.restore()

    body_lst = body.split('\n')
    body = ''
    array_flg = False
    eqnarray_flg = False
    raw_flg = False
    i = iter(body_lst)
    line = i.next()

    while True:
        if '$' in line:  # Inline math expression(s)
            if len(line) > 0:
                line += '\\newline \n'
            body += line
            try:
                line = i.next()
            except StopIteration:
                break

        elif '%' in line:  # Raw LaTeX input
            """
            If % in line assume line is beginning of raw LaTeX input and stop
            post processing
            """
            line = line.replace('%', '')
            raw_flg = True
            while raw_flg:
                if '%' in line:
                    """
                    If % in line assume line is end of LaTeX input and begin
                    post processing
                    """
                    raw_flg = False
                    line = line.replace('%', '') + '\n'
                else:
                    line += '\n'
                line = process_equals(line)
                body += line
                try:
                    line = i.next()
                except StopIteration:
                    break

        elif '#' in line:  # Array input
            """
            If # in line assume line is beginning of array input and contains
            \begin{array} statement
            """
            line = line.replace('#', '')
            array_flg = True
            line = '\\begin{equation*}\n' + line
            while array_flg:
                if '#' in line:
                    """
                    If # in line assume line is end of array input and contains
                    \end{array} statement
                    """
                    array_flg = False
                    line = line.replace('#', '')
                    line += '\\end{equation*}\n'
                else:
                    line += '\n'
                line = process_equals(line)
                body += line
                try:
                    line = i.next()
                except StopIteration:
                    break

        elif '@' in line:  # Align input
            """
            If @ in line assume line is beginning of align input
            """
            line = line.replace('@', '')
            line = line.replace('=', '& = ')
            eqnarray_flg = True
            line = '\\begin{align*}\n' + line
            line = process_equals(line)
            body += line
            try:
                line = i.next()
            except StopIteration:
                break
            while eqnarray_flg:
                if '@' in line:
                    """
                    If @ in line assume line is end of align input
                    """
                    eqnarray_flg = False
                    line = line.replace('@', '')
                    line += '\\end{align*}\n'
                else:
                    line + '\n'
                line = process_equals(line)
                body += line
                try:
                    line = i.next()
                except StopIteration:
                    break

        else:
            if '=' in line:  # Single line equation
                line = '\\begin{equation*}\n' + line + '\n\\end{equation*}'
            else:  # Text with no math expression(s)unless \ or _ in line
                if '\\' in line or '_' in line or '^' in line:
                    line = '\\begin{equation*}\n' + line + '\n\\end{equation*}'
                else:
                    if len(line) > 0:
                        line += '\\newline \n'
            line = process_equals(line)
            body += line
            try:
                line = i.next()
            except StopIteration:
                break
    preview(body, output='dvi', outputTexFile=filename,
            preamble=LatexPrinter.preamble)
    LatexPrinter.LaTeX_flg = False
    return


def MV_format(mv_fmt):
    """
    0 or 1 - Print multivector on one line

    2      - Print each multivector grade on one line

    3      - Print each multivector base on one line
    """
    if LatexPrinter.LaTeX_flg:
        LatexPrinter.fmt_dict['mv'] = mv_fmt
    return


def fct_format(fct_fmt):
    """
    0 - Default sympy latex format

    1 - Do not print arguments of arbitrary functions.
        Use symbol font for arbitrary functions.
        Use enhanced symbol naming for arbitrary functions.
        Use new names for standard functions (acos -> Cos^{-1})

    """
    if LatexPrinter.LaTeX_flg:
        LatexPrinter.fct = fct_fmt
    return


def pdiff_format(pdiff_fmt):
    """
    0 - Use default sympy partial derivative format

    1 - Contracted derivative format (no fraction symbols)
    """
    if LatexPrinter.LaTeX_flg:
        LatexPrinter.fmt_dict['pdiff'] = pdiff_fmt
    return


def sym_format(sym_fmt):
    """
    0 - Use default sympy format

    1 - Use extended symbol format including multiple Greek letters in
        basic symbol (symbol preceding sub and superscripts)and in
        sub and superscripts of basic symbol and accents in basic symbol

    """
    if LatexPrinter.LaTeX_flg:
        LatexPrinter.fmt_dict['sym'] = sym_fmt
    return


def str_format(str_fmt):
    """
    0 - Use default sympy format

    1 - Use extended symbol format including multiple Greek letters in
        basic symbol (symbol preceding sub and superscripts)and in
        sub and superscripts of basic symbol and accents in basic symbol

    """
    if LatexPrinter.LaTeX_flg:
        LatexPrinter.fmt_dict['str'] = str_fmt
    return


def ext_str(xstr):
    return(LatexPrinter.extended_symbol(xstr))
