sketch_markov_test.nx source
↩ module page · 126 lines · 4818 B
1// sketch_markov_test.nx -- Markov chain transition tracker verification.
2
3import "syscalls.nx"
4import "sketch_markov.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 ----
14 let m: *Markov = nx_markov_alloc(4)
15 if m == (0 as *Markov) { return __syscall(93, 5, 0, 0, 0, 0, 0) }
16 if nx_markov_total(m) != 0 { return __syscall(93, 6, 0, 0, 0, 0, 0) }
17 // Reject N<2.
18 if nx_markov_alloc(1) != (0 as *Markov) {
19 return __syscall(93, 7, 0, 0, 0, 0, 0)
20 }
21 // Reject N>MAX.
22 if nx_markov_alloc(5000) != (0 as *Markov) {
23 return __syscall(93, 8, 0, 0, 0, 0, 0)
24 }
25
26 // ---- observe explicit transitions ----
27 nx_markov_observe(m, 0, 1)
28 nx_markov_observe(m, 0, 1)
29 nx_markov_observe(m, 0, 2)
30 nx_markov_observe(m, 1, 0)
31 // counts: t[0][1]=2, t[0][2]=1, t[1][0]=1.
32 if nx_markov_count(m, 0, 1) != 2 { return __syscall(93, 10, 0, 0, 0, 0, 0) }
33 if nx_markov_count(m, 0, 2) != 1 { return __syscall(93, 11, 0, 0, 0, 0, 0) }
34 if nx_markov_count(m, 1, 0) != 1 { return __syscall(93, 12, 0, 0, 0, 0, 0) }
35 if nx_markov_count(m, 2, 3) != 0 { return __syscall(93, 13, 0, 0, 0, 0, 0) }
36 // row_sums: [3, 1, 0, 0]
37 if nx_markov_row_sum(m, 0) != 3 { return __syscall(93, 14, 0, 0, 0, 0, 0) }
38 if nx_markov_row_sum(m, 1) != 1 { return __syscall(93, 15, 0, 0, 0, 0, 0) }
39 if nx_markov_total(m) != 4 { return __syscall(93, 16, 0, 0, 0, 0, 0) }
40
41 // ---- probability query (PPM) ----
42 // P[0][1] = 2/3 = 666_666 PPM (integer truncation -> 666_666)
43 let p01: i64 = nx_markov_probability_ppm(m, 0, 1)
44 if iabs(p01 - 666666) > 1 {
45 return __syscall(93, 20, 0, 0, 0, 0, 0)
46 }
47 // P[0][2] = 1/3 = 333_333 PPM
48 let p02: i64 = nx_markov_probability_ppm(m, 0, 2)
49 if iabs(p02 - 333333) > 1 {
50 return __syscall(93, 21, 0, 0, 0, 0, 0)
51 }
52 // P[1][0] = 1/1 = 1_000_000 PPM
53 let p10: i64 = nx_markov_probability_ppm(m, 1, 0)
54 if p10 != 1000000 {
55 return __syscall(93, 22, 0, 0, 0, 0, 0)
56 }
57 // P[2][anything] = 0 (unobserved row).
58 if nx_markov_probability_ppm(m, 2, 0) != 0 {
59 return __syscall(93, 23, 0, 0, 0, 0, 0)
60 }
61
62 // ---- predict: most likely next state ----
63 // From 0: best is 1 (count 2 > count 1 for state 2).
64 if nx_markov_predict(m, 0) != 1 {
65 return __syscall(93, 30, 0, 0, 0, 0, 0)
66 }
67 // From 1: best is 0 (only observed).
68 if nx_markov_predict(m, 1) != 0 {
69 return __syscall(93, 31, 0, 0, 0, 0, 0)
70 }
71 // From 2 (unobserved): -1.
72 if nx_markov_predict(m, 2) != -1 {
73 return __syscall(93, 32, 0, 0, 0, 0, 0)
74 }
75
76 // ---- step API (sequential streaming) ----
77 let m2: *Markov = nx_markov_alloc(3)
78 // Sequence: 0 -> 1 -> 2 -> 0 -> 1 -> 2 -> 0
79 nx_markov_step(m2, 0) // seed (no transition yet)
80 nx_markov_step(m2, 1) // 0->1
81 nx_markov_step(m2, 2) // 1->2
82 nx_markov_step(m2, 0) // 2->0
83 nx_markov_step(m2, 1) // 0->1
84 nx_markov_step(m2, 2) // 1->2
85 nx_markov_step(m2, 0) // 2->0
86 // Transitions: 0->1 twice, 1->2 twice, 2->0 twice.
87 if nx_markov_count(m2, 0, 1) != 2 { return __syscall(93, 40, 0, 0, 0, 0, 0) }
88 if nx_markov_count(m2, 1, 2) != 2 { return __syscall(93, 41, 0, 0, 0, 0, 0) }
89 if nx_markov_count(m2, 2, 0) != 2 { return __syscall(93, 42, 0, 0, 0, 0, 0) }
90 if nx_markov_total(m2) != 6 { return __syscall(93, 43, 0, 0, 0, 0, 0) }
91 // Deterministic cycle: P[0][1]=1.0, P[1][2]=1.0, P[2][0]=1.0.
92 if nx_markov_probability_ppm(m2, 0, 1) != 1000000 {
93 return __syscall(93, 44, 0, 0, 0, 0, 0)
94 }
95
96 // ---- input validation ----
97 if nx_markov_observe(m, -1, 1) != -1 {
98 return __syscall(93, 50, 0, 0, 0, 0, 0)
99 }
100 if nx_markov_observe(m, 0, 99) != -1 {
101 return __syscall(93, 51, 0, 0, 0, 0, 0)
102 }
103 if nx_markov_step(m2, 99) != -1 {
104 return __syscall(93, 52, 0, 0, 0, 0, 0)
105 }
106
107 // ---- typed envelope ----
108 let q: *ApproxI64 = nx_markov_query_probability(m, 0, 1)
109 if q.envelope_kind != NX_ENV_ABS {
110 return __syscall(93, 60, 0, 0, 0, 0, 0)
111 }
112 if q.param_a != 1 {
113 return __syscall(93, 61, 0, 0, 0, 0, 0)
114 }
115 if q.maturity != NX_MATURITY_PRODUCTION {
116 return __syscall(93, 62, 0, 0, 0, 0, 0)
117 }
118
119 // ---- reset ----
120 nx_markov_reset(m)
121 if nx_markov_total(m) != 0 { return __syscall(93, 70, 0, 0, 0, 0, 0) }
122 if nx_markov_count(m, 0, 1) != 0 { return __syscall(93, 71, 0, 0, 0, 0, 0) }
123 if nx_markov_probability_ppm(m, 0, 1) != 0 { return __syscall(93, 72, 0, 0, 0, 0, 0) }
124
125 return 0
126}