sketch_correlation_test.nx source
↩ module page · 158 lines · 4838 B
1// sketch_correlation_test.nx -- streaming Pearson + regression verification.
2
3import "syscalls.nx"
4import "sketch_correlation.nx"
5import "sketch_types.nx"
6
7func iabs(x: i64) -> i64 {
8 if x < 0 { return -x }
9 return x
10}
11
12func main() -> i64 {
13 // ---- alloc + empty ----
14 let c: *Correlation = nx_corr_alloc()
15 if c == (0 as *Correlation) { return __syscall(93, 5, 0, 0, 0, 0, 0) }
16 if c.n != 0 { return __syscall(93, 6, 0, 0, 0, 0, 0) }
17 // Single point -> n<2 -> returns 0.
18 nx_corr_add(c, 5, 10)
19 if nx_corr_r_ppm(c) != 0 {
20 return __syscall(93, 10, 0, 0, 0, 0, 0)
21 }
22
23 // ---- perfect positive correlation: r = +1.0 ----
24 // y = 2x for x in 1..20. r should be exactly 1.0 (PPM = 1_000_000).
25 let c1: *Correlation = nx_corr_alloc()
26 var i: i64 = 1
27 while i <= 20 {
28 nx_corr_add(c1, i, 2 * i)
29 i = i + 1
30 }
31 let r1: i64 = nx_corr_r_ppm(c1)
32 if iabs(r1 - 1000000) > 10000 {
33 return __syscall(93, 20, 0, 0, 0, 0, 0)
34 }
35 // Slope should be 2.0 (PPM = 2_000_000).
36 let s1: i64 = nx_corr_slope_ppm(c1)
37 if iabs(s1 - 2000000) > 10000 {
38 return __syscall(93, 21, 0, 0, 0, 0, 0)
39 }
40 // Intercept should be 0.
41 let b1: i64 = nx_corr_intercept(c1)
42 if iabs(b1) > 2 {
43 return __syscall(93, 22, 0, 0, 0, 0, 0)
44 }
45
46 // ---- perfect negative correlation: r = -1.0 ----
47 let c2: *Correlation = nx_corr_alloc()
48 i = 1
49 while i <= 20 {
50 nx_corr_add(c2, i, 100 - i)
51 i = i + 1
52 }
53 let r2: i64 = nx_corr_r_ppm(c2)
54 if iabs(r2 - (-1000000)) > 10000 {
55 return __syscall(93, 30, 0, 0, 0, 0, 0)
56 }
57 let s2: i64 = nx_corr_slope_ppm(c2)
58 // slope = -1.0 (PPM = -1_000_000).
59 if iabs(s2 - (-1000000)) > 10000 {
60 return __syscall(93, 31, 0, 0, 0, 0, 0)
61 }
62 // intercept = 100.
63 let b2: i64 = nx_corr_intercept(c2)
64 if iabs(b2 - 100) > 2 {
65 return __syscall(93, 32, 0, 0, 0, 0, 0)
66 }
67
68 // ---- zero correlation (degenerate symmetric x) ----
69 // For y = x², the correlation r is positive but slope is approximately
70 // mean(x). Skip this exact test -- variance and mean both nonzero.
71 // Instead test: constant y, varying x -> r=0, slope=0.
72 let c3: *Correlation = nx_corr_alloc()
73 i = 1
74 while i <= 20 {
75 nx_corr_add(c3, i, 50) // y constant
76 i = i + 1
77 }
78 // var_y = 0 -> r = 0 (by guard). slope = 0 (cov_xy = 0).
79 if nx_corr_r_ppm(c3) != 0 {
80 return __syscall(93, 40, 0, 0, 0, 0, 0)
81 }
82 if nx_corr_slope_ppm(c3) != 0 {
83 return __syscall(93, 41, 0, 0, 0, 0, 0)
84 }
85
86 // ---- linear with offset: y = 3x + 5 ----
87 let c4: *Correlation = nx_corr_alloc()
88 i = 1
89 while i <= 20 {
90 nx_corr_add(c4, i, 3 * i + 5)
91 i = i + 1
92 }
93 // slope=3 (PPM=3_000_000), intercept=5, r=1.0.
94 let r4: i64 = nx_corr_r_ppm(c4)
95 if iabs(r4 - 1000000) > 10000 {
96 return __syscall(93, 50, 0, 0, 0, 0, 0)
97 }
98 let s4: i64 = nx_corr_slope_ppm(c4)
99 if iabs(s4 - 3000000) > 10000 {
100 return __syscall(93, 51, 0, 0, 0, 0, 0)
101 }
102 let b4: i64 = nx_corr_intercept(c4)
103 if iabs(b4 - 5) > 2 {
104 return __syscall(93, 52, 0, 0, 0, 0, 0)
105 }
106
107 // ---- typed envelope ----
108 let q: *ApproxI64 = nx_corr_query_r(c1)
109 if q.envelope_kind != NX_ENV_ABS {
110 return __syscall(93, 60, 0, 0, 0, 0, 0)
111 }
112 if q.maturity != NX_MATURITY_PRODUCTION {
113 return __syscall(93, 61, 0, 0, 0, 0, 0)
114 }
115
116 // ---- overflow guard ----
117 if nx_corr_safe_p(32768, 0) != 0 {
118 return __syscall(93, 70, 0, 0, 0, 0, 0)
119 }
120 if nx_corr_safe_p(0, 32768) != 0 {
121 return __syscall(93, 71, 0, 0, 0, 0, 0)
122 }
123 if nx_corr_safe_p(1000, 1000) != 1 {
124 return __syscall(93, 72, 0, 0, 0, 0, 0)
125 }
126 let co: *Correlation = nx_corr_alloc()
127 if nx_corr_add(co, 32768, 0) != -1 {
128 return __syscall(93, 73, 0, 0, 0, 0, 0)
129 }
130 if co.n != 0 {
131 return __syscall(93, 74, 0, 0, 0, 0, 0)
132 }
133
134 // ---- merge ----
135 let m_a: *Correlation = nx_corr_alloc()
136 let m_b: *Correlation = nx_corr_alloc()
137 i = 1
138 while i <= 10 {
139 nx_corr_add(m_a, i, 2 * i)
140 i = i + 1
141 }
142 i = 11
143 while i <= 20 {
144 nx_corr_add(m_b, i, 2 * i)
145 i = i + 1
146 }
147 let merged: *Correlation = nx_corr_merge(m_a, m_b)
148 if nx_corr_count(merged) != 20 {
149 return __syscall(93, 80, 0, 0, 0, 0, 0)
150 }
151 // Merged is equivalent to c1 (same data). r=1.0, slope=2.0.
152 let r_m: i64 = nx_corr_r_ppm(merged)
153 if iabs(r_m - 1000000) > 10000 {
154 return __syscall(93, 81, 0, 0, 0, 0, 0)
155 }
156
157 return 0
158}