proof_engine/ecology/
evolution.rs1use crate::worldgen::Rng;
4
5#[derive(Debug, Clone)]
7pub struct EvolvingTrait {
8 pub name: String,
9 pub value: f64,
10 pub heritability: f64,
11 pub mutation_variance: f64,
12}
13
14pub fn evolve_trait(trait_val: &mut EvolvingTrait, selection_optimum: f64, pop_size: usize, rng: &mut Rng) {
16 let selection_diff = selection_optimum - trait_val.value;
18 let selection_response = selection_diff * trait_val.heritability * 0.1;
19
20 let drift = rng.gaussian() * (1.0 / (pop_size as f64).sqrt()) * trait_val.mutation_variance;
22
23 let mutation = rng.gaussian() * trait_val.mutation_variance * 0.01;
25
26 trait_val.value += selection_response + drift + mutation;
27}
28
29pub fn check_speciation(pop_a_trait: f64, pop_b_trait: f64, threshold: f64) -> bool {
31 (pop_a_trait - pop_b_trait).abs() > threshold
32}
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37
38 #[test]
39 fn test_evolve_trait_toward_optimum() {
40 let mut rng = Rng::new(42);
41 let mut t = EvolvingTrait {
42 name: "size".to_string(), value: 0.5, heritability: 0.8, mutation_variance: 0.1,
43 };
44 for _ in 0..1000 {
45 evolve_trait(&mut t, 0.9, 100, &mut rng);
46 }
47 assert!(t.value > 0.6, "trait should move toward optimum: {}", t.value);
48 }
49}