sketch_holt_vs_ewma_trended_bench.nx source
↩ module page · 79 lines · 2729 B
1// sketch_holt_vs_ewma_trended_bench.nx -- trend tracking paired bench.
2//
3// CLAIM TO VALIDATE:
4// Holt's method (Holt 1957) = EWMA + linear trend component. On
5// trended data, Holt's h-step forecast extrapolates the trend.
6// EWMA tracks level only -- its forecast is FLAT (=current level),
7// so it lags behind the trend.
8//
9// WORKLOAD:
10// y_t = 100 + 5*t (linear trend, slope=5)
11// Stream t=1..50 into both.
12// Forecast h=5 steps ahead: truth y_55 = 100 + 5*55 = 375.
13// At step 50: y_50 = 350.
14// Holt forecast(5) ~ y_50 + 5*trend = 350 + 25 = 375 (matches truth)
15// EWMA forecast = y_50 ~ 350 (flat extrapolation; lags by 25)
16//
17// MEASUREMENT:
18// ACCURACY axis vs truth 375.
19
20import "syscalls.nx"
21import "sketch_holt.nx"
22import "sketch_ewma.nx"
23import "sketch_comparator.nx"
24import "sketch_types.nx"
25
26func iabs_he(x: i64) -> i64 {
27 if x < 0 { return -x }
28 return x
29}
30
31func main() -> i64 {
32 let alpha_ppm: i64 = 300000 // 0.3
33 let beta_ppm: i64 = 200000 // 0.2 trend smoothing
34
35 let holt: *Holt = nx_holt_alloc(alpha_ppm, beta_ppm)
36 let ewma: *Ewma = nx_ewma_alloc(alpha_ppm)
37 if holt == (0 as *Holt) { return __syscall(93, 1, 0, 0, 0, 0, 0) }
38 if ewma == (0 as *Ewma) { return __syscall(93, 2, 0, 0, 0, 0, 0) }
39
40 // ---- Stream trended series y_t = 100 + 5*t ----
41 var t: i64 = 1
42 while t <= 50 {
43 let y: i64 = 100 + 5 * t
44 nx_holt_add(holt, y)
45 nx_ewma_add(ewma, y)
46 t = t + 1
47 }
48
49 // ---- Forecast 5 steps ahead ----
50 let truth: i64 = 100 + 5 * 55 // 375
51 let holt_fc: i64 = nx_holt_forecast(holt, 5)
52 let ewma_fc: i64 = nx_ewma_value(ewma) // flat forecast = current level
53
54 // ---- Sanity: both produced reasonable values ----
55 if holt_fc <= 0 { return __syscall(93, 5, 0, 0, 0, 0, 0) }
56 if ewma_fc <= 0 { return __syscall(93, 6, 0, 0, 0, 0, 0) }
57
58 // ---- ACCURACY: Holt closer to truth=375 ----
59 let acc: *ComparisonResult = nx_cmp_accuracy(holt_fc, ewma_fc, truth, 10000)
60 if acc.verdict != NX_CMP_VERDICT_BEATS {
61 return __syscall(93, 10, 0, 0, 0, 0, 0)
62 }
63 // Holt should be materially closer (EWMA lags by ~25 on slope=5,h=5).
64 if acc.delta_ppm < 30000 { // require >=3% improvement-of-truth
65 return __syscall(93, 11, 0, 0, 0, 0, 0)
66 }
67
68 // ---- Sanity: Holt's forecast within 10% of truth ----
69 if iabs_he(holt_fc - truth) > (truth * 10) / 100 {
70 return __syscall(93, 20, 0, 0, 0, 0, 0)
71 }
72 // ---- Sanity: EWMA forecast is materially BELOW truth (lag confirmed) ----
73 if ewma_fc >= truth {
74 // EWMA shouldn't beat truth -- it lags
75 return __syscall(93, 30, 0, 0, 0, 0, 0)
76 }
77
78 return 0
79}