1use petgraph::{algo::astar, prelude::UnGraph};
2
3use ndarray::{array, Array2, Axis};
4
5use crate::{Edge, Node, Pedigree};
6
7#[derive(Debug)]
8pub struct DMatrix(Array2<f64>);
9
10impl DMatrix {
11 pub fn from(nodes: &Vec<Node>, posterior_max: f64) -> Self {
12 println!();
13 println!();
14 println!("Calculating divergences between all pairs of nodes...");
15 println!();
16 let mut divergences = Array2::<f64>::zeros((nodes.len(), nodes.len()));
17
18 let pb = progress_bars::Progress::new(
19 "Calculating Divergences ",
20 binomial_coefficient(nodes.len(), 2),
21 );
22
23 for (i, first) in nodes.iter().enumerate() {
25 for (j, second) in nodes.iter().skip(i + 1).enumerate() {
26 pb.inc(1);
27 assert!(first.sites.as_ref().is_some());
28 assert!(second.sites.as_ref().is_some());
29 if first.sites.as_ref().unwrap().len() != second.sites.as_ref().unwrap().len() {
30 println!(
31 "Lengths do not match, all bets are off: {} vs {}",
32 first.sites.as_ref().unwrap().len(),
33 second.sites.as_ref().unwrap().len()
34 );
35 divergences[[i, j]] = 0.0;
36 continue;
37 }
38 assert_eq!(
39 first.sites.as_ref().unwrap().len(),
40 second.sites.as_ref().unwrap().len()
41 );
42
43 let mut divergence = 0;
44 let mut compared_sites = 0;
45
46 for (k, f) in first.sites.as_ref().unwrap().iter().enumerate() {
49 let s = second
50 .sites
51 .as_ref()
52 .unwrap()
53 .get(k)
54 .expect("Partner methylation site must exists");
55
56 if f.posteriormax < posterior_max || s.posteriormax < posterior_max {
58 continue;
59 }
60
61 divergence += f.status_numeric().abs_diff(s.status_numeric());
62 compared_sites += 1;
63 }
64
65 let divergence = divergence as f64 / (2.0 * compared_sites as f64);
66 divergences[[i, j]] = divergence;
67 }
68 }
69 pb.finish();
70 DMatrix(divergences)
71 }
72 pub fn convert(&self, nodes: &[Node], edges: &[Edge]) -> Pedigree {
74 let e = edges
75 .iter()
76 .map(|e| {
77 (
78 e.from.id,
79 e.to.id,
80 e.from.generation.abs_diff(e.to.generation) as usize,
81 )
83 })
84 .collect::<Vec<(usize, usize, usize)>>();
85
86 let graph = UnGraph::<usize, usize, usize>::from_edges(e);
87
88 let mut pedigree = Pedigree(Array2::<f64>::default((0, 4)));
89
90 for (i, source) in nodes.iter().enumerate() {
91 for (j, target) in nodes.iter().skip(i + 1).enumerate() {
92 if source.id == target.id {
93 continue;
95 }
96
97 let path = astar(
98 &graph,
99 source.id.into(),
100 |finish| finish == target.id.into(),
101 |e| *e.weight(),
102 |_| 0,
103 );
104
105 match path {
106 None => continue,
107 Some(path) => {
108 let distance = path.0;
109 let visited = path.1;
110
111 let t0: f64 = visited
112 .iter()
113 .map(|n| {
114 edges
115 .iter()
116 .find_map(|e| {
117 if e.from.id == n.index() {
118 return Some(e.from.generation);
119 }
120 if e.to.id == n.index() {
121 return Some(e.to.generation);
122 }
123 None
124 })
125 .unwrap()
126 })
127 .min()
128 .unwrap() as f64;
129
130 let t1 = source.generation as f64;
131 let t2 = target.generation as f64;
132
133 let div = self.0.get((i, j)).unwrap().to_owned();
134
135 assert_eq!(distance as f64, t1 - t0 + t2 - t0);
136 pedigree
137 .0
138 .push(Axis(0), array![t0, t1, t2, div].view())
139 .expect("Could not insert row into pedigree");
140 }
141 }
142 }
143 }
144
145 pedigree
146 }
147}
148
149fn binomial_coefficient(n: usize, k: usize) -> usize {
150 let mut result = 1;
151 let k = k.min(n - k); for i in 0..k {
153 result *= n - i;
154 result /= i + 1;
155 }
156 result
157}
158
159#[cfg(test)]
160mod test {
161 use super::*;
162 #[test]
163 fn test_binomial_coefficient() {
164 assert_eq!(binomial_coefficient(5, 0), 1);
165 assert_eq!(binomial_coefficient(5, 1), 5);
166 assert_eq!(binomial_coefficient(5, 2), 10);
167 assert_eq!(binomial_coefficient(5, 3), 10);
168 assert_eq!(binomial_coefficient(5, 4), 5);
169 assert_eq!(binomial_coefficient(5, 5), 1);
170 }
171}