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, "&" as *u8) } else {
165 if c == 0x3C { o = mp_put(b, o, "<" as *u8) } else {
166 if c == 0x3E { o = mp_put(b, o, ">" as *u8) } else {
167 if c == 0x22 { o = mp_put(b, o, """ as *u8) } else {
168 if c == 0x27 { o = mp_put(b, o, "'" 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, " — " 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 — 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}