Finish LaTeX converter
dkl9

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} &lt; ${r}`;
212
-                    case 10:
213
-                        return `${l} &#8614; ${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} &lt; 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}&#770;`;
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} &#120499; ${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]}&#8407;${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