dkl9 commited on 2023-218 12:30:40
Showing 1 changed files, with 21 additions and 203 deletions.
| ... | ... |
@@ -10,6 +10,10 @@ const LATEX_SYM = {
|
| 10 | 10 |
"rationals": "\\mathbb{Q}",
|
| 11 | 11 |
"integers": "\\mathbb{Z}",
|
| 12 | 12 |
"naturals": "\\mathbb{N}",
|
| 13 |
+ "infty": "\\infty", |
|
| 14 |
+ "inf": "\\infty", |
|
| 15 |
+ "infinity": "\\infty", |
|
| 16 |
+ "star": "*", |
|
| 13 | 17 |
}; |
| 14 | 18 |
[ |
| 15 | 19 |
"alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "theta", |
| ... | ... |
@@ -134,230 +138,44 @@ RTensorRender.toLaTeX = function() {
|
| 134 | 138 |
return `\\lfloor ${fa} \\rfloor`;
|
| 135 | 139 |
case "hat": |
| 136 | 140 |
return `\\hat{${fa}}`;
|
| 137 |
- // TODO: there's more! |
|
| 138 |
- } |
|
| 139 |
- } |
|
| 140 |
- // anything else |
|
| 141 |
- return `${this.l.toLaTeX()}(${al.join(", ")})`;
|
|
| 142 |
- default: |
|
| 143 |
- return "?"; |
|
| 144 |
- } |
|
| 145 |
-}; |
|
| 146 |
- |
|
| 147 |
-const thingy = {
|
|
| 148 |
- // fancy HTML version of the AST |
|
| 149 |
- toHTML() {
|
|
| 150 |
- const lp = `<span class="big">(</span>`; |
|
| 151 |
- const rp = `<span class="big">)</span>`; |
|
| 152 |
- switch (this.ts) {
|
|
| 153 |
- case 1: |
|
| 154 |
- // underscores indicate subscripts |
|
| 155 |
- let sbu = this.v.replace(/'/g, ucFromNcr("prime")).
|
|
| 156 |
- split("_").map(s => RTensorRender.unicodify(s)).
|
|
| 157 |
- map(([s, b]) => {
|
|
| 158 |
- const s2 = new String(s); |
|
| 159 |
- s2.greek = b; |
|
| 160 |
- return s2; |
|
| 161 |
- }); |
|
| 162 |
- const cgify = s => s.greek ? `<span class="greek">${s}</span>` : s;
|
|
| 163 |
- const it = sbu.length > 1 ? |
|
| 164 |
- `${cgify(sbu[0])}<sub>${sbu.slice(1).map(cgify).join("_")}</sub>`:
|
|
| 165 |
- cgify(sbu[0]); |
|
| 166 |
- const spacify = sbu[0].replace(new RegExp(ucFromNcr("prime"), "g"), "").length >= 2 ? ` class="spaced"` : ``;
|
|
| 167 |
- return (AST.BUILTIN_FUNCS[this.v] != null || EXTRA_BUILTINS.has(this.v)) ? |
|
| 168 |
- `<var class="builtin">${it}</var>` :
|
|
| 169 |
- `<var${spacify}>${it}</var>`;
|
|
| 170 |
- break; |
|
| 171 |
- case 2: |
|
| 172 |
- return `${this.v}`;
|
|
| 173 |
- case 3: |
|
| 174 |
- const l = this.l.toHTML(); |
|
| 175 |
- const r = this.r.toHTML(); |
|
| 176 |
- const pl = this.l.shouldParenMul() ? `${lp}${l}${rp}` : l;
|
|
| 177 |
- const pr = this.r.shouldParenMul() ? `${lp}${r}${rp}` : r;
|
|
| 178 |
- switch (this.m) {
|
|
| 179 |
- case 0: |
|
| 180 |
- if ((this.r.ts == 7 || this.r.ts == 8) && this.r.l.v == "pm") {
|
|
| 181 |
- return `${l} ${r}`;
|
|
| 182 |
- } |
|
| 183 |
- return `${l} + ${r}`;
|
|
| 184 |
- case 1: |
|
| 185 |
- return `${l} ${ucFromNcr("minus")} ${pr}`;
|
|
| 186 |
- case 2: |
|
| 187 |
- const dot = this.l.ts == 2 && this.r.ts == 2; |
|
| 188 |
- return `${pl}${dot ? ` ${ucFromNcr("sdot")} ` : ""}${pr}`;
|
|
| 189 |
- case 3: |
|
| 190 |
- return `<table class="frac"> |
|
| 191 |
- <tr class="numer"><td>${l}</td></tr>
|
|
| 192 |
- <tr class="denom"><td>${r}</td></tr>
|
|
| 193 |
- </table>`; |
|
| 194 |
- case 4: |
|
| 195 |
- const spe = this.l.shouldParenExp(); |
|
| 196 |
- return `${spe ? lp : ""}${l}${spe ? rp : ""}<sup>${r}</sup>`;
|
|
| 197 |
- case 5: |
|
| 198 |
- return `log<sub>${l}</sub>${lp}${r}${rp}`;
|
|
| 199 |
- case 6: |
|
| 200 |
- case 11: |
|
| 201 |
- return `${l} = ${r}`;
|
|
| 202 |
- case 7: |
|
| 203 |
- return `<table class="rboth"><tr> |
|
| 204 |
- <td><sup><sup><sup class="rord">${l}</sup></sup></sup><span class="rcal">${ucFromNcr("radic")}</span></td>
|
|
| 205 |
- <td><span class="rcand">${r}</span></td>
|
|
| 206 |
- </tr></table>`; |
|
| 207 |
- // TODO: case 8 not handled, because comma operator is confusing |
|
| 208 |
- case 8: |
|
| 209 |
- return `${l}, ${r}`;
|
|
| 210 |
- case 9: |
|
| 211 |
- return `${l} < ${r}`;
|
|
| 212 |
- case 10: |
|
| 213 |
- return `${l} ↦ ${r}`;
|
|
| 214 |
- default: |
|
| 215 |
- return `${this.l.toHTML()} ? ${this.r.toHTML()}`;
|
|
| 216 |
- } |
|
| 217 |
- break; |
|
| 218 |
- case 4: |
|
| 219 |
- return this.l ? `${this.m.toHTML()} = ${this.r.toHTML()}` : this.m.toHTML();
|
|
| 220 |
- case 5: |
|
| 221 |
- const m = this.m.toHTML(); |
|
| 222 |
- const pm = this.m.shouldParenMul() ? `${lp}${m}${rp}` : m;
|
|
| 223 |
- switch (this.l) {
|
|
| 224 |
- case 0: |
|
| 225 |
- return `+${pm}`;
|
|
| 226 |
- case 1: |
|
| 227 |
- return ucFromNcr("minus") + pm;
|
|
| 228 |
- // case 2 not handled, because unary asterisk is not defined |
|
| 229 |
- case 3: |
|
| 230 |
- return `<table class="frac"> |
|
| 231 |
- <tr class="numer"><td>1</td></tr> |
|
| 232 |
- <tr class="denom"><td>${m}</td></tr>
|
|
| 233 |
- </table>`; |
|
| 234 |
- case 4: |
|
| 235 |
- return `<var>e</var><sup>${m}</sup>`;
|
|
| 236 |
- case 5: |
|
| 237 |
- return `ln(${m})`;
|
|
| 238 |
- case 6: |
|
| 239 |
- return `${m} = 0`;
|
|
| 240 |
- case 7: |
|
| 241 |
- return `<table class="rboth"><tr> |
|
| 242 |
- <td><span class="rcal">${ucFromNcr("radic")}</span></td>
|
|
| 243 |
- <td><span class="rcand">${m}</span></td>
|
|
| 244 |
- </tr></table>`; |
|
| 245 |
- // likewise, no unary comma |
|
| 246 |
- case 9: |
|
| 247 |
- return `${m} < 0`;
|
|
| 248 |
- // likewise, no unary maplet |
|
| 249 |
- // likewise, no unary assignment |
|
| 250 |
- default: |
|
| 251 |
- return `? ${m}`;
|
|
| 252 |
- } |
|
| 253 |
- break; |
|
| 254 |
- case 6: |
|
| 255 |
- return `${this.l.toHTML()}[${this.m.toHTML()}]`;
|
|
| 256 |
- case 7: |
|
| 257 |
- case 8: |
|
| 258 |
- const fa = this.m[0] ? this.m[0].toHTML() : "?"; |
|
| 259 |
- const sa = this.m[1] ? this.m[1].toHTML() : "?"; |
|
| 260 |
- const ta = this.m[2] ? this.m[2].toHTML() : "?"; |
|
| 261 |
- const al = this.m.map(x => x.toHTML()); |
|
| 262 |
- // special functions |
|
| 263 |
- if (this.l.ts == 1) {
|
|
| 264 |
- switch (this.l.v) {
|
|
| 265 |
- case "abs": |
|
| 266 |
- return `|${fa}|`;
|
|
| 267 |
- case "all": |
|
| 268 |
- return `${al.map(x => "(" + x + ")").join(` ${ucFromNcr("and")} `)}`;
|
|
| 269 |
- case "any": |
|
| 270 |
- return `${al.map(x => "(" + x + ")").join(` ${ucFromNcr("or")} `)}`;
|
|
| 271 |
- case "approx": |
|
| 272 |
- return `${fa} ${ucFromNcr("approx")} ${sa}`;
|
|
| 273 |
- case "at": |
|
| 274 |
- return `${lp}${fa}${rp}<span class="ebar">|</span><table class="ebounds">
|
|
| 275 |
- <tr><td>${this.m[2] ? ta : ""}</td></tr><tr><td>${sa}</td></tr>
|
|
| 276 |
- </table>`; |
|
| 277 |
- case "brace": |
|
| 278 |
- return `<span class="big">{</span>${fa}<span class="big">}</span>`;
|
|
| 279 |
- case "bracket": |
|
| 280 |
- return `<span class="big">[</span>${fa}<span class="big">]</span>`;
|
|
| 281 |
- case "ceil": |
|
| 282 |
- return ucFromNcr("lceil") + fa + ucFromNcr("rceil");
|
|
| 283 |
- case "cross": |
|
| 284 |
- return `${fa} ${ucFromNcr("Cross")} ${sa}`;
|
|
| 285 |
- case "dot": |
|
| 286 |
- return `${fa} ${ucFromNcr("sdot")} ${sa}`;
|
|
| 287 |
- case "fact": |
|
| 288 |
- const clp = this.m[0].shouldParenMul() ? lp : ""; |
|
| 289 |
- const crp = this.m[0].shouldParenMul() ? rp : ""; |
|
| 290 |
- return `${clp}${fa}${crp}!`;
|
|
| 291 |
- case "filter": |
|
| 292 |
- return `{<var>x</var> ${ucFromNcr("in")} ${fa} | ${sa}(<var>x</var>)}`;
|
|
| 293 |
- case "floor": |
|
| 294 |
- return ucFromNcr("lfloor") + fa + ucFromNcr("rfloor");
|
|
| 295 |
- case "hat": |
|
| 296 |
- return `${fa}̂`;
|
|
| 297 | 141 |
case "if": |
| 298 |
- return `<span class="big">{</span><table class="pwf"><tr>
|
|
| 299 |
- <td>${sa}</td>
|
|
| 300 |
- <td class="cond">if ${fa}</td>
|
|
| 301 |
- </tr><tr> |
|
| 302 |
- <td>${ta}</td>
|
|
| 303 |
- <td class="cond">otherwise</td> |
|
| 304 |
- </tr></table>`; |
|
| 142 |
+ return `\\begin{cases}${sa} & \\text{if } ${fa} \\\\ ${ta} & \\text{otherwise}\\end{cases}`;
|
|
| 305 | 143 |
case "in": |
| 306 |
- return `${fa} <span class="greek">${ucFromNcr("in")}</span> ${sa}`;
|
|
| 144 |
+ return `${fa} \\in ${sa}`;
|
|
| 307 | 145 |
case "int": |
| 308 | 146 |
return this.m[1] ? |
| 309 |
- `<span class="intsym">${ucFromNcr("int")}</span> <table class="intbs">
|
|
| 310 |
- <tr class="intb"><td class="ub">${sa}</td></tr>
|
|
| 311 |
- <tr class="intb"><td>${fa}</td></tr>
|
|
| 312 |
- </table> ${ta}` :
|
|
| 313 |
- `<span class="intsym">${ucFromNcr("int")}</span> ${fa}`;
|
|
| 147 |
+ `\\int_{${fa}}^{${sa}}{${ta}}` :
|
|
| 148 |
+ `\\int{${fa}}`;
|
|
| 314 | 149 |
case "intersection": |
| 315 |
- return `${fa} <span class="greek">${ucFromNcr("Intersection")}</span> ${sa}`;
|
|
| 150 |
+ return `${fa} \\cap ${sa}`;
|
|
| 316 | 151 |
case "lim": |
| 317 |
- return `<table class="limls"> |
|
| 318 |
- <tr><td>${sa}</td></tr>
|
|
| 319 |
- <tr><td>${true ? `<span class="big">${ucFromNcr("Lambda")}</span>` : "lim"}</td></tr>
|
|
| 320 |
- <tr><td>${fa}</td></tr>
|
|
| 321 |
- </table> ${ta}`;
|
|
| 152 |
+ // you'll want one of |
|
| 153 |
+ // \newcommand{\Lim}[3]{\mathop{\displaystyle\vcenter{\hbox{\huge$\Lambda$}}}\limits_{#1}^{#2}{#3}}
|
|
| 154 |
+ // \newcommand{\Lim}[3]{\lim_{#1 \rightarrow #2}{#3}}
|
|
| 155 |
+ return `\\Lim{${fa}}{${sa}}{${ta}}`;
|
|
| 322 | 156 |
case "map": |
| 323 |
- return `${fa} 𝚳 ${sa}`;
|
|
| 157 |
+ return `\\left[${sa}(x) | x \\in ${fa}\\right]`;
|
|
| 324 | 158 |
case "matrix": |
| 325 | 159 |
const rc = parseInt(this.m[0]?.v || "2") || 2; |
| 326 | 160 |
const cc = parseInt(this.m[1]?.v || "2") || 2; |
| 327 |
- return `<table class="mat"> |
|
| 328 |
- <tr><td>${(new Array(rc)).fill(0).map((_x, i) =>
|
|
| 329 |
- this.m.slice(2 + i * cc, 2 + (i + 1) * cc).map(el => el.toHTML()).join("</td><td>")).
|
|
| 330 |
- join("</td></tr>\n<tr><td>")}</td></tr>
|
|
| 331 |
- </table>`; |
|
| 161 |
+ 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}`;
|
|
| 332 | 162 |
case "paren": |
| 333 | 163 |
return `${lp}${fa}${rp}`;
|
| 334 | 164 |
case "pm": |
| 335 |
- return `${ucFromNcr("plusmn")} ${this.m[0].shouldParenMul() ? lp + fa + rp : fa}`;
|
|
| 165 |
+ return `\\pm ${this.m[0].shouldParenMul() ? lp + fa + rp : fa}`;
|
|
| 336 | 166 |
case "product": |
| 337 |
- return `<table class="sum"> |
|
| 338 |
- <tr><td>${sa}</td></tr>
|
|
| 339 |
- <tr><td><span class="big">${ucFromNcr("Product")}</span></td></tr>
|
|
| 340 |
- <tr><td>${fa}</td></tr>
|
|
| 341 |
- </table> ${ta}`;
|
|
| 167 |
+ return `\\prod_{${fa}}^{${sa}}{${ta}}`;
|
|
| 342 | 168 |
case "sum": |
| 343 |
- return `<table class="sum"> |
|
| 344 |
- <tr><td>${sa}</td></tr>
|
|
| 345 |
- <tr><td><span class="big">${ucFromNcr("sum")}</span></td></tr>
|
|
| 346 |
- <tr><td>${fa}</td></tr>
|
|
| 347 |
- </table> ${ta}`;
|
|
| 169 |
+ return `\\sum_{${fa}}^{${sa}}{${ta}}`;
|
|
| 348 | 170 |
case "union": |
| 349 |
- return `${fa} <span class="greek">${ucFromNcr("Union")}</span> ${sa}`;
|
|
| 171 |
+ return `${fa} \\cup ${sa}`;
|
|
| 350 | 172 |
case "vec": |
| 351 |
- // TODO: there's a better way (include notation in variable names) |
|
| 352 |
- const m = fa.match(/(.*)(\<sub\>.*\<\/sub\>)?(.*?)/); |
|
| 353 |
- //alert(`${m[1]} and ${m[2]} and ${m[3]}`);
|
|
| 354 |
- return `${m[1]}⃗${m[2] || ""}${m[3] || ""}`;
|
|
| 173 |
+ return `\\vec{${fa}}`;
|
|
| 355 | 174 |
} |
| 356 | 175 |
} |
| 357 | 176 |
// anything else |
| 358 |
- return `${this.l.toHTML()}(${this.m.map(x => x.toHTML()).join(", ")})`;
|
|
| 177 |
+ return `${this.l.toLaTeX()}(${al.join(", ")})`;
|
|
| 359 | 178 |
default: |
| 360 | 179 |
return "?"; |
| 361 | 180 |
} |
| 362 |
- }, |
|
| 363 | 181 |
}; |
| 364 | 182 |