code wiki / (root) / nx_inter_layer_coherence.nx

nx_inter_layer_coherence.nx source

↩ module page · 363 lines · 14469 B

1// nx_inter_layer_coherence.nx -- cross-layer constraint checker. 2// 3// Per honest audit 2026-05-16: per-layer graders can each be S-class 4// while the OVERALL composition is nonsense -- river flowing uphill, 5// forest in a desert biome, town built on a cliff edge, castle in a 6// swamp. This primitive grades the INTER-LAYER CONSTRAINTS that 7// must hold for a coherent world. 8// 9// Four constraints scored individually + composed: 10// 11// 1. RIVER_DRAINAGE: rivers should flow downhill. For each polyline 12// segment, sample heightmap at both endpoints; score = fraction 13// of segments where h_end < h_start. 14// 15// 2. FOREST_BIOME_MATCH: forests should sit in biomes that support 16// forests (BOREAL_FOREST / TEMPERATE_FOREST / TROPICAL_RAINFOREST 17// or GRASSLAND). Score = fraction of forest positions in valid 18// biomes. 19// 20// 3. TOWN_FLATNESS: towns should be on relatively flat ground. Sample 21// local heightmap stddev within town radius; score = inverse of 22// normalised stddev. 23// 24// 4. CASTLE_DEFENSIVE: castles benefit from elevation advantage. 25// Score = fraction of castles whose centre elevation exceeds the 26// mean elevation in a surrounding band of 2x radius. 27// 28// Each function returns Q14 [0, Q]; nx_inter_layer_coherence_grade 29// composes them into a LAYER_VERDICT (kind = NX_LAYER_KIND_READABILITY, 30// refine = NX_LAYER_REFINE_FIX_COHERENCE). 31// 32// genealogy_id: world_design_coherence_canon + 33// leopold_wolman_1957_drainage + 34// medieval_settlement_geography_canon 35// lineage_id: nx_inter_layer_coherence_4axis_v1 36 37// nx_safety_envelope: 38// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 39// sil_target: SIL1 40// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 41// verdict: NOT_YET_EVALUATED 42 43import "nx_syscalls.nx" 44import "nx_tier.nx" 45import "nx_layer_verdict.nx" 46 47const NX_ILC_Q: nx_int = 16384 48 49// ===== Axis indices ================================================= 50const NX_ILC_AXIS_RIVER: nx_int = 0 51const NX_ILC_AXIS_FOREST_BIOME: nx_int = 1 52const NX_ILC_AXIS_TOWN_FLAT: nx_int = 2 53const NX_ILC_AXIS_CASTLE_HIGH: nx_int = 3 54 55const NX_ILC_AXIS_COUNT: nx_int = 4 56 57// ===== Helper: heightmap sample (clamped) ========================== 58func _ilc_h_at( 59 heightmap: *i64, w: nx_int, h: nx_int, x: nx_int, y: nx_int 60) -> nx_int { 61 var cx: nx_int = x 62 var cy: nx_int = y 63 if cx < 0 { cx = 0 } 64 if cx >= w { cx = w - 1 } 65 if cy < 0 { cy = 0 } 66 if cy >= h { cy = h - 1 } 67 return heightmap[cy * w + cx] 68} 69 70// ===== 1. River drainage: rivers must flow downhill ================ 71// rivers: flat array of N polylines, each n_points_per_river control 72// points stored as 2 i64 (x, y) in heightmap-cell coords (NOT Q14). 73// Caller may scale Q14 river coords down before calling. 74func nx_coherence_river_drainage( 75 rivers: *i64, n_rivers: nx_int, points_per: nx_int, 76 heightmap: *i64, w: nx_int, hgt: nx_int 77) -> nx_int { 78 if n_rivers <= 0 { return NX_ILC_Q / 2 } // skip => MARGINAL 79 let q: nx_int = NX_ILC_Q 80 var n_segments: nx_int = 0 81 var n_downhill: nx_int = 0 82 var r: nx_int = 0 83 while r < n_rivers { 84 var pi: nx_int = 0 85 while pi < points_per - 1 { 86 let idx0: nx_int = (r * points_per + pi) * 2 87 let idx1: nx_int = (r * points_per + pi + 1) * 2 88 let x0: nx_int = rivers[idx0 ] 89 let y0: nx_int = rivers[idx0 + 1] 90 let x1: nx_int = rivers[idx1 ] 91 let y1: nx_int = rivers[idx1 + 1] 92 let h0: nx_int = _ilc_h_at(heightmap, w, hgt, x0, y0) 93 let h1: nx_int = _ilc_h_at(heightmap, w, hgt, x1, y1) 94 if h1 <= h0 { n_downhill = n_downhill + 1 } 95 n_segments = n_segments + 1 96 pi = pi + 1 97 } 98 r = r + 1 99 } 100 if n_segments == 0 { return 0 } 101 return (n_downhill * q) / n_segments 102} 103 104// ===== 2. Forest in valid biome ==================================== 105// forests: flat array of N positions (x, y) in heightmap-cell coords. 106// biome_map: parallel i64 array of biome ids. 107// Valid forest biomes: 1 (BOREAL_FOREST), 4 (GRASSLAND), 5 108// (TEMPERATE_FOREST), 11 (TROPICAL_RAINFOREST). 109func nx_coherence_forest_in_biome( 110 forests: *i64, n_forests: nx_int, 111 biome_map: *i64, w: nx_int, hgt: nx_int 112) -> nx_int { 113 if n_forests <= 0 { return NX_ILC_Q / 2 } 114 let q: nx_int = NX_ILC_Q 115 var n_valid: nx_int = 0 116 var i: nx_int = 0 117 while i < n_forests { 118 let x: nx_int = forests[i * 2 ] 119 let y: nx_int = forests[i * 2 + 1] 120 let b: nx_int = _ilc_h_at(biome_map, w, hgt, x, y) 121 if b == 1 { n_valid = n_valid + 1 } 122 if b == 4 { n_valid = n_valid + 1 } 123 if b == 5 { n_valid = n_valid + 1 } 124 if b == 11 { n_valid = n_valid + 1 } 125 i = i + 1 126 } 127 return (n_valid * q) / n_forests 128} 129 130// ===== 3. Town on flat ground ====================================== 131// towns: flat array of N records (cx, cy, radius) in heightmap-cell 132// coords. For each town, compute local heightmap variation in a 133// circle of given radius. Score = average per-town flatness Q14. 134func nx_coherence_town_on_flatland( 135 towns: *i64, n_towns: nx_int, 136 heightmap: *i64, w: nx_int, hgt: nx_int, max_relief: nx_int 137) -> nx_int { 138 if n_towns <= 0 { return NX_ILC_Q / 2 } 139 if max_relief <= 0 { return 0 } 140 let q: nx_int = NX_ILC_Q 141 var sum_flat: nx_int = 0 142 var i: nx_int = 0 143 while i < n_towns { 144 let cx: nx_int = towns[i * 3 ] 145 let cy: nx_int = towns[i * 3 + 1] 146 let r: nx_int = towns[i * 3 + 2] 147 if r <= 0 { i = i + 1 } 148 if r > 0 { 149 // Sample local stddev via mean abs deviation in a square. 150 let r_sq: nx_int = r * r 151 var sum_h: nx_int = 0 152 var count: nx_int = 0 153 var dy: nx_int = 0 - r 154 while dy <= r { 155 var dx: nx_int = 0 - r 156 while dx <= r { 157 if dx * dx + dy * dy <= r_sq { 158 sum_h = sum_h + _ilc_h_at(heightmap, w, hgt, cx + dx, cy + dy) 159 count = count + 1 160 } 161 dx = dx + 1 162 } 163 dy = dy + 1 164 } 165 if count == 0 { i = i + 1 } 166 if count > 0 { 167 let mean_h: nx_int = sum_h / count 168 var dev_sum: nx_int = 0 169 var dy2: nx_int = 0 - r 170 while dy2 <= r { 171 var dx2: nx_int = 0 - r 172 while dx2 <= r { 173 if dx2 * dx2 + dy2 * dy2 <= r_sq { 174 var d: nx_int = _ilc_h_at(heightmap, w, hgt, cx + dx2, cy + dy2) - mean_h 175 if d < 0 { d = 0 - d } 176 dev_sum = dev_sum + d 177 } 178 dx2 = dx2 + 1 179 } 180 dy2 = dy2 + 1 181 } 182 let mean_dev: nx_int = dev_sum / count 183 // Score = 1 - mean_dev / (max_relief / 10). 184 // mean_dev = 0 -> q (perfectly flat) 185 // mean_dev = max/10 -> 0 (very rugged) 186 let target: nx_int = max_relief / 10 187 if target <= 0 { sum_flat = sum_flat + q } 188 if target > 0 { 189 var dev_score: nx_int = q - (mean_dev * q) / target 190 if dev_score < 0 { dev_score = 0 } 191 if dev_score > q { dev_score = q } 192 sum_flat = sum_flat + dev_score 193 } 194 i = i + 1 195 } 196 } 197 } 198 return sum_flat / n_towns 199} 200 201// ===== 4. Castle on elevated ground ================================ 202// castles: flat array of N records (cx, cy, radius) in heightmap-cell 203// coords. For each castle, compare centre elevation to the mean in 204// an annular ring (2r radius). 205func nx_coherence_castle_on_high( 206 castles: *i64, n_castles: nx_int, 207 heightmap: *i64, w: nx_int, hgt: nx_int 208) -> nx_int { 209 if n_castles <= 0 { return NX_ILC_Q / 2 } 210 let q: nx_int = NX_ILC_Q 211 var n_high: nx_int = 0 212 var i: nx_int = 0 213 while i < n_castles { 214 let cx: nx_int = castles[i * 3 ] 215 let cy: nx_int = castles[i * 3 + 1] 216 let r: nx_int = castles[i * 3 + 2] 217 let centre_h: nx_int = _ilc_h_at(heightmap, w, hgt, cx, cy) 218 // Sample ring at 2r distance. 219 var sum_h: nx_int = 0 220 var count: nx_int = 0 221 let r2: nx_int = 2 * r 222 if r2 > 0 { 223 var dy: nx_int = 0 - r2 224 while dy <= r2 { 225 var dx: nx_int = 0 - r2 226 while dx <= r2 { 227 let d_sq: nx_int = dx * dx + dy * dy 228 let r2_sq: nx_int = r2 * r2 229 let r_sq: nx_int = r * r 230 // Annular band: r < sqrt(d_sq) < 2r. 231 if d_sq > r_sq { 232 if d_sq <= r2_sq { 233 sum_h = sum_h + _ilc_h_at(heightmap, w, hgt, cx + dx, cy + dy) 234 count = count + 1 235 } 236 } 237 dx = dx + 1 238 } 239 dy = dy + 1 240 } 241 } 242 if count > 0 { 243 let mean_ring: nx_int = sum_h / count 244 if centre_h >= mean_ring { n_high = n_high + 1 } 245 } 246 i = i + 1 247 } 248 return (n_high * q) / n_castles 249} 250 251// ===== Public: compose all 4 axes into a LAYER_VERDICT ============ 252func nx_inter_layer_coherence_grade( 253 river_score: nx_int, forest_score: nx_int, 254 town_score: nx_int, castle_score: nx_int, 255 out_verdict: *i64 256) { 257 nx_layer_verdict_init(out_verdict, NX_LAYER_KIND_READABILITY, 258 NX_ILC_AXIS_COUNT, NX_LAYER_REFINE_FIX_COHERENCE) 259 out_verdict[NX_LV_OFF_AXIS_0 + NX_ILC_AXIS_RIVER] = river_score 260 out_verdict[NX_LV_OFF_AXIS_0 + NX_ILC_AXIS_FOREST_BIOME] = forest_score 261 out_verdict[NX_LV_OFF_AXIS_0 + NX_ILC_AXIS_TOWN_FLAT] = town_score 262 out_verdict[NX_LV_OFF_AXIS_0 + NX_ILC_AXIS_CASTLE_HIGH] = castle_score 263 nx_layer_verdict_finalize(out_verdict) 264} 265 266// ===== Self-test ==================================================== 267func main() -> i64 { 268 let q: nx_int = NX_ILC_Q 269 270 let w: nx_int = 16 271 let h: nx_int = 16 272 let n: nx_int = w * h 273 274 // Linear ramp heightmap (h = y * 100); rivers flowing south->north 275 // SHOULD flow downhill (decreasing y -> decreasing h), wait that 276 // logic is wrong. Actually y=0 -> h=0, y=15 -> h=1500. River 277 // flowing "downhill" means from y=15 to y=0 (high to low). 278 let map: *i64 = (sys_mmap(n * NX_SIZEOF_NX_INT)) as *i64 279 var i: nx_int = 0 280 while i < n { 281 let y: nx_int = i / w 282 map[i] = y * 100 283 i = i + 1 284 } 285 286 // T1: River drainage -- 1 river with 4 points going downhill 287 // (y=15 to y=0). All segments should pass. 288 let rivers: *i64 = (sys_mmap(2 * 4 * NX_SIZEOF_NX_INT)) as *i64 289 rivers[0] = 4; rivers[1] = 15 290 rivers[2] = 4; rivers[3] = 10 291 rivers[4] = 4; rivers[5] = 5 292 rivers[6] = 4; rivers[7] = 0 293 let s_r: nx_int = nx_coherence_river_drainage(rivers, 1, 4, map, w, h) 294 if s_r != q { return __syscall(93, 1, 0, 0, 0, 0, 0) } 295 296 // T2: River flowing UPHILL -- all segments fail. 297 rivers[0] = 4; rivers[1] = 0 298 rivers[2] = 4; rivers[3] = 5 299 rivers[4] = 4; rivers[5] = 10 300 rivers[6] = 4; rivers[7] = 15 301 let s_r2: nx_int = nx_coherence_river_drainage(rivers, 1, 4, map, w, h) 302 if s_r2 != 0 { return __syscall(93, 2, 0, 0, 0, 0, 0) } 303 304 // T3: Forest in biome. All-forest biome map (biome 5 everywhere). 305 let biome: *i64 = (sys_mmap(n * NX_SIZEOF_NX_INT)) as *i64 306 var bi: nx_int = 0 307 while bi < n { biome[bi] = 5; bi = bi + 1 } 308 let forests: *i64 = (sys_mmap(2 * 3 * NX_SIZEOF_NX_INT)) as *i64 309 forests[0] = 4; forests[1] = 4 310 forests[2] = 8; forests[3] = 8 311 forests[4] = 12; forests[5] = 12 312 let s_f: nx_int = nx_coherence_forest_in_biome(forests, 3, biome, w, h) 313 if s_f != q { return __syscall(93, 10, 0, 0, 0, 0, 0) } 314 315 // T4: Forest in DESERT biome -- 0 valid. 316 var bi2: nx_int = 0 317 while bi2 < n { biome[bi2] = 8; bi2 = bi2 + 1 } 318 let s_f2: nx_int = nx_coherence_forest_in_biome(forests, 3, biome, w, h) 319 if s_f2 != 0 { return __syscall(93, 11, 0, 0, 0, 0, 0) } 320 321 // T5: Town on flat (constant heightmap) -> score ~ Q. 322 let map_flat: *i64 = (sys_mmap(n * NX_SIZEOF_NX_INT)) as *i64 323 var fi: nx_int = 0 324 while fi < n { map_flat[fi] = 100; fi = fi + 1 } 325 let towns: *i64 = (sys_mmap(3 * 2 * NX_SIZEOF_NX_INT)) as *i64 326 towns[0] = 8; towns[1] = 8; towns[2] = 3 327 towns[3] = 4; towns[4] = 4; towns[5] = 2 328 let s_t: nx_int = nx_coherence_town_on_flatland(towns, 2, map_flat, w, h, 1000) 329 if s_t < q * 9 / 10 { return __syscall(93, 20, 0, 0, 0, 0, 0) } 330 331 // T6: Town on rugged ramp -> score lower than flat. 332 let s_t2: nx_int = nx_coherence_town_on_flatland(towns, 2, map, w, h, 1000) 333 if s_t2 >= s_t { return __syscall(93, 21, 0, 0, 0, 0, 0) } 334 335 // T7: Castle on elevated ground. Place castle at the peak of the 336 // ramp (y = high) -- centre h > mean ring h. 337 let castles: *i64 = (sys_mmap(3 * 2 * NX_SIZEOF_NX_INT)) as *i64 338 castles[0] = 8; castles[1] = 13; castles[2] = 2 339 let s_c: nx_int = nx_coherence_castle_on_high(castles, 1, map, w, h) 340 if s_c < q / 2 { return __syscall(93, 30, 0, 0, 0, 0, 0) } 341 342 // T8: Castle in a valley (y = low) -> score 0 (centre below ring mean). 343 castles[0] = 8; castles[1] = 2; castles[2] = 2 344 let s_c2: nx_int = nx_coherence_castle_on_high(castles, 1, map, w, h) 345 if s_c2 > 0 { return __syscall(93, 31, 0, 0, 0, 0, 0) } 346 347 // T9: Compose into a verdict and finalize. 348 let verdict: *i64 = (sys_mmap(NX_LV_STRIDE * NX_SIZEOF_NX_INT)) as *i64 349 // s_r=Q, s_f=Q (from T3), s_t=Q, s_c=Q -> 4 wins -> S. 350 nx_inter_layer_coherence_grade(s_r, s_f, s_t, s_c, verdict) 351 if verdict[NX_LV_OFF_GRADE] != NX_LV_GRADE_S { 352 return __syscall(93, 40, 0, 0, 0, 0, 0) 353 } 354 355 // T10: Compose with a deliberately failing forest axis -> A grade 356 // (3 wins, 1 loss, wins = n - 1). 357 nx_inter_layer_coherence_grade(s_r, 0, s_t, s_c, verdict) 358 if verdict[NX_LV_OFF_GRADE] != NX_LV_GRADE_A { 359 return __syscall(93, 41, 0, 0, 0, 0, 0) 360 } 361 362 return 0 363}