code wiki / (root) / sketch_holt_test.nx

sketch_holt_test.nx source

↩ module page · 86 lines · 3060 B

1// sketch_holt_test.nx -- Holt's linear forecast verification. 2 3import "syscalls.nx" 4import "sketch_holt.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 + bounds ---- 14 let h: *Holt = nx_holt_alloc(200000, 100000) // alpha=0.2, beta=0.1 15 if h == (0 as *Holt) { return __syscall(93, 5, 0, 0, 0, 0, 0) } 16 if nx_holt_alloc(0, 100000) != (0 as *Holt) { 17 return __syscall(93, 6, 0, 0, 0, 0, 0) 18 } 19 if nx_holt_alloc(2000000, 100000) != (0 as *Holt) { 20 return __syscall(93, 7, 0, 0, 0, 0, 0) 21 } 22 23 // ---- first sample initializes level ---- 24 nx_holt_add(h, 100) 25 if nx_holt_level(h) != 100 { return __syscall(93, 10, 0, 0, 0, 0, 0) } 26 if nx_holt_trend(h) != 0 { return __syscall(93, 11, 0, 0, 0, 0, 0) } 27 if nx_holt_count(h) != 1 { return __syscall(93, 12, 0, 0, 0, 0, 0) } 28 29 // ---- second sample with constant offset: trend emerges ---- 30 nx_holt_add(h, 110) 31 // level_carry = 100 + 0 = 100; new_level = 0.2*110 + 0.8*100 = 22+80 = 102 32 // level_delta = 102 - 100 = 2 33 // new_trend = 0.1 * 2 + 0.9 * 0 = 0 34 if iabs(nx_holt_level(h) - 102) > 1 { return __syscall(93, 20, 0, 0, 0, 0, 0) } 35 // Trend integer-truncates to 0 here. 36 37 // ---- trending data: linear ramp y = 10*t ---- 38 let h2: *Holt = nx_holt_alloc(500000, 500000) // alpha=0.5, beta=0.5 39 var i: i64 = 1 40 while i <= 50 { 41 nx_holt_add(h2, 10 * i) 42 i = i + 1 43 } 44 // After enough data, level should be near 500 (10*50), trend ~10. 45 let lvl: i64 = nx_holt_level(h2) 46 if iabs(lvl - 500) > 50 { 47 return __syscall(93, 30, 0, 0, 0, 0, 0) 48 } 49 let trnd: i64 = nx_holt_trend(h2) 50 if iabs(trnd - 10) > 3 { 51 return __syscall(93, 31, 0, 0, 0, 0, 0) 52 } 53 54 // ---- forecast: 5 steps ahead ---- 55 let f5: i64 = nx_holt_forecast(h2, 5) 56 // level + 5 * trend ~ 500 + 50 = 550. 57 if iabs(f5 - 550) > 80 { 58 return __syscall(93, 40, 0, 0, 0, 0, 0) 59 } 60 61 // ---- typed envelope ---- 62 let q: *ApproxI64 = nx_holt_query_forecast(h2, 10) 63 if q.envelope_kind != NX_ENV_ABS { 64 return __syscall(93, 50, 0, 0, 0, 0, 0) 65 } 66 if q.param_a != 10 { 67 return __syscall(93, 51, 0, 0, 0, 0, 0) 68 } 69 if q.maturity != NX_MATURITY_PRODUCTION { 70 return __syscall(93, 52, 0, 0, 0, 0, 0) 71 } 72 73 // ---- spike rejection: heavy smoothing dampens spike ---- 74 let h3: *Holt = nx_holt_alloc(50000, 50000) // alpha=0.05, beta=0.05 75 nx_holt_add(h3, 100) 76 nx_holt_add(h3, 100) 77 nx_holt_add(h3, 10000) // huge spike 78 // With heavy smoothing, level should remain near 100 (spike barely affects). 79 // After 3 samples: alpha=0.05 -> spike contributes only 5%. 80 let lvl_spike: i64 = nx_holt_level(h3) 81 if lvl_spike > 700 { // spike dampened to less than ~7% of true 82 return __syscall(93, 60, 0, 0, 0, 0, 0) 83 } 84 85 return 0 86}