Skip to main content

radiate_core/
lineage.rs

1use crate::phenotype::{FamilyId, PhenotypeId};
2use std::collections::HashMap;
3// use std::collections::HashSet;
4// use std::collections::VecDeque;
5
6#[derive(Clone, Debug)]
7pub enum LineageUpdate {
8    Mutate {
9        family: FamilyId,
10        parent: PhenotypeId,
11        child: PhenotypeId,
12    },
13    Crossover {
14        families: (FamilyId, FamilyId),
15        parents: (PhenotypeId, PhenotypeId),
16        child: PhenotypeId,
17    },
18    Replace {
19        reason: &'static str,
20        old: (FamilyId, PhenotypeId),
21        new: (FamilyId, PhenotypeId),
22    },
23    Invalid,
24}
25
26impl
27    From<(
28        (FamilyId, FamilyId),
29        (PhenotypeId, PhenotypeId),
30        PhenotypeId,
31    )> for LineageUpdate
32{
33    fn from(
34        (parent_lineages, parent_versions, child_id): (
35            (FamilyId, FamilyId),
36            (PhenotypeId, PhenotypeId),
37            PhenotypeId,
38        ),
39    ) -> Self {
40        if parent_versions.0 == child_id || parent_versions.1 == child_id {
41            return LineageUpdate::Invalid;
42        }
43
44        LineageUpdate::Crossover {
45            families: parent_lineages,
46            parents: parent_versions,
47            child: child_id,
48        }
49    }
50}
51
52impl From<((FamilyId, PhenotypeId), PhenotypeId)> for LineageUpdate {
53    fn from((parent_id, child_id): ((FamilyId, PhenotypeId), PhenotypeId)) -> Self {
54        if parent_id.1 == child_id {
55            return LineageUpdate::Invalid;
56        }
57
58        LineageUpdate::Mutate {
59            family: parent_id.0,
60            parent: parent_id.1,
61            child: child_id,
62        }
63    }
64}
65
66impl
67    From<(
68        &'static str,
69        (FamilyId, PhenotypeId),
70        (FamilyId, PhenotypeId),
71    )> for LineageUpdate
72{
73    fn from(
74        (reason, (old_family, old_id), (new_family, new_id)): (
75            &'static str,
76            (FamilyId, PhenotypeId),
77            (FamilyId, PhenotypeId),
78        ),
79    ) -> Self {
80        if old_id == new_id {
81            return LineageUpdate::Invalid;
82        }
83
84        LineageUpdate::Replace {
85            reason,
86            old: (old_family, old_id),
87            new: (new_family, new_id),
88        }
89    }
90}
91
92#[derive(Clone, Debug)]
93pub enum LineageEvent {
94    Mutate {
95        operator: &'static str,
96        family: FamilyId,
97        parent: PhenotypeId,
98        child: PhenotypeId,
99    },
100    Crossover {
101        operator: &'static str,
102        families: (FamilyId, FamilyId),
103        parents: (PhenotypeId, PhenotypeId),
104        child: PhenotypeId,
105    },
106    Replace {
107        reason: &'static str,
108        old: (FamilyId, PhenotypeId),
109        new: (FamilyId, PhenotypeId),
110    },
111}
112
113#[derive(Clone, Debug, Default)]
114pub struct LineageStats {
115    pub updates: usize,
116    pub parent_usage: HashMap<PhenotypeId, usize>,
117    pub family_usage: HashMap<FamilyId, usize>,
118    pub family_pairs: HashMap<(FamilyId, FamilyId), usize>,
119    pub cross_family_crossovers: usize,
120    pub within_family_crossovers: usize,
121}
122
123#[derive(Clone, Debug, Default)]
124pub struct Lineage {
125    stats: LineageStats,
126}
127
128impl Lineage {
129    pub fn rollover(&mut self) {
130        self.stats = LineageStats::default();
131    }
132
133    pub fn stats(&self) -> &LineageStats {
134        &self.stats
135    }
136
137    pub fn extend<I: IntoIterator<Item = impl Into<LineageUpdate>>>(
138        &mut self,
139        operation: &'static str,
140        events: I,
141    ) {
142        for event in events {
143            self.push(operation, event.into());
144        }
145    }
146
147    pub fn push(&mut self, operator: &'static str, update: LineageUpdate) {
148        match update {
149            LineageUpdate::Invalid => return,
150            LineageUpdate::Mutate {
151                family,
152                parent,
153                child,
154            } => {
155                *self.stats.parent_usage.entry(parent).or_insert(0) += 1;
156                *self.stats.family_usage.entry(family).or_insert(0) += 1;
157
158                LineageEvent::Mutate {
159                    operator,
160                    child,
161                    family,
162                    parent,
163                }
164            }
165            LineageUpdate::Crossover {
166                families,
167                parents,
168                child,
169            } => {
170                *self.stats.parent_usage.entry(parents.0).or_insert(0) += 1;
171                *self.stats.parent_usage.entry(parents.1).or_insert(0) += 1;
172                *self.stats.family_usage.entry(families.0).or_insert(0) += 1;
173                *self.stats.family_usage.entry(families.1).or_insert(0) += 1;
174
175                if families.0 == families.1 {
176                    self.stats.within_family_crossovers += 1;
177                } else {
178                    self.stats.cross_family_crossovers += 1;
179                };
180
181                let (a, b) = if families.0 <= families.1 {
182                    (families.0, families.1)
183                } else {
184                    (families.1, families.0)
185                };
186
187                *self.stats.family_pairs.entry((a, b)).or_insert(0) += 1;
188
189                LineageEvent::Crossover {
190                    operator,
191                    families,
192                    parents,
193                    child,
194                }
195            }
196            LineageUpdate::Replace { reason, old, new } => {
197                LineageEvent::Replace { reason, old, new }
198            }
199        };
200
201        self.stats.updates += 1;
202    }
203}