rustyhmmer 0.1.1

Pure-Rust HMMER3 hmmsearch with byte-identical --tblout output
Documentation












pub const K: usize = 20;


pub const KP: usize = 29;




pub const SYM: &[u8; KP] = b"ACDEFGHIKLMNPQRSTVWY-BJZOUX*~";


pub const GAP: u8 = 20; 
pub const AMINO_B: u8 = 21;
pub const AMINO_J: u8 = 22;
pub const AMINO_Z: u8 = 23;
pub const AMINO_O: u8 = 24;
pub const AMINO_U: u8 = 25;
pub const AMINO_X: u8 = 26; 
pub const NONRESIDUE: u8 = 27; 
pub const MISSING: u8 = 28; 


pub const ILLEGAL: u8 = 255;







pub struct AminoMap {
    inmap: [u8; 256],
}

impl AminoMap {
    pub fn new() -> Self {
        let mut inmap = [ILLEGAL; 256];
        for (code, &c) in SYM.iter().enumerate() {
            inmap[c as usize] = code as u8;
            inmap[c.to_ascii_lowercase() as usize] = code as u8;
        }
        AminoMap { inmap }
    }

    
    #[inline]
    pub fn code(&self, c: u8) -> u8 {
        self.inmap[c as usize]
    }

    
    
    
    
    pub fn digitize(&self, seq: &[u8]) -> Vec<u8> {
        let mut dsq = Vec::with_capacity(seq.len() + 2);
        dsq.push(255u8); 
        for &c in seq {
            if c.is_ascii_whitespace() {
                continue;
            }
            let code = self.inmap[c as usize];
            dsq.push(if code == ILLEGAL { AMINO_X } else { code });
        }
        dsq.push(255u8); 
        dsq
    }
}

impl Default for AminoMap {
    fn default() -> Self {
        Self::new()
    }
}





pub const AMINO_FREQ: [f64; K] = [
    0.0787945, 
    0.0151600, 
    0.0535222, 
    0.0668298, 
    0.0397062, 
    0.0695071, 
    0.0229198, 
    0.0590092, 
    0.0594422, 
    0.0963728, 
    0.0237718, 
    0.0414386, 
    0.0482904, 
    0.0395639, 
    0.0540978, 
    0.0683364, 
    0.0540687, 
    0.0673417, 
    0.0114135, 
    0.0304133, 
];

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn symbol_table_len() {
        assert_eq!(SYM.len(), KP);
        assert_eq!(&SYM[..K], b"ACDEFGHIKLMNPQRSTVWY");
    }

    #[test]
    fn canonical_codes() {
        let m = AminoMap::new();
        assert_eq!(m.code(b'A'), 0);
        assert_eq!(m.code(b'Y'), 19);
        assert_eq!(m.code(b'a'), 0); 
        assert_eq!(m.code(b'X'), AMINO_X);
        assert_eq!(m.code(b'@'), ILLEGAL);
    }

    #[test]
    fn digitize_sentinels() {
        let m = AminoMap::new();
        let dsq = m.digitize(b"ACDY");
        assert_eq!(dsq, vec![255, 0, 1, 2, 19, 255]);
    }

    #[test]
    fn background_sums_to_one() {
        let s: f64 = AMINO_FREQ.iter().sum();
        assert!((s - 1.0).abs() < 1e-6, "sum={s}");
    }
}