1use std::ops::{Add, Sub};
2
3use crate::DemesForwardError;
4
5#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
7pub struct ForwardTime(f64);
8
9impl ForwardTime {
10 pub fn valid(&self) -> bool {
12 self.0.is_finite() && self.0.is_sign_positive()
13 }
14
15 pub fn new<F: Into<ForwardTime>>(value: F) -> Self {
17 value.into()
18 }
19
20 pub fn value(&self) -> f64 {
22 self.0
23 }
24}
25
26impl std::fmt::Display for ForwardTime {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 write!(f, "{}", self.0)
29 }
30}
31
32impl<T> From<T> for ForwardTime
33where
34 T: Into<f64>,
35{
36 fn from(value: T) -> Self {
37 Self(value.into())
38 }
39}
40
41impl Sub for ForwardTime {
42 type Output = Self;
43 fn sub(self, rhs: Self) -> Self::Output {
44 (self.0 - rhs.0).into()
45 }
46}
47
48impl Add for ForwardTime {
49 type Output = Self;
50 fn add(self, rhs: Self) -> Self::Output {
51 (self.0 + rhs.0).into()
52 }
53}
54
55pub(crate) struct TimeIterator {
56 current_time: ForwardTime,
57 final_time: ForwardTime,
58}
59
60impl Iterator for TimeIterator {
61 type Item = ForwardTime;
62
63 fn next(&mut self) -> Option<Self::Item> {
64 if self.current_time.0 < self.final_time.0 - 1.0 {
65 self.current_time = self.current_time + 1.0.into();
66 Some(self.current_time)
67 } else {
68 None
69 }
70 }
71}
72
73#[derive(Debug, Clone)]
74pub struct ModelTime {
75 backwards_burn_in_time: demes::Time,
76 model_duration: f64,
77 burnin_generation: f64,
78 minimum_epoch_end_time: f64,
79}
80
81impl ModelTime {
82 pub(crate) fn convert(
83 &self,
84 time: ForwardTime,
85 ) -> Result<Option<demes::Time>, DemesForwardError> {
86 if time.value() < self.model_duration + self.burnin_generation {
87 Ok(Some(
88 (self.burnin_generation + self.model_duration - 1.0 - time.value()
89 + self.minimum_epoch_end_time)
90 .try_into()?,
91 ))
92 } else {
93 Ok(None)
94 }
95 }
96
97 pub(crate) fn model_start_time(&self) -> demes::Time {
98 self.convert(0.into()).unwrap().unwrap()
99 }
100
101 pub fn backwards_burn_in_time(&self) -> demes::Time {
102 self.backwards_burn_in_time
103 }
104}
105
106fn get_model_start_time(graph: &demes::Graph) -> Result<demes::Time, demes::DemesError> {
107 let mut times = graph
109 .demes()
110 .iter()
111 .filter(|deme| deme.start_time() == f64::INFINITY)
112 .map(|deme| deme.epochs()[0].end_time())
113 .collect::<Vec<_>>();
114
115 times.extend(
117 graph
118 .demes()
119 .iter()
120 .filter(|deme| deme.start_time() != f64::INFINITY)
121 .map(|deme| deme.start_time()),
122 );
123
124 times.extend(
125 graph
126 .migrations()
127 .iter()
128 .filter(|migration| migration.start_time() != f64::INFINITY)
129 .map(|migration| migration.start_time()),
130 );
131
132 times.extend(
133 graph
134 .migrations()
135 .iter()
136 .filter(|migration| migration.start_time() != f64::INFINITY)
137 .map(|migration| migration.end_time()),
138 );
139
140 times.extend(graph.pulses().iter().map(|pulse| pulse.time()));
141
142 debug_assert!(!times.is_empty());
143
144 demes::Time::try_from(f64::from(*times.iter().max().unwrap()) + 1.0)
145}
146
147impl ModelTime {
148 pub(crate) fn new_from_graph(
149 burnin_time_length: crate::ForwardTime,
150 graph: &demes::Graph,
151 ) -> Result<Self, crate::DemesForwardError> {
152 let model_start_time = get_model_start_time(graph)?;
156
157 let most_recent_deme_end = graph
158 .demes()
159 .iter()
160 .map(|deme| deme.end_time())
161 .collect::<Vec<_>>()
162 .into_iter()
163 .min()
164 .unwrap();
165 let model_duration = if most_recent_deme_end > 0.0 {
166 f64::from(model_start_time) - f64::from(most_recent_deme_end)
167 } else {
168 f64::from(model_start_time)
169 };
170
171 let burnin_generation = burnin_time_length.value();
172 Ok(Self {
173 backwards_burn_in_time: model_start_time,
174 model_duration,
175 burnin_generation,
176 minimum_epoch_end_time: graph.most_recent_deme_end_time().into(),
177 })
178 }
179
180 pub(crate) fn burnin_generation(&self) -> f64 {
181 self.burnin_generation
182 }
183
184 pub(crate) fn model_duration(&self) -> f64 {
185 self.model_duration
186 }
187
188 pub(crate) fn time_iterator(&self, start: Option<ForwardTime>) -> TimeIterator {
189 let current_time = match start {
190 Some(value) => (value.0 - 1.0).into(),
191 None => (-1.0).into(),
192 };
193 TimeIterator {
194 current_time,
195 final_time: (self.burnin_generation() + self.model_duration()).into(),
196 }
197 }
198}
199
200pub enum BackwardTimeWrapper {
201 Float(f64),
202 Time(demes::Time),
203}
204
205impl From<f64> for BackwardTimeWrapper {
206 fn from(value: f64) -> Self {
207 Self::Float(value)
208 }
209}
210
211impl From<demes::Time> for BackwardTimeWrapper {
212 fn from(value: demes::Time) -> Self {
213 Self::Time(value)
214 }
215}
216
217pub enum ForwardTimeWrapper {
218 Float(f64),
219 Time(ForwardTime),
220}
221
222impl From<f64> for ForwardTimeWrapper {
223 fn from(value: f64) -> Self {
224 Self::Float(value)
225 }
226}
227
228impl From<ForwardTime> for ForwardTimeWrapper {
229 fn from(value: ForwardTime) -> Self {
230 Self::Time(value)
231 }
232}