Fix the XHTML issue and stupid JS mistakes
dkl9

dkl9 commited on 2025-201 23:41:36
Showing 6 changed files, with 464 additions and 5 deletions.

... ...
@@ -0,0 +1 @@
1
+*.png
... ...
@@ -2,10 +2,10 @@
2 2
 <html>
3 3
     <head>
4 4
         <meta charset="utf-8">
5
-        <meta http-equiv="refresh" content"0;URL=rtensor.xhtml">
6
-        <title>Redirecting to rtensor.xhtml</title>
5
+        <meta http-equiv="refresh" content="0;URL=rtensor.html">
6
+        <title>Redirecting to rtensor.html</title>
7 7
     </head>
8 8
     <body>
9
-        <p>If you're not redirected automatically: <a href="rtensor.xhtml">follow the link</a></p>
9
+        <p>If you're not redirected automatically: <a href="rtensor.html">follow the link</a></p>
10 10
     </body>
11 11
 </html>
... ...
@@ -0,0 +1,457 @@
1
+<!doctype html>
2
+<html>
3
+    <head>
4
+        <meta charset="utf-8" />
5
+        <title>RTensor</title>
6
+        <link rel="stylesheet" href="maths.css" />
7
+        <style>
8
+            /*
9
+            look at this -- 27 lines of CSS!
10
+            that's all you need!
11
+            what's wrong with the web developers these days?!
12
+            */
13
+            body {
14
+                font-size: 1.2em;
15
+            }
16
+            input[type=text] {
17
+                font-family: serif;
18
+                font-size: 1em;
19
+                width: calc(100% - 5ch);
20
+            }
21
+            p, td, tr, table {
22
+                margin: 0;
23
+            }
24
+            td {
25
+                padding: 0.5vh;
26
+                border: 1px solid black;
27
+            }
28
+            .bad {
29
+                background-color: lightcoral;
30
+            }
31
+            .good {
32
+                background-color: lightgreen;
33
+            }
34
+            .excode {
35
+                cursor: pointer;
36
+            }
37
+            #title, #vnum {
38
+                margin: 0 2em 0 0;
39
+                display: inline-block;
40
+            }
41
+        </style>
42
+        <link rel="icon" href='data:image/svg+xml,&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"&gt;&lt;style&gt;text { font: italic bold 40px "Garamond", serif; }&lt;/style&gt;&lt;text fill="none" stroke="white" stroke-width="16px" y="40" x="8" textLength="56px"&gt;f(x)&lt;/text&gt;&lt;text y="40" x="8" textLength="56px"&gt;f(x)&lt;/text&gt;&lt;/svg&gt;' />
43
+    </head>
44
+    <body>
45
+        <noscript>do you really expect a usable calculator without javascript?</noscript>
46
+        <h1 id="title">RTensor</h1>
47
+        <h2 id="vnum"><a href="changelog.md">version 2.3</a></h2>
48
+        <br />
49
+        <details>
50
+            <summary>important remarks</summary>
51
+            <p>I made this many months ago with reckless/weird development practices, and haven't tested it since.
52
+            Hopefully, it still works, but one of the dozens of moving parts may have broken.
53
+            I might fix it sometime.</p>
54
+            <p><a href="/essays/rtensor_doc">There is prose documentation.</a></p>
55
+            <p>Comments and questions on RTensor are welcome.
56
+            Email them to <code>contact@[this domain]</code>.</p>
57
+            <p><a href="/">dkl9 home</a></p>
58
+        </details>
59
+        <details>
60
+            <summary>documentation (example table)</summary>
61
+            RTensor == (R)ecursive (Tensor)<br />
62
+            if, when pressing enter, nothing happens, it's probably an uncaught evaluation error, or a very slow computation<br />
63
+            you can use up/down arrow keys to navigate history<br />
64
+            some examples can be double-clicked on to run them
65
+            <table cellspacing="0">
66
+                <tr><td>example</td><td>explanation</td></tr>
67
+                <tr><td>123</td><td>integer literal (scalar)</td></tr>
68
+                <tr><td>3.14</td><td>non-integer literal (scalar)</td></tr>
69
+                <tr><td>.. 3.14</td><td>single-element vector</td></tr>
70
+                <tr><td>abc</td><td>identifier</td></tr>
71
+                <tr><td>f'</td><td>prime symbols in identifiers</td></tr>
72
+                <tr><td>pi; phi; true; false; null</td><td>built-in special constants</td></tr>
73
+                <tr><td>a = expr</td><td>save value to identifier</td></tr>
74
+                <tr><td>_</td><td>most recent result</td></tr>
75
+                <tr><td>a + b; a - b; a * b; a / b</td><td>basic operations</td></tr>
76
+                <tr><td>a ^ b</td><td>exponents</td></tr>
77
+                <tr><td>b \ x</td><td>base-b logarithm of x</td></tr>
78
+                <tr><td>a == b</td><td>check equality</td></tr>
79
+                <tr class="bad"><td class="excode">(-/10)^2 == 10</td><td>equality is sensitive to numerical error</td></tr>
80
+                <tr><td>a &lt; b</td><td>comparison</td></tr>
81
+                <tr class="bad"><td>a &lt; x &lt; b</td><td>can't chain comparison</td></tr>
82
+                <tr><td>n -/ x</td><td>nth-root of x</td></tr>
83
+                <tr><td>a, b, c</td><td>tensor [a, b, c]</td></tr>
84
+                <tr class="good"><td>(a, b, c)[2]</td><td>tensor indexing; returns b</td></tr>
85
+                <tr class="bad"><td>(a, b, c)[4]</td><td>tensor index out of range</td></tr>
86
+                <tr><td>v[i] = a</td><td>assign to item in vector</td></tr>
87
+                <tr class="good"><td class="excode">(3, 4, 5) * 0.5</td><td>vector-scalar operation</td></tr>
88
+                <tr class="good"><td class="excode">(1, 2) + (3, 4)</td><td>vector-vector operation</td></tr>
89
+                <tr class="bad"><td class="excode">(6, 2, 3) + (4, 4)</td><td>incompatible dimensions</td></tr>
90
+                <tr><td class="excode">(3, 4, 5), (6, 7, 8)</td><td>matrix</td></tr>
91
+                <tr><td class="excode">(3, 4, 5) .. (6, 7, 8)</td><td>vector concatenation</td></tr>
92
+                <tr class="good"><td class="excode">1 .. 10</td><td>range of integers</td></tr>
93
+                <tr class="bad"><td class="excode">1..10</td><td>spacing matters here</td></tr>
94
+                <tr class="bad"><td class="excode">1 .. (5, 10)</td><td>invalid</td></tr>
95
+                <tr class="good"><td>b^2 - 4*a*c</td><td>quadratic discriminant</td></tr>
96
+                <tr class="good"><td>b ^ 2 -4 *a*c</td><td>spacing (usually) doesn't matter</td></tr>
97
+                <tr><td>-x; /x; ^x; \x</td><td>negative; reciprocal; e<sup>x</sup>; ln(x)</td></tr>
98
+                <tr><td>== x</td><td>is x zero?</td></tr>
99
+                <tr><td>&lt; x</td><td>is x negative?</td></tr>
100
+                <tr><td>-/x</td><td>square root</td></tr>
101
+                <tr><td>/-x</td><td>negative reciprocal</td></tr>
102
+                <tr><td class="excode">a = 3; sin(a)^2 + cos(a)^2</td><td>semicolon-separated statements</td></tr>
103
+                <tr><td class="excode">cos(x)</td><td>function evaluation</td></tr>
104
+                <tr><td class="excode">arctan(3, 2)</td><td>two-argument function</td></tr>
105
+                <tr><td class="excode">cos((0, 1))</td><td>function of a vector</td></tr>
106
+                <tr><td class="excode">f(x) = x^2</td><td>function definition</td></tr>
107
+                <tr><td class="excode">f = x =&gt; x^2</td><td>anonymous function (saved to variable here)</td></tr>
108
+                <tr><td class="excode">f = x =&gt; y =&gt; x + y; f(3)(5)</td><td>two-argument function by currying</td></tr>
109
+                <tr><td class="excode">f(x) = y =&gt; x + y; f(3)(5)</td><td>mixed currying syntax</td></tr>
110
+                <tr><td class="excode">f = x, y =&gt; x + y; f(3, 5)</td><td>two-argument function</td></tr>
111
+                <tr><td class="excode">f(x) = (a =&gt; a^2 + a)(\x); f(3)</td><td>hacky local variables</td></tr>
112
+                <tr><td class="excode">f(x) = (a = \x)*0 + (a^2 + a); f(3)</td><td>less hacky local variables</td></tr>
113
+                <tr>
114
+                    <td>abs(x); floor(x); clear()<br />len(v); any(v); all(v); tail(v); trim(v)<br />sin(x); cos(x)<br />arcsin(y); arccos(y); arctan(y)</td>
115
+                    <td>various built-in functions</td>
116
+                </tr>
117
+                <tr><td>zero(n)</td><td>n-element vector of zeroes</td></tr>
118
+                <tr><td class="excode">tail(..0); trim(..0); zero(0); 1 .. 0</td><td>empty list (four ways)</td></tr>
119
+                <tr class="good"><td class="excode">random()</td><td>random number, 0 to 1</td></tr>
120
+                <tr class="bad"><td>random(a)</td><td>invalid</td></tr>
121
+                <tr class="good"><td>random(a, b)</td><td>random integer, a to b (inclusive)</td></tr>
122
+                <tr class="good">
123
+                    <td class="excode">fact(n) = n * fact(n - 1)<br />fact(0) = 1</td>
124
+                    <td>recursive functions</td>
125
+                </tr>
126
+                <tr class="bad">
127
+                    <td>fact(0) = 1<br />fact(n) = n * fact(n - 1)</td>
128
+                    <td>always define base cases last</td>
129
+                </tr>
130
+                <tr>
131
+                    <td class="excode">A(m, n) = A(m - 1, A(m, n - 1))<br />A(m, 0) = A(m - 1, 1)<br />A(0, n) = n + 1</td>
132
+                    <td>the Ackermann function,<br />right out of Wikipedia<br />(beware: very recursive and slow)</td>
133
+                </tr>
134
+                <tr>
135
+                    <td class="excode">psi(x) = if(all((-1 &lt; x, x &lt; 1)), ^/-(1 - x^2), 0)</td>
136
+                    <td>the &#936; bump function, right out of Wikipedia</td>
137
+                </tr>
138
+                <tr>
139
+                    <td class="excode">fact(n) = if[n == 0, 1, n * fact(n - 1)]</td>
140
+                    <td>recursive function with a conditional</td>
141
+                </tr>
142
+                <tr>
143
+                    <td class="excode">map(1 .. 5, fact)</td>
144
+                    <td>first few factorials<br />(assuming fact is already defined)</td>
145
+                </tr>
146
+                <tr>
147
+                    <td class="excode">((f =&gt; (n =&gt; (if(n==1,(_=&gt;1),f(f)))(n-1) * n))((f =&gt; (n =&gt; (if(n==1,(_=&gt;1),f(f)))(n-1) * n))))(6)</td>
148
+                    <td>factorial without named functions</td>
149
+                </tr>
150
+                <tr><td>filter(v, (x =&gt; 1 - &lt;x))</td><td>remove negative items from vector</td></tr>
151
+                <tr><td>reduce(v, (a, b =&gt; a + b))</td><td>sum of the items of a vector</td></tr>
152
+                <tr>
153
+                    <td class="excode">aloz(v, i) = if[len(v) &lt; i, 0, v[i]]</td>
154
+                    <td>access list at index, or 0 if index beyond length</td>
155
+                </tr>
156
+                <tr>
157
+                    <td class="excode">dot(u, v) = if[any((==len(u), ==len(v))), 0, u[1] * v[1] + dot(tail(u), tail(v))]</td>
158
+                    <td>dot product of vectors</td>
159
+                </tr>
160
+                <tr>
161
+                    <td class="excode">
162
+                        prime(n) = for[(g = 2), floor(n / g) &lt; n / g, (g = if(&lt;(n - g^2 - 1), n, g + 1)), g] == n
163
+                    </td>
164
+                    <td>sieve-based primality checker</td>
165
+                </tr>
166
+                <tr>
167
+                    <td class="excode">
168
+                        div(a, b) = floor(a / b) == a / b<br />
169
+                        fp(n, l) = 1 - any(map(l, (k =&gt; div(n, k))))<br />
170
+                        last(v) = v(len(v))<br />
171
+                        fnp(n) = for[(v = zero(0)) + (p = 2), len(v) &lt; n, if[fp(p, v), (v = v, p), (p = p + 1)], v]
172
+                    </td>
173
+                    <td>first n primes by accelerated sieve</td>
174
+                </tr>
175
+                <tr>
176
+                    <td class="excode">
177
+                        dv(a, b) = (x =&gt; x == floor(x))(b / a)<br />
178
+                        factor(n, g) = if(dv(g, n), zero(1) + g, zero(0)) .. factor(if(dv(g, n), n / g, n), if(dv(g, n), g, g + 1))<br />
179
+                        factor(1, g) = zero(0)<br />
180
+                        factor(n) = factor(floor(n), 2)<br />
181
+                    </td>
182
+                    <td>integer factorisation</td>
183
+                </tr>
184
+                <tr>
185
+                    <td class="excode">
186
+                        cond(v) = len(v) &lt; 20<br />
187
+                        next(v) = v, (v[len(v)] + v[len(v) - 1])<br />
188
+                        for[(v = 1, 1), cond(v), (v = next(v)), v]
189
+                    </td>
190
+                    <td>list of Fibonacci numbers</td>
191
+                </tr>
192
+                <tr>
193
+                    <td class="excode">
194
+                        qs(v) = qs(filter(tail(v), (x =&gt; x &lt; v[1]))) .. (.. v[1]) .. qs(filter(tail(v), (x =&gt; 1 - (x &lt; v[1]))))<br />
195
+                        qs(zero(0)) = zero(0)<br />
196
+                        tv = map(zero(30), (_x =&gt; random(1, 100)))<br />
197
+                        qs(tv)
198
+                    </td>
199
+                    <td>quicksort algorithm implementation</td>
200
+                </tr>
201
+                <tr>
202
+                    <td class="excode">
203
+                        a(n) = a(n-a(n-1)) + a(n-a(n-2))<br />
204
+                        a(1) = 1<br />
205
+                        a(2) = 1
206
+                    </td>
207
+                    <td>the Hofstadter Q-sequence,<br />right out of the OEIS<br />(beware: very recursive and slow)</td>
208
+                </tr>
209
+                <tr>
210
+                    <td class="excode">
211
+                        Qs(v) = v, (v(len(v) + 1 - v(len(v))) + v(len(v) + 1 - v(len(v) - 1)))<br />
212
+                        Qc(v) = len(v) &lt; 100<br />
213
+                        for((1, 1), Qc, Qs)
214
+                    </td>
215
+                    <td>the Hofstadter Q-sequence,<br />computed iteratively (much faster)</td>
216
+                </tr>
217
+                <tr>
218
+                    <td class="excode">
219
+                        pe(x, p) = sum[(i = 1), len(p), p[i] * x^(i - 1)]<br />
220
+                        pe(4, (-2, 5, 6))
221
+                    </td>
222
+                    <td>polynomial evaluation<br />6x<sup>2</sup> + 5x - 2 at x = 4</td>
223
+                </tr>
224
+                <tr>
225
+                    <td class="excode">
226
+                        pd(p) = tail(map(p, (x, i =&gt; (i - 1) * x)))<br />
227
+                        pd((2, 1, 4, 1))
228
+                    </td>
229
+                    <td>polynomial derivative: x<sup>3</sup> + 4x<sup>2</sup> + x + 2</td>
230
+                </tr>
231
+                <tr>
232
+                    <td class="excode">
233
+                        rnr(v) = 1 - ==pe(v(1), v(2))<br />
234
+                        nrs(v) = (v(1) - pe(v(1), v(2)) / pe(v(1), pd(v(2)))), v(2)<br />
235
+                        pr(x, p) = (for((x, p), rnr, nrs))(1)<br />
236
+                        pr(0, (2, 1, 4, 1))
237
+                    </td>
238
+                    <td>
239
+                        polynomial rootfinding by Newton's method<br />
240
+                        (assuming pe and pd are already defined)<br />
241
+                        root of x<sup>3</sup> + 4x<sup>2</sup> + x + 2 near 0<br />
242
+                        (may loop or error when unable to find root)
243
+                    </td>
244
+                </tr>
245
+                <tr>
246
+                    <td class="excode">
247
+                        digits(n, b) = digits(floor(n / b), b), (n - b * floor(n / b))<br />
248
+                        digits(0, b) = zero(0)
249
+                    </td>
250
+                    <td>
251
+                        vector of digits of number in base<br />
252
+                        (errors on negative inputs)
253
+                    </td>
254
+                </tr>
255
+                <tr>
256
+                    <td class="excode">T(n) = sum[(k = 1), n, k]</td>
257
+                    <td>the triangle numbers,<br />right out of Wolfram MathWorld</td>
258
+                </tr>
259
+                <tr>
260
+                    <td class="excode">render[(x = (-b + pm(-/(b^2 - 4*a*c))) / (2*a))]</td>
261
+                    <td>render quadratic formula</td>
262
+                </tr>
263
+                <tr>
264
+                    <td class="excode">html[(x = (-b + pm(-/(b^2 - 4*a*c))) / (2*a))]</td>
265
+                    <td>HTML behind the quadratic formula</td>
266
+                </tr>
267
+                <tr>
268
+                    <td class="excode">render[(sum((k=1), n, k^2) = (n + 1) * (2*n + 1) * n / 6)]</td>
269
+                    <td>render sum-of-squares formula</td>
270
+                </tr>
271
+                <tr>
272
+                    <td class="excode">render[(pi/4 = int(0, 1, -/(1 - x^2)*dx))]</td>
273
+                    <td>render an integral for &#960; &#247; 4</td>
274
+                </tr>
275
+                <tr>
276
+                    <td class="excode">
277
+                        mod(a,b) = a - b * floor(a / b)<br />
278
+                        gcd(m, n) = gcd(n, mod(m, n))<br />
279
+                        gcd(m, 0) = m
280
+                    </td>
281
+                    <td>Euclid's GCD algorithm</td>
282
+                </tr>
283
+                <tr>
284
+                    <td class="excode">int(a, b, f, n) = sum[(k = 1), n, (b - a) / n * f(a + (b - a) * ((k - /2) / n))]</td>
285
+                    <td>numerical integration by midpoint sum</td>
286
+                </tr>
287
+                <tr>
288
+                    <td class="excode">
289
+                        cint(a, b, u, f, n) = sum[(k = 1), n, (u(a + (b - a) * ((k + 1) / n)) - u(a + (b - a) * (k / n))) * f(u(a + (b - a) * ((k - /2) / n)))]
290
+                    </td>
291
+                    <td>numerical contour integration<br />(with parametric curve function u)</td>
292
+                </tr>
293
+                <tr>
294
+                    <td class="excode">fact2(n) = fact(2 * n)<br />succ(n) = n + 1<br />cat = fact2 / fact^2 / succ</td>
295
+                    <td>Catalan numbers by functional arithmetic<br />(assuming fact is already defined)</td>
296
+                </tr>
297
+                <tr>
298
+                    <td class="excode">latex[integers == filter(reals, (r =&gt; floor(r) == ceil(r)))]</td>
299
+                    <td>generate L<sub>A</sub>T<sub>E</sub>X for a weird definition of the integers</td>
300
+                </tr>
301
+            </table>
302
+        </details>
303
+        <textarea id="bci" cols="120" rows="8"># Throw in some code ...</textarea><br />
304
+        <span>use alternative numeric type:</span>
305
+        <div id="iol"></div>
306
+        <script type="module">
307
+            /*<![CDATA[*/
308
+            import {ioLog, fts} from "./rtensor_common.js";
309
+            import {BUILTIN_FUNCS} from "./rtensor_lib.js";
310
+            import {TokenStream, NewParser} from "./maths_parser.js";
311
+            import {NUMERIC_TYPES} from "./maths_ast.js";
312
+
313
+            const calcVars = Object.fromEntries(Object.entries(BUILTIN_FUNCS));
314
+            calcVars["_"] = calcVars["null"];
315
+            const pastInps = [];
316
+            const iol = document.getElementById("iol");
317
+            const bci = document.getElementById("bci");
318
+            var histPos = 0;
319
+
320
+            // handle keydown events in the latest input line
321
+            // for history navigation and input submission
322
+            function inpKeyHandler(ev) {
323
+                let nd = false;
324
+                switch (ev.key) {
325
+                    case "ArrowUp":
326
+                        if (pastInps.length <= 1) {
327
+                            break;
328
+                        }
329
+                        histPos--;
330
+                        if (histPos < 1) {
331
+                            histPos = 1;
332
+                        }
333
+                        ev.target.value = pastInps[histPos].value;
334
+                        nd = true;
335
+                        break;
336
+                    case "ArrowDown":
337
+                        histPos++;
338
+                        if (histPos > pastInps.length) {
339
+                            histPos = pastInps.length;
340
+                        }
341
+                        ev.target.value = (pastInps[histPos] || { value: "" }).value;
342
+                        nd = true;
343
+                        break;
344
+                    case "Enter":
345
+                        if (ev.target.value.trim() != "") {
346
+                            evalInp();
347
+                            nextInp();
348
+                        }
349
+                        nd = true;
350
+                        break;
351
+                    default:
352
+                        break;
353
+                }
354
+                if (nd) {
355
+                    ev.preventDefault();
356
+                }
357
+            }
358
+
359
+            function evalInp() {
360
+                let disp;
361
+                let perr = false;
362
+                const ci = document.getElementById("cil" + pastInps.length.toString());
363
+                const st = ci.value.split(";");
364
+                for (let i = 0; i < st.length; i++) {
365
+                    const wt = st[i];
366
+                    const lexer = new TokenStream(wt);
367
+                    try {
368
+                        const ast = NewParser.statement(lexer);
369
+                        if (ast === null) {
370
+                            disp = "syntax error";
371
+                            break;
372
+                        } else {
373
+                            perr = perr || (lexer.tind != lexer.toks.length - 1);
374
+                            document.body.style.cursor = "wait";
375
+                            try {
376
+                                const res = ast.evaluate(calcVars, false);
377
+                                if (res != null) { calcVars["_"] = res; }
378
+                                const svn = "_" + pastInps.length.toString();
379
+                                calcVars[svn] = res;
380
+                                disp = (res == null) ? "evaluation error" : (svn + " = " + fts(res));
381
+                            } catch (err) {
382
+                                disp = err;
383
+                            }
384
+                            document.body.style.cursor = "auto";
385
+                        }
386
+                    } catch (err) {
387
+                        disp = err;
388
+                    }
389
+                }
390
+                ioLog(disp);
391
+                if (perr) { ioLog("possible syntax error"); }
392
+            }
393
+
394
+            // disable the current input line, add its contents to history,
395
+            // and add a new input line
396
+            function nextInp() {
397
+                const prev = (document.getElementById("cil" + pastInps.length.toString()) || {});
398
+                prev.onkeydown = null;
399
+                prev.disabled = true;
400
+                pastInps.push(prev);
401
+                const newi = document.createElement("input");
402
+                newi.id = "cil" + pastInps.length.toString();
403
+                newi.onkeydown = inpKeyHandler;
404
+                newi.type = "text";
405
+                iol.append("> ");
406
+                iol.appendChild(newi);
407
+                document.getElementById("cil" + pastInps.length.toString()).focus();
408
+                histPos = pastInps.length;
409
+            }
410
+            
411
+            function vce(t) {
412
+                t.split("\n").forEach(l => {
413
+                    if (l.trim() != "") {
414
+                        iol.lastElementChild.value = l;
415
+                        evalInp();
416
+                        nextInp();
417
+                    }
418
+                });
419
+            }
420
+            
421
+            const ech = document.getElementsByClassName("excode");
422
+            for (let i = 0; i < ech.length; i++) {
423
+                ech[i].ondblclick = ev => vce(ev.target.innerText);
424
+            }
425
+            
426
+            window.onbeforeunload = ev => (pastInps.length > 1 ? "Quit RTensor?" : undefined);
427
+
428
+            // create a link for a version of the calculator using each numeric type
429
+            Object.keys(NUMERIC_TYPES).forEach(ntn => {
430
+                const le = document.createElement("a");
431
+                le.innerText = " " + ntn;
432
+                le.href = "?nt=" + ntn;
433
+                document.body.insertBefore(le, iol);
434
+            });
435
+            document.body.insertBefore(document.createElement("br"), iol);
436
+
437
+            bci.onchange = ev => {
438
+                // split by lines, except with backslash continuation
439
+                ev.target.value.split(/(?<!\\)\n/g).
440
+                    // remove backslash continuation
441
+                    map(l => l.replace(/\\\n/g, "\n")).
442
+                    // remove comments and blank lines
443
+                    filter(l => l.replace(/#.*/, "").trim()).
444
+                    forEach(l => {
445
+                        const ci = document.getElementById("cil" + pastInps.length.toString());
446
+                        ci.value = l;
447
+                        evalInp();
448
+                        nextInp();
449
+                    });
450
+                ev.target.value = "";
451
+            };
452
+
453
+            nextInp();
454
+            /*]]>*/
455
+        </script>
456
+    </body>
457
+</html>
... ...
@@ -314,7 +314,6 @@ export const RTensorRender = {
314 314
                         case "vec":
315 315
                             // TODO: there's a better way (include notation in variable names)
316 316
                             const m = fa.match(/(.*)(\<sub\>.*\<\/sub\>)?(.*?)/);
317
-                            //alert(`${m[1]} and ${m[2]} and ${m[3]}`);
318 317
                             return `${m[1]}&#8407;${m[2] || ""}${m[3] || ""}`;
319 318
                     }
320 319
                 }
... ...
@@ -2,6 +2,8 @@
2 2
 
3 3
 import {fts} from "../rtensor_common.js";
4 4
 import {BasicNumber} from "./basic.js";
5
+import {IDENT_AST} from "../rtensor_lib.js";
6
+import {vecOp, NumericType} from "../maths_ast.js";
5 7
 
6 8
 // check if vectors (Arrays of numbers) a and b are completely equal
7 9
 const vecEq = (a, b) => (a?.eq && b?.eq) ?
... ...
@@ -5,7 +5,7 @@ import {BasicNumber} from "./basic.js";
5 5
 BasicNumber.keys.forEach(k => (Number.prototype[k] = BasicNumber.prototype[k]));
6 6
 
7 7
 Number.ify = function(x) {
8
-    if (typeof x == "object" && x.constructor == Complex) {
8
+    if (typeof x == "object" && x.constructor.name == "Complex") {
9 9
         return x.im ? null : new Number(x.re);
10 10
     } else if (typeof x == "boolean") {
11 11
         return 1*x;
12 12