code wiki / (root) / nx_chem_molecule_test.nx

nx_chem_molecule_test.nx source

↩ module page · 279 lines · 11527 B

1// nx_chem_molecule_test.nx -- C2.0 KAT for MolGraph struct + builder. 2// 3// All molecules constructed by hand (no SMILES parser yet -- that's 4// C2.1). Verifies: struct layout, atom + bond adders, bounded 5// lookups, error-code path on overflow, count-by-Z helper, and the 6// convenience builders for the canonical reference molecules. 7// 8// expect_exit: 0 9// 10// license_tier: ORIGINAL 11 12import "nx_chem_molecule.nx" 13 14// ============================================================ 15// A -- new + empty graph defaults. 16// ============================================================ 17func a_new_empty() -> nx_int { 18 let m: *MolGraph = nx_chem_mol_new(8, 8) 19 if m.n_atoms != 0 { return 11 } 20 if m.n_bonds != 0 { return 12 } 21 if m.capacity_atoms != 8 { return 13 } 22 if m.capacity_bonds != 8 { return 14 } 23 if m.is_valid != 1 { return 15 } 24 if m.err_code != NX_MOL_OK { return 16 } 25 let null_a: *Atom = nx_chem_mol_atom(m, 0) 26 if (null_a as nx_int) != 0 { return 17 } // empty graph: lookup must return null 27 let null_b: *Bond = nx_chem_mol_bond(m, 0) 28 if (null_b as nx_int) != 0 { return 18 } 29 return 0 30} 31 32// ============================================================ 33// B -- atom_add appends + lookup returns the same atom. 34// ============================================================ 35func b_atom_add() -> nx_int { 36 let m: *MolGraph = nx_chem_mol_new(4, 4) 37 let i: nx_int = nx_chem_mol_atom_add(m, 8) 38 if i != 0 { return 21 } 39 if m.n_atoms != 1 { return 22 } 40 let a: *Atom = nx_chem_mol_atom(m, 0) 41 if (a as nx_int) == 0 { return 23 } 42 if a.z != 8 { return 24 } 43 if a.charge != 0 { return 25 } 44 if a.isotope != 0 { return 26 } 45 if a.h_count != -1 { return 27 } // implicit by default 46 if a.aromaticity != 0 { return 28 } 47 if a.stereo != NX_STEREO_NONE { return 29 } 48 // out-of-range lookup must return null 49 let bad: *Atom = nx_chem_mol_atom(m, 5) 50 if (bad as nx_int) != 0 { return 30 } 51 let neg: *Atom = nx_chem_mol_atom(m, -1) 52 if (neg as nx_int) != 0 { return 31 } 53 return 0 54} 55 56// ============================================================ 57// C -- bond_add appends + endpoint validation. 58// ============================================================ 59func c_bond_add() -> nx_int { 60 let m: *MolGraph = nx_chem_mol_new(4, 4) 61 let c1: nx_int = nx_chem_mol_atom_add(m, 6) 62 let c2: nx_int = nx_chem_mol_atom_add(m, 6) 63 let bi: nx_int = nx_chem_mol_bond_add(m, c1, c2, NX_BOND_SINGLE) 64 if bi != 0 { return 41 } 65 if m.n_bonds != 1 { return 42 } 66 let b: *Bond = nx_chem_mol_bond(m, 0) 67 if (b as nx_int) == 0 { return 43 } 68 if b.a != c1 { return 44 } 69 if b.b != c2 { return 45 } 70 if b.order != NX_BOND_SINGLE { return 46 } 71 if b.in_ring != 0 { return 47 } 72 return 0 73} 74 75// ============================================================ 76// D -- atom-overflow returns -1 + sets structured error. 77// ============================================================ 78func d_atom_overflow() -> nx_int { 79 let m: *MolGraph = nx_chem_mol_new(2, 2) 80 let _ok1: nx_int = nx_chem_mol_atom_add(m, 6) 81 let _ok2: nx_int = nx_chem_mol_atom_add(m, 6) 82 let fail: nx_int = nx_chem_mol_atom_add(m, 6) 83 if fail != -1 { return 51 } 84 if m.is_valid != 0 { return 52 } 85 if m.err_code != NX_MOL_ERR_ATOM_OVERFLOW { return 53 } 86 return 0 87} 88 89// ============================================================ 90// E -- bond-add rejects invalid atom index with structured error. 91// ============================================================ 92func e_bond_bad_atom() -> nx_int { 93 let m: *MolGraph = nx_chem_mol_new(4, 4) 94 let _c1: nx_int = nx_chem_mol_atom_add(m, 6) 95 // try to bond atom 0 to atom 5 (which doesn't exist) 96 let fail: nx_int = nx_chem_mol_bond_add(m, 0, 5, NX_BOND_SINGLE) 97 if fail != -1 { return 61 } 98 if m.is_valid != 0 { return 62 } 99 if m.err_code != NX_MOL_ERR_BAD_ATOM_INDEX { return 63 } 100 return 0 101} 102 103// ============================================================ 104// F -- bond-add rejects invalid bond order. 105// ============================================================ 106func f_bond_bad_order() -> nx_int { 107 let m: *MolGraph = nx_chem_mol_new(4, 4) 108 let c1: nx_int = nx_chem_mol_atom_add(m, 6) 109 let c2: nx_int = nx_chem_mol_atom_add(m, 6) 110 let fail: nx_int = nx_chem_mol_bond_add(m, c1, c2, 99) 111 if fail != -1 { return 71 } 112 if m.err_code != NX_MOL_ERR_BAD_BOND_ORDER { return 72 } 113 return 0 114} 115 116// ============================================================ 117// G -- water builder: single O atom, 0 bonds. 118// ============================================================ 119func g_water() -> nx_int { 120 let m: *MolGraph = nx_chem_mol_water() 121 if m.n_atoms != 1 { return 81 } 122 if m.n_bonds != 0 { return 82 } 123 let o: *Atom = nx_chem_mol_atom(m, 0) 124 if o.z != 8 { return 83 } 125 if nx_chem_mol_count_z(m, 8) != 1 { return 84 } 126 if nx_chem_mol_count_z(m, 6) != 0 { return 85 } 127 return 0 128} 129 130// ============================================================ 131// H -- methane builder: single C atom. 132// ============================================================ 133func h_methane() -> nx_int { 134 let m: *MolGraph = nx_chem_mol_methane() 135 if m.n_atoms != 1 { return 91 } 136 let c: *Atom = nx_chem_mol_atom(m, 0) 137 if c.z != 6 { return 92 } 138 return 0 139} 140 141// ============================================================ 142// I -- ethanol builder: C-C-O, 2 single bonds. 143// ============================================================ 144func i_ethanol() -> nx_int { 145 let m: *MolGraph = nx_chem_mol_ethanol() 146 if m.n_atoms != 3 { return 101 } 147 if m.n_bonds != 2 { return 102 } 148 if nx_chem_mol_count_z(m, 6) != 2 { return 103 } // 2 carbons 149 if nx_chem_mol_count_z(m, 8) != 1 { return 104 } // 1 oxygen 150 let b0: *Bond = nx_chem_mol_bond(m, 0) 151 if b0.order != NX_BOND_SINGLE { return 105 } 152 if b0.a != 0 { return 106 } // C-C 153 if b0.b != 1 { return 107 } 154 let b1: *Bond = nx_chem_mol_bond(m, 1) 155 if b1.order != NX_BOND_SINGLE { return 108 } 156 if b1.a != 1 { return 109 } // C-O 157 if b1.b != 2 { return 110 } 158 return 0 159} 160 161// ============================================================ 162// J -- ethene builder: C=C. 163// ============================================================ 164func j_ethene() -> nx_int { 165 let m: *MolGraph = nx_chem_mol_ethene() 166 if m.n_atoms != 2 { return 121 } 167 if m.n_bonds != 1 { return 122 } 168 let b: *Bond = nx_chem_mol_bond(m, 0) 169 if b.order != NX_BOND_DOUBLE { return 123 } 170 return 0 171} 172 173// ============================================================ 174// K -- ethyne builder: C#C. 175// ============================================================ 176func k_ethyne() -> nx_int { 177 let m: *MolGraph = nx_chem_mol_ethyne() 178 if m.n_atoms != 2 { return 131 } 179 if m.n_bonds != 1 { return 132 } 180 let b: *Bond = nx_chem_mol_bond(m, 0) 181 if b.order != NX_BOND_TRIPLE { return 133 } 182 return 0 183} 184 185// ============================================================ 186// L -- benzene builder: 6 aromatic carbons in a ring. 187// Verifies 6-aromaticity-tuple (E3 EXCEED axis) is lit for every 188// supported model on every atom + every bond + ring perception flag. 189// ============================================================ 190func l_benzene() -> nx_int { 191 let m: *MolGraph = nx_chem_mol_benzene() 192 if m.n_atoms != 6 { return 141 } 193 if m.n_bonds != 6 { return 142 } 194 if nx_chem_mol_count_z(m, 6) != 6 { return 143 } 195 let all_arom: nx_int = NX_AROM_DAYLIGHT | NX_AROM_OPENEYE | NX_AROM_RDKIT | NX_AROM_MDL | NX_AROM_TRIPOS | NX_AROM_MMFF 196 // every atom: aromaticity bits all set + in_ring 197 var i: nx_int = 0 198 while i < 6 { 199 let a: *Atom = nx_chem_mol_atom(m, i) 200 if a.aromaticity != all_arom { return 150 + i } 201 if a.in_ring != 1 { return 160 + i } 202 if a.z != 6 { return 170 + i } 203 i = i + 1 204 } 205 // every bond: order=aromatic + aromaticity bits all set + in_ring 206 var j: nx_int = 0 207 while j < 6 { 208 let b: *Bond = nx_chem_mol_bond(m, j) 209 if b.order != NX_BOND_AROMATIC { return 180 + j } 210 if b.aromaticity != all_arom { return 190 + j } 211 if b.in_ring != 1 { return 200 + j } 212 j = j + 1 213 } 214 // ring closure: bond 5 connects atom 5 back to atom 0 215 let b5: *Bond = nx_chem_mol_bond(m, 5) 216 if b5.a != 5 { return 211 } 217 if b5.b != 0 { return 212 } 218 return 0 219} 220 221func main() -> nx_exit { 222 println("=== nx_chem_molecule -- C2.0 KAT: MolGraph struct + builders ===" as *u8) 223 224 let ra: nx_int = a_new_empty() 225 if ra != 0 { println("A new_empty FAIL" as *u8); return ra } 226 println("A new_empty PASS fresh graph: 0 atoms / 0 bonds / valid / null lookups" as *u8) 227 228 let rb: nx_int = b_atom_add() 229 if rb != 0 { println("B atom_add FAIL" as *u8); return rb } 230 println("B atom_add PASS atom_add returns index 0; lookup returns matching atom; bounds reject" as *u8) 231 232 let rc: nx_int = c_bond_add() 233 if rc != 0 { println("C bond_add FAIL" as *u8); return rc } 234 println("C bond_add PASS bond_add appends + records endpoints + order" as *u8) 235 236 let rd: nx_int = d_atom_overflow() 237 if rd != 0 { println("D atom_overflow FAIL" as *u8); return rd } 238 println("D atom_overflow PASS capacity exceeded -> -1 + is_valid=0 + structured err_code" as *u8) 239 240 let re: nx_int = e_bond_bad_atom() 241 if re != 0 { println("E bond_bad_atom FAIL" as *u8); return re } 242 println("E bond_bad_atom PASS bond_add rejects out-of-range atom index with structured err" as *u8) 243 244 let rf: nx_int = f_bond_bad_order() 245 if rf != 0 { println("F bond_bad_order FAIL" as *u8); return rf } 246 println("F bond_bad_order PASS bond_add rejects invalid bond order with structured err" as *u8) 247 248 let rg: nx_int = g_water() 249 if rg != 0 { println("G water FAIL" as *u8); return rg } 250 println("G water PASS H2O = 1 O atom (H-suppressed); count_z(O)=1, count_z(C)=0" as *u8) 251 252 let rh: nx_int = h_methane() 253 if rh != 0 { println("H methane FAIL" as *u8); return rh } 254 println("H methane PASS CH4 = 1 C atom (H-suppressed)" as *u8) 255 256 let ri: nx_int = i_ethanol() 257 if ri != 0 { println("I ethanol FAIL" as *u8); return ri } 258 println("I ethanol PASS CCO = C-C-O; 2 single bonds; 2C + 1O" as *u8) 259 260 let rj: nx_int = j_ethene() 261 if rj != 0 { println("J ethene FAIL" as *u8); return rj } 262 println("J ethene PASS C=C; 1 double bond" as *u8) 263 264 let rk: nx_int = k_ethyne() 265 if rk != 0 { println("K ethyne FAIL" as *u8); return rk } 266 println("K ethyne PASS C#C; 1 triple bond" as *u8) 267 268 let rl: nx_int = l_benzene() 269 if rl != 0 { println("L benzene FAIL" as *u8); return rl } 270 println("L benzene PASS c1ccccc1: 6C + 6 aromatic bonds; 6-aromaticity-tuple lit on every atom+bond; ring perception flagged" as *u8) 271 272 println("" as *u8) 273 println("=== C2.0 substrate milestone PASS ===" as *u8) 274 println(" MolGraph : Atom + Bond + graph container with capacity-checked appends" as *u8) 275 println(" EXCEED axes : E3 (6-aromaticity-tuple slot; lit for benzene) + E4 (per-bond stereo slot)" as *u8) 276 println(" forward-compat : isotope / charge / radical / stereo / map_num / in_ring slots present" as *u8) 277 println(" next : C2.1 -- nx_chem_smiles parser (organic subset + bracket atoms basic)" as *u8) 278 return 0 279}