DKL9 GitList
Repositories
DKL9 home
rtensor
Code
Commits
Branches
Tags
Search
Tree:
e05fe4a
Branches
Tags
master
rtensor
rtensor.xhtml
Another module fix, hopefully the last
dkl9
commited
e05fe4a
at 2023-199 09:13:03
rtensor.xhtml
Blame
History
Raw
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8" /> <title>RTensor</title> <link rel="stylesheet" href="maths.css" /> <style> /* look at this -- 27 lines of CSS! that's all you need! what's wrong with the web developers these days?! */ body { font-size: 1.2em; } input[type=text] { font-family: serif; font-size: 1em; width: calc(100% - 3ch); } p, td, tr, table { margin: 0; } td { padding: 0.5vh; border: 1px solid black; } .bad { background-color: lightcoral; } .good { background-color: lightgreen; } .excode { cursor: pointer; } #title, #vnum { margin: 0 2em 0 0; display: inline-block; } </style> <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>' /> </head> <body> <noscript>do you really expect a usable calculator without javascript?</noscript> <h1 id="title">RTensor</h1> <h2 id="vnum"><a href="changelog.md">version 2.3-dev</a></h2> <br /> <details> <summary>important remarks</summary> <p>I made this many months ago with reckless/weird development practices, and haven't tested it since. Hopefully, it still works, but one of the dozens of moving parts may have broken. I might fix it sometime.</p> <p><a href="/essays/rtensor_doc">There is prose documentation.</a></p> <p>Comments and questions on RTensor are welcome. Email them to <code>contact@[this domain]</code>.</p> <p><a href="/">dkl9 home</a></p> </details> <details> <summary>documentation (example table)</summary> RTensor == (R)ecursive (Tensor)<br /> if, when pressing enter, nothing happens, it's probably an uncaught evaluation error, or a very slow computation<br /> you can use up/down arrow keys to navigate history<br /> some examples can be double-clicked on to run them <table cellspacing="0"> <tr><td>example</td><td>explanation</td></tr> <tr><td>123</td><td>integer literal (scalar)</td></tr> <tr><td>3.14</td><td>non-integer literal (scalar)</td></tr> <tr><td>.. 3.14</td><td>single-element vector</td></tr> <tr><td>abc</td><td>identifier</td></tr> <tr><td>f'</td><td>prime symbols in identifiers</td></tr> <tr><td>pi; phi; true; false; null</td><td>built-in special constants</td></tr> <tr><td>a = expr</td><td>save value to identifier</td></tr> <tr><td>_</td><td>most recent result</td></tr> <tr><td>a + b; a - b; a * b; a / b</td><td>basic operations</td></tr> <tr><td>a ^ b</td><td>exponents</td></tr> <tr><td>b \ x</td><td>base-b logarithm of x</td></tr> <tr><td>a == b</td><td>check equality</td></tr> <tr class="bad"><td class="excode">(-/10)^2 == 10</td><td>equality is sensitive to numerical error</td></tr> <tr><td>a < b</td><td>comparison</td></tr> <tr class="bad"><td>a < x < b</td><td>can't chain comparison</td></tr> <tr><td>n -/ x</td><td>nth-root of x</td></tr> <tr><td>a, b, c</td><td>tensor [a, b, c]</td></tr> <tr class="good"><td>(a, b, c)[2]</td><td>tensor indexing; returns b</td></tr> <tr class="bad"><td>(a, b, c)[4]</td><td>tensor index out of range</td></tr> <tr><td>v[i] = a</td><td>assign to item in vector</td></tr> <tr class="good"><td class="excode">(3, 4, 5) * 0.5</td><td>vector-scalar operation</td></tr> <tr class="good"><td class="excode">(1, 2) + (3, 4)</td><td>vector-vector operation</td></tr> <tr class="bad"><td class="excode">(6, 2, 3) + (4, 4)</td><td>incompatible dimensions</td></tr> <tr><td class="excode">(3, 4, 5), (6, 7, 8)</td><td>matrix</td></tr> <tr><td class="excode">(3, 4, 5) .. (6, 7, 8)</td><td>vector concatenation</td></tr> <tr class="good"><td class="excode">1 .. 10</td><td>range of integers</td></tr> <tr class="bad"><td class="excode">1..10</td><td>spacing matters here</td></tr> <tr class="bad"><td class="excode">1 .. (5, 10)</td><td>invalid</td></tr> <tr class="good"><td>b^2 - 4*a*c</td><td>quadratic discriminant</td></tr> <tr class="good"><td>b ^ 2 -4 *a*c</td><td>spacing (usually) doesn't matter</td></tr> <tr><td>-x; /x; ^x; \x</td><td>negative; reciprocal; e<sup>x</sup>; ln(x)</td></tr> <tr><td>== x</td><td>is x zero?</td></tr> <tr><td>< x</td><td>is x negative?</td></tr> <tr><td>-/x</td><td>square root</td></tr> <tr><td>/-x</td><td>negative reciprocal</td></tr> <tr><td class="excode">a = 3; sin(a)^2 + cos(a)^2</td><td>semicolon-separated statements</td></tr> <tr><td class="excode">cos(x)</td><td>function evaluation</td></tr> <tr><td class="excode">arctan(3, 2)</td><td>two-argument function</td></tr> <tr><td class="excode">cos((0, 1))</td><td>function of a vector</td></tr> <tr><td class="excode">f(x) = x^2</td><td>function definition</td></tr> <tr><td class="excode">f = x => x^2</td><td>anonymous function (saved to variable here)</td></tr> <tr><td class="excode">f = x => y => x + y; f(3)(5)</td><td>two-argument function by currying</td></tr> <tr><td class="excode">f(x) = y => x + y; f(3)(5)</td><td>mixed currying syntax</td></tr> <tr><td class="excode">f = x, y => x + y; f(3, 5)</td><td>two-argument function</td></tr> <tr><td class="excode">f(x) = (a => a^2 + a)(\x); f(3)</td><td>hacky local variables</td></tr> <tr><td class="excode">f(x) = (a = \x)*0 + (a^2 + a); f(3)</td><td>less hacky local variables</td></tr> <tr> <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> <td>various built-in functions</td> </tr> <tr><td>zero(n)</td><td>n-element vector of zeroes</td></tr> <tr><td class="excode">tail(..0); trim(..0); zero(0); 1 .. 0</td><td>empty list (four ways)</td></tr> <tr class="good"><td class="excode">random()</td><td>random number, 0 to 1</td></tr> <tr class="bad"><td>random(a)</td><td>invalid</td></tr> <tr class="good"><td>random(a, b)</td><td>random integer, a to b (inclusive)</td></tr> <tr class="good"> <td class="excode">fact(n) = n * fact(n - 1)<br />fact(0) = 1</td> <td>recursive functions</td> </tr> <tr class="bad"> <td>fact(0) = 1<br />fact(n) = n * fact(n - 1)</td> <td>always define base cases last</td> </tr> <tr> <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> <td>the Ackermann function,<br />right out of Wikipedia<br />(beware: very recursive and slow)</td> </tr> <tr> <td class="excode">psi(x) = if(all((-1 < x, x < 1)), ^/-(1 - x^2), 0)</td> <td>the Ψ bump function, right out of Wikipedia</td> </tr> <tr> <td class="excode">fact(n) = if[n == 0, 1, n * fact(n - 1)]</td> <td>recursive function with a conditional</td> </tr> <tr> <td class="excode">map(1 .. 5, fact)</td> <td>first few factorials<br />(assuming fact is already defined)</td> </tr> <tr> <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> <td>factorial without named functions</td> </tr> <tr><td>filter(v, (x => 1 - <x))</td><td>remove negative items from vector</td></tr> <tr><td>reduce(v, (a, b => a + b))</td><td>sum of the items of a vector</td></tr> <tr> <td class="excode">aloz(v, i) = if[len(v) < i, 0, v[i]]</td> <td>access list at index, or 0 if index beyond length</td> </tr> <tr> <td class="excode">dot(u, v) = if[any((==len(u), ==len(v))), 0, u[1] * v[1] + dot(tail(u), tail(v))]</td> <td>dot product of vectors</td> </tr> <tr> <td class="excode"> prime(n) = for[(g = 2), floor(n / g) < n / g, (g = if(<(n - g^2 - 1), n, g + 1)), g] == n </td> <td>sieve-based primality checker</td> </tr> <tr> <td class="excode"> div(a, b) = floor(a / b) == a / b<br /> fp(n, l) = 1 - any(map(l, (k => div(n, k))))<br /> last(v) = v(len(v))<br /> fnp(n) = for[(v = zero(0)) + (p = 2), len(v) < n, if[fp(p, v), (v = v, p), (p = p + 1)], v] </td> <td>first n primes by accelerated sieve</td> </tr> <tr> <td class="excode"> dv(a, b) = (x => x == floor(x))(b / a)<br /> 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 /> factor(1, g) = zero(0)<br /> factor(n) = factor(floor(n), 2)<br /> </td> <td>integer factorisation</td> </tr> <tr> <td class="excode"> cond(v) = len(v) < 20<br /> next(v) = v, (v[len(v)] + v[len(v) - 1])<br /> for[(v = 1, 1), cond(v), (v = next(v)), v] </td> <td>list of Fibonacci numbers</td> </tr> <tr> <td class="excode"> qs(v) = qs(filter(tail(v), (x => x < v[1]))) .. (.. v[1]) .. qs(filter(tail(v), (x => 1 - (x < v[1]))))<br /> qs(zero(0)) = zero(0)<br /> tv = map(zero(30), (_x => random(1, 100)))<br /> qs(tv) </td> <td>quicksort algorithm implementation</td> </tr> <tr> <td class="excode"> a(n) = a(n-a(n-1)) + a(n-a(n-2))<br /> a(1) = 1<br /> a(2) = 1 </td> <td>the Hofstadter Q-sequence,<br />right out of the OEIS<br />(beware: very recursive and slow)</td> </tr> <tr> <td class="excode"> Qs(v) = v, (v(len(v) + 1 - v(len(v))) + v(len(v) + 1 - v(len(v) - 1)))<br /> Qc(v) = len(v) < 100<br /> for((1, 1), Qc, Qs) </td> <td>the Hofstadter Q-sequence,<br />computed iteratively (much faster)</td> </tr> <tr> <td class="excode"> pe(x, p) = sum[(i = 1), len(p), p[i] * x^(i - 1)]<br /> pe(4, (-2, 5, 6)) </td> <td>polynomial evaluation<br />6x<sup>2</sup> + 5x - 2 at x = 4</td> </tr> <tr> <td class="excode"> pd(p) = tail(map(p, (x, i => (i - 1) * x)))<br /> pd((2, 1, 4, 1)) </td> <td>polynomial derivative: x<sup>3</sup> + 4x<sup>2</sup> + x + 2</td> </tr> <tr> <td class="excode"> rnr(v) = 1 - ==pe(v(1), v(2))<br /> nrs(v) = (v(1) - pe(v(1), v(2)) / pe(v(1), pd(v(2)))), v(2)<br /> pr(x, p) = (for((x, p), rnr, nrs))(1)<br /> pr(0, (2, 1, 4, 1)) </td> <td> polynomial rootfinding by Newton's method<br /> (assuming pe and pd are already defined)<br /> root of x<sup>3</sup> + 4x<sup>2</sup> + x + 2 near 0<br /> (may loop or error when unable to find root) </td> </tr> <tr> <td class="excode"> digits(n, b) = digits(floor(n / b), b), (n - b * floor(n / b))<br /> digits(0, b) = zero(0) </td> <td> vector of digits of number in base<br /> (errors on negative inputs) </td> </tr> <tr> <td class="excode">T(n) = sum[(k = 1), n, k]</td> <td>the triangle numbers,<br />right out of Wolfram MathWorld</td> </tr> <tr> <td class="excode">render[(x = (-b + pm(-/(b^2 - 4*a*c))) / (2*a))]</td> <td>render quadratic formula</td> </tr> <tr> <td class="excode">html[(x = (-b + pm(-/(b^2 - 4*a*c))) / (2*a))]</td> <td>HTML behind the quadratic formula</td> </tr> <tr> <td class="excode">render[(sum((k=1), n, k^2) = (n + 1) * (2*n + 1) * n / 6)]</td> <td>render sum-of-squares formula</td> </tr> <tr> <td class="excode">render[(pi/4 = int(0, 1, -/(1 - x^2)*dx))]</td> <td>render an integral for π ÷ 4</td> </tr> <tr> <td class="excode"> mod(a,b) = a - b * floor(a / b)<br /> gcd(m, n) = gcd(n, mod(m, n))<br /> gcd(m, 0) = m </td> <td>Euclid's GCD algorithm</td> </tr> <tr> <td class="excode">int(a, b, f, n) = sum[(k = 1), n, (b - a) / n * f(a + (b - a) * ((k - /2) / n))]</td> <td>numerical integration by midpoint sum</td> </tr> <tr> <td class="excode"> 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)))] </td> <td>numerical contour integration<br />(with parametric curve function u)</td> </tr> <tr> <td class="excode">fact2(n) = fact(2 * n)<br />succ(n) = n + 1<br />cat = fact2 / fact^2 / succ</td> <td>Catalan numbers by functional arithmetic<br />(assuming fact is already defined)</td> </tr> </table> </details> <textarea id="bci" cols="120" rows="8"># Throw in some code ...</textarea><br /> <span>use alternative numeric type:</span> <div id="iol"></div> <script type="module"> /*<![CDATA[*/ import {ioLog} from "./rtensor_common.js"; import {BUILTIN_FUNCS} from "./rtensor_lib.js"; import {TokenStream, NewParser} from "./maths_parser.js"; import {NUMERIC_TYPES} from "./maths_ast.js"; const calcVars = Object.fromEntries(Object.entries(BUILTIN_FUNCS)); calcVars["_"] = calcVars["null"]; const pastInps = []; const iol = document.getElementById("iol"); const bci = document.getElementById("bci"); var histPos = 0; // handle keydown events in the latest input line // for history navigation and input submission function inpKeyHandler(ev) { let nd = false; switch (ev.key) { case "ArrowUp": if (pastInps.length <= 1) { break; } histPos--; if (histPos < 1) { histPos = 1; } ev.target.value = pastInps[histPos].value; nd = true; break; case "ArrowDown": histPos++; if (histPos > pastInps.length) { histPos = pastInps.length; } ev.target.value = (pastInps[histPos] || { value: "" }).value; nd = true; break; case "Enter": if (ev.target.value.trim() != "") { evalInp(); nextInp(); } nd = true; break; default: break; } if (nd) { ev.preventDefault(); } } function evalInp() { let disp; let perr = false; const ci = document.getElementById("cil" + pastInps.length.toString()); const st = ci.value.split(";"); for (let i = 0; i < st.length; i++) { const wt = st[i]; const lexer = new TokenStream(wt); try { const ast = NewParser.statement(lexer); if (ast === null) { disp = "syntax error"; break; } else { perr = perr || (lexer.tind != lexer.toks.length - 1); document.body.style.cursor = "wait"; try { const res = ast.evaluate(calcVars, false); if (res != null) { calcVars["_"] = res; } const svn = "_" + pastInps.length.toString(); calcVars[svn] = res; disp = (res == null) ? "evaluation error" : (svn + " = " + fts(res)); } catch (err) { disp = err; } document.body.style.cursor = "auto"; } } catch (err) { disp = err; } } ioLog(disp); if (perr) { ioLog("possible syntax error"); } } // disable the current input line, add its contents to history, // and add a new input line function nextInp() { const prev = (document.getElementById("cil" + pastInps.length.toString()) || {}); prev.onkeydown = null; prev.disabled = true; pastInps.push(prev); const newi = document.createElement("input"); newi.id = "cil" + pastInps.length.toString(); newi.onkeydown = inpKeyHandler; newi.type = "text"; iol.append("> "); iol.appendChild(newi); document.getElementById("cil" + pastInps.length.toString()).focus(); histPos = pastInps.length; } function vce(t) { t.split("\n").forEach(l => { if (l.trim() != "") { iol.lastElementChild.value = l; evalInp(); nextInp(); } }); } const ech = document.getElementsByClassName("excode"); for (let i = 0; i < ech.length; i++) { ech[i].ondblclick = ev => vce(ev.target.innerText); } window.onbeforeunload = ev => (pastInps.length > 1 ? "Quit RTensor?" : undefined); // create a link for a version of the calculator using each numeric type Object.keys(NUMERIC_TYPES).forEach(ntn => { const le = document.createElement("a"); le.innerText = " " + ntn; le.href = "?nt=" + ntn; document.body.insertBefore(le, iol); }); document.body.insertBefore(document.createElement("br"), iol); bci.onchange = ev => { // split by lines, except with backslash continuation ev.target.value.split(/(?<!\\)\n/g). // remove backslash continuation map(l => l.replace(/\\\n/g, "\n")). // remove comments and blank lines filter(l => l.replace(/#.*/, "").trim()). forEach(l => { const ci = document.getElementById("cil" + pastInps.length.toString()); ci.value = l; evalInp(); nextInp(); }); ev.target.value = ""; }; nextInp(); /*]]>*/ </script> </body> </html>