nx_arc_anchor_test.nx source
↩ module page · 94 lines · 3533 B
1// nx_arc_anchor_test.nx -- smoke for co-occurrence + arc anchor discovery.
2//
3// Ingests a small corpus with TWO recurring (outfit, location)
4// motifs and verifies the anchor discoverer surfaces them both
5// as OUTFIT_LOCATION anchors WITHOUT any pre-seeded scene list.
6//
7// Exit code:
8// 0 all assertions pass
9// N assertion N failed
10
11import "syscalls.nx"
12import "nx_media_pool.nx"
13import "nx_storybeat.nx"
14import "nx_storydb.nx"
15import "nx_text_ingest.nx"
16import "nx_term_registry.nx"
17import "nx_term_extract.nx"
18import "nx_term_cooccur.nx"
19import "nx_arc_anchor.nx"
20
21func main() -> i64 {
22
23 // Corpus: each line repeats a co-occurrence so counts > 1.
24 let buf: *u8 = sys_mmap(2048)
25 var k: i64 = 0
26 while k < 2048 { buf[k] = 0; k = k + 1 }
27 let story: *u8 = "Sarah walked into the kitchen wearing an apron.\n\nLater she stood in the kitchen wearing an apron.\n\nThe next morning she slipped into the bedroom wearing a robe.\n\nShe was in the bedroom wearing a robe again.\n\nShe stepped into the kitchen wearing an apron.\n"
28 var si: i64 = 0
29 while story[si] != 0 {
30 buf[si] = story[si]
31 si = si + 1
32 }
33 let slen: i64 = si
34
35 let db: *StoryDb = nx_storydb_alloc()
36 let mid: i64 = nx_media_pool_add(db.media_pool, NX_MEDIA_TYPE_TEXT,
37 NX_MEDIA_SRC_USER_PASTE,
38 buf, slen,
39 0 as *u8, 0,
40 0 as *u8, 0,
41 1700000000)
42 if mid < 0 { return 10 }
43 if nx_text_ingest(db, mid) != NX_TEXT_INGEST_OK { return 11 }
44 if db.n_beats < 3 { return 12 }
45
46 let reg: *TermRegistry = nx_term_registry_alloc()
47 if nx_term_extract_all(db, reg) != NX_EXTR_OK { return 13 }
48
49 // Co-occurrence walk.
50 let co: *Cooccur = nx_cooccur_alloc()
51 let n_pairs: i64 = nx_cooccur_observe_db(co, db)
52 if n_pairs < 1 { return 20 }
53
54 // Top-K query.
55 let scratch_buf: *u8 = sys_mmap(32 * NX_COOCCUR_PAIR_BYTES)
56 let scratch: *CooccurPair = scratch_buf as *CooccurPair
57 let n_top: i64 = nx_cooccur_top_k(co, scratch, 32)
58 if n_top < 1 { return 21 }
59
60 // Verify the top pair has count >= 2 (kitchen+apron seen >= 3
61 // times, but only beats with BOTH outfit_id and location_id
62 // populated count -- which depends on extractor success).
63 let top0: *CooccurPair = scratch_buf as *CooccurPair
64 if top0.count < 1 { return 22 }
65
66 // Anchor discovery.
67 let anchor_buf: *u8 = sys_mmap(16 * NX_ARC_ANCHOR_BYTES)
68 let anchors: *ArcAnchor = anchor_buf as *ArcAnchor
69 let n_anch: i64 = nx_arc_anchor_discover(co, reg, scratch, 32,
70 anchors, 16)
71 if n_anch < 1 { return 30 }
72
73 // Verify at least one anchor classifies as OUTFIT_LOCATION.
74 var n_outfit_loc: i64 = 0
75 var i: i64 = 0
76 while i < n_anch {
77 let a: *ArcAnchor =
78 (((anchor_buf as i64) + i * NX_ARC_ANCHOR_BYTES) as *ArcAnchor)
79 if a.anchor_kind == NX_ANCHOR_OUTFIT_LOCATION {
80 n_outfit_loc = n_outfit_loc + 1
81 }
82 i = i + 1
83 }
84 if n_outfit_loc < 1 { return 31 }
85
86 // Verify the strongest OUTFIT_LOCATION anchor reached PROMOTED
87 // stage (count >= 3 per NX_ARC_ANCHOR_PROMOTE_N) OR sits at
88 // SUPERVISED with non-zero count (allow either; smoke corpus
89 // may not exceed threshold).
90 let a0: *ArcAnchor = anchor_buf as *ArcAnchor
91 if a0.cooccur_count <= 0 { return 32 }
92
93 return 0
94}