Source code for sympy.galgebra.latex_ex

#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)


[docs]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
[docs] 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
[docs]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 Format(fmt='1 1 1 1'): LatexPrinter.format_str(fmt) return
[docs]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
[docs]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
[docs]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
[docs]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
[docs]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
[docs]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))