code wiki / (root) / nx_ice_distribution_test.nx

nx_ice_distribution_test.nx source

↩ module page · 215 lines · 11821 B

1// nx_ice_distribution_test.nx -- gate for the derived geometric coupling. 2// 3// THE CLAIM UNDER TEST is that nx_ice_recrystal's asserted coupling was not 4// merely unproven but WRONG IN A KNOWN DIRECTION, and that the right value 5// falls out of a size distribution as exact arithmetic. 6// 7// T4 is the measurement that matters: the number fraction of crystals lost 8// is far larger than the mass fraction melted, so a coupling of 1.0 -- which 9// is the claim that they are equal -- under-states how fast the mean size 10// grows. T5 puts a number on how wrong, and T6 states the direction as a 11// verdict rather than leaving a reader to work it out. 12// 13// T2 is the conservation law that keeps the rest honest: melting and 14// redepositing must not change total mass, and if it did, every growth 15// figure here would be an artefact of losing or inventing ice. 16// expect_exit: 0 license_tier: ORIGINAL 17import "nx_syscalls.nx" 18import "nx_ice_distribution.nx" 19import "nx_ice_recrystal.nx" 20 21func tw(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 22func tn(v: i64) -> i64 { let b: *u8 = sys_mmap(24); var m: i64 = v; if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } let t: *u8 = sys_mmap(24); var k: i64 = 0; if m == 0 { t[0] = 48 as u8; k = 1 } while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } var i: i64 = 0; while i < k { b[i] = t[k - 1 - i]; i = i + 1 } sys_write(1, b, k); return 0 } 23func iabs(v: i64) -> i64 { if v < 0 { return 0 - v } return v } 24 25func main() -> i64 { 26 var pass: i64 = 0 27 var total: i64 = 0 28 29 let s: *IceDist = dist_reference() 30 31 // --- T1 The reference profile is well formed and ASCENDING, which is a 32 // precondition of the melt walk rather than a convention: melting 33 // the wrong end would silently invert every result below. --- 34 total = total + 1 35 var ok1: i64 = 1 36 if dist_is_ascending(s) != 1 { ok1 = 0 } 37 if dist_total_count(s) <= 0 { ok1 = 0 } 38 if dist_total_mass(s) <= 0 { ok1 = 0 } 39 let mean0: i64 = dist_mean_diameter(s) 40 if mean0 < 150 { ok1 = 0 } 41 if mean0 > 350 { ok1 = 0 } 42 tw("T1 reference profile ascending, " as *u8); tn(dist_total_count(s)) 43 tw(" crystals, mean D=" as *u8); tn(mean0); tw(" (0.1um): " as *u8) 44 if ok1 == 1 { pass = pass + 1; tw("PASS\n" as *u8) } else { tw("FAIL\n" as *u8) } 45 46 // --- T2 ***MASS CONSERVATION.*** Melting and redepositing moves ice 47 // between crystals; it must not create or destroy any. Every 48 // growth number in this gate is meaningless if this fails. --- 49 total = total + 1 50 let s2: *IceDist = dist_reference() 51 let m_before: i64 = dist_total_mass(s2) 52 dist_apply_cycle(s2, 100) 53 let m_after: i64 = dist_total_mass(s2) 54 let drift: i64 = iabs(m_after - m_before) * 1000 / m_before 55 tw("T2 mass before=" as *u8); tn(m_before); tw(" after a 100permil cycle=" as *u8); tn(m_after) 56 // The tolerance is not a fudge: diameters are quantised to 0.1 um, so a 57 // bin's volume carries up to 3 x 0.05/d relative error after rounding -- 58 // about 7 permil for a 20 um crystal, partly cancelling across bins. 59 // Anything beyond that is a leak, not quantisation, and 175 permil is 60 // what this check caught on the first run. 61 tw(", drift=" as *u8); tn(drift); tw(" permil (quantisation budget 15): " as *u8) 62 if drift <= 15 { pass = pass + 1; tw("PASS\n" as *u8) } else { tw("FAIL\n" as *u8) } 63 64 // --- T3 A cycle COARSENS: the mean diameter must rise, and the crystal 65 // count must fall. Those are two independent consequences of the 66 // same mechanism, so checking both is not redundant. --- 67 total = total + 1 68 let mean_after: i64 = dist_mean_diameter(s2) 69 let cnt_after: i64 = dist_total_count(s2) 70 tw("T3 after one cycle: mean D " as *u8); tn(mean0); tw("->" as *u8); tn(mean_after) 71 tw(", count " as *u8); tn(dist_total_count(s)); tw("->" as *u8); tn(cnt_after); tw(": " as *u8) 72 var ok3: i64 = 1 73 if mean_after <= mean0 { ok3 = 0 } 74 if cnt_after >= dist_total_count(s) { ok3 = 0 } 75 if ok3 == 1 { pass = pass + 1; tw("PASS\n" as *u8) } else { tw("FAIL\n" as *u8) } 76 77 // --- T4 ***THE MEASUREMENT THAT KILLS THE ASSERTION.*** Melting 100 78 // permil of the MASS removes far more than 100 permil of the 79 // COUNT, because small crystals are numerous and light. A 80 // coupling of 1.0 is precisely the claim that these two numbers 81 // are equal. --- 82 total = total + 1 83 let phi: i64 = 100 84 let nu: i64 = dist_number_fraction_permil(s, phi) 85 tw("T4 melting " as *u8); tn(phi); tw(" permil of the MASS removes " as *u8); tn(nu) 86 tw(" permil of the COUNT -- a coupling of 1.0 claims these are equal: " as *u8) 87 var ok4: i64 = 1 88 if nu <= phi { ok4 = 0 } 89 if nu >= 1000 { ok4 = 0 } 90 if ok4 == 1 { pass = pass + 1; tw("PASS\n" as *u8) } else { tw("FAIL\n" as *u8) } 91 92 // --- T5 ***HOW WRONG, AS A NUMBER.*** The derived coupling against the 93 // constant nx_ice_recrystal asserts. --- 94 total = total + 1 95 let derived: i64 = dist_derived_coupling(s, phi) 96 let err: i64 = dist_coupling_error_permil(s, phi, IR_COUPLING) 97 tw("T5 derived coupling=" as *u8); tn(derived) 98 tw(" vs asserted IR_COUPLING=" as *u8); tn(IR_COUPLING) 99 tw(" -> assertion is off by " as *u8); tn(err); tw(" permil: " as *u8) 100 var ok5: i64 = 1 101 if derived <= IR_COUPLING { ok5 = 0 } 102 if err >= 0 { ok5 = 0 } 103 if ok5 == 1 { pass = pass + 1; tw("PASS\n" as *u8) } else { tw("FAIL\n" as *u8) } 104 105 // --- T6 ***THE DIRECTION, AS A VERDICT.*** The asserted constant 106 // UNDER-states damage, which is the direction that reports a 107 // product as fine when it is not. A consumer must not have to 108 // infer this from the sign of a number. --- 109 total = total + 1 110 let conservative: i64 = dist_asserted_is_conservative(s, phi, IR_COUPLING) 111 tw("T6 is the asserted coupling conservative? " as *u8); tn(conservative) 112 tw(" (0 = it UNDER-states damage, the unsafe direction): " as *u8) 113 if conservative == 0 { pass = pass + 1; tw("PASS\n" as *u8) } else { tw("FAIL\n" as *u8) } 114 115 // --- T7 NON-VACUITY of T6: the verdict must be capable of saying yes. 116 // Handed a genuinely conservative constant it must report 1, so 117 // T6 is measuring the constant and not hard-wired to complain. --- 118 total = total + 1 119 let big: i64 = derived * 2 120 let conservative2: i64 = dist_asserted_is_conservative(s, phi, big) 121 tw("T7 handed a deliberately large coupling (" as *u8); tn(big) 122 tw(") the same check reports conservative=" as *u8); tn(conservative2); tw(" (want 1): " as *u8) 123 if conservative2 == 1 { pass = pass + 1; tw("PASS\n" as *u8) } else { tw("FAIL\n" as *u8) } 124 125 // --- T8 The coupling DEPENDS ON THE DISTRIBUTION, which is the whole 126 // reason it could never have been a universal constant. A 127 // narrow, uniform population loses far less of its count for the 128 // same mass melted than a broad one with a small-crystal tail. --- 129 total = total + 1 130 let narrow: *IceDist = dist_new(3) 131 dist_set(narrow, 0, 240, 1000) 132 dist_set(narrow, 1, 250, 1000) 133 dist_set(narrow, 2, 260, 1000) 134 let c_narrow: i64 = dist_derived_coupling(narrow, phi) 135 tw("T8 broad profile coupling=" as *u8); tn(derived) 136 tw(" vs narrow profile coupling=" as *u8); tn(c_narrow) 137 tw(" -- not a universal constant: " as *u8) 138 var ok8: i64 = 1 139 if c_narrow == DIST_INVALID { ok8 = 0 } 140 if c_narrow >= derived { ok8 = 0 } 141 if ok8 == 1 { pass = pass + 1; tw("PASS\n" as *u8) } else { tw("FAIL\n" as *u8) } 142 143 // --- T9 Zero melt is zero growth, exactly. The control that proves the 144 // growth tracks the excursion rather than being applied to every 145 // distribution the model touches. --- 146 total = total + 1 147 let s9: *IceDist = dist_reference() 148 let mean9: i64 = dist_mean_diameter(s9) 149 dist_apply_cycle(s9, 0) 150 var ok9: i64 = 1 151 if dist_mean_diameter(s9) != mean9 { ok9 = 0 } 152 if dist_number_fraction_permil(s, 0) != 0 { ok9 = 0 } 153 if dist_volume_growth_permil(s, 0) != 0 { ok9 = 0 } 154 tw("T9 a zero-amplitude cycle changes nothing at all: " as *u8) 155 if ok9 == 1 { pass = pass + 1; tw("PASS\n" as *u8) } else { tw("FAIL\n" as *u8) } 156 157 // --- T10 FAIL-CLOSED, and the reference profile is FLAGGED. A caller 158 // using the built-in shape rather than measured bin counts must 159 // be able to tell -- otherwise a shape-correct answer reads as a 160 // measured one. --- 161 total = total + 1 162 var ok10: i64 = 1 163 if dist_number_fraction_permil(s, 0 - 1) != DIST_INVALID { ok10 = 0 } 164 if dist_number_fraction_permil(s, 1001) != DIST_INVALID { ok10 = 0 } 165 if dist_derived_coupling(s, 0) != DIST_INVALID { ok10 = 0 } 166 if dist_profile_is_reference() != 1 { ok10 = 0 } 167 let bad: *IceDist = dist_new(2) 168 dist_set(bad, 0, 300, 10) 169 dist_set(bad, 1, 100, 10) 170 if dist_count_melted(bad, 100) != DIST_INVALID { ok10 = 0 } 171 tw("T10 out-of-range phi refused, descending bins refused, reference profile flagged: " as *u8) 172 if ok10 == 1 { pass = pass + 1; tw("PASS\n" as *u8) } else { tw("FAIL\n" as *u8) } 173 174 // --- T11 CROSS-ORGAN AGREEMENT. Feeding the DERIVED coupling into 175 // nx_ice_recrystal must produce more growth than the asserted one 176 // did, by the margin T5 measured. The two organs are independent 177 // paths to the same quantity, so agreement is evidence. --- 178 total = total + 1 179 let with_asserted: i64 = ir_size_after_cycles(250, phi, 10) 180 let growth_derived: i64 = dist_volume_growth_permil(s, phi) 181 var v: i64 = 250 * 250 * 250 182 var c: i64 = 0 183 while c < 10 { v = v + v * growth_derived / 1000; c = c + 1 } 184 let with_derived: i64 = ir_icbrt(v) 185 tw("T11 after 10 cycles: asserted coupling gives D=" as *u8); tn(with_asserted) 186 tw(", derived coupling gives D=" as *u8); tn(with_derived) 187 tw(" -- the assertion was optimistic: " as *u8) 188 if with_derived > with_asserted { pass = pass + 1; tw("PASS\n" as *u8) } else { tw("FAIL\n" as *u8) } 189 190 // --- T12 ***THE CORRECTION TO A PUBLISHED NUMBER.*** Wave 26 published 191 // the realistic -20/-16 C case (33 permil of the ice cycling, 192 // 17 excursions over 60 days) using the ASSERTED coupling and 193 // reported 43.6 um. Recomputed with the coupling derived from 194 // the distribution, the real figure is worse. Both are printed 195 // so the size of the correction is visible rather than quietly 196 // replaced. --- 197 total = total + 1 198 let phi_real: i64 = 33 199 let g_real: i64 = dist_volume_growth_permil(s, phi_real) 200 let pub: i64 = ir_size_combined(250, 537500, 60, phi_real, 17) 201 let corrected: i64 = ir_size_combined_growth(250, 537500, 60, g_real, 17) 202 tw("T12 realistic -20/-16C over 60d: published(asserted coupling) D=" as *u8); tn(pub) 203 tw(" corrected(derived coupling) D=" as *u8); tn(corrected) 204 tw(" per-cycle growth=" as *u8); tn(g_real); tw(" permil; grades " as *u8) 205 tn(ir_texture_grade(pub)); tw(" -> " as *u8); tn(ir_texture_grade(corrected)); tw(": " as *u8) 206 var ok12: i64 = 1 207 if g_real <= 0 { ok12 = 0 } 208 if corrected <= pub { ok12 = 0 } 209 if ir_texture_grade(corrected) < ir_texture_grade(pub) { ok12 = 0 } 210 if ok12 == 1 { pass = pass + 1; tw("PASS\n" as *u8) } else { tw("FAIL\n" as *u8) } 211 212 tw("ICE-DISTRIBUTION-GATE passed " as *u8); tn(pass); tw("/" as *u8); tn(total) 213 if pass == total { tw(" verdict=GREEN\n" as *u8); sys_exit(0); return 0 } 214 tw(" verdict=RED\n" as *u8); sys_exit(1); return 1 215}