DKL9 GitList
Repositories
DKL9 home
rtensor
Code
Commits
Branches
Tags
Search
Tree:
eb004f6
Branches
Tags
master
rtensor
rtensor_to_latex.js
Finish LaTeX converter
dkl9
commited
eb004f6
at 2023-218 12:30:40
rtensor_to_latex.js
Blame
History
Raw
"use strict"; import {AST} from "./maths_ast.js"; import {RTensorRender} from "./rtensor_to_html.js"; const LATEX_SYM = { "del": "\\nabla", "complexes": "\\mathbb{C}", "reals": "\\mathbb{R}", "rationals": "\\mathbb{Q}", "integers": "\\mathbb{Z}", "naturals": "\\mathbb{N}", "infty": "\\infty", "inf": "\\infty", "infinity": "\\infty", "star": "*", }; [ "alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "theta", "iota", "kappa", "lambda", "mu", "nu", "xi", "omicron", "pi", "rho", "sigma", "tau", "upsilon", "phi", "chi", "psi", "omega", ].map(x => [x, x[0].toUpperCase() + x.slice(1)]). forEach(([x, y]) => (LATEX_SYM[x] = "\\" + x) + (LATEX_SYM[y] = "\\" + y)); [ "sin", "cos", "tan", "csc", "sec", "cot", "arcsin", "arccos", "arctan", "exp", "ln", "log", "partial", "pm", ].forEach(x => (LATEX_SYM[x] = "\\" + x)); RTensorRender.toLaTeX = function() { const lp = "\\left("; const rp = "\\right)"; switch (this.ts) { case 1: return this.v.split("_").map(s => LATEX_SYM[s] || s).join("_"); case 2: return `${this.v}`; case 3: const l = this.l.toLaTeX(); const r = this.r.toLaTeX(); const pl = this.l.shouldParenMul() ? `${lp}${l}${rp}` : l; const pr = this.r.shouldParenMul() ? `${lp}${r}${rp}` : r; switch (this.m) { case 0: if ((this.r.ts == 7 || this.r.ts == 8) && this.r.l.v == "pm") { return `${l} ${r}`; } return `${l} + ${r}`; case 1: return `${l} - ${r}`; case 2: const dot = this.l.ts == 2 && this.r.ts == 2; return `${pl}${dot ? " \\cdot " : ""}${pr}`; case 3: return `\\frac{${l}}{${r}}`; case 4: const spe = this.l.shouldParenExp(); return `${spe ? lp : ""}${l}${spe ? rp : ""}^{${r}}`; case 5: return `\\log_{${l}}{${pr}}`; case 6: case 11: return `${l} = ${r}`; case 7: return `\\sqrt[${l}]{${r}}`; // TODO: comma operator is confusing case 8: return `${l}, ${r}`; case 9: return `${l} < ${r}`; case 10: return `${l} \\mapsto ${r}`; default: return `${pl} ? ${pr}`; } break; case 4: return this.l ? `${this.m.toLaTeX()} = ${this.r.toLaTeX()}` : this.m.toLaTeX(); case 5: const m = this.m.toLaTeX(); const pm = this.m.shouldParenMul() ? `${lp}${m}${rp}` : m; switch (this.l) { case 0: return `+${pm}`; case 1: return `-${pm}`; case 3: return `\\frac{1}{${m}}`; case 4: return `e^{${m}}`; case 5: return `\\ln{${pm}}`; case 6: return `${m} = 0`; case 7: return `\\sqrt{${m}}`; case 9: return `${m} < 0`; default: return `? ${pm}`; } case 6: return `${this.l.toLaTeX()}[${this.m.toLaTeX()}]`; case 7: case 8: const fa = this.m[0] ? this.m[0].toLaTeX() : "?"; const sa = this.m[1] ? this.m[1].toLaTeX() : "?"; const ta = this.m[2] ? this.m[2].toLaTeX() : "?"; const al = this.m.map(x => x.toLaTeX()); let ls = null; // special functions if (this.l.ts == 1) { switch (this.l.v) { case "abs": return `\\left|${fa}\\right|`; case "all": ls = "\\wedge"; case "any": return `${al.map(x => lp + x + rp).join(` ${ls || "\\vee"} `)}` case "approx": return `${fa} \\approx ${sa}`; case "at": return `${lp}${fa}\\right|_{${sa}}^{${this.m[2] ? ta : ""}}`; case "brace": return `\\left{${fa}\\right}`; case "bracket": return `\\left[${fa}\\right]`; case "ceil": return `\\lceil ${fa} \\rceil`; case "cross": return `${fa} \\times ${sa}`; case "dot": return `${fa} \\cdot ${sa}`; case "fact": return this.m[0].shouldParenMul() ? `${lp}${fa}${rp}!` : `${fa}!`; case "filter": return `\\left{x \\in ${fa} | ${sa}(x)\\right}`; case "floor": return `\\lfloor ${fa} \\rfloor`; case "hat": return `\\hat{${fa}}`; case "if": return `\\begin{cases}${sa} & \\text{if } ${fa} \\\\ ${ta} & \\text{otherwise}\\end{cases}`; case "in": return `${fa} \\in ${sa}`; case "int": return this.m[1] ? `\\int_{${fa}}^{${sa}}{${ta}}` : `\\int{${fa}}`; case "intersection": return `${fa} \\cap ${sa}`; case "lim": // you'll want one of // \newcommand{\Lim}[3]{\mathop{\displaystyle\vcenter{\hbox{\huge$\Lambda$}}}\limits_{#1}^{#2}{#3}} // \newcommand{\Lim}[3]{\lim_{#1 \rightarrow #2}{#3}} return `\\Lim{${fa}}{${sa}}{${ta}}`; case "map": return `\\left[${sa}(x) | x \\in ${fa}\\right]`; case "matrix": const rc = parseInt(this.m[0]?.v || "2") || 2; const cc = parseInt(this.m[1]?.v || "2") || 2; return `\\begin{pmatrix}\n${(new Array(rc)).fill(0).map((_x, i) => this.m.slice(2 + i * cc, 2 + (i + 1) * cc).map(el => el.toLaTeX()).join(" & ")).join(" \\\\\n")}\n\\end{pmatrix}`; case "paren": return `${lp}${fa}${rp}`; case "pm": return `\\pm ${this.m[0].shouldParenMul() ? lp + fa + rp : fa}`; case "product": return `\\prod_{${fa}}^{${sa}}{${ta}}`; case "sum": return `\\sum_{${fa}}^{${sa}}{${ta}}`; case "union": return `${fa} \\cup ${sa}`; case "vec": return `\\vec{${fa}}`; } } // anything else return `${this.l.toLaTeX()}(${al.join(", ")})`; default: return "?"; } };