nx_numeric_oracle_test.nx source
↩ module page · 161 lines · 7016 B
1// nx_numeric_oracle_test.nx -- verify the verifier.
2//
3// The oracle is the tool every future kernel passes through. If the
4// oracle is buggy, every "verified" claim downstream is suspect. So
5// we test it harder than a normal smoke -- positive + negative paths,
6// witness extraction, all 6 verdicts, metamorphic invariants.
7
8import "nx_syscalls.nx"
9import "nx_tier.nx"
10import "nx_prng.nx"
11import "nx_tensor.nx"
12import "nx_numeric_oracle.nx"
13
14func main() -> nx_int {
15 let err: *i64 = (sys_mmap(8)) as *i64
16 let witness: *i64 = (sys_mmap(NX_NO_WITNESS_FIELDS * 8)) as *i64
17
18 // ===== Build two identical i64 3x4 tensors ===================
19 let shape: *i64 = (sys_mmap(16)) as *i64
20 shape[0] = 3; shape[1] = 4
21
22 let ta: *NxTensor = nx_t_alloc(NX_DT_I64, shape, 2, err)
23 let tb: *NxTensor = nx_t_alloc(NX_DT_I64, shape, 2, err)
24 nx_t_fill_zero(ta)
25 nx_t_fill_zero(tb)
26
27 let idx: *i64 = (sys_mmap(64)) as *i64
28 idx[0] = 0; idx[1] = 0; nx_t_set_i64(ta, idx, 42); nx_t_set_i64(tb, idx, 42)
29 idx[0] = 1; idx[1] = 2; nx_t_set_i64(ta, idx, 99); nx_t_set_i64(tb, idx, 99)
30 idx[0] = 2; idx[1] = 3; nx_t_set_i64(ta, idx, 1000); nx_t_set_i64(tb, idx, 1000)
31
32 // ===== BIT_EXACT: identical tensors -> EQUAL =================
33 let v1: nx_int = nx_no_check_bit_exact_i64(ta, tb, witness)
34 if v1 != NX_NO_VERDICT_EQUAL { return 1 }
35
36 // ===== BIT_EXACT: mutate one cell -> DIFFERS + witness =======
37 idx[0] = 1; idx[1] = 2; nx_t_set_i64(tb, idx, 100)
38 let v2: nx_int = nx_no_check_bit_exact_i64(ta, tb, witness)
39 if v2 != NX_NO_VERDICT_DIFFERS { return 2 }
40 // Witness should have row=1, col=2, actual=99, expected=100
41 if witness[NX_NO_WITNESS_F_IDX0] != 1 { return 3 }
42 if witness[NX_NO_WITNESS_F_IDX1] != 2 { return 4 }
43 if witness[NX_NO_WITNESS_F_ACTUAL] != 99 { return 5 }
44 if witness[NX_NO_WITNESS_F_EXPECTED] != 100 { return 6 }
45 if witness[NX_NO_WITNESS_F_ABS_DIFF] != 1 { return 7 }
46 // Repair
47 idx[0] = 1; idx[1] = 2; nx_t_set_i64(tb, idx, 99)
48
49 // ===== Shape mismatch -> SHAPE_MISMATCH =====================
50 let shape3: *i64 = (sys_mmap(16)) as *i64
51 shape3[0] = 4; shape3[1] = 4
52 let tc: *NxTensor = nx_t_alloc(NX_DT_I64, shape3, 2, err)
53 let v3: nx_int = nx_no_check_bit_exact_i64(ta, tc, witness)
54 if v3 != NX_NO_VERDICT_SHAPE_MISMATCH { return 10 }
55
56 // ===== Ndim mismatch -> SHAPE_MISMATCH ======================
57 shape3[0] = 12
58 let td: *NxTensor = nx_t_alloc(NX_DT_I64, shape3, 1, err)
59 let v4: nx_int = nx_no_check_bit_exact_i64(ta, td, witness)
60 if v4 != NX_NO_VERDICT_SHAPE_MISMATCH { return 11 }
61
62 // ===== Structural-only check ================================
63 let v5: nx_int = nx_no_check_structural(ta, tb)
64 if v5 != NX_NO_VERDICT_EQUAL { return 12 }
65 let v6: nx_int = nx_no_check_structural(ta, tc)
66 if v6 != NX_NO_VERDICT_SHAPE_MISMATCH { return 13 }
67
68 // ===== EPSILON_REL with eps=0 acts like bit-exact ===========
69 let v7: nx_int = nx_no_check_epsilon_rel_q10(ta, tb, 0, witness)
70 if v7 != NX_NO_VERDICT_EQUAL { return 20 }
71
72 // Differ by 1 unit, eps_q10 = 0 -> DIFFERS
73 idx[0] = 0; idx[1] = 0; nx_t_set_i64(tb, idx, 43)
74 let v8: nx_int = nx_no_check_epsilon_rel_q10(ta, tb, 0, witness)
75 if v8 != NX_NO_VERDICT_DIFFERS { return 21 }
76
77 // Same delta, eps_q10 = 51 (5% relative) -> EQUAL since
78 // 1 <= 0.05 * 43 = 2 (after Q10 math floors).
79 // Actually 51 * 43 / 1024 = 2; |42 - 43| = 1 <= 2 -> EQUAL.
80 let v9: nx_int = nx_no_check_epsilon_rel_q10(ta, tb, 51, witness)
81 if v9 != NX_NO_VERDICT_EQUAL { return 22 }
82 // Repair
83 idx[0] = 0; idx[1] = 0; nx_t_set_i64(tb, idx, 42)
84
85 // ===== Property-based generator ==============================
86 let prng: *i64 = (sys_mmap(8)) as *i64
87 nx_prng_init(prng, 12345)
88 let gen_t: *NxTensor = nx_no_gen_random_i64(shape, 2,
89 0 - 50, 50, prng, err)
90 if (gen_t as nx_int) == 0 { return 30 }
91 if gen_t.numel != 12 { return 31 }
92 // Spot-check: every element should be in [-50, 50)
93 let pg: *i64 = gen_t.storage as *i64
94 var k: nx_int = 0
95 while k < gen_t.numel {
96 if pg[k] < 0 - 50 { return 32 }
97 if pg[k] >= 50 { return 33 }
98 k = k + 1
99 }
100
101 // Same seed -> reproducible: generate again and check identical
102 nx_prng_init(prng, 12345)
103 let gen_t2: *NxTensor = nx_no_gen_random_i64(shape, 2,
104 0 - 50, 50, prng, err)
105 let v10: nx_int = nx_no_check_bit_exact_i64(gen_t, gen_t2, witness)
106 if v10 != NX_NO_VERDICT_EQUAL { return 34 } // reproducibility holds
107
108 // ===== Metamorphic: double-transpose identity ===============
109 //
110 // permute reverse twice should land you back at the original
111 // logical indexing. Build a 2x3 tensor with marker values.
112 let mshape: *i64 = (sys_mmap(16)) as *i64
113 mshape[0] = 2; mshape[1] = 3
114 let tm: *NxTensor = nx_t_alloc(NX_DT_I64, mshape, 2, err)
115 idx[0] = 0; idx[1] = 0; nx_t_set_i64(tm, idx, 1)
116 idx[0] = 0; idx[1] = 1; nx_t_set_i64(tm, idx, 2)
117 idx[0] = 0; idx[1] = 2; nx_t_set_i64(tm, idx, 3)
118 idx[0] = 1; idx[1] = 0; nx_t_set_i64(tm, idx, 4)
119 idx[0] = 1; idx[1] = 1; nx_t_set_i64(tm, idx, 5)
120 idx[0] = 1; idx[1] = 2; nx_t_set_i64(tm, idx, 6)
121
122 let v11: nx_int = nx_no_check_double_transpose_id(tm, witness)
123 if v11 != NX_NO_VERDICT_EQUAL { return 40 }
124
125 // ===== Differential verdict routing ========================
126 let v12: nx_int = nx_no_differential_verdict(ta, tb,
127 NX_NO_CMP_BIT_EXACT,
128 0, witness)
129 if v12 != NX_NO_VERDICT_EQUAL { return 50 }
130
131 let v13: nx_int = nx_no_differential_verdict(ta, tc,
132 NX_NO_CMP_STRUCTURAL,
133 0, witness)
134 if v13 != NX_NO_VERDICT_SHAPE_MISMATCH { return 51 }
135
136 // ===== Kahan sum (i64 = plain sum for v1) ==================
137 let vals: *i64 = (sys_mmap(40)) as *i64
138 vals[0] = 1; vals[1] = 2; vals[2] = 3; vals[3] = 4; vals[4] = 5
139 if nx_no_kahan_sum_i64(vals, 5) != 15 { return 60 }
140
141 // ===== Reproducibility check (hash bytes) ==================
142 let h1: *u8 = sys_mmap(32)
143 let h2: *u8 = sys_mmap(32)
144 var i: nx_int = 0
145 while i < 32 {
146 h1[i] = i
147 h2[i] = i
148 i = i + 1
149 }
150 if nx_no_check_reproducible(h1, h2, 32) != NX_NO_VERDICT_EQUAL { return 70 }
151 h2[5] = 99
152 if nx_no_check_reproducible(h1, h2, 32) != NX_NO_VERDICT_DIFFERS { return 71 }
153
154 // ===== Enum validity =======================================
155 if nx_no_cmp_kind_is_valid(NX_NO_CMP_BIT_EXACT) != 1 { return 80 }
156 if nx_no_cmp_kind_is_valid(NX_NO_CMP_N_KINDS) != 0 { return 81 }
157 if nx_no_verdict_is_valid(NX_NO_VERDICT_EQUAL) != 1 { return 82 }
158 if nx_no_verdict_is_valid(NX_NO_VERDICT_N_KINDS) != 0 { return 83 }
159
160 return 0
161}