code wiki / (root) / nx_sequence_kat_test.nx

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}