nx_sequence_kat_test.nx source
↩ module page · 201 lines · 8605 B
1// nx_sequence_kat_test.nx -- G0.1 KAT for the DNA sequence primitive.
2//
3// All vectors hand-verifiable from the 2-bit encoding spec in
4// nx_sequence.nx header. Encoding: A=00 C=01 G=10 T=11, packed
5// big-endian within byte (4 bases per byte, base 0 = high bits).
6//
7// expect_exit: 0
8//
9// license_tier: ORIGINAL
10
11import "nx_syscalls.nx"
12import "nx_const.nx"
13import "nx_sequence.nx"
14
15func main() -> i64 {
16
17 // ============================================================
18 // Section A -- single-base encode / decode round-trip.
19 // ============================================================
20
21 if dna_encode_base(0x41) != 0 { return 1 } // 'A' -> 0
22 if dna_encode_base(0x43) != 1 { return 2 } // 'C' -> 1
23 if dna_encode_base(0x47) != 2 { return 3 } // 'G' -> 2
24 if dna_encode_base(0x54) != 3 { return 4 } // 'T' -> 3
25 if dna_encode_base(0x61) != 0 { return 5 } // 'a' -> 0 (lowercase)
26 if dna_encode_base(0x74) != 3 { return 6 } // 't' -> 3 (lowercase)
27 if dna_encode_base(0x4E) != -1 { return 7 } // 'N' -> -1 (refused per G0.1)
28 if dna_encode_base(0x58) != -1 { return 8 } // 'X' -> -1
29 if dna_encode_base(0x00) != -1 { return 9 } // NUL -> -1
30
31 if dna_decode_base(0) != 0x41 { return 10 } // 0 -> 'A'
32 if dna_decode_base(1) != 0x43 { return 11 } // 1 -> 'C'
33 if dna_decode_base(2) != 0x47 { return 12 } // 2 -> 'G'
34 if dna_decode_base(3) != 0x54 { return 13 } // 3 -> 'T'
35
36 if dna_complement_code(0) != 3 { return 14 } // A -> T
37 if dna_complement_code(1) != 2 { return 15 } // C -> G
38 if dna_complement_code(2) != 1 { return 16 } // G -> C
39 if dna_complement_code(3) != 0 { return 17 } // T -> A
40
41 // ============================================================
42 // Section B -- pack / unpack on "ACGTACGTACGT" (12 bases, 3 bytes).
43 // Expected packed bytes: 0x1B 0x1B 0x1B
44 // "ACGT" = 00 01 10 11 = 0x1B; repeated 3x.
45 // ============================================================
46
47 let asc1: *u8 = sys_mmap(16)
48 asc1[0] = 0x41; asc1[1] = 0x43; asc1[2] = 0x47; asc1[3] = 0x54 // ACGT
49 asc1[4] = 0x41; asc1[5] = 0x43; asc1[6] = 0x47; asc1[7] = 0x54 // ACGT
50 asc1[8] = 0x41; asc1[9] = 0x43; asc1[10]= 0x47; asc1[11]= 0x54 // ACGT
51
52 let pack1: *u8 = sys_mmap(8)
53 if dna_pack(asc1, 12, pack1) != 0 { return 20 }
54 if (pack1[0] & 0xff) != 0x1B { return 21 }
55 if (pack1[1] & 0xff) != 0x1B { return 22 }
56 if (pack1[2] & 0xff) != 0x1B { return 23 }
57
58 let asc1_rt: *u8 = sys_mmap(16)
59 dna_unpack(pack1, 12, asc1_rt)
60 var i: i64 = 0
61 while i < 12 {
62 if (asc1_rt[i] & 0xff) != (asc1[i] & 0xff) { return 30 + i }
63 i = i + 1
64 }
65
66 // ============================================================
67 // Section C -- pack of "ACG" (3 bases, partial byte).
68 // Expected: byte 0 = 0x18 = 00 01 10 00 (trailing 2 bits zero).
69 // ============================================================
70
71 let asc_acg: *u8 = sys_mmap(8)
72 asc_acg[0] = 0x41; asc_acg[1] = 0x43; asc_acg[2] = 0x47
73 let pack_acg: *u8 = sys_mmap(4)
74 if dna_pack(asc_acg, 3, pack_acg) != 0 { return 45 }
75 if (pack_acg[0] & 0xff) != 0x18 { return 46 }
76
77 // ============================================================
78 // Section D -- pack refuses non-ACGT.
79 // ============================================================
80
81 let asc_bad: *u8 = sys_mmap(8)
82 asc_bad[0] = 0x41; asc_bad[1] = 0x4E; asc_bad[2] = 0x43 // A N C
83 let pack_bad: *u8 = sys_mmap(4)
84 if dna_pack(asc_bad, 3, pack_bad) != -1 { return 47 }
85
86 // ============================================================
87 // Section E -- reverse-complement palindrome "ACGT" -> "ACGT".
88 // Packed in and out: 0x1B.
89 // ============================================================
90
91 let pal_in: *u8 = sys_mmap(4)
92 let pal_out: *u8 = sys_mmap(4)
93 pal_in[0] = 0x1B
94 if dna_revcomp(pal_in, 4, pal_out) != 0 { return 50 }
95 if (pal_out[0] & 0xff) != 0x1B { return 51 }
96
97 // ============================================================
98 // Section F -- reverse-complement "ACGTGCAT" (8 bases, 2 bytes).
99 // in: A C G T G C A T = 0x1B 0x93
100 // rev: T A C G T G C A
101 // comp: A T G C A C G T = 0x39 0x1B
102 // ============================================================
103
104 let f_in: *u8 = sys_mmap(4)
105 let f_out: *u8 = sys_mmap(4)
106 f_in[0] = 0x1B; f_in[1] = 0x93
107 if dna_revcomp(f_in, 8, f_out) != 0 { return 55 }
108 if (f_out[0] & 0xff) != 0x39 { return 56 }
109 if (f_out[1] & 0xff) != 0x1B { return 57 }
110
111 // ============================================================
112 // Section G -- reverse-complement "AAAACGT" (7 bases, partial-byte).
113 // in: A A A A C G T (-) = 0x00 0x6C (last slot zero)
114 // rev: T G C A A A A
115 // comp: A C G T T T T (-) = 0x1B 0xFC
116 // ============================================================
117
118 let g_in: *u8 = sys_mmap(4)
119 let g_out: *u8 = sys_mmap(4)
120 g_in[0] = 0x00; g_in[1] = 0x6C
121 if dna_revcomp(g_in, 7, g_out) != 0 { return 60 }
122 if (g_out[0] & 0xff) != 0x1B { return 61 }
123 if (g_out[1] & 0xff) != 0xFC { return 62 }
124
125 // ============================================================
126 // Section H -- k-mer extraction on "ACGTAC" (6 bases).
127 // packed: 0x1B 0x10 (byte 1 = 00 01 00 00)
128 // pos 0 k=4: A C G T = 0x1B
129 // pos 1 k=4: C G T A = 0x6C
130 // pos 2 k=4: G T A C = 0xB1
131 // pos 0 k=2: A C = 0x01 (bits: 00 01 in low 4)
132 // pos 4 k=2: A C = 0x01
133 // ============================================================
134
135 let h_in: *u8 = sys_mmap(4)
136 h_in[0] = 0x1B; h_in[1] = 0x10
137 if dna_kmer_at(h_in, 0, 4) != 0x1B { return 65 }
138 if dna_kmer_at(h_in, 1, 4) != 0x6C { return 66 }
139 if dna_kmer_at(h_in, 2, 4) != 0xB1 { return 67 }
140 if dna_kmer_at(h_in, 0, 2) != 0x01 { return 68 }
141 if dna_kmer_at(h_in, 4, 2) != 0x01 { return 69 }
142
143 // ============================================================
144 // Section I -- in-register k-mer reverse-complement.
145 // ACGT (0x1B) -> ACGT (0x1B) palindrome
146 // AAAA (0x00) -> TTTT (0xFF)
147 // TTTT (0xFF) -> AAAA (0x00)
148 // ACAT (0x13) -> ATGT (0x3B)
149 // ACAT = A=00 C=01 A=00 T=11 = 00011011-shifted? let me recheck:
150 // A C A T = 00 01 00 11 -> high-to-low = 00 01 00 11 = 0x13
151 // rev: T A C A
152 // comp: A T G T = 00 11 10 11 = 0x3B
153 // ============================================================
154
155 if dna_kmer_revcomp(0x1B, 4) != 0x1B { return 70 }
156 if dna_kmer_revcomp(0x00, 4) != 0xFF { return 71 }
157 if dna_kmer_revcomp(0xFF, 4) != 0x00 { return 72 }
158 if dna_kmer_revcomp(0x13, 4) != 0x3B { return 73 }
159
160 // ============================================================
161 // Section J -- canonical k-mer = min(fwd, revcomp).
162 // ============================================================
163
164 if dna_kmer_canonical(0x1B, 4) != 0x1B { return 75 } // palindrome
165 if dna_kmer_canonical(0x00, 4) != 0x00 { return 76 } // AAAA < TTTT
166 if dna_kmer_canonical(0xFF, 4) != 0x00 { return 77 } // TTTT -> AAAA wins
167 if dna_kmer_canonical(0x13, 4) != 0x13 { return 78 } // ACAT < ATGT
168 if dna_kmer_canonical(0x3B, 4) != 0x13 { return 79 } // ATGT -> ACAT wins
169
170 // ============================================================
171 // Section K -- per-base get/set on packed array.
172 // Set bases ACGT into a zero buffer one at a time, then read.
173 // ============================================================
174
175 let k_buf: *u8 = sys_mmap(4)
176 dna_set_base(k_buf, 0, NX_DNA_A)
177 dna_set_base(k_buf, 1, NX_DNA_C)
178 dna_set_base(k_buf, 2, NX_DNA_G)
179 dna_set_base(k_buf, 3, NX_DNA_T)
180 if (k_buf[0] & 0xff) != 0x1B { return 85 }
181 if dna_get_base(k_buf, 0) != 0 { return 86 }
182 if dna_get_base(k_buf, 1) != 1 { return 87 }
183 if dna_get_base(k_buf, 2) != 2 { return 88 }
184 if dna_get_base(k_buf, 3) != 3 { return 89 }
185
186 // ============================================================
187 // Section L -- round-trip composition:
188 // revcomp(revcomp(X)) == X for X = "ACGTGCAT" (8 bases).
189 // ============================================================
190
191 let l_in: *u8 = sys_mmap(4)
192 let l_mid: *u8 = sys_mmap(4)
193 let l_back: *u8 = sys_mmap(4)
194 l_in[0] = 0x1B; l_in[1] = 0x93
195 dna_revcomp(l_in, 8, l_mid)
196 dna_revcomp(l_mid, 8, l_back)
197 if (l_back[0] & 0xff) != (l_in[0] & 0xff) { return 90 }
198 if (l_back[1] & 0xff) != (l_in[1] & 0xff) { return 91 }
199
200 return 0
201}