sciforge-lib 0.0.4

Scientific computing library — mathematics, physics, chemistry, biology, astronomy, geology, meteorology.
Documentation
pub fn snp_allele_frequency(alt_count: usize, total_alleles: usize) -> f64 {
    alt_count as f64 / total_alleles.max(1) as f64
}

pub fn minor_allele_frequency(allele_freq: f64) -> f64 {
    allele_freq.min(1.0 - allele_freq)
}

pub fn hardy_weinberg_expected(p: f64) -> (f64, f64, f64) {
    let q = 1.0 - p;
    (p * p, 2.0 * p * q, q * q)
}

pub fn hardy_weinberg_chi_squared(observed: &[f64; 3], expected: &[f64; 3]) -> f64 {
    let mut chi2 = 0.0;
    for i in 0..3 {
        if expected[i] > 0.0 {
            chi2 += (observed[i] - expected[i]).powi(2) / expected[i];
        }
    }
    chi2
}

pub fn ti_tv_ratio(transitions: usize, transversions: usize) -> f64 {
    transitions as f64 / transversions.max(1) as f64
}

pub fn heterozygosity(allele_freqs: &[f64]) -> f64 {
    let sum_sq: f64 = allele_freqs.iter().map(|f| f * f).sum();
    1.0 - sum_sq
}

pub fn fst_weir_cockerham(het_within: f64, het_total: f64) -> f64 {
    1.0 - het_within / het_total.max(1e-30)
}

pub fn linkage_disequilibrium(freq_ab: f64, freq_a: f64, freq_b: f64) -> f64 {
    freq_ab - freq_a * freq_b
}

pub fn r_squared_ld(d: f64, freq_a: f64, freq_b: f64) -> f64 {
    let denom = freq_a * (1.0 - freq_a) * freq_b * (1.0 - freq_b);
    if denom <= 0.0 {
        return 0.0;
    }
    d * d / denom
}

pub fn d_prime(d: f64, freq_a: f64, freq_b: f64) -> f64 {
    let d_max = if d >= 0.0 {
        (freq_a * (1.0 - freq_b)).min((1.0 - freq_a) * freq_b)
    } else {
        (freq_a * freq_b).min((1.0 - freq_a) * (1.0 - freq_b))
    };
    d / d_max.max(1e-30)
}

pub fn indel_frameshift(indel_length: i64) -> bool {
    indel_length % 3 != 0
}

pub fn copy_number_variant_dosage(reads_sample: f64, reads_reference: f64, ploidy: f64) -> f64 {
    ploidy * reads_sample / reads_reference.max(1e-30)
}