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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
use either::Either;
use necsim_impls_no_std::cogs::{
    habitat::almost_infinite::AlmostInfiniteHabitat,
    origin_sampler::{
        pre_sampler::OriginPreSampler,
        singleton_demes::{
            circle::SingletonDemesCircleOriginSampler,
            rectangle::SingletonDemesRectangleOriginSampler, SingletonDemesOriginSampler,
        },
    },
};
use serde::{Deserialize, Serialize};

use necsim_core::{
    cogs::MathsCore,
    landscape::{LandscapeExtent, Location},
};
#[cfg(feature = "almost-infinite-normal-dispersal")]
use necsim_core_bond::NonNegativeF64;
#[cfg(feature = "almost-infinite-clark2dt-dispersal")]
use necsim_core_bond::PositiveF64;

#[cfg(feature = "almost-infinite-clark2dt-dispersal")]
pub mod clark2dt;
#[cfg(feature = "almost-infinite-normal-dispersal")]
pub mod normal;

#[derive(Debug, Serialize, Deserialize)]
#[allow(clippy::module_name_repetitions)]
#[serde(deny_unknown_fields)]
#[serde(rename = "AlmostInfinite")]
pub struct AlmostInfiniteArguments {
    sample: Sample,
    dispersal: Dispersal,
}

#[cfg(feature = "almost-infinite-normal-dispersal")]
type NormalDispersalArguments = normal::AlmostInfiniteNormalDispersalArguments;
#[cfg(not(feature = "almost-infinite-normal-dispersal"))]
type NormalDispersalArguments = !;

#[cfg(feature = "almost-infinite-clark2dt-dispersal")]
type Clark2DtDispersalArguments = clark2dt::AlmostInfiniteClark2DtDispersalArguments;
#[cfg(not(feature = "almost-infinite-clark2dt-dispersal"))]
type Clark2DtDispersalArguments = !;

impl AlmostInfiniteArguments {
    #[must_use]
    pub fn load(self) -> Either<NormalDispersalArguments, Clark2DtDispersalArguments> {
        match self {
            #[cfg(feature = "almost-infinite-normal-dispersal")]
            Self {
                sample,
                dispersal: Dispersal::Normal { sigma },
            } => Either::Left(normal::AlmostInfiniteNormalDispersalArguments { sample, sigma }),
            #[cfg(feature = "almost-infinite-clark2dt-dispersal")]
            Self {
                sample,
                dispersal: Dispersal::Clark2Dt { shape_u, tail_p },
            } => Either::Right(clark2dt::AlmostInfiniteClark2DtDispersalArguments {
                sample,
                shape_u,
                tail_p,
            }),
        }
    }

    #[cfg(feature = "almost-infinite-normal-dispersal")]
    #[must_use]
    pub fn from_normal(args: &normal::AlmostInfiniteNormalDispersalArguments) -> Self {
        Self {
            sample: args.sample.clone(),
            dispersal: Dispersal::Normal { sigma: args.sigma },
        }
    }

    #[cfg(feature = "almost-infinite-clark2dt-dispersal")]
    #[must_use]
    pub fn from_clark2dt(args: &clark2dt::AlmostInfiniteClark2DtDispersalArguments) -> Self {
        Self {
            sample: args.sample.clone(),
            dispersal: Dispersal::Clark2Dt {
                shape_u: args.shape_u,
                tail_p: args.tail_p,
            },
        }
    }
}

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub enum Sample {
    Circle {
        #[serde(default = "Sample::default_circle_sample_centre")]
        centre: Location,
        radius: u16,
    },
    Rectangle(LandscapeExtent),
}

impl Sample {
    #[must_use]
    pub const fn default_circle_sample_centre() -> Location {
        const HABITAT_CENTRE: u32 = u32::MAX / 2;

        Location::new(HABITAT_CENTRE, HABITAT_CENTRE)
    }

    pub fn into_origin_sampler<M: MathsCore, I: Iterator<Item = u64>>(
        self,
        habitat: &AlmostInfiniteHabitat<M>,
        pre_sampler: OriginPreSampler<M, I>,
    ) -> SingletonDemesOriginSampler<M, AlmostInfiniteHabitat<M>, I> {
        match self {
            Self::Circle { centre, radius } => SingletonDemesOriginSampler::Circle(
                SingletonDemesCircleOriginSampler::new(pre_sampler, habitat, centre, radius),
            ),
            Self::Rectangle(sample) => SingletonDemesOriginSampler::Rectangle(
                SingletonDemesRectangleOriginSampler::new(pre_sampler, habitat, sample),
            ),
        }
    }
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
enum Dispersal {
    #[cfg(feature = "almost-infinite-normal-dispersal")]
    #[serde(alias = "Gaussian")]
    Normal { sigma: NonNegativeF64 },
    #[cfg(feature = "almost-infinite-clark2dt-dispersal")]
    Clark2Dt {
        #[serde(alias = "u")]
        shape_u: PositiveF64,
        #[serde(default = "PositiveF64::one")]
        #[serde(alias = "p")]
        tail_p: PositiveF64,
    },
}