#latex_ex.py

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

import os,types,StringIO

from sympy.core import S, C, Basic, Symbol, Mul
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, cmp

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

def find_executable(executable, path=None):
    """Try to find 'executable' in the directories listed in 'path' (a
    string listing directories separated by 'os.pathsep'; defaults to
    os.environ['PATH']).  Returns the complete filename or None if not
    found
    """
    if path is None:
        path = os.environ['PATH']
    paths = path.split(os.pathsep)
    extlist = ['']
    if os.name == 'os2':
        (base, ext) = os.path.splitext(executable)
        # executable files on OS/2 can have an arbitrary extension, but
        # .exe is automatically appended if no dot is present in the name
        if not ext:
            executable = executable + ".exe"
    elif sys.platform == 'win32':
        pathext = os.environ['PATHEXT'].lower().split(os.pathsep)
        (base, ext) = os.path.splitext(executable)
        if ext.lower() not in pathext:
            extlist = pathext
    for ext in extlist:
        execname = executable + ext
        if os.path.isfile(execname):
            return execname
        else:
            for p in paths:
                f = os.path.join(p, execname)
                if os.path.isfile(f):
                    return f
    else:
        return None

def debug(tstr):
    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):
    """
    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
            1 - 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.
            2 - 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:
            1 - Print multivector on one line
            2 - Print each grade of multivector on one line
            3 - 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.
            1 - 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.
            2 - 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.
            3 - 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:
            0 - Same as sympy latex module
            1 - 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'
    postscript = '\\end{document}\n'

    @staticmethod
    def latex_bases():
        """
        Generate LaTeX strings for multivector bases
        """
        if type(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 == 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:]:
            coeff = term.as_coeff_mul()[0]

            if coeff.is_negative:
                tex += r" %s" % self._print(term)
            else:
                tex += r" + %s" % self._print(term)

        return tex

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

        if not coeff.is_negative:
            tex = ""
        else:
            coeff = -coeff
            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:
                        name = r"\operatorname{%s}^{%s}" % (LatexPrinter.fct_dict[func], exp)
                    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:
                    name = r"\operatorname{%s}^{%s}" % (func, exp)
                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"\operatorname{\Gamma}^{%s}%s" % (exp, tex)
        else:
            return r"\operatorname{\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_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"\operatorname{\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 = []
        first_flg = True
        for grade in expr.mv:
            if type(grade) != types.IntType:
                if type(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 = []
        first_flg = True
        for grade in expr.mv:
            if type(grade) is not None:
                if type(grade) is not 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(Basic.compare_pretty)
        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

    >>> 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
    nline = len(body_lst)
    iline = 0
    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
    body = LatexPrinter.preamble+body+LatexPrinter.postscript
    latex_file = open(filename,'w')
    latex_file.write(body)
    latex_file.close()

    latex_str = None
    xdvi_str  = None

    if find_executable('latex') is not None:
        latex_str = 'latex'

    if find_executable('xdvi') is not None:
        xdvi_str = 'xdvi'

    if find_executable('yap') is not None:
        xdvi_str = 'yap'

    if latex_str is not None and xdvi_str is not None:
        if debug: #Display latex excution output for debugging purposes
            os.system(latex_str+' '+filename[:-4])
        else: #Works for Linux don't know about Windows
            if sys.platform.startswith('linux'):
                os.system(latex_str+' '+filename[:-4]+' > /dev/null')
            else:
                os.system(latex_str+' '+filename[:-4]+' > NUL')
        os.system(xdvi_str+' '+filename[:-4]+' &')
    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))
