Source code for diofant.printing.latex

"""
A Printer which converts an expression into its LaTeX equivalent.
"""

import re

import mpmath.libmp as mlib
from mpmath.libmp import prec_to_dps

from ..core import Add, Mod, S, Symbol, oo
from ..core.alphabets import greeks
from ..core.compatibility import default_sort_key
from ..core.function import _coeff_isneg
from ..core.operations import AssocOp
from ..core.relational import Relational
from ..logic import true
from ..utilities import has_variety
from .conventions import requires_partial, split_super_sub
from .precedence import PRECEDENCE, precedence
from .printer import Printer


# Hand-picked functions which can be used directly in both LaTeX and MathJax
# Complete list at http://www.mathjax.org/docs/1.1/tex.html#supported-latex-commands
# This variable only contains those functions which diofant uses.
accepted_latex_functions = ['arcsin', 'arccos', 'arctan', 'sin', 'cos', 'tan',
                            'sinh', 'cosh', 'tanh', 'sqrt', 'ln', 'log', 'sec',
                            'csc',  'cot', 'coth', 're', 'im', 'frac', 'root',
                            'arg']

tex_greek_dictionary = {
    'Alpha': 'A',
    'Beta': 'B',
    'Epsilon': 'E',
    'Zeta': 'Z',
    'Eta': 'H',
    'Iota': 'I',
    'Kappa': 'K',
    'Mu': 'M',
    'Nu': 'N',
    'omicron': 'o',
    'Omicron': 'O',
    'Rho': 'P',
    'Tau': 'T',
    'Chi': 'X',
    'lamda': r'\lambda',
    'Lamda': r'\Lambda',
    'khi': r'\chi',
    'Khi': r'X',
    'varepsilon': r'\varepsilon',
    'varkappa': r'\varkappa',
    'varphi': r'\varphi',
    'varpi': r'\varpi',
    'varrho': r'\varrho',
    'varsigma': r'\varsigma',
    'vartheta': r'\vartheta',
}

other_symbols = {'aleph', 'beth', 'daleth', 'gimel', 'ell', 'eth', 'hbar',
                 'hslash', 'mho', 'wp', }

# Variable name modifiers
modifier_dict = {
    # Accents
    'mathring': lambda s: r'\mathring{'+s+r'}',
    'ddddot': lambda s: r'\ddddot{'+s+r'}',
    'dddot': lambda s: r'\dddot{'+s+r'}',
    'ddot': lambda s: r'\ddot{'+s+r'}',
    'dot': lambda s: r'\dot{'+s+r'}',
    'check': lambda s: r'\check{'+s+r'}',
    'breve': lambda s: r'\breve{'+s+r'}',
    'acute': lambda s: r'\acute{'+s+r'}',
    'grave': lambda s: r'\grave{'+s+r'}',
    'tilde': lambda s: r'\tilde{'+s+r'}',
    'hat': lambda s: r'\hat{'+s+r'}',
    'bar': lambda s: r'\bar{'+s+r'}',
    'vec': lambda s: r'\vec{'+s+r'}',
    'prime': lambda s: "{"+s+"}'",
    'prm': lambda s: "{"+s+"}'",
    # Faces
    'bold': lambda s: r'\boldsymbol{'+s+r'}',
    'bm': lambda s: r'\boldsymbol{'+s+r'}',
    # Brackets
    'norm': lambda s: r'\left\|{'+s+r'}\right\|',
    'avg': lambda s: r'\left\langle{'+s+r'}\right\rangle',
    'abs': lambda s: r'\left|{'+s+r'}\right|',
    'mag': lambda s: r'\left|{'+s+r'}\right|',
}

greek_letters_set = frozenset(greeks)


_between_two_numbers_p = (
    re.compile(r'[0-9][} ]*$'),  # search
    re.compile(r'[{ ]*[-+0-9]'),  # match
)


[docs]class LatexPrinter(Printer): printmethod = "_latex" _default_settings = { "order": None, "mode": "plain", "itex": False, "fold_frac_powers": False, "fold_func_brackets": False, "fold_short_frac": None, "long_frac_ratio": 2, "mul_symbol": None, "inv_trig_style": "abbreviated", "mat_str": None, "mat_delim": "[", "symbol_names": {}, } def __init__(self, settings=None): Printer.__init__(self, settings) valid_modes = ['inline', 'plain', 'equation', 'equation*'] if self._settings['mode'] not in valid_modes: raise ValueError("'mode' must be one of 'inline', 'plain', " "'equation' or 'equation*'") if self._settings['inv_trig_style'] not in ['power', 'full', 'abbreviated']: raise ValueError("'inv_trig_style' must be one of 'power', 'full'" "or 'abbreviated'") if self._settings['fold_short_frac'] is None and \ self._settings['mode'] == 'inline': self._settings['fold_short_frac'] = True mul_symbol_table = { None: r" ", "ldot": r" \,.\, ", "dot": r" \cdot ", "times": r" \times " } self._settings['mul_symbol_latex'] = \ mul_symbol_table[self._settings['mul_symbol']] self._settings['mul_symbol_latex_numbers'] = \ mul_symbol_table[self._settings['mul_symbol'] or 'dot'] self._delim_dict = {'(': ')', '[': ']'} def parenthesize(self, item, level): if precedence(item) <= level: return r"\left(%s\right)" % self._print(item) else: return self._print(item) def doprint(self, expr): tex = Printer.doprint(self, expr) if self._settings['mode'] == 'plain': return tex elif self._settings['mode'] == 'inline': return r"$%s$" % tex elif self._settings['itex']: return r"$$%s$$" % tex else: env_str = self._settings['mode'] return r"\begin{%s}%s\end{%s}" % (env_str, tex, env_str) def _needs_mul_brackets(self, expr, first=False, last=False): """ Returns True if the expression needs to be wrapped in brackets when printed as part of a Mul, False otherwise. This is True for Add, but also for some container objects that would not need brackets when appearing last in a Mul, e.g. an Integral. ``last=True`` specifies that this expr is the last to appear in a Mul. ``first=True`` specifies that this expr is the first to appear in a Mul. """ from ..functions import Piecewise from ..concrete import Product, Sum from ..integrals import Integral if expr.is_Add: return True elif expr.is_Relational: return True elif expr.is_Mul: if not first and _coeff_isneg(expr): return True if expr.has(Mod): return True if (not last and any(expr.has(x) for x in (Integral, Piecewise, Product, Sum))): return True return False def _needs_add_brackets(self, expr): """ Returns True if the expression needs to be wrapped in brackets when printed as part of an Add, False otherwise. This is False for most things. """ if expr.is_Relational: return True if expr.has(Mod): return True return False def _do_exponent(self, expr, exp): if exp is not None: return r"\left(%s\right)^{%s}" % (expr, exp) else: return expr def _print_bool(self, e): return r"\mathrm{%s}" % e _print_BooleanTrue = _print_bool _print_BooleanFalse = _print_bool def _print_NoneType(self, e): return r"\mathrm{%s}" % e def _print_Add(self, expr, order=None): if self.order == 'none': terms = list(expr.args) else: terms = expr.as_ordered_terms(order=order or self.order) tex = "" for i, term in enumerate(terms): if i == 0: pass elif _coeff_isneg(term): tex += " - " term = -term else: tex += " + " term_tex = self._print(term) if self._needs_add_brackets(term): term_tex = r"\left(%s\right)" % term_tex tex += term_tex return tex def _print_Cycle(self, expr): from ..combinatorics import Permutation if not expr or (isinstance(expr, Permutation) and not expr.list()): return r"\left( \right)" expr = Permutation(expr) expr_perm = expr.cyclic_form siz = expr.size if expr.array_form[-1] == siz - 1: expr_perm = expr_perm + [[siz - 1]] term_tex = '' for i in expr_perm: term_tex += str(i).replace(',', r"\;") term_tex = term_tex.replace('[', r"\left( ") term_tex = term_tex.replace(']', r"\right)") return term_tex _print_Permutation = _print_Cycle def _print_Float(self, expr): # Based off of that in StrPrinter dps = prec_to_dps(expr._prec) str_real = mlib.to_str(expr._mpf_, dps, strip_zeros=True) # Must always have a mul symbol (as 2.5 10^{20} just looks odd) # thus we use the number separator separator = self._settings['mul_symbol_latex_numbers'] if 'e' in str_real: (mant, exp) = str_real.split('e') if exp[0] == '+': exp = exp[1:] return r"%s%s10^{%s}" % (mant, separator, exp) elif str_real == "+inf": return r"\infty" elif str_real == "-inf": return r"- \infty" else: return str_real def _print_Mul(self, expr): include_parens = False if _coeff_isneg(expr): expr = -expr tex = "- " if expr.is_Add: tex += "(" include_parens = True else: tex = "" from ..simplify import fraction numer, denom = fraction(expr, exact=True) separator = self._settings['mul_symbol_latex'] numbersep = self._settings['mul_symbol_latex_numbers'] def convert(expr): if not expr.is_Mul: return str(self._print(expr)) else: _tex = last_term_tex = "" if self.order != 'none': args = expr.as_ordered_factors() else: args = expr.args for i, term in enumerate(args): term_tex = self._print(term) if self._needs_mul_brackets(term, first=(i == 0), last=(i == len(args) - 1)): term_tex = r"\left(%s\right)" % term_tex if _between_two_numbers_p[0].search(last_term_tex) and \ _between_two_numbers_p[1].match(term_tex): # between two numbers _tex += numbersep elif _tex: _tex += separator _tex += term_tex last_term_tex = term_tex return _tex if denom is S.One: # use the original expression here, since fraction() may have # altered it when producing numer and denom tex += convert(expr) else: snumer = convert(numer) sdenom = convert(denom) ldenom = len(sdenom.split()) ratio = self._settings['long_frac_ratio'] if self._settings['fold_short_frac'] \ and ldenom <= 2 and "^" not in sdenom: # handle short fractions if self._needs_mul_brackets(numer, last=False): tex += r"\left(%s\right) / %s" % (snumer, sdenom) else: tex += r"%s / %s" % (snumer, sdenom) elif len(snumer.split()) > ratio*ldenom: # handle long fractions if self._needs_mul_brackets(numer, last=True): tex += r"\frac{1}{%s}%s\left(%s\right)" \ % (sdenom, separator, snumer) elif numer.is_Mul: # split a long numerator a = S.One b = S.One for x in numer.args: if self._needs_mul_brackets(x, last=False) or \ len(convert(a*x).split()) > ratio*ldenom or \ (b.is_commutative is x.is_commutative is False): b *= x else: a *= x if self._needs_mul_brackets(b, last=True): tex += r"\frac{%s}{%s}%s\left(%s\right)" \ % (convert(a), sdenom, separator, convert(b)) else: tex += r"\frac{%s}{%s}%s%s" \ % (convert(a), sdenom, separator, convert(b)) else: tex += r"\frac{1}{%s}%s%s" % (sdenom, separator, snumer) else: tex += r"\frac{%s}{%s}" % (snumer, sdenom) if include_parens: tex += ")" return tex def _print_Pow(self, expr): from ..integrals import Integral # Treat root(x, n) as special case if expr.exp.is_Rational and abs(expr.exp.numerator) == 1 and expr.exp.denominator != 1: base = self._print(expr.base) expq = expr.exp.denominator if expq == 2: tex = r"\sqrt{%s}" % base elif self._settings['itex']: tex = r"\root{%d}{%s}" % (expq, base) else: tex = r"\sqrt[%d]{%s}" % (expq, base) if expr.exp.is_negative: return r"\frac{1}{%s}" % tex else: return tex elif self._settings['fold_frac_powers'] \ and expr.exp.is_Rational \ and expr.exp.denominator != 1: base, p, q = self.parenthesize(expr.base, PRECEDENCE['Pow']), expr.exp.numerator, expr.exp.denominator if expr.base.is_Function: return self._print(expr.base, "%s/%s" % (p, q)) return r"%s^{%s/%s}" % (base, p, q) elif expr.exp.is_Rational and expr.exp.is_negative and expr.base.is_commutative: # Things like 1/x return self._print_Mul(expr) else: if expr.base.is_Function: return self._print(expr.base, self._print(expr.exp)) else: tex = r"%s^{%s}" if expr.base.is_Float or isinstance(expr.base, Integral): tex = r"\left(%s\right)^{%s}" return tex % (self.parenthesize(expr.base, PRECEDENCE['Pow']), self._print(expr.exp)) def _print_Sum(self, expr): if len(expr.limits) == 1: tex = r"\sum_{%s=%s}^{%s} " % \ tuple(self._print(i) for i in expr.limits[0]) else: def _format_ineq(l): return r"%s \leq %s \leq %s" % \ tuple(self._print(s) for s in (l[1], l[0], l[2])) tex = r"\sum_{\substack{%s}} " % \ str.join('\\\\', [ _format_ineq(l) for l in expr.limits ]) if isinstance(expr.function, Add): tex += r"\left(%s\right)" % self._print(expr.function) else: tex += self._print(expr.function) return tex def _print_Product(self, expr): if len(expr.limits) == 1: tex = r"\prod_{%s=%s}^{%s} " % \ tuple(self._print(i) for i in expr.limits[0]) else: def _format_ineq(l): return r"%s \leq %s \leq %s" % \ tuple(self._print(s) for s in (l[1], l[0], l[2])) tex = r"\prod_{\substack{%s}} " % \ str.join('\\\\', [ _format_ineq(l) for l in expr.limits ]) if isinstance(expr.function, Add): tex += r"\left(%s\right)" % self._print(expr.function) else: tex += self._print(expr.function) return tex def _print_BasisDependent(self, expr): from ..vector import Vector o1 = [] if expr == expr.zero: return expr.zero._latex_form if isinstance(expr, Vector): items = expr.separate().items() else: items = [(0, expr)] for system, vect in items: inneritems = list(vect.components.items()) inneritems.sort(key=lambda x: x[0].__str__()) for k, v in inneritems: if v == 1: o1.append(' + ' + k._latex_form) elif v == -1: o1.append(' - ' + k._latex_form) else: arg_str = '(' + LatexPrinter().doprint(v) + ')' o1.append(' + ' + arg_str + k._latex_form) outstr = (''.join(o1)) if outstr[1] != '-': outstr = outstr[3:] else: outstr = outstr[1:] return outstr def _print_Indexed(self, expr): tex = self._print(expr.base)+'_{%s}' % ','.join( map(self._print, expr.indices)) return tex def _print_IndexedBase(self, expr): return self._print(expr.label) def _print_Derivative(self, expr): dim = len(expr.variables) if requires_partial(expr): diff_symbol = r'\partial' else: diff_symbol = r'd' if dim == 1: tex = r"\frac{%s}{%s %s}" % (diff_symbol, diff_symbol, 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)) for x, i in multiplicity: if i == 1: tex += r"%s %s" % (diff_symbol, self._print(x)) else: tex += r"%s %s^{%s}" % (diff_symbol, self._print(x), i) tex = r"\frac{%s^{%s}}{%s} " % (diff_symbol, dim, tex) if isinstance(expr.expr, AssocOp): return r"%s\left(%s\right)" % (tex, self._print(expr.expr)) else: return r"%s %s" % (tex, self._print(expr.expr)) def _print_Subs(self, subs): expr, old, new = subs.expr, subs.variables, subs.point latex_expr = self._print(expr) latex_old = (self._print(e) for e in old) latex_new = (self._print(e) for e in new) # pragma: no branch latex_subs = r'\\ '.join( e[0] + '=' + e[1] for e in zip(latex_old, latex_new)) return r'\left. %s \right|_{\substack{ %s }}' % (latex_expr, latex_subs) def _print_Integral(self, expr): tex, symbols = "", [] # Only up to \iiiint exists if len(expr.limits) <= 4 and all(len(lim) == 1 for lim in expr.limits): # Use len(expr.limits)-1 so that syntax highlighters don't think # \" is an escaped quote tex = r"\i" + "i"*(len(expr.limits) - 1) + "nt" symbols = [r"\, d%s" % self._print(symbol[0]) for symbol in expr.limits] else: for lim in reversed(expr.limits): symbol = lim[0] tex += r"\int" if len(lim) > 1: if self._settings['mode'] in ['equation', 'equation*'] \ and not self._settings['itex']: tex += r"\limits" if len(lim) == 3: tex += "_{%s}^{%s}" % (self._print(lim[1]), self._print(lim[2])) if len(lim) == 2: tex += "^{%s}" % (self._print(lim[1])) symbols.insert(0, r"\, d%s" % self._print(symbol)) tmpl = r"%s \left(%s\right)%s" if expr.function.is_Add else r"%s %s%s" return tmpl % (tex, str(self._print(expr.function)), "".join(symbols)) def _print_Limit(self, expr): e, z, z0, dir = expr.args tex = r"\lim_{%s \to " % self._print(z) if str(dir) == "real" or z0 in (oo, -oo): tex += r"%s}" % self._print(z0) else: tex += r"%s^%s}" % (self._print(z0), self._print(dir)) if isinstance(e, (AssocOp, Relational)): return r"%s\left(%s\right)" % (tex, self._print(e)) else: return r"%s %s" % (tex, self._print(e)) def _hprint_Function(self, func): r""" Logic to decide how to render a function to latex - if it is a recognized latex name, use the appropriate latex command - if it is a single letter, just use that letter - if it is a longer name, then put \operatorname{} around it and be mindful of undercores in the name """ func = self._deal_with_super_sub(func) if func in accepted_latex_functions: name = r"\%s" % func elif len(func) == 1 or func.startswith('\\'): name = func else: name = r"\operatorname{%s}" % func return name def _print_Function(self, expr, exp=None): r""" Render functions to LaTeX, handling functions that LaTeX knows about e.g., sin, cos, ... by using the proper LaTeX command (\sin, \cos, ...). For single-letter function names, render them as regular LaTeX math symbols. For multi-letter function names that LaTeX does not know about, (e.g., Li, sech) use \operatorname{} so that the function name is rendered in Roman font and LaTeX handles spacing properly. expr is the expression involving the function exp is an exponent """ func = expr.func.__name__ args = [ str(self._print(arg)) for arg in expr.args ] # How inverse trig functions should be displayed, formats are: # abbreviated: asin, full: arcsin, power: sin^-1 inv_trig_style = self._settings['inv_trig_style'] # If we are dealing with a power-style inverse trig function inv_trig_power_case = False # If it is applicable to fold the argument brackets can_fold_brackets = (self._settings['fold_func_brackets'] and len(args) == 1) inv_trig_table = ["asin", "acos", "atan", "acot"] # If the function is an inverse trig function, handle the style if func in inv_trig_table: if inv_trig_style == "abbreviated": func = func elif inv_trig_style == "full": func = "arc" + func[1:] else: # inv_trig_style == "power": func = func[1:] inv_trig_power_case = True # Can never fold brackets if we're raised to a power if exp is not None: can_fold_brackets = False if inv_trig_power_case: name = r"\%s^{-1}" % func elif exp is not None: name = r'%s^{%s}' % (self._hprint_Function(func), exp) else: name = self._hprint_Function(func) if can_fold_brackets: if func in accepted_latex_functions: # Wrap argument safely to avoid parse-time conflicts # with the function name itself name += r" {%s}" else: name += r"%s" else: name += r"{\left (%s \right )}" if inv_trig_power_case and exp is not None: name += r"^{%s}" % exp return name % ",".join(args) def _print_UndefinedFunction(self, expr): return self._hprint_Function(str(expr)) def _print_FunctionClass(self, expr): if hasattr(expr, '_latex_no_arg'): return expr._latex_no_arg(self) return self._hprint_Function(str(expr)) def _print_Lambda(self, expr): symbols, expr = expr.args if len(symbols) == 1: symbols = self._print(symbols[0]) else: symbols = self._print(tuple(symbols)) tex = r"\left( %s \mapsto %s \right)" % (symbols, self._print(expr)) return tex def _print_Min(self, expr, exp=None): args = sorted(expr.args, key=default_sort_key) texargs = [r"%s" % self._print(symbol) for symbol in args] tex = r"\min\left(%s\right)" % ", ".join(texargs) if exp is not None: return r"%s^{%s}" % (tex, exp) else: return tex def _print_Max(self, expr, exp=None): args = sorted(expr.args, key=default_sort_key) texargs = [r"%s" % self._print(symbol) for symbol in args] tex = r"\max\left(%s\right)" % ", ".join(texargs) if exp is not None: return r"%s^{%s}" % (tex, exp) else: return tex 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"\left|{%s}\right|" % self._print(expr.args[0]) if exp is not None: return r"%s^{%s}" % (tex, exp) else: return tex _print_Determinant = _print_Abs def _print_re(self, expr, exp=None): tex = r"\Re{%s}" % self.parenthesize(expr.args[0], PRECEDENCE['Func']) return self._do_exponent(tex, exp) def _print_im(self, expr, exp=None): tex = r"\Im{%s}" % self.parenthesize(expr.args[0], PRECEDENCE['Func']) return self._do_exponent(tex, exp) def _print_Not(self, e): from ..logic import Equivalent, Implies if isinstance(e.args[0], Equivalent): return self._print_Equivalent(e.args[0], r"\not\equiv") if isinstance(e.args[0], Implies): return self._print_Implies(e.args[0], r"\not\Rightarrow") if (e.args[0].is_Boolean): return r"\neg (%s)" % self._print(e.args[0]) else: return r"\neg %s" % self._print(e.args[0]) def _print_LogOp(self, args, char): arg = args[0] if arg.is_Boolean and (not arg.is_Not and not arg.is_Atom): tex = r"\left(%s\right)" % self._print(arg) else: tex = r"%s" % self._print(arg) for arg in args[1:]: if arg.is_Boolean and (not arg.is_Not and not arg.is_Atom): tex += r" %s \left(%s\right)" % (char, self._print(arg)) else: tex += r" %s %s" % (char, self._print(arg)) return tex def _print_And(self, e): args = sorted(e.args, key=default_sort_key) return self._print_LogOp(args, r"\wedge") def _print_Or(self, e): args = sorted(e.args, key=default_sort_key) return self._print_LogOp(args, r"\vee") def _print_Xor(self, e): args = sorted(e.args, key=default_sort_key) return self._print_LogOp(args, r"\veebar") def _print_Implies(self, e, altchar=None): return self._print_LogOp(e.args, altchar or r"\Rightarrow") def _print_Equivalent(self, e, altchar=None): args = sorted(e.args, key=default_sort_key) return self._print_LogOp(args, altchar or r"\equiv") 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_polar_lift(self, expr, exp=None): func = r"\operatorname{polar\_lift}" arg = r"{\left (%s \right )}" % self._print(expr.args[0]) if exp is not None: return r"%s^{%s}%s" % (func, exp, arg) else: return r"%s%s" % (func, arg) def _print_elliptic_k(self, expr, exp=None): tex = r"\left(%s\right)" % self._print(expr.args[0]) if exp is not None: return r"K^{%s}%s" % (exp, tex) else: return r"K%s" % tex def _print_elliptic_f(self, expr, exp=None): tex = r"\left(%s\middle| %s\right)" % \ (self._print(expr.args[0]), self._print(expr.args[1])) if exp is not None: return r"F^{%s}%s" % (exp, tex) else: return r"F%s" % tex def _print_elliptic_e(self, expr, exp=None): if len(expr.args) == 2: tex = r"\left(%s\middle| %s\right)" % \ (self._print(expr.args[0]), self._print(expr.args[1])) else: tex = r"\left(%s\right)" % self._print(expr.args[0]) if exp is not None: return r"E^{%s}%s" % (exp, tex) else: return r"E%s" % tex def _print_elliptic_pi(self, expr, exp=None): if len(expr.args) == 3: tex = r"\left(%s; %s\middle| %s\right)" % \ (self._print(expr.args[0]), self._print(expr.args[1]), self._print(expr.args[2])) else: tex = r"\left(%s\middle| %s\right)" % \ (self._print(expr.args[0]), self._print(expr.args[1])) if exp is not None: return r"\Pi^{%s}%s" % (exp, tex) else: return r"\Pi%s" % tex def _print_uppergamma(self, expr, exp=None): tex = r"\left(%s, %s\right)" % (self._print(expr.args[0]), self._print(expr.args[1])) if exp is not None: return r"\Gamma^{%s}%s" % (exp, tex) else: return r"\Gamma%s" % tex def _print_lowergamma(self, expr, exp=None): tex = r"\left(%s, %s\right)" % (self._print(expr.args[0]), self._print(expr.args[1])) if exp is not None: return r"\gamma^{%s}%s" % (exp, tex) else: return r"\gamma%s" % tex def _print_expint(self, expr, exp=None): tex = r"\left(%s\right)" % self._print(expr.args[1]) nu = self._print(expr.args[0]) if exp is not None: return r"\operatorname{E}_{%s}^{%s}%s" % (nu, exp, tex) else: return r"\operatorname{E}_{%s}%s" % (nu, tex) def _print_fresnels(self, expr, exp=None): tex = r"\left(%s\right)" % self._print(expr.args[0]) if exp is not None: return r"S^{%s}%s" % (exp, tex) else: return r"S%s" % tex def _print_fresnelc(self, expr, exp=None): tex = r"\left(%s\right)" % self._print(expr.args[0]) if exp is not None: return r"C^{%s}%s" % (exp, tex) else: return r"C%s" % tex def _print_subfactorial(self, expr, exp=None): tex = r"!%s" % self.parenthesize(expr.args[0], PRECEDENCE["Func"]) if exp is not None: return r"%s^{%s}" % (tex, exp) else: return tex def _print_factorial(self, expr, exp=None): tex = r"%s!" % self.parenthesize(expr.args[0], PRECEDENCE["Func"]) if exp is not None: return r"%s^{%s}" % (tex, exp) else: return tex def _print_factorial2(self, expr, exp=None): tex = r"%s!!" % self.parenthesize(expr.args[0], PRECEDENCE["Func"]) if exp is not None: return r"%s^{%s}" % (tex, exp) else: return tex def _print_binomial(self, expr, exp=None): tex = r"{\binom{%s}{%s}}" % (self._print(expr.args[0]), self._print(expr.args[1])) if exp is not None: return r"%s^{%s}" % (tex, exp) else: return tex def _print_RisingFactorial(self, expr, exp=None): n, k = expr.args base = r"%s" % self.parenthesize(n, PRECEDENCE['Func']) tex = r"{%s}^{\left(%s\right)}" % (base, self._print(k)) return self._do_exponent(tex, exp) def _print_FallingFactorial(self, expr, exp=None): n, k = expr.args sub = r"%s" % self.parenthesize(k, PRECEDENCE['Func']) tex = r"{\left(%s\right)}_{%s}" % (self._print(n), sub) return self._do_exponent(tex, exp) def _hprint_BesselBase(self, expr, exp, sym): tex = r"%s" % sym need_exp = False if exp is not None: if tex.find('^') == -1: tex = r"%s^{%s}" % (tex, self._print(exp)) else: need_exp = True tex = r"%s_{%s}\left(%s\right)" % (tex, self._print(expr.order), self._print(expr.argument)) if need_exp: tex = self._do_exponent(tex, exp) return tex def _hprint_vec(self, vec): if len(vec) == 0: return "" s = "" for i in vec[:-1]: s += "%s, " % self._print(i) s += self._print(vec[-1]) return s def _print_besselj(self, expr, exp=None): return self._hprint_BesselBase(expr, exp, 'J') def _print_besseli(self, expr, exp=None): return self._hprint_BesselBase(expr, exp, 'I') def _print_besselk(self, expr, exp=None): return self._hprint_BesselBase(expr, exp, 'K') def _print_bessely(self, expr, exp=None): return self._hprint_BesselBase(expr, exp, 'Y') def _print_yn(self, expr, exp=None): return self._hprint_BesselBase(expr, exp, 'y') def _print_jn(self, expr, exp=None): return self._hprint_BesselBase(expr, exp, 'j') def _print_hankel1(self, expr, exp=None): return self._hprint_BesselBase(expr, exp, 'H^{(1)}') def _print_hankel2(self, expr, exp=None): return self._hprint_BesselBase(expr, exp, 'H^{(2)}') def _hprint_airy(self, expr, exp=None, notation=""): tex = r"\left(%s\right)" % self._print(expr.args[0]) if exp is not None: return r"%s^{%s}%s" % (notation, exp, tex) else: return r"%s%s" % (notation, tex) def _hprint_airy_prime(self, expr, exp=None, notation=""): tex = r"\left(%s\right)" % self._print(expr.args[0]) if exp is not None: return r"{%s^\prime}^{%s}%s" % (notation, exp, tex) else: return r"%s^\prime%s" % (notation, tex) def _print_airyai(self, expr, exp=None): return self._hprint_airy(expr, exp, 'Ai') def _print_airybi(self, expr, exp=None): return self._hprint_airy(expr, exp, 'Bi') def _print_airyaiprime(self, expr, exp=None): return self._hprint_airy_prime(expr, exp, 'Ai') def _print_airybiprime(self, expr, exp=None): return self._hprint_airy_prime(expr, exp, 'Bi') def _print_hyper(self, expr, exp=None): tex = r"{{}_{%s}F_{%s}\left(\begin{matrix} %s \\ %s \end{matrix}" \ r"\middle| {%s} \right)}" % \ (self._print(len(expr.ap)), self._print(len(expr.bq)), self._hprint_vec(expr.ap), self._hprint_vec(expr.bq), self._print(expr.argument)) if exp is not None: tex = r"{%s}^{%s}" % (tex, self._print(exp)) return tex def _print_meijerg(self, expr, exp=None): tex = r"{G_{%s, %s}^{%s, %s}\left(\begin{matrix} %s & %s \\" \ r"%s & %s \end{matrix} \middle| {%s} \right)}" % \ (self._print(len(expr.ap)), self._print(len(expr.bq)), self._print(len(expr.bm)), self._print(len(expr.an)), self._hprint_vec(expr.an), self._hprint_vec(expr.aother), self._hprint_vec(expr.bm), self._hprint_vec(expr.bother), self._print(expr.argument)) if exp is not None: tex = r"{%s}^{%s}" % (tex, self._print(exp)) return tex def _print_dirichlet_eta(self, expr, exp=None): tex = r"\left(%s\right)" % self._print(expr.args[0]) if exp is not None: return r"\eta^{%s}%s" % (self._print(exp), tex) return r"\eta%s" % tex def _print_zeta(self, expr, exp=None): if len(expr.args) == 2: tex = r"\left(%s, %s\right)" % tuple(map(self._print, expr.args)) else: tex = r"\left(%s\right)" % self._print(expr.args[0]) if exp is not None: return r"\zeta^{%s}%s" % (self._print(exp), tex) return r"\zeta%s" % tex def _print_lerchphi(self, expr, exp=None): tex = r"\left(%s, %s, %s\right)" % tuple(map(self._print, expr.args)) if exp is None: return r"\Phi%s" % tex return r"\Phi^{%s}%s" % (self._print(exp), tex) def _print_polylog(self, expr, exp=None): s, z = map(self._print, expr.args) tex = r"\left(%s\right)" % z if exp is None: return r"\operatorname{Li}_{%s}%s" % (s, tex) return r"\operatorname{Li}_{%s}^{%s}%s" % (s, self._print(exp), tex) def _print_jacobi(self, expr, exp=None): n, a, b, x = map(self._print, expr.args) tex = r"P_{%s}^{\left(%s,%s\right)}\left(%s\right)" % (n, a, b, x) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (self._print(exp)) return tex def _print_gegenbauer(self, expr, exp=None): n, a, x = map(self._print, expr.args) tex = r"C_{%s}^{\left(%s\right)}\left(%s\right)" % (n, a, x) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (self._print(exp)) return tex def _print_chebyshevt(self, expr, exp=None): n, x = map(self._print, expr.args) tex = r"T_{%s}\left(%s\right)" % (n, x) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (self._print(exp)) return tex def _print_chebyshevu(self, expr, exp=None): n, x = map(self._print, expr.args) tex = r"U_{%s}\left(%s\right)" % (n, x) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (self._print(exp)) return tex def _print_legendre(self, expr, exp=None): n, x = map(self._print, expr.args) tex = r"P_{%s}\left(%s\right)" % (n, x) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (self._print(exp)) return tex def _print_assoc_legendre(self, expr, exp=None): n, a, x = map(self._print, expr.args) tex = r"P_{%s}^{\left(%s\right)}\left(%s\right)" % (n, a, x) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (self._print(exp)) return tex def _print_hermite(self, expr, exp=None): n, x = map(self._print, expr.args) tex = r"H_{%s}\left(%s\right)" % (n, x) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (self._print(exp)) return tex def _print_laguerre(self, expr, exp=None): n, x = map(self._print, expr.args) tex = r"L_{%s}\left(%s\right)" % (n, x) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (self._print(exp)) return tex def _print_assoc_laguerre(self, expr, exp=None): n, a, x = map(self._print, expr.args) tex = r"L_{%s}^{\left(%s\right)}\left(%s\right)" % (n, a, x) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (self._print(exp)) return tex def _print_Ynm(self, expr, exp=None): n, m, theta, phi = map(self._print, expr.args) tex = r"Y_{%s}^{%s}\left(%s,%s\right)" % (n, m, theta, phi) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (self._print(exp)) return tex def _print_Znm(self, expr, exp=None): n, m, theta, phi = map(self._print, expr.args) tex = r"Z_{%s}^{%s}\left(%s,%s\right)" % (n, m, theta, phi) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (self._print(exp)) return tex def _print_Rational(self, expr): if expr.denominator != 1: sign = "" p = expr.numerator if expr.numerator < 0: sign = "- " p = -p if self._settings['fold_short_frac']: return r"%s%d / %d" % (sign, p, expr.denominator) else: return r"%s\frac{%d}{%d}" % (sign, p, expr.denominator) else: return self._print(expr.numerator) def _print_Order(self, expr): s = self._print(expr.expr) if expr.point and any(p != 0 for p in expr.point) or \ len(expr.variables) > 1: s += '; ' if len(expr.variables) > 1: s += self._print(expr.variables) else: s += self._print(expr.variables[0]) s += r'\rightarrow{}' if len(expr.point) > 1: s += self._print(expr.point) else: s += self._print(expr.point[0]) return r"\mathcal{O}\left(%s\right)" % s def _print_Symbol(self, expr): if expr in self._settings['symbol_names']: return self._settings['symbol_names'][expr] return self._deal_with_super_sub(expr.name) if \ '\\' not in expr.name else expr.name _print_Wild = _print_Symbol _print_Dummy = _print_Symbol _print_RandomSymbol = _print_Symbol _print_MatrixSymbol = _print_Symbol def _deal_with_super_sub(self, string): if '{' in string: return string name, supers, subs = split_super_sub(string) name = translate(name) supers = [translate(sup) for sup in supers] subs = [translate(sub) for sub in subs] # glue all items together: if len(supers) > 0: name += "^{%s}" % " ".join(supers) if len(subs) > 0: name += "_{%s}" % " ".join(subs) return name def _print_Relational(self, expr): if self._settings['itex']: gt = r"\gt" lt = r"\lt" else: gt = ">" lt = "<" charmap = { "==": "=", ">": gt, "<": lt, ">=": r"\geq", "<=": r"\leq", "!=": r"\neq", } return "%s %s %s" % (self._print(expr.lhs), charmap[expr.rel_op], self._print(expr.rhs)) def _print_Piecewise(self, expr): ecpairs = [r"%s & \text{for}\: %s" % (self._print(e), self._print(c)) for e, c in expr.args[:-1]] if expr.args[-1].cond == true: ecpairs.append(r"%s & \text{otherwise}" % self._print(expr.args[-1].expr)) else: ecpairs.append(r"%s & \text{for}\: %s" % (self._print(expr.args[-1].expr), self._print(expr.args[-1].cond))) tex = r"\begin{cases} %s \end{cases}" return tex % r" \\".join(ecpairs) def _print_MatrixBase(self, expr): lines = [] for line in range(expr.rows): # horrible, should be 'rows' lines.append(" & ".join([ self._print(i) for i in expr[line, :] ])) mat_str = self._settings['mat_str'] if mat_str is None: if self._settings['mode'] == 'inline': mat_str = 'smallmatrix' else: if (expr.cols <= 10) is True: mat_str = 'matrix' else: mat_str = 'array' out_str = r'\begin{%MATSTR%}%s\end{%MATSTR%}' out_str = out_str.replace('%MATSTR%', mat_str) if mat_str == 'array': out_str = out_str.replace('%s', '{' + 'c'*expr.cols + '}%s') if self._settings['mat_delim']: left_delim = self._settings['mat_delim'] right_delim = self._delim_dict[left_delim] out_str = r'\left' + left_delim + out_str + \ r'\right' + right_delim return out_str % r"\\".join(lines) _print_ImmutableMatrix = _print_MatrixBase _print_Matrix = _print_MatrixBase def _print_MatrixSlice(self, expr): def latexslice(x): x = list(x) if x[2] == 1: del x[2] if x[1] == x[0] + 1: del x[1] if x[0] == 0: x[0] = '' return ':'.join(map(self._print, x)) return (self._print(expr.parent) + r'\left[' + latexslice(expr.rowslice) + ', ' + latexslice(expr.colslice) + r'\right]') def _print_BlockMatrix(self, expr): return self._print(expr.blocks) def _print_Transpose(self, expr): mat = expr.arg from ..matrices import MatrixSymbol if not isinstance(mat, MatrixSymbol): return r"\left(%s\right)^T" % self._print(mat) else: return "%s^T" % self._print(mat) def _print_Adjoint(self, expr): mat = expr.arg from ..matrices import MatrixSymbol if not isinstance(mat, MatrixSymbol): return r"\left(%s\right)^\dag" % self._print(mat) else: return r"%s^\dag" % self._print(mat) def _print_MatAdd(self, expr): terms = list(expr.args) tex = "" for i, term in enumerate(terms): if i == 0: pass elif _coeff_isneg(term): tex += " - " term = -term else: tex += " + " tex += self._print(term) return tex def _print_MatMul(self, expr): from ..core import Add from ..matrices import MatAdd, HadamardProduct def parens(x): if isinstance(x, (Add, MatAdd, HadamardProduct)): return r"\left(%s\right)" % self._print(x) return self._print(x) return ' '.join(map(parens, expr.args)) def _print_Mod(self, expr, exp=None): if exp is not None: return r'\left(%s\bmod{%s}\right)^{%s}' % (self.parenthesize(expr.args[0], PRECEDENCE['Mul']), self._print(expr.args[1]), self._print(exp)) return r'%s\bmod{%s}' % (self.parenthesize(expr.args[0], PRECEDENCE['Mul']), self._print(expr.args[1])) def _print_HadamardProduct(self, expr): from ..core import Add from ..matrices import MatAdd, MatMul def parens(x): if isinstance(x, (Add, MatAdd, MatMul)): return r"\left(%s\right)" % self._print(x) return self._print(x) return r' \circ '.join(map(parens, expr.args)) def _print_MatPow(self, expr): base, exp = expr.base, expr.exp from ..matrices import MatrixSymbol if not isinstance(base, MatrixSymbol): return r"\left(%s\right)^{%s}" % (self._print(base), self._print(exp)) else: return "%s^{%s}" % (self._print(base), self._print(exp)) def _print_ZeroMatrix(self, Z): return r"\mathbb{0}" def _print_Identity(self, I): return r"\mathbb{I}" def _print_tuple(self, expr): return r"\left ( %s\right )" % \ r", \quad ".join([ self._print(i) for i in expr ]) def _print_Tuple(self, expr): return self._print_tuple(expr) def _print_list(self, expr): return r"\left [ %s\right ]" % \ r", \quad ".join([ self._print(i) for i in expr ]) def _print_dict(self, d): keys = sorted(d, key=default_sort_key) items = [] for key in keys: val = d[key] items.append("%s : %s" % (self._print(key), self._print(val))) return r"\left \{ %s\right \}" % r", \quad ".join(items) def _print_Dict(self, expr): return self._print_dict(expr) def _print_Infinity(self, expr): return r"\infty" def _print_NegativeInfinity(self, expr): return r"-\infty" def _print_NaN(self, expr): return r"\mathrm{NaN}" def _print_ComplexInfinity(self, expr): return r"\tilde{\infty}" def _print_Exp1(self, expr): return r"e" def _print_Pi(self, expr): return r"\pi" def _print_GoldenRatio(self, expr): return r"\phi" def _print_EulerGamma(self, expr): return r"\gamma" def _print_ImaginaryUnit(self, expr): return r"i" def _print_DiracDelta(self, expr, exp=None): 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])) if exp: tex = r"\left(%s\right)^{%s}" % (tex, exp) return tex def _print_Heaviside(self, expr, exp=None): tex = r"\theta\left(%s\right)" % self._print(expr.args[0]) if exp: tex = r"\left(%s\right)^{%s}" % (tex, exp) return tex def _print_KroneckerDelta(self, expr, exp=None): i = self._print(expr.args[0]) j = self._print(expr.args[1]) if expr.args[0].is_Atom and expr.args[1].is_Atom: tex = r'\delta_{%s %s}' % (i, j) else: tex = r'\delta_{%s, %s}' % (i, j) if exp: tex = r'\left(%s\right)^{%s}' % (tex, exp) return tex def _print_LeviCivita(self, expr, exp=None): indices = map(self._print, expr.args) if all(x.is_Atom for x in expr.args): tex = r'\varepsilon_{%s}' % " ".join(indices) else: tex = r'\varepsilon_{%s}' % ", ".join(indices) if exp: tex = r'\left(%s\right)^{%s}' % (tex, exp) return tex def _print_ProductSet(self, p): if len(p.sets) > 1 and not has_variety(p.sets): return self._print(p.sets[0]) + "^%d" % len(p.sets) else: return r" \times ".join(self._print(set) for set in p.sets) def _print_RandomDomain(self, d): return 'Domain: ' + self._print(d.as_boolean()) def _print_FiniteSet(self, s): items = sorted(s.args, key=default_sort_key) return self._print_set(items) def _print_set(self, s): items = sorted(s, key=default_sort_key) items = ", ".join(map(self._print, items)) return r"\left\{%s\right\}" % items _print_frozenset = _print_set def _print_Range(self, s): if len(s) > 4: it = iter(s) printset = next(it), next(it), r'\ldots', s._last_element else: printset = tuple(s) return (r"\left\{" + r", ".join(self._print(el) for el in printset) + r"\right\}") def _print_Interval(self, i): if i.left_open: left = '(' else: left = '[' if i.right_open: right = ')' else: right = ']' return r"\left%s%s, %s\right%s" % (left, self._print(i.start), self._print(i.end), right) def _print_Union(self, u): return r" \cup ".join([self._print(i) for i in u.args]) def _print_Complement(self, u): return r" \setminus ".join([self._print(i) for i in u.args]) def _print_Intersection(self, u): return r" \cap ".join([self._print(i) for i in u.args]) def _print_SymmetricDifference(self, u): return r" \triangle ".join([self._print(i) for i in u.args]) def _print_EmptySet(self, e): return r"\emptyset" def _print_Naturals(self, n): return r"\mathbb{N}" def _print_Naturals0(self, n): return r"\mathbb{N}_0" def _print_Integers(self, i): return r"\mathbb{Z}" def _print_Reals(self, i): return r"\mathbb{R}" def _print_Rationals(self, i): return r"\mathbb{Q}" def _print_ImageSet(self, s): return r"\left\{%s\; |\; %s \in %s\right\}" % ( self._print(s.lamda.expr), ', '.join([self._print(var) for var in s.lamda.variables]), self._print(s.base_set)) def _print_Contains(self, e): return r"%s \in %s" % tuple(self._print(a) for a in e.args) def _print_FiniteField(self, expr): return r"\mathbb{F}_{%s}" % expr.order def _print_IntegerRing(self, expr): return r"\mathbb{Z}" def _print_RationalField(self, expr): return r"\mathbb{Q}" def _print_RealField(self, expr): return r"\mathbb{R}" def _print_ComplexField(self, expr): return r"\mathbb{C}" def _print_PolynomialRing(self, expr): domain = self._print(expr.domain) symbols = ", ".join(map(self._print, expr.symbols)) return r"%s\left[%s\right]" % (domain, symbols) def _print_FractionField(self, expr): domain = self._print(expr.domain) symbols = ", ".join(map(self._print, expr.symbols)) return r"%s\left(%s\right)" % (domain, symbols) def _print_Poly(self, poly): cls = poly.__class__.__name__ expr = self._print(poly.as_expr()) gens = list(map(self._print, poly.gens)) domain = "domain=%s" % self._print(poly.domain) args = ", ".join([expr] + gens + [domain]) return r"\operatorname{%s}{\left( %s \right)}" % (cls, args) def _print_RootOf(self, root): cls = root.__class__.__name__ expr = self._print(root.expr) if root.free_symbols: return r"\operatorname{%s} {\left(%s, %s, %d\right)}" % (cls, expr, *root.args[1:]) else: return r"\operatorname{%s} {\left(%s, %d\right)}" % (cls, expr, root.index) def _print_RootSum(self, expr): cls = expr.__class__.__name__ args = [self._print(expr.expr)] args.append(self._print(expr.fun)) return r"\operatorname{%s} {\left(%s\right)}" % (cls, ", ".join(args)) def _print_PolyElement(self, poly): mul_symbol = self._settings['mul_symbol_latex'] return poly.str(self, PRECEDENCE, "{%s}^{%d}", mul_symbol) def _print_FracElement(self, frac): if frac.denom == 1: return self._print(frac.numer) else: numer = self._print(frac.numer) denom = self._print(frac.denom) return r"\frac{%s}{%s}" % (numer, denom) def _print_euler(self, expr): return r"E_{%s}" % self._print(expr.args[0]) def _print_catalan(self, expr): return r"C_{%s}" % self._print(expr.args[0]) def _print_MellinTransform(self, expr): return r"\mathcal{M}_{%s}\left[%s\right]\left(%s\right)" % (self._print(expr.args[1]), self._print(expr.args[0]), self._print(expr.args[2])) def _print_InverseMellinTransform(self, expr): return r"\mathcal{M}^{-1}_{%s}\left[%s\right]\left(%s\right)" % (self._print(expr.args[1]), self._print(expr.args[0]), self._print(expr.args[2])) def _print_LaplaceTransform(self, expr): return r"\mathcal{L}_{%s}\left[%s\right]\left(%s\right)" % (self._print(expr.args[1]), self._print(expr.args[0]), self._print(expr.args[2])) def _print_InverseLaplaceTransform(self, expr): return r"\mathcal{L}^{-1}_{%s}\left[%s\right]\left(%s\right)" % (self._print(expr.args[1]), self._print(expr.args[0]), self._print(expr.args[2])) def _print_FourierTransform(self, expr): return r"\mathcal{F}_{%s}\left[%s\right]\left(%s\right)" % (self._print(expr.args[1]), self._print(expr.args[0]), self._print(expr.args[2])) def _print_InverseFourierTransform(self, expr): return r"\mathcal{F}^{-1}_{%s}\left[%s\right]\left(%s\right)" % (self._print(expr.args[1]), self._print(expr.args[0]), self._print(expr.args[2])) def _print_SineTransform(self, expr): return r"\mathcal{SIN}_{%s}\left[%s\right]\left(%s\right)" % (self._print(expr.args[1]), self._print(expr.args[0]), self._print(expr.args[2])) def _print_InverseSineTransform(self, expr): return r"\mathcal{SIN}^{-1}_{%s}\left[%s\right]\left(%s\right)" % (self._print(expr.args[1]), self._print(expr.args[0]), self._print(expr.args[2])) def _print_CosineTransform(self, expr): return r"\mathcal{COS}_{%s}\left[%s\right]\left(%s\right)" % (self._print(expr.args[1]), self._print(expr.args[0]), self._print(expr.args[2])) def _print_InverseCosineTransform(self, expr): return r"\mathcal{COS}^{-1}_{%s}\left[%s\right]\left(%s\right)" % (self._print(expr.args[1]), self._print(expr.args[0]), self._print(expr.args[2])) def _print_BaseScalarField(self, field): string = field._coord_sys._names[field._index] return r'\boldsymbol{\mathrm{%s}}' % self._print(Symbol(string)) def _print_BaseVectorField(self, field): string = field._coord_sys._names[field._index] return r'\partial_{%s}' % self._print(Symbol(string)) def _print_Differential(self, diff): field = diff._form_field if hasattr(field, '_coord_sys'): string = field._coord_sys._names[field._index] return r'\mathrm{d}%s' % self._print(Symbol(string)) else: return 'd(%s)' % self._print(field) def _print_Tr(self, p): # Todo: Handle indices contents = self._print(p.args[0]) return r'\mbox{Tr}\left(%s\right)' % contents def _print_totient(self, expr, exp=None): if exp is not None: return r'\left(\phi\left(%s\right)\right)^{%s}' % (self._print(expr.args[0]), self._print(exp)) return r'\phi\left(%s\right)' % self._print(expr.args[0]) def _print_divisor_sigma(self, expr, exp=None): if len(expr.args) == 2: tex = r"_%s\left(%s\right)" % tuple(map(self._print, (expr.args[1], expr.args[0]))) else: tex = r"\left(%s\right)" % self._print(expr.args[0]) if exp is not None: return r"\sigma^{%s}%s" % (self._print(exp), tex) return r"\sigma%s" % tex
def translate(s): r""" Check for a modifier ending the string. If present, convert the modifier to latex and translate the rest recursively. Given a description of a Greek letter or other special character, return the appropriate latex. Let everything else pass as given. >>> translate('alphahatdotprime') "{\\dot{\\hat{\\alpha}}}'" """ # Process the rest tex = tex_greek_dictionary.get(s) if tex: return tex elif s.lower() in greek_letters_set or s in other_symbols: return "\\" + s else: # Process modifiers, if any, and recurse for key in sorted(modifier_dict, key=lambda k: len(k), reverse=True): if s.lower().endswith(key) and len(s) > len(key): return modifier_dict[key](translate(s[:-len(key)])) return s
[docs]def latex(expr, **settings): r""" Convert the given expression to LaTeX representation. >>> from diofant.abc import mu, r, tau >>> print(latex((2*tau)**Rational(7, 2))) 8 \sqrt{2} \tau^{\frac{7}{2}} Not using a print statement for printing, results in double backslashes for latex commands since that's the way Python escapes backslashes in strings. >>> latex((2*tau)**Rational(7, 2)) '8 \\sqrt{2} \\tau^{\\frac{7}{2}}' order: Any of the supported monomial orderings (currently "lex", "grlex", or "grevlex") and "none". This parameter does nothing for Mul objects. For very large expressions, set the 'order' keyword to 'none' if speed is a concern. mode: Specifies how the generated code will be delimited. 'mode' can be one of 'plain', 'inline', 'equation' or 'equation*'. If 'mode' is set to 'plain', then the resulting code will not be delimited at all (this is the default). If 'mode' is set to 'inline' then inline LaTeX $ $ will be used. If 'mode' is set to 'equation' or 'equation*', the resulting code will be enclosed in the 'equation' or 'equation*' environment (remember to import 'amsmath' for 'equation*'), unless the 'itex' option is set. In the latter case, the ``$$ $$`` syntax is used. >>> print(latex((2*mu)**Rational(7, 2), mode='plain')) 8 \sqrt{2} \mu^{\frac{7}{2}} >>> print(latex((2*tau)**Rational(7, 2), mode='inline')) $8 \sqrt{2} \tau^{7 / 2}$ >>> print(latex((2*mu)**Rational(7, 2), mode='equation*')) \begin{equation*}8 \sqrt{2} \mu^{\frac{7}{2}}\end{equation*} >>> print(latex((2*mu)**Rational(7, 2), mode='equation')) \begin{equation}8 \sqrt{2} \mu^{\frac{7}{2}}\end{equation} itex: Specifies if itex-specific syntax is used, including emitting ``$$ $$``. >>> print(latex((2*mu)**Rational(7, 2), mode='equation', itex=True)) $$8 \sqrt{2} \mu^{\frac{7}{2}}$$ fold_frac_powers: Emit "^{p/q}" instead of "^{\frac{p}{q}}" for fractional powers. >>> print(latex((2*tau)**Rational(7, 2), fold_frac_powers=True)) 8 \sqrt{2} \tau^{7/2} fold_func_brackets: Fold function brackets where applicable. >>> print(latex((2*tau)**sin(Rational(7, 2)))) \left(2 \tau\right)^{\sin{\left (\frac{7}{2} \right )}} >>> print(latex((2*tau)**sin(Rational(7, 2)), fold_func_brackets = True)) \left(2 \tau\right)^{\sin {\frac{7}{2}}} fold_short_frac: Emit "p / q" instead of "\frac{p}{q}" when the denominator is simple enough (at most two terms and no powers). The default value is `True` for inline mode, False otherwise. >>> print(latex(3*x**2/y)) \frac{3 x^{2}}{y} >>> print(latex(3*x**2/y, fold_short_frac=True)) 3 x^{2} / y long_frac_ratio: The allowed ratio of the width of the numerator to the width of the denominator before we start breaking off long fractions. The default value is 2. >>> print(latex(Integral(r, r)/2/pi, long_frac_ratio=2)) \frac{\int r\, dr}{2 \pi} >>> print(latex(Integral(r, r)/2/pi, long_frac_ratio=0)) \frac{1}{2 \pi} \int r\, dr mul_symbol: The symbol to use for multiplication. Can be one of None, "ldot", "dot", or "times". >>> print(latex((2*tau)**sin(Rational(7, 2)), mul_symbol="times")) \left(2 \times \tau\right)^{\sin{\left (\frac{7}{2} \right )}} inv_trig_style: How inverse trig functions should be displayed. Can be one of "abbreviated", "full", or "power". Defaults to "abbreviated". >>> print(latex(asin(Rational(7, 2)))) \operatorname{asin}{\left (\frac{7}{2} \right )} >>> print(latex(asin(Rational(7, 2)), inv_trig_style="full")) \arcsin{\left (\frac{7}{2} \right )} >>> print(latex(asin(Rational(7, 2)), inv_trig_style="power")) \sin^{-1}{\left (\frac{7}{2} \right )} mat_str: Which matrix environment string to emit. "smallmatrix", "matrix", "array", etc. Defaults to "smallmatrix" for inline mode, "matrix" for matrices of no more than 10 columns, and "array" otherwise. >>> print(latex(Matrix(2, 1, [x, y]))) \left[\begin{matrix}x\\y\end{matrix}\right] >>> print(latex(Matrix(2, 1, [x, y]), mat_str="array")) \left[\begin{array}{c}x\\y\end{array}\right] mat_delim: The delimiter to wrap around matrices. Can be one of "[", "(", or the empty string. Defaults to "[". >>> print(latex(Matrix(2, 1, [x, y]), mat_delim="(")) \left(\begin{matrix}x\\y\end{matrix}\right) symbol_names: Dictionary of symbols and the custom strings they should be emitted as. >>> print(latex(x**2, symbol_names={x: 'x_i'})) x_i^{2} ``latex`` also supports the builtin container types list, tuple, and dictionary. >>> print(latex([2/x, y], mode='inline')) $\left [ 2 / x, \quad y\right ]$ """ return LatexPrinter(settings).doprint(expr)