nx_swarm_tile.nx source
↩ module page · 387 lines · 15585 B
1// nx_swarm_tile.nx -- SWARM FABRIC chunk EXECUTOR (SF-R3 real-artifact): a sovereign, embarrassingly-
2// parallel image generator. Each "chunk" = a horizontal BAND of a fixed-point Mandelbrot render; bands
3// are INDEPENDENT (no cross-tile state) = the exact workload class the operator named (3D render / Monte
4// Carlo / brute-force). The job engine (nx_swarm_job) stays GENERIC -- it leases opaque chunk ids; THIS
5// organ turns chunk id -> real pixels; a DRIVER wires place->lease->render->complete->assemble (rule 9).
6// Proves the north-star "generate an image by combining/parallelizing across the fabric" with REAL output
7// (was SIMULATED in the SF-R3 gate). When remote workers join, the SAME job engine dispatches the SAME
8// bands to them -- distribution is placement, already proven; this is the executor + assembler.
9//
10// render <W> <H> <ntiles> <tile_id> <outdir> -- render band tile_id -> outdir/tile_<id>.raw (RGB)
11// assemble <W> <H> <ntiles> <outdir> <out.ppm> -- stitch bands in order -> a real P6 PPM image
12// [gate] -- self-gate: determinism + structure + coverage + size
13// Fully integer (Q16 fixed-point escape-time) -> bit-identical across any device (the sovereign EXCEED axis:
14// float raster is non-deterministic across hardware). outdir: bare name or under /tmp/. license_tier: ORIGINAL
15import "nx_swarm_lib.nx"
16const T_MAGIC_1048576: i64 = 1048576
17const T_MAGIC_65536: i64 = 65536
18
19const T_SCALE: i64 = 65536 // Q16
20const T_MAXITER: i64 = 128
21const T_ESCAPE: i64 = 262144 // 4 << 16 (|z|^2 > 4)
22// complex window (Q16): real [-2.5, 1.0], imag [-1.25, 1.25]
23const T_XMIN: i64 = 0 - 163840 // -2.5 * 65536
24const T_XSPAN: i64 = 229376 // 3.5 * 65536
25const T_YMIN: i64 = 0 - 81920 // -1.25 * 65536
26const T_YSPAN: i64 = 163840 // 2.5 * 65536
27
28func tl_puts(s: *u8) -> i64 { sys_write(1, s, fa_len(s)); return 0 }
29func tl_eq(a: *u8, b: *u8) -> i64 {
30 var i: i64 = 0
31 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 }
32 if b[i] != (0 as u8) { return 0 }
33 return 1
34}
35
36// outdir guard: bare basename OR under /tmp/, no ".."
37func tl_dir_ok(p: *u8) -> i64 {
38 let n: i64 = fa_len(p)
39 if n < 1 { return 0 }
40 var i: i64 = 0
41 while i + 1 < n { if (p[i] as i64) == 46 { if (p[i+1] as i64) == 46 { return 0 } } i = i + 1 }
42 var slash: i64 = 0
43 i = 0
44 while i < n { if (p[i] as i64) == 47 { slash = 1 } i = i + 1 }
45 if slash == 0 { return 1 }
46 if n < 4 { return 0 }
47 if (p[0] as i64) != 47 { return 0 }
48 if (p[1] as i64) != 116 { return 0 }
49 if (p[2] as i64) != 109 { return 0 }
50 if (p[3] as i64) != 112 { return 0 }
51 if n == 4 { return 1 }
52 if (p[4] as i64) != 47 { return 0 }
53 return 1
54}
55
56// escape-time iteration count for c=(cre,cim) in Q16 fixed-point. Returns iters (0..T_MAXITER).
57func tl_iter(cre: i64, cim: i64) -> i64 {
58 var zr: i64 = 0
59 var zi: i64 = 0
60 var it: i64 = 0
61 var go: i64 = 1
62 while go == 1 {
63 if it >= T_MAXITER { go = 0 } else {
64 let zr2: i64 = (zr * zr) / T_SCALE // zr^2 in Q16
65 let zi2: i64 = (zi * zi) / T_SCALE
66 if zr2 + zi2 > T_ESCAPE { go = 0 } else {
67 let nzr: i64 = zr2 - zi2 + cre // zr' = zr^2 - zi^2 + cre
68 let cross: i64 = (zr * zi) / T_SCALE
69 let nzi: i64 = cross + cross + cim // zi' = 2*zr*zi + cim
70 zr = nzr
71 zi = nzi
72 it = it + 1
73 }
74 }
75 }
76 return it
77}
78
79// color for an iteration count -> rgb[0..2]. In-set (it==MAXITER) = black; else banded palette.
80func tl_color(it: i64, rgb: *u8) -> i64 {
81 if it >= T_MAXITER {
82 rgb[0] = 0 as u8; rgb[1] = 0 as u8; rgb[2] = 0 as u8
83 return 0
84 }
85 rgb[0] = ((it * 8) % 256) as u8
86 rgb[1] = ((it * 5) % 256) as u8
87 rgb[2] = ((64 + it * 11) % 256) as u8
88 return 0
89}
90
91// band row range for tile_id of ntiles over height H: [y0, y1).
92func tl_y0(H: i64, ntiles: i64, tid: i64) -> i64 { return tid * H / ntiles }
93func tl_y1(H: i64, ntiles: i64, tid: i64) -> i64 { return (tid + 1) * H / ntiles }
94
95// build "<dir>/tile_<id>.raw" into out.
96func tl_tile_path(dir: *u8, tid: i64, out: *u8) -> i64 {
97 var o: i64 = 0
98 o = fa_cat(out, o, dir)
99 out[o] = 47 as u8; o = o + 1
100 o = fa_cat(out, o, "tile_" as *u8)
101 o = fa_catn(out, o, tid)
102 o = fa_cat(out, o, ".raw" as *u8)
103 out[o] = 0 as u8
104 return o
105}
106
107func tl_write_all(fd: i64, buf: *u8, n: i64) -> i64 {
108 var off: i64 = 0
109 while off < n {
110 let w: i64 = sys_write(fd, (buf as i64 + off) as *u8, n - off)
111 if w <= 0 { return 0 - 1 }
112 off = off + w
113 }
114 return 0
115}
116
117// render band tid -> outdir/tile_<tid>.raw (RGB rows for [y0,y1)). Returns bytes written or -1.
118func tl_render(W: i64, H: i64, ntiles: i64, tid: i64, outdir: *u8) -> i64 {
119 let y0: i64 = tl_y0(H, ntiles, tid)
120 let y1: i64 = tl_y1(H, ntiles, tid)
121 let rows: i64 = y1 - y0
122 if rows <= 0 { return 0 }
123 let nbytes: i64 = rows * W * 3
124 let buf: *u8 = sys_mmap(nbytes + 16)
125 let rgb: *u8 = sys_mmap(8)
126 var py: i64 = y0
127 var bo: i64 = 0
128 while py < y1 {
129 let cim: i64 = T_YMIN + (py * T_YSPAN) / H
130 var px: i64 = 0
131 while px < W {
132 let cre: i64 = T_XMIN + (px * T_XSPAN) / W
133 let it: i64 = tl_iter(cre, cim)
134 tl_color(it, rgb)
135 buf[bo] = rgb[0]; buf[bo+1] = rgb[1]; buf[bo+2] = rgb[2]
136 bo = bo + 3
137 px = px + 1
138 }
139 py = py + 1
140 }
141 let path: *u8 = sys_mmap(512)
142 tl_tile_path(outdir, tid, path)
143 let fd: i64 = sys_openat_wr(path, 0x1a4)
144 if fd < 0 { return 0 - 1 }
145 let wr: i64 = tl_write_all(fd, buf, bo)
146 sys_close(fd)
147 if wr < 0 { return 0 - 1 }
148 return bo
149}
150
151// assemble: write P6 PPM header + concat tile_0.raw..tile_{n-1}.raw -> outfile. Returns total bytes or -1.
152func tl_assemble(W: i64, H: i64, ntiles: i64, outdir: *u8, outfile: *u8) -> i64 {
153 let fd: i64 = sys_openat_wr(outfile, 0x1a4)
154 if fd < 0 { return 0 - 1 }
155 // header "P6\n<W> <H>\n255\n"
156 let hdr: *u8 = sys_mmap(64)
157 var ho: i64 = 0
158 ho = fa_cat(hdr, ho, "P6\n" as *u8)
159 ho = fa_catn(hdr, ho, W)
160 hdr[ho] = 32 as u8; ho = ho + 1
161 ho = fa_catn(hdr, ho, H)
162 hdr[ho] = 10 as u8; ho = ho + 1
163 ho = fa_cat(hdr, ho, "255\n" as *u8)
164 if tl_write_all(fd, hdr, ho) < 0 { sys_close(fd); return 0 - 1 }
165 var total: i64 = ho
166 let path: *u8 = sys_mmap(512)
167 let rbuf: *u8 = sys_mmap(T_MAGIC_1048576) // 1 MiB streaming
168 var tid: i64 = 0
169 var ok: i64 = 1
170 while tid < ntiles {
171 if ok == 1 {
172 tl_tile_path(outdir, tid, path)
173 let rfd: i64 = sys_openat_rd(path)
174 if rfd < 0 { ok = 0 } else {
175 var go: i64 = 1
176 while go == 1 {
177 let r: i64 = sys_read(rfd, rbuf, T_MAGIC_1048576)
178 if r <= 0 { go = 0 } else {
179 if tl_write_all(fd, rbuf, r) < 0 { go = 0; ok = 0 }
180 total = total + r
181 }
182 }
183 sys_close(rfd)
184 }
185 }
186 tid = tid + 1
187 }
188 sys_close(fd)
189 if ok == 0 { return 0 - 1 }
190 return total
191}
192
193// count distinct byte-triples in a file (bounded) -> a cheap "has structure" probe.
194func tl_distinct_colors(path: *u8, cap: i64) -> i64 {
195 let buf: *u8 = sys_mmap(cap + 16)
196 let n: i64 = sb_read(path, buf, cap)
197 if n < 3 { return 0 }
198 // sample: count how many pixels differ from pixel 0 (structure => >0)
199 let r0: i64 = buf[0] as i64
200 let g0: i64 = buf[1] as i64
201 let b0: i64 = buf[2] as i64
202 var diff: i64 = 0
203 var i: i64 = 3
204 while i + 2 < n {
205 if (buf[i] as i64) != r0 { diff = diff + 1 } else { if (buf[i+1] as i64) != g0 { diff = diff + 1 } else { if (buf[i+2] as i64) != b0 { diff = diff + 1 } } }
206 i = i + 3
207 }
208 return diff
209}
210
211func tl_filesize(path: *u8) -> i64 {
212 let fd: i64 = sys_openat_rd(path)
213 if fd < 0 { return 0 - 1 }
214 var tot: i64 = 0
215 let b: *u8 = sys_mmap(T_MAGIC_65536)
216 var go: i64 = 1
217 while go == 1 {
218 let r: i64 = sys_read(fd, b, T_MAGIC_65536)
219 if r <= 0 { go = 0 } else { tot = tot + r }
220 }
221 sys_close(fd)
222 return tot
223}
224
225func tl_gate() -> i64 {
226 var pass: i64 = 0
227 var total: i64 = 0
228 let now: i64 = sys_now_us()
229 // fresh outdir under /tmp
230 let dir: *u8 = sys_mmap(256)
231 var od: i64 = 0
232 od = fa_cat(dir, od, "/tmp/tile_" as *u8); od = fa_catn(dir, od, now); dir[od] = 0 as u8
233 __syscall(258, AT_FDCWD, dir as i64, 0x1ff, 0, 0, 0) // mkdirat 0777 (raw: SYS_MKDIRAT not in nx_syscalls)
234
235 let W: i64 = 64
236 let H: i64 = 48
237 let NT: i64 = 4
238
239 // T1 render all bands -> each writes rows*W*3 bytes; coverage sums to H
240 total = total + 1
241 var covered: i64 = 0
242 var allok: i64 = 1
243 var tid: i64 = 0
244 while tid < NT {
245 let got: i64 = tl_render(W, H, NT, tid, dir)
246 let rows: i64 = tl_y1(H, NT, tid) - tl_y0(H, NT, tid)
247 if got != rows * W * 3 { allok = 0 }
248 covered = covered + rows
249 tid = tid + 1
250 }
251 if allok == 1 { if covered == H { pass = pass + 1; tl_puts("T1 render+coverage OK\n" as *u8) } }
252
253 // T2 assemble -> PPM size == header + W*H*3
254 total = total + 1
255 let ppm: *u8 = sys_mmap(256)
256 var po: i64 = 0
257 po = fa_cat(ppm, po, dir); ppm[po] = 47 as u8; po = po + 1
258 po = fa_cat(ppm, po, "out.ppm" as *u8); ppm[po] = 0 as u8
259 let asz: i64 = tl_assemble(W, H, NT, dir, ppm)
260 let fsz: i64 = tl_filesize(ppm)
261 // header len for 64x48: "P6\n64 48\n255\n" = 3+2+1+2+1+4 = 13
262 let pixbytes: i64 = W * H * 3
263 var t2: i64 = 0
264 if asz == fsz { if fsz > pixbytes { if fsz < pixbytes + 32 { t2 = 1 } } }
265 if t2 == 1 { pass = pass + 1; tl_puts("T2 assemble-size OK\n" as *u8) }
266
267 // T3 STRUCTURE: the fractal is not a flat color (distinct pixels > 0, and a lot)
268 total = total + 1
269 let diff: i64 = tl_distinct_colors(ppm, pixbytes + 64)
270 if diff > 100 { pass = pass + 1; tl_puts("T3 has-structure OK\n" as *u8) }
271
272 // T4 DETERMINISM (the sovereign EXCEED axis): re-render a band -> byte-identical to the first
273 total = total + 1
274 let dir2: *u8 = sys_mmap(256)
275 var o2: i64 = 0
276 o2 = fa_cat(dir2, o2, "/tmp/tile2_" as *u8); o2 = fa_catn(dir2, o2, now); dir2[o2] = 0 as u8
277 __syscall(258, AT_FDCWD, dir2 as i64, 0x1ff, 0, 0, 0) // mkdirat 0777
278 tl_render(W, H, NT, 1, dir2)
279 let p1: *u8 = sys_mmap(512)
280 let p2: *u8 = sys_mmap(512)
281 tl_tile_path(dir, 1, p1)
282 tl_tile_path(dir2, 1, p2)
283 let b1: *u8 = sys_mmap(T_MAGIC_65536)
284 let b2: *u8 = sys_mmap(T_MAGIC_65536)
285 let n1: i64 = sb_read(p1, b1, T_MAGIC_65536)
286 let n2: i64 = sb_read(p2, b2, T_MAGIC_65536)
287 var iden: i64 = 0
288 if n1 == n2 { if n1 > 0 {
289 var k: i64 = 0
290 var same: i64 = 1
291 while k < n1 { if b1[k] != b2[k] { same = 0; k = n1 } else { k = k + 1 } }
292 if same == 1 { iden = 1 }
293 } }
294 if iden == 1 { pass = pass + 1; tl_puts("T4 deterministic OK\n" as *u8) }
295
296 // T5 the SET is present: some pixels are black (in-set, it==MAXITER) -> the render is a real Mandelbrot
297 total = total + 1
298 let buf: *u8 = sys_mmap(pixbytes + 128)
299 let nn: i64 = sb_read(ppm, buf, pixbytes + 128)
300 var black: i64 = 0
301 var i: i64 = 13 // skip header
302 while i + 2 < nn { if (buf[i] as i64) == 0 { if (buf[i+1] as i64) == 0 { if (buf[i+2] as i64) == 0 { black = black + 1 } } } i = i + 3 }
303 if black > 20 { pass = pass + 1; tl_puts("T5 mandelbrot-set-present OK\n" as *u8) }
304
305 let t: *u8 = sys_mmap(128)
306 var to: i64 = 0
307 to = fa_cat(t, to, "SWARMTILEGATE " as *u8)
308 to = fa_catn(t, to, pass)
309 to = fa_cat(t, to, "/" as *u8)
310 to = fa_catn(t, to, total)
311 if pass == total { to = fa_cat(t, to, " verdict=GREEN\n" as *u8) } else { to = fa_cat(t, to, " verdict=RED\n" as *u8) }
312 sys_write(1, t, to)
313 if pass == total { return 0 }
314 return 1
315}
316
317// ASCII preview to stdout (no files) -- makes the sovereign render visible in a terminal/chat.
318func tl_preview(W: i64, H: i64) -> i64 {
319 let ramp: *u8 = " .:-=+*o#@" as *u8 // 10 chars, low iter -> high iter; in-set = '@'
320 let line: *u8 = sys_mmap(W + 2)
321 var py: i64 = 0
322 while py < H {
323 let cim: i64 = T_YMIN + (py * T_YSPAN) / H
324 var px: i64 = 0
325 while px < W {
326 let cre: i64 = T_XMIN + (px * T_XSPAN) / W
327 let it: i64 = tl_iter(cre, cim)
328 var idx: i64 = it * 9 / T_MAXITER
329 if idx > 9 { idx = 9 }
330 line[px] = ramp[idx]
331 px = px + 1
332 }
333 line[W] = 10 as u8
334 sys_write(1, line, W + 1)
335 py = py + 1
336 }
337 return 0
338}
339
340func main(argc: i64, argv: *i64) -> i64 {
341 if argc >= 2 {
342 let verb: *u8 = argv[1] as *u8
343 let vout: *i64 = sys_mmap(16) as *i64
344 let pend: *i64 = sys_mmap(16) as *i64
345 if tl_eq(verb, "preview" as *u8) == 1 {
346 var W: i64 = 78
347 var H: i64 = 30
348 if argc >= 4 {
349 sb_pint(argv[2] as *u8, fa_len(argv[2] as *u8), 0, vout, pend); W = vout[0]
350 sb_pint(argv[3] as *u8, fa_len(argv[3] as *u8), 0, vout, pend); H = vout[0]
351 }
352 return tl_preview(W, H)
353 }
354 if tl_eq(verb, "render" as *u8) == 1 {
355 if argc < 7 { tl_puts("usage: nx_swarm_tile render <W> <H> <ntiles> <tile_id> <outdir>\n" as *u8); return 2 }
356 sb_pint(argv[2] as *u8, fa_len(argv[2] as *u8), 0, vout, pend); let W: i64 = vout[0]
357 sb_pint(argv[3] as *u8, fa_len(argv[3] as *u8), 0, vout, pend); let H: i64 = vout[0]
358 sb_pint(argv[4] as *u8, fa_len(argv[4] as *u8), 0, vout, pend); let NT: i64 = vout[0]
359 sb_pint(argv[5] as *u8, fa_len(argv[5] as *u8), 0, vout, pend); let TID: i64 = vout[0]
360 let dir: *u8 = argv[6] as *u8
361 if tl_dir_ok(dir) == 0 { tl_puts("SWARMTILE render REFUSED (dir law)\n" as *u8); return 3 }
362 let r: i64 = tl_render(W, H, NT, TID, dir)
363 if r < 0 { tl_puts("SWARMTILE render IO-FAIL\n" as *u8); return 4 }
364 let t: *u8 = sys_mmap(96)
365 var o: i64 = fa_cat(t, 0, "SWARMTILE rendered tile=" as *u8)
366 o = fa_catn(t, o, TID); o = fa_cat(t, o, " bytes=" as *u8); o = fa_catn(t, o, r); o = fa_cat(t, o, "\n" as *u8)
367 sys_write(1, t, o)
368 return 0
369 }
370 if tl_eq(verb, "assemble" as *u8) == 1 {
371 if argc < 7 { tl_puts("usage: nx_swarm_tile assemble <W> <H> <ntiles> <outdir> <out.ppm>\n" as *u8); return 2 }
372 sb_pint(argv[2] as *u8, fa_len(argv[2] as *u8), 0, vout, pend); let W: i64 = vout[0]
373 sb_pint(argv[3] as *u8, fa_len(argv[3] as *u8), 0, vout, pend); let H: i64 = vout[0]
374 sb_pint(argv[4] as *u8, fa_len(argv[4] as *u8), 0, vout, pend); let NT: i64 = vout[0]
375 let dir: *u8 = argv[5] as *u8
376 if tl_dir_ok(dir) == 0 { tl_puts("SWARMTILE assemble REFUSED (dir law)\n" as *u8); return 3 }
377 let r: i64 = tl_assemble(W, H, NT, dir, argv[6] as *u8)
378 if r < 0 { tl_puts("SWARMTILE assemble IO-FAIL\n" as *u8); return 4 }
379 let t: *u8 = sys_mmap(96)
380 var o: i64 = fa_cat(t, 0, "SWARMTILE assembled bytes=" as *u8)
381 o = fa_catn(t, o, r); o = fa_cat(t, o, "\n" as *u8)
382 sys_write(1, t, o)
383 return 0
384 }
385 }
386 return tl_gate()
387}