1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use std::{error::Error as StdError, fmt, marker::PhantomData};

use necsim_core::{
    cogs::{MathsCore, RngCore},
    lineage::Lineage,
};
use necsim_core_bond::NonNegativeF64;

use necsim_impls_no_std::cogs::active_lineage_sampler::resuming::lineage::ExceptionalLineage;

#[derive(Clone, serde::Serialize, serde::Deserialize)]
#[serde(bound = "")]
pub enum SimulationOutcome<M: MathsCore, G: RngCore<M>> {
    Done {
        time: NonNegativeF64,
        steps: u64,
    },
    Paused {
        time: NonNegativeF64,
        steps: u64,
        lineages: Vec<Lineage>,
        rng: G,
        #[serde(skip)]
        marker: PhantomData<M>,
    },
}

#[derive(Debug)]
pub enum ResumeError<E: StdError + Send + Sync + 'static> {
    Sample(Vec<ExceptionalLineage>),
    Simulate(E),
}

impl<E: StdError + Send + Sync + 'static> std::error::Error for ResumeError<E> {}

impl<E: StdError + Send + Sync + 'static> From<E> for ResumeError<E> {
    fn from(err: E) -> Self {
        Self::Simulate(err)
    }
}

impl<E: StdError + Send + Sync + 'static> fmt::Display for ResumeError<E> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Self::Sample(exceptional_lineages) => {
                writeln!(
                    fmt,
                    "{} lineage(s) are incompatible with the scenario, e.g.",
                    exceptional_lineages.len()
                )?;

                if let Some((child, parent)) = exceptional_lineages.iter().find_map(|e| match e {
                    ExceptionalLineage::Coalescence { child, parent } => Some((child, parent)),
                    _ => None,
                }) {
                    writeln!(
                        fmt,
                        "- Lineage #{} at ({}, {}, {}) is at the same indexed location as Lineage \
                         #{}",
                        child.global_reference,
                        child.indexed_location.location().x(),
                        child.indexed_location.location().y(),
                        child.indexed_location.index(),
                        parent,
                    )?;
                }

                if let Some(lineage) = exceptional_lineages.iter().find_map(|e| match e {
                    ExceptionalLineage::OutOfDeme(lineage) => Some(lineage),
                    _ => None,
                }) {
                    writeln!(
                        fmt,
                        "- Lineage #{} at ({}, {}, {}) is outside the deme at its location",
                        lineage.global_reference,
                        lineage.indexed_location.location().x(),
                        lineage.indexed_location.location().y(),
                        lineage.indexed_location.index(),
                    )?;
                }

                if let Some(lineage) = exceptional_lineages.iter().find_map(|e| match e {
                    ExceptionalLineage::OutOfHabitat(lineage) => Some(lineage),
                    _ => None,
                }) {
                    writeln!(
                        fmt,
                        "- Lineage #{} at ({}, {}, {}) is outside the habitable area",
                        lineage.global_reference,
                        lineage.indexed_location.location().x(),
                        lineage.indexed_location.location().y(),
                        lineage.indexed_location.index(),
                    )?;
                }

                Ok(())
            },
            Self::Simulate(err) => fmt::Display::fmt(err, fmt),
        }
    }
}