use necsim_core::{
cogs::{Backup, Habitat, MathsCore},
landscape::IndexedLocation,
};
use necsim_core_bond::{ClosedUnitF64, PositiveF64};
use super::EmigrationChoice;
#[allow(clippy::module_name_repetitions)]
#[derive(Debug)]
pub struct ProbabilisticEmigrationChoice {
probability: ClosedUnitF64,
}
impl ProbabilisticEmigrationChoice {
#[must_use]
pub fn new(probability: ClosedUnitF64) -> Self {
Self { probability }
}
}
#[contract_trait]
impl Backup for ProbabilisticEmigrationChoice {
unsafe fn backup_unchecked(&self) -> Self {
Self {
probability: self.probability,
}
}
}
#[contract_trait]
impl<M: MathsCore, H: Habitat<M>> EmigrationChoice<M, H> for ProbabilisticEmigrationChoice {
fn should_lineage_emigrate(
&self,
_indexed_location: &IndexedLocation,
time: PositiveF64,
_habitat: &H,
) -> bool {
let hash = diffuse(time.get().to_bits());
#[allow(clippy::cast_precision_loss)]
let u01 = ((hash >> 11) as f64) * f64::from_bits(0x3CA0_0000_0000_0000_u64); u01 <= self.probability.get()
}
}
#[inline]
const fn diffuse(mut x: u64) -> u64 {
x = x.wrapping_mul(0x6eed_0e9d_a4d9_4a4f);
let a = x >> 32;
let b = x >> 60;
x ^= a >> b;
x = x.wrapping_mul(0x6eed_0e9d_a4d9_4a4f);
x
}