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,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><style>text { font: italic bold 40px "Garamond", serif; }</style><text fill="none" stroke="white" stroke-width="16px" y="40" x="8" textLength="56px">f(x)</text><text y="40" x="8" textLength="56px">f(x)</text></svg>' />
|
|
| 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 < b</td><td>comparison</td></tr> |
|
| 81 |
+ <tr class="bad"><td>a < x < 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>< 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 => x^2</td><td>anonymous function (saved to variable here)</td></tr> |
|
| 108 |
+ <tr><td class="excode">f = x => y => x + y; f(3)(5)</td><td>two-argument function by currying</td></tr> |
|
| 109 |
+ <tr><td class="excode">f(x) = y => x + y; f(3)(5)</td><td>mixed currying syntax</td></tr> |
|
| 110 |
+ <tr><td class="excode">f = x, y => x + y; f(3, 5)</td><td>two-argument function</td></tr> |
|
| 111 |
+ <tr><td class="excode">f(x) = (a => 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 < x, x < 1)), ^/-(1 - x^2), 0)</td> |
|
| 136 |
+ <td>the Ψ 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 => (n => (if(n==1,(_=>1),f(f)))(n-1) * n))((f => (n => (if(n==1,(_=>1),f(f)))(n-1) * n))))(6)</td> |
|
| 148 |
+ <td>factorial without named functions</td> |
|
| 149 |
+ </tr> |
|
| 150 |
+ <tr><td>filter(v, (x => 1 - <x))</td><td>remove negative items from vector</td></tr> |
|
| 151 |
+ <tr><td>reduce(v, (a, b => 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) < 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) < n / g, (g = if(<(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 => div(n, k))))<br /> |
|
| 170 |
+ last(v) = v(len(v))<br /> |
|
| 171 |
+ fnp(n) = for[(v = zero(0)) + (p = 2), len(v) < 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 => 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) < 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 => x < v[1]))) .. (.. v[1]) .. qs(filter(tail(v), (x => 1 - (x < v[1]))))<br /> |
|
| 195 |
+ qs(zero(0)) = zero(0)<br /> |
|
| 196 |
+ tv = map(zero(30), (_x => 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) < 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 => (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 π ÷ 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 => 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]}⃗${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 |