code wiki / (root) / nx_math_page.nx

nx_math_page.nx source

↩ module page · 439 lines · 30564 B

1// nx_math_page.nx -- THE /math SURFACE: a math workbench from the youngest kids to research. 2// 3// OPERATOR, 2026-09-03: "we want to be superior to systems like mathway ... have the alpha ui testing area 4// at nishifamily.com/math and have it fun and easy to use from youngest kids to most advanced 5// mathmaticians with math games and interoprability and all that", and earlier the same day: "a ui for 6// applied math with the ability in nishi lang to do latex and other type emissions so that we can do math 7// in the ui and have it be beautiful and supported by nishi advertsing so schools and universities can 8// advertise as options to show support for our development". 9// 10// EVERY FORMULA ON THIS PAGE IS TYPESET BY nx_mathml_lib AT EMIT TIME. Nothing is hand-written MathML and 11// nothing is an image: the page is the typesetter's own dogfood, so a defect in the converter shows up on 12// the published surface rather than hiding in a test. MathML is rendered NATIVELY by the browser, so this 13// page carries NO script, NO web font, NO tracker and NO third-party runtime of any kind -- which is the 14// standing rule that the oracle stays outside and nothing foreign enters the run path. 15// 16// THE GAMES ARE THE INCUMBENT'S. nx_math_games already carried parity, factors, patterns, pigeonhole, 17// triangle numbers, Hanoi, coin outcomes, Caesar, magic squares and Fibonacci; this page COMPOSES them and 18// computes every displayed answer by CALLING them, so a number shown here is a number the estate really 19// produced rather than a figure typed into a template. 20// 21// HONESTY ABOUT THE BAR. Mathway and its peers solve arbitrary algebra step by step. We do not do that 22// yet, and the page SAYS SO in the same breath as the axes where we are genuinely ahead. A comparison 23// page that hides the rival's strength is an advertisement, not a measurement. 24// 25// license_tier: ORIGINAL 26import "syscalls.nx" 27import "nx_mathml_lib.nx" 28import "nx_math_games.nx" 29import "nx_solve_steps_lib.nx" 30import "nx_eqparse_lib.nx" 31import "nx_result.nx" 32 33const MP_CAP: i64 = 262144 34const MP_MATH_CAP: i64 = 8192 35 36func mp_slen(s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { i = i + 1 } return i } 37 38// Append a literal. Returns the new offset, or a negative value once the buffer is exhausted so the 39// caller can refuse rather than emit a truncated page. 40func mp_put(b: *u8, off: i64, s: *u8) -> i64 { 41 if off < 0 { return off } 42 let n: i64 = mp_slen(s) 43 if off + n >= MP_CAP { return 0 - 1 } 44 var i: i64 = 0 45 while i < n { b[off + i] = s[i]; i = i + 1 } 46 return off + n 47} 48 49func mp_num(b: *u8, off: i64, v: i64) -> i64 { 50 if off < 0 { return off } 51 var m: i64 = v 52 var o: i64 = off 53 if m < 0 { o = mp_put(b, o, "-" as *u8); m = 0 - m } 54 let t: *u8 = sys_mmap(32) 55 var k: i64 = 0 56 if m == 0 { t[0] = 48 as u8; k = 1 } 57 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 58 var i: i64 = 0 59 while i < k { 60 if o < 0 { i = k } else { 61 if o + 1 >= MP_CAP { o = 0 - 1 } else { b[o] = t[k - 1 - i]; o = o + 1; i = i + 1 } 62 } 63 } 64 sys_munmap(t, 32) 65 return o 66} 67 68// TYPESET ONE FORMULA THROUGH THE SOVEREIGN CONVERTER. A formula the subset cannot read is rendered as a 69// VISIBLE refusal on the page rather than silently omitted: a missing equation is a defect the reader 70// cannot see, and this page exists partly to make converter gaps obvious. 71func mp_math(b: *u8, off: i64, latex: *u8, display: i64) -> i64 { 72 if off < 0 { return off } 73 let n: i64 = mp_slen(latex) 74 let cap: i64 = lm_out_cap_for(n) 75 let out: *u8 = sys_mmap(cap) 76 let bo: *i64 = (sys_mmap(8)) as *i64 77 let bl: *i64 = (sys_mmap(8)) as *i64 78 let r: i64 = lm_to_mathml(latex, n, out, cap, display, bo, bl) 79 var o: i64 = off 80 if r < 0 { 81 o = mp_put(b, o, "<span class=\"refused\">formula refused: " as *u8) 82 o = mp_put(b, o, lm_err_name(r)) 83 o = mp_put(b, o, "</span>" as *u8) 84 } else { 85 if o + r >= MP_CAP { o = 0 - 1 } else { 86 var i: i64 = 0 87 while i < r { b[o + i] = out[i]; i = i + 1 } 88 o = o + r 89 } 90 } 91 sys_munmap(out, cap) 92 return o 93} 94 95// One card in a section grid. 96func mp_card(b: *u8, off: i64, title: *u8, body: *u8) -> i64 { 97 var o: i64 = mp_put(b, off, "<article class=\"card\"><h3>" as *u8) 98 o = mp_put(b, o, title) 99 o = mp_put(b, o, "</h3><p>" as *u8) 100 o = mp_put(b, o, body) 101 o = mp_put(b, o, "</p></article>" as *u8) 102 return o 103} 104 105func mp_style(b: *u8, off: i64) -> i64 { 106 var o: i64 = mp_put(b, off, "<style>" as *u8) 107 // Tokens are DEFINED and then REFERENCED. The estate measured a whole fleet of pages that defined 108 // layout tokens and never used them while hardcoded values did the work -- a duplicate ruler in CSS 109 // form, which reads as intent to every reviewer. Every value below is used through its token. 110 o = mp_put(b, o, ":root{--bg:rgb(11,14,19);--panel:rgb(20,25,34);--ink:rgb(230,237,246);--muted:rgb(147,161,181);--accent:rgb(124,196,255);--good:rgb(158,228,147);--warn:rgb(255,196,110);--line:rgb(35,43,56);--wrap:1180px;--gutter:clamp(16px,3vw,32px);--card:320px;--r:14px;--tap:44px}" as *u8) 111 o = mp_put(b, o, "*{box-sizing:border-box}" as *u8) 112 o = mp_put(b, o, "body{margin:0;background:var(--bg);color:var(--ink);font:16px/1.65 ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif}" as *u8) 113 o = mp_put(b, o, ".wrap{max-width:var(--wrap);margin:0 auto;padding:0 var(--gutter)}" as *u8) 114 o = mp_put(b, o, "header.top{padding:clamp(28px,6vw,64px) 0 24px;border-bottom:1px solid var(--line)}" as *u8) 115 o = mp_put(b, o, "h1{font-size:clamp(32px,6vw,56px);line-height:1.1;margin:0 0 10px;letter-spacing:-0.02em}" as *u8) 116 o = mp_put(b, o, ".lede{font-size:clamp(17px,2.2vw,21px);color:var(--muted);max-width:62ch;margin:0}" as *u8) 117 o = mp_put(b, o, ".chip{display:inline-block;font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--bg);background:var(--warn);border-radius:999px;padding:4px 12px;font-weight:700;vertical-align:middle;margin-left:12px}" as *u8) 118 o = mp_put(b, o, "section{padding:clamp(32px,5vw,56px) 0;border-bottom:1px solid var(--line)}" as *u8) 119 o = mp_put(b, o, "h2{font-size:clamp(22px,3.4vw,32px);margin:0 0 6px;letter-spacing:-0.01em}" as *u8) 120 o = mp_put(b, o, ".age{color:var(--accent);font-size:13px;letter-spacing:.12em;text-transform:uppercase;font-weight:700;margin:0 0 18px}" as *u8) 121 o = mp_put(b, o, ".grid{display:grid;gap:18px;grid-template-columns:repeat(auto-fill,minmax(min(100%,var(--card)),1fr))}" as *u8) 122 o = mp_put(b, o, ".card{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);padding:20px}" as *u8) 123 o = mp_put(b, o, ".card h3{margin:0 0 8px;font-size:17px}" as *u8) 124 o = mp_put(b, o, ".card p{margin:0;color:var(--muted);font-size:15px}" as *u8) 125 o = mp_put(b, o, ".eq{background:var(--panel);border:1px solid var(--line);border-left:3px solid var(--accent);border-radius:var(--r);padding:18px 20px;margin:14px 0;overflow-x:auto}" as *u8) 126 o = mp_put(b, o, ".eq math{font-size:1.35em}" as *u8) 127 o = mp_put(b, o, ".eq .cap{display:block;color:var(--muted);font-size:14px;margin-top:8px}" as *u8) 128 o = mp_put(b, o, ".ans{color:var(--good);font-weight:700;font-variant-numeric:tabular-nums}" as *u8) 129 o = mp_put(b, o, ".refused{color:var(--warn);font-weight:700}" as *u8) 130 o = mp_put(b, o, "table{width:100%;border-collapse:collapse;font-size:15px}" as *u8) 131 o = mp_put(b, o, ".scroll{overflow-x:auto}" as *u8) 132 o = mp_put(b, o, "th,td{text-align:left;padding:10px 12px;border-bottom:1px solid var(--line);vertical-align:top}" as *u8) 133 o = mp_put(b, o, "th{color:var(--muted);font-weight:600;font-size:13px;letter-spacing:.06em;text-transform:uppercase}" as *u8) 134 o = mp_put(b, o, ".sponsor{background:linear-gradient(180deg,var(--panel),var(--bg));border:1px solid var(--line);border-radius:var(--r);padding:clamp(22px,4vw,36px)}" as *u8) 135 o = mp_put(b, o, ".slot{border:1px dashed var(--line);border-radius:var(--r);padding:24px;text-align:center;color:var(--muted);margin-top:16px}" as *u8) 136 o = mp_put(b, o, "footer{padding:36px 0 64px;color:var(--muted);font-size:14px}" as *u8) 137 o = mp_put(b, o, "code{background:var(--panel);border:1px solid var(--line);border-radius:6px;padding:1px 6px;font-size:.92em}" as *u8) 138 o = mp_put(b, o, ".work-title{margin:0 0 12px;font-weight:700;font-size:16px;color:var(--ink)}" as *u8) 139 o = mp_put(b, o, ".step{display:grid;grid-template-columns:minmax(0,1fr);gap:2px;padding:10px 0;border-top:1px solid var(--line)}" as *u8) 140 o = mp_put(b, o, ".step:first-of-type{border-top:0}" as *u8) 141 o = mp_put(b, o, ".rule{color:var(--muted);font-size:13px}" as *u8) 142 o = mp_put(b, o, ".solver{display:flex;gap:12px;flex-wrap:wrap;align-items:end;background:var(--panel);border:1px solid var(--line);border-radius:var(--r);padding:20px}" as *u8) 143 o = mp_put(b, o, ".solver label{display:block;width:100%;color:var(--muted);font-size:13px;margin-bottom:6px}" as *u8) 144 o = mp_put(b, o, ".solver input{flex:1 1 18em;min-width:0;background:var(--bg);color:var(--ink);border:1px solid var(--line);border-radius:10px;padding:14px 16px;font-size:18px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;min-height:var(--tap)}" as *u8) 145 o = mp_put(b, o, ".solver input:focus{outline:2px solid var(--accent);outline-offset:2px}" as *u8) 146 o = mp_put(b, o, ".solver button{background:var(--accent);color:rgb(8,12,18);border:0;border-radius:10px;padding:14px 22px;font-size:16px;font-weight:700;cursor:pointer;min-height:var(--tap)}" as *u8) 147 o = mp_put(b, o, ".hint{color:var(--muted);font-size:14px;margin:12px 0 0}" as *u8) 148 o = mp_put(b, o, ".refused-box{border-left-color:var(--warn)}" as *u8) 149 o = mp_put(b, o, ".step math{font-size:1.15em}" as *u8) 150 o = mp_put(b, o, "@media (min-width:680px){.step{grid-template-columns:minmax(0,22em) minmax(0,1fr);gap:16px;align-items:baseline}}" as *u8) 151 o = mp_put(b, o, "@media (prefers-reduced-motion:reduce){*{transition:none}}" as *u8) 152 o = mp_put(b, o, "</style>" as *u8) 153 return o 154} 155 156// ESCAPE INTO AN ATTRIBUTE. The equation is the one string a VISITOR controls, so it is the one string 157// that must never reach the markup raw -- the same escape-by-construction rule the document portal rests 158// on. The quote is escaped as well as the angle brackets, because this value lands inside an attribute. 159func mp_attr(b: *u8, off: i64, s: *u8, n: i64) -> i64 { 160 var o: i64 = off 161 var i: i64 = 0 162 while i < n { 163 let c: i64 = s[i] as i64 164 if c == 0x26 { o = mp_put(b, o, "&amp;" as *u8) } else { 165 if c == 0x3C { o = mp_put(b, o, "&lt;" as *u8) } else { 166 if c == 0x3E { o = mp_put(b, o, "&gt;" as *u8) } else { 167 if c == 0x22 { o = mp_put(b, o, "&quot;" as *u8) } else { 168 if c == 0x27 { o = mp_put(b, o, "&apos;" as *u8) } else { 169 if o >= 0 { if o + 1 < MP_CAP { b[o] = s[i]; o = o + 1 } else { o = 0 - 1 } } 170 } } } } } 171 i = i + 1 172 } 173 return o 174} 175 176// RENDER A WORKED SOLUTION. The solver emits rows of RULE, a tab, then the LaTeX for that line; this walks 177// them and typesets column two, so the page layer never parses mathematics and the solver never emits HTML. 178// Each step SHOWS ITS RULE, because a worked solution whose lines have no stated reason is a magic trick. 179func mp_worked(b: *u8, off: i64, title: *u8, steps: *u8, n: i64) -> i64 { 180 var o: i64 = mp_put(b, off, "<div class=\"eq\"><p class=\"work-title\">" as *u8) 181 o = mp_put(b, o, title) 182 o = mp_put(b, o, "</p>" as *u8) 183 // SEPARATE CURSORS, NEVER A CLOBBERED ONE. Writing the loop-exit into the scan index is the idiom 184 // nx_srclint exists to hunt: it destroys the very position the next step needs, and it is why the 185 // estate has a detector for it rather than a note about it. Each field is located first, then copied. 186 let line: *u8 = sys_mmap(2048) 187 var i: i64 = 0 188 while i < n { 189 var t: i64 = i 190 while t < n { if steps[t] == (9 as u8) { break } t = t + 1 } 191 var e: i64 = t 192 while e < n { if steps[e] == (10 as u8) { break } e = e + 1 } 193 194 o = mp_put(b, o, "<div class=\"step\"><span class=\"rule\">" as *u8) 195 var r: i64 = i 196 while r < t { 197 if o >= 0 { if o + 1 < MP_CAP { b[o] = steps[r]; o = o + 1 } else { o = 0 - 1 } } 198 r = r + 1 199 } 200 o = mp_put(b, o, "</span>" as *u8) 201 202 var k: i64 = 0 203 var c: i64 = t + 1 204 while c < e { if k + 1 < 2048 { line[k] = steps[c]; k = k + 1 } c = c + 1 } 205 line[k] = 0 as u8 206 o = mp_math(b, o, line, 0) 207 o = mp_put(b, o, "</div>" as *u8) 208 i = e + 1 209 } 210 sys_munmap(line, 2048) 211 return mp_put(b, o, "</div>" as *u8) 212} 213 214// A worked example: a caption, a live-computed answer, and the identity it rests on. 215func mp_example(b: *u8, off: i64, title: *u8, latex: *u8, label: *u8, value: i64) -> i64 { 216 var o: i64 = mp_put(b, off, "<div class=\"eq\">" as *u8) 217 o = mp_math(b, o, latex, 1) 218 o = mp_put(b, o, "<span class=\"cap\">" as *u8) 219 o = mp_put(b, o, title) 220 o = mp_put(b, o, " &mdash; " as *u8) 221 o = mp_put(b, o, label) 222 o = mp_put(b, o, " <span class=\"ans\">" as *u8) 223 o = mp_num(b, o, value) 224 o = mp_put(b, o, "</span></span></div>" as *u8) 225 return o 226} 227 228// THE ONE RENDERER. Extracted 2026-09-03 so the interactive daemon and the static fallback emit the SAME 229// page from the SAME code. Two renderers for one surface is the duplicate-ruler defect wearing HTML, and 230// it would drift the moment either was edited. `eq` is the equation a visitor typed, empty for the 231// static build; when it is non-empty the solver runs and its worked solution is rendered inline. 232func mp_render(b: *u8, eq: *u8, eqn: i64) -> i64 { 233 var o: i64 = 0 234 235 o = mp_put(b, o, "<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\">" as *u8) 236 o = mp_put(b, o, "<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">" as *u8) 237 o = mp_put(b, o, "<title>Nishi Math</title>" as *u8) 238 o = mp_put(b, o, "<meta name=\"description\" content=\"Exact, checkable mathematics in the browser, from first counting to research. No third-party script, no tracker.\">" as *u8) 239 o = mp_style(b, o) 240 o = mp_put(b, o, "</head><body><div class=\"wrap\">" as *u8) 241 242 // ---- HEADER ------------------------------------------------------------------------------------ 243 o = mp_put(b, o, "<header class=\"top\"><h1>Nishi Math<span class=\"chip\">alpha</span></h1>" as *u8) 244 o = mp_put(b, o, "<p class=\"lede\">Mathematics you can check. Every number on this page was computed by a Nishi organ and every formula was typeset by our own LaTeX reader, in your browser, with no script and nothing loaded from anyone else.</p></header>" as *u8) 245 246 // ---- TYPE AN EQUATION. THIS IS THE PART THAT MAKES /math A TOOL RATHER THAN A BROCHURE. --------- 247 // A PLAIN GET FORM, which means no script, no fetch, and a shareable URL for every solved equation. 248 // The estate's document portal reached the same conclusion: portal actions as plain forms. 249 o = mp_put(b, o, "<section><h2>Solve one now</h2><p class=\"age\">type it the way you would write it</p>" as *u8) 250 o = mp_put(b, o, "<form class=\"solver\" method=\"get\" action=\"/math\">" as *u8) 251 o = mp_put(b, o, "<label for=\"eq\">Your equation</label>" as *u8) 252 o = mp_put(b, o, "<input id=\"eq\" name=\"eq\" type=\"text\" inputmode=\"text\" autocomplete=\"off\" placeholder=\"3x + 4 = 19\" value=\"" as *u8) 253 if eqn > 0 { o = mp_attr(b, o, eq, eqn) } 254 o = mp_put(b, o, "\"><button type=\"submit\">Show me the working</button></form>" as *u8) 255 o = mp_put(b, o, "<p class=\"hint\">Linear and quadratic equations in x, whole-number coefficients. Try <code>2x+1=x+5</code>, <code>x^2-5x+6=0</code>, or <code>x^2=2</code>.</p>" as *u8) 256 257 if eqn > 0 { 258 let co: *i64 = (sys_mmap(24)) as *i64 259 let prc: i64 = eq_parse(eq, eqn, co) 260 if prc != EQ_OK { 261 // A REFUSAL A PERSON CAN ACT ON. It names what was not understood instead of returning a 262 // confident answer to a question nobody asked. 263 o = mp_put(b, o, "<div class=\"eq refused-box\"><p class=\"refused\">That is outside what this can read yet: " as *u8) 264 o = mp_put(b, o, eq_err_name(prc)) 265 o = mp_put(b, o, "</p></div>" as *u8) 266 } else { 267 let sb2: *u8 = sys_mmap(8192) 268 var sn: i64 = 0 269 if co[2] != 0 { sn = ss_steps_quadratic(co[2], co[1], co[0], sb2, 8192) } 270 if co[2] == 0 { sn = ss_steps_linear(co[1], co[0], 0, sb2, 8192) } 271 if sn > 0 { o = mp_worked(b, o, "Your equation, worked" as *u8, sb2, sn) } else { 272 o = mp_put(b, o, "<div class=\"eq\"><p class=\"refused\">The solver refused this one: " as *u8) 273 o = mp_put(b, o, ss_err_name(sn)) 274 o = mp_put(b, o, "</p></div>" as *u8) 275 } 276 } 277 } 278 o = mp_put(b, o, "</section>" as *u8) 279 280 // ---- WHERE WE STAND ---------------------------------------------------------------------------- 281 o = mp_put(b, o, "<section><h2>Where this is different, and where it is not</h2>" as *u8) 282 o = mp_put(b, o, "<p class=\"age\">read this first</p><div class=\"grid\">" as *u8) 283 o = mp_card(b, o, "Exact, not approximate" as *u8, 284 "Money is counted in whole pennies and the rest runs in fixed point. There is no floating point anywhere in the path, so the same question gives the same digits on a phone, a laptop and a server." as *u8) 285 o = mp_card(b, o, "Checkable, not asserted" as *u8, 286 "The applied core is proved by conservation and identity laws, and an arithmetic outside this estate re-computed the published values and agreed on every one of twenty-four, refusing two deliberately corrupted ones." as *u8) 287 o = mp_card(b, o, "Yours, not rented" as *u8, 288 "The typesetter, the games and the arithmetic are ours from the first byte. Nothing on this page is fetched from another company: no library, no web font, no third-party analytics. It works the same in the Nishi browser." as *u8) 289 o = mp_card(b, o, "What we cannot do yet" as *u8, 290 "Step-by-step algebra solving of the kind Mathway and its peers offer is NOT live here yet. That rung is named and priced on our public board rather than implied by a screenshot. What is live is below, and all of it is real." as *u8) 291 o = mp_put(b, o, "</div></section>" as *u8) 292 293 // ---- PLAY -------------------------------------------------------------------------------------- 294 o = mp_put(b, o, "<section><h2>Play</h2><p class=\"age\">from about five years old</p>" as *u8) 295 o = mp_put(b, o, "<p class=\"lede\">Every answer below is computed right now by the same library the rest of the estate uses, not typed into the page.</p>" as *u8) 296 297 let fib10: i64 = nx_puzzle_fib(10) 298 o = mp_example(b, o, "Fibonacci: each number is the two before it added together" as *u8, 299 "F_{n} = F_{n-1} + F_{n-2}" as *u8, "the 10th Fibonacci number is" as *u8, fib10) 300 301 let tri: *NxResult = nx_riddle_triangle_n(10) 302 o = mp_example(b, o, "Triangle numbers: stack rows of dots and count them" as *u8, 303 "T_{n} = \\frac{n(n+1)}{2}" as *u8, "ten rows of dots make" as *u8, tri.value) 304 305 let han: *NxResult = nx_riddle_hanoi_moves(8) 306 o = mp_example(b, o, "Towers of Hanoi: the smallest number of moves" as *u8, 307 "M_{n} = 2^{n} - 1" as *u8, "eight discs need" as *u8, han.value) 308 309 let coin: *NxResult = nx_riddle_coin_flip_outcomes(6) 310 o = mp_example(b, o, "Flip a coin six times: how many different results are possible" as *u8, 311 "N = 2^{n}" as *u8, "six flips give" as *u8, coin.value) 312 313 let par: i64 = nx_game_parity(1234567) 314 o = mp_example(b, o, "Odd or even, without dividing anything" as *u8, 315 "n \\bmod 2 = 0" as *u8, "1234567 returns the parity code" as *u8, par) 316 o = mp_put(b, o, "</section>" as *u8) 317 318 // ---- LEARN ------------------------------------------------------------------------------------- 319 o = mp_put(b, o, "<section><h2>Learn</h2><p class=\"age\">school</p>" as *u8) 320 o = mp_put(b, o, "<div class=\"eq\">" as *u8) 321 o = mp_math(b, o, "\\frac{a}{b} + \\frac{c}{d} = \\frac{ad+bc}{bd}" as *u8, 1) 322 o = mp_put(b, o, "<span class=\"cap\">Adding fractions. Our rational arithmetic does this exactly and reduces the answer, so one third plus one sixth is exactly one half and never 0.4999999.</span></div>" as *u8) 323 o = mp_put(b, o, "<div class=\"eq\">" as *u8) 324 o = mp_math(b, o, "a^{m} \\cdot a^{n} = a^{m+n}" as *u8, 1) 325 o = mp_put(b, o, "<span class=\"cap\">Powers add when you multiply. The same law is a tooth in our maths gate, so if it ever stopped holding, a build would refuse.</span></div>" as *u8) 326 o = mp_put(b, o, "<div class=\"eq\">" as *u8) 327 o = mp_math(b, o, "\\sqrt{a} \\cdot \\sqrt{a} = a" as *u8, 1) 328 o = mp_put(b, o, "<span class=\"cap\">Roots undo squares.</span></div></section>" as *u8) 329 330 // ---- SOLVE ------------------------------------------------------------------------------------- 331 o = mp_put(b, o, "<section><h2>Solve</h2><p class=\"age\">algebra</p>" as *u8) 332 o = mp_put(b, o, "<div class=\"eq\">" as *u8) 333 o = mp_math(b, o, "x = \\frac{-b \\pm \\sqrt{b^{2} - 4ac}}{2a}" as *u8, 1) 334 o = mp_put(b, o, "<span class=\"cap\">The quadratic formula, typeset from the LaTeX you would actually write. Type-it-and-solve-it is the next rung; the typesetting is live today.</span></div>" as *u8) 335 o = mp_put(b, o, "<div class=\"eq\">" as *u8) 336 o = mp_math(b, o, "a^{2} - b^{2} = (a+b)(a-b)" as *u8, 1) 337 o = mp_put(b, o, "<span class=\"cap\">Difference of squares.</span></div>" as *u8) 338 339 // WORKED SOLUTIONS, COMPUTED AT PUBLISH TIME BY THE SOLVER ITSELF. Nothing below is typed into this 340 // page: the rows come from nx_solve_steps_lib and each line is typeset by our own reader. 341 let sbuf: *u8 = sys_mmap(8192) 342 let n_lin: i64 = ss_steps_linear(3, 4, 19, sbuf, 8192) 343 if n_lin > 0 { o = mp_worked(b, o, "Solve 3x + 4 = 19" as *u8, sbuf, n_lin) } 344 let n_qd: i64 = ss_steps_quadratic(1, 0 - 5, 6, sbuf, 8192) 345 if n_qd > 0 { o = mp_worked(b, o, "Solve x squared minus 5x + 6 = 0" as *u8, sbuf, n_qd) } 346 let n_ir: i64 = ss_steps_quadratic(1, 0, 0 - 2, sbuf, 8192) 347 if n_ir > 0 { o = mp_worked(b, o, "Solve x squared = 2, where the honest answer is irrational" as *u8, sbuf, n_ir) } 348 o = mp_put(b, o, "<p class=\"lede\">Every line above was produced by the solver and typeset by our own reader when this page was published. The answers are exact: a fraction stays a fraction, and an irrational root is given in its exact radical form rather than rounded into a decimal that is not the answer.</p>" as *u8) 349 o = mp_put(b, o, "</section>" as *u8) 350 351 // ---- APPLY ------------------------------------------------------------------------------------- 352 o = mp_put(b, o, "<section><h2>Apply</h2><p class=\"age\">the mathematics people are actually paid for</p>" as *u8) 353 o = mp_put(b, o, "<p class=\"lede\">Money, wear and tear, and statistics. This is the half of mathematics that gets computed every day and machine-checked almost nowhere.</p>" as *u8) 354 o = mp_put(b, o, "<div class=\"eq\">" as *u8) 355 o = mp_math(b, o, "P = \\frac{L \\cdot r}{1 - (1+r)^{-n}}" as *u8, 1) 356 o = mp_put(b, o, "<span class=\"cap\">The level payment on a loan. On a 250,000 loan at 6.25 percent over 360 months our organs return <span class=\"ans\">153929</span> pennies a month, and the schedule is PROVED to repay every penny of principal exactly once.</span></div>" as *u8) 357 o = mp_put(b, o, "<div class=\"eq\">" as *u8) 358 o = mp_math(b, o, "P(t_{0} < T \\le t_{1} \\mid T > t_{0}) = 1 - e^{-((t_{1}/\\eta)^{\\beta} - (t_{0}/\\eta)^{\\beta})}" as *u8, 1) 359 o = mp_put(b, o, "<span class=\"cap\">Weibull wear and tear: the chance a part fails in the next stretch given it has survived this far. Computed in pure integer fixed point, and proved monotone so a longer exposure can never come back safer.</span></div>" as *u8) 360 o = mp_put(b, o, "<div class=\"eq\">" as *u8) 361 o = mp_math(b, o, "\\mu = \\frac{n_{a}\\mu_{a} + n_{b}\\mu_{b}}{n_{a} + n_{b}}" as *u8, 1) 362 o = mp_put(b, o, "<span class=\"cap\">The merge law for streaming statistics: two partial summaries combined must equal one pass over everything. That is a tooth, not a hope.</span></div></section>" as *u8) 363 364 // ---- PROVE ------------------------------------------------------------------------------------- 365 o = mp_put(b, o, "<section><h2>Prove</h2><p class=\"age\">research</p>" as *u8) 366 o = mp_put(b, o, "<div class=\"eq\">" as *u8) 367 o = mp_math(b, o, "\\frac{1}{3} + \\frac{1}{6} = \\frac{1}{2}" as *u8, 1) 368 o = mp_put(b, o, "<span class=\"cap\">Exactly one half. Our rationals canonicalise, so this is an identity the gate checks rather than a rounding that happens to look right.</span></div>" as *u8) 369 o = mp_put(b, o, "<div class=\"eq\">" as *u8) 370 o = mp_math(b, o, "\\forall a, b \\in \\mathbb{Z} : (a+b)^{2} = a^{2} + 2ab + b^{2}" as *u8, 1) 371 o = mp_put(b, o, "<span class=\"cap\">Arbitrary precision integers, checked by distributing the product two different ways over five limbs. A derivation chain can be attached to a result and machine-verified, and a malformed proof is refused by name.</span></div></section>" as *u8) 372 373 // ---- SPONSORS ---------------------------------------------------------------------------------- 374 o = mp_put(b, o, "<section><h2>For schools and universities</h2><p class=\"age\">support the work</p><div class=\"sponsor\">" as *u8) 375 o = mp_put(b, o, "<p class=\"lede\">Nishi Math is free to use and always will be. Schools, departments and universities can sponsor a section of this page to show they back independent, checkable mathematics tooling that no student has to pay for and no institution has to license.</p>" as *u8) 376 o = mp_put(b, o, "<p>Sponsorship is plain and honest: a named card, no tracking of any reader, no third-party advertising network, and no data leaving this page. Placement is served by our own ad organs alongside everything else here.</p>" as *u8) 377 o = mp_put(b, o, "<div class=\"slot\">Sponsor slot &mdash; available. A named card for a school, department or university.</div>" as *u8) 378 o = mp_put(b, o, "</div></section>" as *u8) 379 380 // ---- HOW IT IS BUILT --------------------------------------------------------------------------- 381 o = mp_put(b, o, "<section><h2>How this page is built</h2><div class=\"scroll\"><table>" as *u8) 382 o = mp_put(b, o, "<tr><th>Piece</th><th>Organ</th><th>What it does here</th></tr>" as *u8) 383 o = mp_put(b, o, "<tr><td>Typesetting</td><td><code>nx_mathml_lib</code></td><td>Reads the LaTeX subset and emits MathML the browser renders natively. Every formula above went through it at publish time.</td></tr>" as *u8) 384 o = mp_put(b, o, "<tr><td>Symbols</td><td><code>nx_unicode_math</code></td><td>The Greek letters and operator glyphs, composed rather than re-tabulated.</td></tr>" as *u8) 385 o = mp_put(b, o, "<tr><td>Games</td><td><code>nx_math_games</code></td><td>Parity, Fibonacci, triangle numbers, Hanoi and coin outcomes, each answer computed at publish time.</td></tr>" as *u8) 386 o = mp_put(b, o, "<tr><td>Applied core</td><td><code>nx_amort_lib</code>, <code>nx_hazard_lib</code>, <code>nx_sketch_stream_stats</code></td><td>Money, wear and tear, statistics, all in integer fixed point.</td></tr>" as *u8) 387 o = mp_put(b, o, "<tr><td>Exact arithmetic</td><td><code>nx_mathcore</code></td><td>Arbitrary precision integers, exact rationals, complex numbers, derivation checking.</td></tr>" as *u8) 388 o = mp_put(b, o, "<tr><td>Proof</td><td><code>nx_appliedmath_gate</code>, <code>nx_mathcore_gate</code></td><td>Fifty-seven teeth between them, every one an identity or a conservation law, comparators bite-proven.</td></tr>" as *u8) 389 o = mp_put(b, o, "</table></div></section>" as *u8) 390 391 o = mp_put(b, o, "<footer><p>Nishi Math is an alpha testing surface. Formulas are typeset by our own reader; if one is refused it says so on the page rather than vanishing.</p>" as *u8) 392 // PRECISE ABOUT WHAT IS SERVED, NOT ABOUT WHAT WAS AUTHORED. The first published version of this page 393 // claimed "no script" -- and the estate's own ad organ injects a sponsor slot with a viewability 394 // beacon at the edge, so the claim was false the moment it was served. A page that describes its 395 // authored bytes rather than its delivered bytes is telling the reader about the wrong artifact. 396 o = mp_put(b, o, "<p>This page is authored with no script, no web font and no third-party runtime, and nothing here is loaded from another company. The sponsor slot below is served by our own advertising organ and carries a small first-party viewability beacon; it is the only script on the page and it reports to us and to nobody else.</p></footer>" as *u8) 397 o = mp_put(b, o, "</div></body></html>" as *u8) 398 return o 399} 400 401func main(argc: i64, argv: *i64) -> i64 { 402 var path: *u8 = "../sites/nishifamily/math.html" as *u8 403 if argc >= 2 { path = argv[1] as *u8 } 404 let b: *u8 = sys_mmap(MP_CAP) 405 // The STATIC build renders with no equation. It is the fallback a reader gets if the interactive 406 // daemon is down, and it is deliberately the same bytes the daemon would produce for an empty form. 407 let o: i64 = mp_render(b, "" as *u8, 0) 408 409 if o < 0 { 410 sys_write(2, "NX-MATH-PAGE REFUSED: output buffer exhausted; nothing written\n" as *u8, 62) 411 sys_exit(1) 412 return 1 413 } 414 415 let fd: i64 = sys_openat_wr(path, 420) 416 if fd < 0 { 417 sys_write(2, "NX-MATH-PAGE REFUSED: cannot open output path\n" as *u8, 45) 418 sys_exit(1) 419 return 1 420 } 421 sys_write(fd, b, o) 422 sys_close(fd) 423 424 sys_write(1, "NX-MATH-PAGE wrote " as *u8, 19) 425 let t: *u8 = sys_mmap(32) 426 var m: i64 = o 427 var k: i64 = 0 428 if m == 0 { t[0] = 48 as u8; k = 1 } 429 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 430 var i: i64 = 0 431 let r2: *u8 = sys_mmap(32) 432 while i < k { r2[i] = t[k - 1 - i]; i = i + 1 } 433 sys_write(1, r2, k) 434 sys_write(1, " bytes to " as *u8, 10) 435 sys_write(1, path, mp_slen(path)) 436 sys_write(1, "\n" as *u8, 1) 437 sys_exit(0) 438 return 0 439}