rustyhmmer 0.1.1

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




use super::constants::ESL_SMALLX1;













#[inline]
pub fn esl_gumbel_pdf(x: f64, mu: f64, lambda: f64) -> f64 {
    let y = lambda * (x - mu);
    lambda * (-y - (-y).exp()).exp()
}













#[inline]
pub fn esl_gumbel_logpdf(x: f64, mu: f64, lambda: f64) -> f64 {
    let y = lambda * (x - mu);
    lambda.ln() - y - (-y).exp()
}













#[inline]
pub fn esl_gumbel_cdf(x: f64, mu: f64, lambda: f64) -> f64 {
    let y = lambda * (x - mu);
    (-(-y).exp()).exp()
}













#[inline]
pub fn esl_gumbel_logcdf(x: f64, mu: f64, lambda: f64) -> f64 {
    let y = lambda * (x - mu);
    -(-y).exp()
}















#[inline]
pub fn esl_gumbel_surv(x: f64, mu: f64, lambda: f64) -> f64 {
    let y = lambda * (x - mu);
    let ey = -(-y).exp();

    
    if ey.abs() < ESL_SMALLX1 {
        -ey
    } else {
        1.0 - ey.exp()
    }
}

















#[inline]
pub fn esl_gumbel_logsurv(x: f64, mu: f64, lambda: f64) -> f64 {
    let y = lambda * (x - mu);
    let ey = -(-y).exp();

    
    
    
    
    if ey.abs() < ESL_SMALLX1 {
        -y
    } else if ey.exp().abs() < ESL_SMALLX1 {
        -ey.exp()
    } else {
        (1.0 - ey.exp()).ln()
    }
}












#[inline]
pub fn esl_gumbel_invcdf(p: f64, mu: f64, lambda: f64) -> f64 {
    mu - ((-p.ln()).ln() / lambda)
}












#[inline]
pub fn esl_gumbel_invsurv(p: f64, mu: f64, lambda: f64) -> f64 {
    
    
    
    let log_part = if p < ESL_SMALLX1 {
        (p.powf(p) - 1.0) / p
    } else {
        (-(1.0 - p).ln()).ln()
    };

    mu - (log_part / lambda)
}

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

    const EPSILON: f64 = 1e-10;

    fn approx_eq(a: f64, b: f64) -> bool {
        if a.is_infinite() && b.is_infinite() {
            return a.signum() == b.signum();
        }
        if a.abs() < EPSILON && b.abs() < EPSILON {
            return true;
        }
        (a - b).abs() / a.abs().max(b.abs()).max(1.0) < EPSILON
    }

    #[test]
    fn test_gumbel_pdf_at_mode() {
        
        
        let pdf = esl_gumbel_pdf(0.0, 0.0, 1.0);
        let expected = 1.0 / std::f64::consts::E;
        assert!(
            approx_eq(pdf, expected),
            "PDF at mode: {} vs {}",
            pdf,
            expected
        );
    }

    #[test]
    fn test_gumbel_cdf_properties() {
        
        let cdf = esl_gumbel_cdf(0.0, 0.0, 1.0);
        let expected = (-1.0_f64).exp();
        assert!(
            approx_eq(cdf, expected),
            "CDF at mu: {} vs {}",
            cdf,
            expected
        );
    }

    #[test]
    fn test_gumbel_surv_cdf_relationship() {
        
        let x = 1.5;
        let mu = 0.0;
        let lambda = 1.0;
        let surv = esl_gumbel_surv(x, mu, lambda);
        let cdf = esl_gumbel_cdf(x, mu, lambda);
        assert!(
            approx_eq(surv + cdf, 1.0),
            "surv + cdf should equal 1: {} + {} = {}",
            surv,
            cdf,
            surv + cdf
        );
    }

    #[test]
    fn test_gumbel_logpdf_pdf_relationship() {
        
        let x = 0.5;
        let mu = 0.0;
        let lambda = 1.0;
        let pdf = esl_gumbel_pdf(x, mu, lambda);
        let logpdf = esl_gumbel_logpdf(x, mu, lambda);
        assert!(
            approx_eq(logpdf, pdf.ln()),
            "logpdf should equal ln(pdf): {} vs {}",
            logpdf,
            pdf.ln()
        );
    }

    #[test]
    fn test_gumbel_invcdf_cdf_inverse() {
        
        let x = 1.5;
        let mu = -20.0;
        let lambda = 0.4;
        let p = esl_gumbel_cdf(x, mu, lambda);
        let recovered = esl_gumbel_invcdf(p, mu, lambda);
        assert!(
            approx_eq(x, recovered),
            "invcdf(cdf(x)) should equal x: {} vs {}",
            x,
            recovered
        );
    }
}