Buckets:
MisterAI/LocalAI_Demo_backends / cpu-diffusers.upgrade-tmp /venv /lib /python3.10 /site-packages /sympy /printing /latex.py
| """ | |
| A Printer which converts an expression into its LaTeX equivalent. | |
| """ | |
| from __future__ import annotations | |
| from typing import Any, Callable, TYPE_CHECKING | |
| import itertools | |
| from sympy.core import Add, Float, Mod, Mul, Number, S, Symbol, Expr | |
| from sympy.core.alphabets import greeks | |
| from sympy.core.containers import Tuple | |
| from sympy.core.function import Function, AppliedUndef, Derivative | |
| from sympy.core.operations import AssocOp | |
| from sympy.core.power import Pow | |
| from sympy.core.sorting import default_sort_key | |
| from sympy.core.sympify import SympifyError | |
| from sympy.logic.boolalg import true, BooleanTrue, BooleanFalse | |
| # sympy.printing imports | |
| from sympy.printing.precedence import precedence_traditional | |
| from sympy.printing.printer import Printer, print_function | |
| from sympy.printing.conventions import split_super_sub, requires_partial | |
| from sympy.printing.precedence import precedence, PRECEDENCE | |
| from mpmath.libmp.libmpf import prec_to_dps, to_str as mlib_to_str | |
| from sympy.utilities.iterables import has_variety, sift | |
| import re | |
| if TYPE_CHECKING: | |
| from sympy.tensor.array import NDimArray | |
| from sympy.vector.basisdependent import BasisDependent | |
| # Hand-picked functions which can be used directly in both LaTeX and MathJax | |
| # Complete list at | |
| # https://docs.mathjax.org/en/latest/tex.html#supported-latex-commands | |
| # This variable only contains those functions which SymPy 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': r'\mathrm{A}', | |
| 'Beta': r'\mathrm{B}', | |
| 'Gamma': r'\Gamma', | |
| 'Delta': r'\Delta', | |
| 'Epsilon': r'\mathrm{E}', | |
| 'Zeta': r'\mathrm{Z}', | |
| 'Eta': r'\mathrm{H}', | |
| 'Theta': r'\Theta', | |
| 'Iota': r'\mathrm{I}', | |
| 'Kappa': r'\mathrm{K}', | |
| 'Lambda': r'\Lambda', | |
| 'Mu': r'\mathrm{M}', | |
| 'Nu': r'\mathrm{N}', | |
| 'Xi': r'\Xi', | |
| 'omicron': 'o', | |
| 'Omicron': r'\mathrm{O}', | |
| 'Pi': r'\Pi', | |
| 'Rho': r'\mathrm{P}', | |
| 'Sigma': r'\Sigma', | |
| 'Tau': r'\mathrm{T}', | |
| 'Upsilon': r'\Upsilon', | |
| 'Phi': r'\Phi', | |
| 'Chi': r'\mathrm{X}', | |
| 'Psi': r'\Psi', | |
| 'Omega': r'\Omega', | |
| 'lamda': r'\lambda', | |
| 'Lamda': r'\Lambda', | |
| 'khi': r'\chi', | |
| 'Khi': r'\mathrm{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: dict[str, Callable[[str], str]] = { | |
| # 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'}', | |
| 'cal': lambda s: r'\mathcal{'+s+r'}', | |
| 'scr': lambda s: r'\mathscr{'+s+r'}', | |
| 'frak': lambda s: r'\mathfrak{'+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'(\d|\\frac{\d+}{\d+})'), # match | |
| ) | |
| def latex_escape(s: str) -> str: | |
| """ | |
| Escape a string such that latex interprets it as plaintext. | |
| We cannot use verbatim easily with mathjax, so escaping is easier. | |
| Rules from https://tex.stackexchange.com/a/34586/41112. | |
| """ | |
| s = s.replace('\\', r'\textbackslash') | |
| for c in '&%$#_{}': | |
| s = s.replace(c, '\\' + c) | |
| s = s.replace('~', r'\textasciitilde') | |
| s = s.replace('^', r'\textasciicircum') | |
| return s | |
| class LatexPrinter(Printer): | |
| printmethod = "_latex" | |
| _default_settings: dict[str, Any] = { | |
| "full_prec": False, | |
| "fold_frac_powers": False, | |
| "fold_func_brackets": False, | |
| "fold_short_frac": None, | |
| "inv_trig_style": "abbreviated", | |
| "itex": False, | |
| "ln_notation": False, | |
| "long_frac_ratio": None, | |
| "mat_delim": "[", | |
| "mat_str": None, | |
| "mode": "plain", | |
| "mul_symbol": None, | |
| "order": None, | |
| "symbol_names": {}, | |
| "root_notation": True, | |
| "mat_symbol_style": "plain", | |
| "imaginary_unit": "i", | |
| "gothic_re_im": False, | |
| "decimal_separator": "period", | |
| "perm_cyclic": True, | |
| "parenthesize_super": True, | |
| "min": None, | |
| "max": None, | |
| "diff_operator": "d", | |
| "adjoint_style": "dagger", | |
| "disable_split_super_sub": False, | |
| } | |
| def __init__(self, settings=None): | |
| Printer.__init__(self, settings) | |
| if 'mode' in 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['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 " | |
| } | |
| try: | |
| self._settings['mul_symbol_latex'] = \ | |
| mul_symbol_table[self._settings['mul_symbol']] | |
| except KeyError: | |
| self._settings['mul_symbol_latex'] = \ | |
| self._settings['mul_symbol'] | |
| try: | |
| self._settings['mul_symbol_latex_numbers'] = \ | |
| mul_symbol_table[self._settings['mul_symbol'] or 'dot'] | |
| except KeyError: | |
| if (self._settings['mul_symbol'].strip() in | |
| ['', ' ', '\\', '\\,', '\\:', '\\;', '\\quad']): | |
| self._settings['mul_symbol_latex_numbers'] = \ | |
| mul_symbol_table['dot'] | |
| else: | |
| self._settings['mul_symbol_latex_numbers'] = \ | |
| self._settings['mul_symbol'] | |
| self._delim_dict = {'(': ')', '[': ']'} | |
| imaginary_unit_table = { | |
| None: r"i", | |
| "i": r"i", | |
| "ri": r"\mathrm{i}", | |
| "ti": r"\text{i}", | |
| "j": r"j", | |
| "rj": r"\mathrm{j}", | |
| "tj": r"\text{j}", | |
| } | |
| imag_unit = self._settings['imaginary_unit'] | |
| self._settings['imaginary_unit_latex'] = imaginary_unit_table.get(imag_unit, imag_unit) | |
| diff_operator_table = { | |
| None: r"d", | |
| "d": r"d", | |
| "rd": r"\mathrm{d}", | |
| "td": r"\text{d}", | |
| } | |
| diff_operator = self._settings['diff_operator'] | |
| self._settings["diff_operator_latex"] = diff_operator_table.get(diff_operator, diff_operator) | |
| def _add_parens(self, s) -> str: | |
| return r"\left({}\right)".format(s) | |
| # TODO: merge this with the above, which requires a lot of test changes | |
| def _add_parens_lspace(self, s) -> str: | |
| return r"\left( {}\right)".format(s) | |
| def parenthesize(self, item, level, is_neg=False, strict=False) -> str: | |
| prec_val = precedence_traditional(item) | |
| if is_neg and strict: | |
| return self._add_parens(self._print(item)) | |
| if (prec_val < level) or ((not strict) and prec_val <= level): | |
| return self._add_parens(self._print(item)) | |
| else: | |
| return self._print(item) | |
| def parenthesize_super(self, s): | |
| """ | |
| Protect superscripts in s | |
| If the parenthesize_super option is set, protect with parentheses, else | |
| wrap in braces. | |
| """ | |
| if "^" in s: | |
| if self._settings['parenthesize_super']: | |
| return self._add_parens(s) | |
| else: | |
| return "{{{}}}".format(s) | |
| return s | |
| def doprint(self, expr) -> str: | |
| 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_brackets(self, expr) -> bool: | |
| """ | |
| Returns True if the expression needs to be wrapped in brackets when | |
| printed, False otherwise. For example: a + b => True; a => False; | |
| 10 => False; -10 => True. | |
| """ | |
| return not ((expr.is_Integer and expr.is_nonnegative) | |
| or (expr.is_Atom and (expr is not S.NegativeOne | |
| and expr.is_Rational is False))) | |
| def _needs_function_brackets(self, expr) -> bool: | |
| """ | |
| Returns True if the expression needs to be wrapped in brackets when | |
| passed as an argument to a function, False otherwise. This is a more | |
| liberal version of _needs_brackets, in that many expressions which need | |
| to be wrapped in brackets when added/subtracted/raised to a power do | |
| not need them when passed to a function. Such an example is a*b. | |
| """ | |
| if not self._needs_brackets(expr): | |
| return False | |
| else: | |
| # Muls of the form a*b*c... can be folded | |
| if expr.is_Mul and not self._mul_is_clean(expr): | |
| return True | |
| # Pows which don't need brackets can be folded | |
| elif expr.is_Pow and not self._pow_is_clean(expr): | |
| return True | |
| # Add and Function always need brackets | |
| elif expr.is_Add or expr.is_Function: | |
| return True | |
| else: | |
| return False | |
| def _needs_mul_brackets(self, expr, first=False, last=False) -> bool: | |
| """ | |
| 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 sympy.concrete.products import Product | |
| from sympy.concrete.summations import Sum | |
| from sympy.integrals.integrals import Integral | |
| if expr.is_Mul: | |
| if not first and expr.could_extract_minus_sign(): | |
| return True | |
| elif precedence_traditional(expr) < PRECEDENCE["Mul"]: | |
| return True | |
| elif expr.is_Relational: | |
| return True | |
| if expr.is_Piecewise: | |
| return True | |
| if any(expr.has(x) for x in (Mod,)): | |
| return True | |
| if (not last and | |
| any(expr.has(x) for x in (Integral, Product, Sum))): | |
| return True | |
| return False | |
| def _needs_add_brackets(self, expr) -> bool: | |
| """ | |
| 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 any(expr.has(x) for x in (Mod,)): | |
| return True | |
| if expr.is_Add: | |
| return True | |
| return False | |
| def _mul_is_clean(self, expr) -> bool: | |
| for arg in expr.args: | |
| if arg.is_Function: | |
| return False | |
| return True | |
| def _pow_is_clean(self, expr) -> bool: | |
| return not self._needs_brackets(expr.base) | |
| def _do_exponent(self, expr: str, exp): | |
| if exp is not None: | |
| return r"\left(%s\right)^{%s}" % (expr, exp) | |
| else: | |
| return expr | |
| def _print_Basic(self, expr): | |
| name = self._deal_with_super_sub(expr.__class__.__name__) | |
| if expr.args: | |
| ls = [self._print(o) for o in expr.args] | |
| s = r"\operatorname{{{}}}\left({}\right)" | |
| return s.format(name, ", ".join(ls)) | |
| else: | |
| return r"\text{{{}}}".format(name) | |
| def _print_bool(self, e: bool | BooleanTrue | BooleanFalse): | |
| return r"\text{%s}" % e | |
| _print_BooleanTrue = _print_bool | |
| _print_BooleanFalse = _print_bool | |
| def _print_NoneType(self, e): | |
| return r"\text{%s}" % e | |
| def _print_Add(self, expr, order=None): | |
| terms = self._as_ordered_terms(expr, order=order) | |
| tex = "" | |
| for i, term in enumerate(terms): | |
| if i == 0: | |
| pass | |
| elif term.could_extract_minus_sign(): | |
| 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 sympy.combinatorics.permutations import Permutation | |
| if expr.size == 0: | |
| 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 | |
| def _print_Permutation(self, expr): | |
| from sympy.combinatorics.permutations import Permutation | |
| from sympy.utilities.exceptions import sympy_deprecation_warning | |
| perm_cyclic = Permutation.print_cyclic | |
| if perm_cyclic is not None: | |
| sympy_deprecation_warning( | |
| f""" | |
| Setting Permutation.print_cyclic is deprecated. Instead use | |
| init_printing(perm_cyclic={perm_cyclic}). | |
| """, | |
| deprecated_since_version="1.6", | |
| active_deprecations_target="deprecated-permutation-print_cyclic", | |
| stacklevel=8, | |
| ) | |
| else: | |
| perm_cyclic = self._settings.get("perm_cyclic", True) | |
| if perm_cyclic: | |
| return self._print_Cycle(expr) | |
| if expr.size == 0: | |
| return r"\left( \right)" | |
| lower = [self._print(arg) for arg in expr.array_form] | |
| upper = [self._print(arg) for arg in range(len(lower))] | |
| row1 = " & ".join(upper) | |
| row2 = " & ".join(lower) | |
| mat = r" \\ ".join((row1, row2)) | |
| return r"\begin{pmatrix} %s \end{pmatrix}" % mat | |
| def _print_AppliedPermutation(self, expr): | |
| perm, var = expr.args | |
| return r"\sigma_{%s}(%s)" % (self._print(perm), self._print(var)) | |
| def _print_Float(self, expr): | |
| # Based off of that in StrPrinter | |
| dps = prec_to_dps(expr._prec) | |
| strip = False if self._settings['full_prec'] else True | |
| low = self._settings["min"] if "min" in self._settings else None | |
| high = self._settings["max"] if "max" in self._settings else None | |
| str_real = mlib_to_str(expr._mpf_, dps, strip_zeros=strip, min_fixed=low, max_fixed=high) | |
| # 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:] | |
| if self._settings['decimal_separator'] == 'comma': | |
| mant = mant.replace('.','{,}') | |
| return r"%s%s10^{%s}" % (mant, separator, exp) | |
| elif str_real == "+inf": | |
| return r"\infty" | |
| elif str_real == "-inf": | |
| return r"- \infty" | |
| else: | |
| if self._settings['decimal_separator'] == 'comma': | |
| str_real = str_real.replace('.','{,}') | |
| return str_real | |
| def _print_Cross(self, expr): | |
| vec1 = expr._expr1 | |
| vec2 = expr._expr2 | |
| return r"%s \times %s" % (self.parenthesize(vec1, PRECEDENCE['Mul']), | |
| self.parenthesize(vec2, PRECEDENCE['Mul'])) | |
| def _print_Curl(self, expr): | |
| vec = expr._expr | |
| return r"\nabla\times %s" % self.parenthesize(vec, PRECEDENCE['Mul']) | |
| def _print_Divergence(self, expr): | |
| vec = expr._expr | |
| return r"\nabla\cdot %s" % self.parenthesize(vec, PRECEDENCE['Mul']) | |
| def _print_Dot(self, expr): | |
| vec1 = expr._expr1 | |
| vec2 = expr._expr2 | |
| return r"%s \cdot %s" % (self.parenthesize(vec1, PRECEDENCE['Mul']), | |
| self.parenthesize(vec2, PRECEDENCE['Mul'])) | |
| def _print_Gradient(self, expr): | |
| func = expr._expr | |
| return r"\nabla %s" % self.parenthesize(func, PRECEDENCE['Mul']) | |
| def _print_Laplacian(self, expr): | |
| func = expr._expr | |
| return r"\Delta %s" % self.parenthesize(func, PRECEDENCE['Mul']) | |
| def _print_Mul(self, expr: Expr): | |
| from sympy.simplify import fraction | |
| separator: str = self._settings['mul_symbol_latex'] | |
| numbersep: str = self._settings['mul_symbol_latex_numbers'] | |
| def convert(expr) -> str: | |
| if not expr.is_Mul: | |
| return str(self._print(expr)) | |
| else: | |
| if self.order not in ('old', 'none'): | |
| args = expr.as_ordered_factors() | |
| else: | |
| args = list(expr.args) | |
| # If there are quantities or prefixes, append them at the back. | |
| units, nonunits = sift(args, lambda x: (hasattr(x, "_scale_factor") or hasattr(x, "is_physical_constant")) or | |
| (isinstance(x, Pow) and | |
| hasattr(x.base, "is_physical_constant")), binary=True) | |
| prefixes, units = sift(units, lambda x: hasattr(x, "_scale_factor"), binary=True) | |
| return convert_args(nonunits + prefixes + units) | |
| def convert_args(args) -> str: | |
| _tex = last_term_tex = "" | |
| for i, term in enumerate(args): | |
| term_tex = self._print(term) | |
| if not (hasattr(term, "_scale_factor") or hasattr(term, "is_physical_constant")): | |
| 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 | |
| elif _tex: | |
| _tex += separator | |
| _tex += term_tex | |
| last_term_tex = term_tex | |
| return _tex | |
| # Check for unevaluated Mul. In this case we need to make sure the | |
| # identities are visible, multiple Rational factors are not combined | |
| # etc so we display in a straight-forward form that fully preserves all | |
| # args and their order. | |
| # XXX: _print_Pow calls this routine with instances of Pow... | |
| if isinstance(expr, Mul): | |
| args = expr.args | |
| if args[0] is S.One or any(isinstance(arg, Number) for arg in args[1:]): | |
| return convert_args(args) | |
| include_parens = False | |
| if expr.could_extract_minus_sign(): | |
| expr = -expr | |
| tex = "- " | |
| if expr.is_Add: | |
| tex += "(" | |
| include_parens = True | |
| else: | |
| tex = "" | |
| numer, denom = fraction(expr, exact=True) | |
| if denom is S.One and Pow(1, -1, evaluate=False) not in expr.args: | |
| # 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 ratio is not None and \ | |
| 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_AlgebraicNumber(self, expr): | |
| if expr.is_aliased: | |
| return self._print(expr.as_poly().as_expr()) | |
| else: | |
| return self._print(expr.as_expr()) | |
| def _print_PrimeIdeal(self, expr): | |
| p = self._print(expr.p) | |
| if expr.is_inert: | |
| return rf'\left({p}\right)' | |
| alpha = self._print(expr.alpha.as_expr()) | |
| return rf'\left({p}, {alpha}\right)' | |
| def _print_Pow(self, expr: Pow): | |
| # Treat x**Rational(1,n) as special case | |
| if expr.exp.is_Rational: | |
| p: int = expr.exp.p # type: ignore | |
| q: int = expr.exp.q # type: ignore | |
| if abs(p) == 1 and q != 1 and self._settings['root_notation']: | |
| base = self._print(expr.base) | |
| if q == 2: | |
| tex = r"\sqrt{%s}" % base | |
| elif self._settings['itex']: | |
| tex = r"\root{%d}{%s}" % (q, base) | |
| else: | |
| tex = r"\sqrt[%d]{%s}" % (q, base) | |
| if expr.exp.is_negative: | |
| return r"\frac{1}{%s}" % tex | |
| else: | |
| return tex | |
| elif self._settings['fold_frac_powers'] and q != 1: | |
| base = self.parenthesize(expr.base, PRECEDENCE['Pow']) | |
| # issue #12886: add parentheses for superscripts raised to powers | |
| if expr.base.is_Symbol: | |
| base = self.parenthesize_super(base) | |
| if expr.base.is_Function: | |
| return self._print(expr.base, exp="%s/%s" % (p, q)) | |
| return r"%s^{%s/%s}" % (base, p, q) | |
| elif expr.exp.is_negative and expr.base.is_commutative: | |
| # special case for 1^(-x), issue 9216 | |
| if expr.base == 1: | |
| return r"%s^{%s}" % (expr.base, expr.exp) | |
| # special case for (1/x)^(-y) and (-1/-x)^(-y), issue 20252 | |
| if expr.base.is_Rational: | |
| base_p: int = expr.base.p # type: ignore | |
| base_q: int = expr.base.q # type: ignore | |
| if base_p * base_q == abs(base_q): | |
| if expr.exp == -1: | |
| return r"\frac{1}{\frac{%s}{%s}}" % (base_p, base_q) | |
| else: | |
| return r"\frac{1}{(\frac{%s}{%s})^{%s}}" % (base_p, base_q, abs(expr.exp)) | |
| # things like 1/x | |
| return self._print_Mul(expr) | |
| if expr.base.is_Function: | |
| return self._print(expr.base, exp=self._print(expr.exp)) | |
| tex = r"%s^{%s}" | |
| return self._helper_print_standard_power(expr, tex) | |
| def _helper_print_standard_power(self, expr, template: str) -> str: | |
| exp = self._print(expr.exp) | |
| # issue #12886: add parentheses around superscripts raised | |
| # to powers | |
| base = self.parenthesize(expr.base, PRECEDENCE['Pow']) | |
| if expr.base.is_Symbol: | |
| base = self.parenthesize_super(base) | |
| elif expr.base.is_Float: | |
| base = r"{%s}" % base | |
| elif (isinstance(expr.base, Derivative) | |
| and base.startswith(r'\left(') | |
| and re.match(r'\\left\(\\d?d?dot', base) | |
| and base.endswith(r'\right)')): | |
| # don't use parentheses around dotted derivative | |
| base = base[6: -7] # remove outermost added parens | |
| return template % (base, exp) | |
| def _print_UnevaluatedExpr(self, expr): | |
| return self._print(expr.args[0]) | |
| 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: 'BasisDependent'): | |
| from sympy.vector import Vector | |
| o1: list[str] = [] | |
| 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 = r'\left(' + self._print(v) + r'\right)' | |
| 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_base = self._print(expr.base) | |
| tex = '{'+tex_base+'}'+'_{%s}' % ','.join( | |
| map(self._print, expr.indices)) | |
| return tex | |
| def _print_IndexedBase(self, expr): | |
| return self._print(expr.label) | |
| def _print_Idx(self, expr): | |
| label = self._print(expr.label) | |
| if expr.upper is not None: | |
| upper = self._print(expr.upper) | |
| if expr.lower is not None: | |
| lower = self._print(expr.lower) | |
| else: | |
| lower = self._print(S.Zero) | |
| interval = '{lower}\\mathrel{{..}}\\nobreak {upper}'.format( | |
| lower = lower, upper = upper) | |
| return '{{{label}}}_{{{interval}}}'.format( | |
| label = label, interval = interval) | |
| #if no bounds are defined this just prints the label | |
| return label | |
| def _print_Derivative(self, expr): | |
| if requires_partial(expr.expr): | |
| diff_symbol = r'\partial' | |
| else: | |
| diff_symbol = self._settings["diff_operator_latex"] | |
| tex = "" | |
| dim = 0 | |
| for x, num in reversed(expr.variable_count): | |
| dim += num | |
| if num == 1: | |
| tex += r"%s %s" % (diff_symbol, self._print(x)) | |
| else: | |
| tex += r"%s %s^{%s}" % (diff_symbol, | |
| self.parenthesize_super(self._print(x)), | |
| self._print(num)) | |
| if dim == 1: | |
| tex = r"\frac{%s}{%s}" % (diff_symbol, tex) | |
| else: | |
| tex = r"\frac{%s^{%s}}{%s}" % (diff_symbol, self._print(dim), tex) | |
| if any(i.could_extract_minus_sign() for i in expr.args): | |
| return r"%s %s" % (tex, self.parenthesize(expr.expr, | |
| PRECEDENCE["Mul"], | |
| is_neg=True, | |
| strict=True)) | |
| return r"%s %s" % (tex, self.parenthesize(expr.expr, | |
| PRECEDENCE["Mul"], | |
| is_neg=False, | |
| strict=True)) | |
| def _print_Subs(self, subs): | |
| expr, old, new = subs.args | |
| latex_expr = self._print(expr) | |
| latex_old = (self._print(e) for e in old) | |
| latex_new = (self._print(e) for e in new) | |
| 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 = "", [] | |
| diff_symbol = self._settings["diff_operator_latex"] | |
| # 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"\, %s%s" % (diff_symbol, 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'] != 'inline' \ | |
| 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"\, %s%s" % (diff_symbol, self._print(symbol))) | |
| return r"%s %s%s" % (tex, self.parenthesize(expr.function, | |
| PRECEDENCE["Mul"], | |
| is_neg=any(i.could_extract_minus_sign() for i in expr.args), | |
| strict=True), | |
| "".join(symbols)) | |
| def _print_Limit(self, expr): | |
| e, z, z0, dir = expr.args | |
| tex = r"\lim_{%s \to " % self._print(z) | |
| if str(dir) == '+-' or z0 in (S.Infinity, S.NegativeInfinity): | |
| tex += r"%s}" % self._print(z0) | |
| else: | |
| tex += r"%s^%s}" % (self._print(z0), self._print(dir)) | |
| if isinstance(e, AssocOp): | |
| return r"%s\left(%s\right)" % (tex, self._print(e)) | |
| else: | |
| return r"%s %s" % (tex, self._print(e)) | |
| def _hprint_Function(self, func: str) -> str: | |
| 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, excluding sub- and superscripts, 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) | |
| superscriptidx = func.find("^") | |
| subscriptidx = func.find("_") | |
| if func in accepted_latex_functions: | |
| name = r"\%s" % func | |
| elif len(func) == 1 or func.startswith('\\') or subscriptidx == 1 or superscriptidx == 1: | |
| name = func | |
| else: | |
| if superscriptidx > 0 and subscriptidx > 0: | |
| name = r"\operatorname{%s}%s" %( | |
| func[:min(subscriptidx,superscriptidx)], | |
| func[min(subscriptidx,superscriptidx):]) | |
| elif superscriptidx > 0: | |
| name = r"\operatorname{%s}%s" %( | |
| func[:superscriptidx], | |
| func[superscriptidx:]) | |
| elif subscriptidx > 0: | |
| name = r"\operatorname{%s}%s" %( | |
| func[:subscriptidx], | |
| func[subscriptidx:]) | |
| else: | |
| name = r"\operatorname{%s}" % func | |
| return name | |
| def _print_Function(self, expr: Function, exp=None) -> str: | |
| 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__ | |
| if hasattr(self, '_print_' + func) and \ | |
| not isinstance(expr, AppliedUndef): | |
| return getattr(self, '_print_' + func)(expr, exp) | |
| else: | |
| 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 and \ | |
| not self._needs_function_brackets(expr.args[0]) | |
| inv_trig_table = [ | |
| "asin", "acos", "atan", | |
| "acsc", "asec", "acot", | |
| "asinh", "acosh", "atanh", | |
| "acsch", "asech", "acoth", | |
| ] | |
| # If the function is an inverse trig function, handle the style | |
| if func in inv_trig_table: | |
| if inv_trig_style == "abbreviated": | |
| pass | |
| elif inv_trig_style == "full": | |
| func = ("ar" if func[-1] == "h" else "arc") + func[1:] | |
| elif 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: | |
| if func in accepted_latex_functions: | |
| name = r"\%s^{-1}" % func | |
| else: | |
| name = r"\operatorname{%s}^{-1}" % func | |
| elif exp is not None: | |
| func_tex = self._hprint_Function(func) | |
| func_tex = self.parenthesize_super(func_tex) | |
| name = r'%s^{%s}' % (func_tex, 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_ElementwiseApplyFunction(self, expr): | |
| return r"{%s}_{\circ}\left({%s}\right)" % ( | |
| self._print(expr.function), | |
| self._print(expr.expr), | |
| ) | |
| def _special_function_classes(self): | |
| from sympy.functions.special.tensor_functions import KroneckerDelta | |
| from sympy.functions.special.gamma_functions import gamma, lowergamma | |
| from sympy.functions.special.beta_functions import beta | |
| from sympy.functions.special.delta_functions import DiracDelta | |
| from sympy.functions.special.error_functions import Chi | |
| return {KroneckerDelta: r'\delta', | |
| gamma: r'\Gamma', | |
| lowergamma: r'\gamma', | |
| beta: r'\operatorname{B}', | |
| DiracDelta: r'\delta', | |
| Chi: r'\operatorname{Chi}'} | |
| def _print_FunctionClass(self, expr): | |
| for cls in self._special_function_classes: | |
| if issubclass(expr, cls) and expr.__name__ == cls.__name__: | |
| return self._special_function_classes[cls] | |
| 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_IdentityFunction(self, expr): | |
| return r"\left( x \mapsto x \right)" | |
| def _hprint_variadic_function(self, expr, exp=None) -> str: | |
| args = sorted(expr.args, key=default_sort_key) | |
| texargs = [r"%s" % self._print(symbol) for symbol in args] | |
| tex = r"\%s\left(%s\right)" % (str(expr.func).lower(), | |
| ", ".join(texargs)) | |
| if exp is not None: | |
| return r"%s^{%s}" % (tex, exp) | |
| else: | |
| return tex | |
| _print_Min = _print_Max = _hprint_variadic_function | |
| def _print_floor(self, expr, exp=None): | |
| tex = r"\left\lfloor{%s}\right\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"\left\lceil{%s}\right\rceil" % self._print(expr.args[0]) | |
| if exp is not None: | |
| return r"%s^{%s}" % (tex, exp) | |
| else: | |
| return tex | |
| def _print_log(self, expr, exp=None): | |
| if not self._settings["ln_notation"]: | |
| tex = r"\log{\left(%s \right)}" % self._print(expr.args[0]) | |
| else: | |
| tex = r"\ln{\left(%s \right)}" % 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 | |
| def _print_re(self, expr, exp=None): | |
| if self._settings['gothic_re_im']: | |
| tex = r"\Re{%s}" % self.parenthesize(expr.args[0], PRECEDENCE['Atom']) | |
| else: | |
| tex = r"\operatorname{{re}}{{{}}}".format(self.parenthesize(expr.args[0], PRECEDENCE['Atom'])) | |
| return self._do_exponent(tex, exp) | |
| def _print_im(self, expr, exp=None): | |
| if self._settings['gothic_re_im']: | |
| tex = r"\Im{%s}" % self.parenthesize(expr.args[0], PRECEDENCE['Atom']) | |
| else: | |
| tex = r"\operatorname{{im}}{{{}}}".format(self.parenthesize(expr.args[0], PRECEDENCE['Atom'])) | |
| return self._do_exponent(tex, exp) | |
| def _print_Not(self, e): | |
| from sympy.logic.boolalg import (Equivalent, Implies) | |
| if isinstance(e.args[0], Equivalent): | |
| return self._print_Equivalent(e.args[0], r"\not\Leftrightarrow") | |
| 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 \left(%s\right)" % 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: | |
| 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: | |
| 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"\Leftrightarrow") | |
| 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_ExpBase(self, expr, exp=None): | |
| # TODO should exp_polar be printed differently? | |
| # what about exp_polar(0), exp_polar(1)? | |
| tex = r"e^{%s}" % self._print(expr.args[0]) | |
| return self._do_exponent(tex, exp) | |
| def _print_Exp1(self, expr, exp=None): | |
| return "e" | |
| 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_beta(self, expr, exp=None): | |
| x = expr.args[0] | |
| # Deal with unevaluated single argument beta | |
| y = expr.args[0] if len(expr.args) == 1 else expr.args[1] | |
| tex = rf"\left({x}, {y}\right)" | |
| if exp is not None: | |
| return r"\operatorname{B}^{%s}%s" % (exp, tex) | |
| else: | |
| return r"\operatorname{B}%s" % tex | |
| def _print_betainc(self, expr, exp=None, operator='B'): | |
| largs = [self._print(arg) for arg in expr.args] | |
| tex = r"\left(%s, %s\right)" % (largs[0], largs[1]) | |
| if exp is not None: | |
| return r"\operatorname{%s}_{(%s, %s)}^{%s}%s" % (operator, largs[2], largs[3], exp, tex) | |
| else: | |
| return r"\operatorname{%s}_{(%s, %s)}%s" % (operator, largs[2], largs[3], tex) | |
| def _print_betainc_regularized(self, expr, exp=None): | |
| return self._print_betainc(expr, exp, operator='I') | |
| 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 _hprint_one_arg_func(self, expr, exp=None) -> str: | |
| tex = r"\left(%s\right)" % self._print(expr.args[0]) | |
| if exp is not None: | |
| return r"%s^{%s}%s" % (self._print(expr.func), exp, tex) | |
| else: | |
| return r"%s%s" % (self._print(expr.func), tex) | |
| _print_gamma = _hprint_one_arg_func | |
| def _print_Chi(self, expr, exp=None): | |
| tex = r"\left(%s\right)" % self._print(expr.args[0]) | |
| if exp is not None: | |
| return r"\operatorname{Chi}^{%s}%s" % (exp, tex) | |
| else: | |
| return r"\operatorname{Chi}%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"\left(%s\right)^{%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: str) -> str: | |
| tex = r"%s" % (sym) | |
| need_exp = False | |
| if exp is not None: | |
| if tex.find('^') == -1: | |
| tex = r"%s^{%s}" % (tex, 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) -> str: | |
| if not vec: | |
| 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 _print_hn1(self, expr, exp=None): | |
| return self._hprint_BesselBase(expr, exp, 'h^{(1)}') | |
| def _print_hn2(self, expr, exp=None): | |
| return self._hprint_BesselBase(expr, exp, 'h^{(2)}') | |
| def _hprint_airy(self, expr, exp=None, notation="") -> str: | |
| 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="") -> str: | |
| 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, 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, 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" % (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" % (exp, tex) | |
| return r"\zeta%s" % tex | |
| def _print_stieltjes(self, expr, exp=None): | |
| if len(expr.args) == 2: | |
| tex = r"_{%s}\left(%s\right)" % tuple(map(self._print, expr.args)) | |
| else: | |
| tex = r"_{%s}" % self._print(expr.args[0]) | |
| if exp is not None: | |
| return r"\gamma%s^{%s}" % (tex, exp) | |
| return r"\gamma%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" % (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, 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}" % (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}" % (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}" % (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}" % (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}" % (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}" % (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}" % (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}" % (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}" % (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}" % (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}" % (exp) | |
| return tex | |
| def __print_mathieu_functions(self, character, args, prime=False, exp=None): | |
| a, q, z = map(self._print, args) | |
| sup = r"^{\prime}" if prime else "" | |
| exp = "" if not exp else "^{%s}" % exp | |
| return r"%s%s\left(%s, %s, %s\right)%s" % (character, sup, a, q, z, exp) | |
| def _print_mathieuc(self, expr, exp=None): | |
| return self.__print_mathieu_functions("C", expr.args, exp=exp) | |
| def _print_mathieus(self, expr, exp=None): | |
| return self.__print_mathieu_functions("S", expr.args, exp=exp) | |
| def _print_mathieucprime(self, expr, exp=None): | |
| return self.__print_mathieu_functions("C", expr.args, prime=True, exp=exp) | |
| def _print_mathieusprime(self, expr, exp=None): | |
| return self.__print_mathieu_functions("S", expr.args, prime=True, exp=exp) | |
| def _print_Rational(self, expr): | |
| if expr.q != 1: | |
| sign = "" | |
| p = expr.p | |
| if expr.p < 0: | |
| sign = "- " | |
| p = -p | |
| if self._settings['fold_short_frac']: | |
| return r"%s%d / %d" % (sign, p, expr.q) | |
| return r"%s\frac{%d}{%d}" % (sign, p, expr.q) | |
| else: | |
| return self._print(expr.p) | |
| def _print_Order(self, expr): | |
| s = self._print(expr.expr) | |
| if expr.point and any(p != S.Zero for p in expr.point) or \ | |
| len(expr.variables) > 1: | |
| s += '; ' | |
| if len(expr.variables) > 1: | |
| s += self._print(expr.variables) | |
| elif expr.variables: | |
| 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"O\left(%s\right)" % s | |
| def _print_Symbol(self, expr: Symbol, style='plain'): | |
| name: str = self._settings['symbol_names'].get(expr) | |
| if name is not None: | |
| return name | |
| return self._deal_with_super_sub(expr.name, style=style) | |
| _print_RandomSymbol = _print_Symbol | |
| def _split_super_sub(self, name: str) -> tuple[str, list[str], list[str]]: | |
| if name is None or '{' in name: | |
| return (name, [], []) | |
| elif self._settings["disable_split_super_sub"]: | |
| name, supers, subs = (name.replace('_', '\\_').replace('^', '\\^'), [], []) | |
| else: | |
| name, supers, subs = split_super_sub(name) | |
| name = translate(name) | |
| supers = [translate(sup) for sup in supers] | |
| subs = [translate(sub) for sub in subs] | |
| return (name, supers, subs) | |
| def _deal_with_super_sub(self, string: str, style='plain') -> str: | |
| name, supers, subs = self._split_super_sub(string) | |
| # apply the style only to the name | |
| if style == 'bold': | |
| name = "\\mathbf{{{}}}".format(name) | |
| # glue all items together: | |
| if supers: | |
| name += "^{%s}" % " ".join(supers) | |
| if subs: | |
| 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_matrix_contents(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') | |
| return out_str % r"\\".join(lines) | |
| def _print_MatrixBase(self, expr): | |
| out_str = self._print_matrix_contents(expr) | |
| 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 | |
| def _print_MatrixElement(self, expr): | |
| matrix_part = self.parenthesize(expr.parent, PRECEDENCE['Atom'], strict=True) | |
| index_part = f"{self._print(expr.i)},{self._print(expr.j)}" | |
| return f"{{{matrix_part}}}_{{{index_part}}}" | |
| def _print_MatrixSlice(self, expr): | |
| def latexslice(x, dim): | |
| x = list(x) | |
| if x[2] == 1: | |
| del x[2] | |
| if x[0] == 0: | |
| x[0] = None | |
| if x[1] == dim: | |
| x[1] = None | |
| return ':'.join(self._print(xi) if xi is not None else '' for xi in x) | |
| return (self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) + r'\left[' + | |
| latexslice(expr.rowslice, expr.parent.rows) + ', ' + | |
| latexslice(expr.colslice, expr.parent.cols) + r'\right]') | |
| def _print_BlockMatrix(self, expr): | |
| return self._print(expr.blocks) | |
| def _print_Transpose(self, expr): | |
| mat = expr.arg | |
| from sympy.matrices import MatrixSymbol, BlockMatrix | |
| if (not isinstance(mat, MatrixSymbol) and | |
| not isinstance(mat, BlockMatrix) and mat.is_MatrixExpr): | |
| return r"\left(%s\right)^{T}" % self._print(mat) | |
| else: | |
| s = self.parenthesize(mat, precedence_traditional(expr), True) | |
| if '^' in s: | |
| return r"\left(%s\right)^{T}" % s | |
| else: | |
| return "%s^{T}" % s | |
| def _print_Trace(self, expr): | |
| mat = expr.arg | |
| return r"\operatorname{tr}\left(%s \right)" % self._print(mat) | |
| def _print_Adjoint(self, expr): | |
| style_to_latex = { | |
| "dagger" : r"\dagger", | |
| "star" : r"\ast", | |
| "hermitian": r"\mathsf{H}" | |
| } | |
| adjoint_style = style_to_latex.get(self._settings["adjoint_style"], r"\dagger") | |
| mat = expr.arg | |
| from sympy.matrices import MatrixSymbol, BlockMatrix | |
| if (not isinstance(mat, MatrixSymbol) and | |
| not isinstance(mat, BlockMatrix) and mat.is_MatrixExpr): | |
| return r"\left(%s\right)^{%s}" % (self._print(mat), adjoint_style) | |
| else: | |
| s = self.parenthesize(mat, precedence_traditional(expr), True) | |
| if '^' in s: | |
| return r"\left(%s\right)^{%s}" % (s, adjoint_style) | |
| else: | |
| return r"%s^{%s}" % (s, adjoint_style) | |
| def _print_MatMul(self, expr): | |
| from sympy import MatMul | |
| # Parenthesize nested MatMul but not other types of Mul objects: | |
| parens = lambda x: self._print(x) if isinstance(x, Mul) and not isinstance(x, MatMul) else \ | |
| self.parenthesize(x, precedence_traditional(expr), False) | |
| args = list(expr.args) | |
| if expr.could_extract_minus_sign(): | |
| if args[0] == -1: | |
| args = args[1:] | |
| else: | |
| args[0] = -args[0] | |
| return '- ' + ' '.join(map(parens, args)) | |
| else: | |
| return ' '.join(map(parens, args)) | |
| def _print_DotProduct(self, expr): | |
| level = precedence_traditional(expr) | |
| left, right = expr.args | |
| return rf"{self.parenthesize(left, level)} \cdot {self.parenthesize(right, level)}" | |
| def _print_Determinant(self, expr): | |
| mat = expr.arg | |
| if mat.is_MatrixExpr: | |
| from sympy.matrices.expressions.blockmatrix import BlockMatrix | |
| if isinstance(mat, BlockMatrix): | |
| return r"\left|{%s}\right|" % self._print_matrix_contents(mat.blocks) | |
| return r"\left|{%s}\right|" % self._print(mat) | |
| return r"\left|{%s}\right|" % self._print_matrix_contents(mat) | |
| 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'], | |
| strict=True), | |
| self.parenthesize(expr.args[1], PRECEDENCE['Mul'], | |
| strict=True), | |
| exp) | |
| return r'%s \bmod %s' % (self.parenthesize(expr.args[0], | |
| PRECEDENCE['Mul'], | |
| strict=True), | |
| self.parenthesize(expr.args[1], | |
| PRECEDENCE['Mul'], | |
| strict=True)) | |
| def _print_HadamardProduct(self, expr): | |
| args = expr.args | |
| prec = PRECEDENCE['Pow'] | |
| parens = self.parenthesize | |
| return r' \circ '.join( | |
| (parens(arg, prec, strict=True) for arg in args)) | |
| def _print_HadamardPower(self, expr): | |
| if precedence_traditional(expr.exp) < PRECEDENCE["Mul"]: | |
| template = r"%s^{\circ \left({%s}\right)}" | |
| else: | |
| template = r"%s^{\circ {%s}}" | |
| return self._helper_print_standard_power(expr, template) | |
| def _print_KroneckerProduct(self, expr): | |
| args = expr.args | |
| prec = PRECEDENCE['Pow'] | |
| parens = self.parenthesize | |
| return r' \otimes '.join( | |
| (parens(arg, prec, strict=True) for arg in args)) | |
| def _print_MatPow(self, expr): | |
| base, exp = expr.base, expr.exp | |
| from sympy.matrices import MatrixSymbol | |
| if not isinstance(base, MatrixSymbol) and base.is_MatrixExpr: | |
| return "\\left(%s\\right)^{%s}" % (self._print(base), | |
| self._print(exp)) | |
| else: | |
| base_str = self._print(base) | |
| if '^' in base_str: | |
| return r"\left(%s\right)^{%s}" % (base_str, self._print(exp)) | |
| else: | |
| return "%s^{%s}" % (base_str, self._print(exp)) | |
| def _print_MatrixSymbol(self, expr): | |
| return self._print_Symbol(expr, style=self._settings[ | |
| 'mat_symbol_style']) | |
| def _print_ZeroMatrix(self, Z): | |
| return "0" if self._settings[ | |
| 'mat_symbol_style'] == 'plain' else r"\mathbf{0}" | |
| def _print_OneMatrix(self, O): | |
| return "1" if self._settings[ | |
| 'mat_symbol_style'] == 'plain' else r"\mathbf{1}" | |
| def _print_Identity(self, I): | |
| return r"\mathbb{I}" if self._settings[ | |
| 'mat_symbol_style'] == 'plain' else r"\mathbf{I}" | |
| def _print_PermutationMatrix(self, P): | |
| perm_str = self._print(P.args[0]) | |
| return "P_{%s}" % perm_str | |
| def _print_NDimArray(self, expr: NDimArray): | |
| if expr.rank() == 0: | |
| return self._print(expr[()]) | |
| mat_str = self._settings['mat_str'] | |
| if mat_str is None: | |
| if self._settings['mode'] == 'inline': | |
| mat_str = 'smallmatrix' | |
| else: | |
| if (expr.rank() == 0) or (expr.shape[-1] <= 10): | |
| mat_str = 'matrix' | |
| else: | |
| mat_str = 'array' | |
| block_str = r'\begin{%MATSTR%}%s\end{%MATSTR%}' | |
| block_str = block_str.replace('%MATSTR%', mat_str) | |
| if mat_str == 'array': | |
| block_str = block_str.replace('%s', '{' + 'c'*expr.shape[0] + '}%s') | |
| if self._settings['mat_delim']: | |
| left_delim: str = self._settings['mat_delim'] | |
| right_delim = self._delim_dict[left_delim] | |
| block_str = r'\left' + left_delim + block_str + \ | |
| r'\right' + right_delim | |
| if expr.rank() == 0: | |
| return block_str % "" | |
| level_str: list[list[str]] = [[] for i in range(expr.rank() + 1)] | |
| shape_ranges = [list(range(i)) for i in expr.shape] | |
| for outer_i in itertools.product(*shape_ranges): | |
| level_str[-1].append(self._print(expr[outer_i])) | |
| even = True | |
| for back_outer_i in range(expr.rank()-1, -1, -1): | |
| if len(level_str[back_outer_i+1]) < expr.shape[back_outer_i]: | |
| break | |
| if even: | |
| level_str[back_outer_i].append( | |
| r" & ".join(level_str[back_outer_i+1])) | |
| else: | |
| level_str[back_outer_i].append( | |
| block_str % (r"\\".join(level_str[back_outer_i+1]))) | |
| if len(level_str[back_outer_i+1]) == 1: | |
| level_str[back_outer_i][-1] = r"\left[" + \ | |
| level_str[back_outer_i][-1] + r"\right]" | |
| even = not even | |
| level_str[back_outer_i+1] = [] | |
| out_str = level_str[0][0] | |
| if expr.rank() % 2 == 1: | |
| out_str = block_str % out_str | |
| return out_str | |
| def _printer_tensor_indices(self, name, indices, index_map: dict): | |
| out_str = self._print(name) | |
| last_valence = None | |
| prev_map = None | |
| for index in indices: | |
| new_valence = index.is_up | |
| if ((index in index_map) or prev_map) and \ | |
| last_valence == new_valence: | |
| out_str += "," | |
| if last_valence != new_valence: | |
| if last_valence is not None: | |
| out_str += "}" | |
| if index.is_up: | |
| out_str += "{}^{" | |
| else: | |
| out_str += "{}_{" | |
| out_str += self._print(index.args[0]) | |
| if index in index_map: | |
| out_str += "=" | |
| out_str += self._print(index_map[index]) | |
| prev_map = True | |
| else: | |
| prev_map = False | |
| last_valence = new_valence | |
| if last_valence is not None: | |
| out_str += "}" | |
| return out_str | |
| def _print_Tensor(self, expr): | |
| name = expr.args[0].args[0] | |
| indices = expr.get_indices() | |
| return self._printer_tensor_indices(name, indices, {}) | |
| def _print_TensorElement(self, expr): | |
| name = expr.expr.args[0].args[0] | |
| indices = expr.expr.get_indices() | |
| index_map = expr.index_map | |
| return self._printer_tensor_indices(name, indices, index_map) | |
| def _print_TensMul(self, expr): | |
| # prints expressions like "A(a)", "3*A(a)", "(1+x)*A(a)" | |
| sign, args = expr._get_args_for_traditional_printer() | |
| return sign + "".join( | |
| [self.parenthesize(arg, precedence(expr)) for arg in args] | |
| ) | |
| def _print_TensAdd(self, expr): | |
| a = [] | |
| args = expr.args | |
| for x in args: | |
| a.append(self.parenthesize(x, precedence(expr))) | |
| a.sort() | |
| s = ' + '.join(a) | |
| s = s.replace('+ -', '- ') | |
| return s | |
| def _print_TensorIndex(self, expr): | |
| return "{}%s{%s}" % ( | |
| "^" if expr.is_up else "_", | |
| self._print(expr.args[0]) | |
| ) | |
| def _print_PartialDerivative(self, expr): | |
| if len(expr.variables) == 1: | |
| return r"\frac{\partial}{\partial {%s}}{%s}" % ( | |
| self._print(expr.variables[0]), | |
| self.parenthesize(expr.expr, PRECEDENCE["Mul"], False) | |
| ) | |
| else: | |
| return r"\frac{\partial^{%s}}{%s}{%s}" % ( | |
| len(expr.variables), | |
| " ".join([r"\partial {%s}" % self._print(i) for i in expr.variables]), | |
| self.parenthesize(expr.expr, PRECEDENCE["Mul"], False) | |
| ) | |
| def _print_ArraySymbol(self, expr): | |
| return self._print(expr.name) | |
| def _print_ArrayElement(self, expr): | |
| return "{{%s}_{%s}}" % ( | |
| self.parenthesize(expr.name, PRECEDENCE["Func"], True), | |
| ", ".join([f"{self._print(i)}" for i in expr.indices])) | |
| def _print_UniversalSet(self, expr): | |
| return r"\mathbb{U}" | |
| def _print_frac(self, expr, exp=None): | |
| if exp is None: | |
| return r"\operatorname{frac}{\left(%s\right)}" % self._print(expr.args[0]) | |
| else: | |
| return r"\operatorname{frac}{\left(%s\right)}^{%s}" % ( | |
| self._print(expr.args[0]), exp) | |
| def _print_tuple(self, expr): | |
| if self._settings['decimal_separator'] == 'comma': | |
| sep = ";" | |
| elif self._settings['decimal_separator'] == 'period': | |
| sep = "," | |
| else: | |
| raise ValueError('Unknown Decimal Separator') | |
| if len(expr) == 1: | |
| # 1-tuple needs a trailing separator | |
| return self._add_parens_lspace(self._print(expr[0]) + sep) | |
| else: | |
| return self._add_parens_lspace( | |
| (sep + r" \ ").join([self._print(i) for i in expr])) | |
| def _print_TensorProduct(self, expr): | |
| elements = [self._print(a) for a in expr.args] | |
| return r' \otimes '.join(elements) | |
| def _print_WedgeProduct(self, expr): | |
| elements = [self._print(a) for a in expr.args] | |
| return r' \wedge '.join(elements) | |
| def _print_Tuple(self, expr): | |
| return self._print_tuple(expr) | |
| def _print_list(self, expr): | |
| if self._settings['decimal_separator'] == 'comma': | |
| return r"\left[ %s\right]" % \ | |
| r"; \ ".join([self._print(i) for i in expr]) | |
| elif self._settings['decimal_separator'] == 'period': | |
| return r"\left[ %s\right]" % \ | |
| r", \ ".join([self._print(i) for i in expr]) | |
| else: | |
| raise ValueError('Unknown Decimal Separator') | |
| def _print_dict(self, d): | |
| keys = sorted(d.keys(), 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", \ ".join(items) | |
| def _print_Dict(self, expr): | |
| return self._print_dict(expr) | |
| 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_SingularityFunction(self, expr, exp=None): | |
| shift = self._print(expr.args[0] - expr.args[1]) | |
| power = self._print(expr.args[2]) | |
| tex = r"{\left\langle %s \right\rangle}^{%s}" % (shift, power) | |
| if exp is not None: | |
| tex = r"{\left({\langle %s \rangle}^{%s}\right)}^{%s}" % (shift, power, exp) | |
| return tex | |
| def _print_Heaviside(self, expr, exp=None): | |
| pargs = ', '.join(self._print(arg) for arg in expr.pargs) | |
| tex = r"\theta\left(%s\right)" % pargs | |
| 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 is not None: | |
| 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_RandomDomain(self, d): | |
| if hasattr(d, 'as_boolean'): | |
| return '\\text{Domain: }' + self._print(d.as_boolean()) | |
| elif hasattr(d, 'set'): | |
| return ('\\text{Domain: }' + self._print(d.symbols) + ' \\in ' + | |
| self._print(d.set)) | |
| elif hasattr(d, 'symbols'): | |
| return '\\text{Domain on }' + self._print(d.symbols) | |
| else: | |
| return self._print(None) | |
| 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) | |
| if self._settings['decimal_separator'] == 'comma': | |
| items = "; ".join(map(self._print, items)) | |
| elif self._settings['decimal_separator'] == 'period': | |
| items = ", ".join(map(self._print, items)) | |
| else: | |
| raise ValueError('Unknown Decimal Separator') | |
| return r"\left\{%s\right\}" % items | |
| _print_frozenset = _print_set | |
| def _print_Range(self, s): | |
| def _print_symbolic_range(): | |
| # Symbolic Range that cannot be resolved | |
| if s.args[0] == 0: | |
| if s.args[2] == 1: | |
| cont = self._print(s.args[1]) | |
| else: | |
| cont = ", ".join(self._print(arg) for arg in s.args) | |
| else: | |
| if s.args[2] == 1: | |
| cont = ", ".join(self._print(arg) for arg in s.args[:2]) | |
| else: | |
| cont = ", ".join(self._print(arg) for arg in s.args) | |
| return(f"\\text{{Range}}\\left({cont}\\right)") | |
| dots = object() | |
| if s.start.is_infinite and s.stop.is_infinite: | |
| if s.step.is_positive: | |
| printset = dots, -1, 0, 1, dots | |
| else: | |
| printset = dots, 1, 0, -1, dots | |
| elif s.start.is_infinite: | |
| printset = dots, s[-1] - s.step, s[-1] | |
| elif s.stop.is_infinite: | |
| it = iter(s) | |
| printset = next(it), next(it), dots | |
| elif s.is_empty is not None: | |
| if (s.size < 4) == True: | |
| printset = tuple(s) | |
| elif s.is_iterable: | |
| it = iter(s) | |
| printset = next(it), next(it), dots, s[-1] | |
| else: | |
| return _print_symbolic_range() | |
| else: | |
| return _print_symbolic_range() | |
| return (r"\left\{" + | |
| r", ".join(self._print(el) if el is not dots else r'\ldots' for el in printset) + | |
| r"\right\}") | |
| def __print_number_polynomial(self, expr, letter, exp=None): | |
| if len(expr.args) == 2: | |
| if exp is not None: | |
| return r"%s_{%s}^{%s}\left(%s\right)" % (letter, | |
| self._print(expr.args[0]), exp, | |
| self._print(expr.args[1])) | |
| return r"%s_{%s}\left(%s\right)" % (letter, | |
| self._print(expr.args[0]), self._print(expr.args[1])) | |
| tex = r"%s_{%s}" % (letter, self._print(expr.args[0])) | |
| if exp is not None: | |
| tex = r"%s^{%s}" % (tex, exp) | |
| return tex | |
| def _print_bernoulli(self, expr, exp=None): | |
| return self.__print_number_polynomial(expr, "B", exp) | |
| def _print_genocchi(self, expr, exp=None): | |
| return self.__print_number_polynomial(expr, "G", exp) | |
| def _print_bell(self, expr, exp=None): | |
| if len(expr.args) == 3: | |
| tex1 = r"B_{%s, %s}" % (self._print(expr.args[0]), | |
| self._print(expr.args[1])) | |
| tex2 = r"\left(%s\right)" % r", ".join(self._print(el) for | |
| el in expr.args[2]) | |
| if exp is not None: | |
| tex = r"%s^{%s}%s" % (tex1, exp, tex2) | |
| else: | |
| tex = tex1 + tex2 | |
| return tex | |
| return self.__print_number_polynomial(expr, "B", exp) | |
| def _print_fibonacci(self, expr, exp=None): | |
| return self.__print_number_polynomial(expr, "F", exp) | |
| def _print_lucas(self, expr, exp=None): | |
| tex = r"L_{%s}" % self._print(expr.args[0]) | |
| if exp is not None: | |
| tex = r"%s^{%s}" % (tex, exp) | |
| return tex | |
| def _print_tribonacci(self, expr, exp=None): | |
| return self.__print_number_polynomial(expr, "T", exp) | |
| def _print_mobius(self, expr, exp=None): | |
| if exp is None: | |
| return r'\mu\left(%s\right)' % self._print(expr.args[0]) | |
| return r'\mu^{%s}\left(%s\right)' % (exp, self._print(expr.args[0])) | |
| def _print_SeqFormula(self, s): | |
| dots = object() | |
| if len(s.start.free_symbols) > 0 or len(s.stop.free_symbols) > 0: | |
| return r"\left\{%s\right\}_{%s=%s}^{%s}" % ( | |
| self._print(s.formula), | |
| self._print(s.variables[0]), | |
| self._print(s.start), | |
| self._print(s.stop) | |
| ) | |
| if s.start is S.NegativeInfinity: | |
| stop = s.stop | |
| printset = (dots, s.coeff(stop - 3), s.coeff(stop - 2), | |
| s.coeff(stop - 1), s.coeff(stop)) | |
| elif s.stop is S.Infinity or s.length > 4: | |
| printset = s[:4] | |
| printset.append(dots) | |
| else: | |
| printset = tuple(s) | |
| return (r"\left[" + | |
| r", ".join(self._print(el) if el is not dots else r'\ldots' for el in printset) + | |
| r"\right]") | |
| _print_SeqPer = _print_SeqFormula | |
| _print_SeqAdd = _print_SeqFormula | |
| _print_SeqMul = _print_SeqFormula | |
| def _print_Interval(self, i): | |
| if i.start == i.end: | |
| return r"\left\{%s\right\}" % self._print(i.start) | |
| else: | |
| 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_AccumulationBounds(self, i): | |
| return r"\left\langle %s, %s\right\rangle" % \ | |
| (self._print(i.min), self._print(i.max)) | |
| def _print_Union(self, u): | |
| prec = precedence_traditional(u) | |
| args_str = [self.parenthesize(i, prec) for i in u.args] | |
| return r" \cup ".join(args_str) | |
| def _print_Complement(self, u): | |
| prec = precedence_traditional(u) | |
| args_str = [self.parenthesize(i, prec) for i in u.args] | |
| return r" \setminus ".join(args_str) | |
| def _print_Intersection(self, u): | |
| prec = precedence_traditional(u) | |
| args_str = [self.parenthesize(i, prec) for i in u.args] | |
| return r" \cap ".join(args_str) | |
| def _print_SymmetricDifference(self, u): | |
| prec = precedence_traditional(u) | |
| args_str = [self.parenthesize(i, prec) for i in u.args] | |
| return r" \triangle ".join(args_str) | |
| def _print_ProductSet(self, p): | |
| prec = precedence_traditional(p) | |
| if len(p.sets) >= 1 and not has_variety(p.sets): | |
| return self.parenthesize(p.sets[0], prec) + "^{%d}" % len(p.sets) | |
| return r" \times ".join( | |
| self.parenthesize(set, prec) for set in p.sets) | |
| 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_Rationals(self, i): | |
| return r"\mathbb{Q}" | |
| def _print_Reals(self, i): | |
| return r"\mathbb{R}" | |
| def _print_Complexes(self, i): | |
| return r"\mathbb{C}" | |
| def _print_ImageSet(self, s): | |
| expr = s.lamda.expr | |
| sig = s.lamda.signature | |
| xys = ((self._print(x), self._print(y)) for x, y in zip(sig, s.base_sets)) | |
| xinys = r", ".join(r"%s \in %s" % xy for xy in xys) | |
| return r"\left\{%s\; \middle|\; %s\right\}" % (self._print(expr), xinys) | |
| def _print_ConditionSet(self, s): | |
| vars_print = ', '.join([self._print(var) for var in Tuple(s.sym)]) | |
| if s.base_set is S.UniversalSet: | |
| return r"\left\{%s\; \middle|\; %s \right\}" % \ | |
| (vars_print, self._print(s.condition)) | |
| return r"\left\{%s\; \middle|\; %s \in %s \wedge %s \right\}" % ( | |
| vars_print, | |
| vars_print, | |
| self._print(s.base_set), | |
| self._print(s.condition)) | |
| def _print_PowerSet(self, expr): | |
| arg_print = self._print(expr.args[0]) | |
| return r"\mathcal{{P}}\left({}\right)".format(arg_print) | |
| def _print_ComplexRegion(self, s): | |
| vars_print = ', '.join([self._print(var) for var in s.variables]) | |
| return r"\left\{%s\; \middle|\; %s \in %s \right\}" % ( | |
| self._print(s.expr), | |
| vars_print, | |
| self._print(s.sets)) | |
| def _print_Contains(self, e): | |
| return r"%s \in %s" % tuple(self._print(a) for a in e.args) | |
| def _print_FourierSeries(self, s): | |
| if s.an.formula is S.Zero and s.bn.formula is S.Zero: | |
| return self._print(s.a0) | |
| return self._print_Add(s.truncate()) + r' + \ldots' | |
| def _print_FormalPowerSeries(self, s): | |
| return self._print_Add(s.infinite) | |
| def _print_FiniteField(self, expr): | |
| return r"\mathbb{F}_{%s}" % expr.mod | |
| 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_PolynomialRingBase(self, expr): | |
| domain = self._print(expr.domain) | |
| symbols = ", ".join(map(self._print, expr.symbols)) | |
| inv = "" | |
| if not expr.is_Poly: | |
| inv = r"S_<^{-1}" | |
| return r"%s%s\left[%s\right]" % (inv, domain, symbols) | |
| def _print_Poly(self, poly): | |
| cls = poly.__class__.__name__ | |
| terms = [] | |
| for monom, coeff in poly.terms(): | |
| s_monom = '' | |
| for i, exp in enumerate(monom): | |
| if exp > 0: | |
| if exp == 1: | |
| s_monom += self._print(poly.gens[i]) | |
| else: | |
| s_monom += self._print(pow(poly.gens[i], exp)) | |
| if coeff.is_Add: | |
| if s_monom: | |
| s_coeff = r"\left(%s\right)" % self._print(coeff) | |
| else: | |
| s_coeff = self._print(coeff) | |
| else: | |
| if s_monom: | |
| if coeff is S.One: | |
| terms.extend(['+', s_monom]) | |
| continue | |
| if coeff is S.NegativeOne: | |
| terms.extend(['-', s_monom]) | |
| continue | |
| s_coeff = self._print(coeff) | |
| if not s_monom: | |
| s_term = s_coeff | |
| else: | |
| s_term = s_coeff + " " + s_monom | |
| if s_term.startswith('-'): | |
| terms.extend(['-', s_term[1:]]) | |
| else: | |
| terms.extend(['+', s_term]) | |
| if terms[0] in ('-', '+'): | |
| modifier = terms.pop(0) | |
| if modifier == '-': | |
| terms[0] = '-' + terms[0] | |
| expr = ' '.join(terms) | |
| gens = list(map(self._print, poly.gens)) | |
| domain = "domain=%s" % self._print(poly.get_domain()) | |
| args = ", ".join([expr] + gens + [domain]) | |
| if cls in accepted_latex_functions: | |
| tex = r"\%s {\left(%s \right)}" % (cls, args) | |
| else: | |
| tex = r"\operatorname{%s}{\left( %s \right)}" % (cls, args) | |
| return tex | |
| def _print_ComplexRootOf(self, root): | |
| cls = root.__class__.__name__ | |
| if cls == "ComplexRootOf": | |
| cls = "CRootOf" | |
| expr = self._print(root.expr) | |
| index = root.index | |
| if cls in accepted_latex_functions: | |
| return r"\%s {\left(%s, %d\right)}" % (cls, expr, index) | |
| else: | |
| return r"\operatorname{%s} {\left(%s, %d\right)}" % (cls, expr, | |
| index) | |
| def _print_RootSum(self, expr): | |
| cls = expr.__class__.__name__ | |
| args = [self._print(expr.expr)] | |
| if expr.fun is not S.IdentityFunction: | |
| args.append(self._print(expr.fun)) | |
| if cls in accepted_latex_functions: | |
| return r"\%s {\left(%s\right)}" % (cls, ", ".join(args)) | |
| else: | |
| return r"\operatorname{%s} {\left(%s\right)}" % (cls, | |
| ", ".join(args)) | |
| def _print_OrdinalOmega(self, expr): | |
| return r"\omega" | |
| def _print_OmegaPower(self, expr): | |
| exp, mul = expr.args | |
| if mul != 1: | |
| if exp != 1: | |
| return r"{} \omega^{{{}}}".format(mul, exp) | |
| else: | |
| return r"{} \omega".format(mul) | |
| else: | |
| if exp != 1: | |
| return r"\omega^{{{}}}".format(exp) | |
| else: | |
| return r"\omega" | |
| def _print_Ordinal(self, expr): | |
| return " + ".join([self._print(arg) for arg in expr.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, exp=None): | |
| m, x = (expr.args[0], None) if len(expr.args) == 1 else expr.args | |
| tex = r"E_{%s}" % self._print(m) | |
| if exp is not None: | |
| tex = r"%s^{%s}" % (tex, exp) | |
| if x is not None: | |
| tex = r"%s\left(%s\right)" % (tex, self._print(x)) | |
| return tex | |
| def _print_catalan(self, expr, exp=None): | |
| tex = r"C_{%s}" % self._print(expr.args[0]) | |
| if exp is not None: | |
| tex = r"%s^{%s}" % (tex, exp) | |
| return tex | |
| def _print_UnifiedTransform(self, expr, s, inverse=False): | |
| return r"\mathcal{{{}}}{}_{{{}}}\left[{}\right]\left({}\right)".format(s, '^{-1}' if inverse else '', self._print(expr.args[1]), self._print(expr.args[0]), self._print(expr.args[2])) | |
| def _print_MellinTransform(self, expr): | |
| return self._print_UnifiedTransform(expr, 'M') | |
| def _print_InverseMellinTransform(self, expr): | |
| return self._print_UnifiedTransform(expr, 'M', True) | |
| def _print_LaplaceTransform(self, expr): | |
| return self._print_UnifiedTransform(expr, 'L') | |
| def _print_InverseLaplaceTransform(self, expr): | |
| return self._print_UnifiedTransform(expr, 'L', True) | |
| def _print_FourierTransform(self, expr): | |
| return self._print_UnifiedTransform(expr, 'F') | |
| def _print_InverseFourierTransform(self, expr): | |
| return self._print_UnifiedTransform(expr, 'F', True) | |
| def _print_SineTransform(self, expr): | |
| return self._print_UnifiedTransform(expr, 'SIN') | |
| def _print_InverseSineTransform(self, expr): | |
| return self._print_UnifiedTransform(expr, 'SIN', True) | |
| def _print_CosineTransform(self, expr): | |
| return self._print_UnifiedTransform(expr, 'COS') | |
| def _print_InverseCosineTransform(self, expr): | |
| return self._print_UnifiedTransform(expr, 'COS', True) | |
| def _print_DMP(self, p): | |
| try: | |
| if p.ring is not None: | |
| # TODO incorporate order | |
| return self._print(p.ring.to_sympy(p)) | |
| except SympifyError: | |
| pass | |
| return self._print(repr(p)) | |
| def _print_DMF(self, p): | |
| return self._print_DMP(p) | |
| def _print_Object(self, object): | |
| return self._print(Symbol(object.name)) | |
| def _print_LambertW(self, expr, exp=None): | |
| arg0 = self._print(expr.args[0]) | |
| exp = r"^{%s}" % (exp,) if exp is not None else "" | |
| if len(expr.args) == 1: | |
| result = r"W%s\left(%s\right)" % (exp, arg0) | |
| else: | |
| arg1 = self._print(expr.args[1]) | |
| result = "W{0}_{{{1}}}\\left({2}\\right)".format(exp, arg1, arg0) | |
| return result | |
| def _print_Expectation(self, expr): | |
| return r"\operatorname{{E}}\left[{}\right]".format(self._print(expr.args[0])) | |
| def _print_Variance(self, expr): | |
| return r"\operatorname{{Var}}\left({}\right)".format(self._print(expr.args[0])) | |
| def _print_Covariance(self, expr): | |
| return r"\operatorname{{Cov}}\left({}\right)".format(", ".join(self._print(arg) for arg in expr.args)) | |
| def _print_Probability(self, expr): | |
| return r"\operatorname{{P}}\left({}\right)".format(self._print(expr.args[0])) | |
| def _print_Morphism(self, morphism): | |
| domain = self._print(morphism.domain) | |
| codomain = self._print(morphism.codomain) | |
| return "%s\\rightarrow %s" % (domain, codomain) | |
| def _print_TransferFunction(self, expr): | |
| num, den = self._print(expr.num), self._print(expr.den) | |
| return r"\frac{%s}{%s}" % (num, den) | |
| def _print_Series(self, expr): | |
| args = list(expr.args) | |
| parens = lambda x: self.parenthesize(x, precedence_traditional(expr), | |
| False) | |
| return ' '.join(map(parens, args)) | |
| def _print_MIMOSeries(self, expr): | |
| from sympy.physics.control.lti import MIMOParallel | |
| args = list(expr.args)[::-1] | |
| parens = lambda x: self.parenthesize(x, precedence_traditional(expr), | |
| False) if isinstance(x, MIMOParallel) else self._print(x) | |
| return r"\cdot".join(map(parens, args)) | |
| def _print_Parallel(self, expr): | |
| return ' + '.join(map(self._print, expr.args)) | |
| def _print_MIMOParallel(self, expr): | |
| return ' + '.join(map(self._print, expr.args)) | |
| def _print_Feedback(self, expr): | |
| from sympy.physics.control import TransferFunction, Series | |
| num, tf = expr.sys1, TransferFunction(1, 1, expr.var) | |
| num_arg_list = list(num.args) if isinstance(num, Series) else [num] | |
| den_arg_list = list(expr.sys2.args) if \ | |
| isinstance(expr.sys2, Series) else [expr.sys2] | |
| den_term_1 = tf | |
| if isinstance(num, Series) and isinstance(expr.sys2, Series): | |
| den_term_2 = Series(*num_arg_list, *den_arg_list) | |
| elif isinstance(num, Series) and isinstance(expr.sys2, TransferFunction): | |
| if expr.sys2 == tf: | |
| den_term_2 = Series(*num_arg_list) | |
| else: | |
| den_term_2 = tf, Series(*num_arg_list, expr.sys2) | |
| elif isinstance(num, TransferFunction) and isinstance(expr.sys2, Series): | |
| if num == tf: | |
| den_term_2 = Series(*den_arg_list) | |
| else: | |
| den_term_2 = Series(num, *den_arg_list) | |
| else: | |
| if num == tf: | |
| den_term_2 = Series(*den_arg_list) | |
| elif expr.sys2 == tf: | |
| den_term_2 = Series(*num_arg_list) | |
| else: | |
| den_term_2 = Series(*num_arg_list, *den_arg_list) | |
| numer = self._print(num) | |
| denom_1 = self._print(den_term_1) | |
| denom_2 = self._print(den_term_2) | |
| _sign = "+" if expr.sign == -1 else "-" | |
| return r"\frac{%s}{%s %s %s}" % (numer, denom_1, _sign, denom_2) | |
| def _print_MIMOFeedback(self, expr): | |
| from sympy.physics.control import MIMOSeries | |
| inv_mat = self._print(MIMOSeries(expr.sys2, expr.sys1)) | |
| sys1 = self._print(expr.sys1) | |
| _sign = "+" if expr.sign == -1 else "-" | |
| return r"\left(I_{\tau} %s %s\right)^{-1} \cdot %s" % (_sign, inv_mat, sys1) | |
| def _print_TransferFunctionMatrix(self, expr): | |
| mat = self._print(expr._expr_mat) | |
| return r"%s_\tau" % mat | |
| def _print_DFT(self, expr): | |
| return r"\text{{{}}}_{{{}}}".format(expr.__class__.__name__, expr.n) | |
| _print_IDFT = _print_DFT | |
| def _print_NamedMorphism(self, morphism): | |
| pretty_name = self._print(Symbol(morphism.name)) | |
| pretty_morphism = self._print_Morphism(morphism) | |
| return "%s:%s" % (pretty_name, pretty_morphism) | |
| def _print_IdentityMorphism(self, morphism): | |
| from sympy.categories import NamedMorphism | |
| return self._print_NamedMorphism(NamedMorphism( | |
| morphism.domain, morphism.codomain, "id")) | |
| def _print_CompositeMorphism(self, morphism): | |
| # All components of the morphism have names and it is thus | |
| # possible to build the name of the composite. | |
| component_names_list = [self._print(Symbol(component.name)) for | |
| component in morphism.components] | |
| component_names_list.reverse() | |
| component_names = "\\circ ".join(component_names_list) + ":" | |
| pretty_morphism = self._print_Morphism(morphism) | |
| return component_names + pretty_morphism | |
| def _print_Category(self, morphism): | |
| return r"\mathbf{{{}}}".format(self._print(Symbol(morphism.name))) | |
| def _print_Diagram(self, diagram): | |
| if not diagram.premises: | |
| # This is an empty diagram. | |
| return self._print(S.EmptySet) | |
| latex_result = self._print(diagram.premises) | |
| if diagram.conclusions: | |
| latex_result += "\\Longrightarrow %s" % \ | |
| self._print(diagram.conclusions) | |
| return latex_result | |
| def _print_DiagramGrid(self, grid): | |
| latex_result = "\\begin{array}{%s}\n" % ("c" * grid.width) | |
| for i in range(grid.height): | |
| for j in range(grid.width): | |
| if grid[i, j]: | |
| latex_result += latex(grid[i, j]) | |
| latex_result += " " | |
| if j != grid.width - 1: | |
| latex_result += "& " | |
| if i != grid.height - 1: | |
| latex_result += "\\\\" | |
| latex_result += "\n" | |
| latex_result += "\\end{array}\n" | |
| return latex_result | |
| def _print_FreeModule(self, M): | |
| return '{{{}}}^{{{}}}'.format(self._print(M.ring), self._print(M.rank)) | |
| def _print_FreeModuleElement(self, m): | |
| # Print as row vector for convenience, for now. | |
| return r"\left[ {} \right]".format(",".join( | |
| '{' + self._print(x) + '}' for x in m)) | |
| def _print_SubModule(self, m): | |
| gens = [[self._print(m.ring.to_sympy(x)) for x in g] for g in m.gens] | |
| curly = lambda o: r"{" + o + r"}" | |
| square = lambda o: r"\left[ " + o + r" \right]" | |
| gens_latex = ",".join(curly(square(",".join(curly(x) for x in g))) for g in gens) | |
| return r"\left\langle {} \right\rangle".format(gens_latex) | |
| def _print_SubQuotientModule(self, m): | |
| gens_latex = ",".join(["{" + self._print(g) + "}" for g in m.gens]) | |
| return r"\left\langle {} \right\rangle".format(gens_latex) | |
| def _print_ModuleImplementedIdeal(self, m): | |
| gens = [m.ring.to_sympy(x) for [x] in m._module.gens] | |
| gens_latex = ",".join('{' + self._print(x) + '}' for x in gens) | |
| return r"\left\langle {} \right\rangle".format(gens_latex) | |
| def _print_Quaternion(self, expr): | |
| # TODO: This expression is potentially confusing, | |
| # shall we print it as `Quaternion( ... )`? | |
| s = [self.parenthesize(i, PRECEDENCE["Mul"], strict=True) | |
| for i in expr.args] | |
| a = [s[0]] + [i+" "+j for i, j in zip(s[1:], "ijk")] | |
| return " + ".join(a) | |
| def _print_QuotientRing(self, R): | |
| # TODO nicer fractions for few generators... | |
| return r"\frac{{{}}}{{{}}}".format(self._print(R.ring), | |
| self._print(R.base_ideal)) | |
| def _print_QuotientRingElement(self, x): | |
| x_latex = self._print(x.ring.to_sympy(x)) | |
| return r"{{{}}} + {{{}}}".format(x_latex, | |
| self._print(x.ring.base_ideal)) | |
| def _print_QuotientModuleElement(self, m): | |
| data = [m.module.ring.to_sympy(x) for x in m.data] | |
| data_latex = r"\left[ {} \right]".format(",".join( | |
| '{' + self._print(x) + '}' for x in data)) | |
| return r"{{{}}} + {{{}}}".format(data_latex, | |
| self._print(m.module.killed_module)) | |
| def _print_QuotientModule(self, M): | |
| # TODO nicer fractions for few generators... | |
| return r"\frac{{{}}}{{{}}}".format(self._print(M.base), | |
| self._print(M.killed_module)) | |
| def _print_MatrixHomomorphism(self, h): | |
| return r"{{{}}} : {{{}}} \to {{{}}}".format(self._print(h._sympy_matrix()), | |
| self._print(h.domain), self._print(h.codomain)) | |
| def _print_Manifold(self, manifold): | |
| name, supers, subs = self._split_super_sub(manifold.name.name) | |
| name = r'\text{%s}' % name | |
| if supers: | |
| name += "^{%s}" % " ".join(supers) | |
| if subs: | |
| name += "_{%s}" % " ".join(subs) | |
| return name | |
| def _print_Patch(self, patch): | |
| return r'\text{%s}_{%s}' % (self._print(patch.name), self._print(patch.manifold)) | |
| def _print_CoordSystem(self, coordsys): | |
| return r'\text{%s}^{\text{%s}}_{%s}' % ( | |
| self._print(coordsys.name), self._print(coordsys.patch.name), self._print(coordsys.manifold) | |
| ) | |
| def _print_CovarDerivativeOp(self, cvd): | |
| return r'\mathbb{\nabla}_{%s}' % self._print(cvd._wrt) | |
| def _print_BaseScalarField(self, field): | |
| string = field._coord_sys.symbols[field._index].name | |
| return r'\mathbf{{{}}}'.format(self._print(Symbol(string))) | |
| def _print_BaseVectorField(self, field): | |
| string = field._coord_sys.symbols[field._index].name | |
| return r'\partial_{{{}}}'.format(self._print(Symbol(string))) | |
| def _print_Differential(self, diff): | |
| field = diff._form_field | |
| if hasattr(field, '_coord_sys'): | |
| string = field._coord_sys.symbols[field._index].name | |
| return r'\operatorname{{d}}{}'.format(self._print(Symbol(string))) | |
| else: | |
| string = self._print(field) | |
| return r'\operatorname{{d}}\left({}\right)'.format(string) | |
| def _print_Tr(self, p): | |
| # TODO: Handle indices | |
| contents = self._print(p.args[0]) | |
| return r'\operatorname{{tr}}\left({}\right)'.format(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]), exp) | |
| return r'\phi\left(%s\right)' % self._print(expr.args[0]) | |
| def _print_reduced_totient(self, expr, exp=None): | |
| if exp is not None: | |
| return r'\left(\lambda\left(%s\right)\right)^{%s}' % \ | |
| (self._print(expr.args[0]), exp) | |
| return r'\lambda\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" % (exp, tex) | |
| return r"\sigma%s" % tex | |
| def _print_udivisor_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" % (exp, tex) | |
| return r"\sigma^*%s" % tex | |
| def _print_primenu(self, expr, exp=None): | |
| if exp is not None: | |
| return r'\left(\nu\left(%s\right)\right)^{%s}' % \ | |
| (self._print(expr.args[0]), exp) | |
| return r'\nu\left(%s\right)' % self._print(expr.args[0]) | |
| def _print_primeomega(self, expr, exp=None): | |
| if exp is not None: | |
| return r'\left(\Omega\left(%s\right)\right)^{%s}' % \ | |
| (self._print(expr.args[0]), exp) | |
| return r'\Omega\left(%s\right)' % self._print(expr.args[0]) | |
| def _print_Str(self, s): | |
| return str(s.name) | |
| def _print_float(self, expr): | |
| return self._print(Float(expr)) | |
| def _print_int(self, expr): | |
| return str(expr) | |
| def _print_mpz(self, expr): | |
| return str(expr) | |
| def _print_mpq(self, expr): | |
| return str(expr) | |
| def _print_fmpz(self, expr): | |
| return str(expr) | |
| def _print_fmpq(self, expr): | |
| return str(expr) | |
| def _print_Predicate(self, expr): | |
| return r"\operatorname{{Q}}_{{\text{{{}}}}}".format(latex_escape(str(expr.name))) | |
| def _print_AppliedPredicate(self, expr): | |
| pred = expr.function | |
| args = expr.arguments | |
| pred_latex = self._print(pred) | |
| args_latex = ', '.join([self._print(a) for a in args]) | |
| return '%s(%s)' % (pred_latex, args_latex) | |
| def emptyPrinter(self, expr): | |
| # default to just printing as monospace, like would normally be shown | |
| s = super().emptyPrinter(expr) | |
| return r"\mathtt{\text{%s}}" % latex_escape(s) | |
| def translate(s: str) -> str: | |
| 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. | |
| >>> from sympy.printing.latex import translate | |
| >>> 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: | |
| return "\\" + s.lower() | |
| elif s in other_symbols: | |
| return "\\" + s | |
| else: | |
| # Process modifiers, if any, and recurse | |
| for key in sorted(modifier_dict.keys(), key=len, reverse=True): | |
| if s.lower().endswith(key) and len(s) > len(key): | |
| return modifier_dict[key](translate(s[:-len(key)])) | |
| return s | |
| def latex(expr, **settings): | |
| r"""Convert the given expression to LaTeX string representation. | |
| Parameters | |
| ========== | |
| full_prec: boolean, optional | |
| If set to True, a floating point number is printed with full precision. | |
| fold_frac_powers : boolean, optional | |
| Emit ``^{p/q}`` instead of ``^{\frac{p}{q}}`` for fractional powers. | |
| fold_func_brackets : boolean, optional | |
| Fold function brackets where applicable. | |
| fold_short_frac : boolean, optional | |
| 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. | |
| inv_trig_style : string, optional | |
| How inverse trig functions should be displayed. Can be one of | |
| ``'abbreviated'``, ``'full'``, or ``'power'``. Defaults to | |
| ``'abbreviated'``. | |
| itex : boolean, optional | |
| Specifies if itex-specific syntax is used, including emitting | |
| ``$$...$$``. | |
| ln_notation : boolean, optional | |
| If set to ``True``, ``\ln`` is used instead of default ``\log``. | |
| long_frac_ratio : float or None, optional | |
| The allowed ratio of the width of the numerator to the width of the | |
| denominator before the printer breaks off long fractions. If ``None`` | |
| (the default value), long fractions are not broken up. | |
| mat_delim : string, optional | |
| The delimiter to wrap around matrices. Can be one of ``'['``, ``'('``, | |
| or the empty string ``''``. Defaults to ``'['``. | |
| mat_str : string, optional | |
| 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. | |
| mode: string, optional | |
| 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. | |
| mul_symbol : string or None, optional | |
| The symbol to use for multiplication. Can be one of ``None``, | |
| ``'ldot'``, ``'dot'``, or ``'times'``. | |
| order: string, optional | |
| Any of the supported monomial orderings (currently ``'lex'``, | |
| ``'grlex'``, or ``'grevlex'``), ``'old'``, and ``'none'``. This | |
| parameter does nothing for `~.Mul` objects. Setting order to ``'old'`` | |
| uses the compatibility ordering for ``~.Add`` defined in Printer. For | |
| very large expressions, set the ``order`` keyword to ``'none'`` if | |
| speed is a concern. | |
| symbol_names : dictionary of strings mapped to symbols, optional | |
| Dictionary of symbols and the custom strings they should be emitted as. | |
| root_notation : boolean, optional | |
| If set to ``False``, exponents of the form 1/n are printed in fractonal | |
| form. Default is ``True``, to print exponent in root form. | |
| mat_symbol_style : string, optional | |
| Can be either ``'plain'`` (default) or ``'bold'``. If set to | |
| ``'bold'``, a `~.MatrixSymbol` A will be printed as ``\mathbf{A}``, | |
| otherwise as ``A``. | |
| imaginary_unit : string, optional | |
| String to use for the imaginary unit. Defined options are ``'i'`` | |
| (default) and ``'j'``. Adding ``r`` or ``t`` in front gives ``\mathrm`` | |
| or ``\text``, so ``'ri'`` leads to ``\mathrm{i}`` which gives | |
| `\mathrm{i}`. | |
| gothic_re_im : boolean, optional | |
| If set to ``True``, `\Re` and `\Im` is used for ``re`` and ``im``, respectively. | |
| The default is ``False`` leading to `\operatorname{re}` and `\operatorname{im}`. | |
| decimal_separator : string, optional | |
| Specifies what separator to use to separate the whole and fractional parts of a | |
| floating point number as in `2.5` for the default, ``period`` or `2{,}5` | |
| when ``comma`` is specified. Lists, sets, and tuple are printed with semicolon | |
| separating the elements when ``comma`` is chosen. For example, [1; 2; 3] when | |
| ``comma`` is chosen and [1,2,3] for when ``period`` is chosen. | |
| parenthesize_super : boolean, optional | |
| If set to ``False``, superscripted expressions will not be parenthesized when | |
| powered. Default is ``True``, which parenthesizes the expression when powered. | |
| min: Integer or None, optional | |
| Sets the lower bound for the exponent to print floating point numbers in | |
| fixed-point format. | |
| max: Integer or None, optional | |
| Sets the upper bound for the exponent to print floating point numbers in | |
| fixed-point format. | |
| diff_operator: string, optional | |
| String to use for differential operator. Default is ``'d'``, to print in italic | |
| form. ``'rd'``, ``'td'`` are shortcuts for ``\mathrm{d}`` and ``\text{d}``. | |
| adjoint_style: string, optional | |
| String to use for the adjoint symbol. Defined options are ``'dagger'`` | |
| (default),``'star'``, and ``'hermitian'``. | |
| Notes | |
| ===== | |
| Not using a print statement for printing, results in double backslashes for | |
| latex commands since that's the way Python escapes backslashes in strings. | |
| >>> from sympy import latex, Rational | |
| >>> from sympy.abc import tau | |
| >>> latex((2*tau)**Rational(7,2)) | |
| '8 \\sqrt{2} \\tau^{\\frac{7}{2}}' | |
| >>> print(latex((2*tau)**Rational(7,2))) | |
| 8 \sqrt{2} \tau^{\frac{7}{2}} | |
| Examples | |
| ======== | |
| >>> from sympy import latex, pi, sin, asin, Integral, Matrix, Rational, log | |
| >>> from sympy.abc import x, y, mu, r, tau | |
| Basic usage: | |
| >>> print(latex((2*tau)**Rational(7,2))) | |
| 8 \sqrt{2} \tau^{\frac{7}{2}} | |
| ``mode`` and ``itex`` options: | |
| >>> 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} | |
| >>> print(latex((2*mu)**Rational(7,2), mode='equation', itex=True)) | |
| $$8 \sqrt{2} \mu^{\frac{7}{2}}$$ | |
| >>> 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} | |
| >>> print(latex((2*mu)**Rational(7,2), mode='equation', itex=True)) | |
| $$8 \sqrt{2} \mu^{\frac{7}{2}}$$ | |
| Fraction options: | |
| >>> print(latex((2*tau)**Rational(7,2), fold_frac_powers=True)) | |
| 8 \sqrt{2} \tau^{7/2} | |
| >>> 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}}} | |
| >>> 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 | |
| >>> 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 | |
| Multiplication options: | |
| >>> print(latex((2*tau)**sin(Rational(7,2)), mul_symbol="times")) | |
| \left(2 \times \tau\right)^{\sin{\left(\frac{7}{2} \right)}} | |
| Trig options: | |
| >>> 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)} | |
| Matrix options: | |
| >>> 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] | |
| >>> print(latex(Matrix(2, 1, [x, y]), mat_delim="(")) | |
| \left(\begin{matrix}x\\y\end{matrix}\right) | |
| Custom printing of symbols: | |
| >>> print(latex(x**2, symbol_names={x: 'x_i'})) | |
| x_i^{2} | |
| Logarithms: | |
| >>> print(latex(log(10))) | |
| \log{\left(10 \right)} | |
| >>> print(latex(log(10), ln_notation=True)) | |
| \ln{\left(10 \right)} | |
| ``latex()`` also supports the builtin container types :class:`list`, | |
| :class:`tuple`, and :class:`dict`: | |
| >>> print(latex([2/x, y], mode='inline')) | |
| $\left[ 2 / x, \ y\right]$ | |
| Unsupported types are rendered as monospaced plaintext: | |
| >>> print(latex(int)) | |
| \mathtt{\text{<class 'int'>}} | |
| >>> print(latex("plain % text")) | |
| \mathtt{\text{plain \% text}} | |
| See :ref:`printer_method_example` for an example of how to override | |
| this behavior for your own types by implementing ``_latex``. | |
| .. versionchanged:: 1.7.0 | |
| Unsupported types no longer have their ``str`` representation treated as valid latex. | |
| """ | |
| return LatexPrinter(settings).doprint(expr) | |
| def print_latex(expr, **settings): | |
| """Prints LaTeX representation of the given expression. Takes the same | |
| settings as ``latex()``.""" | |
| print(latex(expr, **settings)) | |
| def multiline_latex(lhs, rhs, terms_per_line=1, environment="align*", use_dots=False, **settings): | |
| r""" | |
| This function generates a LaTeX equation with a multiline right-hand side | |
| in an ``align*``, ``eqnarray`` or ``IEEEeqnarray`` environment. | |
| Parameters | |
| ========== | |
| lhs : Expr | |
| Left-hand side of equation | |
| rhs : Expr | |
| Right-hand side of equation | |
| terms_per_line : integer, optional | |
| Number of terms per line to print. Default is 1. | |
| environment : "string", optional | |
| Which LaTeX wnvironment to use for the output. Options are "align*" | |
| (default), "eqnarray", and "IEEEeqnarray". | |
| use_dots : boolean, optional | |
| If ``True``, ``\\dots`` is added to the end of each line. Default is ``False``. | |
| Examples | |
| ======== | |
| >>> from sympy import multiline_latex, symbols, sin, cos, exp, log, I | |
| >>> x, y, alpha = symbols('x y alpha') | |
| >>> expr = sin(alpha*y) + exp(I*alpha) - cos(log(y)) | |
| >>> print(multiline_latex(x, expr)) | |
| \begin{align*} | |
| x = & e^{i \alpha} \\ | |
| & + \sin{\left(\alpha y \right)} \\ | |
| & - \cos{\left(\log{\left(y \right)} \right)} | |
| \end{align*} | |
| Using at most two terms per line: | |
| >>> print(multiline_latex(x, expr, 2)) | |
| \begin{align*} | |
| x = & e^{i \alpha} + \sin{\left(\alpha y \right)} \\ | |
| & - \cos{\left(\log{\left(y \right)} \right)} | |
| \end{align*} | |
| Using ``eqnarray`` and dots: | |
| >>> print(multiline_latex(x, expr, terms_per_line=2, environment="eqnarray", use_dots=True)) | |
| \begin{eqnarray} | |
| x & = & e^{i \alpha} + \sin{\left(\alpha y \right)} \dots\nonumber\\ | |
| & & - \cos{\left(\log{\left(y \right)} \right)} | |
| \end{eqnarray} | |
| Using ``IEEEeqnarray``: | |
| >>> print(multiline_latex(x, expr, environment="IEEEeqnarray")) | |
| \begin{IEEEeqnarray}{rCl} | |
| x & = & e^{i \alpha} \nonumber\\ | |
| & & + \sin{\left(\alpha y \right)} \nonumber\\ | |
| & & - \cos{\left(\log{\left(y \right)} \right)} | |
| \end{IEEEeqnarray} | |
| Notes | |
| ===== | |
| All optional parameters from ``latex`` can also be used. | |
| """ | |
| # Based on code from https://github.com/sympy/sympy/issues/3001 | |
| l = LatexPrinter(**settings) | |
| if environment == "eqnarray": | |
| result = r'\begin{eqnarray}' + '\n' | |
| first_term = '& = &' | |
| nonumber = r'\nonumber' | |
| end_term = '\n\\end{eqnarray}' | |
| doubleet = True | |
| elif environment == "IEEEeqnarray": | |
| result = r'\begin{IEEEeqnarray}{rCl}' + '\n' | |
| first_term = '& = &' | |
| nonumber = r'\nonumber' | |
| end_term = '\n\\end{IEEEeqnarray}' | |
| doubleet = True | |
| elif environment == "align*": | |
| result = r'\begin{align*}' + '\n' | |
| first_term = '= &' | |
| nonumber = '' | |
| end_term = '\n\\end{align*}' | |
| doubleet = False | |
| else: | |
| raise ValueError("Unknown environment: {}".format(environment)) | |
| dots = '' | |
| if use_dots: | |
| dots=r'\dots' | |
| terms = rhs.as_ordered_terms() | |
| n_terms = len(terms) | |
| term_count = 1 | |
| for i in range(n_terms): | |
| term = terms[i] | |
| term_start = '' | |
| term_end = '' | |
| sign = '+' | |
| if term_count > terms_per_line: | |
| if doubleet: | |
| term_start = '& & ' | |
| else: | |
| term_start = '& ' | |
| term_count = 1 | |
| if term_count == terms_per_line: | |
| # End of line | |
| if i < n_terms-1: | |
| # There are terms remaining | |
| term_end = dots + nonumber + r'\\' + '\n' | |
| else: | |
| term_end = '' | |
| if term.as_ordered_factors()[0] == -1: | |
| term = -1*term | |
| sign = r'-' | |
| if i == 0: # beginning | |
| if sign == '+': | |
| sign = '' | |
| result += r'{:s} {:s}{:s} {:s} {:s}'.format(l.doprint(lhs), | |
| first_term, sign, l.doprint(term), term_end) | |
| else: | |
| result += r'{:s}{:s} {:s} {:s}'.format(term_start, sign, | |
| l.doprint(term), term_end) | |
| term_count += 1 | |
| result += end_term | |
| return result | |
Xet Storage Details
- Size:
- 124 kB
- Xet hash:
- 514682b892a3e79be8cde3fa1cd95a96f60c6ec0d9fc70164c2256860bd67627
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.