code wiki / (root) / nx_chem_fingerprint.nx

nx_chem_fingerprint.nx

buildroot/runtime/nx_chem_fingerprint.nx

14054 B344 linesdepth 7pulls 8 transitivereach 1 importersview sourcekind librarytopic chem
docsdependenciesstructsconstsfunctions

about

nx_chem_fingerprint.nx -- C2.6 milestone: ECFP-style Morgan circular-substructure fingerprint + Tanimoto similarity. Algorithm: extended-connectivity hashing (Rogers & Hahn 2010). 1. Each atom gets an initial invariant from chemistry-relevant features: (heavy-neighbor count, valence-sum, atomic number, formal charge, implicit-H count, in-ring flag, aromaticity). 2. For each refinement iteration r in 1..radius: new_inv[i] = poly_hash(old_inv[i], [(bond_order, neighbor_old_inv)] sorted) The sorted-list-of-(bond, neighbor) construction makes the hash atom-order-invariant; the polynomial multiplier 31 is pinned by source identity ("ECFP4_v1_mul_31"). 3. After radius iterations, accumulate ALL invariants seen across all atoms at all radii into the fingerprint bit-set. 4. Fold into a bit vector of length N_BITS by setting bit[h & (N_BITS-1)] for each accumulated invariant h. EXCEED axis hit (landscape doc): E5 -- hash-pinned fingerprint definitions. Algorithm identity is the source bytes of this file. RDKit's Morgan/ECFP doesn't match the ECFP-paper Figure 8 (RDKit Issue #2018); the nx substrate ships content-addressed semantics: ECFP4_v1 computed in 2026 matches ECFP4_v1 computed in 2030 because the function bytes are bit-identical. Honest gaps (deferred): - Stereo-aware ECFP (folds Atom.stereo + Bond.stereo into invariants): C2.6.1 future iteration; current MVP is stereo-blind. - FCFP (functional-class equivalence rather than atomic-equivalence): C2.7 future primitive. - Variable bit length (current 1024 only; 512 / 2048 / 4096 hash-pinned variants are simple parameter changes when needed). nx_safety_envelope: intended_use: chemoinformatic similarity + substructure hashing; foundation for nx_chem_similarity_search and nx_chem_chemometrics descriptor matrix sil_target: SIL1 evidence: [C2.6 KAT in nx_chem_fingerprint_test.nx; algorithm hash-pinned by source bytes;

dependencies 2 imports · 1 importers

nx_chem.nx nx_chem_molecule.nx nx_chem_fingerprint.nx nx_chem_fingerprint_test.nx

imports: nx_chem.nxnx_chem_molecule.nx

imported by: nx_chem_fingerprint_test.nx

structs

none

consts

46const NX_MAGIC_10000: i64 = 10000
49const NX_CHEM_ECFP_V1_MUL: nx_int = 31 // polynomial-hash multiplier
50const NX_CHEM_ECFP_V1_INIT_SEED: nx_int = 5381 // djb2-style seed
51const NX_CHEM_ECFP_DEFAULT_BITS: nx_int = 1024
52const NX_CHEM_ECFP_DEFAULT_RADIUS: nx_int = 2 // ECFP4 standard
55const NX_CHEM_FP_BITS_PER_SLOT: nx_int = 64

functions

76func nx_chem_fp_initial_invariant(m: *MolGraph, atom_idx: nx_int) -> nx_int
125func nx_chem_fp_sort_asc(arr: *nx_int, n: nx_int) -> nx_int
156func nx_chem_fp_hash_neighborhood(
177func nx_chem_fp_refine_step(m: *MolGraph, old_inv: *nx_int, new_inv: *nx_int) -> nx_int
218func nx_chem_fp_set_bit(slots: *nx_int, bit_idx: nx_int) -> nx_int
228func nx_chem_fp_get_bit(slots: *nx_int, bit_idx: nx_int) -> nx_int
called by 1: i_set_get_bit
241func nx_chem_fp_popcount_u64(v: nx_int) -> nx_int
259func nx_chem_compute_ecfp_fingerprint(
302func nx_chem_fp_tanimoto_q4(fp_a: *nx_int, fp_b: *nx_int, n_bits: nx_int) -> nx_int
322func nx_chem_fp_popcount(fp: *nx_int, n_bits: nx_int) -> nx_int
336func nx_chem_fp_equal(fp_a: *nx_int, fp_b: *nx_int, n_bits: nx_int) -> nx_int