sciforge 0.0.3

A comprehensive scientific computing library in pure Rust with zero dependencies
Documentation
//! Dispatch handler for evolution functions.

use super::super::params::*;
use crate::hub::domain::biology as bio;
use crate::hub::domain::common::errors::{HubError, HubResult};
use crate::hub::engine::experience::runner::RunOutput;

pub(super) fn dispatch(func: &str, p: &Params) -> HubResult<RunOutput> {
    match func {
        "adaptation_rate" => Ok(RunOutput::Scalar(
            bio::evolution::adaptation::adaptation_rate(
                get_f(p, "selection_coefficient")?,
                get_f(p, "mutation_rate")?,
                get_f(p, "population_size")?,
            ),
        )),
        "fisher_geometric_adaptation" => Ok(RunOutput::Scalar(
            bio::evolution::adaptation::fisher_geometric_adaptation(
                get_v(p, "phenotype")?,
                get_v(p, "optimum")?,
            ),
        )),
        "adaptive_walk_progress" => Ok(RunOutput::Scalar(
            bio::evolution::adaptation::adaptive_walk_progress(
                get_f(p, "current_fitness")?,
                get_f(p, "max_fitness")?,
                get_f(p, "beneficial_rate")?,
                get_u(p, "step")?,
            ),
        )),
        "beneficial_mutation_fixation_probability" => Ok(RunOutput::Scalar(
            bio::evolution::adaptation::beneficial_mutation_fixation_probability(
                get_f(p, "s")?,
                get_f(p, "ne")?,
            ),
        )),
        "phenotypic_plasticity" => Ok(RunOutput::Scalar(
            bio::evolution::adaptation::phenotypic_plasticity(
                get_f(p, "genotype_value")?,
                get_f(p, "environment")?,
                get_f(p, "reaction_norm_slope")?,
            ),
        )),
        "baldwin_effect" => Ok(RunOutput::Scalar(
            bio::evolution::adaptation::baldwin_effect(
                get_f(p, "learning_rate")?,
                get_f(p, "genetic_assimilation")?,
                get_u(p, "generations")?,
            ),
        )),
        "red_queen_coevolution" => {
            let (a, b) = bio::evolution::adaptation::red_queen_coevolution(
                get_f(p, "host_fitness")?,
                get_f(p, "parasite_fitness")?,
                get_f(p, "host_adapt_rate")?,
                get_f(p, "parasite_adapt_rate")?,
                get_f(p, "dt")?,
            );
            Ok(RunOutput::Pair(a, b))
        }
        "environmental_gradient_selection" => Ok(RunOutput::Scalar(
            bio::evolution::adaptation::environmental_gradient_selection(
                get_f(p, "position")?,
                get_f(p, "optimum_slope")?,
                get_f(p, "selection_width")?,
                get_f(p, "phenotype")?,
            ),
        )),
        "frequency_dependent_selection" => Ok(RunOutput::Scalar(
            bio::evolution::adaptation::frequency_dependent_selection(
                get_f(p, "frequency")?,
                get_f(p, "baseline_fitness")?,
                get_f(p, "fd_coefficient")?,
            ),
        )),
        "adaptive_radiation_rate" => Ok(RunOutput::Scalar(
            bio::evolution::adaptation::adaptive_radiation_rate(
                get_u(p, "niche_count")?,
                get_u(p, "occupied")?,
                get_f(p, "diversification_rate")?,
            ),
        )),
        "fitness_landscape_nk" => {
            let genotype = get_str(p, "genotype")?.as_bytes();
            Ok(RunOutput::Scalar(
                bio::evolution::fitness::fitness_landscape_nk(
                    genotype,
                    get_u(p, "k")?,
                    get_m(p, "contributions")?,
                ),
            ))
        }
        "fitness_landscape_additive" => {
            let genotype = get_str(p, "genotype")?.as_bytes();
            Ok(RunOutput::Scalar(
                bio::evolution::fitness::fitness_landscape_additive(genotype, get_v(p, "effects")?),
            ))
        }
        "fisher_geometric_model" => Ok(RunOutput::Scalar(
            bio::evolution::fitness::fisher_geometric_model(
                get_f(p, "distance")?,
                get_u(p, "n_dimensions")?,
            ),
        )),
        "mutation_step_probability" => Ok(RunOutput::Scalar(
            bio::evolution::fitness::mutation_step_probability(
                get_f(p, "distance")?,
                get_f(p, "step_size")?,
                get_u(p, "n_dim")?,
            ),
        )),
        "adaptive_walk" => Ok(RunOutput::Vector(bio::evolution::fitness::adaptive_walk(
            get_f(p, "distance0")?,
            get_f(p, "step_size")?,
            get_u(p, "n_dim")?,
            get_u(p, "max_steps")?,
        ))),
        "epistasis" => Ok(RunOutput::Scalar(bio::evolution::fitness::epistasis(
            get_f(p, "w_ab")?,
            get_f(p, "w_a")?,
            get_f(p, "w_b")?,
            get_f(p, "w_ref")?,
        ))),
        "evolution_frequency_dependent_fitness" => Ok(RunOutput::Scalar(
            bio::evolution::fitness::frequency_dependent_fitness(
                get_f(p, "freq")?,
                get_f(p, "advantage_rare")?,
            ),
        )),
        "density_dependent_fitness" => Ok(RunOutput::Scalar(
            bio::evolution::fitness::density_dependent_fitness(
                get_f(p, "population")?,
                get_f(p, "carrying_capacity")?,
                get_f(p, "r_max")?,
            ),
        )),
        "wrightian_fitness" => {
            let genotype_v = get_v(p, "genotype")?;
            let genotype: Vec<bool> = genotype_v.iter().map(|&x| x != 0.0).collect();
            Ok(RunOutput::Scalar(
                bio::evolution::fitness::wrightian_fitness(
                    &genotype,
                    get_v(p, "loci_effects")?,
                    get_v(p, "dominance")?,
                ),
            ))
        }
        "substitution_rate" => Ok(RunOutput::Scalar(
            bio::evolution::molecular::substitution_rate(
                get_f(p, "mu")?,
                get_f(p, "ne")?,
                get_f(p, "s")?,
            ),
        )),
        "evolution_dn_ds_ratio" => Ok(RunOutput::Scalar(bio::evolution::molecular::dn_ds_ratio(
            get_f(p, "dn")?,
            get_f(p, "ds")?,
        ))),
        "evolution_molecular_clock_rate" => Ok(RunOutput::Scalar(
            bio::evolution::molecular::molecular_clock_rate(
                get_f(p, "substitutions")?,
                get_f(p, "divergence_time")?,
            ),
        )),
        "coalescent_time_pair" => Ok(RunOutput::Scalar(
            bio::evolution::molecular::coalescent_time_pair(get_f(p, "ne")?),
        )),
        "expected_segregating_sites" => Ok(RunOutput::Scalar(
            bio::evolution::molecular::expected_segregating_sites(
                get_f(p, "theta")?,
                get_u(p, "n")?,
            ),
        )),
        "watterson_estimator" => Ok(RunOutput::Scalar(
            bio::evolution::molecular::watterson_estimator(get_u(p, "seg_sites")?, get_u(p, "n")?),
        )),
        "mcdonald_kreitman" => Ok(RunOutput::Scalar(
            bio::evolution::molecular::mcdonald_kreitman(
                get_f(p, "dn")?,
                get_f(p, "ds")?,
                get_f(p, "pn")?,
                get_f(p, "ps")?,
            ),
        )),
        "neutral_substitution_rate" => Ok(RunOutput::Scalar(
            bio::evolution::neutral_theory::neutral_substitution_rate(get_f(p, "mutation_rate")?),
        )),
        "effective_neutral_mutations" => Ok(RunOutput::Scalar(
            bio::evolution::neutral_theory::effective_neutral_mutations(
                get_u(p, "total_mutations")?,
                get_f(p, "fraction_neutral")?,
            ),
        )),
        "nearly_neutral_boundary" => Ok(RunOutput::Scalar(
            bio::evolution::neutral_theory::nearly_neutral_boundary(get_f(p, "ne")?),
        )),
        "evolution_tajima_d" => Ok(RunOutput::Scalar(bio::evolution::neutral_theory::tajima_d(
            get_f(p, "pi")?,
            get_f(p, "theta_w")?,
            get_u(p, "n")?,
        ))),
        "evolution_watterson_theta" => Ok(RunOutput::Scalar(
            bio::evolution::neutral_theory::watterson_theta(
                get_u(p, "segregating_sites")?,
                get_u(p, "n")?,
                get_u(p, "sequence_length")?,
            ),
        )),
        "evolution_nucleotide_diversity" => Ok(RunOutput::Scalar(
            bio::evolution::neutral_theory::nucleotide_diversity(
                get_v(p, "differences")?,
                get_u(p, "n_sequences")?,
            ),
        )),
        "ewens_sampling_formula" => Ok(RunOutput::Scalar(
            bio::evolution::neutral_theory::ewens_sampling_formula(
                get_u(p, "n")?,
                get_f(p, "theta")?,
            ),
        )),
        "evolution_coalescent_expected_time" => Ok(RunOutput::Scalar(
            bio::evolution::neutral_theory::coalescent_expected_time(
                get_u(p, "n")?,
                get_f(p, "ne")?,
            ),
        )),
        "mcdonald_kreitman_ratio" => Ok(RunOutput::Scalar(
            bio::evolution::neutral_theory::mcdonald_kreitman_ratio(
                get_f(p, "dn")?,
                get_f(p, "ds")?,
                get_f(p, "pn")?,
                get_f(p, "ps")?,
            ),
        )),
        "neutrality_index" => Ok(RunOutput::Scalar(
            bio::evolution::neutral_theory::neutrality_index(
                get_f(p, "dn")?,
                get_f(p, "ds")?,
                get_f(p, "pn")?,
                get_f(p, "ps")?,
            ),
        )),
        "direction_of_selection" => Ok(RunOutput::Scalar(
            bio::evolution::neutral_theory::direction_of_selection(get_f(p, "ni")?),
        )),
        "speciation_rate_bdi" => Ok(RunOutput::Scalar(
            bio::evolution::speciation::speciation_rate_bdi(
                get_f(p, "lambda")?,
                get_f(p, "mu")?,
                get_f(p, "t")?,
                get_f(p, "n0")?,
            ),
        )),
        "allopatric_divergence" => Ok(RunOutput::Scalar(
            bio::evolution::speciation::allopatric_divergence(
                get_f(p, "d0")?,
                get_f(p, "mu")?,
                get_f(p, "t")?,
            ),
        )),
        "reproductive_isolation" => Ok(RunOutput::Scalar(
            bio::evolution::speciation::reproductive_isolation(
                get_f(p, "genetic_distance")?,
                get_f(p, "k")?,
                get_f(p, "n")?,
            ),
        )),
        "reinforcement_strength" => Ok(RunOutput::Scalar(
            bio::evolution::speciation::reinforcement_strength(
                get_f(p, "sympatry")?,
                get_f(p, "hybrid_fitness")?,
            ),
        )),
        "yule_process_expected_species" => Ok(RunOutput::Scalar(
            bio::evolution::speciation::yule_process_expected_species(
                get_f(p, "lambda")?,
                get_f(p, "t")?,
            ),
        )),
        "birth_death_survival" => Ok(RunOutput::Scalar(
            bio::evolution::speciation::birth_death_survival(
                get_f(p, "lambda")?,
                get_f(p, "mu")?,
                get_f(p, "t")?,
            ),
        )),
        "character_displacement" => {
            let (a, b) = bio::evolution::speciation::character_displacement(
                get_f(p, "z1")?,
                get_f(p, "z2")?,
                get_f(p, "alpha")?,
                get_f(p, "sigma")?,
            );
            Ok(RunOutput::Pair(a, b))
        }
        "ecological_speciation_fitness" => {
            let (a, b) = bio::evolution::speciation::ecological_speciation_fitness(
                get_f(p, "trait_val")?,
                get_f(p, "optimum1")?,
                get_f(p, "optimum2")?,
                get_f(p, "sigma")?,
            );
            Ok(RunOutput::Pair(a, b))
        }
        "coalescent_expected_time" => Ok(RunOutput::Scalar(
            bio::evolution::neutral_theory::coalescent_expected_time(
                get_u(p, "n")?,
                get_f(p, "ne")?,
            ),
        )),
        "dn_ds_ratio" => Ok(RunOutput::Scalar(bio::evolution::molecular::dn_ds_ratio(
            get_f(p, "dn")?,
            get_f(p, "ds")?,
        ))),
        "frequency_dependent_fitness" => Ok(RunOutput::Scalar(
            bio::evolution::fitness::frequency_dependent_fitness(
                get_f(p, "freq")?,
                get_f(p, "advantage_rare")?,
            ),
        )),
        "molecular_clock_rate" => Ok(RunOutput::Scalar(
            bio::evolution::molecular::molecular_clock_rate(
                get_f(p, "substitutions")?,
                get_f(p, "divergence_time")?,
            ),
        )),
        "tajima_d" => Ok(RunOutput::Scalar(bio::evolution::neutral_theory::tajima_d(
            get_f(p, "pi")?,
            get_f(p, "theta_w")?,
            get_u(p, "n")?,
        ))),
        "nucleotide_diversity" => Ok(RunOutput::Scalar(
            bio::evolution::neutral_theory::nucleotide_diversity(
                get_v(p, "differences")?,
                get_u(p, "n_sequences")?,
            ),
        )),
        "watterson_theta" => Ok(RunOutput::Scalar(
            bio::evolution::neutral_theory::watterson_theta(
                get_u(p, "segregating_sites")?,
                get_u(p, "n")?,
                get_u(p, "sequence_length")?,
            ),
        )),
        "fitness_landscape_rugged" => {
            let gv = get_v(p, "genotype")?;
            let genotype: Vec<u8> = gv.iter().map(|&x| x as u8).collect();
            let pv = get_v(p, "peaks_flat")?;
            let pw = get_v(p, "peak_widths")?;
            let peak_len = genotype.len();
            let peaks: Vec<(Vec<u8>, f64)> = pv
                .chunks(peak_len)
                .zip(pw.iter())
                .map(|(g, &w)| (g.iter().map(|&x| x as u8).collect(), w))
                .collect();
            let peak_refs: Vec<(&[u8], f64)> =
                peaks.iter().map(|(g, w)| (g.as_slice(), *w)).collect();
            Ok(RunOutput::Scalar(
                bio::evolution::fitness::fitness_landscape_rugged(&genotype, &peak_refs),
            ))
        }
        _ => Err(HubError::InvalidInput(format!("unknown function: {func}"))),
    }
}