code wiki / (root) / nx_alignment_test.nx

nx_alignment_test.nx source

↩ module page · 118 lines · 4633 B

1// nx_alignment_test.nx -- KAT for AlignmentRecord + mapq + revcomp remap. 2// 3// expect_exit: 0 4// 5// license_tier: ORIGINAL 6 7import "nx_syscalls.nx" 8import "nx_const.nx" 9import "nx_alignment.nx" 10 11func main() -> i64 { 12 13 // ============================================================ 14 // Section A -- AlignmentRecord constructor + field round-trip. 15 // ============================================================ 16 17 let fields: *i64 = sys_mmap(128) as *i64 18 fields[0] = 7 // query_id 19 fields[1] = 3 // ref_id 20 fields[2] = 100 // q_start 21 fields[3] = 150 // q_end 22 fields[4] = 50000 // r_start 23 fields[5] = 50050 // r_end 24 fields[6] = NX_STRAND_FWD 25 fields[7] = 96 // score 26 fields[8] = 45 // mapq 27 fields[9] = 12 // n_seeds 28 29 let rec: *AlignmentRecord = nx_alignment_new(fields) 30 if rec.query_id != 7 { return 1 } 31 if rec.ref_id != 3 { return 2 } 32 if rec.q_start != 100 { return 3 } 33 if rec.q_end != 150 { return 4 } 34 if rec.r_start != 50000 { return 5 } 35 if rec.r_end != 50050 { return 6 } 36 if rec.strand != NX_STRAND_FWD { return 7 } 37 if rec.score != 96 { return 8 } 38 if rec.mapq != 45 { return 9 } 39 if rec.n_seeds != 12 { return 10 } 40 41 // Reverse-strand variant. 42 fields[6] = NX_STRAND_REV 43 let rec_rev: *AlignmentRecord = nx_alignment_new(fields) 44 if rec_rev.strand != NX_STRAND_REV { return 11 } 45 46 // ============================================================ 47 // Section B -- mapq formula edge cases. 48 // ============================================================ 49 50 // Uniquely placed (no secondary): mapq = 60. 51 if nx_alignment_compute_mapq(100, 0) != 60 { return 20 } 52 53 // secondary == primary -> cannot distinguish, mapq = 0. 54 if nx_alignment_compute_mapq(100, 100) != 0 { return 21 } 55 56 // secondary == primary/2 -> 60 * (100-50)/100 = 30. 57 if nx_alignment_compute_mapq(100, 50) != 30 { return 22 } 58 59 // secondary < primary by tiny amount (high confidence boundary). 60 // 60 * (100-99)/100 = 0 (integer truncation). 61 if nx_alignment_compute_mapq(100, 99) != 0 { return 23 } 62 63 // secondary > primary -> impossible-but-defensive, clamps to 0. 64 if nx_alignment_compute_mapq(50, 100) != 0 { return 24 } 65 66 // primary == 0 -> no alignment -> 0. 67 if nx_alignment_compute_mapq(0, 0) != 0 { return 25 } 68 69 // primary < 0 -> defensive 0. 70 if nx_alignment_compute_mapq(-5, 0) != 0 { return 26 } 71 72 // High-quality typical: primary=200 secondary=50 -> 60*150/200 = 45. 73 if nx_alignment_compute_mapq(200, 50) != 45 { return 27 } 74 75 // Mid-quality: primary=60 secondary=20 -> 60*40/60 = 40. 76 if nx_alignment_compute_mapq(60, 20) != 40 { return 28 } 77 78 // Verify cap: large primary, small secondary still clamps at 60. 79 if nx_alignment_compute_mapq(10000, 0) != 60 { return 29 } 80 81 // ============================================================ 82 // Section C -- revcomp coordinate remap. 83 // ============================================================ 84 85 let out_s: *i64 = sys_mmap(16) as *i64 86 let out_e: *i64 = sys_mmap(16) as *i64 87 88 // q_len=10, rc-coords [2..6) -> orig-coords [10-6, 10-2) = [4..8) 89 if nx_remap_revcomp_coords(10, 2, 6, out_s, out_e) != 0 { return 40 } 90 if out_s[0] != 4 { return 41 } 91 if out_e[0] != 8 { return 42 } 92 93 // Involution: remap(remap(x)) == x. 94 // Apply remap again to [4, 8) with q_len=10 -> [10-8, 10-4) = [2, 6). Same as start. 95 let inv_s: *i64 = sys_mmap(16) as *i64 96 let inv_e: *i64 = sys_mmap(16) as *i64 97 if nx_remap_revcomp_coords(10, 4, 8, inv_s, inv_e) != 0 { return 43 } 98 if inv_s[0] != 2 { return 44 } 99 if inv_e[0] != 6 { return 45 } 100 101 // Edge: full range [0..q_len) maps to [0..q_len). 102 if nx_remap_revcomp_coords(10, 0, 10, out_s, out_e) != 0 { return 50 } 103 if out_s[0] != 0 { return 51 } 104 if out_e[0] != 10 { return 52 } 105 106 // Edge: single-base [3..4) with q_len=10 -> [6..7). 107 if nx_remap_revcomp_coords(10, 3, 4, out_s, out_e) != 0 { return 53 } 108 if out_s[0] != 6 { return 54 } 109 if out_e[0] != 7 { return 55 } 110 111 // Bad input rejection. 112 if nx_remap_revcomp_coords(0, 0, 5, out_s, out_e) != -1 { return 60 } // q_len=0 113 if nx_remap_revcomp_coords(10, -1, 5, out_s, out_e) != -1 { return 61 } // negative start 114 if nx_remap_revcomp_coords(10, 5, 3, out_s, out_e) != -1 { return 62 } // end <= start 115 if nx_remap_revcomp_coords(10, 5, 11, out_s, out_e) != -1 { return 63 } // end > q_len 116 117 return 0 118}