From a729663eebdc82a13904d3be640501cde69969b1 Mon Sep 17 00:00:00 2001 From: Momo Langenstein Date: Fri, 13 May 2022 04:56:03 +0000 Subject: [PATCH 01/42] Untested impl of more robust index sampling --- necsim/core/src/cogs/rng.rs | 133 ++++++++++++------ .../alias/sampler/indexed/mod.rs | 5 +- .../alias/sampler/indexed/tests.rs | 7 - .../alias/sampler/stack/mod.rs | 5 +- .../alias/sampler/stack/tests.rs | 7 - 5 files changed, 97 insertions(+), 60 deletions(-) diff --git a/necsim/core/src/cogs/rng.rs b/necsim/core/src/cogs/rng.rs index b9145f0fc..f08ae55c1 100644 --- a/necsim/core/src/cogs/rng.rs +++ b/necsim/core/src/cogs/rng.rs @@ -41,6 +41,7 @@ pub trait SeedableRng: RngCore { const INC: u64 = 11_634_580_027_462_260_723_u64; let mut seed = Self::Seed::default(); + for chunk in seed.as_mut().chunks_mut(4) { // We advance the state first (to get away from the input value, // in case it has low Hamming Weight). @@ -96,68 +97,112 @@ pub trait RngSampler: RngCore { #[inline] #[debug_ensures(ret < length.get(), "samples U(0, length - 1)")] fn sample_index(&mut self, length: NonZeroUsize) -> usize { - // attributes on expressions are experimental - // see https://github.com/rust-lang/rust/issues/15701 - #[allow( - clippy::cast_precision_loss, - clippy::cast_possible_truncation, - clippy::cast_sign_loss - )] - let index = - M::floor(self.sample_uniform_closed_open().get() * (length.get() as f64)) as usize; - // Safety in case of f64 rounding errors - index.min(length.get() - 1) + #[cfg(target_pointer_width = "32")] + #[allow(clippy::cast_possible_truncation)] + { + self.sample_index_u32(unsafe { NonZeroU32::new_unchecked(length.get() as u32) }) + as usize + } + #[cfg(target_pointer_width = "64")] + #[allow(clippy::cast_possible_truncation)] + { + self.sample_index_u64(unsafe { NonZeroU64::new_unchecked(length.get() as u64) }) + as usize + } } #[must_use] #[inline] #[debug_ensures(ret < length.get(), "samples U(0, length - 1)")] fn sample_index_u32(&mut self, length: NonZeroU32) -> u32 { - // attributes on expressions are experimental - // see https://github.com/rust-lang/rust/issues/15701 - #[allow( - clippy::cast_precision_loss, - clippy::cast_possible_truncation, - clippy::cast_sign_loss - )] - let index = - M::floor(self.sample_uniform_closed_open().get() * f64::from(length.get())) as u32; - // Safety in case of f64 rounding errors - index.min(length.get() - 1) + // TODO: Check if delegation to `sample_index_u64` is faster + + // Adapted from: + // https://docs.rs/rand/0.8.4/rand/distributions/uniform/trait.UniformSampler.html#method.sample_single + + const LOWER_MASK: u64 = !0 >> 32; + + // Conservative approximation of the acceptance zone + let acceptance_zone = (length.get() << length.leading_zeros()).wrapping_sub(1); + + loop { + let raw = self.sample_u64(); + + let sample_check_lo = (raw & LOWER_MASK) * u64::from(length.get()); + + #[allow(clippy::cast_possible_truncation)] + if (sample_check_lo as u32) <= acceptance_zone { + return (sample_check_lo >> 32) as u32; + } + + let sample_check_hi = (raw >> 32) * u64::from(length.get()); + + #[allow(clippy::cast_possible_truncation)] + if (sample_check_hi as u32) <= acceptance_zone { + return (sample_check_hi >> 32) as u32; + } + } } #[must_use] #[inline] #[debug_ensures(ret < length.get(), "samples U(0, length - 1)")] fn sample_index_u64(&mut self, length: NonZeroU64) -> u64 { - // attributes on expressions are experimental - // see https://github.com/rust-lang/rust/issues/15701 - #[allow( - clippy::cast_precision_loss, - clippy::cast_possible_truncation, - clippy::cast_sign_loss - )] - let index = - M::floor(self.sample_uniform_closed_open().get() * (length.get() as f64)) as u64; - // Safety in case of f64 rounding errors - index.min(length.get() - 1) + // Adapted from: + // https://docs.rs/rand/0.8.4/rand/distributions/uniform/trait.UniformSampler.html#method.sample_single + + // Conservative approximation of the acceptance zone + let acceptance_zone = (length.get() << length.leading_zeros()).wrapping_sub(1); + + loop { + let raw = self.sample_u64(); + + let sample_check = u128::from(raw) * u128::from(length.get()); + + #[allow(clippy::cast_possible_truncation)] + if (sample_check as u64) <= acceptance_zone { + return (sample_check >> 64) as u64; + } + } } #[must_use] #[inline] #[debug_ensures(ret < length.get(), "samples U(0, length - 1)")] fn sample_index_u128(&mut self, length: NonZeroU128) -> u128 { - // attributes on expressions are experimental - // see https://github.com/rust-lang/rust/issues/15701 - #[allow( - clippy::cast_precision_loss, - clippy::cast_possible_truncation, - clippy::cast_sign_loss - )] - let index = - M::floor(self.sample_uniform_closed_open().get() * (length.get() as f64)) as u128; - // Safety in case of f64 rounding errors - index.min(length.get() - 1) + // Adapted from: + // https://docs.rs/rand/0.8.4/rand/distributions/uniform/trait.UniformSampler.html#method.sample_single + + const LOWER_MASK: u128 = !0 >> 64; + + // Conservative approximation of the acceptance zone + let acceptance_zone = (length.get() << length.leading_zeros()).wrapping_sub(1); + + loop { + let raw_hi = u128::from(self.sample_u64()); + let raw_lo = u128::from(self.sample_u64()); + + // 256-bit multiplication (hi, lo) = (raw_hi, raw_lo) * length + let mut low = raw_lo * (length.get() & LOWER_MASK); + let mut t = low >> 64; + low &= LOWER_MASK; + t += raw_hi * (length.get() & LOWER_MASK); + low += (t & LOWER_MASK) << 64; + let mut high = t >> 64; + t = low >> 64; + low &= LOWER_MASK; + t += (length.get() >> 64) * raw_lo; + low += (t & LOWER_MASK) << 64; + high += t >> 64; + high += raw_hi * (length.get() >> 64); + + let sample = high; + let check = low; + + if check <= acceptance_zone { + return sample; + } + } } #[must_use] diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs index 857a81824..df51351c9 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs @@ -1,9 +1,10 @@ use alloc::{vec, vec::Vec}; use core::{ cmp::Ordering, + convert::TryFrom, fmt, hash::Hash, - num::{NonZeroU128, NonZeroUsize}, + num::{NonZeroU128, NonZeroU64, NonZeroUsize}, }; use fnv::FnvBuildHasher; @@ -190,6 +191,8 @@ impl DynamicAliasMethodIndexedSampler { if let Some(total_weight) = NonZeroU128::new(self.total_weight) { let cdf_sample = if let [_group] = &self.groups[..] { 0_u128 + } else if let Ok(total_weight) = NonZeroU64::try_from(total_weight) { + u128::from(rng.sample_index_u64(total_weight)) } else { rng.sample_index_u128(total_weight) }; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs index 00e8d33a5..5f8310137 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs @@ -1100,11 +1100,4 @@ impl RngCore for DummyRng { self.0.pop().unwrap() } } - -#[contract_trait] -impl Backup for DummyRng { - unsafe fn backup_unchecked(&self) -> Self { - Self(self.0.clone()) - } -} // GRCOV_EXCL_STOP diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs index a0af49b8e..237653a8f 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs @@ -1,9 +1,10 @@ use alloc::{vec, vec::Vec}; use core::{ cmp::Ordering, + convert::TryFrom, fmt, hash::Hash, - num::{NonZeroU128, NonZeroUsize}, + num::{NonZeroU128, NonZeroU64, NonZeroUsize}, }; use necsim_core::cogs::{Backup, MathsCore, RngCore, RngSampler}; @@ -124,6 +125,8 @@ impl DynamicAliasMethodStackSampler { if let Some(total_weight) = NonZeroU128::new(self.total_weight) { let cdf_sample = if let [_group] = &self.groups[..] { 0_u128 + } else if let Ok(total_weight) = NonZeroU64::try_from(total_weight) { + u128::from(rng.sample_index_u64(total_weight)) } else { rng.sample_index_u128(total_weight) }; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs index 461fe6904..b2e6739c1 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs @@ -598,11 +598,4 @@ impl RngCore for DummyRng { self.0.pop().unwrap() } } - -#[contract_trait] -impl Backup for DummyRng { - unsafe fn backup_unchecked(&self) -> Self { - Self(self.0.clone()) - } -} // GRCOV_EXCL_STOP From fe3a6204ab8f92702ecae31121cce4189d7358b1 Mon Sep 17 00:00:00 2001 From: Momo Langenstein Date: Mon, 16 May 2022 10:15:02 +0000 Subject: [PATCH 02/42] Start of modular RNG generator+sampler redesign experiment --- .../core/src/cogs/active_lineage_sampler.rs | 4 +- necsim/core/src/cogs/coalescence_sampler.rs | 16 +- necsim/core/src/cogs/dispersal_sampler.rs | 6 +- necsim/core/src/cogs/emigration_exit.rs | 4 +- necsim/core/src/cogs/event_sampler.rs | 6 +- necsim/core/src/cogs/habitat.rs | 4 +- necsim/core/src/cogs/mod.rs | 5 +- necsim/core/src/cogs/rng.rs | 314 +++++++++++++++--- necsim/core/src/simulation/backup.rs | 6 +- necsim/core/src/simulation/builder.rs | 11 +- necsim/core/src/simulation/mod.rs | 4 +- .../partial/active_lineage_sampler.rs | 6 +- .../src/simulation/partial/emigration_exit.rs | 4 +- .../src/simulation/partial/event_sampler.rs | 8 +- .../src/simulation/process/immigration.rs | 4 +- necsim/core/src/simulation/process/local.rs | 4 +- 16 files changed, 324 insertions(+), 82 deletions(-) diff --git a/necsim/core/src/cogs/active_lineage_sampler.rs b/necsim/core/src/cogs/active_lineage_sampler.rs index 98df0a19e..bb8b2cc76 100644 --- a/necsim/core/src/cogs/active_lineage_sampler.rs +++ b/necsim/core/src/cogs/active_lineage_sampler.rs @@ -4,7 +4,7 @@ use necsim_core_bond::{NonNegativeF64, PositiveF64}; use super::{ CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, Habitat, ImmigrationEntry, - LineageStore, MathsCore, RngCore, SpeciationProbability, TurnoverRate, + LineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, }; use crate::{lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation}; @@ -15,7 +15,7 @@ use crate::{lineage::Lineage, simulation::partial::active_lineage_sampler::Parti pub trait ActiveLineageSampler< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, diff --git a/necsim/core/src/cogs/coalescence_sampler.rs b/necsim/core/src/cogs/coalescence_sampler.rs index 93af7bc92..526d64cf7 100644 --- a/necsim/core/src/cogs/coalescence_sampler.rs +++ b/necsim/core/src/cogs/coalescence_sampler.rs @@ -5,13 +5,14 @@ use necsim_core_bond::ClosedOpenUnitF64; use serde::{Deserialize, Serialize}; use crate::{ - cogs::{Backup, MathsCore, RngCore}, + cogs::{ + rng::UniformClosedOpenUnit, Backup, DistributionSampler, Habitat, LineageStore, MathsCore, + Rng, + }, landscape::{IndexedLocation, Location}, lineage::LineageInteraction, }; -use super::{Habitat, LineageStore}; - #[allow(clippy::inline_always, clippy::inline_fn_without_body)] #[contract_trait] pub trait CoalescenceSampler, S: LineageStore>: @@ -57,10 +58,11 @@ impl Eq for CoalescenceRngSample {} impl CoalescenceRngSample { #[must_use] #[inline] - pub fn new>(rng: &mut G) -> Self { - use crate::cogs::RngSampler; - - Self(rng.sample_uniform_closed_open()) + pub fn new>(rng: &mut G) -> Self + where + G::Sampler: DistributionSampler, + { + Self(rng.sample::()) } #[must_use] diff --git a/necsim/core/src/cogs/dispersal_sampler.rs b/necsim/core/src/cogs/dispersal_sampler.rs index 00f7e01ed..5d6a817e7 100644 --- a/necsim/core/src/cogs/dispersal_sampler.rs +++ b/necsim/core/src/cogs/dispersal_sampler.rs @@ -1,7 +1,7 @@ use necsim_core_bond::ClosedUnitF64; use crate::{ - cogs::{MathsCore, RngCore}, + cogs::{MathsCore, Rng}, landscape::Location, }; @@ -11,7 +11,7 @@ use super::Habitat; #[allow(clippy::no_effect_underscore_binding)] #[allow(clippy::module_name_repetitions)] #[contract_trait] -pub trait DispersalSampler, G: RngCore>: +pub trait DispersalSampler, G: Rng>: crate::cogs::Backup + core::fmt::Debug { #[must_use] @@ -29,7 +29,7 @@ pub trait DispersalSampler, G: RngCore>: #[allow(clippy::no_effect_underscore_binding)] #[allow(clippy::module_name_repetitions)] #[contract_trait] -pub trait SeparableDispersalSampler, G: RngCore>: +pub trait SeparableDispersalSampler, G: Rng>: DispersalSampler { #[must_use] diff --git a/necsim/core/src/cogs/emigration_exit.rs b/necsim/core/src/cogs/emigration_exit.rs index 45c6d37c3..3812eee63 100644 --- a/necsim/core/src/cogs/emigration_exit.rs +++ b/necsim/core/src/cogs/emigration_exit.rs @@ -1,7 +1,7 @@ use necsim_core_bond::{NonNegativeF64, PositiveF64}; use crate::{ - cogs::{Habitat, LineageStore, MathsCore, RngCore}, + cogs::{Habitat, LineageStore, MathsCore, Rng}, landscape::{IndexedLocation, Location}, lineage::GlobalLineageReference, simulation::partial::emigration_exit::PartialSimulation, @@ -14,7 +14,7 @@ use crate::{ )] #[allow(clippy::no_effect_underscore_binding)] #[contract_trait] -pub trait EmigrationExit, G: RngCore, S: LineageStore>: +pub trait EmigrationExit, G: Rng, S: LineageStore>: crate::cogs::Backup + core::fmt::Debug { #[must_use] diff --git a/necsim/core/src/cogs/event_sampler.rs b/necsim/core/src/cogs/event_sampler.rs index 1a619935f..7aecda59f 100644 --- a/necsim/core/src/cogs/event_sampler.rs +++ b/necsim/core/src/cogs/event_sampler.rs @@ -1,8 +1,8 @@ use necsim_core_bond::PositiveF64; use super::{ - CoalescenceSampler, DispersalSampler, EmigrationExit, Habitat, LineageStore, MathsCore, - RngCore, SpeciationProbability, TurnoverRate, + CoalescenceSampler, DispersalSampler, EmigrationExit, Habitat, LineageStore, MathsCore, Rng, + SpeciationProbability, TurnoverRate, }; use crate::{ event::{DispersalEvent, SpeciationEvent}, @@ -21,7 +21,7 @@ pub struct EventHandler { pub trait EventSampler< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, diff --git a/necsim/core/src/cogs/habitat.rs b/necsim/core/src/cogs/habitat.rs index 105ed41b6..1442637ad 100644 --- a/necsim/core/src/cogs/habitat.rs +++ b/necsim/core/src/cogs/habitat.rs @@ -2,7 +2,7 @@ use necsim_core_bond::OffByOneU64; use crate::landscape::{IndexedLocation, LandscapeExtent, Location}; -use super::{MathsCore, RngCore}; +use super::{MathsCore, Rng}; #[allow( clippy::inline_always, @@ -67,7 +67,7 @@ pub trait Habitat: crate::cogs::Backup + core::fmt::Debug + Sized clippy::no_effect_underscore_binding )] #[contract_trait] -pub trait UniformlySampleableHabitat>: Habitat { +pub trait UniformlySampleableHabitat>: Habitat { #[debug_ensures( old(self).get_extent().contains(ret.location()) && ret.index() < old(self).get_habitat_at_location(ret.location()), diff --git a/necsim/core/src/cogs/mod.rs b/necsim/core/src/cogs/mod.rs index 97233e2f6..7fa38cfc1 100644 --- a/necsim/core/src/cogs/mod.rs +++ b/necsim/core/src/cogs/mod.rs @@ -10,7 +10,10 @@ pub mod speciation_probability; pub use speciation_probability::SpeciationProbability; pub mod rng; -pub use rng::{HabitatPrimeableRng, PrimeableRng, RngCore, RngSampler, SeedableRng, SplittableRng}; +pub use rng::{ + Distribution, DistributionSampler, HabitatPrimeableRng, PrimeableRng, Rng, RngCore, + SeedableRng, SplittableRng, +}; pub mod dispersal_sampler; pub use dispersal_sampler::{DispersalSampler, SeparableDispersalSampler}; diff --git a/necsim/core/src/cogs/rng.rs b/necsim/core/src/cogs/rng.rs index f08ae55c1..616853c26 100644 --- a/necsim/core/src/cogs/rng.rs +++ b/necsim/core/src/cogs/rng.rs @@ -1,11 +1,12 @@ use core::{ convert::AsMut, default::Default, + marker::PhantomData, num::{NonZeroU128, NonZeroU32, NonZeroU64, NonZeroUsize}, ptr::copy_nonoverlapping, }; -use serde::{de::DeserializeOwned, Serialize}; +use serde::{de::DeserializeOwned, Deserialize, Deserializer, Serialize, Serializer}; use necsim_core_bond::{ ClosedOpenUnitF64, ClosedUnitF64, NonNegativeF64, OpenClosedUnitF64, PositiveF64, @@ -17,7 +18,7 @@ use crate::{ }; #[allow(clippy::module_name_repetitions)] -pub trait RngCore: +pub trait RngCore: crate::cogs::Backup + Sized + Clone + core::fmt::Debug + Serialize + DeserializeOwned { type Seed: AsMut<[u8]> + Default + Sized; @@ -30,7 +31,7 @@ pub trait RngCore: } #[allow(clippy::module_name_repetitions)] -pub trait SeedableRng: RngCore { +pub trait SeedableRng: RngCore { #[must_use] fn seed_from_u64(mut state: u64) -> Self { // Implementation from: @@ -64,9 +65,278 @@ pub trait SeedableRng: RngCore { } } -impl> SeedableRng for R {} +impl SeedableRng for R {} -#[allow(clippy::inline_always, clippy::inline_fn_without_body)] +#[allow(clippy::module_name_repetitions)] +pub trait PrimeableRng: RngCore { + fn prime_with(&mut self, location_index: u64, time_index: u64); +} + +#[allow(clippy::module_name_repetitions)] +pub trait HabitatPrimeableRng>: PrimeableRng { + #[inline] + fn prime_with_habitat( + &mut self, + habitat: &H, + indexed_location: &IndexedLocation, + time_index: u64, + ) { + self.prime_with( + habitat.map_indexed_location_to_u64_injective(indexed_location), + time_index, + ); + } +} + +impl, R: PrimeableRng> HabitatPrimeableRng for R {} + +#[allow(clippy::module_name_repetitions)] +pub trait SplittableRng: RngCore { + #[must_use] + fn split(self) -> (Self, Self); + + #[must_use] + fn split_to_stream(self, stream: u64) -> Self; +} + +pub trait Distribution { + type Parameters; + type Sample; +} + +pub trait Rng: RngCore { + type Generator: RngCore; + type Sampler; + + #[must_use] + fn generator(&mut self) -> &mut Self::Generator; + + #[must_use] + fn sample_with(&mut self, params: D::Parameters) -> D::Sample + where + Self::Sampler: DistributionSampler; + + #[must_use] + fn sample>(&mut self) -> D::Sample + where + Self::Sampler: DistributionSampler, + { + self.sample_with(()) + } +} + +#[allow(clippy::module_name_repetitions)] +pub trait DistributionSampler { + type ConcreteSampler: DistributionSampler; + + #[must_use] + fn concrete(&self) -> &Self::ConcreteSampler; + + #[must_use] + fn sample_with(&self, rng: &mut R, samplers: &S, params: D::Parameters) -> D::Sample; + + #[must_use] + fn sample(&self, rng: &mut R, samplers: &S) -> D::Sample + where + D: Distribution, + { + self.sample_with(rng, samplers, ()) + } +} + +pub enum UniformClosedOpenUnit {} + +impl Distribution for UniformClosedOpenUnit { + type Parameters = (); + type Sample = ClosedOpenUnitF64; +} + +pub enum UniformOpenClosedUnit {} + +impl Distribution for UniformOpenClosedUnit { + type Parameters = (); + type Sample = OpenClosedUnitF64; +} + +pub enum IndexUsize {} + +pub struct Length(pub T); + +impl Distribution for IndexUsize { + type Parameters = Length; + type Sample = usize; +} + +pub enum IndexU32 {} + +impl Distribution for IndexU32 { + type Parameters = Length; + type Sample = u32; +} + +pub enum IndexU64 {} + +impl Distribution for IndexU64 { + type Parameters = Length; + type Sample = u64; +} + +pub enum IndexU128 {} + +impl Distribution for IndexU128 { + type Parameters = Length; + type Sample = u128; +} + +pub enum Exponential {} + +pub struct Lambda(pub PositiveF64); + +impl Distribution for Exponential { + type Parameters = Lambda; + type Sample = NonNegativeF64; +} + +pub enum Event {} + +impl Distribution for Event { + type Parameters = ClosedUnitF64; + type Sample = bool; +} + +pub enum StandardNormal2D {} + +impl Distribution for StandardNormal2D { + type Parameters = (); + type Sample = (f64, f64); +} + +pub enum Normal2D {} + +pub struct Normal { + pub mu: f64, + pub sigma: NonNegativeF64, +} + +impl Distribution for Normal2D { + type Parameters = Normal; + type Sample = (f64, f64); +} + +#[derive(Clone, Debug)] +#[allow(clippy::module_name_repetitions)] +pub struct SimpleRng { + inner: R, + _marker: PhantomData, +} + +impl Serialize for SimpleRng { + fn serialize(&self, serializer: S) -> Result { + self.inner.serialize(serializer) + } +} + +impl<'de, M: MathsCore, R: RngCore> Deserialize<'de> for SimpleRng { + fn deserialize>(deserializer: D) -> Result { + let inner = R::deserialize(deserializer)?; + + Ok(Self { + inner, + _marker: PhantomData::, + }) + } +} + +#[contract_trait] +impl crate::cogs::Backup for SimpleRng { + unsafe fn backup_unchecked(&self) -> Self { + Self { + inner: self.inner.backup_unchecked(), + _marker: PhantomData::, + } + } +} + +impl RngCore for SimpleRng { + type Seed = R::Seed; + + #[must_use] + fn from_seed(seed: Self::Seed) -> Self { + Self { + inner: R::from_seed(seed), + _marker: PhantomData::, + } + } + + #[must_use] + fn sample_u64(&mut self) -> u64 { + self.inner.sample_u64() + } +} + +impl Rng for SimpleRng { + type Generator = R; + type Sampler = SimplerDistributionSamplers; + + fn generator(&mut self) -> &mut Self::Generator { + &mut self.inner + } + + fn sample_with(&mut self, params: D::Parameters) -> D::Sample + where + Self::Sampler: DistributionSampler, + { + let samplers = SimplerDistributionSamplers { + _marker: PhantomData::<(M, R)>, + }; + + samplers.sample_with(&mut self.inner, &samplers, params) + } +} + +#[allow(clippy::module_name_repetitions)] +pub struct SimplerDistributionSamplers { + _marker: PhantomData<(M, R)>, +} + +impl DistributionSampler + for SimplerDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with(&self, rng: &mut R, _samplers: &S, _params: ()) -> ClosedOpenUnitF64 { + // http://prng.di.unimi.it -> Generating uniform doubles in the unit interval + #[allow(clippy::cast_precision_loss)] + let u01 = ((rng.sample_u64() >> 11) as f64) * f64::from_bits(0x3CA0_0000_0000_0000_u64); // 0x1.0p-53 + + unsafe { ClosedOpenUnitF64::new_unchecked(u01) } + } +} + +impl DistributionSampler + for SimplerDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with(&self, rng: &mut R, _samplers: &S, _params: ()) -> OpenClosedUnitF64 { + // http://prng.di.unimi.it -> Generating uniform doubles in the unit interval + #[allow(clippy::cast_precision_loss)] + let u01 = + (((rng.sample_u64() >> 11) + 1) as f64) * f64::from_bits(0x3CA0_0000_0000_0000_u64); // 0x1.0p-53 + + unsafe { OpenClosedUnitF64::new_unchecked(u01) } + } +} + +/*#[allow(clippy::inline_always, clippy::inline_fn_without_body)] #[allow(clippy::module_name_repetitions)] #[contract_trait] pub trait RngSampler: RngCore { @@ -242,36 +512,4 @@ pub trait RngSampler: RngCore { } } -impl> RngSampler for R {} - -#[allow(clippy::module_name_repetitions)] -pub trait PrimeableRng: RngCore { - fn prime_with(&mut self, location_index: u64, time_index: u64); -} - -#[allow(clippy::module_name_repetitions)] -pub trait HabitatPrimeableRng>: PrimeableRng { - #[inline] - fn prime_with_habitat( - &mut self, - habitat: &H, - indexed_location: &IndexedLocation, - time_index: u64, - ) { - self.prime_with( - habitat.map_indexed_location_to_u64_injective(indexed_location), - time_index, - ); - } -} - -impl, H: Habitat> HabitatPrimeableRng for R {} - -#[allow(clippy::module_name_repetitions)] -pub trait SplittableRng: RngCore { - #[must_use] - fn split(self) -> (Self, Self); - - #[must_use] - fn split_to_stream(self, stream: u64) -> Self; -} +impl> RngSampler for R {}*/ diff --git a/necsim/core/src/simulation/backup.rs b/necsim/core/src/simulation/backup.rs index 455d78e27..1ec3bf0ad 100644 --- a/necsim/core/src/simulation/backup.rs +++ b/necsim/core/src/simulation/backup.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use crate::cogs::{ backup::BackedUp, ActiveLineageSampler, Backup, CoalescenceSampler, DispersalSampler, - EmigrationExit, EventSampler, Habitat, ImmigrationEntry, LineageStore, MathsCore, RngCore, + EmigrationExit, EventSampler, Habitat, ImmigrationEntry, LineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, }; @@ -12,7 +12,7 @@ use super::Simulation; impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, @@ -46,7 +46,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, diff --git a/necsim/core/src/simulation/builder.rs b/necsim/core/src/simulation/builder.rs index c73c112cb..4c8111f89 100644 --- a/necsim/core/src/simulation/builder.rs +++ b/necsim/core/src/simulation/builder.rs @@ -2,8 +2,7 @@ use core::{marker::PhantomData, num::Wrapping}; use crate::cogs::{ ActiveLineageSampler, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, - Habitat, ImmigrationEntry, LineageStore, MathsCore, RngCore, SpeciationProbability, - TurnoverRate, + Habitat, ImmigrationEntry, LineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, }; #[derive(Debug)] @@ -11,7 +10,7 @@ use crate::cogs::{ pub struct SimulationBuilder< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, @@ -39,7 +38,7 @@ pub struct SimulationBuilder< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, @@ -92,7 +91,7 @@ impl< pub struct Simulation< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, @@ -132,7 +131,7 @@ pub struct Simulation< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, diff --git a/necsim/core/src/simulation/mod.rs b/necsim/core/src/simulation/mod.rs index c5356f1a2..f5318eea3 100644 --- a/necsim/core/src/simulation/mod.rs +++ b/necsim/core/src/simulation/mod.rs @@ -11,7 +11,7 @@ use core::num::Wrapping; use crate::{ cogs::{ ActiveLineageSampler, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, - Habitat, ImmigrationEntry, LineageStore, MathsCore, RngCore, SpeciationProbability, + Habitat, ImmigrationEntry, LineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, }, lineage::TieBreaker, @@ -25,7 +25,7 @@ use necsim_core_bond::{NonNegativeF64, PositiveF64}; impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, diff --git a/necsim/core/src/simulation/partial/active_lineage_sampler.rs b/necsim/core/src/simulation/partial/active_lineage_sampler.rs index 846d0be89..36e5cc67f 100644 --- a/necsim/core/src/simulation/partial/active_lineage_sampler.rs +++ b/necsim/core/src/simulation/partial/active_lineage_sampler.rs @@ -2,14 +2,14 @@ use core::marker::PhantomData; use crate::cogs::{ CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, Habitat, LineageStore, - MathsCore, RngCore, SpeciationProbability, TurnoverRate, + MathsCore, Rng, SpeciationProbability, TurnoverRate, }; #[repr(C)] pub struct PartialSimulation< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, @@ -34,7 +34,7 @@ pub struct PartialSimulation< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, diff --git a/necsim/core/src/simulation/partial/emigration_exit.rs b/necsim/core/src/simulation/partial/emigration_exit.rs index ebac274f8..968e24f82 100644 --- a/necsim/core/src/simulation/partial/emigration_exit.rs +++ b/necsim/core/src/simulation/partial/emigration_exit.rs @@ -1,9 +1,9 @@ use core::marker::PhantomData; -use crate::cogs::{Habitat, LineageStore, MathsCore, RngCore}; +use crate::cogs::{Habitat, LineageStore, MathsCore, Rng}; #[repr(C)] -pub struct PartialSimulation, G: RngCore, S: LineageStore> { +pub struct PartialSimulation, G: Rng, S: LineageStore> { pub maths: PhantomData, pub habitat: H, pub lineage_store: S, diff --git a/necsim/core/src/simulation/partial/event_sampler.rs b/necsim/core/src/simulation/partial/event_sampler.rs index 8e56b884f..2cd68c655 100644 --- a/necsim/core/src/simulation/partial/event_sampler.rs +++ b/necsim/core/src/simulation/partial/event_sampler.rs @@ -1,15 +1,15 @@ use core::marker::PhantomData; use crate::cogs::{ - CoalescenceSampler, DispersalSampler, EmigrationExit, Habitat, LineageStore, MathsCore, - RngCore, SpeciationProbability, TurnoverRate, + CoalescenceSampler, DispersalSampler, EmigrationExit, Habitat, LineageStore, MathsCore, Rng, + SpeciationProbability, TurnoverRate, }; #[repr(C)] pub struct PartialSimulation< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, @@ -32,7 +32,7 @@ pub struct PartialSimulation< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, diff --git a/necsim/core/src/simulation/process/immigration.rs b/necsim/core/src/simulation/process/immigration.rs index aa1c49b3c..64e7eeccb 100644 --- a/necsim/core/src/simulation/process/immigration.rs +++ b/necsim/core/src/simulation/process/immigration.rs @@ -3,7 +3,7 @@ use core::num::Wrapping; use crate::{ cogs::{ ActiveLineageSampler, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, - Habitat, ImmigrationEntry, LineageStore, MathsCore, RngCore, SpeciationProbability, + Habitat, ImmigrationEntry, LineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, }, event::DispersalEvent, @@ -15,7 +15,7 @@ use crate::{ impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, diff --git a/necsim/core/src/simulation/process/local.rs b/necsim/core/src/simulation/process/local.rs index 2aad2fb89..01a681ffb 100644 --- a/necsim/core/src/simulation/process/local.rs +++ b/necsim/core/src/simulation/process/local.rs @@ -5,7 +5,7 @@ use necsim_core_bond::PositiveF64; use crate::{ cogs::{ event_sampler::EventHandler, ActiveLineageSampler, CoalescenceSampler, DispersalSampler, - EmigrationExit, EventSampler, Habitat, ImmigrationEntry, LineageStore, MathsCore, RngCore, + EmigrationExit, EventSampler, Habitat, ImmigrationEntry, LineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, @@ -17,7 +17,7 @@ use crate::{ impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, From b8358667a669a72172be65cf91350c50cc6093f6 Mon Sep 17 00:00:00 2001 From: Momo Langenstein Date: Tue, 17 May 2022 07:42:29 +0000 Subject: [PATCH 03/42] Some further progress in the exploration --- necsim/core/src/cogs/rng.rs | 100 +++++++++++++ necsim/impls/cuda/src/cogs/rng.rs | 37 +++-- necsim/impls/no-std/src/alias/mod.rs | 35 ++--- necsim/impls/no-std/src/alias/packed.rs | 33 ++--- .../alias/individual/mod.rs | 24 ++- .../alias/individual/sampler.rs | 15 +- .../alias/location/mod.rs | 28 +++- .../alias/location/sampler.rs | 23 +-- .../alias/sampler/indexed/mod.rs | 33 +++-- .../alias/sampler/indexed/tests.rs | 140 ++++++++++++++++-- .../alias/sampler/stack/mod.rs | 8 +- .../alias/sampler/stack/tests.rs | 2 +- .../active_lineage_sampler/classical/mod.rs | 8 +- .../classical/sampler.rs | 6 +- .../independent/event_time_sampler/const.rs | 18 ++- .../independent/event_time_sampler/exp.rs | 21 ++- .../independent/event_time_sampler/fixed.rs | 7 +- .../event_time_sampler/geometric.rs | 7 +- .../independent/event_time_sampler/mod.rs | 10 +- .../independent/event_time_sampler/poisson.rs | 4 +- .../active_lineage_sampler/independent/mod.rs | 8 +- .../independent/sampler.rs | 4 +- .../independent/singular.rs | 4 +- .../active_lineage_sampler/resuming/mod.rs | 8 +- .../resuming/sampler.rs | 6 +- .../cogs/active_lineage_sampler/singular.rs | 6 +- .../almost_infinite_normal.rs | 14 +- .../in_memory/alias/dispersal.rs | 4 +- .../dispersal_sampler/in_memory/alias/mod.rs | 8 +- .../in_memory/cumulative/dispersal.rs | 6 +- .../in_memory/cumulative/mod.rs | 4 +- .../cogs/dispersal_sampler/in_memory/mod.rs | 4 +- .../in_memory/packed_alias/dispersal.rs | 4 +- .../in_memory/packed_alias/mod.rs | 10 +- .../in_memory/separable_alias/dispersal.rs | 8 +- .../in_memory/separable_alias/mod.rs | 8 +- .../src/cogs/dispersal_sampler/non_spatial.rs | 16 +- .../dispersal_sampler/spatially_implicit.rs | 16 +- .../cogs/dispersal_sampler/trespassing/mod.rs | 14 +- .../dispersal_sampler/trespassing/uniform.rs | 10 +- .../cogs/dispersal_sampler/wrapping_noise.rs | 12 +- .../no-std/src/cogs/emigration_exit/domain.rs | 4 +- .../cogs/emigration_exit/independent/mod.rs | 12 +- .../no-std/src/cogs/emigration_exit/never.rs | 10 +- .../gillespie/conditional/mod.rs | 12 +- .../gillespie/conditional/probability.rs | 6 +- .../src/cogs/event_sampler/gillespie/mod.rs | 6 +- .../event_sampler/gillespie/unconditional.rs | 16 +- .../src/cogs/event_sampler/independent.rs | 14 +- .../no-std/src/cogs/event_sampler/tracking.rs | 6 +- .../src/cogs/event_sampler/unconditional.rs | 13 +- .../src/cogs/habitat/almost_infinite.rs | 4 +- .../no-std/src/cogs/habitat/in_memory.rs | 6 +- .../no-std/src/cogs/habitat/non_spatial.rs | 6 +- .../src/cogs/habitat/spatially_implicit.rs | 4 +- .../src/cogs/habitat/wrapping_noise/mod.rs | 8 +- necsim/impls/no-std/src/cogs/rng/rand.rs | 59 +++----- necsim/impls/no-std/src/cogs/rng/seahash.rs | 16 +- necsim/impls/no-std/src/cogs/rng/wyhash.rs | 21 +-- necsim/impls/no-std/src/lib.rs | 1 + .../independent/individuals.rs | 5 +- .../parallelisation/independent/landscape.rs | 5 +- .../independent/monolithic/mod.rs | 5 +- .../parallelisation/monolithic/averaging.rs | 5 +- .../parallelisation/monolithic/lockstep.rs | 5 +- .../parallelisation/monolithic/monolithic.rs | 5 +- .../parallelisation/monolithic/optimistic.rs | 4 +- .../monolithic/optimistic_lockstep.rs | 5 +- 68 files changed, 613 insertions(+), 383 deletions(-) diff --git a/necsim/core/src/cogs/rng.rs b/necsim/core/src/cogs/rng.rs index 616853c26..3a0130ea9 100644 --- a/necsim/core/src/cogs/rng.rs +++ b/necsim/core/src/cogs/rng.rs @@ -336,6 +336,106 @@ impl DistributionSampler> + DistributionSampler for SimplerDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with(&self, rng: &mut R, samplers: &S, params: Length) -> usize { + let length = params.0; + + let u01: ClosedOpenUnitF64 = samplers.sample(rng, samplers); + + #[allow( + clippy::cast_precision_loss, + clippy::cast_possible_truncation, + clippy::cast_sign_loss + )] + let index = M::floor(u01.get() * (length.get() as f64)) as usize; + + // Safety in case of f64 rounding errors + index.min(length.get() - 1) + } +} + +impl> + DistributionSampler for SimplerDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with(&self, rng: &mut R, samplers: &S, params: Length) -> u32 { + let length = params.0; + + let u01: ClosedOpenUnitF64 = samplers.sample(rng, samplers); + + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + let index = M::floor(u01.get() * f64::from(length.get())) as u32; + + // Safety in case of f64 rounding errors + index.min(length.get() - 1) + } +} + +impl> + DistributionSampler for SimplerDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with(&self, rng: &mut R, samplers: &S, params: Length) -> u64 { + let length = params.0; + + let u01: ClosedOpenUnitF64 = samplers.sample(rng, samplers); + + #[allow( + clippy::cast_precision_loss, + clippy::cast_possible_truncation, + clippy::cast_sign_loss + )] + let index = M::floor(u01.get() * (length.get() as f64)) as u64; + + // Safety in case of f64 rounding errors + index.min(length.get() - 1) + } +} + +impl> + DistributionSampler for SimplerDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with(&self, rng: &mut R, samplers: &S, params: Length) -> u128 { + let length = params.0; + + let u01: ClosedOpenUnitF64 = samplers.sample(rng, samplers); + + #[allow( + clippy::cast_precision_loss, + clippy::cast_possible_truncation, + clippy::cast_sign_loss + )] + let index = M::floor(u01.get() * (length.get() as f64)) as u128; + + // Safety in case of f64 rounding errors + index.min(length.get() - 1) + } +} + /*#[allow(clippy::inline_always, clippy::inline_fn_without_body)] #[allow(clippy::module_name_repetitions)] #[contract_trait] diff --git a/necsim/impls/cuda/src/cogs/rng.rs b/necsim/impls/cuda/src/cogs/rng.rs index 63073c126..af411f60e 100644 --- a/necsim/impls/cuda/src/cogs/rng.rs +++ b/necsim/impls/cuda/src/cogs/rng.rs @@ -1,6 +1,6 @@ use core::marker::PhantomData; -use necsim_core::cogs::{MathsCore, PrimeableRng, RngCore}; +use necsim_core::cogs::{Distribution, DistributionSampler, MathsCore, Rng, RngCore}; use const_type_layout::TypeGraphLayout; use rust_cuda::safety::StackOnly; @@ -12,13 +12,13 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cuda(free = "M", free = "R")] pub struct CudaRng where - R: RngCore + StackOnly + ~const TypeGraphLayout, + R: Rng + StackOnly + ~const TypeGraphLayout, { inner: R, marker: PhantomData, } -impl + StackOnly + ~const TypeGraphLayout> Clone for CudaRng { +impl + StackOnly + ~const TypeGraphLayout> Clone for CudaRng { fn clone(&self) -> Self { Self { inner: self.inner.clone(), @@ -27,7 +27,7 @@ impl + StackOnly + ~const TypeGraphLayout> Clone for } } -impl + StackOnly + ~const TypeGraphLayout> From for CudaRng { +impl + StackOnly + ~const TypeGraphLayout> From for CudaRng { #[must_use] #[inline] fn from(rng: R) -> Self { @@ -38,10 +38,10 @@ impl + StackOnly + ~const TypeGraphLayout> From f } } -impl + StackOnly + ~const TypeGraphLayout> RngCore +impl + StackOnly + ~const TypeGraphLayout> RngCore for CudaRng { - type Seed = >::Seed; + type Seed = ::Seed; #[must_use] #[inline] @@ -59,24 +59,29 @@ impl + StackOnly + ~const TypeGraphLayout> RngCore + StackOnly + ~const TypeGraphLayout> PrimeableRng - for CudaRng -{ - #[inline] - fn prime_with(&mut self, location_index: u64, time_index: u64) { - self.inner.prime_with(location_index, time_index); +impl + StackOnly + ~const TypeGraphLayout> Rng for CudaRng { + type Generator = R::Generator; + type Sampler = R::Sampler; + + fn generator(&mut self) -> &mut Self::Generator { + self.inner.generator() + } + + fn sample_with(&mut self, params: D::Parameters) -> D::Sample + where + Self::Sampler: DistributionSampler, + { + self.inner.sample_with(params) } } -impl + StackOnly + ~const TypeGraphLayout> Serialize for CudaRng { +impl + StackOnly + ~const TypeGraphLayout> Serialize for CudaRng { fn serialize(&self, serializer: S) -> Result { self.inner.serialize(serializer) } } -impl<'de, M: MathsCore, R: RngCore + StackOnly + ~const TypeGraphLayout> Deserialize<'de> - for CudaRng -{ +impl<'de, M: MathsCore, R: Rng + StackOnly + ~const TypeGraphLayout> Deserialize<'de> for CudaRng { fn deserialize>(deserializer: D) -> Result { let inner = R::deserialize(deserializer)?; diff --git a/necsim/impls/no-std/src/alias/mod.rs b/necsim/impls/no-std/src/alias/mod.rs index 2eec4ef53..f916d83d8 100644 --- a/necsim/impls/no-std/src/alias/mod.rs +++ b/necsim/impls/no-std/src/alias/mod.rs @@ -1,6 +1,11 @@ +use core::num::NonZeroUsize; + use alloc::vec::Vec; -use necsim_core::cogs::{MathsCore, RngCore}; +use necsim_core::cogs::{ + rng::{Event, IndexUsize, Length}, + DistributionSampler, MathsCore, Rng, +}; use necsim_core_bond::{ClosedUnitF64, NonNegativeF64}; pub mod packed; @@ -89,22 +94,18 @@ impl AliasMethodSampler { } #[debug_ensures(self.Es.contains(&ret), "returns one of the weighted events")] - pub fn sample_event>(&self, rng: &mut G) -> E { - use necsim_core::cogs::RngSampler; - - let x = rng.sample_uniform_closed_open(); - - #[allow( - clippy::cast_precision_loss, - clippy::cast_possible_truncation, - clippy::cast_sign_loss - )] - let i = M::floor(x.get() * (self.Es.len() as f64)) as usize; // index into events - - #[allow(clippy::cast_precision_loss)] - let y = x.get() * (self.Es.len() as f64) - (i as f64); // U(0,1) to compare against U[i] - - if y < self.Us[i].get() { + pub fn sample_event>(&self, rng: &mut G) -> E + where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, + { + // Safety: Es is non-empty by the precondition on construction + let length = unsafe { NonZeroUsize::new_unchecked(self.Es.len()) }; + + let i = rng.sample_with::(Length(length)); // index into events + + // Select Es[i] over Ks[i] according to its bucket percentage Us[i] + if rng.sample_with::(self.Us[i]) { self.Es[i] } else { self.Ks[i] diff --git a/necsim/impls/no-std/src/alias/packed.rs b/necsim/impls/no-std/src/alias/packed.rs index fcce6f9af..bca820be3 100644 --- a/necsim/impls/no-std/src/alias/packed.rs +++ b/necsim/impls/no-std/src/alias/packed.rs @@ -1,8 +1,11 @@ -use core::cmp::Ordering; +use core::{cmp::Ordering, num::NonZeroUsize}; use alloc::vec::Vec; -use necsim_core::cogs::{MathsCore, RngCore}; +use necsim_core::cogs::{ + rng::{Event, IndexUsize, Length}, + DistributionSampler, MathsCore, Rng, +}; use necsim_core_bond::{ClosedUnitF64, NonNegativeF64}; #[allow(clippy::module_name_repetitions)] @@ -108,27 +111,23 @@ impl AliasMethodSamplerAtom { old(alias_samplers).iter().map(|s| s.e).any(|e| e == ret), "returns one of the weighted events" )] - pub fn sample_event>( + pub fn sample_event>( alias_samplers: &[AliasMethodSamplerAtom], rng: &mut G, - ) -> E { - use necsim_core::cogs::RngSampler; + ) -> E + where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, + { + // Safety: alias_samplers is non-empty by the precondition + let length = unsafe { NonZeroUsize::new_unchecked(alias_samplers.len()) }; - let x = rng.sample_uniform_closed_open(); - - #[allow( - clippy::cast_precision_loss, - clippy::cast_possible_truncation, - clippy::cast_sign_loss - )] - let i = M::floor(x.get() * (alias_samplers.len() as f64)) as usize; // index into events - - #[allow(clippy::cast_precision_loss)] - let y = x.get() * (alias_samplers.len() as f64) - (i as f64); // U(0,1) to compare against U[i] + let i = rng.sample_with::(Length(length)); // index into events let sample = &alias_samplers[i]; - if y < sample.u.get() { + // Select E over K according to its bucket percentage U + if rng.sample_with::(sample.u) { sample.e } else { sample.k diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs index 94049419d..f128a9fc8 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs @@ -4,9 +4,9 @@ use core::{fmt, marker::PhantomData}; use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_core::cogs::{ - Backup, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, Habitat, - ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, RngCore, SpeciationProbability, - TurnoverRate, + rng::Exponential, Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, + EmigrationExit, EventSampler, Habitat, ImmigrationEntry, + LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, }; use crate::cogs::{ @@ -22,7 +22,7 @@ mod sampler; pub struct IndividualAliasActiveLineageSampler< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -31,7 +31,9 @@ pub struct IndividualAliasActiveLineageSampler< N: SpeciationProbability, E: EventSampler, I: ImmigrationEntry, -> { +> where + G::Sampler: DistributionSampler, +{ alias_sampler: DynamicAliasMethodStackSampler, number_active_lineages: usize, last_event_time: NonNegativeF64, @@ -42,7 +44,7 @@ pub struct IndividualAliasActiveLineageSampler< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -52,6 +54,8 @@ impl< E: EventSampler, I: ImmigrationEntry, > IndividualAliasActiveLineageSampler +where + G::Sampler: DistributionSampler, { #[must_use] pub fn init_with_store<'h, O: TrustedOriginSampler<'h, M, Habitat = H>>( @@ -149,7 +153,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -159,6 +163,8 @@ impl< E: EventSampler, I: ImmigrationEntry, > fmt::Debug for IndividualAliasActiveLineageSampler +where + G::Sampler: DistributionSampler, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("IndividualAliasActiveLineageSampler") @@ -172,7 +178,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -182,6 +188,8 @@ impl< E: EventSampler, I: ImmigrationEntry, > Backup for IndividualAliasActiveLineageSampler +where + G::Sampler: DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs index fc5440e6e..b0130ead7 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs @@ -2,9 +2,10 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ - ActiveLineageSampler, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, - Habitat, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, RngCore, - SpeciationProbability, TurnoverRate, + rng::{Exponential, Lambda}, + ActiveLineageSampler, CoalescenceSampler, DispersalSampler, DistributionSampler, + EmigrationExit, EventSampler, Habitat, ImmigrationEntry, + LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, }, lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation, @@ -18,7 +19,7 @@ use super::IndividualAliasActiveLineageSampler; impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -29,6 +30,8 @@ impl< I: ImmigrationEntry, > ActiveLineageSampler for IndividualAliasActiveLineageSampler +where + G::Sampler: DistributionSampler, { type LineageIterator<'a> = impl Iterator where H: 'a, G: 'a, S: 'a, X: 'a, D: 'a, C: 'a, T: 'a, N: 'a, E: 'a, I: 'a; @@ -60,12 +63,10 @@ impl< rng: &mut G, early_peek_stop: F, ) -> Option<(Lineage, PositiveF64)> { - use necsim_core::cogs::RngSampler; - let total_rate = self.alias_sampler.total_weight(); if let Ok(lambda) = PositiveF64::new(total_rate.get()) { - let event_time = self.last_event_time + rng.sample_exponential(lambda); + let event_time = self.last_event_time + rng.sample_with::(Lambda(lambda)); let next_event_time = PositiveF64::max_after(self.last_event_time, event_time); diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs index b8c4e29fc..206db19e6 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs @@ -5,8 +5,10 @@ use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_core::{ cogs::{ - Backup, CoalescenceSampler, DispersalSampler, EmigrationExit, GloballyCoherentLineageStore, - Habitat, ImmigrationEntry, MathsCore, RngCore, SpeciationProbability, TurnoverRate, + rng::{Exponential, IndexUsize}, + Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, EmigrationExit, + GloballyCoherentLineageStore, Habitat, ImmigrationEntry, MathsCore, Rng, + SpeciationProbability, TurnoverRate, }, landscape::Location, }; @@ -25,7 +27,7 @@ mod sampler; pub struct LocationAliasActiveLineageSampler< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -34,7 +36,10 @@ pub struct LocationAliasActiveLineageSampler< N: SpeciationProbability, E: GillespieEventSampler, I: ImmigrationEntry, -> { +> where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, +{ alias_sampler: DynamicAliasMethodIndexedSampler, number_active_lineages: usize, last_event_time: NonNegativeF64, @@ -45,7 +50,7 @@ pub struct LocationAliasActiveLineageSampler< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -55,6 +60,9 @@ impl< E: GillespieEventSampler, I: ImmigrationEntry, > LocationAliasActiveLineageSampler +where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { #[must_use] pub fn init_with_store<'h, O: TrustedOriginSampler<'h, M, Habitat = H>>( @@ -199,7 +207,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -209,6 +217,9 @@ impl< E: GillespieEventSampler, I: ImmigrationEntry, > core::fmt::Debug for LocationAliasActiveLineageSampler +where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { f.debug_struct("LocationAliasActiveLineageSampler") @@ -222,7 +233,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -232,6 +243,9 @@ impl< E: GillespieEventSampler, I: ImmigrationEntry, > Backup for LocationAliasActiveLineageSampler +where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs index 0ccbe5a34..cdf70e474 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs @@ -2,9 +2,10 @@ use core::{num::NonZeroUsize, ops::ControlFlow}; use necsim_core::{ cogs::{ - ActiveLineageSampler, Backup, CoalescenceSampler, DispersalSampler, EmigrationExit, - GloballyCoherentLineageStore, Habitat, ImmigrationEntry, MathsCore, RngCore, - SpeciationProbability, TurnoverRate, + rng::{Exponential, IndexUsize, Lambda, Length}, + ActiveLineageSampler, Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, + EmigrationExit, GloballyCoherentLineageStore, Habitat, ImmigrationEntry, + MathsCore, Rng, SpeciationProbability, TurnoverRate, }, lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation, @@ -20,7 +21,7 @@ use super::LocationAliasActiveLineageSampler; impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -31,6 +32,9 @@ impl< I: ImmigrationEntry, > ActiveLineageSampler for LocationAliasActiveLineageSampler +where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { type LineageIterator<'a> = impl Iterator where H: 'a, G: 'a, S: 'a, X: 'a, D: 'a, C: 'a, T: 'a, N: 'a, E: 'a, I: 'a; @@ -67,12 +71,10 @@ impl< rng: &mut G, early_peek_stop: F, ) -> Option<(Lineage, PositiveF64)> { - use necsim_core::cogs::RngSampler; - let total_rate = self.alias_sampler.total_weight(); if let Ok(lambda) = PositiveF64::new(total_rate.get()) { - let event_time = self.last_event_time + rng.sample_exponential(lambda); + let event_time = self.last_event_time + rng.sample_with::(Lambda(lambda)); let next_event_time = PositiveF64::max_after(self.last_event_time, event_time); @@ -95,10 +97,11 @@ impl< // Safety: `lineages_at_location` must be >0 since // `chosen_active_location` can only be selected in that case - let chosen_lineage_index_at_location = rng - .sample_index(unsafe { NonZeroUsize::new_unchecked(lineages_at_location.len()) }); + let chosen_lineage_index_at_location = rng.sample_with::(Length(unsafe { + NonZeroUsize::new_unchecked(lineages_at_location.len()) + })); // Safety: reference clone is only used to then remove the lineage, which is - // owned + // owned let chosen_lineage_reference = unsafe { lineages_at_location[chosen_lineage_index_at_location].backup_unchecked() }; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs index df51351c9..3eacfaafc 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs @@ -10,7 +10,10 @@ use core::{ use fnv::FnvBuildHasher; use hashbrown::HashMap; -use necsim_core::cogs::{Backup, MathsCore, RngCore, RngSampler}; +use necsim_core::cogs::{ + rng::{IndexU128, IndexU64, IndexUsize, Length}, + Backup, DistributionSampler, MathsCore, Rng, +}; use necsim_core_bond::{NonNegativeF64, PositiveF64}; #[cfg(test)] @@ -46,11 +49,14 @@ impl RejectionSamplingGroup { self.events.iter() } - unsafe fn sample_pop_inplace>( + unsafe fn sample_pop_inplace>( &mut self, lookup: &mut HashMap, rng: &mut G, - ) -> (Option<&mut Self>, E) { + ) -> (Option<&mut Self>, E) + where + G::Sampler: DistributionSampler, + { if let [event] = &self.events[..] { lookup.remove(event); @@ -60,7 +66,8 @@ impl RejectionSamplingGroup { loop { // Safety: By construction, the group never contains zero elements - let index = rng.sample_index(NonZeroUsize::new_unchecked(self.weights.len())); + let index = rng + .sample_with::(Length(NonZeroUsize::new_unchecked(self.weights.len()))); let height = rng.sample_u64() >> 11; // 53rd bit of weight is always 1, so sampling chance >= 50% @@ -85,11 +92,14 @@ impl RejectionSamplingGroup { } #[cfg(test)] - fn sample_pop>( + fn sample_pop>( mut self, lookup: &mut HashMap, rng: &mut G, - ) -> (Option, E) { + ) -> (Option, E) + where + G::Sampler: DistributionSampler, + { match unsafe { self.sample_pop_inplace(lookup, rng) } { (Some(_), event) => (Some(self), event), (None, event) => (None, event), @@ -187,14 +197,19 @@ impl DynamicAliasMethodIndexedSampler { self.groups.iter().flat_map(RejectionSamplingGroup::iter) } - pub fn sample_pop>(&mut self, rng: &mut G) -> Option { + pub fn sample_pop>(&mut self, rng: &mut G) -> Option + where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, + { if let Some(total_weight) = NonZeroU128::new(self.total_weight) { let cdf_sample = if let [_group] = &self.groups[..] { 0_u128 } else if let Ok(total_weight) = NonZeroU64::try_from(total_weight) { - u128::from(rng.sample_index_u64(total_weight)) + u128::from(rng.sample_with::(Length(total_weight))) } else { - rng.sample_index_u128(total_weight) + rng.sample_with::(Length(total_weight)) }; let mut cdf_acc = 0_u128; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs index 5f8310137..94ecebc74 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs @@ -1,9 +1,14 @@ use alloc::{vec, vec::Vec}; +use core::num::{NonZeroU128, NonZeroU64, NonZeroUsize}; use hashbrown::HashMap; -use necsim_core::cogs::{Backup, RngCore, SeedableRng}; +use necsim_core::cogs::{ + rng::{IndexU128, IndexU64, IndexUsize, Length, SimpleRng}, + Backup, Distribution, DistributionSampler, Rng, RngCore, SeedableRng, +}; use necsim_core_bond::{NonNegativeF64, PositiveF64}; +use necsim_core_maths::MathsCore; use crate::cogs::{maths::intrinsics::IntrinsicsMathsCore, rng::wyhash::WyHash}; @@ -183,7 +188,7 @@ fn sample_single_group() { let mut tally = [0_u64; 6]; - let mut rng = WyHash::::seed_from_u64(24897); + let mut rng = SimpleRng::::seed_from_u64(24897); for _ in 0..N { let (maybe_group, sample) = group.sample_pop(&mut lookup, &mut rng); @@ -898,7 +903,7 @@ fn add_update_event_full() { fn sample_single_group_full() { const N: usize = 10_000_000; - let mut rng = WyHash::::seed_from_u64(471_093); + let mut rng = SimpleRng::::seed_from_u64(471_093); let mut sampler = DynamicAliasMethodIndexedSampler::with_capacity(6); @@ -947,7 +952,7 @@ fn sample_single_group_full() { fn sample_three_groups_full() { const N: usize = 10_000_000; - let mut rng = WyHash::::seed_from_u64(739_139); + let mut rng = SimpleRng::::seed_from_u64(739_139); let mut sampler = DynamicAliasMethodIndexedSampler::with_capacity(6); @@ -993,7 +998,7 @@ fn sample_three_groups_full() { fn sample_three_groups_full_reverse() { const N: usize = 10_000_000; - let mut rng = WyHash::::seed_from_u64(248_971); + let mut rng = SimpleRng::::seed_from_u64(248_971); let mut sampler = DynamicAliasMethodIndexedSampler::with_capacity(6); @@ -1072,22 +1077,21 @@ fn debug_display_sampler() { // GRCOV_EXCL_START #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -struct DummyRng(Vec); +struct DummyRng(Vec); impl DummyRng { fn new(mut vec: Vec) -> Self { vec.reverse(); - #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] - Self( - vec.into_iter() - .map(|u01| ((u01 / f64::from_bits(0x3CA0_0000_0000_0000_u64)) as u64) << 11) - .collect(), - ) + Self(vec) + } + + fn sample_f64(&mut self) -> f64 { + self.0.pop().unwrap() } } -impl RngCore for DummyRng { +impl RngCore for DummyRng { type Seed = [u8; 0]; #[must_use] @@ -1097,7 +1101,115 @@ impl RngCore for DummyRng { #[must_use] fn sample_u64(&mut self) -> u64 { - self.0.pop().unwrap() + // #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + ((self.sample_f64() / f64::from_bits(0x3CA0_0000_0000_0000_u64)) as u64) << 11 + } +} + +impl Rng for DummyRng { + type Generator = Self; + type Sampler = DummyDistributionSamplers; + + fn generator(&mut self) -> &mut Self::Generator { + self + } + + fn sample_with(&mut self, params: D::Parameters) -> D::Sample + where + Self::Sampler: DistributionSampler, + { + let samplers = DummyDistributionSamplers; + + samplers.sample_with(self, &samplers, params) + } +} + +struct DummyDistributionSamplers; + +impl DistributionSampler + for DummyDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with( + &self, + rng: &mut DummyRng, + samplers: &DummyDistributionSamplers, + params: Length, + ) -> usize { + let length = params.0; + + /*#[allow( + clippy::cast_precision_loss, + clippy::cast_possible_truncation, + clippy::cast_sign_loss + )]*/ + let index = IntrinsicsMathsCore::floor(rng.sample_f64() * (length.get() as f64)) as usize; + + // Safety in case of f64 rounding errors + index.min(length.get() - 1) + } +} + +impl DistributionSampler + for DummyDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with( + &self, + rng: &mut DummyRng, + samplers: &DummyDistributionSamplers, + params: Length, + ) -> u64 { + let length = params.0; + + /*#[allow( + clippy::cast_precision_loss, + clippy::cast_possible_truncation, + clippy::cast_sign_loss + )]*/ + let index = IntrinsicsMathsCore::floor(rng.sample_f64() * (length.get() as f64)) as u64; + + // Safety in case of f64 rounding errors + index.min(length.get() - 1) + } +} + +impl DistributionSampler + for DummyDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with( + &self, + rng: &mut DummyRng, + samplers: &DummyDistributionSamplers, + params: Length, + ) -> u128 { + let length = params.0; + + /*#[allow( + clippy::cast_precision_loss, + clippy::cast_possible_truncation, + clippy::cast_sign_loss + )]*/ + let index = IntrinsicsMathsCore::floor(rng.sample_f64() * (length.get() as f64)) as u128; + + // Safety in case of f64 rounding errors + index.min(length.get() - 1) } } // GRCOV_EXCL_STOP diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs index 237653a8f..48c4e3f23 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs @@ -7,7 +7,7 @@ use core::{ num::{NonZeroU128, NonZeroU64, NonZeroUsize}, }; -use necsim_core::cogs::{Backup, MathsCore, RngCore, RngSampler}; +use necsim_core::cogs::{Backup, MathsCore, Rng, RngCore}; use necsim_core_bond::{NonNegativeF64, PositiveF64}; #[cfg(test)] @@ -42,7 +42,7 @@ impl RejectionSamplingGroup { self.events.iter() } - unsafe fn sample_pop_inplace>( + unsafe fn sample_pop_inplace>( &mut self, rng: &mut G, ) -> (Option<&mut Self>, E) { @@ -70,7 +70,7 @@ impl RejectionSamplingGroup { } #[cfg(test)] - fn sample_pop>(mut self, rng: &mut G) -> (Option, E) { + fn sample_pop>(mut self, rng: &mut G) -> (Option, E) { match unsafe { self.sample_pop_inplace(rng) } { (Some(_), event) => (Some(self), event), (None, event) => (None, event), @@ -121,7 +121,7 @@ impl DynamicAliasMethodStackSampler { self.groups.iter().flat_map(RejectionSamplingGroup::iter) } - pub fn sample_pop>(&mut self, rng: &mut G) -> Option { + pub fn sample_pop>(&mut self, rng: &mut G) -> Option { if let Some(total_weight) = NonZeroU128::new(self.total_weight) { let cdf_sample = if let [_group] = &self.groups[..] { 0_u128 diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs index b2e6739c1..9cc9b547c 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs @@ -585,7 +585,7 @@ impl DummyRng { } } -impl RngCore for DummyRng { +impl RngCore for DummyRng { type Seed = [u8; 0]; #[must_use] diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs index 2bd683d45..b1e89e4f7 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use necsim_core::cogs::{ Backup, DispersalSampler, EmigrationExit, Habitat, ImmigrationEntry, - LocallyCoherentLineageStore, MathsCore, RngCore, SpeciationProbability, + LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, }; use necsim_core_bond::NonNegativeF64; @@ -19,7 +19,7 @@ mod sampler; pub struct ClassicalActiveLineageSampler< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -35,7 +35,7 @@ pub struct ClassicalActiveLineageSampler< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -126,7 +126,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs index b8aa51b46..3e1ec7f1a 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs @@ -6,7 +6,7 @@ use core::{ use necsim_core::{ cogs::{ ActiveLineageSampler, DispersalSampler, EmigrationExit, Habitat, ImmigrationEntry, - LocallyCoherentLineageStore, MathsCore, RngCore, SpeciationProbability, + LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, }, lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation, @@ -25,7 +25,7 @@ use super::ClassicalActiveLineageSampler; impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -106,8 +106,6 @@ impl< rng: &mut G, early_peek_stop: F, ) -> Option<(Lineage, PositiveF64)> { - use necsim_core::cogs::RngSampler; - if let Some(number_active_lineages) = NonZeroU64::new(self.number_active_lineages() as u64) { let lambda = simulation.turnover_rate.get_uniform_turnover_rate() diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/const.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/const.rs index b69bc20c0..c8f230dc9 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/const.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/const.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{Habitat, MathsCore, PrimeableRng, TurnoverRate}, + cogs::{Habitat, MathsCore, PrimeableRng, Rng, TurnoverRate}, landscape::IndexedLocation, }; use necsim_core_bond::{NonNegativeF64, PositiveF64}; @@ -21,18 +21,26 @@ impl ConstEventTimeSampler { } #[contract_trait] -impl, G: PrimeableRng, T: TurnoverRate> +impl, G: Rng, T: TurnoverRate> EventTimeSampler for ConstEventTimeSampler { #[inline] fn next_event_time_at_indexed_location_weakly_after( &self, - _indexed_location: &IndexedLocation, + indexed_location: &IndexedLocation, _time: NonNegativeF64, - _habitat: &H, - _rng: &mut G, + habitat: &H, + rng: &mut G, _turnover_rate: &T, ) -> NonNegativeF64 { + // Note: Since the constant event time is not controlled by the RNG, + // feeding it directly into it should not cause a feedback loop + rng.generator().prime_with_habitat( + habitat, + indexed_location, + self.event_time.get().to_bits(), + ); + self.event_time.into() } } diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs index 8b6bdc9c4..73c36935d 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs @@ -1,5 +1,8 @@ use necsim_core::{ - cogs::{Habitat, HabitatPrimeableRng, MathsCore, PrimeableRng, RngSampler, TurnoverRate}, + cogs::{ + rng::{Exponential, Lambda}, + Habitat, HabitatPrimeableRng, MathsCore, PrimeableRng, Rng, TurnoverRate, + }, landscape::IndexedLocation, }; use necsim_core_bond::{NonNegativeF64, PositiveF64}; @@ -24,7 +27,7 @@ impl ExpEventTimeSampler { } #[contract_trait] -impl, G: PrimeableRng, T: TurnoverRate> +impl, G: Rng, T: TurnoverRate> EventTimeSampler for ExpEventTimeSampler { #[inline] @@ -55,12 +58,13 @@ impl, G: PrimeableRng, T: TurnoverRate> let mut time_slice_end = NonNegativeF64::from(time_step + 1) * self.delta_t; #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] - rng.prime_with_habitat(habitat, indexed_location, time_step); + rng.generator() + .prime_with_habitat(habitat, indexed_location, time_step); let mut sub_index: u64 = 0; loop { - event_time += rng.sample_exponential(lambda); + event_time += rng.sample_with::(Lambda(lambda)); sub_index = sub_index.wrapping_add(INV_PHI); @@ -72,13 +76,18 @@ impl, G: PrimeableRng, T: TurnoverRate> event_time = time_slice_end; time_slice_end = NonNegativeF64::from(time_step + 1) * self.delta_t; - rng.prime_with_habitat(habitat, indexed_location, time_step); + rng.generator() + .prime_with_habitat(habitat, indexed_location, time_step); } else if event_time > time { break; } } - rng.prime_with_habitat(habitat, indexed_location, time_step.wrapping_add(sub_index)); + rng.generator().prime_with_habitat( + habitat, + indexed_location, + time_step.wrapping_add(sub_index), + ); event_time } diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/fixed.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/fixed.rs index 5685d57fe..386738869 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/fixed.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/fixed.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{Habitat, HabitatPrimeableRng, MathsCore, PrimeableRng, TurnoverRate}, + cogs::{Habitat, HabitatPrimeableRng, MathsCore, PrimeableRng, Rng, TurnoverRate}, landscape::IndexedLocation, }; use necsim_core_bond::NonNegativeF64; @@ -12,7 +12,7 @@ use super::EventTimeSampler; pub struct FixedEventTimeSampler([u8; 0]); #[contract_trait] -impl, G: PrimeableRng, T: TurnoverRate> +impl, G: Rng, T: TurnoverRate> EventTimeSampler for FixedEventTimeSampler { #[inline] @@ -31,7 +31,8 @@ impl, G: PrimeableRng, T: TurnoverRate> #[allow(clippy::cast_sign_loss)] let time_step = M::floor(time.get() * lambda.get()) as u64 + 1; - rng.prime_with_habitat(habitat, indexed_location, time_step); + rng.generator() + .prime_with_habitat(habitat, indexed_location, time_step); NonNegativeF64::from(time_step) / lambda } diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs index be31a8a60..3f6c8b0bf 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{Habitat, HabitatPrimeableRng, MathsCore, PrimeableRng, RngSampler, TurnoverRate}, + cogs::{Habitat, HabitatPrimeableRng, MathsCore, PrimeableRng, Rng, TurnoverRate}, landscape::IndexedLocation, }; use necsim_core_bond::{NonNegativeF64, PositiveF64}; @@ -21,7 +21,7 @@ impl GeometricEventTimeSampler { } #[contract_trait] -impl, G: PrimeableRng, T: TurnoverRate> +impl, G: Rng, T: TurnoverRate> EventTimeSampler for GeometricEventTimeSampler { #[inline] @@ -44,7 +44,8 @@ impl, G: PrimeableRng, T: TurnoverRate> let mut time_step = M::floor(time.get() / self.delta_t.get()) as u64 + 1; loop { - rng.prime_with_habitat(habitat, indexed_location, time_step); + rng.generator() + .prime_with_habitat(habitat, indexed_location, time_step); if rng.sample_event(event_probability_per_step) { break; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/mod.rs index 19c8f2e58..d5aaf6bb1 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/mod.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{Habitat, MathsCore, PrimeableRng, TurnoverRate}, + cogs::{Habitat, MathsCore, PrimeableRng, Rng, TurnoverRate}, landscape::IndexedLocation, }; use necsim_core_bond::NonNegativeF64; @@ -13,8 +13,12 @@ pub mod poisson; #[allow(clippy::module_name_repetitions)] #[allow(clippy::inline_always, clippy::inline_fn_without_body)] #[contract_trait] -pub trait EventTimeSampler, G: PrimeableRng, T: TurnoverRate>: - Clone + core::fmt::Debug +pub trait EventTimeSampler< + M: MathsCore, + H: Habitat, + G: Rng, + T: TurnoverRate, +>: Clone + core::fmt::Debug { #[debug_requires( habitat.get_habitat_at_location(indexed_location.location()) > 0, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs index fcd1355ab..381362042 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{Habitat, HabitatPrimeableRng, MathsCore, PrimeableRng, RngSampler, TurnoverRate}, + cogs::{Habitat, HabitatPrimeableRng, MathsCore, PrimeableRng, Rng, TurnoverRate}, landscape::IndexedLocation, }; use necsim_core_bond::{NonNegativeF64, PositiveF64}; @@ -24,7 +24,7 @@ impl PoissonEventTimeSampler { } #[contract_trait] -impl, G: PrimeableRng, T: TurnoverRate> +impl, G: Rng, T: TurnoverRate> EventTimeSampler for PoissonEventTimeSampler { #[inline] diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/mod.rs index 1aafbee33..ecf692a1d 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/mod.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ - Backup, DispersalSampler, EmigrationExit, Habitat, MathsCore, PrimeableRng, + Backup, DispersalSampler, EmigrationExit, Habitat, MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, }, lineage::Lineage, @@ -30,7 +30,7 @@ use event_time_sampler::EventTimeSampler; pub struct IndependentActiveLineageSampler< M: MathsCore, H: Habitat, - G: PrimeableRng, + G: Rng, X: EmigrationExit>, D: DispersalSampler, T: TurnoverRate, @@ -52,7 +52,7 @@ pub struct IndependentActiveLineageSampler< impl< M: MathsCore, H: Habitat, - G: PrimeableRng, + G: Rng, X: EmigrationExit>, D: DispersalSampler, T: TurnoverRate, @@ -138,7 +138,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: PrimeableRng, + G: Rng, X: EmigrationExit>, D: DispersalSampler, T: TurnoverRate, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/sampler.rs index 9625dbe3f..013b1a994 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/sampler.rs @@ -3,7 +3,7 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ ActiveLineageSampler, DispersalSampler, EmigrationExit, Habitat, MathsCore, PrimeableRng, - SpeciationProbability, TurnoverRate, + Rng, SpeciationProbability, TurnoverRate, }, lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation, @@ -23,7 +23,7 @@ use super::{EventTimeSampler, IndependentActiveLineageSampler}; impl< M: MathsCore, H: Habitat, - G: PrimeableRng, + G: Rng, X: EmigrationExit>, D: DispersalSampler, T: TurnoverRate, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/singular.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/singular.rs index 5a045befb..95f102ee6 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/singular.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/singular.rs @@ -1,5 +1,5 @@ use necsim_core::cogs::{ - DispersalSampler, EmigrationExit, Habitat, MathsCore, PrimeableRng, SpeciationProbability, + DispersalSampler, EmigrationExit, Habitat, MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, }; @@ -19,7 +19,7 @@ use super::{EventTimeSampler, IndependentActiveLineageSampler}; impl< M: MathsCore, H: Habitat, - G: PrimeableRng, + G: Rng, X: EmigrationExit>, D: DispersalSampler, T: TurnoverRate, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/resuming/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/resuming/mod.rs index 2489c5f62..de2475df0 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/resuming/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/resuming/mod.rs @@ -4,7 +4,7 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ ActiveLineageSampler, Backup, CoalescenceSampler, DispersalSampler, EmigrationExit, - EventSampler, Habitat, ImmigrationEntry, LineageStore, MathsCore, RngCore, + EventSampler, Habitat, ImmigrationEntry, LineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, }, lineage::Lineage, @@ -19,7 +19,7 @@ pub mod lineage; pub struct RestartFixUpActiveLineageSampler< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, @@ -40,7 +40,7 @@ pub struct RestartFixUpActiveLineageSampler< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, @@ -71,7 +71,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/resuming/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/resuming/sampler.rs index 4520f67e6..65d718f77 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/resuming/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/resuming/sampler.rs @@ -3,8 +3,8 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ ActiveLineageSampler, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, - Habitat, ImmigrationEntry, LineageStore, MathsCore, RngCore, SpeciationProbability, - TurnoverRate, + Habitat, ImmigrationEntry, LineageStore, MathsCore, Rng, + SpeciationProbability, TurnoverRate, }, lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation, @@ -16,7 +16,7 @@ use super::RestartFixUpActiveLineageSampler; impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/singular.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/singular.rs index f595c9808..fd0526d4d 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/singular.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/singular.rs @@ -1,8 +1,8 @@ use necsim_core::{ cogs::{ ActiveLineageSampler, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, - Habitat, ImmigrationEntry, LineageStore, MathsCore, RngCore, SpeciationProbability, - TurnoverRate, + Habitat, ImmigrationEntry, LineageStore, MathsCore, Rng, + SpeciationProbability, TurnoverRate, }, lineage::Lineage, }; @@ -11,7 +11,7 @@ use necsim_core::{ pub trait SingularActiveLineageSampler< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs index 7b71b472b..8100b5656 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; use necsim_core::{ - cogs::{Backup, DispersalSampler, MathsCore, RngCore, SeparableDispersalSampler}, + cogs::{Backup, DispersalSampler, MathsCore, Rng, SeparableDispersalSampler}, landscape::Location, }; use necsim_core_bond::{ClosedUnitF64, NonNegativeF64}; @@ -12,13 +12,13 @@ use crate::cogs::habitat::almost_infinite::AlmostInfiniteHabitat; #[derive(Debug)] #[cfg_attr(feature = "cuda", derive(rust_cuda::common::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M", free = "G"))] -pub struct AlmostInfiniteNormalDispersalSampler> { +pub struct AlmostInfiniteNormalDispersalSampler> { sigma: NonNegativeF64, self_dispersal: ClosedUnitF64, marker: PhantomData<(M, G)>, } -impl> AlmostInfiniteNormalDispersalSampler { +impl> AlmostInfiniteNormalDispersalSampler { #[must_use] pub fn new(sigma: NonNegativeF64) -> Self { let self_dispersal_1d = if sigma > 0.0_f64 { @@ -40,7 +40,7 @@ impl> AlmostInfiniteNormalDispersalSampler { } #[contract_trait] -impl> Backup for AlmostInfiniteNormalDispersalSampler { +impl> Backup for AlmostInfiniteNormalDispersalSampler { unsafe fn backup_unchecked(&self) -> Self { Self { sigma: self.sigma, @@ -51,7 +51,7 @@ impl> Backup for AlmostInfiniteNormalDispersalSample } #[contract_trait] -impl> DispersalSampler, G> +impl> DispersalSampler, G> for AlmostInfiniteNormalDispersalSampler { #[must_use] @@ -61,8 +61,6 @@ impl> DispersalSampler, _habitat: &AlmostInfiniteHabitat, rng: &mut G, ) -> Location { - use necsim_core::cogs::RngSampler; - const WRAP: i64 = 1 << 32; let (dx, dy): (f64, f64) = rng.sample_2d_normal(0.0_f64, self.sigma); @@ -85,7 +83,7 @@ impl> DispersalSampler, } #[contract_trait] -impl> SeparableDispersalSampler, G> +impl> SeparableDispersalSampler, G> for AlmostInfiniteNormalDispersalSampler { #[must_use] diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/dispersal.rs index 08730e87a..88827eece 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/dispersal.rs @@ -1,12 +1,12 @@ use necsim_core::{ - cogs::{DispersalSampler, Habitat, MathsCore, RngCore}, + cogs::{DispersalSampler, Habitat, MathsCore, Rng}, landscape::Location, }; use super::InMemoryAliasDispersalSampler; #[contract_trait] -impl, G: RngCore> DispersalSampler +impl, G: Rng> DispersalSampler for InMemoryAliasDispersalSampler { #[must_use] diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/mod.rs index e063db091..a4b19842f 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/mod.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use alloc::vec::Vec; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, RngCore}, + cogs::{Backup, Habitat, MathsCore, Rng}, landscape::Location, }; use necsim_core_bond::NonNegativeF64; @@ -17,13 +17,13 @@ mod dispersal; #[allow(clippy::module_name_repetitions)] #[derive(Debug)] -pub struct InMemoryAliasDispersalSampler, G: RngCore> { +pub struct InMemoryAliasDispersalSampler, G: Rng> { alias_dispersal: Array2D>>, marker: PhantomData<(M, H, G)>, } #[contract_trait] -impl, G: RngCore> InMemoryDispersalSampler +impl, G: Rng> InMemoryDispersalSampler for InMemoryAliasDispersalSampler { /// Creates a new `InMemoryAliasDispersalSampler` from the @@ -77,7 +77,7 @@ impl, G: RngCore> InMemoryDispersalSampler, G: RngCore> Backup for InMemoryAliasDispersalSampler { +impl, G: Rng> Backup for InMemoryAliasDispersalSampler { unsafe fn backup_unchecked(&self) -> Self { Self { alias_dispersal: self.alias_dispersal.clone(), diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/dispersal.rs index d5495b774..4b34d84c9 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/dispersal.rs @@ -1,12 +1,12 @@ use necsim_core::{ - cogs::{DispersalSampler, Habitat, MathsCore, RngCore}, + cogs::{DispersalSampler, Habitat, MathsCore, Rng}, landscape::Location, }; use super::InMemoryCumulativeDispersalSampler; #[contract_trait] -impl, G: RngCore> DispersalSampler +impl, G: Rng> DispersalSampler for InMemoryCumulativeDispersalSampler { #[must_use] @@ -16,8 +16,6 @@ impl, G: RngCore> DispersalSampler habitat: &H, rng: &mut G, ) -> Location { - use necsim_core::cogs::RngSampler; - let location_index = (location.y().wrapping_sub(habitat.get_extent().y()) as usize) * usize::from(habitat.get_extent().width()) + (location.x().wrapping_sub(habitat.get_extent().x()) as usize); diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/mod.rs index 956ffd211..fe030a331 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/mod.rs @@ -1,7 +1,7 @@ use alloc::{boxed::Box, vec}; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, RngCore}, + cogs::{Backup, Habitat, MathsCore, Rng}, landscape::Location, }; use necsim_core_bond::{ClosedUnitF64, NonNegativeF64}; @@ -19,7 +19,7 @@ pub struct InMemoryCumulativeDispersalSampler { } #[contract_trait] -impl, G: RngCore> InMemoryDispersalSampler +impl, G: Rng> InMemoryDispersalSampler for InMemoryCumulativeDispersalSampler { /// Creates a new `InMemoryCumulativeDispersalSampler` from the diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/mod.rs index e046c4daa..1d32de4a0 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/mod.rs @@ -1,4 +1,4 @@ -use necsim_core::cogs::{DispersalSampler, Habitat, MathsCore, RngCore}; +use necsim_core::cogs::{DispersalSampler, Habitat, MathsCore, Rng}; use crate::array2d::Array2D; @@ -15,7 +15,7 @@ use necsim_core_bond::NonNegativeF64; #[allow(clippy::module_name_repetitions)] #[allow(clippy::inline_always, clippy::inline_fn_without_body)] #[contract_trait] -pub trait InMemoryDispersalSampler, G: RngCore>: +pub trait InMemoryDispersalSampler, G: Rng>: DispersalSampler + Sized { #[debug_requires(( diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/dispersal.rs index 107405bcd..16722013d 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/dispersal.rs @@ -1,7 +1,7 @@ use core::ops::Range; use necsim_core::{ - cogs::{DispersalSampler, Habitat, MathsCore, RngCore}, + cogs::{DispersalSampler, Habitat, MathsCore, Rng}, landscape::Location, }; @@ -10,7 +10,7 @@ use crate::alias::packed::AliasMethodSamplerAtom; use super::InMemoryPackedAliasDispersalSampler; #[contract_trait] -impl, G: RngCore> DispersalSampler +impl, G: Rng> DispersalSampler for InMemoryPackedAliasDispersalSampler { #[must_use] diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs index f3c191fdf..59bc188d3 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs @@ -5,7 +5,7 @@ use necsim_core_bond::NonNegativeF64; use r#final::Final; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, RngCore}, + cogs::{Backup, Habitat, MathsCore, Rng}, landscape::Location, }; @@ -42,7 +42,7 @@ impl From for Range { #[allow(clippy::module_name_repetitions)] #[cfg_attr(feature = "cuda", derive(rust_cuda::common::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M", free = "H", free = "G"))] -pub struct InMemoryPackedAliasDispersalSampler, G: RngCore> { +pub struct InMemoryPackedAliasDispersalSampler, G: Rng> { #[cfg_attr(feature = "cuda", cuda(embed))] alias_dispersal_ranges: Final>, #[cfg_attr(feature = "cuda", cuda(embed))] @@ -51,7 +51,7 @@ pub struct InMemoryPackedAliasDispersalSampler, G: R } #[contract_trait] -impl, G: RngCore> InMemoryDispersalSampler +impl, G: Rng> InMemoryDispersalSampler for InMemoryPackedAliasDispersalSampler { /// Creates a new `InMemoryPackedAliasDispersalSampler` from the @@ -112,7 +112,7 @@ impl, G: RngCore> InMemoryDispersalSampler, G: RngCore> core::fmt::Debug +impl, G: Rng> core::fmt::Debug for InMemoryPackedAliasDispersalSampler { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { @@ -131,7 +131,7 @@ impl, G: RngCore> core::fmt::Debug } #[contract_trait] -impl, G: RngCore> Backup +impl, G: Rng> Backup for InMemoryPackedAliasDispersalSampler { unsafe fn backup_unchecked(&self) -> Self { diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs index 84bf3f84c..1c7c37e99 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{DispersalSampler, Habitat, MathsCore, RngCore, SeparableDispersalSampler}, + cogs::{DispersalSampler, Habitat, MathsCore, Rng, SeparableDispersalSampler}, landscape::Location, }; use necsim_core_bond::ClosedUnitF64; @@ -7,7 +7,7 @@ use necsim_core_bond::ClosedUnitF64; use super::InMemorySeparableAliasDispersalSampler; #[contract_trait] -impl, G: RngCore> DispersalSampler +impl, G: Rng> DispersalSampler for InMemorySeparableAliasDispersalSampler { #[must_use] @@ -17,8 +17,6 @@ impl, G: RngCore> DispersalSampler habitat: &H, rng: &mut G, ) -> Location { - use necsim_core::cogs::RngSampler; - let self_dispersal_at_location = self.get_self_dispersal_probability_at_location(location, habitat); @@ -35,7 +33,7 @@ impl, G: RngCore> DispersalSampler } #[contract_trait] -impl, G: RngCore> SeparableDispersalSampler +impl, G: Rng> SeparableDispersalSampler for InMemorySeparableAliasDispersalSampler { #[must_use] diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/mod.rs index 57c81986b..70cda163e 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/mod.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use alloc::vec::Vec; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, RngCore}, + cogs::{Backup, Habitat, MathsCore, Rng}, landscape::Location, }; use necsim_core_bond::{ClosedUnitF64, NonNegativeF64}; @@ -17,14 +17,14 @@ mod dispersal; #[allow(clippy::module_name_repetitions)] #[derive(Debug)] -pub struct InMemorySeparableAliasDispersalSampler, G: RngCore> { +pub struct InMemorySeparableAliasDispersalSampler, G: Rng> { alias_dispersal: Array2D>>, self_dispersal: Array2D, _marker: PhantomData<(M, H, G)>, } #[contract_trait] -impl, G: RngCore> InMemoryDispersalSampler +impl, G: Rng> InMemoryDispersalSampler for InMemorySeparableAliasDispersalSampler { /// Creates a new `InMemorySeparableAliasDispersalSampler` from the @@ -112,7 +112,7 @@ impl, G: RngCore> InMemoryDispersalSampler, G: RngCore> Backup +impl, G: Rng> Backup for InMemorySeparableAliasDispersalSampler { unsafe fn backup_unchecked(&self) -> Self { diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/non_spatial.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/non_spatial.rs index 23fbe2a0e..929521c05 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/non_spatial.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/non_spatial.rs @@ -1,7 +1,7 @@ use core::{marker::PhantomData, num::NonZeroU64}; use necsim_core::{ - cogs::{Backup, DispersalSampler, Habitat, MathsCore, RngCore, SeparableDispersalSampler}, + cogs::{Backup, DispersalSampler, Habitat, MathsCore, Rng, SeparableDispersalSampler}, landscape::Location, }; use necsim_core_bond::ClosedUnitF64; @@ -12,11 +12,11 @@ use crate::cogs::habitat::non_spatial::NonSpatialHabitat; #[derive(Debug)] #[cfg_attr(feature = "cuda", derive(rust_cuda::common::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M", free = "G"))] -pub struct NonSpatialDispersalSampler> { +pub struct NonSpatialDispersalSampler> { marker: PhantomData<(M, G)>, } -impl> Default for NonSpatialDispersalSampler { +impl> Default for NonSpatialDispersalSampler { #[must_use] fn default() -> Self { Self { @@ -26,7 +26,7 @@ impl> Default for NonSpatialDispersalSampler { } #[contract_trait] -impl> Backup for NonSpatialDispersalSampler { +impl> Backup for NonSpatialDispersalSampler { unsafe fn backup_unchecked(&self) -> Self { Self { marker: PhantomData::<(M, G)>, @@ -35,7 +35,7 @@ impl> Backup for NonSpatialDispersalSampler { } #[contract_trait] -impl> DispersalSampler, G> +impl> DispersalSampler, G> for NonSpatialDispersalSampler { #[must_use] @@ -46,8 +46,6 @@ impl> DispersalSampler, G> habitat: &NonSpatialHabitat, rng: &mut G, ) -> Location { - use necsim_core::cogs::RngSampler; - let habitat_index_max = habitat.get_extent().width().get() * habitat.get_extent().height().get(); @@ -70,7 +68,7 @@ impl> DispersalSampler, G> } #[contract_trait] -impl> SeparableDispersalSampler, G> +impl> SeparableDispersalSampler, G> for NonSpatialDispersalSampler { #[must_use] @@ -83,8 +81,6 @@ impl> SeparableDispersalSampler, rng: &mut G, ) -> Location { - use necsim_core::cogs::RngSampler; - let habitat_index_max = habitat.get_extent().width().get() * habitat.get_extent().height().get(); let current_location_index = diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs index 9664e50bb..3451bc9bb 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{Backup, DispersalSampler, Habitat, MathsCore, RngCore, SeparableDispersalSampler}, + cogs::{Backup, DispersalSampler, Habitat, MathsCore, Rng, SeparableDispersalSampler}, landscape::Location, }; use necsim_core_bond::{ClosedUnitF64, OpenClosedUnitF64 as PositiveUnitF64}; @@ -13,7 +13,7 @@ use crate::cogs::{ #[derive(Debug)] #[cfg_attr(feature = "cuda", derive(rust_cuda::common::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M"))] -pub struct SpatiallyImplicitDispersalSampler> { +pub struct SpatiallyImplicitDispersalSampler> { #[cfg_attr(feature = "cuda", cuda(embed))] local: NonSpatialDispersalSampler, #[cfg_attr(feature = "cuda", cuda(embed))] @@ -21,7 +21,7 @@ pub struct SpatiallyImplicitDispersalSampler> { local_migration_probability_per_generation: PositiveUnitF64, } -impl> SpatiallyImplicitDispersalSampler { +impl> SpatiallyImplicitDispersalSampler { #[must_use] pub fn new(local_migration_probability_per_generation: PositiveUnitF64) -> Self { Self { @@ -33,7 +33,7 @@ impl> SpatiallyImplicitDispersalSampler { } #[contract_trait] -impl> Backup for SpatiallyImplicitDispersalSampler { +impl> Backup for SpatiallyImplicitDispersalSampler { unsafe fn backup_unchecked(&self) -> Self { Self { local: self.local.backup_unchecked(), @@ -45,7 +45,7 @@ impl> Backup for SpatiallyImplicitDispersalSampler> DispersalSampler, G> +impl> DispersalSampler, G> for SpatiallyImplicitDispersalSampler { #[must_use] @@ -62,8 +62,6 @@ impl> DispersalSampler, rng: &mut G, ) -> Location { - use necsim_core::cogs::RngSampler; - // By PRE, location must be habitable, i.e. either in the local or the meta // habitat if habitat.local().get_extent().contains(location) { @@ -89,7 +87,7 @@ impl> DispersalSampler> SeparableDispersalSampler, G> +impl> SeparableDispersalSampler, G> for SpatiallyImplicitDispersalSampler { #[must_use] @@ -106,8 +104,6 @@ impl> SeparableDispersalSampler, rng: &mut G, ) -> Location { - use necsim_core::cogs::RngSampler; - // By PRE, location must be habitable, i.e. either in the local or the meta // habitat if habitat.local().get_extent().contains(location) { diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/trespassing/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/trespassing/mod.rs index 996dc2684..e91e6e088 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/trespassing/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/trespassing/mod.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; use necsim_core::{ - cogs::{Backup, DispersalSampler, Habitat, MathsCore, RngCore, SeparableDispersalSampler}, + cogs::{Backup, DispersalSampler, Habitat, MathsCore, Rng, SeparableDispersalSampler}, landscape::Location, }; use necsim_core_bond::ClosedUnitF64; @@ -12,7 +12,7 @@ pub mod uniform; #[allow(clippy::no_effect_underscore_binding)] #[allow(clippy::module_name_repetitions)] #[contract_trait] -pub trait AntiTrespassingDispersalSampler, G: RngCore>: +pub trait AntiTrespassingDispersalSampler, G: Rng>: Backup + core::fmt::Debug { #[must_use] @@ -33,7 +33,7 @@ pub trait AntiTrespassingDispersalSampler, G: RngCor pub struct TrespassingDispersalSampler< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, D: DispersalSampler, T: AntiTrespassingDispersalSampler, > { @@ -47,7 +47,7 @@ pub struct TrespassingDispersalSampler< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, D: DispersalSampler, T: AntiTrespassingDispersalSampler, > TrespassingDispersalSampler @@ -66,7 +66,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, D: DispersalSampler, T: AntiTrespassingDispersalSampler, > Backup for TrespassingDispersalSampler @@ -83,7 +83,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, D: DispersalSampler, T: AntiTrespassingDispersalSampler, > DispersalSampler for TrespassingDispersalSampler @@ -126,7 +126,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, D: SeparableDispersalSampler, T: AntiTrespassingDispersalSampler, > SeparableDispersalSampler for TrespassingDispersalSampler diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/trespassing/uniform.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/trespassing/uniform.rs index 22e3216d2..6902e935d 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/trespassing/uniform.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/trespassing/uniform.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; use necsim_core::{ - cogs::{Backup, MathsCore, RngCore, UniformlySampleableHabitat}, + cogs::{Backup, MathsCore, Rng, UniformlySampleableHabitat}, landscape::Location, }; @@ -14,12 +14,12 @@ use super::AntiTrespassingDispersalSampler; pub struct UniformAntiTrespassingDispersalSampler< M: MathsCore, H: UniformlySampleableHabitat, - G: RngCore, + G: Rng, > { marker: PhantomData<(M, H, G)>, } -impl, G: RngCore> Default +impl, G: Rng> Default for UniformAntiTrespassingDispersalSampler { #[must_use] @@ -31,7 +31,7 @@ impl, G: RngCore> Default } #[contract_trait] -impl, G: RngCore> Backup +impl, G: Rng> Backup for UniformAntiTrespassingDispersalSampler { unsafe fn backup_unchecked(&self) -> Self { @@ -42,7 +42,7 @@ impl, G: RngCore> Backup } #[contract_trait] -impl, G: RngCore> +impl, G: Rng> AntiTrespassingDispersalSampler for UniformAntiTrespassingDispersalSampler { #[must_use] diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/wrapping_noise.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/wrapping_noise.rs index 5f38306db..e423248d3 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/wrapping_noise.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/wrapping_noise.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - Backup, DispersalSampler, Habitat, MathsCore, RngCore, RngSampler, + Backup, DispersalSampler, Habitat, MathsCore, Rng, SeparableDispersalSampler, }, landscape::Location, @@ -16,12 +16,12 @@ use crate::cogs::{ #[derive(Debug)] #[cfg_attr(feature = "cuda", derive(rust_cuda::common::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M"))] -pub struct WrappingNoiseApproximateNormalDispersalSampler> { +pub struct WrappingNoiseApproximateNormalDispersalSampler> { #[cfg_attr(feature = "cuda", cuda(embed))] inner: AlmostInfiniteNormalDispersalSampler, } -impl> WrappingNoiseApproximateNormalDispersalSampler { +impl> WrappingNoiseApproximateNormalDispersalSampler { #[must_use] pub fn new(sigma: NonNegativeF64) -> Self { Self { @@ -31,7 +31,7 @@ impl> WrappingNoiseApproximateNormalDispersalSampler } #[contract_trait] -impl> Backup for WrappingNoiseApproximateNormalDispersalSampler { +impl> Backup for WrappingNoiseApproximateNormalDispersalSampler { unsafe fn backup_unchecked(&self) -> Self { Self { inner: self.inner.backup_unchecked(), @@ -40,7 +40,7 @@ impl> Backup for WrappingNoiseApproximateNormalDispe } #[contract_trait] -impl> DispersalSampler, G> +impl> DispersalSampler, G> for WrappingNoiseApproximateNormalDispersalSampler { #[must_use] @@ -65,7 +65,7 @@ impl> DispersalSampler, G } #[contract_trait] -impl> SeparableDispersalSampler, G> +impl> SeparableDispersalSampler, G> for WrappingNoiseApproximateNormalDispersalSampler { #[must_use] diff --git a/necsim/impls/no-std/src/cogs/emigration_exit/domain.rs b/necsim/impls/no-std/src/cogs/emigration_exit/domain.rs index dca13451b..4fbc4873c 100644 --- a/necsim/impls/no-std/src/cogs/emigration_exit/domain.rs +++ b/necsim/impls/no-std/src/cogs/emigration_exit/domain.rs @@ -6,7 +6,7 @@ use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_core::{ cogs::{ coalescence_sampler::CoalescenceRngSample, Backup, EmigrationExit, Habitat, - LocallyCoherentLineageStore, MathsCore, RngCore, + LocallyCoherentLineageStore, MathsCore, Rng, }, landscape::{IndexedLocation, Location}, lineage::{GlobalLineageReference, MigratingLineage, TieBreaker}, @@ -45,7 +45,7 @@ impl< M: MathsCore, H: Habitat, C: Decomposition, - G: RngCore, + G: Rng, S: LocallyCoherentLineageStore, > EmigrationExit for DomainEmigrationExit { diff --git a/necsim/impls/no-std/src/cogs/emigration_exit/independent/mod.rs b/necsim/impls/no-std/src/cogs/emigration_exit/independent/mod.rs index 5720aca3a..42a6a868a 100644 --- a/necsim/impls/no-std/src/cogs/emigration_exit/independent/mod.rs +++ b/necsim/impls/no-std/src/cogs/emigration_exit/independent/mod.rs @@ -2,8 +2,7 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ - coalescence_sampler::CoalescenceRngSample, Backup, EmigrationExit, Habitat, MathsCore, - RngCore, + coalescence_sampler::CoalescenceRngSample, Backup, EmigrationExit, Habitat, MathsCore, Rng, }, landscape::{IndexedLocation, Location}, lineage::{GlobalLineageReference, MigratingLineage, TieBreaker}, @@ -52,13 +51,8 @@ impl, C: Decomposition, E: EmigrationChoice, - C: Decomposition, - E: EmigrationChoice, - G: RngCore, - > EmigrationExit> +impl, C: Decomposition, E: EmigrationChoice, G: Rng> + EmigrationExit> for IndependentEmigrationExit { #[must_use] diff --git a/necsim/impls/no-std/src/cogs/emigration_exit/never.rs b/necsim/impls/no-std/src/cogs/emigration_exit/never.rs index 74a68fdda..d24934c67 100644 --- a/necsim/impls/no-std/src/cogs/emigration_exit/never.rs +++ b/necsim/impls/no-std/src/cogs/emigration_exit/never.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{Backup, EmigrationExit, Habitat, LineageStore, MathsCore, RngCore}, + cogs::{Backup, EmigrationExit, Habitat, LineageStore, MathsCore, Rng}, landscape::{IndexedLocation, Location}, lineage::GlobalLineageReference, simulation::partial::emigration_exit::PartialSimulation, @@ -19,8 +19,12 @@ impl Backup for NeverEmigrationExit { } #[contract_trait] -impl, G: RngCore, S: LineageStore> EmigrationExit - for NeverEmigrationExit +impl< + M: MathsCore, + H: Habitat, + G: Rng, + S: LineageStore, + > EmigrationExit for NeverEmigrationExit { #[must_use] #[inline] diff --git a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/mod.rs b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/mod.rs index 2775ad348..dab070974 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/mod.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/mod.rs @@ -4,7 +4,7 @@ use necsim_core::{ cogs::{ coalescence_sampler::CoalescenceRngSample, event_sampler::EventHandler, Backup, CoalescenceSampler, EmigrationExit, EventSampler, GloballyCoherentLineageStore, Habitat, - MathsCore, RngCore, RngSampler, SeparableDispersalSampler, SpeciationProbability, + MathsCore, Rng, SeparableDispersalSampler, SpeciationProbability, TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, @@ -28,7 +28,7 @@ use probability::ProbabilityAtLocation; pub struct ConditionalGillespieEventSampler< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: GloballyCoherentLineageStore, X: EmigrationExit, D: SeparableDispersalSampler, @@ -42,7 +42,7 @@ pub struct ConditionalGillespieEventSampler< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: GloballyCoherentLineageStore, X: EmigrationExit, D: SeparableDispersalSampler, @@ -61,7 +61,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: GloballyCoherentLineageStore, X: EmigrationExit, D: SeparableDispersalSampler, @@ -80,7 +80,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: GloballyCoherentLineageStore, X: EmigrationExit, D: SeparableDispersalSampler, @@ -232,7 +232,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: GloballyCoherentLineageStore, X: EmigrationExit, D: SeparableDispersalSampler, diff --git a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/probability.rs b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/probability.rs index 8d7ccaba2..18e191eae 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/probability.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/probability.rs @@ -1,7 +1,7 @@ use necsim_core::{ cogs::{ - GloballyCoherentLineageStore, Habitat, MathsCore, RngCore, SeparableDispersalSampler, - SpeciationProbability, + GloballyCoherentLineageStore, Habitat, MathsCore, Rng, + SeparableDispersalSampler, SpeciationProbability, }, landscape::Location, }; @@ -20,7 +20,7 @@ impl ProbabilityAtLocation { pub fn new< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: GloballyCoherentLineageStore, D: SeparableDispersalSampler, N: SpeciationProbability, diff --git a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/mod.rs b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/mod.rs index f0c8b72cb..5a79a1626 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/mod.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/mod.rs @@ -1,7 +1,7 @@ use necsim_core::{ cogs::{ - CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, Habitat, LineageStore, - MathsCore, RngCore, SpeciationProbability, TurnoverRate, + CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, Habitat, + LineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, }, landscape::Location, }; @@ -16,7 +16,7 @@ pub mod unconditional; pub trait GillespieEventSampler< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, diff --git a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs index b1864186d..60f73d73e 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs @@ -4,8 +4,8 @@ use necsim_core::{ cogs::{ coalescence_sampler::CoalescenceRngSample, event_sampler::EventHandler, Backup, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, - GloballyCoherentLineageStore, Habitat, MathsCore, RngCore, SpeciationProbability, - TurnoverRate, + GloballyCoherentLineageStore, Habitat, MathsCore, Rng, + SpeciationProbability, TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, landscape::Location, @@ -21,7 +21,7 @@ use super::GillespieEventSampler; pub struct UnconditionalGillespieEventSampler< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -36,7 +36,7 @@ pub struct UnconditionalGillespieEventSampler< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -56,7 +56,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -76,7 +76,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -110,8 +110,6 @@ impl< }: EventHandler, auxiliary: Aux, ) -> Q { - use necsim_core::cogs::RngSampler; - if rng.sample_event( simulation .speciation_probability @@ -185,7 +183,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, diff --git a/necsim/impls/no-std/src/cogs/event_sampler/independent.rs b/necsim/impls/no-std/src/cogs/event_sampler/independent.rs index baeb01622..b70a5ea73 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/independent.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/independent.rs @@ -4,7 +4,7 @@ use necsim_core::{ cogs::{ coalescence_sampler::CoalescenceRngSample, event_sampler::EventHandler, Backup, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, Habitat, MathsCore, - RngCore, SpeciationProbability, TurnoverRate, + Rng, SpeciationProbability, TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, lineage::Lineage, @@ -37,7 +37,7 @@ use super::tracking::{MinSpeciationTrackingEventSampler, SpeciationSample}; pub struct IndependentEventSampler< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, X: EmigrationExit>, D: DispersalSampler, T: TurnoverRate, @@ -56,7 +56,7 @@ pub struct IndependentEventSampler< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, X: EmigrationExit>, D: DispersalSampler, T: TurnoverRate, @@ -75,7 +75,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, X: EmigrationExit>, D: DispersalSampler, T: TurnoverRate, @@ -94,7 +94,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, X: EmigrationExit>, D: DispersalSampler, T: TurnoverRate, @@ -147,8 +147,6 @@ impl< }: EventHandler, auxiliary: Aux, ) -> Q { - use necsim_core::cogs::RngSampler; - let speciation_sample = rng.sample_uniform_closed_open(); SpeciationSample::update_min( @@ -230,7 +228,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, X: EmigrationExit>, D: DispersalSampler, T: TurnoverRate, diff --git a/necsim/impls/no-std/src/cogs/event_sampler/tracking.rs b/necsim/impls/no-std/src/cogs/event_sampler/tracking.rs index 8b5c1cccd..5b825f178 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/tracking.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/tracking.rs @@ -4,8 +4,8 @@ use necsim_core_bond::{ClosedOpenUnitF64, PositiveF64}; use necsim_core::{ cogs::{ - CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, Habitat, LineageStore, - MathsCore, RngCore, SpeciationProbability, TurnoverRate, + CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, Habitat, + LineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, }, landscape::IndexedLocation, }; @@ -13,7 +13,7 @@ use necsim_core::{ pub trait MinSpeciationTrackingEventSampler< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LineageStore, X: EmigrationExit, D: DispersalSampler, diff --git a/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs b/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs index b20c476e7..7c97b3423 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs @@ -4,7 +4,8 @@ use necsim_core::{ cogs::{ coalescence_sampler::CoalescenceRngSample, event_sampler::EventHandler, Backup, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, Habitat, - LocallyCoherentLineageStore, MathsCore, RngCore, SpeciationProbability, TurnoverRate, + LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, + TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, lineage::Lineage, @@ -17,7 +18,7 @@ use necsim_core_bond::PositiveF64; pub struct UnconditionalEventSampler< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -32,7 +33,7 @@ pub struct UnconditionalEventSampler< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -52,7 +53,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -72,7 +73,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -106,8 +107,6 @@ impl< }: EventHandler, auxiliary: Aux, ) -> Q { - use necsim_core::cogs::RngSampler; - if rng.sample_event( simulation .speciation_probability diff --git a/necsim/impls/no-std/src/cogs/habitat/almost_infinite.rs b/necsim/impls/no-std/src/cogs/habitat/almost_infinite.rs index 914672dbc..84c668f9d 100644 --- a/necsim/impls/no-std/src/cogs/habitat/almost_infinite.rs +++ b/necsim/impls/no-std/src/cogs/habitat/almost_infinite.rs @@ -1,7 +1,7 @@ use core::{fmt, marker::PhantomData}; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, RngCore, UniformlySampleableHabitat}, + cogs::{Backup, Habitat, MathsCore, Rng, UniformlySampleableHabitat}, landscape::{IndexedLocation, LandscapeExtent, Location}, }; use necsim_core_bond::{OffByOneU32, OffByOneU64}; @@ -78,7 +78,7 @@ impl Habitat for AlmostInfiniteHabitat { } #[contract_trait] -impl> UniformlySampleableHabitat for AlmostInfiniteHabitat { +impl> UniformlySampleableHabitat for AlmostInfiniteHabitat { #[must_use] #[inline] fn sample_habitable_indexed_location(&self, rng: &mut G) -> IndexedLocation { diff --git a/necsim/impls/no-std/src/cogs/habitat/in_memory.rs b/necsim/impls/no-std/src/cogs/habitat/in_memory.rs index 7ee8a1cd4..f611f629a 100644 --- a/necsim/impls/no-std/src/cogs/habitat/in_memory.rs +++ b/necsim/impls/no-std/src/cogs/habitat/in_memory.rs @@ -5,7 +5,7 @@ use alloc::{boxed::Box, vec::Vec}; use r#final::Final; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, RngCore, UniformlySampleableHabitat}, + cogs::{Backup, Habitat, MathsCore, Rng, UniformlySampleableHabitat}, landscape::{IndexedLocation, LandscapeExtent, Location}, }; use necsim_core_bond::{OffByOneU32, OffByOneU64}; @@ -106,12 +106,10 @@ impl Habitat for InMemoryHabitat { } #[contract_trait] -impl> UniformlySampleableHabitat for InMemoryHabitat { +impl> UniformlySampleableHabitat for InMemoryHabitat { #[must_use] #[inline] fn sample_habitable_indexed_location(&self, rng: &mut G) -> IndexedLocation { - use necsim_core::cogs::RngSampler; - let indexed_location_index = rng.sample_index_u64(self.get_total_habitat().into()); let location_index = match self.u64_injection.binary_search(&indexed_location_index) { diff --git a/necsim/impls/no-std/src/cogs/habitat/non_spatial.rs b/necsim/impls/no-std/src/cogs/habitat/non_spatial.rs index bbba06e66..5a7189ff4 100644 --- a/necsim/impls/no-std/src/cogs/habitat/non_spatial.rs +++ b/necsim/impls/no-std/src/cogs/habitat/non_spatial.rs @@ -4,7 +4,7 @@ use core::{ }; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, RngCore, UniformlySampleableHabitat}, + cogs::{Backup, Habitat, MathsCore, Rng, UniformlySampleableHabitat}, landscape::{IndexedLocation, LandscapeExtent, Location}, }; use necsim_core_bond::{OffByOneU32, OffByOneU64}; @@ -116,12 +116,10 @@ impl Habitat for NonSpatialHabitat { } #[contract_trait] -impl> UniformlySampleableHabitat for NonSpatialHabitat { +impl> UniformlySampleableHabitat for NonSpatialHabitat { #[must_use] #[inline] fn sample_habitable_indexed_location(&self, rng: &mut G) -> IndexedLocation { - use necsim_core::cogs::RngSampler; - let habitat_index_max = self.extent.width().get() * self.extent.height().get() * u64::from(self.deme.get()); diff --git a/necsim/impls/no-std/src/cogs/habitat/spatially_implicit.rs b/necsim/impls/no-std/src/cogs/habitat/spatially_implicit.rs index 5f78012e9..80f7812da 100644 --- a/necsim/impls/no-std/src/cogs/habitat/spatially_implicit.rs +++ b/necsim/impls/no-std/src/cogs/habitat/spatially_implicit.rs @@ -1,7 +1,7 @@ use core::num::NonZeroU32; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, RngCore, UniformlySampleableHabitat}, + cogs::{Backup, Habitat, MathsCore, Rng, UniformlySampleableHabitat}, landscape::{IndexedLocation, LandscapeExtent, Location}, }; use necsim_core_bond::{OffByOneU32, OffByOneU64}; @@ -128,7 +128,7 @@ impl Habitat for SpatiallyImplicitHabitat { } #[contract_trait] -impl> UniformlySampleableHabitat for SpatiallyImplicitHabitat { +impl> UniformlySampleableHabitat for SpatiallyImplicitHabitat { #[must_use] #[inline] fn sample_habitable_indexed_location(&self, rng: &mut G) -> IndexedLocation { diff --git a/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/mod.rs b/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/mod.rs index e86345216..3604aa8a7 100644 --- a/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/mod.rs +++ b/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/mod.rs @@ -1,14 +1,16 @@ use alloc::boxed::Box; use core::{fmt, num::NonZeroUsize}; -use necsim_core_bond::{ClosedUnitF64, OffByOneU64, OpenClosedUnitF64 as PositiveUnitF64}; + use r#final::Final; +use necsim_core_bond::{ClosedUnitF64, OffByOneU64, OpenClosedUnitF64 as PositiveUnitF64}; + mod opensimplex_noise; use opensimplex_noise::OpenSimplexNoise; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, RngCore, UniformlySampleableHabitat}, + cogs::{Backup, Habitat, MathsCore, Rng, UniformlySampleableHabitat}, landscape::{IndexedLocation, LandscapeExtent, Location}, }; @@ -189,7 +191,7 @@ impl Habitat for WrappingNoiseHabitat { } #[contract_trait] -impl> UniformlySampleableHabitat for WrappingNoiseHabitat { +impl> UniformlySampleableHabitat for WrappingNoiseHabitat { #[must_use] fn sample_habitable_indexed_location(&self, rng: &mut G) -> IndexedLocation { // Rejection sample until a habitable location is found diff --git a/necsim/impls/no-std/src/cogs/rng/rand.rs b/necsim/impls/no-std/src/cogs/rng/rand.rs index 8e979e343..bd09e7755 100644 --- a/necsim/impls/no-std/src/cogs/rng/rand.rs +++ b/necsim/impls/no-std/src/cogs/rng/rand.rs @@ -1,44 +1,34 @@ -use core::{fmt, marker::PhantomData}; +use core::fmt; -use necsim_core::cogs::{Backup, MathsCore, RngCore}; +use necsim_core::cogs::{Backup, RngCore}; use rand_core::{RngCore as RandRngCore, SeedableRng as RandSeedableRng}; use serde::{de::DeserializeOwned, Deserialize, Deserializer, Serialize, Serializer}; #[allow(clippy::module_name_repetitions)] #[derive(Clone, TypeLayout)] -#[layout(free = "M")] #[repr(transparent)] -pub struct RandRng< - M: MathsCore, - G: RandRngCore + RandSeedableRng + Clone + Serialize + DeserializeOwned, -> { +pub struct RandRng { inner: G, - marker: PhantomData, } -impl From - for RandRng +impl From + for RandRng { fn from(inner: G) -> Self { - Self { - inner, - marker: PhantomData::, - } + Self { inner } } } -impl - RandRng -{ +impl RandRng { #[must_use] pub fn into_inner(self) -> G { self.inner } } -impl - fmt::Debug for RandRng +impl fmt::Debug + for RandRng { default fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { struct InnerRng(&'static str); @@ -55,10 +45,8 @@ impl fmt::Debug for RandRng +impl + fmt::Debug for RandRng { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_tuple("RandRng").field(&self.inner).finish() @@ -66,40 +54,34 @@ impl< } #[contract_trait] -impl Backup - for RandRng +impl Backup + for RandRng { unsafe fn backup_unchecked(&self) -> Self { self.clone() } } -impl - Serialize for RandRng +impl Serialize + for RandRng { fn serialize(&self, serializer: S) -> Result { self.inner.serialize(serializer) } } -impl< - 'de, - M: MathsCore, - G: RandRngCore + RandSeedableRng + Clone + Serialize + DeserializeOwned, - > Deserialize<'de> for RandRng +impl<'de, G: RandRngCore + RandSeedableRng + Clone + Serialize + DeserializeOwned> Deserialize<'de> + for RandRng { fn deserialize>(deserializer: D) -> Result { let inner = G::deserialize(deserializer)?; - Ok(Self { - inner, - marker: PhantomData::, - }) + Ok(Self { inner }) } } -impl - RngCore for RandRng +impl RngCore + for RandRng { type Seed = G::Seed; @@ -108,7 +90,6 @@ impl Self { Self { inner: G::from_seed(seed), - marker: PhantomData::, } } diff --git a/necsim/impls/no-std/src/cogs/rng/seahash.rs b/necsim/impls/no-std/src/cogs/rng/seahash.rs index 93cc87ecd..ea316ce72 100644 --- a/necsim/impls/no-std/src/cogs/rng/seahash.rs +++ b/necsim/impls/no-std/src/cogs/rng/seahash.rs @@ -1,30 +1,25 @@ -use core::marker::PhantomData; - -use necsim_core::cogs::{Backup, MathsCore, PrimeableRng, RngCore}; +use necsim_core::cogs::{Backup, PrimeableRng, RngCore}; use serde::{Deserialize, Serialize}; #[allow(clippy::module_name_repetitions, clippy::unsafe_derive_deserialize)] #[derive(Clone, Debug, Serialize, Deserialize, TypeLayout)] #[serde(deny_unknown_fields)] -#[layout(free = "M")] -pub struct SeaHash { +pub struct SeaHash { seed: u64, location: u64, time: u64, offset: u64, - #[serde(skip)] - marker: PhantomData, } #[contract_trait] -impl Backup for SeaHash { +impl Backup for SeaHash { unsafe fn backup_unchecked(&self) -> Self { self.clone() } } -impl RngCore for SeaHash { +impl RngCore for SeaHash { type Seed = [u8; 8]; #[must_use] @@ -37,7 +32,6 @@ impl RngCore for SeaHash { location: 0_u64, time: 0_u64, offset: 0_u64, - marker: PhantomData::, } } @@ -53,7 +47,7 @@ impl RngCore for SeaHash { } } -impl PrimeableRng for SeaHash { +impl PrimeableRng for SeaHash { fn prime_with(&mut self, location_index: u64, time_index: u64) { self.location = location_index; self.time = time_index; diff --git a/necsim/impls/no-std/src/cogs/rng/wyhash.rs b/necsim/impls/no-std/src/cogs/rng/wyhash.rs index c4fdeed68..d1fa184fa 100644 --- a/necsim/impls/no-std/src/cogs/rng/wyhash.rs +++ b/necsim/impls/no-std/src/cogs/rng/wyhash.rs @@ -1,6 +1,4 @@ -use core::marker::PhantomData; - -use necsim_core::cogs::{Backup, MathsCore, PrimeableRng, RngCore}; +use necsim_core::cogs::{Backup, PrimeableRng, RngCore}; use serde::{Deserialize, Serialize}; @@ -13,24 +11,21 @@ const P5: u64 = 0xeb44_acca_b455_d165; #[allow(clippy::module_name_repetitions, clippy::unsafe_derive_deserialize)] #[derive(Clone, Debug, Serialize, Deserialize, TypeLayout)] -#[layout(free = "M")] #[serde(deny_unknown_fields)] #[repr(C)] -pub struct WyHash { +pub struct WyHash { seed: u64, state: u64, - #[serde(skip)] - marker: PhantomData, } #[contract_trait] -impl Backup for WyHash { +impl Backup for WyHash { unsafe fn backup_unchecked(&self) -> Self { self.clone() } } -impl RngCore for WyHash { +impl RngCore for WyHash { type Seed = [u8; 8]; #[must_use] @@ -38,11 +33,7 @@ impl RngCore for WyHash { fn from_seed(seed: Self::Seed) -> Self { let seed = u64::from_le_bytes(seed); - Self { - seed, - state: seed, - marker: PhantomData::, - } + Self { seed, state: seed } } #[must_use] @@ -60,7 +51,7 @@ impl RngCore for WyHash { } } -impl PrimeableRng for WyHash { +impl PrimeableRng for WyHash { #[inline] fn prime_with(&mut self, location_index: u64, time_index: u64) { let location_index = seahash_diffuse(location_index); diff --git a/necsim/impls/no-std/src/lib.rs b/necsim/impls/no-std/src/lib.rs index 8e8c88d8a..fda8c949f 100644 --- a/necsim/impls/no-std/src/lib.rs +++ b/necsim/impls/no-std/src/lib.rs @@ -10,6 +10,7 @@ #![feature(control_flow_enum)] #![feature(negative_impls)] #![feature(impl_trait_in_assoc_type)] +#![feature(associated_type_bounds)] #![allow(incomplete_features)] #![feature(specialization)] diff --git a/necsim/impls/no-std/src/parallelisation/independent/individuals.rs b/necsim/impls/no-std/src/parallelisation/independent/individuals.rs index 93fbe37f0..9498a714c 100644 --- a/necsim/impls/no-std/src/parallelisation/independent/individuals.rs +++ b/necsim/impls/no-std/src/parallelisation/independent/individuals.rs @@ -9,7 +9,8 @@ use necsim_core_bond::NonNegativeF64; use necsim_core::{ cogs::{ - DispersalSampler, Habitat, MathsCore, PrimeableRng, SpeciationProbability, TurnoverRate, + DispersalSampler, Habitat, MathsCore, PrimeableRng, Rng, SpeciationProbability, + TurnoverRate, }, lineage::Lineage, reporter::Reporter, @@ -39,7 +40,7 @@ pub fn simulate< 'p, M: MathsCore, H: Habitat, - G: PrimeableRng, + G: Rng, D: DispersalSampler, T: TurnoverRate, N: SpeciationProbability, diff --git a/necsim/impls/no-std/src/parallelisation/independent/landscape.rs b/necsim/impls/no-std/src/parallelisation/independent/landscape.rs index 75c83085d..ff7d0808a 100644 --- a/necsim/impls/no-std/src/parallelisation/independent/landscape.rs +++ b/necsim/impls/no-std/src/parallelisation/independent/landscape.rs @@ -9,7 +9,8 @@ use necsim_core_bond::NonNegativeF64; use necsim_core::{ cogs::{ - DispersalSampler, Habitat, MathsCore, PrimeableRng, SpeciationProbability, TurnoverRate, + DispersalSampler, Habitat, MathsCore, PrimeableRng, Rng, SpeciationProbability, + TurnoverRate, }, event::DispersalEvent, landscape::IndexedLocation, @@ -44,7 +45,7 @@ pub fn simulate< H: Habitat, C: Decomposition, E: EmigrationChoice, - G: PrimeableRng, + G: Rng, D: DispersalSampler, T: TurnoverRate, N: SpeciationProbability, diff --git a/necsim/impls/no-std/src/parallelisation/independent/monolithic/mod.rs b/necsim/impls/no-std/src/parallelisation/independent/monolithic/mod.rs index b3ac9a64c..e543487a6 100644 --- a/necsim/impls/no-std/src/parallelisation/independent/monolithic/mod.rs +++ b/necsim/impls/no-std/src/parallelisation/independent/monolithic/mod.rs @@ -8,7 +8,8 @@ use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_core::{ cogs::{ - DispersalSampler, Habitat, MathsCore, PrimeableRng, SpeciationProbability, TurnoverRate, + DispersalSampler, Habitat, MathsCore, PrimeableRng, Rng, SpeciationProbability, + TurnoverRate, }, lineage::Lineage, reporter::{boolean::Boolean, Reporter}, @@ -44,7 +45,7 @@ pub fn simulate< 'p, M: MathsCore, H: Habitat, - G: PrimeableRng, + G: Rng, D: DispersalSampler, T: TurnoverRate, N: SpeciationProbability, diff --git a/necsim/impls/no-std/src/parallelisation/monolithic/averaging.rs b/necsim/impls/no-std/src/parallelisation/monolithic/averaging.rs index 187ee4038..b9149241e 100644 --- a/necsim/impls/no-std/src/parallelisation/monolithic/averaging.rs +++ b/necsim/impls/no-std/src/parallelisation/monolithic/averaging.rs @@ -3,7 +3,8 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ ActiveLineageSampler, CoalescenceSampler, DispersalSampler, EventSampler, Habitat, - LocallyCoherentLineageStore, MathsCore, RngCore, SpeciationProbability, TurnoverRate, + LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, + TurnoverRate, }, reporter::Reporter, simulation::Simulation, @@ -26,7 +27,7 @@ pub fn simulate< 'p, M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LocallyCoherentLineageStore, D: DispersalSampler, C: CoalescenceSampler, diff --git a/necsim/impls/no-std/src/parallelisation/monolithic/lockstep.rs b/necsim/impls/no-std/src/parallelisation/monolithic/lockstep.rs index 174c2c358..0fac89dfe 100644 --- a/necsim/impls/no-std/src/parallelisation/monolithic/lockstep.rs +++ b/necsim/impls/no-std/src/parallelisation/monolithic/lockstep.rs @@ -3,7 +3,8 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ ActiveLineageSampler, CoalescenceSampler, DispersalSampler, EventSampler, Habitat, - LocallyCoherentLineageStore, MathsCore, RngCore, SpeciationProbability, TurnoverRate, + LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, + TurnoverRate, }, reporter::{NullReporter, Reporter}, simulation::Simulation, @@ -26,7 +27,7 @@ pub fn simulate< 'p, M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LocallyCoherentLineageStore, D: DispersalSampler, C: CoalescenceSampler, diff --git a/necsim/impls/no-std/src/parallelisation/monolithic/monolithic.rs b/necsim/impls/no-std/src/parallelisation/monolithic/monolithic.rs index 895344836..feffe1fef 100644 --- a/necsim/impls/no-std/src/parallelisation/monolithic/monolithic.rs +++ b/necsim/impls/no-std/src/parallelisation/monolithic/monolithic.rs @@ -3,7 +3,8 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ ActiveLineageSampler, CoalescenceSampler, DispersalSampler, EventSampler, Habitat, - LocallyCoherentLineageStore, MathsCore, RngCore, SpeciationProbability, TurnoverRate, + LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, + TurnoverRate, }, reporter::Reporter, simulation::Simulation, @@ -25,7 +26,7 @@ pub fn simulate< 'p, M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LocallyCoherentLineageStore, D: DispersalSampler, C: CoalescenceSampler, diff --git a/necsim/impls/no-std/src/parallelisation/monolithic/optimistic.rs b/necsim/impls/no-std/src/parallelisation/monolithic/optimistic.rs index bb5109217..553fcb735 100644 --- a/necsim/impls/no-std/src/parallelisation/monolithic/optimistic.rs +++ b/necsim/impls/no-std/src/parallelisation/monolithic/optimistic.rs @@ -4,7 +4,7 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ backup::BackedUp, ActiveLineageSampler, Backup, CoalescenceSampler, DispersalSampler, - EventSampler, Habitat, LocallyCoherentLineageStore, MathsCore, RngCore, + EventSampler, Habitat, LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, }, lineage::MigratingLineage, @@ -31,7 +31,7 @@ pub fn simulate< 'p, M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LocallyCoherentLineageStore, D: DispersalSampler, C: CoalescenceSampler, diff --git a/necsim/impls/no-std/src/parallelisation/monolithic/optimistic_lockstep.rs b/necsim/impls/no-std/src/parallelisation/monolithic/optimistic_lockstep.rs index 767e5cbb9..0930e18f7 100644 --- a/necsim/impls/no-std/src/parallelisation/monolithic/optimistic_lockstep.rs +++ b/necsim/impls/no-std/src/parallelisation/monolithic/optimistic_lockstep.rs @@ -3,7 +3,8 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ ActiveLineageSampler, Backup, CoalescenceSampler, DispersalSampler, EventSampler, Habitat, - LocallyCoherentLineageStore, MathsCore, RngCore, SpeciationProbability, TurnoverRate, + LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, + TurnoverRate, }, reporter::{NullReporter, Reporter}, simulation::Simulation, @@ -26,7 +27,7 @@ pub fn simulate< 'p, M: MathsCore, H: Habitat, - G: RngCore, + G: Rng, S: LocallyCoherentLineageStore, D: DispersalSampler, C: CoalescenceSampler, From ed6085b5c2a3c80bfcb74a5fd313e1b2b1961035 Mon Sep 17 00:00:00 2001 From: Momo Langenstein Date: Wed, 18 May 2022 07:03:31 +0000 Subject: [PATCH 04/42] Some more progress --- .../alias/individual/mod.rs | 16 +- .../alias/individual/sampler.rs | 5 +- .../alias/location/mod.rs | 10 +- .../alias/location/sampler.rs | 4 +- .../alias/sampler/indexed/tests.rs | 12 +- .../alias/sampler/stack/mod.rs | 29 +++- .../alias/sampler/stack/tests.rs | 139 ++++++++++++++++-- .../active_lineage_sampler/classical/mod.rs | 14 +- .../classical/sampler.rs | 15 +- .../independent/event_time_sampler/const.rs | 2 +- .../independent/event_time_sampler/exp.rs | 5 +- .../event_time_sampler/geometric.rs | 9 +- .../independent/event_time_sampler/poisson.rs | 23 ++- .../almost_infinite_normal.rs | 29 +++- .../src/cogs/dispersal_sampler/non_spatial.rs | 35 ++++- .../dispersal_sampler/spatially_implicit.rs | 34 ++++- .../cogs/dispersal_sampler/wrapping_noise.rs | 28 +++- .../src/cogs/habitat/wrapping_noise/mod.rs | 4 +- 18 files changed, 338 insertions(+), 75 deletions(-) diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs index f128a9fc8..7a85d9e6c 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs @@ -4,9 +4,10 @@ use core::{fmt, marker::PhantomData}; use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_core::cogs::{ - rng::Exponential, Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, - EmigrationExit, EventSampler, Habitat, ImmigrationEntry, - LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, + rng::{Exponential, IndexU128, IndexU64, IndexUsize}, + Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, EmigrationExit, + EventSampler, Habitat, ImmigrationEntry, LocallyCoherentLineageStore, + MathsCore, Rng, SpeciationProbability, TurnoverRate, }; use crate::cogs::{ @@ -56,6 +57,9 @@ impl< > IndividualAliasActiveLineageSampler where G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { #[must_use] pub fn init_with_store<'h, O: TrustedOriginSampler<'h, M, Habitat = H>>( @@ -165,6 +169,9 @@ impl< > fmt::Debug for IndividualAliasActiveLineageSampler where G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("IndividualAliasActiveLineageSampler") @@ -190,6 +197,9 @@ impl< > Backup for IndividualAliasActiveLineageSampler where G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs index b0130ead7..35e0c0028 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs @@ -2,7 +2,7 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ - rng::{Exponential, Lambda}, + rng::{Exponential, IndexU128, IndexU64, IndexUsize, Lambda}, ActiveLineageSampler, CoalescenceSampler, DispersalSampler, DistributionSampler, EmigrationExit, EventSampler, Habitat, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, @@ -32,6 +32,9 @@ impl< for IndividualAliasActiveLineageSampler where G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { type LineageIterator<'a> = impl Iterator where H: 'a, G: 'a, S: 'a, X: 'a, D: 'a, C: 'a, T: 'a, N: 'a, E: 'a, I: 'a; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs index 206db19e6..f2b195cf0 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs @@ -5,7 +5,7 @@ use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_core::{ cogs::{ - rng::{Exponential, IndexUsize}, + rng::{Exponential, IndexU128, IndexU64, IndexUsize}, Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, EmigrationExit, GloballyCoherentLineageStore, Habitat, ImmigrationEntry, MathsCore, Rng, SpeciationProbability, TurnoverRate, @@ -39,6 +39,8 @@ pub struct LocationAliasActiveLineageSampler< > where G::Sampler: DistributionSampler, G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { alias_sampler: DynamicAliasMethodIndexedSampler, number_active_lineages: usize, @@ -63,6 +65,8 @@ impl< where G::Sampler: DistributionSampler, G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { #[must_use] pub fn init_with_store<'h, O: TrustedOriginSampler<'h, M, Habitat = H>>( @@ -220,6 +224,8 @@ impl< where G::Sampler: DistributionSampler, G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { f.debug_struct("LocationAliasActiveLineageSampler") @@ -246,6 +252,8 @@ impl< where G::Sampler: DistributionSampler, G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs index cdf70e474..6b8c627f5 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs @@ -2,7 +2,7 @@ use core::{num::NonZeroUsize, ops::ControlFlow}; use necsim_core::{ cogs::{ - rng::{Exponential, IndexUsize, Lambda, Length}, + rng::{Exponential, IndexU128, IndexU64, IndexUsize, Lambda, Length}, ActiveLineageSampler, Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, EmigrationExit, GloballyCoherentLineageStore, Habitat, ImmigrationEntry, MathsCore, Rng, SpeciationProbability, TurnoverRate, @@ -35,6 +35,8 @@ impl< where G::Sampler: DistributionSampler, G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { type LineageIterator<'a> = impl Iterator where H: 'a, G: 'a, S: 'a, X: 'a, D: 'a, C: 'a, T: 'a, N: 'a, E: 'a, I: 'a; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs index 94ecebc74..3e2b341b4 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs @@ -1143,11 +1143,11 @@ impl DistributionSampler usize { let length = params.0; - /*#[allow( + #[allow( clippy::cast_precision_loss, clippy::cast_possible_truncation, clippy::cast_sign_loss - )]*/ + )] let index = IntrinsicsMathsCore::floor(rng.sample_f64() * (length.get() as f64)) as usize; // Safety in case of f64 rounding errors @@ -1172,11 +1172,11 @@ impl DistributionSampler u64 { let length = params.0; - /*#[allow( + #[allow( clippy::cast_precision_loss, clippy::cast_possible_truncation, clippy::cast_sign_loss - )]*/ + )] let index = IntrinsicsMathsCore::floor(rng.sample_f64() * (length.get() as f64)) as u64; // Safety in case of f64 rounding errors @@ -1201,11 +1201,11 @@ impl DistributionSampler u128 { let length = params.0; - /*#[allow( + #[allow( clippy::cast_precision_loss, clippy::cast_possible_truncation, clippy::cast_sign_loss - )]*/ + )] let index = IntrinsicsMathsCore::floor(rng.sample_f64() * (length.get() as f64)) as u128; // Safety in case of f64 rounding errors diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs index 48c4e3f23..bc3ecb692 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs @@ -7,7 +7,10 @@ use core::{ num::{NonZeroU128, NonZeroU64, NonZeroUsize}, }; -use necsim_core::cogs::{Backup, MathsCore, Rng, RngCore}; +use necsim_core::cogs::{ + rng::{IndexU128, IndexU64, IndexUsize, Length}, + Backup, DistributionSampler, MathsCore, Rng, +}; use necsim_core_bond::{NonNegativeF64, PositiveF64}; #[cfg(test)] @@ -45,7 +48,10 @@ impl RejectionSamplingGroup { unsafe fn sample_pop_inplace>( &mut self, rng: &mut G, - ) -> (Option<&mut Self>, E) { + ) -> (Option<&mut Self>, E) + where + G::Sampler: DistributionSampler, + { if let [_event] = &self.events[..] { // Safety: If there is only one event, the pop must succeed return (None, self.events.pop().unwrap_unchecked()); @@ -53,7 +59,8 @@ impl RejectionSamplingGroup { loop { // Safety: By construction, the group never contains zero elements - let index = rng.sample_index(NonZeroUsize::new_unchecked(self.weights.len())); + let index = rng + .sample_with::(Length(NonZeroUsize::new_unchecked(self.weights.len()))); let height = rng.sample_u64() >> 11; // 53rd bit of weight is always 1, so sampling chance >= 50% @@ -70,7 +77,10 @@ impl RejectionSamplingGroup { } #[cfg(test)] - fn sample_pop>(mut self, rng: &mut G) -> (Option, E) { + fn sample_pop>(mut self, rng: &mut G) -> (Option, E) + where + G::Sampler: DistributionSampler, + { match unsafe { self.sample_pop_inplace(rng) } { (Some(_), event) => (Some(self), event), (None, event) => (None, event), @@ -121,14 +131,19 @@ impl DynamicAliasMethodStackSampler { self.groups.iter().flat_map(RejectionSamplingGroup::iter) } - pub fn sample_pop>(&mut self, rng: &mut G) -> Option { + pub fn sample_pop>(&mut self, rng: &mut G) -> Option + where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, + { if let Some(total_weight) = NonZeroU128::new(self.total_weight) { let cdf_sample = if let [_group] = &self.groups[..] { 0_u128 } else if let Ok(total_weight) = NonZeroU64::try_from(total_weight) { - u128::from(rng.sample_index_u64(total_weight)) + u128::from(rng.sample_with::(Length(total_weight))) } else { - rng.sample_index_u128(total_weight) + rng.sample_with::(Length(total_weight)) }; let mut cdf_acc = 0_u128; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs index 9cc9b547c..5fb69cc0d 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs @@ -1,7 +1,13 @@ +use core::num::{NonZeroU128, NonZeroU64, NonZeroUsize}; + use alloc::{vec, vec::Vec}; -use necsim_core::cogs::{Backup, RngCore, SeedableRng}; +use necsim_core::cogs::{ + rng::{IndexU128, IndexU64, IndexUsize, Length, SimpleRng}, + Backup, Distribution, DistributionSampler, Rng, RngCore, SeedableRng, +}; use necsim_core_bond::{NonNegativeF64, PositiveF64}; +use necsim_core_maths::MathsCore; use crate::cogs::{maths::intrinsics::IntrinsicsMathsCore, rng::wyhash::WyHash}; @@ -96,7 +102,7 @@ fn sample_single_group() { let mut tally = [0_u64; 6]; - let mut rng = WyHash::::seed_from_u64(24897); + let mut rng = SimpleRng::::seed_from_u64(24897); for _ in 0..N { let (maybe_group, sample) = group.sample_pop(&mut rng); @@ -396,7 +402,7 @@ fn add_remove_event_full() { fn sample_single_group_full() { const N: usize = 10_000_000; - let mut rng = WyHash::::seed_from_u64(471_093); + let mut rng = SimpleRng::::seed_from_u64(471_093); let mut sampler = DynamicAliasMethodStackSampler::with_capacity(6); @@ -445,7 +451,7 @@ fn sample_single_group_full() { fn sample_three_groups_full() { const N: usize = 10_000_000; - let mut rng = WyHash::::seed_from_u64(739_139); + let mut rng = SimpleRng::::seed_from_u64(739_139); let mut sampler = DynamicAliasMethodStackSampler::with_capacity(6); @@ -491,7 +497,7 @@ fn sample_three_groups_full() { fn sample_three_groups_full_reverse() { const N: usize = 10_000_000; - let mut rng = WyHash::::seed_from_u64(248_971); + let mut rng = SimpleRng::::seed_from_u64(248_971); let mut sampler = DynamicAliasMethodStackSampler::with_capacity(6); @@ -570,18 +576,17 @@ fn debug_display_sampler() { // GRCOV_EXCL_START #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -struct DummyRng(Vec); +struct DummyRng(Vec); impl DummyRng { fn new(mut vec: Vec) -> Self { vec.reverse(); - #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] - Self( - vec.into_iter() - .map(|u01| ((u01 / f64::from_bits(0x3CA0_0000_0000_0000_u64)) as u64) << 11) - .collect(), - ) + Self(vec) + } + + fn sample_f64(&mut self) -> f64 { + self.0.pop().unwrap() } } @@ -595,7 +600,115 @@ impl RngCore for DummyRng { #[must_use] fn sample_u64(&mut self) -> u64 { - self.0.pop().unwrap() + // #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + ((self.sample_f64() / f64::from_bits(0x3CA0_0000_0000_0000_u64)) as u64) << 11 + } +} + +impl Rng for DummyRng { + type Generator = Self; + type Sampler = DummyDistributionSamplers; + + fn generator(&mut self) -> &mut Self::Generator { + self + } + + fn sample_with(&mut self, params: D::Parameters) -> D::Sample + where + Self::Sampler: DistributionSampler, + { + let samplers = DummyDistributionSamplers; + + samplers.sample_with(self, &samplers, params) + } +} + +struct DummyDistributionSamplers; + +impl DistributionSampler + for DummyDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with( + &self, + rng: &mut DummyRng, + samplers: &DummyDistributionSamplers, + params: Length, + ) -> usize { + let length = params.0; + + #[allow( + clippy::cast_precision_loss, + clippy::cast_possible_truncation, + clippy::cast_sign_loss + )] + let index = IntrinsicsMathsCore::floor(rng.sample_f64() * (length.get() as f64)) as usize; + + // Safety in case of f64 rounding errors + index.min(length.get() - 1) + } +} + +impl DistributionSampler + for DummyDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with( + &self, + rng: &mut DummyRng, + samplers: &DummyDistributionSamplers, + params: Length, + ) -> u64 { + let length = params.0; + + #[allow( + clippy::cast_precision_loss, + clippy::cast_possible_truncation, + clippy::cast_sign_loss + )] + let index = IntrinsicsMathsCore::floor(rng.sample_f64() * (length.get() as f64)) as u64; + + // Safety in case of f64 rounding errors + index.min(length.get() - 1) + } +} + +impl DistributionSampler + for DummyDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with( + &self, + rng: &mut DummyRng, + samplers: &DummyDistributionSamplers, + params: Length, + ) -> u128 { + let length = params.0; + + #[allow( + clippy::cast_precision_loss, + clippy::cast_possible_truncation, + clippy::cast_sign_loss + )] + let index = IntrinsicsMathsCore::floor(rng.sample_f64() * (length.get() as f64)) as u128; + + // Safety in case of f64 rounding errors + index.min(length.get() - 1) } } // GRCOV_EXCL_STOP diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs index b1e89e4f7..721b46387 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs @@ -2,7 +2,8 @@ use alloc::vec::Vec; use core::marker::PhantomData; use necsim_core::cogs::{ - Backup, DispersalSampler, EmigrationExit, Habitat, ImmigrationEntry, + rng::{Exponential, IndexUsize}, + Backup, DispersalSampler, DistributionSampler, EmigrationExit, Habitat, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, }; use necsim_core_bond::NonNegativeF64; @@ -25,7 +26,10 @@ pub struct ClassicalActiveLineageSampler< D: DispersalSampler, N: SpeciationProbability, I: ImmigrationEntry, -> { +> where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, +{ active_lineage_references: Vec, last_event_time: NonNegativeF64, #[allow(clippy::type_complexity)] @@ -42,6 +46,9 @@ impl< N: SpeciationProbability, I: ImmigrationEntry, > ClassicalActiveLineageSampler +where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { #[must_use] pub fn init_with_store<'h, O: TrustedOriginSampler<'h, M, Habitat = H>>( @@ -133,6 +140,9 @@ impl< N: SpeciationProbability, I: ImmigrationEntry, > Backup for ClassicalActiveLineageSampler +where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs index 3e1ec7f1a..75364840a 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs @@ -5,8 +5,10 @@ use core::{ use necsim_core::{ cogs::{ - ActiveLineageSampler, DispersalSampler, EmigrationExit, Habitat, ImmigrationEntry, - LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, + rng::{Exponential, IndexUsize, Lambda, Length}, + ActiveLineageSampler, DispersalSampler, DistributionSampler, EmigrationExit, Habitat, + ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, + SpeciationProbability, }, lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation, @@ -55,6 +57,9 @@ impl< >, I, > for ClassicalActiveLineageSampler +where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { type LineageIterator<'a> = impl Iterator where H: 'a, G: 'a, S: 'a, X: 'a, D: 'a, N: 'a, I: 'a; @@ -111,7 +116,7 @@ impl< let lambda = simulation.turnover_rate.get_uniform_turnover_rate() * PositiveF64::from(number_active_lineages); - let event_time = self.last_event_time + rng.sample_exponential(lambda); + let event_time = self.last_event_time + rng.sample_with::(Lambda(lambda)); let next_event_time = PositiveF64::max_after(self.last_event_time, event_time); @@ -123,9 +128,9 @@ impl< // Safety: The outer if statement has already shown that the number // of remaining lineages is non-zero - let chosen_lineage_index = rng.sample_index(unsafe { + let chosen_lineage_index = rng.sample_with::(Length(unsafe { NonZeroUsize::new_unchecked(self.active_lineage_references.len()) - }); + })); let chosen_lineage_reference = self .active_lineage_references .swap_remove(chosen_lineage_index); diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/const.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/const.rs index c8f230dc9..312603e7d 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/const.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/const.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{Habitat, MathsCore, PrimeableRng, Rng, TurnoverRate}, + cogs::{Habitat, HabitatPrimeableRng, MathsCore, PrimeableRng, Rng, TurnoverRate}, landscape::IndexedLocation, }; use necsim_core_bond::{NonNegativeF64, PositiveF64}; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs index 73c36935d..002de74bb 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs @@ -1,7 +1,8 @@ use necsim_core::{ cogs::{ rng::{Exponential, Lambda}, - Habitat, HabitatPrimeableRng, MathsCore, PrimeableRng, Rng, TurnoverRate, + DistributionSampler, Habitat, HabitatPrimeableRng, MathsCore, PrimeableRng, Rng, + TurnoverRate, }, landscape::IndexedLocation, }; @@ -29,6 +30,8 @@ impl ExpEventTimeSampler { #[contract_trait] impl, G: Rng, T: TurnoverRate> EventTimeSampler for ExpEventTimeSampler +where + G::Sampler: DistributionSampler, { #[inline] fn next_event_time_at_indexed_location_weakly_after( diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs index 3f6c8b0bf..e7e635446 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs @@ -1,5 +1,8 @@ use necsim_core::{ - cogs::{Habitat, HabitatPrimeableRng, MathsCore, PrimeableRng, Rng, TurnoverRate}, + cogs::{ + rng::Event, DistributionSampler, Habitat, HabitatPrimeableRng, MathsCore, PrimeableRng, + Rng, TurnoverRate, + }, landscape::IndexedLocation, }; use necsim_core_bond::{NonNegativeF64, PositiveF64}; @@ -23,6 +26,8 @@ impl GeometricEventTimeSampler { #[contract_trait] impl, G: Rng, T: TurnoverRate> EventTimeSampler for GeometricEventTimeSampler +where + G::Sampler: DistributionSampler, { #[inline] fn next_event_time_at_indexed_location_weakly_after( @@ -47,7 +52,7 @@ impl, G: Rng, T: Turnove rng.generator() .prime_with_habitat(habitat, indexed_location, time_step); - if rng.sample_event(event_probability_per_step) { + if rng.sample_with::(event_probability_per_step) { break; } diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs index 381362042..cafdbe373 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs @@ -1,5 +1,9 @@ use necsim_core::{ - cogs::{Habitat, HabitatPrimeableRng, MathsCore, PrimeableRng, Rng, TurnoverRate}, + cogs::{ + rng::{Normal, Normal2D, UniformClosedOpenUnit}, + DistributionSampler, Habitat, HabitatPrimeableRng, MathsCore, PrimeableRng, Rng, + TurnoverRate, + }, landscape::IndexedLocation, }; use necsim_core_bond::{NonNegativeF64, PositiveF64}; @@ -26,6 +30,9 @@ impl PoissonEventTimeSampler { #[contract_trait] impl, G: Rng, T: TurnoverRate> EventTimeSampler for PoissonEventTimeSampler +where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { #[inline] fn next_event_time_at_indexed_location_weakly_after( @@ -46,7 +53,8 @@ impl, G: Rng, T: Turnove let mut time_step = M::floor(time.get() / self.delta_t.get()) as u64; let (event_time, event_index) = loop { - rng.prime_with_habitat(habitat, indexed_location, time_step); + rng.generator() + .prime_with_habitat(habitat, indexed_location, time_step); let number_events_at_time_steps = if no_event_probability_per_step > 0.0_f64 { // https://en.wikipedia.org/wiki/Poisson_distribution#cite_ref-Devroye1986_54-0 @@ -54,7 +62,7 @@ impl, G: Rng, T: Turnove let mut prod = no_event_probability_per_step; let mut acc = no_event_probability_per_step; - let u = rng.sample_uniform_closed_open(); + let u = rng.sample::(); while u > acc && prod > 0.0_f64 { poisson += 1; @@ -67,7 +75,10 @@ impl, G: Rng, T: Turnove // Fallback in case no_event_probability_per_step underflows #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] let normal_as_poisson = rng - .sample_2d_normal(lambda_per_step.get(), lambda_per_step.sqrt::()) + .sample_with::(Normal { + mu: lambda_per_step.get(), + sigma: lambda_per_step.sqrt::(), + }) .0 .max(0.0_f64) as u32; @@ -79,7 +90,7 @@ impl, G: Rng, T: Turnove for event_index in 0..number_events_at_time_steps { #[allow(clippy::cast_precision_loss)] let event_time = (NonNegativeF64::from(time_step) - + NonNegativeF64::from(rng.sample_uniform_closed_open())) + + NonNegativeF64::from(rng.sample::())) * self.delta_t; if event_time > time { @@ -99,7 +110,7 @@ impl, G: Rng, T: Turnove } }; - rng.prime_with_habitat( + rng.generator().prime_with_habitat( habitat, indexed_location, time_step + INV_PHI.wrapping_mul(u64::from(event_index + 1)), diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs index 8100b5656..cb1242313 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs @@ -1,7 +1,10 @@ use core::marker::PhantomData; use necsim_core::{ - cogs::{Backup, DispersalSampler, MathsCore, Rng, SeparableDispersalSampler}, + cogs::{ + rng::{Normal, Normal2D}, + Backup, DispersalSampler, DistributionSampler, MathsCore, Rng, SeparableDispersalSampler, + }, landscape::Location, }; use necsim_core_bond::{ClosedUnitF64, NonNegativeF64}; @@ -12,13 +15,19 @@ use crate::cogs::habitat::almost_infinite::AlmostInfiniteHabitat; #[derive(Debug)] #[cfg_attr(feature = "cuda", derive(rust_cuda::common::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M", free = "G"))] -pub struct AlmostInfiniteNormalDispersalSampler> { +pub struct AlmostInfiniteNormalDispersalSampler> +where + G::Sampler: DistributionSampler, +{ sigma: NonNegativeF64, self_dispersal: ClosedUnitF64, marker: PhantomData<(M, G)>, } -impl> AlmostInfiniteNormalDispersalSampler { +impl> AlmostInfiniteNormalDispersalSampler +where + G::Sampler: DistributionSampler, +{ #[must_use] pub fn new(sigma: NonNegativeF64) -> Self { let self_dispersal_1d = if sigma > 0.0_f64 { @@ -40,7 +49,10 @@ impl> AlmostInfiniteNormalDispersalSampler { } #[contract_trait] -impl> Backup for AlmostInfiniteNormalDispersalSampler { +impl> Backup for AlmostInfiniteNormalDispersalSampler +where + G::Sampler: DistributionSampler, +{ unsafe fn backup_unchecked(&self) -> Self { Self { sigma: self.sigma, @@ -53,6 +65,8 @@ impl> Backup for AlmostInfiniteNormalDispersalSampler> DispersalSampler, G> for AlmostInfiniteNormalDispersalSampler +where + G::Sampler: DistributionSampler, { #[must_use] fn sample_dispersal_from_location( @@ -63,7 +77,10 @@ impl> DispersalSampler, G> ) -> Location { const WRAP: i64 = 1 << 32; - let (dx, dy): (f64, f64) = rng.sample_2d_normal(0.0_f64, self.sigma); + let (dx, dy): (f64, f64) = rng.sample_with::(Normal { + mu: 0.0_f64, + sigma: self.sigma, + }); // Discrete dispersal assumes lineage positions are centred on (0.5, 0.5), // i.e. |dispersal| >= 0.5 changes the cell @@ -85,6 +102,8 @@ impl> DispersalSampler, G> #[contract_trait] impl> SeparableDispersalSampler, G> for AlmostInfiniteNormalDispersalSampler +where + G::Sampler: DistributionSampler, { #[must_use] fn sample_non_self_dispersal_from_location( diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/non_spatial.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/non_spatial.rs index 929521c05..7be0ddfd3 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/non_spatial.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/non_spatial.rs @@ -1,7 +1,11 @@ use core::{marker::PhantomData, num::NonZeroU64}; use necsim_core::{ - cogs::{Backup, DispersalSampler, Habitat, MathsCore, Rng, SeparableDispersalSampler}, + cogs::{ + rng::{IndexU64, Length}, + Backup, DispersalSampler, DistributionSampler, Habitat, MathsCore, Rng, + SeparableDispersalSampler, + }, landscape::Location, }; use necsim_core_bond::ClosedUnitF64; @@ -12,11 +16,17 @@ use crate::cogs::habitat::non_spatial::NonSpatialHabitat; #[derive(Debug)] #[cfg_attr(feature = "cuda", derive(rust_cuda::common::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M", free = "G"))] -pub struct NonSpatialDispersalSampler> { +pub struct NonSpatialDispersalSampler> +where + G::Sampler: DistributionSampler, +{ marker: PhantomData<(M, G)>, } -impl> Default for NonSpatialDispersalSampler { +impl> Default for NonSpatialDispersalSampler +where + G::Sampler: DistributionSampler, +{ #[must_use] fn default() -> Self { Self { @@ -26,7 +36,10 @@ impl> Default for NonSpatialDispersalSampler { } #[contract_trait] -impl> Backup for NonSpatialDispersalSampler { +impl> Backup for NonSpatialDispersalSampler +where + G::Sampler: DistributionSampler, +{ unsafe fn backup_unchecked(&self) -> Self { Self { marker: PhantomData::<(M, G)>, @@ -37,6 +50,8 @@ impl> Backup for NonSpatialDispersalSampler { #[contract_trait] impl> DispersalSampler, G> for NonSpatialDispersalSampler +where + G::Sampler: DistributionSampler, { #[must_use] #[inline] @@ -50,8 +65,9 @@ impl> DispersalSampler, G> habitat.get_extent().width().get() * habitat.get_extent().height().get(); // Safety: habitat width and height are both > 0 - let dispersal_target_index = - rng.sample_index_u64(unsafe { NonZeroU64::new_unchecked(habitat_index_max) }); + let dispersal_target_index = rng.sample_with::(Length(unsafe { + NonZeroU64::new_unchecked(habitat_index_max) + })); #[allow(clippy::cast_possible_truncation)] Location::new( @@ -70,6 +86,8 @@ impl> DispersalSampler, G> #[contract_trait] impl> SeparableDispersalSampler, G> for NonSpatialDispersalSampler +where + G::Sampler: DistributionSampler, { #[must_use] #[debug_requires(( @@ -88,8 +106,9 @@ impl> SeparableDispersalSampler, let dispersal_target_index = { // Safety: by PRE, `habitat_index_max` > 1 - let dispersal_target_index = - rng.sample_index_u64(unsafe { NonZeroU64::new_unchecked(habitat_index_max - 1) }); + let dispersal_target_index = rng.sample_with::(Length(unsafe { + NonZeroU64::new_unchecked(habitat_index_max - 1) + })); if dispersal_target_index >= current_location_index { dispersal_target_index + 1 diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs index 3451bc9bb..6f20be60a 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs @@ -1,5 +1,9 @@ use necsim_core::{ - cogs::{Backup, DispersalSampler, Habitat, MathsCore, Rng, SeparableDispersalSampler}, + cogs::{ + rng::{Event, IndexU64}, + Backup, DispersalSampler, DistributionSampler, Habitat, MathsCore, Rng, + SeparableDispersalSampler, + }, landscape::Location, }; use necsim_core_bond::{ClosedUnitF64, OpenClosedUnitF64 as PositiveUnitF64}; @@ -13,7 +17,11 @@ use crate::cogs::{ #[derive(Debug)] #[cfg_attr(feature = "cuda", derive(rust_cuda::common::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M"))] -pub struct SpatiallyImplicitDispersalSampler> { +pub struct SpatiallyImplicitDispersalSampler> +where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, +{ #[cfg_attr(feature = "cuda", cuda(embed))] local: NonSpatialDispersalSampler, #[cfg_attr(feature = "cuda", cuda(embed))] @@ -21,7 +29,11 @@ pub struct SpatiallyImplicitDispersalSampler> { local_migration_probability_per_generation: PositiveUnitF64, } -impl> SpatiallyImplicitDispersalSampler { +impl> SpatiallyImplicitDispersalSampler +where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, +{ #[must_use] pub fn new(local_migration_probability_per_generation: PositiveUnitF64) -> Self { Self { @@ -33,7 +45,11 @@ impl> SpatiallyImplicitDispersalSampler { } #[contract_trait] -impl> Backup for SpatiallyImplicitDispersalSampler { +impl> Backup for SpatiallyImplicitDispersalSampler +where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, +{ unsafe fn backup_unchecked(&self) -> Self { Self { local: self.local.backup_unchecked(), @@ -47,6 +63,9 @@ impl> Backup for SpatiallyImplicitDispersalSampler #[contract_trait] impl> DispersalSampler, G> for SpatiallyImplicitDispersalSampler +where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { #[must_use] #[debug_ensures(habitat.meta().get_extent().contains(&ret) || ( @@ -65,7 +84,7 @@ impl> DispersalSampler, G // By PRE, location must be habitable, i.e. either in the local or the meta // habitat if habitat.local().get_extent().contains(location) { - if rng.sample_event(self.local_migration_probability_per_generation.into()) { + if rng.sample_with::(self.local_migration_probability_per_generation.into()) { // Provide a dummpy Location in the meta community to disperse from self.meta.sample_dispersal_from_location( &Location::new( @@ -89,6 +108,9 @@ impl> DispersalSampler, G #[contract_trait] impl> SeparableDispersalSampler, G> for SpatiallyImplicitDispersalSampler +where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { #[must_use] #[debug_ensures(habitat.meta().get_extent().contains(&ret) || ( @@ -107,7 +129,7 @@ impl> SeparableDispersalSampler(self.local_migration_probability_per_generation.into()) { // Provide a dummpy Location in the meta community to disperse from // As the individual is dispersing to a different community, // we can use standard dispersal in the meta community diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/wrapping_noise.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/wrapping_noise.rs index e423248d3..22c70b7eb 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/wrapping_noise.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/wrapping_noise.rs @@ -1,7 +1,7 @@ use necsim_core::{ cogs::{ Backup, DispersalSampler, Habitat, MathsCore, Rng, - SeparableDispersalSampler, + SeparableDispersalSampler, DistributionSampler, rng::{Normal2D, Event}, }, landscape::Location, }; @@ -16,12 +16,20 @@ use crate::cogs::{ #[derive(Debug)] #[cfg_attr(feature = "cuda", derive(rust_cuda::common::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M"))] -pub struct WrappingNoiseApproximateNormalDispersalSampler> { +pub struct WrappingNoiseApproximateNormalDispersalSampler> +where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, +{ #[cfg_attr(feature = "cuda", cuda(embed))] inner: AlmostInfiniteNormalDispersalSampler, } -impl> WrappingNoiseApproximateNormalDispersalSampler { +impl> WrappingNoiseApproximateNormalDispersalSampler +where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, +{ #[must_use] pub fn new(sigma: NonNegativeF64) -> Self { Self { @@ -31,7 +39,11 @@ impl> WrappingNoiseApproximateNormalDispersalSampler> Backup for WrappingNoiseApproximateNormalDispersalSampler { +impl> Backup for WrappingNoiseApproximateNormalDispersalSampler +where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, +{ unsafe fn backup_unchecked(&self) -> Self { Self { inner: self.inner.backup_unchecked(), @@ -42,6 +54,9 @@ impl> Backup for WrappingNoiseApproximateNormalDispersal #[contract_trait] impl> DispersalSampler, G> for WrappingNoiseApproximateNormalDispersalSampler +where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { #[must_use] #[inline] @@ -56,7 +71,7 @@ impl> DispersalSampler, G> // targets are rejected. // If seperable dispersal is not required, this can be implemented as a // direct rejection sampling loop instead. - if rng.sample_event(self.get_self_dispersal_probability_at_location(location, habitat)) { + if rng.sample_with::(self.get_self_dispersal_probability_at_location(location, habitat)) { location.clone() } else { self.sample_non_self_dispersal_from_location(location, habitat, rng) @@ -67,6 +82,9 @@ impl> DispersalSampler, G> #[contract_trait] impl> SeparableDispersalSampler, G> for WrappingNoiseApproximateNormalDispersalSampler +where + G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { #[must_use] fn sample_non_self_dispersal_from_location( diff --git a/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/mod.rs b/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/mod.rs index 3604aa8a7..5d87ec583 100644 --- a/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/mod.rs +++ b/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/mod.rs @@ -10,7 +10,7 @@ mod opensimplex_noise; use opensimplex_noise::OpenSimplexNoise; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, Rng, UniformlySampleableHabitat}, + cogs::{Backup, Habitat, MathsCore, Rng, UniformlySampleableHabitat, RngCore}, landscape::{IndexedLocation, LandscapeExtent, Location}, }; @@ -62,7 +62,7 @@ impl WrappingNoiseHabitat { // Utilise a PRNG to avoid sampling degeneracies for finding the // threshold which would poison the entire sampler - let mut rng: WyHash = WyHash::from_seed(seed.to_le_bytes()); + let mut rng = WyHash::from_seed(seed.to_le_bytes()); for _ in 0..(1_usize << 16) { let location = rng.sample_u64(); From d8f8c535153082c2da7c0932ac0a9cbc3fec4ab4 Mon Sep 17 00:00:00 2001 From: Momo Langenstein Date: Wed, 18 May 2022 08:13:50 +0000 Subject: [PATCH 05/42] Finished refactoring of necsim-impls --- necsim/impls/no-std/src/alias/mod.rs | 4 +- necsim/impls/no-std/src/alias/packed.rs | 4 +- .../alias/individual/mod.rs | 28 +++++++------- .../alias/individual/sampler.rs | 12 +++--- .../alias/location/mod.rs | 32 ++++++++-------- .../alias/location/sampler.rs | 12 +++--- .../alias/sampler/indexed/mod.rs | 6 +-- .../alias/sampler/indexed/tests.rs | 12 +++--- .../alias/sampler/stack/mod.rs | 6 +-- .../alias/sampler/stack/tests.rs | 12 +++--- .../active_lineage_sampler/classical/mod.rs | 20 ++++++---- .../classical/sampler.rs | 11 +++--- .../independent/event_time_sampler/poisson.rs | 4 +- .../active_lineage_sampler/independent/mod.rs | 12 ++++-- .../independent/sampler.rs | 6 ++- .../independent/singular.rs | 6 ++- .../resuming/sampler.rs | 4 +- .../cogs/active_lineage_sampler/singular.rs | 4 +- .../in_memory/alias/dispersal.rs | 8 +++- .../dispersal_sampler/in_memory/alias/mod.rs | 20 ++++++++-- .../in_memory/cumulative/contract.rs | 12 +++--- .../in_memory/cumulative/dispersal.rs | 10 +++-- .../in_memory/cumulative/mod.rs | 21 +++++++++-- .../in_memory/packed_alias/dispersal.rs | 8 +++- .../in_memory/packed_alias/mod.rs | 23 ++++++++++-- .../in_memory/separable_alias/dispersal.rs | 15 +++++++- .../in_memory/separable_alias/mod.rs | 17 ++++++++- .../dispersal_sampler/spatially_implicit.rs | 20 +++++----- .../no-std/src/cogs/emigration_exit/domain.rs | 37 +++++++++++++------ .../cogs/emigration_exit/independent/mod.rs | 32 ++++++++++------ .../no-std/src/cogs/emigration_exit/never.rs | 8 +--- .../gillespie/conditional/mod.rs | 22 ++++++++--- .../gillespie/conditional/probability.rs | 4 +- .../src/cogs/event_sampler/gillespie/mod.rs | 4 +- .../event_sampler/gillespie/unconditional.rs | 29 ++++++++++++--- .../src/cogs/event_sampler/independent.rs | 21 ++++++++--- .../no-std/src/cogs/event_sampler/tracking.rs | 4 +- .../src/cogs/event_sampler/unconditional.rs | 24 +++++++++--- .../no-std/src/cogs/habitat/in_memory.rs | 13 +++++-- .../no-std/src/cogs/habitat/non_spatial.rs | 15 ++++++-- .../src/cogs/habitat/spatially_implicit.rs | 10 ++++- .../independent/individuals.rs | 9 +++-- .../parallelisation/independent/landscape.rs | 17 +++++---- .../independent/monolithic/mod.rs | 9 +++-- .../parallelisation/monolithic/averaging.rs | 17 +++++---- .../parallelisation/monolithic/lockstep.rs | 17 +++++---- .../parallelisation/monolithic/monolithic.rs | 3 +- .../parallelisation/monolithic/optimistic.rs | 17 +++++---- .../monolithic/optimistic_lockstep.rs | 17 +++++---- .../cogs/dispersal_sampler/in_memory/mod.rs | 6 +-- necsim/impls/std/src/cogs/rng/pcg.rs | 27 +++++--------- 51 files changed, 460 insertions(+), 251 deletions(-) diff --git a/necsim/impls/no-std/src/alias/mod.rs b/necsim/impls/no-std/src/alias/mod.rs index f916d83d8..cbabed87c 100644 --- a/necsim/impls/no-std/src/alias/mod.rs +++ b/necsim/impls/no-std/src/alias/mod.rs @@ -96,8 +96,8 @@ impl AliasMethodSampler { #[debug_ensures(self.Es.contains(&ret), "returns one of the weighted events")] pub fn sample_event>(&self, rng: &mut G) -> E where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler, { // Safety: Es is non-empty by the precondition on construction let length = unsafe { NonZeroUsize::new_unchecked(self.Es.len()) }; diff --git a/necsim/impls/no-std/src/alias/packed.rs b/necsim/impls/no-std/src/alias/packed.rs index bca820be3..fcc0aab9a 100644 --- a/necsim/impls/no-std/src/alias/packed.rs +++ b/necsim/impls/no-std/src/alias/packed.rs @@ -116,8 +116,8 @@ impl AliasMethodSamplerAtom { rng: &mut G, ) -> E where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler, { // Safety: alias_samplers is non-empty by the precondition let length = unsafe { NonZeroUsize::new_unchecked(alias_samplers.len()) }; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs index 7a85d9e6c..490784d5c 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs @@ -6,8 +6,8 @@ use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_core::cogs::{ rng::{Exponential, IndexU128, IndexU64, IndexUsize}, Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, EmigrationExit, - EventSampler, Habitat, ImmigrationEntry, LocallyCoherentLineageStore, - MathsCore, Rng, SpeciationProbability, TurnoverRate, + EventSampler, Habitat, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, + SpeciationProbability, TurnoverRate, }; use crate::cogs::{ @@ -56,10 +56,10 @@ impl< I: ImmigrationEntry, > IndividualAliasActiveLineageSampler where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { #[must_use] pub fn init_with_store<'h, O: TrustedOriginSampler<'h, M, Habitat = H>>( @@ -168,10 +168,10 @@ impl< I: ImmigrationEntry, > fmt::Debug for IndividualAliasActiveLineageSampler where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("IndividualAliasActiveLineageSampler") @@ -196,10 +196,10 @@ impl< I: ImmigrationEntry, > Backup for IndividualAliasActiveLineageSampler where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs index 35e0c0028..cf56e5058 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs @@ -4,8 +4,8 @@ use necsim_core::{ cogs::{ rng::{Exponential, IndexU128, IndexU64, IndexUsize, Lambda}, ActiveLineageSampler, CoalescenceSampler, DispersalSampler, DistributionSampler, - EmigrationExit, EventSampler, Habitat, ImmigrationEntry, - LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, + EmigrationExit, EventSampler, Habitat, ImmigrationEntry, LocallyCoherentLineageStore, + MathsCore, Rng, SpeciationProbability, TurnoverRate, }, lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation, @@ -31,10 +31,10 @@ impl< > ActiveLineageSampler for IndividualAliasActiveLineageSampler where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { type LineageIterator<'a> = impl Iterator where H: 'a, G: 'a, S: 'a, X: 'a, D: 'a, C: 'a, T: 'a, N: 'a, E: 'a, I: 'a; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs index f2b195cf0..34ed04bd0 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs @@ -37,10 +37,10 @@ pub struct LocationAliasActiveLineageSampler< E: GillespieEventSampler, I: ImmigrationEntry, > where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { alias_sampler: DynamicAliasMethodIndexedSampler, number_active_lineages: usize, @@ -63,10 +63,10 @@ impl< I: ImmigrationEntry, > LocationAliasActiveLineageSampler where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { #[must_use] pub fn init_with_store<'h, O: TrustedOriginSampler<'h, M, Habitat = H>>( @@ -222,10 +222,10 @@ impl< I: ImmigrationEntry, > core::fmt::Debug for LocationAliasActiveLineageSampler where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { f.debug_struct("LocationAliasActiveLineageSampler") @@ -250,10 +250,10 @@ impl< I: ImmigrationEntry, > Backup for LocationAliasActiveLineageSampler where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs index 6b8c627f5..ca1717dad 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs @@ -4,8 +4,8 @@ use necsim_core::{ cogs::{ rng::{Exponential, IndexU128, IndexU64, IndexUsize, Lambda, Length}, ActiveLineageSampler, Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, - EmigrationExit, GloballyCoherentLineageStore, Habitat, ImmigrationEntry, - MathsCore, Rng, SpeciationProbability, TurnoverRate, + EmigrationExit, GloballyCoherentLineageStore, Habitat, ImmigrationEntry, MathsCore, Rng, + SpeciationProbability, TurnoverRate, }, lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation, @@ -33,10 +33,10 @@ impl< > ActiveLineageSampler for LocationAliasActiveLineageSampler where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { type LineageIterator<'a> = impl Iterator where H: 'a, G: 'a, S: 'a, X: 'a, D: 'a, C: 'a, T: 'a, N: 'a, E: 'a, I: 'a; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs index 3eacfaafc..6c5416b89 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs @@ -199,9 +199,9 @@ impl DynamicAliasMethodIndexedSampler { pub fn sample_pop>(&mut self, rng: &mut G) -> Option where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler, { if let Some(total_weight) = NonZeroU128::new(self.total_weight) { let cdf_sample = if let [_group] = &self.groups[..] { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs index 3e2b341b4..c866a6886 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs @@ -1101,8 +1101,10 @@ impl RngCore for DummyRng { #[must_use] fn sample_u64(&mut self) -> u64 { - // #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] - ((self.sample_f64() / f64::from_bits(0x3CA0_0000_0000_0000_u64)) as u64) << 11 + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + { + ((self.sample_f64() / f64::from_bits(0x3CA0_0000_0000_0000_u64)) as u64) << 11 + } } } @@ -1138,7 +1140,7 @@ impl DistributionSampler, ) -> usize { let length = params.0; @@ -1167,7 +1169,7 @@ impl DistributionSampler, ) -> u64 { let length = params.0; @@ -1196,7 +1198,7 @@ impl DistributionSampler, ) -> u128 { let length = params.0; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs index bc3ecb692..5ce8675bb 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs @@ -133,9 +133,9 @@ impl DynamicAliasMethodStackSampler { pub fn sample_pop>(&mut self, rng: &mut G) -> Option where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler, { if let Some(total_weight) = NonZeroU128::new(self.total_weight) { let cdf_sample = if let [_group] = &self.groups[..] { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs index 5fb69cc0d..06ff6339c 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs @@ -600,8 +600,10 @@ impl RngCore for DummyRng { #[must_use] fn sample_u64(&mut self) -> u64 { - // #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] - ((self.sample_f64() / f64::from_bits(0x3CA0_0000_0000_0000_u64)) as u64) << 11 + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + { + ((self.sample_f64() / f64::from_bits(0x3CA0_0000_0000_0000_u64)) as u64) << 11 + } } } @@ -637,7 +639,7 @@ impl DistributionSampler, ) -> usize { let length = params.0; @@ -666,7 +668,7 @@ impl DistributionSampler, ) -> u64 { let length = params.0; @@ -695,7 +697,7 @@ impl DistributionSampler, ) -> u128 { let length = params.0; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs index 721b46387..339fa1036 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs @@ -2,7 +2,7 @@ use alloc::vec::Vec; use core::marker::PhantomData; use necsim_core::cogs::{ - rng::{Exponential, IndexUsize}, + rng::{Event, Exponential, IndexUsize, UniformClosedOpenUnit}, Backup, DispersalSampler, DistributionSampler, EmigrationExit, Habitat, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, }; @@ -27,8 +27,10 @@ pub struct ClassicalActiveLineageSampler< N: SpeciationProbability, I: ImmigrationEntry, > where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { active_lineage_references: Vec, last_event_time: NonNegativeF64, @@ -47,8 +49,10 @@ impl< I: ImmigrationEntry, > ClassicalActiveLineageSampler where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { #[must_use] pub fn init_with_store<'h, O: TrustedOriginSampler<'h, M, Habitat = H>>( @@ -141,8 +145,10 @@ impl< I: ImmigrationEntry, > Backup for ClassicalActiveLineageSampler where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs index 75364840a..3512b9ca3 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs @@ -5,10 +5,9 @@ use core::{ use necsim_core::{ cogs::{ - rng::{Exponential, IndexUsize, Lambda, Length}, + rng::{Event, Exponential, IndexUsize, Lambda, Length, UniformClosedOpenUnit}, ActiveLineageSampler, DispersalSampler, DistributionSampler, EmigrationExit, Habitat, - ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, - SpeciationProbability, + ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, }, lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation, @@ -58,8 +57,10 @@ impl< I, > for ClassicalActiveLineageSampler where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { type LineageIterator<'a> = impl Iterator where H: 'a, G: 'a, S: 'a, X: 'a, D: 'a, N: 'a, I: 'a; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs index cafdbe373..0eb959300 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs @@ -31,8 +31,8 @@ impl PoissonEventTimeSampler { impl, G: Rng, T: TurnoverRate> EventTimeSampler for PoissonEventTimeSampler where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler, { #[inline] fn next_event_time_at_indexed_location_weakly_after( diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/mod.rs index ecf692a1d..9642d7979 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/mod.rs @@ -3,8 +3,8 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ - Backup, DispersalSampler, EmigrationExit, Habitat, MathsCore, PrimeableRng, Rng, - SpeciationProbability, TurnoverRate, + rng::UniformClosedOpenUnit, Backup, DispersalSampler, DistributionSampler, EmigrationExit, + Habitat, MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, }, lineage::Lineage, }; @@ -36,7 +36,9 @@ pub struct IndependentActiveLineageSampler< T: TurnoverRate, N: SpeciationProbability, J: EventTimeSampler, -> { +> where + G::Sampler: DistributionSampler, +{ #[cfg_attr( feature = "cuda", cuda(embed = "Option>") @@ -59,6 +61,8 @@ impl< N: SpeciationProbability, J: EventTimeSampler, > IndependentActiveLineageSampler +where + G::Sampler: DistributionSampler, { #[must_use] pub fn init_with_store_and_lineages<'h, O: TrustedOriginSampler<'h, M, Habitat = H>>( @@ -145,6 +149,8 @@ impl< N: SpeciationProbability, J: EventTimeSampler, > Backup for IndependentActiveLineageSampler +where + G::Sampler: DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/sampler.rs index 013b1a994..fb951a52a 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/sampler.rs @@ -2,8 +2,8 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ - ActiveLineageSampler, DispersalSampler, EmigrationExit, Habitat, MathsCore, PrimeableRng, - Rng, SpeciationProbability, TurnoverRate, + rng::UniformClosedOpenUnit, ActiveLineageSampler, DispersalSampler, DistributionSampler, + EmigrationExit, Habitat, MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, }, lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation, @@ -43,6 +43,8 @@ impl< IndependentEventSampler, NeverImmigrationEntry, > for IndependentActiveLineageSampler +where + G::Sampler: DistributionSampler, { type LineageIterator<'a> = impl Iterator where H: 'a, G: 'a, X: 'a, D: 'a, T: 'a, N: 'a, J: 'a; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/singular.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/singular.rs index 95f102ee6..1e197de68 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/singular.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/singular.rs @@ -1,6 +1,6 @@ use necsim_core::cogs::{ - DispersalSampler, EmigrationExit, Habitat, MathsCore, PrimeableRng, Rng, SpeciationProbability, - TurnoverRate, + rng::UniformClosedOpenUnit, DispersalSampler, DistributionSampler, EmigrationExit, Habitat, + MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, }; use necsim_core::lineage::Lineage; @@ -39,6 +39,8 @@ impl< IndependentEventSampler, NeverImmigrationEntry, > for IndependentActiveLineageSampler +where + G::Sampler: DistributionSampler, { #[must_use] #[inline] diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/resuming/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/resuming/sampler.rs index 65d718f77..fe94a105b 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/resuming/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/resuming/sampler.rs @@ -3,8 +3,8 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ ActiveLineageSampler, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, - Habitat, ImmigrationEntry, LineageStore, MathsCore, Rng, - SpeciationProbability, TurnoverRate, + Habitat, ImmigrationEntry, LineageStore, MathsCore, Rng, SpeciationProbability, + TurnoverRate, }, lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/singular.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/singular.rs index fd0526d4d..2cc096afc 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/singular.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/singular.rs @@ -1,8 +1,8 @@ use necsim_core::{ cogs::{ ActiveLineageSampler, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, - Habitat, ImmigrationEntry, LineageStore, MathsCore, Rng, - SpeciationProbability, TurnoverRate, + Habitat, ImmigrationEntry, LineageStore, MathsCore, Rng, SpeciationProbability, + TurnoverRate, }, lineage::Lineage, }; diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/dispersal.rs index 88827eece..302921b3e 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/dispersal.rs @@ -1,5 +1,8 @@ use necsim_core::{ - cogs::{DispersalSampler, Habitat, MathsCore, Rng}, + cogs::{ + rng::{Event, IndexUsize}, + DispersalSampler, DistributionSampler, Habitat, MathsCore, Rng, + }, landscape::Location, }; @@ -8,6 +11,9 @@ use super::InMemoryAliasDispersalSampler; #[contract_trait] impl, G: Rng> DispersalSampler for InMemoryAliasDispersalSampler +where + G::Sampler: DistributionSampler + + DistributionSampler, { #[must_use] fn sample_dispersal_from_location( diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/mod.rs index a4b19842f..87dda5998 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/mod.rs @@ -3,7 +3,10 @@ use core::marker::PhantomData; use alloc::vec::Vec; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, Rng}, + cogs::{ + rng::{Event, IndexUsize}, + Backup, DistributionSampler, Habitat, MathsCore, Rng, + }, landscape::Location, }; use necsim_core_bond::NonNegativeF64; @@ -17,7 +20,11 @@ mod dispersal; #[allow(clippy::module_name_repetitions)] #[derive(Debug)] -pub struct InMemoryAliasDispersalSampler, G: Rng> { +pub struct InMemoryAliasDispersalSampler, G: Rng> +where + G::Sampler: DistributionSampler + + DistributionSampler, +{ alias_dispersal: Array2D>>, marker: PhantomData<(M, H, G)>, } @@ -25,6 +32,9 @@ pub struct InMemoryAliasDispersalSampler, G: Rng> #[contract_trait] impl, G: Rng> InMemoryDispersalSampler for InMemoryAliasDispersalSampler +where + G::Sampler: DistributionSampler + + DistributionSampler, { /// Creates a new `InMemoryAliasDispersalSampler` from the /// `dispersal` map and extent of the habitat map. @@ -77,7 +87,11 @@ impl, G: Rng> InMemoryDispersalSampler } #[contract_trait] -impl, G: Rng> Backup for InMemoryAliasDispersalSampler { +impl, G: Rng> Backup for InMemoryAliasDispersalSampler +where + G::Sampler: DistributionSampler + + DistributionSampler, +{ unsafe fn backup_unchecked(&self) -> Self { Self { alias_dispersal: self.alias_dispersal.clone(), diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/contract.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/contract.rs index 44f099a80..cc0f41401 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/contract.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/contract.rs @@ -1,15 +1,15 @@ use necsim_core::{ - cogs::{Habitat, MathsCore}, + cogs::{rng::UniformClosedOpenUnit, DistributionSampler, Habitat, MathsCore, Rng}, landscape::Location, }; use super::InMemoryCumulativeDispersalSampler; -impl InMemoryCumulativeDispersalSampler { - pub(super) fn explicit_only_valid_targets_dispersal_contract>( - &self, - habitat: &H, - ) -> bool { +impl, G: Rng> InMemoryCumulativeDispersalSampler +where + G::Sampler: DistributionSampler, +{ + pub(super) fn explicit_only_valid_targets_dispersal_contract(&self, habitat: &H) -> bool { let habitat_width = habitat.get_extent().width(); for target_index in self.valid_dispersal_targets.iter().filter_map(|x| *x) { diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/dispersal.rs index 4b34d84c9..9ca1dadec 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/dispersal.rs @@ -1,5 +1,7 @@ use necsim_core::{ - cogs::{DispersalSampler, Habitat, MathsCore, Rng}, + cogs::{ + rng::UniformClosedOpenUnit, DispersalSampler, DistributionSampler, Habitat, MathsCore, Rng, + }, landscape::Location, }; @@ -7,7 +9,9 @@ use super::InMemoryCumulativeDispersalSampler; #[contract_trait] impl, G: Rng> DispersalSampler - for InMemoryCumulativeDispersalSampler + for InMemoryCumulativeDispersalSampler +where + G::Sampler: DistributionSampler, { #[must_use] fn sample_dispersal_from_location( @@ -26,7 +30,7 @@ impl, G: Rng> DispersalSampler let cumulative_dispersals_at_location = &self.cumulative_dispersal [location_index * habitat_area..(location_index + 1) * habitat_area]; - let cumulative_percentage_sample = rng.sample_uniform_closed_open().into(); + let cumulative_percentage_sample = rng.sample::().into(); let dispersal_target_index = usize::min( match cumulative_dispersals_at_location.binary_search(&cumulative_percentage_sample) { diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/mod.rs index fe030a331..7a658eb1b 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/mod.rs @@ -1,7 +1,9 @@ +use core::marker::PhantomData; + use alloc::{boxed::Box, vec}; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, Rng}, + cogs::{rng::UniformClosedOpenUnit, Backup, DistributionSampler, Habitat, MathsCore, Rng}, landscape::Location, }; use necsim_core_bond::{ClosedUnitF64, NonNegativeF64}; @@ -13,14 +15,20 @@ mod dispersal; #[allow(clippy::module_name_repetitions)] #[derive(Debug)] -pub struct InMemoryCumulativeDispersalSampler { +pub struct InMemoryCumulativeDispersalSampler, G: Rng> +where + G::Sampler: DistributionSampler, +{ cumulative_dispersal: Box<[ClosedUnitF64]>, valid_dispersal_targets: Box<[Option]>, + marker: PhantomData<(M, H, G)>, } #[contract_trait] impl, G: Rng> InMemoryDispersalSampler - for InMemoryCumulativeDispersalSampler + for InMemoryCumulativeDispersalSampler +where + G::Sampler: DistributionSampler, { /// Creates a new `InMemoryCumulativeDispersalSampler` from the /// `dispersal` map and extent of the habitat map. @@ -96,16 +104,21 @@ impl, G: Rng> InMemoryDispersalSampler InMemoryCumulativeDispersalSampler { cumulative_dispersal, valid_dispersal_targets, + marker: PhantomData::<(M, H, G)>, } } } #[contract_trait] -impl Backup for InMemoryCumulativeDispersalSampler { +impl, G: Rng> Backup for InMemoryCumulativeDispersalSampler +where + G::Sampler: DistributionSampler, +{ unsafe fn backup_unchecked(&self) -> Self { Self { cumulative_dispersal: self.cumulative_dispersal.clone(), valid_dispersal_targets: self.valid_dispersal_targets.clone(), + marker: PhantomData::<(M, H, G)>, } } } diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/dispersal.rs index 16722013d..06189f91a 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/dispersal.rs @@ -1,7 +1,10 @@ use core::ops::Range; use necsim_core::{ - cogs::{DispersalSampler, Habitat, MathsCore, Rng}, + cogs::{ + rng::{Event, IndexUsize}, + DispersalSampler, DistributionSampler, Habitat, MathsCore, Rng, + }, landscape::Location, }; @@ -12,6 +15,9 @@ use super::InMemoryPackedAliasDispersalSampler; #[contract_trait] impl, G: Rng> DispersalSampler for InMemoryPackedAliasDispersalSampler +where + G::Sampler: DistributionSampler + + DistributionSampler, { #[must_use] fn sample_dispersal_from_location( diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs index 59bc188d3..ec27a0fa1 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs @@ -5,7 +5,10 @@ use necsim_core_bond::NonNegativeF64; use r#final::Final; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, Rng}, + cogs::{ + rng::{Event, IndexUsize}, + Backup, DistributionSampler, Habitat, MathsCore, Rng, + }, landscape::Location, }; @@ -42,7 +45,11 @@ impl From for Range { #[allow(clippy::module_name_repetitions)] #[cfg_attr(feature = "cuda", derive(rust_cuda::common::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M", free = "H", free = "G"))] -pub struct InMemoryPackedAliasDispersalSampler, G: Rng> { +pub struct InMemoryPackedAliasDispersalSampler, G: Rng> +where + G::Sampler: DistributionSampler + + DistributionSampler, +{ #[cfg_attr(feature = "cuda", cuda(embed))] alias_dispersal_ranges: Final>, #[cfg_attr(feature = "cuda", cuda(embed))] @@ -53,6 +60,9 @@ pub struct InMemoryPackedAliasDispersalSampler, G: R #[contract_trait] impl, G: Rng> InMemoryDispersalSampler for InMemoryPackedAliasDispersalSampler +where + G::Sampler: DistributionSampler + + DistributionSampler, { /// Creates a new `InMemoryPackedAliasDispersalSampler` from the /// `dispersal` map and extent of the habitat map. @@ -114,6 +124,9 @@ impl, G: Rng> InMemoryDispersalSampler impl, G: Rng> core::fmt::Debug for InMemoryPackedAliasDispersalSampler +where + G::Sampler: DistributionSampler + + DistributionSampler, { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { f.debug_struct(stringify!(InMemoryPackedAliasDispersalSampler)) @@ -131,8 +144,10 @@ impl, G: Rng> core::fmt::Debug } #[contract_trait] -impl, G: Rng> Backup - for InMemoryPackedAliasDispersalSampler +impl, G: Rng> Backup for InMemoryPackedAliasDispersalSampler +where + G::Sampler: DistributionSampler + + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs index 1c7c37e99..437ec6bb2 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs @@ -1,5 +1,8 @@ use necsim_core::{ - cogs::{DispersalSampler, Habitat, MathsCore, Rng, SeparableDispersalSampler}, + cogs::{ + rng::{Event, IndexUsize}, + DispersalSampler, DistributionSampler, Habitat, MathsCore, Rng, SeparableDispersalSampler, + }, landscape::Location, }; use necsim_core_bond::ClosedUnitF64; @@ -9,6 +12,9 @@ use super::InMemorySeparableAliasDispersalSampler; #[contract_trait] impl, G: Rng> DispersalSampler for InMemorySeparableAliasDispersalSampler +where + G::Sampler: DistributionSampler + + DistributionSampler, { #[must_use] fn sample_dispersal_from_location( @@ -24,7 +30,9 @@ impl, G: Rng> DispersalSampler return location.clone(); } - if self_dispersal_at_location > 0.0_f64 && rng.sample_event(self_dispersal_at_location) { + if self_dispersal_at_location > 0.0_f64 + && rng.sample_with::(self_dispersal_at_location) + { return location.clone(); } @@ -35,6 +43,9 @@ impl, G: Rng> DispersalSampler #[contract_trait] impl, G: Rng> SeparableDispersalSampler for InMemorySeparableAliasDispersalSampler +where + G::Sampler: DistributionSampler + + DistributionSampler, { #[must_use] fn sample_non_self_dispersal_from_location( diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/mod.rs index 70cda163e..0d6604292 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/mod.rs @@ -3,7 +3,10 @@ use core::marker::PhantomData; use alloc::vec::Vec; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, Rng}, + cogs::{ + rng::{Event, IndexUsize}, + Backup, DistributionSampler, Habitat, MathsCore, Rng, + }, landscape::Location, }; use necsim_core_bond::{ClosedUnitF64, NonNegativeF64}; @@ -17,7 +20,11 @@ mod dispersal; #[allow(clippy::module_name_repetitions)] #[derive(Debug)] -pub struct InMemorySeparableAliasDispersalSampler, G: Rng> { +pub struct InMemorySeparableAliasDispersalSampler, G: Rng> +where + G::Sampler: DistributionSampler + + DistributionSampler, +{ alias_dispersal: Array2D>>, self_dispersal: Array2D, _marker: PhantomData<(M, H, G)>, @@ -26,6 +33,9 @@ pub struct InMemorySeparableAliasDispersalSampler, G #[contract_trait] impl, G: Rng> InMemoryDispersalSampler for InMemorySeparableAliasDispersalSampler +where + G::Sampler: DistributionSampler + + DistributionSampler, { /// Creates a new `InMemorySeparableAliasDispersalSampler` from the /// `dispersal` map and extent of the habitat map. @@ -114,6 +124,9 @@ impl, G: Rng> InMemoryDispersalSampler #[contract_trait] impl, G: Rng> Backup for InMemorySeparableAliasDispersalSampler +where + G::Sampler: DistributionSampler + + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs index 6f20be60a..f8c442481 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs @@ -19,8 +19,8 @@ use crate::cogs::{ #[cfg_attr(feature = "cuda", cuda(free = "M"))] pub struct SpatiallyImplicitDispersalSampler> where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler, { #[cfg_attr(feature = "cuda", cuda(embed))] local: NonSpatialDispersalSampler, @@ -31,8 +31,8 @@ where impl> SpatiallyImplicitDispersalSampler where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler, { #[must_use] pub fn new(local_migration_probability_per_generation: PositiveUnitF64) -> Self { @@ -47,8 +47,8 @@ where #[contract_trait] impl> Backup for SpatiallyImplicitDispersalSampler where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { @@ -64,8 +64,8 @@ where impl> DispersalSampler, G> for SpatiallyImplicitDispersalSampler where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler, { #[must_use] #[debug_ensures(habitat.meta().get_extent().contains(&ret) || ( @@ -109,8 +109,8 @@ where impl> SeparableDispersalSampler, G> for SpatiallyImplicitDispersalSampler where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler, { #[must_use] #[debug_ensures(habitat.meta().get_extent().contains(&ret) || ( diff --git a/necsim/impls/no-std/src/cogs/emigration_exit/domain.rs b/necsim/impls/no-std/src/cogs/emigration_exit/domain.rs index 4fbc4873c..969a16cd7 100644 --- a/necsim/impls/no-std/src/cogs/emigration_exit/domain.rs +++ b/necsim/impls/no-std/src/cogs/emigration_exit/domain.rs @@ -5,8 +5,8 @@ use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_core::{ cogs::{ - coalescence_sampler::CoalescenceRngSample, Backup, EmigrationExit, Habitat, - LocallyCoherentLineageStore, MathsCore, Rng, + coalescence_sampler::CoalescenceRngSample, rng::UniformClosedOpenUnit, Backup, + DistributionSampler, EmigrationExit, Habitat, LocallyCoherentLineageStore, MathsCore, Rng, }, landscape::{IndexedLocation, Location}, lineage::{GlobalLineageReference, MigratingLineage, TieBreaker}, @@ -17,14 +17,21 @@ use crate::decomposition::Decomposition; #[allow(clippy::module_name_repetitions)] #[derive(Debug)] -pub struct DomainEmigrationExit, C: Decomposition> { +pub struct DomainEmigrationExit, G: Rng, C: Decomposition> +where + G::Sampler: DistributionSampler, +{ decomposition: C, emigrants: Vec<(u32, MigratingLineage)>, - _marker: PhantomData<(M, H)>, + _marker: PhantomData<(M, H, G)>, } #[contract_trait] -impl, C: Decomposition> Backup for DomainEmigrationExit { +impl, G: Rng, C: Decomposition> Backup + for DomainEmigrationExit +where + G::Sampler: DistributionSampler, +{ unsafe fn backup_unchecked(&self) -> Self { Self { decomposition: self.decomposition.backup_unchecked(), @@ -35,7 +42,7 @@ impl, C: Decomposition> Backup for DomainEmigr (*partition, migrating_lineage.backup_unchecked()) }) .collect(), - _marker: PhantomData::<(M, H)>, + _marker: PhantomData::<(M, H, G)>, } } } @@ -47,7 +54,9 @@ impl< C: Decomposition, G: Rng, S: LocallyCoherentLineageStore, - > EmigrationExit for DomainEmigrationExit + > EmigrationExit for DomainEmigrationExit +where + G::Sampler: DistributionSampler, { #[must_use] #[debug_ensures(ret.is_some() == ( @@ -106,13 +115,17 @@ impl< } } -impl, C: Decomposition> DomainEmigrationExit { +impl, G: Rng, C: Decomposition> + DomainEmigrationExit +where + G::Sampler: DistributionSampler, +{ #[must_use] pub fn new(decomposition: C) -> Self { Self { decomposition, emigrants: Vec::new(), - _marker: PhantomData::<(M, H)>, + _marker: PhantomData::<(M, H, G)>, } } @@ -125,8 +138,10 @@ impl, C: Decomposition> DomainEmigrationExit, C: Decomposition> Iterator - for DomainEmigrationExit +impl, G: Rng, C: Decomposition> Iterator + for DomainEmigrationExit +where + G::Sampler: DistributionSampler, { type Item = (u32, MigratingLineage); diff --git a/necsim/impls/no-std/src/cogs/emigration_exit/independent/mod.rs b/necsim/impls/no-std/src/cogs/emigration_exit/independent/mod.rs index 42a6a868a..661d30b8b 100644 --- a/necsim/impls/no-std/src/cogs/emigration_exit/independent/mod.rs +++ b/necsim/impls/no-std/src/cogs/emigration_exit/independent/mod.rs @@ -2,7 +2,8 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ - coalescence_sampler::CoalescenceRngSample, Backup, EmigrationExit, Habitat, MathsCore, Rng, + coalescence_sampler::CoalescenceRngSample, rng::UniformClosedOpenUnit, Backup, + DistributionSampler, EmigrationExit, Habitat, MathsCore, Rng, }, landscape::{IndexedLocation, Location}, lineage::{GlobalLineageReference, MigratingLineage, TieBreaker}, @@ -22,18 +23,23 @@ use choice::EmigrationChoice; pub struct IndependentEmigrationExit< M: MathsCore, H: Habitat, + G: Rng, C: Decomposition, E: EmigrationChoice, -> { +> where + G::Sampler: DistributionSampler, +{ decomposition: C, choice: E, emigrant: Option<(u32, MigratingLineage)>, - _marker: PhantomData<(M, H)>, + _marker: PhantomData<(M, H, G)>, } #[contract_trait] -impl, C: Decomposition, E: EmigrationChoice> Backup - for IndependentEmigrationExit +impl, G: Rng, C: Decomposition, E: EmigrationChoice> + Backup for IndependentEmigrationExit +where + G::Sampler: DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { @@ -45,15 +51,17 @@ impl, C: Decomposition, E: EmigrationChoice, + _marker: PhantomData::<(M, H, G)>, } } } #[contract_trait] -impl, C: Decomposition, E: EmigrationChoice, G: Rng> +impl, G: Rng, C: Decomposition, E: EmigrationChoice> EmigrationExit> - for IndependentEmigrationExit + for IndependentEmigrationExit +where + G::Sampler: DistributionSampler, { #[must_use] #[inline] @@ -126,8 +134,10 @@ impl, C: Decomposition, E: EmigrationChoice, C: Decomposition, E: EmigrationChoice> - IndependentEmigrationExit +impl, G: Rng, C: Decomposition, E: EmigrationChoice> + IndependentEmigrationExit +where + G::Sampler: DistributionSampler, { #[must_use] pub fn new(decomposition: C, choice: E) -> Self { @@ -135,7 +145,7 @@ impl, C: Decomposition, E: EmigrationChoice, + _marker: PhantomData::<(M, H, G)>, } } diff --git a/necsim/impls/no-std/src/cogs/emigration_exit/never.rs b/necsim/impls/no-std/src/cogs/emigration_exit/never.rs index d24934c67..0e5f2e7ec 100644 --- a/necsim/impls/no-std/src/cogs/emigration_exit/never.rs +++ b/necsim/impls/no-std/src/cogs/emigration_exit/never.rs @@ -19,12 +19,8 @@ impl Backup for NeverEmigrationExit { } #[contract_trait] -impl< - M: MathsCore, - H: Habitat, - G: Rng, - S: LineageStore, - > EmigrationExit for NeverEmigrationExit +impl, G: Rng, S: LineageStore> EmigrationExit + for NeverEmigrationExit { #[must_use] #[inline] diff --git a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/mod.rs b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/mod.rs index dab070974..39c5d85db 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/mod.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/mod.rs @@ -2,10 +2,10 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ - coalescence_sampler::CoalescenceRngSample, event_sampler::EventHandler, Backup, - CoalescenceSampler, EmigrationExit, EventSampler, GloballyCoherentLineageStore, Habitat, - MathsCore, Rng, SeparableDispersalSampler, SpeciationProbability, - TurnoverRate, + coalescence_sampler::CoalescenceRngSample, event_sampler::EventHandler, + rng::UniformClosedOpenUnit, Backup, CoalescenceSampler, DistributionSampler, + EmigrationExit, EventSampler, GloballyCoherentLineageStore, Habitat, MathsCore, Rng, + SeparableDispersalSampler, SpeciationProbability, TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, landscape::Location, @@ -34,7 +34,9 @@ pub struct ConditionalGillespieEventSampler< D: SeparableDispersalSampler, T: TurnoverRate, N: SpeciationProbability, -> { +> where + G::Sampler: DistributionSampler, +{ #[allow(clippy::type_complexity)] marker: PhantomData<(M, H, G, S, X, D, T, N)>, } @@ -49,6 +51,8 @@ impl< T: TurnoverRate, N: SpeciationProbability, > Default for ConditionalGillespieEventSampler +where + G::Sampler: DistributionSampler, { fn default() -> Self { Self { @@ -68,6 +72,8 @@ impl< T: TurnoverRate, N: SpeciationProbability, > Backup for ConditionalGillespieEventSampler +where + G::Sampler: DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { @@ -88,6 +94,8 @@ impl< N: SpeciationProbability, > EventSampler, T, N> for ConditionalGillespieEventSampler +where + G::Sampler: DistributionSampler, { #[must_use] fn sample_event_for_lineage_at_event_time_or_emigrate< @@ -135,7 +143,7 @@ impl< false, ); - let event_sample = probability_at_location.total() * rng.sample_uniform_closed_open(); + let event_sample = probability_at_location.total() * rng.sample::(); if event_sample < probability_at_location.speciation() { // Speciation Event @@ -240,6 +248,8 @@ impl< N: SpeciationProbability, > GillespieEventSampler, T, N> for ConditionalGillespieEventSampler +where + G::Sampler: DistributionSampler, { #[must_use] fn get_event_rate_at_location( diff --git a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/probability.rs b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/probability.rs index 18e191eae..ae82c49b9 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/probability.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/probability.rs @@ -1,7 +1,7 @@ use necsim_core::{ cogs::{ - GloballyCoherentLineageStore, Habitat, MathsCore, Rng, - SeparableDispersalSampler, SpeciationProbability, + GloballyCoherentLineageStore, Habitat, MathsCore, Rng, SeparableDispersalSampler, + SpeciationProbability, }, landscape::Location, }; diff --git a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/mod.rs b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/mod.rs index 5a79a1626..577e068d5 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/mod.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/mod.rs @@ -1,7 +1,7 @@ use necsim_core::{ cogs::{ - CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, Habitat, - LineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, + CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, Habitat, LineageStore, + MathsCore, Rng, SpeciationProbability, TurnoverRate, }, landscape::Location, }; diff --git a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs index 60f73d73e..07eb9c646 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs @@ -2,10 +2,12 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ - coalescence_sampler::CoalescenceRngSample, event_sampler::EventHandler, Backup, - CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, - GloballyCoherentLineageStore, Habitat, MathsCore, Rng, - SpeciationProbability, TurnoverRate, + coalescence_sampler::CoalescenceRngSample, + event_sampler::EventHandler, + rng::{Event, UniformClosedOpenUnit}, + Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, EmigrationExit, + EventSampler, GloballyCoherentLineageStore, Habitat, MathsCore, Rng, SpeciationProbability, + TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, landscape::Location, @@ -28,7 +30,10 @@ pub struct UnconditionalGillespieEventSampler< C: CoalescenceSampler, T: TurnoverRate, N: SpeciationProbability, -> { +> where + G::Sampler: DistributionSampler + + DistributionSampler, +{ #[allow(clippy::type_complexity)] marker: PhantomData<(M, H, G, S, X, D, C, T, N)>, } @@ -44,6 +49,9 @@ impl< T: TurnoverRate, N: SpeciationProbability, > Default for UnconditionalGillespieEventSampler +where + G::Sampler: DistributionSampler + + DistributionSampler, { fn default() -> Self { Self { @@ -64,6 +72,9 @@ impl< T: TurnoverRate, N: SpeciationProbability, > Backup for UnconditionalGillespieEventSampler +where + G::Sampler: DistributionSampler + + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { @@ -85,6 +96,9 @@ impl< N: SpeciationProbability, > EventSampler for UnconditionalGillespieEventSampler +where + G::Sampler: DistributionSampler + + DistributionSampler, { #[must_use] fn sample_event_for_lineage_at_event_time_or_emigrate< @@ -110,7 +124,7 @@ impl< }: EventHandler, auxiliary: Aux, ) -> Q { - if rng.sample_event( + if rng.sample_with::( simulation .speciation_probability .get_speciation_probability_at_location( @@ -192,6 +206,9 @@ impl< N: SpeciationProbability, > GillespieEventSampler for UnconditionalGillespieEventSampler +where + G::Sampler: DistributionSampler + + DistributionSampler, { #[must_use] fn get_event_rate_at_location( diff --git a/necsim/impls/no-std/src/cogs/event_sampler/independent.rs b/necsim/impls/no-std/src/cogs/event_sampler/independent.rs index b70a5ea73..6592ebdf8 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/independent.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/independent.rs @@ -2,9 +2,10 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ - coalescence_sampler::CoalescenceRngSample, event_sampler::EventHandler, Backup, - CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, Habitat, MathsCore, - Rng, SpeciationProbability, TurnoverRate, + coalescence_sampler::CoalescenceRngSample, event_sampler::EventHandler, + rng::UniformClosedOpenUnit, Backup, CoalescenceSampler, DispersalSampler, + DistributionSampler, EmigrationExit, EventSampler, Habitat, MathsCore, Rng, + SpeciationProbability, TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, lineage::Lineage, @@ -42,7 +43,9 @@ pub struct IndependentEventSampler< D: DispersalSampler, T: TurnoverRate, N: SpeciationProbability, -> { +> where + G::Sampler: DistributionSampler, +{ #[cfg_attr( feature = "cuda", cuda( @@ -62,6 +65,8 @@ impl< T: TurnoverRate, N: SpeciationProbability, > Default for IndependentEventSampler +where + G::Sampler: DistributionSampler, { fn default() -> Self { Self { @@ -81,6 +86,8 @@ impl< T: TurnoverRate, N: SpeciationProbability, > Backup for IndependentEventSampler +where + G::Sampler: DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { @@ -111,6 +118,8 @@ impl< T, N, > for IndependentEventSampler +where + G::Sampler: DistributionSampler, { #[must_use] #[inline] @@ -147,7 +156,7 @@ impl< }: EventHandler, auxiliary: Aux, ) -> Q { - let speciation_sample = rng.sample_uniform_closed_open(); + let speciation_sample = rng.sample::(); SpeciationSample::update_min( &mut self.min_spec_sample, @@ -245,6 +254,8 @@ impl< T, N, > for IndependentEventSampler +where + G::Sampler: DistributionSampler, { fn replace_min_speciation( &mut self, diff --git a/necsim/impls/no-std/src/cogs/event_sampler/tracking.rs b/necsim/impls/no-std/src/cogs/event_sampler/tracking.rs index 5b825f178..2ab61dd71 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/tracking.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/tracking.rs @@ -4,8 +4,8 @@ use necsim_core_bond::{ClosedOpenUnitF64, PositiveF64}; use necsim_core::{ cogs::{ - CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, Habitat, - LineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, + CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, Habitat, LineageStore, + MathsCore, Rng, SpeciationProbability, TurnoverRate, }, landscape::IndexedLocation, }; diff --git a/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs b/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs index 7c97b3423..2b6da1505 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs @@ -2,9 +2,11 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ - coalescence_sampler::CoalescenceRngSample, event_sampler::EventHandler, Backup, - CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, Habitat, - LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, + coalescence_sampler::CoalescenceRngSample, + event_sampler::EventHandler, + rng::{Event, UniformClosedOpenUnit}, + Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, EmigrationExit, + EventSampler, Habitat, LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, @@ -25,7 +27,10 @@ pub struct UnconditionalEventSampler< C: CoalescenceSampler, T: TurnoverRate, N: SpeciationProbability, -> { +> where + G::Sampler: DistributionSampler + + DistributionSampler, +{ #[allow(clippy::type_complexity)] marker: PhantomData<(M, H, G, S, X, D, C, T, N)>, } @@ -41,6 +46,9 @@ impl< T: TurnoverRate, N: SpeciationProbability, > Default for UnconditionalEventSampler +where + G::Sampler: DistributionSampler + + DistributionSampler, { fn default() -> Self { Self { @@ -61,6 +69,9 @@ impl< T: TurnoverRate, N: SpeciationProbability, > Backup for UnconditionalEventSampler +where + G::Sampler: DistributionSampler + + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { @@ -82,6 +93,9 @@ impl< N: SpeciationProbability, > EventSampler for UnconditionalEventSampler +where + G::Sampler: DistributionSampler + + DistributionSampler, { #[must_use] fn sample_event_for_lineage_at_event_time_or_emigrate< @@ -107,7 +121,7 @@ impl< }: EventHandler, auxiliary: Aux, ) -> Q { - if rng.sample_event( + if rng.sample_with::( simulation .speciation_probability .get_speciation_probability_at_location( diff --git a/necsim/impls/no-std/src/cogs/habitat/in_memory.rs b/necsim/impls/no-std/src/cogs/habitat/in_memory.rs index f611f629a..146b8ed81 100644 --- a/necsim/impls/no-std/src/cogs/habitat/in_memory.rs +++ b/necsim/impls/no-std/src/cogs/habitat/in_memory.rs @@ -5,7 +5,10 @@ use alloc::{boxed::Box, vec::Vec}; use r#final::Final; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, Rng, UniformlySampleableHabitat}, + cogs::{ + rng::{IndexU64, Length}, + Backup, DistributionSampler, Habitat, MathsCore, Rng, UniformlySampleableHabitat, + }, landscape::{IndexedLocation, LandscapeExtent, Location}, }; use necsim_core_bond::{OffByOneU32, OffByOneU64}; @@ -106,11 +109,15 @@ impl Habitat for InMemoryHabitat { } #[contract_trait] -impl> UniformlySampleableHabitat for InMemoryHabitat { +impl> UniformlySampleableHabitat for InMemoryHabitat +where + G::Sampler: DistributionSampler, +{ #[must_use] #[inline] fn sample_habitable_indexed_location(&self, rng: &mut G) -> IndexedLocation { - let indexed_location_index = rng.sample_index_u64(self.get_total_habitat().into()); + let indexed_location_index = + rng.sample_with::(Length(self.get_total_habitat().into())); let location_index = match self.u64_injection.binary_search(&indexed_location_index) { Ok(index) => index, diff --git a/necsim/impls/no-std/src/cogs/habitat/non_spatial.rs b/necsim/impls/no-std/src/cogs/habitat/non_spatial.rs index 5a7189ff4..03d421a42 100644 --- a/necsim/impls/no-std/src/cogs/habitat/non_spatial.rs +++ b/necsim/impls/no-std/src/cogs/habitat/non_spatial.rs @@ -4,7 +4,10 @@ use core::{ }; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, Rng, UniformlySampleableHabitat}, + cogs::{ + rng::{IndexU64, Length}, + Backup, DistributionSampler, Habitat, MathsCore, Rng, UniformlySampleableHabitat, + }, landscape::{IndexedLocation, LandscapeExtent, Location}, }; use necsim_core_bond::{OffByOneU32, OffByOneU64}; @@ -116,7 +119,10 @@ impl Habitat for NonSpatialHabitat { } #[contract_trait] -impl> UniformlySampleableHabitat for NonSpatialHabitat { +impl> UniformlySampleableHabitat for NonSpatialHabitat +where + G::Sampler: DistributionSampler, +{ #[must_use] #[inline] fn sample_habitable_indexed_location(&self, rng: &mut G) -> IndexedLocation { @@ -124,8 +130,9 @@ impl> UniformlySampleableHabitat for NonSpatialHab self.extent.width().get() * self.extent.height().get() * u64::from(self.deme.get()); // Safety: habitat width, height, and deme are all > 0 - let mut dispersal_target_index = - rng.sample_index_u64(unsafe { NonZeroU64::new_unchecked(habitat_index_max) }); + let mut dispersal_target_index = rng.sample_with::(Length(unsafe { + NonZeroU64::new_unchecked(habitat_index_max) + })); #[allow(clippy::cast_possible_truncation)] let index = (dispersal_target_index % u64::from(self.deme.get())) as u32; dispersal_target_index /= u64::from(self.deme.get()); diff --git a/necsim/impls/no-std/src/cogs/habitat/spatially_implicit.rs b/necsim/impls/no-std/src/cogs/habitat/spatially_implicit.rs index 80f7812da..e029edf6c 100644 --- a/necsim/impls/no-std/src/cogs/habitat/spatially_implicit.rs +++ b/necsim/impls/no-std/src/cogs/habitat/spatially_implicit.rs @@ -1,7 +1,10 @@ use core::num::NonZeroU32; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, Rng, UniformlySampleableHabitat}, + cogs::{ + rng::IndexU64, Backup, DistributionSampler, Habitat, MathsCore, Rng, + UniformlySampleableHabitat, + }, landscape::{IndexedLocation, LandscapeExtent, Location}, }; use necsim_core_bond::{OffByOneU32, OffByOneU64}; @@ -128,7 +131,10 @@ impl Habitat for SpatiallyImplicitHabitat { } #[contract_trait] -impl> UniformlySampleableHabitat for SpatiallyImplicitHabitat { +impl> UniformlySampleableHabitat for SpatiallyImplicitHabitat +where + G::Sampler: DistributionSampler, +{ #[must_use] #[inline] fn sample_habitable_indexed_location(&self, rng: &mut G) -> IndexedLocation { diff --git a/necsim/impls/no-std/src/parallelisation/independent/individuals.rs b/necsim/impls/no-std/src/parallelisation/independent/individuals.rs index 9498a714c..a442883df 100644 --- a/necsim/impls/no-std/src/parallelisation/independent/individuals.rs +++ b/necsim/impls/no-std/src/parallelisation/independent/individuals.rs @@ -9,8 +9,8 @@ use necsim_core_bond::NonNegativeF64; use necsim_core::{ cogs::{ - DispersalSampler, Habitat, MathsCore, PrimeableRng, Rng, SpeciationProbability, - TurnoverRate, + rng::UniformClosedOpenUnit, DispersalSampler, DistributionSampler, Habitat, MathsCore, + PrimeableRng, Rng, SpeciationProbability, TurnoverRate, }, lineage::Lineage, reporter::Reporter, @@ -84,7 +84,10 @@ pub fn simulate< NonNegativeF64, u64, impl IntoIterator, -) { +) +where + G::Sampler: DistributionSampler, +{ let mut lineages = VecDeque::from_iter(lineages); let mut proxy = IgnoreProgressReporterProxy::from(local_partition); let mut min_spec_samples = dedup_cache.construct(lineages.len()); diff --git a/necsim/impls/no-std/src/parallelisation/independent/landscape.rs b/necsim/impls/no-std/src/parallelisation/independent/landscape.rs index ff7d0808a..292e6f78f 100644 --- a/necsim/impls/no-std/src/parallelisation/independent/landscape.rs +++ b/necsim/impls/no-std/src/parallelisation/independent/landscape.rs @@ -9,8 +9,8 @@ use necsim_core_bond::NonNegativeF64; use necsim_core::{ cogs::{ - DispersalSampler, Habitat, MathsCore, PrimeableRng, Rng, SpeciationProbability, - TurnoverRate, + rng::UniformClosedOpenUnit, DispersalSampler, DistributionSampler, Habitat, MathsCore, + PrimeableRng, Rng, SpeciationProbability, TurnoverRate, }, event::DispersalEvent, landscape::IndexedLocation, @@ -54,12 +54,12 @@ pub fn simulate< H, G, IndependentLineageStore, - IndependentEmigrationExit, + IndependentEmigrationExit, D, IndependentCoalescenceSampler, T, N, - IndependentEventSampler, D, T, N>, + IndependentEventSampler, D, T, N>, NeverImmigrationEntry, >, R: Reporter, @@ -71,12 +71,12 @@ pub fn simulate< H, G, IndependentLineageStore, - IndependentEmigrationExit, + IndependentEmigrationExit, D, IndependentCoalescenceSampler, T, N, - IndependentEventSampler, D, T, N>, + IndependentEventSampler, D, T, N>, NeverImmigrationEntry, A, >, @@ -89,7 +89,10 @@ pub fn simulate< NonNegativeF64, u64, impl IntoIterator, -) { +) +where + G::Sampler: DistributionSampler, +{ let mut lineages = VecDeque::from_iter(lineages); let mut proxy = IgnoreProgressReporterProxy::from(local_partition); let mut min_spec_samples = dedup_cache.construct(lineages.len()); diff --git a/necsim/impls/no-std/src/parallelisation/independent/monolithic/mod.rs b/necsim/impls/no-std/src/parallelisation/independent/monolithic/mod.rs index e543487a6..b7508aaf1 100644 --- a/necsim/impls/no-std/src/parallelisation/independent/monolithic/mod.rs +++ b/necsim/impls/no-std/src/parallelisation/independent/monolithic/mod.rs @@ -8,8 +8,8 @@ use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_core::{ cogs::{ - DispersalSampler, Habitat, MathsCore, PrimeableRng, Rng, SpeciationProbability, - TurnoverRate, + rng::UniformClosedOpenUnit, DispersalSampler, DistributionSampler, Habitat, MathsCore, + PrimeableRng, Rng, SpeciationProbability, TurnoverRate, }, lineage::Lineage, reporter::{boolean::Boolean, Reporter}, @@ -91,7 +91,10 @@ pub fn simulate< NonNegativeF64, u64, impl IntoIterator, -) { +) +where + G::Sampler: DistributionSampler, +{ let mut slow_lineages = lineages .into_iter() .map(|lineage| { diff --git a/necsim/impls/no-std/src/parallelisation/monolithic/averaging.rs b/necsim/impls/no-std/src/parallelisation/monolithic/averaging.rs index b9149241e..c535f74b9 100644 --- a/necsim/impls/no-std/src/parallelisation/monolithic/averaging.rs +++ b/necsim/impls/no-std/src/parallelisation/monolithic/averaging.rs @@ -2,9 +2,9 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ - ActiveLineageSampler, CoalescenceSampler, DispersalSampler, EventSampler, Habitat, - LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, - TurnoverRate, + rng::UniformClosedOpenUnit, ActiveLineageSampler, CoalescenceSampler, DispersalSampler, + DistributionSampler, EventSampler, Habitat, LocallyCoherentLineageStore, MathsCore, Rng, + SpeciationProbability, TurnoverRate, }, reporter::Reporter, simulation::Simulation, @@ -34,13 +34,13 @@ pub fn simulate< T: TurnoverRate, N: SpeciationProbability, O: Decomposition, - E: EventSampler, D, C, T, N>, + E: EventSampler, D, C, T, N>, A: ActiveLineageSampler< M, H, G, S, - DomainEmigrationExit, + DomainEmigrationExit, D, C, T, @@ -56,7 +56,7 @@ pub fn simulate< H, G, S, - DomainEmigrationExit, + DomainEmigrationExit, D, C, T, @@ -67,7 +67,10 @@ pub fn simulate< >, independent_time_slice: PositiveF64, local_partition: &mut L, -) -> (Status, NonNegativeF64, u64) { +) -> (Status, NonNegativeF64, u64) +where + G::Sampler: DistributionSampler, +{ // Ensure that the progress bar starts with the expected target local_partition.report_progress_sync(simulation.get_balanced_remaining_work().0); diff --git a/necsim/impls/no-std/src/parallelisation/monolithic/lockstep.rs b/necsim/impls/no-std/src/parallelisation/monolithic/lockstep.rs index 0fac89dfe..deebee9a9 100644 --- a/necsim/impls/no-std/src/parallelisation/monolithic/lockstep.rs +++ b/necsim/impls/no-std/src/parallelisation/monolithic/lockstep.rs @@ -2,9 +2,9 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ - ActiveLineageSampler, CoalescenceSampler, DispersalSampler, EventSampler, Habitat, - LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, - TurnoverRate, + rng::UniformClosedOpenUnit, ActiveLineageSampler, CoalescenceSampler, DispersalSampler, + DistributionSampler, EventSampler, Habitat, LocallyCoherentLineageStore, MathsCore, Rng, + SpeciationProbability, TurnoverRate, }, reporter::{NullReporter, Reporter}, simulation::Simulation, @@ -34,13 +34,13 @@ pub fn simulate< T: TurnoverRate, N: SpeciationProbability, O: Decomposition, - E: EventSampler, D, C, T, N>, + E: EventSampler, D, C, T, N>, A: ActiveLineageSampler< M, H, G, S, - DomainEmigrationExit, + DomainEmigrationExit, D, C, T, @@ -56,7 +56,7 @@ pub fn simulate< H, G, S, - DomainEmigrationExit, + DomainEmigrationExit, D, C, T, @@ -66,7 +66,10 @@ pub fn simulate< A, >, local_partition: &mut L, -) -> (Status, NonNegativeF64, u64) { +) -> (Status, NonNegativeF64, u64) +where + G::Sampler: DistributionSampler, +{ // Ensure that the progress bar starts with the expected target local_partition.report_progress_sync(simulation.get_balanced_remaining_work().0); diff --git a/necsim/impls/no-std/src/parallelisation/monolithic/monolithic.rs b/necsim/impls/no-std/src/parallelisation/monolithic/monolithic.rs index feffe1fef..38df79c17 100644 --- a/necsim/impls/no-std/src/parallelisation/monolithic/monolithic.rs +++ b/necsim/impls/no-std/src/parallelisation/monolithic/monolithic.rs @@ -3,8 +3,7 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ ActiveLineageSampler, CoalescenceSampler, DispersalSampler, EventSampler, Habitat, - LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, - TurnoverRate, + LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, }, reporter::Reporter, simulation::Simulation, diff --git a/necsim/impls/no-std/src/parallelisation/monolithic/optimistic.rs b/necsim/impls/no-std/src/parallelisation/monolithic/optimistic.rs index 553fcb735..3924e6ffd 100644 --- a/necsim/impls/no-std/src/parallelisation/monolithic/optimistic.rs +++ b/necsim/impls/no-std/src/parallelisation/monolithic/optimistic.rs @@ -3,9 +3,9 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ - backup::BackedUp, ActiveLineageSampler, Backup, CoalescenceSampler, DispersalSampler, - EventSampler, Habitat, LocallyCoherentLineageStore, MathsCore, Rng, - SpeciationProbability, TurnoverRate, + backup::BackedUp, rng::UniformClosedOpenUnit, ActiveLineageSampler, Backup, + CoalescenceSampler, DispersalSampler, DistributionSampler, EventSampler, Habitat, + LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, }, lineage::MigratingLineage, reporter::Reporter, @@ -38,13 +38,13 @@ pub fn simulate< T: TurnoverRate, N: SpeciationProbability, O: Decomposition, - E: EventSampler, D, C, T, N>, + E: EventSampler, D, C, T, N>, A: ActiveLineageSampler< M, H, G, S, - DomainEmigrationExit, + DomainEmigrationExit, D, C, T, @@ -60,7 +60,7 @@ pub fn simulate< H, G, S, - DomainEmigrationExit, + DomainEmigrationExit, D, C, T, @@ -71,7 +71,10 @@ pub fn simulate< >, independent_time_slice: PositiveF64, local_partition: &mut L, -) -> (Status, NonNegativeF64, u64) { +) -> (Status, NonNegativeF64, u64) +where + G::Sampler: DistributionSampler, +{ // Ensure that the progress bar starts with the expected target local_partition.report_progress_sync(simulation.get_balanced_remaining_work().0); diff --git a/necsim/impls/no-std/src/parallelisation/monolithic/optimistic_lockstep.rs b/necsim/impls/no-std/src/parallelisation/monolithic/optimistic_lockstep.rs index 0930e18f7..acc862bf6 100644 --- a/necsim/impls/no-std/src/parallelisation/monolithic/optimistic_lockstep.rs +++ b/necsim/impls/no-std/src/parallelisation/monolithic/optimistic_lockstep.rs @@ -2,9 +2,9 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ - ActiveLineageSampler, Backup, CoalescenceSampler, DispersalSampler, EventSampler, Habitat, - LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, - TurnoverRate, + rng::UniformClosedOpenUnit, ActiveLineageSampler, Backup, CoalescenceSampler, + DispersalSampler, DistributionSampler, EventSampler, Habitat, LocallyCoherentLineageStore, + MathsCore, Rng, SpeciationProbability, TurnoverRate, }, reporter::{NullReporter, Reporter}, simulation::Simulation, @@ -34,13 +34,13 @@ pub fn simulate< T: TurnoverRate, N: SpeciationProbability, O: Decomposition, - E: EventSampler, D, C, T, N>, + E: EventSampler, D, C, T, N>, A: ActiveLineageSampler< M, H, G, S, - DomainEmigrationExit, + DomainEmigrationExit, D, C, T, @@ -56,7 +56,7 @@ pub fn simulate< H, G, S, - DomainEmigrationExit, + DomainEmigrationExit, D, C, T, @@ -66,7 +66,10 @@ pub fn simulate< A, >, local_partition: &mut L, -) -> (Status, NonNegativeF64, u64) { +) -> (Status, NonNegativeF64, u64) +where + G::Sampler: DistributionSampler, +{ // Ensure that the progress bar starts with the expected target local_partition.report_progress_sync(simulation.get_balanced_remaining_work().0); diff --git a/necsim/impls/std/src/cogs/dispersal_sampler/in_memory/mod.rs b/necsim/impls/std/src/cogs/dispersal_sampler/in_memory/mod.rs index e58acd679..3ebb85ce8 100644 --- a/necsim/impls/std/src/cogs/dispersal_sampler/in_memory/mod.rs +++ b/necsim/impls/std/src/cogs/dispersal_sampler/in_memory/mod.rs @@ -1,4 +1,4 @@ -use necsim_core::cogs::{Habitat, MathsCore, RngCore}; +use necsim_core::cogs::{Habitat, MathsCore, Rng}; use necsim_impls_no_std::array2d::Array2D; pub mod error; @@ -13,7 +13,7 @@ use necsim_impls_no_std::cogs::dispersal_sampler::in_memory::{ #[allow(clippy::module_name_repetitions)] #[allow(clippy::inline_always, clippy::inline_fn_without_body)] #[contract_trait] -pub trait InMemoryDispersalSampler, G: RngCore>: +pub trait InMemoryDispersalSampler, G: Rng>: InMemoryDispersalSamplerNoError + Sized { #[debug_ensures( @@ -40,7 +40,7 @@ pub trait InMemoryDispersalSampler, G: RngCore>: } #[contract_trait] -impl, G: RngCore, T: InMemoryDispersalSamplerNoError> +impl, G: Rng, T: InMemoryDispersalSamplerNoError> InMemoryDispersalSampler for T { /// Creates a new `T` from the `dispersal` map and extent of the habitat diff --git a/necsim/impls/std/src/cogs/rng/pcg.rs b/necsim/impls/std/src/cogs/rng/pcg.rs index 23f5d3d68..81664a89f 100644 --- a/necsim/impls/std/src/cogs/rng/pcg.rs +++ b/necsim/impls/std/src/cogs/rng/pcg.rs @@ -1,29 +1,27 @@ -use std::{fmt, marker::PhantomData}; +use std::fmt; use pcg_rand::{seeds::PcgSeeder, PCGStateInfo, Pcg64}; use rand_core::{RngCore as _, SeedableRng}; use serde::{Deserialize, Serialize}; -use necsim_core::cogs::{MathsCore, RngCore, SplittableRng}; +use necsim_core::cogs::{RngCore, SplittableRng}; #[allow(clippy::module_name_repetitions)] #[derive(Serialize, Deserialize)] #[serde(from = "PcgState", into = "PcgState")] -pub struct Pcg { +pub struct Pcg { inner: Pcg64, - marker: PhantomData, } -impl Clone for Pcg { +impl Clone for Pcg { fn clone(&self) -> Self { Self { inner: Pcg64::restore_state_with_no_verification(self.inner.get_state()), - marker: PhantomData::, } } } -impl fmt::Debug for Pcg { +impl fmt::Debug for Pcg { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let state = self.inner.get_state(); @@ -34,7 +32,7 @@ impl fmt::Debug for Pcg { } } -impl RngCore for Pcg { +impl RngCore for Pcg { type Seed = [u8; 16]; #[must_use] @@ -45,7 +43,6 @@ impl RngCore for Pcg { u128::from_le_bytes(seed), 0_u128, )), - marker: PhantomData::, } } @@ -56,7 +53,7 @@ impl RngCore for Pcg { } } -impl SplittableRng for Pcg { +impl SplittableRng for Pcg { #[allow(clippy::identity_op)] fn split(self) -> (Self, Self) { let mut left_state = self.inner.get_state(); @@ -67,11 +64,9 @@ impl SplittableRng for Pcg { let left = Self { inner: Pcg64::restore_state_with_no_verification(left_state), - marker: PhantomData::, }; let right = Self { inner: Pcg64::restore_state_with_no_verification(right_state), - marker: PhantomData::, }; (left, right) @@ -83,7 +78,6 @@ impl SplittableRng for Pcg { Self { inner: Pcg64::restore_state_with_no_verification(state), - marker: PhantomData::, } } } @@ -96,8 +90,8 @@ struct PcgState { increment: u128, } -impl From> for PcgState { - fn from(rng: Pcg) -> Self { +impl From for PcgState { + fn from(rng: Pcg) -> Self { let state_info = rng.inner.get_state(); Self { @@ -107,7 +101,7 @@ impl From> for PcgState { } } -impl From for Pcg { +impl From for Pcg { fn from(state: PcgState) -> Self { use pcg_rand::{ multiplier::{DefaultMultiplier, Multiplier}, @@ -125,7 +119,6 @@ impl From for Pcg { Self { inner: Pcg64::restore_state_with_no_verification(state_info), - marker: PhantomData::, } } } From a40424a0981bd2876e78aec88ea67c691985e941 Mon Sep 17 00:00:00 2001 From: Momo Langenstein Date: Wed, 18 May 2022 12:55:02 +0000 Subject: [PATCH 06/42] It compiles? --- necsim/core/src/cogs/rng.rs | 109 ++++++++++++- necsim/impls/cuda/src/cogs/rng.rs | 9 ++ .../alias/sampler/indexed/tests.rs | 4 + .../alias/sampler/stack/tests.rs | 4 + .../algorithms/cuda/cpu-kernel/src/lib.rs | 9 +- .../algorithms/cuda/cpu-kernel/src/link.rs | 81 ++++++---- .../algorithms/cuda/cpu-kernel/src/patch.rs | 4 +- .../algorithms/cuda/gpu-kernel/src/lib.rs | 5 +- .../algorithms/cuda/src/initialiser/fixup.rs | 10 +- .../cuda/src/initialiser/genesis.rs | 10 +- .../algorithms/cuda/src/initialiser/mod.rs | 10 +- .../algorithms/cuda/src/initialiser/resume.rs | 10 +- rustcoalescence/algorithms/cuda/src/launch.rs | 36 +++-- rustcoalescence/algorithms/cuda/src/lib.rs | 144 +++++++++++++----- .../cuda/src/parallelisation/monolithic.rs | 4 +- .../src/event_skipping/initialiser/fixup.rs | 13 +- .../src/event_skipping/initialiser/genesis.rs | 13 +- .../src/event_skipping/initialiser/mod.rs | 10 +- .../src/event_skipping/initialiser/resume.rs | 14 +- .../gillespie/src/event_skipping/launch.rs | 14 +- .../gillespie/src/event_skipping/mod.rs | 17 ++- .../gillespie/classical/initialiser/fixup.rs | 13 +- .../classical/initialiser/genesis.rs | 15 +- .../gillespie/classical/initialiser/mod.rs | 16 +- .../gillespie/classical/initialiser/resume.rs | 13 +- .../src/gillespie/classical/launch.rs | 15 +- .../gillespie/src/gillespie/classical/mod.rs | 4 +- .../gillespie/turnover/initialiser/fixup.rs | 13 +- .../gillespie/turnover/initialiser/genesis.rs | 15 +- .../src/gillespie/turnover/initialiser/mod.rs | 16 +- .../gillespie/turnover/initialiser/resume.rs | 13 +- .../src/gillespie/turnover/launch.rs | 15 +- .../gillespie/src/gillespie/turnover/mod.rs | 13 +- .../algorithms/gillespie/src/lib.rs | 1 + .../independent/src/initialiser/fixup.rs | 17 ++- .../independent/src/initialiser/genesis.rs | 11 +- .../independent/src/initialiser/mod.rs | 12 +- .../independent/src/initialiser/resume.rs | 17 ++- .../algorithms/independent/src/launch.rs | 15 +- .../algorithms/independent/src/lib.rs | 18 ++- rustcoalescence/algorithms/src/lib.rs | 4 +- rustcoalescence/algorithms/src/result.rs | 4 +- .../scenarios/src/almost_infinite.rs | 19 ++- rustcoalescence/scenarios/src/lib.rs | 4 +- rustcoalescence/scenarios/src/non_spatial.rs | 19 ++- .../src/spatially_explicit/turnover/map.rs | 19 ++- .../spatially_explicit/turnover/uniform.rs | 19 ++- .../scenarios/src/spatially_implicit.rs | 23 ++- rustcoalescence/src/args/config/rng/mod.rs | 22 +-- .../src/cli/simulate/dispatch/valid/rng.rs | 12 +- rustcoalescence/src/cli/simulate/parse/rng.rs | 12 +- 51 files changed, 693 insertions(+), 246 deletions(-) diff --git a/necsim/core/src/cogs/rng.rs b/necsim/core/src/cogs/rng.rs index 3a0130ea9..ce282cc5c 100644 --- a/necsim/core/src/cogs/rng.rs +++ b/necsim/core/src/cogs/rng.rs @@ -111,6 +111,9 @@ pub trait Rng: RngCore { #[must_use] fn generator(&mut self) -> &mut Self::Generator; + #[must_use] + fn map_generator Self::Generator>(self, map: F) -> Self; + #[must_use] fn sample_with(&mut self, params: D::Parameters) -> D::Sample where @@ -223,11 +226,12 @@ impl Distribution for Normal2D { type Sample = (f64, f64); } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, TypeLayout)] +#[layout(free = "M")] #[allow(clippy::module_name_repetitions)] pub struct SimpleRng { inner: R, - _marker: PhantomData, + marker: PhantomData, } impl Serialize for SimpleRng { @@ -242,7 +246,7 @@ impl<'de, M: MathsCore, R: RngCore> Deserialize<'de> for SimpleRng { Ok(Self { inner, - _marker: PhantomData::, + marker: PhantomData::, }) } } @@ -252,7 +256,7 @@ impl crate::cogs::Backup for SimpleRng { unsafe fn backup_unchecked(&self) -> Self { Self { inner: self.inner.backup_unchecked(), - _marker: PhantomData::, + marker: PhantomData::, } } } @@ -264,7 +268,7 @@ impl RngCore for SimpleRng { fn from_seed(seed: Self::Seed) -> Self { Self { inner: R::from_seed(seed), - _marker: PhantomData::, + marker: PhantomData::, } } @@ -282,6 +286,15 @@ impl Rng for SimpleRng { &mut self.inner } + fn map_generator Self::Generator>(self, map: F) -> Self { + let SimpleRng { inner, marker } = self; + + SimpleRng { + inner: map(inner), + marker, + } + } + fn sample_with(&mut self, params: D::Parameters) -> D::Sample where Self::Sampler: DistributionSampler, @@ -436,6 +449,92 @@ impl> + DistributionSampler for SimplerDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with(&self, rng: &mut R, samplers: &S, params: Lambda) -> NonNegativeF64 { + let lambda = params.0; + + let u01: OpenClosedUnitF64 = samplers.sample(rng, samplers); + + // Inverse transform sample: X = -ln(U(0,1]) / lambda + -u01.ln::() / lambda + } +} + +impl> + DistributionSampler for SimplerDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with(&self, rng: &mut R, samplers: &S, params: ClosedUnitF64) -> bool { + let probability = params; + + let u01: ClosedOpenUnitF64 = samplers.sample(rng, samplers); + + // if probability == 1, then U[0, 1) always < 1.0 + // if probability == 0, then U[0, 1) never < 0.0 + u01 < probability + } +} + +#[allow(clippy::trait_duplication_in_bounds)] +impl< + M: MathsCore, + R: RngCore, + S: DistributionSampler + + DistributionSampler, + > DistributionSampler for SimplerDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with(&self, rng: &mut R, samplers: &S, _params: ()) -> (f64, f64) { + // Basic Box-Muller transform + let u0 = + DistributionSampler::::sample(samplers, rng, samplers); + let u1 = + DistributionSampler::::sample(samplers, rng, samplers); + + let r = M::sqrt(-2.0_f64 * M::ln(u0.get())); + let theta = -core::f64::consts::TAU * u1.get(); + + (r * M::sin(theta), r * M::cos(theta)) + } +} + +impl> + DistributionSampler for SimplerDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with(&self, rng: &mut R, samplers: &S, params: Normal) -> (f64, f64) { + let (z0, z1) = samplers.sample(rng, samplers); + + ( + z0 * params.sigma.get() + params.mu, + z1 * params.sigma.get() + params.mu, + ) + } +} + /*#[allow(clippy::inline_always, clippy::inline_fn_without_body)] #[allow(clippy::module_name_repetitions)] #[contract_trait] diff --git a/necsim/impls/cuda/src/cogs/rng.rs b/necsim/impls/cuda/src/cogs/rng.rs index af411f60e..6f04b14e2 100644 --- a/necsim/impls/cuda/src/cogs/rng.rs +++ b/necsim/impls/cuda/src/cogs/rng.rs @@ -67,6 +67,15 @@ impl + StackOnly + ~const TypeGraphLayout> Rng for Cu self.inner.generator() } + fn map_generator Self::Generator>(self, map: F) -> Self { + let CudaRng { inner, marker } = self; + + CudaRng { + inner: inner.map_generator(map), + marker, + } + } + fn sample_with(&mut self, params: D::Parameters) -> D::Sample where Self::Sampler: DistributionSampler, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs index c866a6886..81bd218de 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs @@ -1116,6 +1116,10 @@ impl Rng for DummyRng { self } + fn map_generator Self::Generator>(self, map: F) -> Self { + map(self) + } + fn sample_with(&mut self, params: D::Parameters) -> D::Sample where Self::Sampler: DistributionSampler, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs index 06ff6339c..f9486183d 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs @@ -615,6 +615,10 @@ impl Rng for DummyRng { self } + fn map_generator Self::Generator>(self, map: F) -> Self { + map(self) + } + fn sample_with(&mut self, params: D::Parameters) -> D::Sample where Self::Sampler: DistributionSampler, diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs b/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs index 5436bea05..1caa2d456 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs @@ -1,13 +1,14 @@ #![deny(clippy::pedantic)] #![feature(const_eval_limit)] #![const_eval_limit = "1000000000000"] +#![feature(associated_type_bounds)] #![allow(incomplete_features)] #![feature(specialization)] use necsim_core::{ cogs::{ CoalescenceSampler, DispersalSampler, EmigrationExit, Habitat, ImmigrationEntry, - LineageStore, MathsCore, PrimeableRng, SpeciationProbability, TurnoverRate, + LineageStore, MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, }, reporter::boolean::Boolean, }; @@ -38,7 +39,7 @@ pub type KernelCompilationCallback = dyn FnMut(&Function) -> CudaResult<()>; pub struct SimulationKernel< M: MathsCore, H: Habitat + RustToCuda, - G: PrimeableRng + RustToCuda, + G: Rng + RustToCuda, S: LineageStore + RustToCuda, X: EmigrationExit + RustToCuda, D: DispersalSampler + RustToCuda, @@ -80,7 +81,7 @@ pub struct SimulationKernel< impl< M: MathsCore, H: Habitat + RustToCuda, - G: PrimeableRng + RustToCuda, + G: Rng + RustToCuda, S: LineageStore + RustToCuda, X: EmigrationExit + RustToCuda, D: DispersalSampler + RustToCuda, @@ -139,7 +140,7 @@ impl< impl< M: MathsCore, H: Habitat + RustToCuda, - G: PrimeableRng + RustToCuda, + G: Rng + RustToCuda, S: LineageStore + RustToCuda, X: EmigrationExit + RustToCuda, D: DispersalSampler + RustToCuda, diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs b/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs index 98f3b0819..255da478e 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs @@ -34,8 +34,9 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_impls_no_std::cogs::rng::wyhash::WyHash< - necsim_impls_cuda::cogs::maths::NvptxMathsCore + necsim_core::cogs::rng::SimpleRng< + necsim_impls_cuda::cogs::maths::NvptxMathsCore, + necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, >, necsim_impls_no_std::cogs::lineage_store::independent::IndependentLineageStore< @@ -55,9 +56,10 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_impls_no_std::cogs::rng::wyhash::WyHash< - necsim_impls_cuda::cogs::maths::NvptxMathsCore, - >, + necsim_core::cogs::rng::SimpleRng< + necsim_impls_cuda::cogs::maths::NvptxMathsCore, + necsim_impls_no_std::cogs::rng::wyhash::WyHash, + >, >, necsim_impls_no_std::cogs::emigration_exit::never::NeverEmigrationExit, $dispersal, @@ -70,8 +72,9 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_impls_no_std::cogs::rng::wyhash::WyHash< + necsim_core::cogs::rng::SimpleRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, + necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, >, necsim_impls_no_std::cogs::emigration_exit::never::NeverEmigrationExit, @@ -89,8 +92,9 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_impls_no_std::cogs::rng::wyhash::WyHash< - necsim_impls_cuda::cogs::maths::NvptxMathsCore + necsim_core::cogs::rng::SimpleRng< + necsim_impls_cuda::cogs::maths::NvptxMathsCore, + necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, >, necsim_impls_no_std::cogs::lineage_store::independent::IndependentLineageStore< @@ -103,8 +107,9 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_impls_no_std::cogs::rng::wyhash::WyHash< - necsim_impls_cuda::cogs::maths::NvptxMathsCore + necsim_core::cogs::rng::SimpleRng< + necsim_impls_cuda::cogs::maths::NvptxMathsCore, + necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, >, $dispersal, @@ -113,8 +118,9 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_impls_no_std::cogs::rng::wyhash::WyHash< - necsim_impls_cuda::cogs::maths::NvptxMathsCore + necsim_core::cogs::rng::SimpleRng< + necsim_impls_cuda::cogs::maths::NvptxMathsCore, + necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, >, >, @@ -130,8 +136,9 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_impls_no_std::cogs::rng::wyhash::WyHash< + necsim_core::cogs::rng::SimpleRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, + necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, >, necsim_impls_no_std::cogs::emigration_exit::never::NeverEmigrationExit, @@ -140,8 +147,9 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_impls_no_std::cogs::rng::wyhash::WyHash< - necsim_impls_cuda::cogs::maths::NvptxMathsCore + necsim_core::cogs::rng::SimpleRng< + necsim_impls_cuda::cogs::maths::NvptxMathsCore, + necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, >, $dispersal, @@ -150,8 +158,9 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_impls_no_std::cogs::rng::wyhash::WyHash< - necsim_impls_cuda::cogs::maths::NvptxMathsCore + necsim_core::cogs::rng::SimpleRng< + necsim_impls_cuda::cogs::maths::NvptxMathsCore, + necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, >, >, @@ -165,8 +174,9 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_impls_no_std::cogs::rng::wyhash::WyHash< + necsim_core::cogs::rng::SimpleRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, + necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, >, necsim_impls_no_std::cogs::emigration_exit::never::NeverEmigrationExit, @@ -175,8 +185,9 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_impls_no_std::cogs::rng::wyhash::WyHash< - necsim_impls_cuda::cogs::maths::NvptxMathsCore + necsim_core::cogs::rng::SimpleRng< + necsim_impls_cuda::cogs::maths::NvptxMathsCore, + necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, >, $dispersal, @@ -185,8 +196,9 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_impls_no_std::cogs::rng::wyhash::WyHash< - necsim_impls_cuda::cogs::maths::NvptxMathsCore + necsim_core::cogs::rng::SimpleRng< + necsim_impls_cuda::cogs::maths::NvptxMathsCore, + necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, >, >, @@ -209,8 +221,9 @@ link_kernel!( necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_impls_no_std::cogs::rng::wyhash::WyHash< - necsim_impls_cuda::cogs::maths::NvptxMathsCore + necsim_core::cogs::rng::SimpleRng< + necsim_impls_cuda::cogs::maths::NvptxMathsCore, + necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, >, >, @@ -226,8 +239,9 @@ link_kernel!( necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_impls_no_std::cogs::rng::wyhash::WyHash< - necsim_impls_cuda::cogs::maths::NvptxMathsCore + necsim_core::cogs::rng::SimpleRng< + necsim_impls_cuda::cogs::maths::NvptxMathsCore, + necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, >, >, @@ -243,8 +257,9 @@ link_kernel!( necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_impls_no_std::cogs::rng::wyhash::WyHash< - necsim_impls_cuda::cogs::maths::NvptxMathsCore + necsim_core::cogs::rng::SimpleRng< + necsim_impls_cuda::cogs::maths::NvptxMathsCore, + necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, >, >, @@ -263,8 +278,9 @@ link_kernel!( >, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_impls_no_std::cogs::rng::wyhash::WyHash< - necsim_impls_cuda::cogs::maths::NvptxMathsCore + necsim_core::cogs::rng::SimpleRng< + necsim_impls_cuda::cogs::maths::NvptxMathsCore, + necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, >, >, @@ -283,8 +299,9 @@ link_kernel!( >, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_impls_no_std::cogs::rng::wyhash::WyHash< - necsim_impls_cuda::cogs::maths::NvptxMathsCore + necsim_core::cogs::rng::SimpleRng< + necsim_impls_cuda::cogs::maths::NvptxMathsCore, + necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, >, >, diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs b/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs index 129565624..f0d63342c 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs @@ -3,7 +3,7 @@ use std::sync::atomic::AtomicU64; use necsim_core::{ cogs::{ CoalescenceSampler, DispersalSampler, EmigrationExit, Habitat, ImmigrationEntry, - LineageStore, MathsCore, PrimeableRng, SpeciationProbability, TurnoverRate, + LineageStore, MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, }, lineage::Lineage, reporter::boolean::{Boolean, False, True}, @@ -40,7 +40,7 @@ extern "C" { unsafe impl< M: MathsCore, H: Habitat + RustToCuda, - G: PrimeableRng + RustToCuda, + G: Rng + RustToCuda, S: LineageStore + RustToCuda, X: EmigrationExit + RustToCuda, D: DispersalSampler + RustToCuda, diff --git a/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs b/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs index 53299dc7b..24cf141e0 100644 --- a/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs +++ b/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs @@ -2,6 +2,7 @@ #![no_std] #![feature(const_eval_limit)] #![const_eval_limit = "1000000000000"] +#![feature(associated_type_bounds)] #![cfg_attr(target_os = "cuda", feature(abi_ptx))] #![cfg_attr(target_os = "cuda", feature(alloc_error_handler))] #![cfg_attr(target_os = "cuda", feature(panic_info_message))] @@ -18,7 +19,7 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ CoalescenceSampler, DispersalSampler, EmigrationExit, Habitat, ImmigrationEntry, - LineageStore, MathsCore, PrimeableRng, SpeciationProbability, TurnoverRate, + LineageStore, MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, }, reporter::boolean::Boolean, }; @@ -38,7 +39,7 @@ use rust_cuda::common::RustToCuda; pub fn simulate< M: MathsCore, H: Habitat + RustToCuda, - G: PrimeableRng + RustToCuda, + G: Rng + RustToCuda, S: LineageStore + RustToCuda, X: EmigrationExit + RustToCuda, D: DispersalSampler + RustToCuda, diff --git a/rustcoalescence/algorithms/cuda/src/initialiser/fixup.rs b/rustcoalescence/algorithms/cuda/src/initialiser/fixup.rs index 4e91831cc..ab03e1758 100644 --- a/rustcoalescence/algorithms/cuda/src/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/cuda/src/initialiser/fixup.rs @@ -1,5 +1,8 @@ use necsim_core::{ - cogs::{EmigrationExit, MathsCore, PrimeableRng}, + cogs::{ + rng::{Event, IndexUsize, UniformClosedOpenUnit}, + DistributionSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, + }, lineage::Lineage, }; use necsim_core_bond::{NonNegativeF64, PositiveF64}; @@ -43,7 +46,7 @@ pub struct FixUpInitialiser> { impl< L: ExactSizeIterator, M: MathsCore, - G: PrimeableRng + RustToCuda, + G: Rng + RustToCuda, O: Scenario, > CudaLineageStoreSampleInitialiser> for FixUpInitialiser where @@ -51,6 +54,9 @@ where O::DispersalSampler>: RustToCuda, O::TurnoverRate: RustToCuda, O::SpeciationProbability: RustToCuda, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler, { type ActiveLineageSampler< X: EmigrationExit> + RustToCuda, diff --git a/rustcoalescence/algorithms/cuda/src/initialiser/genesis.rs b/rustcoalescence/algorithms/cuda/src/initialiser/genesis.rs index 5f851c286..499f2d0f4 100644 --- a/rustcoalescence/algorithms/cuda/src/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/cuda/src/initialiser/genesis.rs @@ -1,5 +1,8 @@ use necsim_core::{ - cogs::{EmigrationExit, MathsCore, PrimeableRng}, + cogs::{ + rng::{Event, IndexUsize, UniformClosedOpenUnit}, + DistributionSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, + }, lineage::Lineage, }; @@ -23,13 +26,16 @@ use super::CudaLineageStoreSampleInitialiser; #[allow(clippy::module_name_repetitions)] pub struct GenesisInitialiser; -impl + RustToCuda, O: Scenario> +impl + RustToCuda, O: Scenario> CudaLineageStoreSampleInitialiser for GenesisInitialiser where O::Habitat: RustToCuda, O::DispersalSampler>: RustToCuda, O::TurnoverRate: RustToCuda, O::SpeciationProbability: RustToCuda, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler, { type ActiveLineageSampler< X: EmigrationExit> + RustToCuda, diff --git a/rustcoalescence/algorithms/cuda/src/initialiser/mod.rs b/rustcoalescence/algorithms/cuda/src/initialiser/mod.rs index a1a39e87e..09f931146 100644 --- a/rustcoalescence/algorithms/cuda/src/initialiser/mod.rs +++ b/rustcoalescence/algorithms/cuda/src/initialiser/mod.rs @@ -1,5 +1,8 @@ use necsim_core::{ - cogs::{DispersalSampler, EmigrationExit, MathsCore, PrimeableRng}, + cogs::{ + rng::{Event, IndexUsize, UniformClosedOpenUnit}, + DispersalSampler, DistributionSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, + }, lineage::Lineage, }; @@ -28,7 +31,7 @@ pub mod resume; #[allow(clippy::module_name_repetitions)] pub trait CudaLineageStoreSampleInitialiser< M: MathsCore, - G: PrimeableRng + RustToCuda, + G: Rng + RustToCuda, O: Scenario, Error: From, > where @@ -36,6 +39,9 @@ pub trait CudaLineageStoreSampleInitialiser< O::DispersalSampler>: RustToCuda, O::TurnoverRate: RustToCuda, O::SpeciationProbability: RustToCuda, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler, { type DispersalSampler: DispersalSampler + RustToCuda; type ActiveLineageSampler< diff --git a/rustcoalescence/algorithms/cuda/src/initialiser/resume.rs b/rustcoalescence/algorithms/cuda/src/initialiser/resume.rs index 2cba7640b..417bbb08e 100644 --- a/rustcoalescence/algorithms/cuda/src/initialiser/resume.rs +++ b/rustcoalescence/algorithms/cuda/src/initialiser/resume.rs @@ -1,5 +1,8 @@ use necsim_core::{ - cogs::{EmigrationExit, MathsCore, PrimeableRng}, + cogs::{ + rng::{Event, IndexUsize, UniformClosedOpenUnit}, + DistributionSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, + }, lineage::Lineage, }; use necsim_core_bond::NonNegativeF64; @@ -32,7 +35,7 @@ pub struct ResumeInitialiser> { impl< L: ExactSizeIterator, M: MathsCore, - G: PrimeableRng + RustToCuda, + G: Rng + RustToCuda, O: Scenario, > CudaLineageStoreSampleInitialiser> for ResumeInitialiser where @@ -40,6 +43,9 @@ where O::DispersalSampler>: RustToCuda, O::TurnoverRate: RustToCuda, O::SpeciationProbability: RustToCuda, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler, { type ActiveLineageSampler< X: EmigrationExit> + RustToCuda, diff --git a/rustcoalescence/algorithms/cuda/src/launch.rs b/rustcoalescence/algorithms/cuda/src/launch.rs index 40fd18f7b..90cbc9350 100644 --- a/rustcoalescence/algorithms/cuda/src/launch.rs +++ b/rustcoalescence/algorithms/cuda/src/launch.rs @@ -1,6 +1,10 @@ use std::marker::PhantomData; -use necsim_core::{cogs::MathsCore, reporter::Reporter, simulation::SimulationBuilder}; +use necsim_core::{ + cogs::{rng::SimpleRng, MathsCore}, + reporter::Reporter, + simulation::SimulationBuilder, +}; use necsim_core_bond::NonNegativeF64; use necsim_impls_cuda::cogs::rng::CudaRng; @@ -46,35 +50,36 @@ use crate::{ parallelisation, }; -#[allow(clippy::too_many_lines)] +#[allow(clippy::too_many_lines, clippy::type_complexity)] pub fn initialise_and_simulate< 'p, M: MathsCore, - O: Scenario>>, + O: Scenario>>, R: Reporter, P: LocalPartition<'p, R>, I: Iterator, - L: CudaLineageStoreSampleInitialiser>, O, Error>, + L: CudaLineageStoreSampleInitialiser>, O, Error>, Error: From, >( args: &CudaArguments, - rng: CudaRng>, + rng: CudaRng>, scenario: O, pre_sampler: OriginPreSampler, pause_before: Option, local_partition: &mut P, lineage_store_sampler_initialiser: L, -) -> Result>>, Error> +) -> Result>>, Error> where O::Habitat: RustToCuda, - O::DispersalSampler>>>: - RustToCuda, + O::DispersalSampler< + InMemoryPackedAliasDispersalSampler>>, + >: RustToCuda, O::TurnoverRate: RustToCuda, O::SpeciationProbability: RustToCuda, SimulationKernel< M, O::Habitat, - CudaRng>, + CudaRng>, IndependentLineageStore, NeverEmigrationExit, L::DispersalSampler, @@ -84,7 +89,7 @@ where IndependentEventSampler< M, O::Habitat, - CudaRng>, + CudaRng>, NeverEmigrationExit, L::DispersalSampler, O::TurnoverRate, @@ -97,7 +102,7 @@ where >: SimulatableKernel< M, O::Habitat, - CudaRng>, + CudaRng>, IndependentLineageStore, NeverEmigrationExit, L::DispersalSampler, @@ -107,7 +112,7 @@ where IndependentEventSampler< M, O::Habitat, - CudaRng>, + CudaRng>, NeverEmigrationExit, L::DispersalSampler, O::TurnoverRate, @@ -126,8 +131,11 @@ where speciation_probability, origin_sampler_auxiliary, decomposition_auxiliary, - ) = scenario - .build::>>>(); + ) = scenario.build::>, + >>(); let coalescence_sampler = IndependentCoalescenceSampler::default(); let event_sampler = IndependentEventSampler::default(); diff --git a/rustcoalescence/algorithms/cuda/src/lib.rs b/rustcoalescence/algorithms/cuda/src/lib.rs index e2c221dca..a88d58a51 100644 --- a/rustcoalescence/algorithms/cuda/src/lib.rs +++ b/rustcoalescence/algorithms/cuda/src/lib.rs @@ -1,11 +1,16 @@ #![deny(clippy::pedantic)] +#![feature(associated_type_bounds)] #![allow(incomplete_features)] #![feature(inline_const_pat)] #[macro_use] extern crate serde_derive_state; -use necsim_core::{cogs::MathsCore, lineage::Lineage, reporter::Reporter}; +use necsim_core::{ + cogs::{rng::SimpleRng, MathsCore}, + lineage::Lineage, + reporter::Reporter, +}; use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_impls_cuda::cogs::{maths::NvptxMathsCore, rng::CudaRng}; @@ -74,24 +79,25 @@ impl AlgorithmDefaults for CudaAlgorithm { impl< 'p, M: MathsCore, - O: Scenario>>, + O: Scenario>>, R: Reporter, P: LocalPartition<'p, R>, > Algorithm<'p, M, O, R, P> for CudaAlgorithm where O::Habitat: RustToCuda, - O::DispersalSampler>>>: - RustToCuda, + O::DispersalSampler< + InMemoryPackedAliasDispersalSampler>>, + >: RustToCuda, O::TurnoverRate: RustToCuda, O::SpeciationProbability: RustToCuda, SimulationKernel< M, O::Habitat, - CudaRng>, + CudaRng>, IndependentLineageStore, NeverEmigrationExit, O::DispersalSampler< - InMemoryPackedAliasDispersalSampler>>, + InMemoryPackedAliasDispersalSampler>>, >, IndependentCoalescenceSampler, O::TurnoverRate, @@ -99,10 +105,14 @@ where IndependentEventSampler< M, O::Habitat, - CudaRng>, + CudaRng>, NeverEmigrationExit, O::DispersalSampler< - InMemoryPackedAliasDispersalSampler>>, + InMemoryPackedAliasDispersalSampler< + M, + O::Habitat, + CudaRng>, + >, >, O::TurnoverRate, O::SpeciationProbability, @@ -111,10 +121,14 @@ where IndependentActiveLineageSampler< M, O::Habitat, - CudaRng>, + CudaRng>, NeverEmigrationExit, O::DispersalSampler< - InMemoryPackedAliasDispersalSampler>>, + InMemoryPackedAliasDispersalSampler< + M, + O::Habitat, + CudaRng>, + >, >, O::TurnoverRate, O::SpeciationProbability, @@ -125,11 +139,11 @@ where >: SimulatableKernel< M, O::Habitat, - CudaRng>, + CudaRng>, IndependentLineageStore, NeverEmigrationExit, O::DispersalSampler< - InMemoryPackedAliasDispersalSampler>>, + InMemoryPackedAliasDispersalSampler>>, >, IndependentCoalescenceSampler, O::TurnoverRate, @@ -137,10 +151,14 @@ where IndependentEventSampler< M, O::Habitat, - CudaRng>, + CudaRng>, NeverEmigrationExit, O::DispersalSampler< - InMemoryPackedAliasDispersalSampler>>, + InMemoryPackedAliasDispersalSampler< + M, + O::Habitat, + CudaRng>, + >, >, O::TurnoverRate, O::SpeciationProbability, @@ -149,10 +167,14 @@ where IndependentActiveLineageSampler< M, O::Habitat, - CudaRng>, + CudaRng>, NeverEmigrationExit, O::DispersalSampler< - InMemoryPackedAliasDispersalSampler>>, + InMemoryPackedAliasDispersalSampler< + M, + O::Habitat, + CudaRng>, + >, >, O::TurnoverRate, O::SpeciationProbability, @@ -164,17 +186,21 @@ where SimulationKernel< M, O::Habitat, - CudaRng>, + CudaRng>, IndependentLineageStore, NeverEmigrationExit, TrespassingDispersalSampler< M, O::Habitat, - CudaRng>, + CudaRng>, O::DispersalSampler< - InMemoryPackedAliasDispersalSampler>>, + InMemoryPackedAliasDispersalSampler< + M, + O::Habitat, + CudaRng>, + >, >, - UniformAntiTrespassingDispersalSampler>>, + UniformAntiTrespassingDispersalSampler>>, >, IndependentCoalescenceSampler, O::TurnoverRate, @@ -182,16 +208,24 @@ where IndependentEventSampler< M, O::Habitat, - CudaRng>, + CudaRng>, NeverEmigrationExit, TrespassingDispersalSampler< M, O::Habitat, - CudaRng>, + CudaRng>, O::DispersalSampler< - InMemoryPackedAliasDispersalSampler>>, + InMemoryPackedAliasDispersalSampler< + M, + O::Habitat, + CudaRng>, + >, + >, + UniformAntiTrespassingDispersalSampler< + M, + O::Habitat, + CudaRng>, >, - UniformAntiTrespassingDispersalSampler>>, >, O::TurnoverRate, O::SpeciationProbability, @@ -200,16 +234,24 @@ where IndependentActiveLineageSampler< M, O::Habitat, - CudaRng>, + CudaRng>, NeverEmigrationExit, TrespassingDispersalSampler< M, O::Habitat, - CudaRng>, + CudaRng>, O::DispersalSampler< - InMemoryPackedAliasDispersalSampler>>, + InMemoryPackedAliasDispersalSampler< + M, + O::Habitat, + CudaRng>, + >, + >, + UniformAntiTrespassingDispersalSampler< + M, + O::Habitat, + CudaRng>, >, - UniformAntiTrespassingDispersalSampler>>, >, O::TurnoverRate, O::SpeciationProbability, @@ -220,17 +262,21 @@ where >: SimulatableKernel< M, O::Habitat, - CudaRng>, + CudaRng>, IndependentLineageStore, NeverEmigrationExit, TrespassingDispersalSampler< M, O::Habitat, - CudaRng>, + CudaRng>, O::DispersalSampler< - InMemoryPackedAliasDispersalSampler>>, + InMemoryPackedAliasDispersalSampler< + M, + O::Habitat, + CudaRng>, + >, >, - UniformAntiTrespassingDispersalSampler>>, + UniformAntiTrespassingDispersalSampler>>, >, IndependentCoalescenceSampler, O::TurnoverRate, @@ -238,16 +284,24 @@ where IndependentEventSampler< M, O::Habitat, - CudaRng>, + CudaRng>, NeverEmigrationExit, TrespassingDispersalSampler< M, O::Habitat, - CudaRng>, + CudaRng>, O::DispersalSampler< - InMemoryPackedAliasDispersalSampler>>, + InMemoryPackedAliasDispersalSampler< + M, + O::Habitat, + CudaRng>, + >, + >, + UniformAntiTrespassingDispersalSampler< + M, + O::Habitat, + CudaRng>, >, - UniformAntiTrespassingDispersalSampler>>, >, O::TurnoverRate, O::SpeciationProbability, @@ -256,16 +310,24 @@ where IndependentActiveLineageSampler< M, O::Habitat, - CudaRng>, + CudaRng>, NeverEmigrationExit, TrespassingDispersalSampler< M, O::Habitat, - CudaRng>, + CudaRng>, O::DispersalSampler< - InMemoryPackedAliasDispersalSampler>>, + InMemoryPackedAliasDispersalSampler< + M, + O::Habitat, + CudaRng>, + >, + >, + UniformAntiTrespassingDispersalSampler< + M, + O::Habitat, + CudaRng>, >, - UniformAntiTrespassingDispersalSampler>>, >, O::TurnoverRate, O::SpeciationProbability, @@ -276,7 +338,7 @@ where >, { type LineageStore = IndependentLineageStore; - type Rng = CudaRng>; + type Rng = CudaRng>; fn get_logical_partition(args: &Self::Arguments, _local_partition: &P) -> Partition { match &args.parallelism_mode { diff --git a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs index 66e1ff479..7b55fcb89 100644 --- a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs +++ b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs @@ -10,7 +10,7 @@ use rust_cuda::{ use necsim_core::{ cogs::{ CoalescenceSampler, DispersalSampler, EmigrationExit, Habitat, ImmigrationEntry, - LineageStore, MathsCore, PrimeableRng, SpeciationProbability, TurnoverRate, + LineageStore, MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, }, lineage::Lineage, reporter::{boolean::Boolean, Reporter}, @@ -50,7 +50,7 @@ pub fn simulate< 'p, M: MathsCore, H: Habitat + RustToCuda, - G: PrimeableRng + RustToCuda, + G: Rng + RustToCuda, S: LineageStore + RustToCuda, X: EmigrationExit + RustToCuda, D: DispersalSampler + RustToCuda, diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/fixup.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/fixup.rs index fcd0f20a2..1b05a8d52 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/fixup.rs @@ -1,7 +1,8 @@ use necsim_core::{ cogs::{ - EmigrationExit, GloballyCoherentLineageStore, ImmigrationEntry, MathsCore, RngCore, - SeparableDispersalSampler, + rng::{Event, Exponential, IndexU128, IndexU64, IndexUsize, UniformClosedOpenUnit}, + DistributionSampler, EmigrationExit, GloballyCoherentLineageStore, ImmigrationEntry, + MathsCore, Rng, SeparableDispersalSampler, }, event::DispersalEvent, lineage::{Lineage, LineageInteraction}, @@ -45,11 +46,17 @@ pub struct FixUpInitialiser> { pub fixup_strategy: RestartFixUpStrategy, } -impl, M: MathsCore, G: RngCore, O: Scenario> +impl, M: MathsCore, G: Rng, O: Scenario> EventSkippingLineageStoreSampleInitialiser> for FixUpInitialiser where O::DispersalSampler>: SeparableDispersalSampler, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { type ActiveLineageSampler< S: GloballyCoherentLineageStore, diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/genesis.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/genesis.rs index 079a47cd3..8229dd02c 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/genesis.rs @@ -1,7 +1,8 @@ use necsim_core::{ cogs::{ - EmigrationExit, GloballyCoherentLineageStore, ImmigrationEntry, MathsCore, RngCore, - SeparableDispersalSampler, + rng::{Event, Exponential, IndexU128, IndexU64, IndexUsize, UniformClosedOpenUnit}, + DistributionSampler, EmigrationExit, GloballyCoherentLineageStore, ImmigrationEntry, + MathsCore, Rng, SeparableDispersalSampler, }, reporter::Reporter, }; @@ -22,11 +23,17 @@ use super::EventSkippingLineageStoreSampleInitialiser; #[allow(clippy::module_name_repetitions)] pub struct GenesisInitialiser; -impl, O: Scenario> +impl, O: Scenario> EventSkippingLineageStoreSampleInitialiser for GenesisInitialiser where O::DispersalSampler>: SeparableDispersalSampler, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { type ActiveLineageSampler< S: GloballyCoherentLineageStore, diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/mod.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/mod.rs index 2b14b98f9..537dc8e76 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/mod.rs @@ -1,7 +1,8 @@ use necsim_core::{ cogs::{ - ActiveLineageSampler, EmigrationExit, GloballyCoherentLineageStore, ImmigrationEntry, - MathsCore, RngCore, SeparableDispersalSampler, + rng::{Event, IndexUsize, UniformClosedOpenUnit}, + ActiveLineageSampler, DistributionSampler, EmigrationExit, GloballyCoherentLineageStore, + ImmigrationEntry, MathsCore, Rng, SeparableDispersalSampler, }, reporter::Reporter, }; @@ -23,12 +24,15 @@ pub mod resume; #[allow(clippy::module_name_repetitions)] pub trait EventSkippingLineageStoreSampleInitialiser< M: MathsCore, - G: RngCore, + G: Rng, O: Scenario, Error, > where O::DispersalSampler>: SeparableDispersalSampler, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler, { type DispersalSampler: SeparableDispersalSampler; type ActiveLineageSampler< diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/resume.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/resume.rs index 5ae570961..a2ba351e6 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/resume.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/resume.rs @@ -1,7 +1,8 @@ use necsim_core::{ cogs::{ - EmigrationExit, GloballyCoherentLineageStore, ImmigrationEntry, MathsCore, RngCore, - SeparableDispersalSampler, + rng::{Event, Exponential, IndexU128, IndexU64, IndexUsize, UniformClosedOpenUnit}, + DistributionSampler, EmigrationExit, GloballyCoherentLineageStore, ImmigrationEntry, + MathsCore, Rng, SeparableDispersalSampler, }, lineage::Lineage, reporter::Reporter, @@ -28,11 +29,18 @@ pub struct ResumeInitialiser> { pub resume_after: Option, } -impl, M: MathsCore, G: RngCore, O: Scenario> +#[allow(clippy::type_complexity)] +impl, M: MathsCore, G: Rng, O: Scenario> EventSkippingLineageStoreSampleInitialiser> for ResumeInitialiser where O::DispersalSampler>: SeparableDispersalSampler, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { type ActiveLineageSampler< S: GloballyCoherentLineageStore, diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs index 5fa1e4391..a8dc76277 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs @@ -2,8 +2,9 @@ use std::{hint::unreachable_unchecked, marker::PhantomData}; use necsim_core::{ cogs::{ - ActiveLineageSampler, GloballyCoherentLineageStore, MathsCore, SeparableDispersalSampler, - SplittableRng, + rng::{Event, IndexUsize, UniformClosedOpenUnit}, + ActiveLineageSampler, DistributionSampler, GloballyCoherentLineageStore, MathsCore, Rng, + SeparableDispersalSampler, SplittableRng, }, reporter::Reporter, simulation::SimulationBuilder, @@ -37,7 +38,7 @@ use crate::arguments::{ pub fn initialise_and_simulate< 'p, M: MathsCore, - G: SplittableRng, + G: Rng, O: Scenario, R: Reporter, P: LocalPartition<'p, R>, @@ -58,6 +59,9 @@ where GloballyCoherentLineageStore, O::DispersalSampler>: SeparableDispersalSampler, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler, { match args.parallelism_mode { ParallelismMode::Monolithic => { @@ -129,7 +133,9 @@ where } }, non_monolithic_parallelism_mode => { - let rng = rng.split_to_stream(u64::from(local_partition.get_partition().rank())); + let rng = rng.map_generator(|rng| { + rng.split_to_stream(u64::from(local_partition.get_partition().rank())) + }); let ( habitat, diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/mod.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/mod.rs index 4dc2bfa4e..f67f83e60 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/mod.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{GloballyCoherentLineageStore, MathsCore, SeparableDispersalSampler}, + cogs::{rng::SimpleRng, GloballyCoherentLineageStore, MathsCore, SeparableDispersalSampler}, lineage::Lineage, reporter::Reporter, }; @@ -41,16 +41,21 @@ impl AlgorithmDefaults for EventSkippingAlgorithm { type MathsCore = IntrinsicsMathsCore; } -impl<'p, O: Scenario>, R: Reporter, P: LocalPartition<'p, R>, M: MathsCore> - Algorithm<'p, M, O, R, P> for EventSkippingAlgorithm +impl< + 'p, + O: Scenario>, + R: Reporter, + P: LocalPartition<'p, R>, + M: MathsCore, + > Algorithm<'p, M, O, R, P> for EventSkippingAlgorithm where O::LineageStore>: GloballyCoherentLineageStore, - O::DispersalSampler>>: - SeparableDispersalSampler>, + O::DispersalSampler>>: + SeparableDispersalSampler>, { type LineageStore = O::LineageStore>; - type Rng = Pcg; + type Rng = SimpleRng; fn get_logical_partition(args: &Self::Arguments, local_partition: &P) -> Partition { get_gillespie_logical_partition(args, local_partition) diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs index 5e6f21e03..16121c022 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs @@ -1,5 +1,9 @@ use necsim_core::{ - cogs::{EmigrationExit, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, RngCore}, + cogs::{ + rng::{Event, Exponential, IndexUsize, UniformClosedOpenUnit}, + DistributionSampler, EmigrationExit, ImmigrationEntry, LocallyCoherentLineageStore, + MathsCore, Rng, + }, event::DispersalEvent, lineage::{Lineage, LineageInteraction}, reporter::Reporter, @@ -43,8 +47,13 @@ pub struct FixUpInitialiser> { pub fixup_strategy: RestartFixUpStrategy, } -impl, M: MathsCore, G: RngCore, O: Scenario> +impl, M: MathsCore, G: Rng, O: Scenario> ClassicalLineageStoreSampleInitialiser> for FixUpInitialiser +where + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { type ActiveLineageSampler< S: LocallyCoherentLineageStore, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/genesis.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/genesis.rs index 4d8529154..f6ba30fdc 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/genesis.rs @@ -1,5 +1,9 @@ use necsim_core::{ - cogs::{EmigrationExit, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, RngCore}, + cogs::{ + rng::{Event, Exponential, IndexUsize, UniformClosedOpenUnit}, + DistributionSampler, EmigrationExit, ImmigrationEntry, LocallyCoherentLineageStore, + MathsCore, Rng, + }, reporter::Reporter, }; @@ -17,8 +21,13 @@ use super::ClassicalLineageStoreSampleInitialiser; #[allow(clippy::module_name_repetitions)] pub struct GenesisInitialiser; -impl, O: Scenario> - ClassicalLineageStoreSampleInitialiser for GenesisInitialiser +impl, O: Scenario> ClassicalLineageStoreSampleInitialiser + for GenesisInitialiser +where + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { type ActiveLineageSampler< S: LocallyCoherentLineageStore, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/mod.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/mod.rs index f03b13e2a..f5226dbe3 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/mod.rs @@ -1,7 +1,8 @@ use necsim_core::{ cogs::{ - ActiveLineageSampler, DispersalSampler, EmigrationExit, ImmigrationEntry, - LocallyCoherentLineageStore, MathsCore, RngCore, + rng::{Event, IndexUsize, UniformClosedOpenUnit}, + ActiveLineageSampler, DispersalSampler, DistributionSampler, EmigrationExit, + ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, }, reporter::Reporter, }; @@ -21,12 +22,11 @@ pub mod genesis; pub mod resume; #[allow(clippy::module_name_repetitions)] -pub trait ClassicalLineageStoreSampleInitialiser< - M: MathsCore, - G: RngCore, - O: Scenario, - Error, -> +pub trait ClassicalLineageStoreSampleInitialiser, O: Scenario, Error> +where + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler, { type DispersalSampler: DispersalSampler; type ActiveLineageSampler< diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/resume.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/resume.rs index a2c313ccd..72254ed31 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/resume.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/resume.rs @@ -1,5 +1,9 @@ use necsim_core::{ - cogs::{EmigrationExit, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, RngCore}, + cogs::{ + rng::{Event, Exponential, IndexUsize, UniformClosedOpenUnit}, + DistributionSampler, EmigrationExit, ImmigrationEntry, LocallyCoherentLineageStore, + MathsCore, Rng, + }, lineage::Lineage, reporter::Reporter, }; @@ -23,8 +27,13 @@ pub struct ResumeInitialiser> { pub resume_after: Option, } -impl, M: MathsCore, G: RngCore, O: Scenario> +impl, M: MathsCore, G: Rng, O: Scenario> ClassicalLineageStoreSampleInitialiser> for ResumeInitialiser +where + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { type ActiveLineageSampler< S: LocallyCoherentLineageStore, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs index e770d1d3e..5321faaa8 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs @@ -1,7 +1,11 @@ use std::{hint::unreachable_unchecked, marker::PhantomData}; use necsim_core::{ - cogs::{ActiveLineageSampler, LocallyCoherentLineageStore, MathsCore, SplittableRng}, + cogs::{ + rng::{Event, IndexUsize, UniformClosedOpenUnit}, + ActiveLineageSampler, DistributionSampler, LocallyCoherentLineageStore, MathsCore, Rng, + SplittableRng, + }, reporter::Reporter, simulation::SimulationBuilder, }; @@ -37,7 +41,7 @@ use super::initialiser::ClassicalLineageStoreSampleInitialiser; pub fn initialise_and_simulate< 'p, M: MathsCore, - G: SplittableRng, + G: Rng, O: Scenario, R: Reporter, P: LocalPartition<'p, R>, @@ -56,6 +60,9 @@ pub fn initialise_and_simulate< where O::LineageStore>: LocallyCoherentLineageStore, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler, { match args.parallelism_mode { ParallelismMode::Monolithic => { @@ -124,7 +131,9 @@ where } }, non_monolithic_parallelism_mode => { - let rng = rng.split_to_stream(u64::from(local_partition.get_partition().rank())); + let rng = rng.map_generator(|rng| { + rng.split_to_stream(u64::from(local_partition.get_partition().rank())) + }); let ( habitat, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/mod.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/mod.rs index 06114bca7..a2fbf3f77 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/mod.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{LocallyCoherentLineageStore, MathsCore}, + cogs::{rng::SimpleRng, LocallyCoherentLineageStore, MathsCore}, lineage::Lineage, reporter::Reporter, }; @@ -31,7 +31,7 @@ use initialiser::{ // Optimised 'Classical' implementation for the `UniformTurnoverSampler` impl< 'p, - O: Scenario, TurnoverRate = UniformTurnoverRate>, + O: Scenario, TurnoverRate = UniformTurnoverRate>, R: Reporter, P: LocalPartition<'p, R>, M: MathsCore, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/fixup.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/fixup.rs index 66243468d..ed4797930 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/fixup.rs @@ -1,7 +1,8 @@ use necsim_core::{ cogs::{ - CoalescenceSampler, EmigrationExit, EventSampler, ImmigrationEntry, - LocallyCoherentLineageStore, MathsCore, RngCore, + rng::{Event, Exponential, IndexU128, IndexU64, IndexUsize}, + CoalescenceSampler, DistributionSampler, EmigrationExit, EventSampler, ImmigrationEntry, + LocallyCoherentLineageStore, MathsCore, Rng, }, event::DispersalEvent, lineage::{Lineage, LineageInteraction}, @@ -43,8 +44,14 @@ pub struct FixUpInitialiser> { pub fixup_strategy: RestartFixUpStrategy, } -impl, M: MathsCore, G: RngCore, O: Scenario> +impl, M: MathsCore, G: Rng, O: Scenario> GillespieLineageStoreSampleInitialiser> for FixUpInitialiser +where + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { type ActiveLineageSampler< S: LocallyCoherentLineageStore, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/genesis.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/genesis.rs index b3a4f8430..40704a80d 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/genesis.rs @@ -1,7 +1,8 @@ use necsim_core::{ cogs::{ - CoalescenceSampler, EmigrationExit, EventSampler, ImmigrationEntry, - LocallyCoherentLineageStore, MathsCore, RngCore, + rng::{Event, Exponential, IndexU128, IndexU64, IndexUsize}, + CoalescenceSampler, DistributionSampler, EmigrationExit, EventSampler, ImmigrationEntry, + LocallyCoherentLineageStore, MathsCore, Rng, }, reporter::Reporter, }; @@ -20,8 +21,14 @@ use super::GillespieLineageStoreSampleInitialiser; #[allow(clippy::module_name_repetitions)] pub struct GenesisInitialiser; -impl, O: Scenario> - GillespieLineageStoreSampleInitialiser for GenesisInitialiser +impl, O: Scenario> GillespieLineageStoreSampleInitialiser + for GenesisInitialiser +where + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { type ActiveLineageSampler< S: LocallyCoherentLineageStore, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/mod.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/mod.rs index cee39068f..eadba6dc8 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/mod.rs @@ -1,7 +1,9 @@ use necsim_core::{ cogs::{ - ActiveLineageSampler, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, - ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, RngCore, + rng::{Event, IndexUsize}, + ActiveLineageSampler, CoalescenceSampler, DispersalSampler, DistributionSampler, + EmigrationExit, EventSampler, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, + Rng, }, reporter::Reporter, }; @@ -19,12 +21,10 @@ pub mod genesis; pub mod resume; #[allow(clippy::module_name_repetitions)] -pub trait GillespieLineageStoreSampleInitialiser< - M: MathsCore, - G: RngCore, - O: Scenario, - Error, -> +pub trait GillespieLineageStoreSampleInitialiser, O: Scenario, Error> +where + G::Sampler: DistributionSampler + + DistributionSampler, { type DispersalSampler: DispersalSampler; type ActiveLineageSampler< diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/resume.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/resume.rs index 2e1264ef5..060ae98a8 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/resume.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/resume.rs @@ -1,7 +1,8 @@ use necsim_core::{ cogs::{ - CoalescenceSampler, EmigrationExit, EventSampler, ImmigrationEntry, - LocallyCoherentLineageStore, MathsCore, RngCore, + rng::{Event, Exponential, IndexU128, IndexU64, IndexUsize}, + CoalescenceSampler, DistributionSampler, EmigrationExit, EventSampler, ImmigrationEntry, + LocallyCoherentLineageStore, MathsCore, Rng, }, lineage::Lineage, reporter::Reporter, @@ -26,8 +27,14 @@ pub struct ResumeInitialiser> { pub resume_after: Option, } -impl, M: MathsCore, G: RngCore, O: Scenario> +impl, M: MathsCore, G: Rng, O: Scenario> GillespieLineageStoreSampleInitialiser> for ResumeInitialiser +where + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, { type ActiveLineageSampler< S: LocallyCoherentLineageStore, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs index 4f23dea77..b106364b8 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs @@ -1,7 +1,11 @@ use std::{hint::unreachable_unchecked, marker::PhantomData}; use necsim_core::{ - cogs::{ActiveLineageSampler, LocallyCoherentLineageStore, MathsCore, SplittableRng}, + cogs::{ + rng::{Event, IndexUsize, UniformClosedOpenUnit}, + ActiveLineageSampler, DistributionSampler, LocallyCoherentLineageStore, MathsCore, Rng, + SplittableRng, + }, reporter::Reporter, simulation::SimulationBuilder, }; @@ -36,7 +40,7 @@ use super::initialiser::GillespieLineageStoreSampleInitialiser; pub fn initialise_and_simulate< 'p, M: MathsCore, - G: SplittableRng, + G: Rng, O: Scenario, R: Reporter, P: LocalPartition<'p, R>, @@ -55,6 +59,9 @@ pub fn initialise_and_simulate< where O::LineageStore>: LocallyCoherentLineageStore, + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler, { match args.parallelism_mode { ParallelismMode::Monolithic => { @@ -124,7 +131,9 @@ where } }, non_monolithic_parallelism_mode => { - let rng = rng.split_to_stream(u64::from(local_partition.get_partition().rank())); + let rng = rng.map_generator(|rng| { + rng.split_to_stream(u64::from(local_partition.get_partition().rank())) + }); let ( habitat, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/mod.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/mod.rs index 7f44e6280..3aac781a1 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/mod.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{LocallyCoherentLineageStore, MathsCore}, + cogs::{rng::SimpleRng, LocallyCoherentLineageStore, MathsCore}, lineage::Lineage, reporter::Reporter, }; @@ -31,14 +31,19 @@ use initialiser::{ }; // Default 'Gillespie' implementation for any turnover sampler -impl<'p, O: Scenario>, R: Reporter, P: LocalPartition<'p, R>, M: MathsCore> - Algorithm<'p, M, O, R, P> for GillespieAlgorithm +impl< + 'p, + O: Scenario>, + R: Reporter, + P: LocalPartition<'p, R>, + M: MathsCore, + > Algorithm<'p, M, O, R, P> for GillespieAlgorithm where O::LineageStore>: LocallyCoherentLineageStore, { type LineageStore = O::LineageStore>; - type Rng = Pcg; + type Rng = SimpleRng; default fn get_logical_partition(args: &Self::Arguments, local_partition: &P) -> Partition { get_gillespie_logical_partition(args, local_partition) diff --git a/rustcoalescence/algorithms/gillespie/src/lib.rs b/rustcoalescence/algorithms/gillespie/src/lib.rs index 2cb62f1b1..82ba4c5ed 100644 --- a/rustcoalescence/algorithms/gillespie/src/lib.rs +++ b/rustcoalescence/algorithms/gillespie/src/lib.rs @@ -1,5 +1,6 @@ #![deny(clippy::pedantic)] #![feature(never_type)] +#![feature(associated_type_bounds)] #![allow(incomplete_features)] #![feature(specialization)] diff --git a/rustcoalescence/algorithms/independent/src/initialiser/fixup.rs b/rustcoalescence/algorithms/independent/src/initialiser/fixup.rs index 8ed395c40..ddca78463 100644 --- a/rustcoalescence/algorithms/independent/src/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/independent/src/initialiser/fixup.rs @@ -1,5 +1,8 @@ use necsim_core::{ - cogs::{EmigrationExit, MathsCore, PrimeableRng}, + cogs::{ + rng::{Event, IndexUsize, UniformClosedOpenUnit}, + DistributionSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, + }, lineage::Lineage, }; use necsim_core_bond::{NonNegativeF64, PositiveF64}; @@ -36,8 +39,16 @@ pub struct FixUpInitialiser> { pub fixup_strategy: RestartFixUpStrategy, } -impl, M: MathsCore, G: PrimeableRng, O: Scenario> - IndependentLineageStoreSampleInitialiser> for FixUpInitialiser +impl< + L: ExactSizeIterator, + M: MathsCore, + G: Rng, + O: Scenario, + > IndependentLineageStoreSampleInitialiser> for FixUpInitialiser +where + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler, { type ActiveLineageSampler< X: EmigrationExit>, diff --git a/rustcoalescence/algorithms/independent/src/initialiser/genesis.rs b/rustcoalescence/algorithms/independent/src/initialiser/genesis.rs index 6d960f0e5..f00285217 100644 --- a/rustcoalescence/algorithms/independent/src/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/independent/src/initialiser/genesis.rs @@ -1,5 +1,8 @@ use necsim_core::{ - cogs::{EmigrationExit, MathsCore, PrimeableRng}, + cogs::{ + rng::{Event, IndexUsize, UniformClosedOpenUnit}, + DistributionSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, + }, lineage::Lineage, }; @@ -19,8 +22,12 @@ use super::IndependentLineageStoreSampleInitialiser; #[allow(clippy::module_name_repetitions)] pub struct GenesisInitialiser; -impl, O: Scenario> +impl, O: Scenario> IndependentLineageStoreSampleInitialiser for GenesisInitialiser +where + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler, { type ActiveLineageSampler< X: EmigrationExit>, diff --git a/rustcoalescence/algorithms/independent/src/initialiser/mod.rs b/rustcoalescence/algorithms/independent/src/initialiser/mod.rs index d62dc31d6..f54da064d 100644 --- a/rustcoalescence/algorithms/independent/src/initialiser/mod.rs +++ b/rustcoalescence/algorithms/independent/src/initialiser/mod.rs @@ -1,5 +1,8 @@ use necsim_core::{ - cogs::{DispersalSampler, EmigrationExit, MathsCore, PrimeableRng}, + cogs::{ + rng::{Event, IndexUsize, UniformClosedOpenUnit}, + DispersalSampler, DistributionSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, + }, lineage::Lineage, }; @@ -24,10 +27,13 @@ pub mod resume; #[allow(clippy::module_name_repetitions)] pub trait IndependentLineageStoreSampleInitialiser< M: MathsCore, - G: PrimeableRng, + G: Rng, O: Scenario, Error, -> +> where + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler, { type DispersalSampler: DispersalSampler; type ActiveLineageSampler> { pub resume_after: Option, } -impl, M: MathsCore, G: PrimeableRng, O: Scenario> - IndependentLineageStoreSampleInitialiser> for ResumeInitialiser +impl< + L: ExactSizeIterator, + M: MathsCore, + G: Rng, + O: Scenario, + > IndependentLineageStoreSampleInitialiser> for ResumeInitialiser +where + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler, { type ActiveLineageSampler< X: EmigrationExit>, diff --git a/rustcoalescence/algorithms/independent/src/launch.rs b/rustcoalescence/algorithms/independent/src/launch.rs index a16586f88..bd0f88e53 100644 --- a/rustcoalescence/algorithms/independent/src/launch.rs +++ b/rustcoalescence/algorithms/independent/src/launch.rs @@ -1,7 +1,10 @@ use std::marker::PhantomData; use necsim_core::{ - cogs::{MathsCore, PrimeableRng}, + cogs::{ + rng::{Event, IndexUsize, Normal2D, UniformClosedOpenUnit}, + DistributionSampler, MathsCore, PrimeableRng, Rng, + }, reporter::Reporter, simulation::SimulationBuilder, }; @@ -46,7 +49,7 @@ use crate::{ pub fn initialise_and_simulate< 'p, M: MathsCore, - G: PrimeableRng, + G: Rng, O: Scenario, R: Reporter, P: LocalPartition<'p, R>, @@ -61,7 +64,13 @@ pub fn initialise_and_simulate< pause_before: Option, local_partition: &mut P, lineage_store_sampler_initialiser: L, -) -> Result, Error> { +) -> Result, Error> +where + G::Sampler: DistributionSampler + + DistributionSampler + + DistributionSampler + + DistributionSampler, +{ match args.parallelism_mode { ParallelismMode::Monolithic(MonolithicParallelismMode { event_slice }) | ParallelismMode::IsolatedIndividuals(IsolatedParallelismMode { event_slice, .. }) diff --git a/rustcoalescence/algorithms/independent/src/lib.rs b/rustcoalescence/algorithms/independent/src/lib.rs index 8a7d0473d..faa502de1 100644 --- a/rustcoalescence/algorithms/independent/src/lib.rs +++ b/rustcoalescence/algorithms/independent/src/lib.rs @@ -1,10 +1,15 @@ #![deny(clippy::pedantic)] #![feature(never_type)] +#![feature(associated_type_bounds)] #[macro_use] extern crate serde_derive_state; -use necsim_core::{cogs::MathsCore, lineage::Lineage, reporter::Reporter}; +use necsim_core::{ + cogs::{rng::SimpleRng, MathsCore}, + lineage::Lineage, + reporter::Reporter, +}; use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_impls_no_std::cogs::{ @@ -41,11 +46,16 @@ impl AlgorithmDefaults for IndependentAlgorithm { type MathsCore = IntrinsicsMathsCore; } -impl<'p, O: Scenario>, R: Reporter, P: LocalPartition<'p, R>, M: MathsCore> - Algorithm<'p, M, O, R, P> for IndependentAlgorithm +impl< + 'p, + O: Scenario>, + R: Reporter, + P: LocalPartition<'p, R>, + M: MathsCore, + > Algorithm<'p, M, O, R, P> for IndependentAlgorithm { type LineageStore = IndependentLineageStore; - type Rng = WyHash; + type Rng = SimpleRng; fn get_logical_partition(args: &Self::Arguments, local_partition: &P) -> Partition { match &args.parallelism_mode { diff --git a/rustcoalescence/algorithms/src/lib.rs b/rustcoalescence/algorithms/src/lib.rs index 7ed7ce88a..2c1138524 100644 --- a/rustcoalescence/algorithms/src/lib.rs +++ b/rustcoalescence/algorithms/src/lib.rs @@ -3,7 +3,7 @@ use std::error::Error as StdError; use necsim_core::{ - cogs::{LineageStore, MathsCore, RngCore}, + cogs::{LineageStore, MathsCore, Rng}, lineage::Lineage, reporter::Reporter, }; @@ -37,7 +37,7 @@ pub trait Algorithm< P: LocalPartition<'p, R>, >: Sized + AlgorithmParamters + AlgorithmDefaults { - type Rng: RngCore; + type Rng: Rng; type LineageStore: LineageStore; fn get_logical_partition(args: &Self::Arguments, local_partition: &P) -> Partition; diff --git a/rustcoalescence/algorithms/src/result.rs b/rustcoalescence/algorithms/src/result.rs index 6fa2d4b4d..cf1c7c98d 100644 --- a/rustcoalescence/algorithms/src/result.rs +++ b/rustcoalescence/algorithms/src/result.rs @@ -1,14 +1,14 @@ use std::{error::Error as StdError, fmt, marker::PhantomData}; use necsim_core::{ - cogs::{MathsCore, RngCore}, + cogs::{MathsCore, Rng}, lineage::Lineage, }; use necsim_core_bond::NonNegativeF64; use necsim_impls_no_std::cogs::active_lineage_sampler::resuming::lineage::ExceptionalLineage; -pub enum SimulationOutcome> { +pub enum SimulationOutcome> { Done { time: NonNegativeF64, steps: u64, diff --git a/rustcoalescence/scenarios/src/almost_infinite.rs b/rustcoalescence/scenarios/src/almost_infinite.rs index 7b0e7c805..8d645589c 100644 --- a/rustcoalescence/scenarios/src/almost_infinite.rs +++ b/rustcoalescence/scenarios/src/almost_infinite.rs @@ -1,6 +1,8 @@ use serde::{Deserialize, Serialize}; -use necsim_core::cogs::{DispersalSampler, LineageStore, MathsCore, RngCore}; +use necsim_core::cogs::{ + rng::Normal2D, DispersalSampler, DistributionSampler, LineageStore, MathsCore, Rng, +}; use necsim_core_bond::{NonNegativeF64, OpenClosedUnitF64 as PositiveUnitF64}; use necsim_partitioning_core::partition::Partition; @@ -21,7 +23,10 @@ use necsim_impls_no_std::{ use crate::{Scenario, ScenarioParameters}; #[allow(clippy::module_name_repetitions)] -pub struct AlmostInfiniteScenario> { +pub struct AlmostInfiniteScenario> +where + G::Sampler: DistributionSampler, +{ radius: u16, habitat: AlmostInfiniteHabitat, @@ -38,12 +43,18 @@ pub struct AlmostInfiniteArguments { pub sigma: NonNegativeF64, } -impl> ScenarioParameters for AlmostInfiniteScenario { +impl> ScenarioParameters for AlmostInfiniteScenario +where + G::Sampler: DistributionSampler, +{ type Arguments = AlmostInfiniteArguments; type Error = !; } -impl> Scenario for AlmostInfiniteScenario { +impl> Scenario for AlmostInfiniteScenario +where + G::Sampler: DistributionSampler, +{ type Decomposition = RadialDecomposition; type DecompositionAuxiliary = (); type DispersalSampler> = diff --git a/rustcoalescence/scenarios/src/lib.rs b/rustcoalescence/scenarios/src/lib.rs index 8f8dfc13a..05bd7a7ac 100644 --- a/rustcoalescence/scenarios/src/lib.rs +++ b/rustcoalescence/scenarios/src/lib.rs @@ -6,7 +6,7 @@ extern crate log; use necsim_core::cogs::{ - DispersalSampler, LineageStore, MathsCore, RngCore, SpeciationProbability, TurnoverRate, + DispersalSampler, LineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, UniformlySampleableHabitat, }; use necsim_core_bond::OpenClosedUnitF64 as PositiveUnitF64; @@ -31,7 +31,7 @@ pub trait ScenarioParameters { type Error; } -pub trait Scenario>: Sized + ScenarioParameters { +pub trait Scenario>: Sized + ScenarioParameters { type Habitat: UniformlySampleableHabitat; type OriginSampler<'h, I: Iterator>: TrustedOriginSampler< 'h, diff --git a/rustcoalescence/scenarios/src/non_spatial.rs b/rustcoalescence/scenarios/src/non_spatial.rs index 9e5d15b94..7bb043702 100644 --- a/rustcoalescence/scenarios/src/non_spatial.rs +++ b/rustcoalescence/scenarios/src/non_spatial.rs @@ -2,7 +2,9 @@ use std::num::NonZeroU32; use serde::{Deserialize, Serialize}; -use necsim_core::cogs::{DispersalSampler, LineageStore, MathsCore, RngCore}; +use necsim_core::cogs::{ + rng::IndexU64, DispersalSampler, DistributionSampler, LineageStore, MathsCore, Rng, +}; use necsim_core_bond::{OffByOneU32, OpenClosedUnitF64 as PositiveUnitF64}; use necsim_partitioning_core::partition::Partition; @@ -20,7 +22,10 @@ use necsim_impls_no_std::{ use crate::{Scenario, ScenarioParameters}; #[allow(clippy::module_name_repetitions)] -pub struct NonSpatialScenario> { +pub struct NonSpatialScenario> +where + G::Sampler: DistributionSampler, +{ habitat: NonSpatialHabitat, dispersal_sampler: NonSpatialDispersalSampler, turnover_rate: UniformTurnoverRate, @@ -34,12 +39,18 @@ pub struct NonSpatialArguments { pub deme: NonZeroU32, } -impl> ScenarioParameters for NonSpatialScenario { +impl> ScenarioParameters for NonSpatialScenario +where + G::Sampler: DistributionSampler, +{ type Arguments = NonSpatialArguments; type Error = !; } -impl> Scenario for NonSpatialScenario { +impl> Scenario for NonSpatialScenario +where + G::Sampler: DistributionSampler, +{ type Decomposition = ModuloDecomposition; type DecompositionAuxiliary = (); type DispersalSampler> = diff --git a/rustcoalescence/scenarios/src/spatially_explicit/turnover/map.rs b/rustcoalescence/scenarios/src/spatially_explicit/turnover/map.rs index 34786cd4c..973f888ab 100644 --- a/rustcoalescence/scenarios/src/spatially_explicit/turnover/map.rs +++ b/rustcoalescence/scenarios/src/spatially_explicit/turnover/map.rs @@ -2,7 +2,9 @@ use std::{convert::TryFrom, marker::PhantomData, path::PathBuf}; use serde::{Deserialize, Serialize, Serializer}; -use necsim_core::cogs::{DispersalSampler, Habitat, LineageStore, MathsCore, RngCore}; +use necsim_core::cogs::{ + rng::IndexU64, DispersalSampler, DistributionSampler, Habitat, LineageStore, MathsCore, Rng, +}; use necsim_core_bond::{NonNegativeF64, OpenClosedUnitF64 as PositiveUnitF64}; use necsim_partitioning_core::partition::Partition; @@ -38,7 +40,10 @@ pub enum SpatiallyExplicitTurnoverMapScenarioError { } #[allow(clippy::module_name_repetitions)] -pub struct SpatiallyExplicitTurnoverMapScenario> { +pub struct SpatiallyExplicitTurnoverMapScenario> +where + G::Sampler: DistributionSampler, +{ habitat: InMemoryHabitat, dispersal_map: Array2D, turnover_rate: InMemoryTurnoverRate, @@ -46,14 +51,18 @@ pub struct SpatiallyExplicitTurnoverMapScenario> { _marker: PhantomData, } -impl> ScenarioParameters - for SpatiallyExplicitTurnoverMapScenario +impl> ScenarioParameters for SpatiallyExplicitTurnoverMapScenario +where + G::Sampler: DistributionSampler, { type Arguments = SpatiallyExplicitTurnoverMapArguments; type Error = SpatiallyExplicitTurnoverMapScenarioError; } -impl> Scenario for SpatiallyExplicitTurnoverMapScenario { +impl> Scenario for SpatiallyExplicitTurnoverMapScenario +where + G::Sampler: DistributionSampler, +{ type Decomposition = EqualDecomposition; type DecompositionAuxiliary = (); type DispersalSampler> = D; diff --git a/rustcoalescence/scenarios/src/spatially_explicit/turnover/uniform.rs b/rustcoalescence/scenarios/src/spatially_explicit/turnover/uniform.rs index f87f41e40..fed318aa6 100644 --- a/rustcoalescence/scenarios/src/spatially_explicit/turnover/uniform.rs +++ b/rustcoalescence/scenarios/src/spatially_explicit/turnover/uniform.rs @@ -2,7 +2,9 @@ use std::{convert::TryFrom, marker::PhantomData, path::PathBuf}; use serde::{Deserialize, Serialize, Serializer}; -use necsim_core::cogs::{DispersalSampler, Habitat, LineageStore, MathsCore, RngCore}; +use necsim_core::cogs::{ + rng::IndexU64, DispersalSampler, DistributionSampler, Habitat, LineageStore, MathsCore, Rng, +}; use necsim_core_bond::{NonNegativeF64, OpenClosedUnitF64 as PositiveUnitF64, PositiveF64}; use necsim_partitioning_core::partition::Partition; @@ -36,7 +38,10 @@ pub enum SpatiallyExplicitUniformTurnoverScenarioError { } #[allow(clippy::module_name_repetitions)] -pub struct SpatiallyExplicitUniformTurnoverScenario> { +pub struct SpatiallyExplicitUniformTurnoverScenario> +where + G::Sampler: DistributionSampler, +{ habitat: InMemoryHabitat, dispersal_map: Array2D, turnover_rate: UniformTurnoverRate, @@ -44,15 +49,17 @@ pub struct SpatiallyExplicitUniformTurnoverScenario> _marker: PhantomData, } -impl> ScenarioParameters - for SpatiallyExplicitUniformTurnoverScenario +impl> ScenarioParameters for SpatiallyExplicitUniformTurnoverScenario +where + G::Sampler: DistributionSampler, { type Arguments = SpatiallyExplicitUniformTurnoverArguments; type Error = SpatiallyExplicitUniformTurnoverScenarioError; } -impl> Scenario - for SpatiallyExplicitUniformTurnoverScenario +impl> Scenario for SpatiallyExplicitUniformTurnoverScenario +where + G::Sampler: DistributionSampler, { type Decomposition = EqualDecomposition; type DecompositionAuxiliary = (); diff --git a/rustcoalescence/scenarios/src/spatially_implicit.rs b/rustcoalescence/scenarios/src/spatially_implicit.rs index 8c6ed774f..37a64f123 100644 --- a/rustcoalescence/scenarios/src/spatially_implicit.rs +++ b/rustcoalescence/scenarios/src/spatially_implicit.rs @@ -2,7 +2,10 @@ use std::num::NonZeroU32; use serde::{Deserialize, Serialize}; -use necsim_core::cogs::{DispersalSampler, LineageStore, MathsCore, RngCore}; +use necsim_core::cogs::{ + rng::{Event, IndexU64}, + DispersalSampler, DistributionSampler, LineageStore, MathsCore, Rng, +}; use necsim_core_bond::{OffByOneU32, OpenClosedUnitF64 as PositiveUnitF64}; use necsim_partitioning_core::partition::Partition; @@ -22,7 +25,11 @@ use necsim_impls_no_std::{ use crate::{Scenario, ScenarioParameters}; #[allow(clippy::module_name_repetitions)] -pub struct SpatiallyImplicitScenario> { +pub struct SpatiallyImplicitScenario> +where + G::Sampler: DistributionSampler + + DistributionSampler, +{ habitat: SpatiallyImplicitHabitat, dispersal_sampler: SpatiallyImplicitDispersalSampler, turnover_rate: UniformTurnoverRate, @@ -41,12 +48,20 @@ pub struct SpatiallyImplicitArguments { pub migration_probability_per_generation: PositiveUnitF64, } -impl> ScenarioParameters for SpatiallyImplicitScenario { +impl> ScenarioParameters for SpatiallyImplicitScenario +where + G::Sampler: DistributionSampler + + DistributionSampler, +{ type Arguments = SpatiallyImplicitArguments; type Error = !; } -impl> Scenario for SpatiallyImplicitScenario { +impl> Scenario for SpatiallyImplicitScenario +where + G::Sampler: DistributionSampler + + DistributionSampler, +{ type Decomposition = ModuloDecomposition; type DecompositionAuxiliary = (); type DispersalSampler> = diff --git a/rustcoalescence/src/args/config/rng/mod.rs b/rustcoalescence/src/args/config/rng/mod.rs index 6899a848a..406800030 100644 --- a/rustcoalescence/src/args/config/rng/mod.rs +++ b/rustcoalescence/src/args/config/rng/mod.rs @@ -3,7 +3,7 @@ use std::{fmt, marker::PhantomData}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_state::DeserializeState; -use necsim_core::cogs::{MathsCore, RngCore}; +use necsim_core::cogs::{MathsCore, Rng}; use necsim_partitioning_core::partition::Partition; mod base32; @@ -12,19 +12,21 @@ use self::base32::Base32String; #[derive(Debug, Serialize)] #[serde(bound = "")] -pub enum Rng> { +#[serde(rename = "Rng")] +#[allow(clippy::module_name_repetitions)] +pub enum RngConfig> { Seed(u64), Sponge(Base32String), State(Base32RngState), } #[allow(dead_code)] -pub struct Base32RngState> { +pub struct Base32RngState> { rng: G, marker: PhantomData, } -impl<'de, M: MathsCore, G: RngCore> DeserializeState<'de, Partition> for Rng { +impl<'de, M: MathsCore, G: Rng> DeserializeState<'de, Partition> for RngConfig { fn deserialize_state>( partition: &mut Partition, deserializer: D, @@ -73,7 +75,7 @@ impl<'de, M: MathsCore, G: RngCore> DeserializeState<'de, Partition> for Rng< } } -impl> From for Base32RngState { +impl> From for Base32RngState { fn from(rng: G) -> Self { Self { rng, @@ -82,7 +84,7 @@ impl> From for Base32RngState { } } -impl> Base32RngState { +impl> Base32RngState { #[must_use] #[allow(dead_code)] pub fn into(self) -> G { @@ -90,7 +92,7 @@ impl> Base32RngState { } } -impl> fmt::Debug for Base32RngState { +impl> fmt::Debug for Base32RngState { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match ProtectedState::serialize(&self.rng) { Ok(state) => Base32String::new(&state).fmt(fmt), @@ -99,7 +101,7 @@ impl> fmt::Debug for Base32RngState { } } -impl> Serialize for Base32RngState { +impl> Serialize for Base32RngState { fn serialize(&self, serializer: S) -> Result { let state = ProtectedState::serialize(&self.rng).map_err(serde::ser::Error::custom)?; @@ -107,7 +109,7 @@ impl> Serialize for Base32RngState { } } -impl<'de, M: MathsCore, G: RngCore> Deserialize<'de> for Base32RngState { +impl<'de, M: MathsCore, G: Rng> Deserialize<'de> for Base32RngState { fn deserialize>(deserializer: D) -> Result { let state = Base32String::deserialize(deserializer)?; @@ -129,7 +131,7 @@ impl<'de, M: MathsCore, G: RngCore> Deserialize<'de> for Base32RngState #[derive(Debug, Deserialize)] #[serde(bound = "")] #[serde(rename = "Rng")] -enum RngRaw> { +enum RngRaw> { Entropy, Seed(u64), #[serde(deserialize_with = "deserialize_rng_sponge")] diff --git a/rustcoalescence/src/cli/simulate/dispatch/valid/rng.rs b/rustcoalescence/src/cli/simulate/dispatch/valid/rng.rs index 929556339..542611cb9 100644 --- a/rustcoalescence/src/cli/simulate/dispatch/valid/rng.rs +++ b/rustcoalescence/src/cli/simulate/dispatch/valid/rng.rs @@ -13,7 +13,7 @@ use rustcoalescence_scenarios::Scenario; use crate::{ args::config::{ - rng::{Base32RngState, Rng as RngArgs}, + rng::{Base32RngState, RngConfig}, sample::Sample, }, cli::simulate::parse, @@ -51,9 +51,9 @@ where normalised_args, &mut A::get_logical_partition(&algorithm_args, &local_partition), )? { - RngArgs::Seed(seed) => SeedableRng::seed_from_u64(seed), - RngArgs::Sponge(bytes) => { - let mut seed = >::Seed::default(); + RngConfig::Seed(seed) => SeedableRng::seed_from_u64(seed), + RngConfig::Sponge(bytes) => { + let mut seed = ::Seed::default(); let mut sponge = Keccak::v256(); sponge.update(&bytes); @@ -61,7 +61,7 @@ where RngCore::from_seed(seed) }, - RngArgs::State(state) => state.into(), + RngConfig::State(state) => state.into(), }; let result = info::dispatch::( @@ -83,7 +83,7 @@ where rng: paused_rng, .. } => { - normalised_args.rng(&RngArgs::State(Base32RngState::from(paused_rng))); + normalised_args.rng(&RngConfig::State(Base32RngState::from(paused_rng))); Ok(SimulationOutcome::Paused { time, diff --git a/rustcoalescence/src/cli/simulate/parse/rng.rs b/rustcoalescence/src/cli/simulate/parse/rng.rs index 2c463d296..b059a2223 100644 --- a/rustcoalescence/src/cli/simulate/parse/rng.rs +++ b/rustcoalescence/src/cli/simulate/parse/rng.rs @@ -1,16 +1,16 @@ -use necsim_core::cogs::{MathsCore, RngCore}; +use necsim_core::cogs::{MathsCore, Rng}; use necsim_partitioning_core::partition::Partition; -use crate::args::{config::rng::Rng, utils::parse::try_parse_state}; +use crate::args::{config::rng::RngConfig, utils::parse::try_parse_state}; use super::super::BufferingSimulateArgsBuilder; #[allow(dead_code)] -pub(in super::super) fn parse_and_normalise>( +pub(in super::super) fn parse_and_normalise>( ron_args: &str, normalised_args: &mut BufferingSimulateArgsBuilder, partition: &mut Partition, -) -> anyhow::Result> { +) -> anyhow::Result> { let SimulateArgsRngOnly { rng } = try_parse_state("simulate", ron_args, partition)?; normalised_args.rng(&rng); @@ -22,8 +22,8 @@ pub(in super::super) fn parse_and_normalise>( #[serde(bound = "")] #[serde(rename = "Simulate")] #[serde(deserialize_state = "Partition")] -struct SimulateArgsRngOnly> { +struct SimulateArgsRngOnly> { #[serde(alias = "randomness")] #[serde(deserialize_state)] - rng: Rng, + rng: RngConfig, } From c4542b54dd705ca556eab0ee5c7c322c3f5adc8d Mon Sep 17 00:00:00 2001 From: Momo Langenstein Date: Wed, 18 May 2022 13:18:24 +0000 Subject: [PATCH 07/42] Make SimpleRNG FFI safe --- necsim/core/src/cogs/rng.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/necsim/core/src/cogs/rng.rs b/necsim/core/src/cogs/rng.rs index ce282cc5c..d1c78bec4 100644 --- a/necsim/core/src/cogs/rng.rs +++ b/necsim/core/src/cogs/rng.rs @@ -229,6 +229,7 @@ impl Distribution for Normal2D { #[derive(Clone, Debug, TypeLayout)] #[layout(free = "M")] #[allow(clippy::module_name_repetitions)] +#[repr(transparent)] pub struct SimpleRng { inner: R, marker: PhantomData, From bf2300732a0c8f2567db51c88005e8cce54ff6f9 Mon Sep 17 00:00:00 2001 From: Momo Langenstein Date: Thu, 19 May 2022 10:05:11 +0000 Subject: [PATCH 08/42] Some first refactoring --- necsim/core/src/cogs/coalescence_sampler.rs | 11 +- necsim/core/src/cogs/distribution.rs | 141 ++++ necsim/core/src/cogs/mod.rs | 8 +- necsim/core/src/cogs/rng.rs | 639 +----------------- necsim/impls/cuda/src/cogs/rng.rs | 17 +- necsim/impls/no-std/src/alias/mod.rs | 20 +- necsim/impls/no-std/src/alias/packed.rs | 10 +- .../alias/individual/mod.rs | 2 +- .../alias/individual/sampler.rs | 6 +- .../alias/location/mod.rs | 2 +- .../alias/location/sampler.rs | 13 +- .../alias/sampler/indexed/mod.rs | 14 +- .../alias/sampler/indexed/tests.rs | 16 +- .../alias/sampler/stack/mod.rs | 14 +- .../alias/sampler/stack/tests.rs | 16 +- .../active_lineage_sampler/classical/mod.rs | 8 +- .../classical/sampler.rs | 18 +- .../independent/event_time_sampler/const.rs | 2 +- .../independent/event_time_sampler/exp.rs | 7 +- .../independent/event_time_sampler/fixed.rs | 2 +- .../event_time_sampler/geometric.rs | 8 +- .../independent/event_time_sampler/poisson.rs | 21 +- .../active_lineage_sampler/independent/mod.rs | 4 +- .../independent/sampler.rs | 5 +- .../independent/singular.rs | 4 +- .../almost_infinite_normal.rs | 16 +- .../in_memory/alias/dispersal.rs | 4 +- .../dispersal_sampler/in_memory/alias/mod.rs | 8 +- .../in_memory/cumulative/contract.rs | 2 +- .../in_memory/cumulative/dispersal.rs | 5 +- .../in_memory/cumulative/mod.rs | 4 +- .../in_memory/packed_alias/dispersal.rs | 4 +- .../in_memory/packed_alias/mod.rs | 10 +- .../in_memory/separable_alias/dispersal.rs | 11 +- .../in_memory/separable_alias/mod.rs | 8 +- .../src/cogs/dispersal_sampler/non_spatial.rs | 18 +- .../dispersal_sampler/spatially_implicit.rs | 18 +- .../cogs/dispersal_sampler/wrapping_noise.rs | 30 +- .../no-std/src/cogs/emigration_exit/domain.rs | 2 +- .../cogs/emigration_exit/independent/mod.rs | 2 +- .../gillespie/conditional/mod.rs | 8 +- .../event_sampler/gillespie/unconditional.rs | 19 +- .../src/cogs/event_sampler/independent.rs | 8 +- .../src/cogs/event_sampler/unconditional.rs | 17 +- .../no-std/src/cogs/habitat/in_memory.rs | 7 +- .../no-std/src/cogs/habitat/non_spatial.rs | 12 +- .../src/cogs/habitat/spatially_implicit.rs | 2 +- .../src/cogs/habitat/wrapping_noise/mod.rs | 2 +- necsim/impls/no-std/src/cogs/rng/mod.rs | 1 + necsim/impls/no-std/src/cogs/rng/simple.rs | 553 +++++++++++++++ .../independent/individuals.rs | 4 +- .../parallelisation/independent/landscape.rs | 4 +- .../independent/monolithic/mod.rs | 4 +- .../parallelisation/monolithic/averaging.rs | 6 +- .../parallelisation/monolithic/lockstep.rs | 6 +- .../parallelisation/monolithic/optimistic.rs | 2 +- .../monolithic/optimistic_lockstep.rs | 2 +- .../algorithms/cuda/cpu-kernel/src/link.rs | 38 +- .../algorithms/cuda/src/initialiser/fixup.rs | 4 +- .../cuda/src/initialiser/genesis.rs | 4 +- .../algorithms/cuda/src/initialiser/mod.rs | 4 +- .../algorithms/cuda/src/initialiser/resume.rs | 4 +- rustcoalescence/algorithms/cuda/src/launch.rs | 8 +- rustcoalescence/algorithms/cuda/src/lib.rs | 8 +- .../src/event_skipping/initialiser/fixup.rs | 6 +- .../src/event_skipping/initialiser/genesis.rs | 6 +- .../src/event_skipping/initialiser/mod.rs | 4 +- .../src/event_skipping/initialiser/resume.rs | 6 +- .../gillespie/src/event_skipping/launch.rs | 4 +- .../gillespie/src/event_skipping/mod.rs | 3 +- .../gillespie/classical/initialiser/fixup.rs | 4 +- .../classical/initialiser/genesis.rs | 4 +- .../gillespie/classical/initialiser/mod.rs | 4 +- .../gillespie/classical/initialiser/resume.rs | 4 +- .../src/gillespie/classical/launch.rs | 4 +- .../gillespie/src/gillespie/classical/mod.rs | 5 +- .../gillespie/turnover/initialiser/fixup.rs | 4 +- .../gillespie/turnover/initialiser/genesis.rs | 4 +- .../src/gillespie/turnover/initialiser/mod.rs | 4 +- .../gillespie/turnover/initialiser/resume.rs | 4 +- .../src/gillespie/turnover/launch.rs | 4 +- .../gillespie/src/gillespie/turnover/mod.rs | 4 +- .../independent/src/initialiser/fixup.rs | 4 +- .../independent/src/initialiser/genesis.rs | 4 +- .../independent/src/initialiser/mod.rs | 4 +- .../independent/src/initialiser/resume.rs | 4 +- .../algorithms/independent/src/launch.rs | 4 +- .../algorithms/independent/src/lib.rs | 12 +- .../scenarios/src/almost_infinite.rs | 2 +- rustcoalescence/scenarios/src/non_spatial.rs | 2 +- .../src/spatially_explicit/turnover/map.rs | 3 +- .../spatially_explicit/turnover/uniform.rs | 3 +- .../scenarios/src/spatially_implicit.rs | 8 +- .../scenarios/src/wrapping_noise.rs | 23 +- 94 files changed, 1088 insertions(+), 940 deletions(-) create mode 100644 necsim/core/src/cogs/distribution.rs create mode 100644 necsim/impls/no-std/src/cogs/rng/simple.rs diff --git a/necsim/core/src/cogs/coalescence_sampler.rs b/necsim/core/src/cogs/coalescence_sampler.rs index 526d64cf7..6af72afa7 100644 --- a/necsim/core/src/cogs/coalescence_sampler.rs +++ b/necsim/core/src/cogs/coalescence_sampler.rs @@ -6,8 +6,8 @@ use serde::{Deserialize, Serialize}; use crate::{ cogs::{ - rng::UniformClosedOpenUnit, Backup, DistributionSampler, Habitat, LineageStore, MathsCore, - Rng, + distribution::UniformClosedOpenUnit, Backup, Habitat, LineageStore, MathsCore, Rng, + SampledDistribution, Samples, }, landscape::{IndexedLocation, Location}, lineage::LineageInteraction, @@ -58,11 +58,8 @@ impl Eq for CoalescenceRngSample {} impl CoalescenceRngSample { #[must_use] #[inline] - pub fn new>(rng: &mut G) -> Self - where - G::Sampler: DistributionSampler, - { - Self(rng.sample::()) + pub fn new + Samples>(rng: &mut G) -> Self { + Self(UniformClosedOpenUnit::sample(rng)) } #[must_use] diff --git a/necsim/core/src/cogs/distribution.rs b/necsim/core/src/cogs/distribution.rs new file mode 100644 index 000000000..f59cdf509 --- /dev/null +++ b/necsim/core/src/cogs/distribution.rs @@ -0,0 +1,141 @@ +use core::num::{NonZeroU128, NonZeroU32, NonZeroU64, NonZeroUsize}; + +use necsim_core_bond::{ + ClosedOpenUnitF64, ClosedUnitF64, NonNegativeF64, OpenClosedUnitF64, PositiveF64, +}; + +use crate::cogs::{MathsCore, RngCore, Samples}; + +pub trait Distribution { + type Parameters; + type Sample; +} + +#[allow(clippy::module_name_repetitions)] +pub trait SampledDistribution: Distribution { + fn sample_with>( + rng: &mut R, + params: Self::Parameters, + ) -> Self::Sample; + + fn sample>(rng: &mut R) -> Self::Sample + where + Self: Distribution, + { + Self::sample_with(rng, ()) + } +} + +impl SampledDistribution for D { + fn sample_with>( + rng: &mut R, + params: Self::Parameters, + ) -> Self::Sample { + rng.sample_with(params) + } +} + +#[allow(clippy::module_name_repetitions)] +pub trait DistributionSampler { + type ConcreteSampler: DistributionSampler; + + #[must_use] + fn concrete(&self) -> &Self::ConcreteSampler; + + #[must_use] + fn sample_with(&self, rng: &mut R, samplers: &S, params: D::Parameters) -> D::Sample; + + #[must_use] + fn sample(&self, rng: &mut R, samplers: &S) -> D::Sample + where + D: Distribution, + { + self.sample_with(rng, samplers, ()) + } +} + +pub enum UniformClosedOpenUnit {} + +impl Distribution for UniformClosedOpenUnit { + type Parameters = (); + type Sample = ClosedOpenUnitF64; +} + +pub enum UniformOpenClosedUnit {} + +impl Distribution for UniformOpenClosedUnit { + type Parameters = (); + type Sample = OpenClosedUnitF64; +} + +pub enum IndexUsize {} + +pub struct Length(pub T); + +impl Distribution for IndexUsize { + type Parameters = Length; + type Sample = usize; +} + +pub enum IndexU32 {} + +impl Distribution for IndexU32 { + type Parameters = Length; + type Sample = u32; +} + +pub enum IndexU64 {} + +impl Distribution for IndexU64 { + type Parameters = Length; + type Sample = u64; +} + +pub enum IndexU128 {} + +impl Distribution for IndexU128 { + type Parameters = Length; + type Sample = u128; +} + +pub struct Lambda(pub PositiveF64); + +pub enum Exponential {} + +impl Distribution for Exponential { + type Parameters = Lambda; + type Sample = NonNegativeF64; +} + +pub enum Poisson {} + +impl Distribution for Poisson { + type Parameters = Lambda; + type Sample = usize; +} + +pub enum Bernoulli {} + +impl Distribution for Bernoulli { + type Parameters = ClosedUnitF64; + type Sample = bool; +} + +pub enum StandardNormal2D {} + +impl Distribution for StandardNormal2D { + type Parameters = (); + type Sample = (f64, f64); +} + +pub struct Normal { + pub mu: f64, + pub sigma: NonNegativeF64, +} + +pub enum Normal2D {} + +impl Distribution for Normal2D { + type Parameters = Normal; + type Sample = (f64, f64); +} diff --git a/necsim/core/src/cogs/mod.rs b/necsim/core/src/cogs/mod.rs index 7fa38cfc1..80324d2f8 100644 --- a/necsim/core/src/cogs/mod.rs +++ b/necsim/core/src/cogs/mod.rs @@ -10,10 +10,10 @@ pub mod speciation_probability; pub use speciation_probability::SpeciationProbability; pub mod rng; -pub use rng::{ - Distribution, DistributionSampler, HabitatPrimeableRng, PrimeableRng, Rng, RngCore, - SeedableRng, SplittableRng, -}; +pub use rng::{PrimeableRng, Rng, RngCore, Samples, SeedableRng, SplittableRng}; + +pub mod distribution; +pub use distribution::{Distribution, DistributionSampler, SampledDistribution}; pub mod dispersal_sampler; pub use dispersal_sampler::{DispersalSampler, SeparableDispersalSampler}; diff --git a/necsim/core/src/cogs/rng.rs b/necsim/core/src/cogs/rng.rs index d1c78bec4..3075e6424 100644 --- a/necsim/core/src/cogs/rng.rs +++ b/necsim/core/src/cogs/rng.rs @@ -1,22 +1,25 @@ -use core::{ - convert::AsMut, - default::Default, - marker::PhantomData, - num::{NonZeroU128, NonZeroU32, NonZeroU64, NonZeroUsize}, - ptr::copy_nonoverlapping, -}; - -use serde::{de::DeserializeOwned, Deserialize, Deserializer, Serialize, Serializer}; +use core::{convert::AsMut, ptr::copy_nonoverlapping}; -use necsim_core_bond::{ - ClosedOpenUnitF64, ClosedUnitF64, NonNegativeF64, OpenClosedUnitF64, PositiveF64, -}; +use serde::{de::DeserializeOwned, Serialize}; use crate::{ - cogs::{Habitat, MathsCore}, + cogs::{Distribution, DistributionSampler, Habitat, MathsCore}, landscape::IndexedLocation, }; +pub trait Rng: RngCore { + type Generator: RngCore; + type Sampler; + + #[must_use] + fn generator(&mut self) -> &mut Self::Generator; + + #[must_use] + fn map_generator Self::Generator>(self, map: F) -> Self; + + fn with_rng Q, Q>(&mut self, inner: F) -> Q; +} + #[allow(clippy::module_name_repetitions)] pub trait RngCore: crate::cogs::Backup + Sized + Clone + core::fmt::Debug + Serialize + DeserializeOwned @@ -99,617 +102,25 @@ pub trait SplittableRng: RngCore { fn split_to_stream(self, stream: u64) -> Self; } -pub trait Distribution { - type Parameters; - type Sample; -} - -pub trait Rng: RngCore { - type Generator: RngCore; - type Sampler; - - #[must_use] - fn generator(&mut self) -> &mut Self::Generator; - - #[must_use] - fn map_generator Self::Generator>(self, map: F) -> Self; - - #[must_use] - fn sample_with(&mut self, params: D::Parameters) -> D::Sample - where - Self::Sampler: DistributionSampler; - - #[must_use] - fn sample>(&mut self) -> D::Sample - where - Self::Sampler: DistributionSampler, - { - self.sample_with(()) - } -} - -#[allow(clippy::module_name_repetitions)] -pub trait DistributionSampler { - type ConcreteSampler: DistributionSampler; - +pub trait Samples: Rng { #[must_use] - fn concrete(&self) -> &Self::ConcreteSampler; + fn sample_with(&mut self, params: D::Parameters) -> D::Sample; #[must_use] - fn sample_with(&self, rng: &mut R, samplers: &S, params: D::Parameters) -> D::Sample; - - #[must_use] - fn sample(&self, rng: &mut R, samplers: &S) -> D::Sample + fn sample(&mut self) -> D::Sample where D: Distribution, { - self.sample_with(rng, samplers, ()) - } -} - -pub enum UniformClosedOpenUnit {} - -impl Distribution for UniformClosedOpenUnit { - type Parameters = (); - type Sample = ClosedOpenUnitF64; -} - -pub enum UniformOpenClosedUnit {} - -impl Distribution for UniformOpenClosedUnit { - type Parameters = (); - type Sample = OpenClosedUnitF64; -} - -pub enum IndexUsize {} - -pub struct Length(pub T); - -impl Distribution for IndexUsize { - type Parameters = Length; - type Sample = usize; -} - -pub enum IndexU32 {} - -impl Distribution for IndexU32 { - type Parameters = Length; - type Sample = u32; -} - -pub enum IndexU64 {} - -impl Distribution for IndexU64 { - type Parameters = Length; - type Sample = u64; -} - -pub enum IndexU128 {} - -impl Distribution for IndexU128 { - type Parameters = Length; - type Sample = u128; -} - -pub enum Exponential {} - -pub struct Lambda(pub PositiveF64); - -impl Distribution for Exponential { - type Parameters = Lambda; - type Sample = NonNegativeF64; -} - -pub enum Event {} - -impl Distribution for Event { - type Parameters = ClosedUnitF64; - type Sample = bool; -} - -pub enum StandardNormal2D {} - -impl Distribution for StandardNormal2D { - type Parameters = (); - type Sample = (f64, f64); -} - -pub enum Normal2D {} - -pub struct Normal { - pub mu: f64, - pub sigma: NonNegativeF64, -} - -impl Distribution for Normal2D { - type Parameters = Normal; - type Sample = (f64, f64); -} - -#[derive(Clone, Debug, TypeLayout)] -#[layout(free = "M")] -#[allow(clippy::module_name_repetitions)] -#[repr(transparent)] -pub struct SimpleRng { - inner: R, - marker: PhantomData, -} - -impl Serialize for SimpleRng { - fn serialize(&self, serializer: S) -> Result { - self.inner.serialize(serializer) - } -} - -impl<'de, M: MathsCore, R: RngCore> Deserialize<'de> for SimpleRng { - fn deserialize>(deserializer: D) -> Result { - let inner = R::deserialize(deserializer)?; - - Ok(Self { - inner, - marker: PhantomData::, - }) - } -} - -#[contract_trait] -impl crate::cogs::Backup for SimpleRng { - unsafe fn backup_unchecked(&self) -> Self { - Self { - inner: self.inner.backup_unchecked(), - marker: PhantomData::, - } - } -} - -impl RngCore for SimpleRng { - type Seed = R::Seed; - - #[must_use] - fn from_seed(seed: Self::Seed) -> Self { - Self { - inner: R::from_seed(seed), - marker: PhantomData::, - } - } - - #[must_use] - fn sample_u64(&mut self) -> u64 { - self.inner.sample_u64() - } -} - -impl Rng for SimpleRng { - type Generator = R; - type Sampler = SimplerDistributionSamplers; - - fn generator(&mut self) -> &mut Self::Generator { - &mut self.inner - } - - fn map_generator Self::Generator>(self, map: F) -> Self { - let SimpleRng { inner, marker } = self; - - SimpleRng { - inner: map(inner), - marker, - } - } - - fn sample_with(&mut self, params: D::Parameters) -> D::Sample - where - Self::Sampler: DistributionSampler, - { - let samplers = SimplerDistributionSamplers { - _marker: PhantomData::<(M, R)>, - }; - - samplers.sample_with(&mut self.inner, &samplers, params) - } -} - -#[allow(clippy::module_name_repetitions)] -pub struct SimplerDistributionSamplers { - _marker: PhantomData<(M, R)>, -} - -impl DistributionSampler - for SimplerDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_with(&self, rng: &mut R, _samplers: &S, _params: ()) -> ClosedOpenUnitF64 { - // http://prng.di.unimi.it -> Generating uniform doubles in the unit interval - #[allow(clippy::cast_precision_loss)] - let u01 = ((rng.sample_u64() >> 11) as f64) * f64::from_bits(0x3CA0_0000_0000_0000_u64); // 0x1.0p-53 - - unsafe { ClosedOpenUnitF64::new_unchecked(u01) } - } -} - -impl DistributionSampler - for SimplerDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_with(&self, rng: &mut R, _samplers: &S, _params: ()) -> OpenClosedUnitF64 { - // http://prng.di.unimi.it -> Generating uniform doubles in the unit interval - #[allow(clippy::cast_precision_loss)] - let u01 = - (((rng.sample_u64() >> 11) + 1) as f64) * f64::from_bits(0x3CA0_0000_0000_0000_u64); // 0x1.0p-53 - - unsafe { OpenClosedUnitF64::new_unchecked(u01) } - } -} - -impl> - DistributionSampler for SimplerDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_with(&self, rng: &mut R, samplers: &S, params: Length) -> usize { - let length = params.0; - - let u01: ClosedOpenUnitF64 = samplers.sample(rng, samplers); - - #[allow( - clippy::cast_precision_loss, - clippy::cast_possible_truncation, - clippy::cast_sign_loss - )] - let index = M::floor(u01.get() * (length.get() as f64)) as usize; - - // Safety in case of f64 rounding errors - index.min(length.get() - 1) - } -} - -impl> - DistributionSampler for SimplerDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_with(&self, rng: &mut R, samplers: &S, params: Length) -> u32 { - let length = params.0; - - let u01: ClosedOpenUnitF64 = samplers.sample(rng, samplers); - - #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] - let index = M::floor(u01.get() * f64::from(length.get())) as u32; - - // Safety in case of f64 rounding errors - index.min(length.get() - 1) - } -} - -impl> - DistributionSampler for SimplerDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_with(&self, rng: &mut R, samplers: &S, params: Length) -> u64 { - let length = params.0; - - let u01: ClosedOpenUnitF64 = samplers.sample(rng, samplers); - - #[allow( - clippy::cast_precision_loss, - clippy::cast_possible_truncation, - clippy::cast_sign_loss - )] - let index = M::floor(u01.get() * (length.get() as f64)) as u64; - - // Safety in case of f64 rounding errors - index.min(length.get() - 1) - } -} - -impl> - DistributionSampler for SimplerDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_with(&self, rng: &mut R, samplers: &S, params: Length) -> u128 { - let length = params.0; - - let u01: ClosedOpenUnitF64 = samplers.sample(rng, samplers); - - #[allow( - clippy::cast_precision_loss, - clippy::cast_possible_truncation, - clippy::cast_sign_loss - )] - let index = M::floor(u01.get() * (length.get() as f64)) as u128; - - // Safety in case of f64 rounding errors - index.min(length.get() - 1) - } -} - -impl> - DistributionSampler for SimplerDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_with(&self, rng: &mut R, samplers: &S, params: Lambda) -> NonNegativeF64 { - let lambda = params.0; - - let u01: OpenClosedUnitF64 = samplers.sample(rng, samplers); - - // Inverse transform sample: X = -ln(U(0,1]) / lambda - -u01.ln::() / lambda - } -} - -impl> - DistributionSampler for SimplerDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_with(&self, rng: &mut R, samplers: &S, params: ClosedUnitF64) -> bool { - let probability = params; - - let u01: ClosedOpenUnitF64 = samplers.sample(rng, samplers); - - // if probability == 1, then U[0, 1) always < 1.0 - // if probability == 0, then U[0, 1) never < 0.0 - u01 < probability - } -} - -#[allow(clippy::trait_duplication_in_bounds)] -impl< - M: MathsCore, - R: RngCore, - S: DistributionSampler - + DistributionSampler, - > DistributionSampler for SimplerDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_with(&self, rng: &mut R, samplers: &S, _params: ()) -> (f64, f64) { - // Basic Box-Muller transform - let u0 = - DistributionSampler::::sample(samplers, rng, samplers); - let u1 = - DistributionSampler::::sample(samplers, rng, samplers); - - let r = M::sqrt(-2.0_f64 * M::ln(u0.get())); - let theta = -core::f64::consts::TAU * u1.get(); - - (r * M::sin(theta), r * M::cos(theta)) + self.sample_with(()) } } -impl> - DistributionSampler for SimplerDistributionSamplers +impl> Samples for R +where + R::Sampler: DistributionSampler, { - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_with(&self, rng: &mut R, samplers: &S, params: Normal) -> (f64, f64) { - let (z0, z1) = samplers.sample(rng, samplers); - - ( - z0 * params.sigma.get() + params.mu, - z1 * params.sigma.get() + params.mu, - ) - } -} - -/*#[allow(clippy::inline_always, clippy::inline_fn_without_body)] -#[allow(clippy::module_name_repetitions)] -#[contract_trait] -pub trait RngSampler: RngCore { #[must_use] - #[inline] - /// Samples a uniform sample within `[0.0, 1.0)`, i.e. `0.0 <= X < 1.0` - fn sample_uniform_closed_open(&mut self) -> ClosedOpenUnitF64 { - // http://prng.di.unimi.it -> Generating uniform doubles in the unit interval - #[allow(clippy::cast_precision_loss)] - let u01 = ((self.sample_u64() >> 11) as f64) * f64::from_bits(0x3CA0_0000_0000_0000_u64); // 0x1.0p-53 - - unsafe { ClosedOpenUnitF64::new_unchecked(u01) } - } - - #[must_use] - #[inline] - /// Samples a uniform sample within `(0.0, 1.0]`, i.e. `0.0 < X <= 1.0` - fn sample_uniform_open_closed(&mut self) -> OpenClosedUnitF64 { - // http://prng.di.unimi.it -> Generating uniform doubles in the unit interval - #[allow(clippy::cast_precision_loss)] - let u01 = - (((self.sample_u64() >> 11) + 1) as f64) * f64::from_bits(0x3CA0_0000_0000_0000_u64); // 0x1.0p-53 - - unsafe { OpenClosedUnitF64::new_unchecked(u01) } - } - - #[must_use] - #[inline] - #[debug_ensures(ret < length.get(), "samples U(0, length - 1)")] - fn sample_index(&mut self, length: NonZeroUsize) -> usize { - #[cfg(target_pointer_width = "32")] - #[allow(clippy::cast_possible_truncation)] - { - self.sample_index_u32(unsafe { NonZeroU32::new_unchecked(length.get() as u32) }) - as usize - } - #[cfg(target_pointer_width = "64")] - #[allow(clippy::cast_possible_truncation)] - { - self.sample_index_u64(unsafe { NonZeroU64::new_unchecked(length.get() as u64) }) - as usize - } - } - - #[must_use] - #[inline] - #[debug_ensures(ret < length.get(), "samples U(0, length - 1)")] - fn sample_index_u32(&mut self, length: NonZeroU32) -> u32 { - // TODO: Check if delegation to `sample_index_u64` is faster - - // Adapted from: - // https://docs.rs/rand/0.8.4/rand/distributions/uniform/trait.UniformSampler.html#method.sample_single - - const LOWER_MASK: u64 = !0 >> 32; - - // Conservative approximation of the acceptance zone - let acceptance_zone = (length.get() << length.leading_zeros()).wrapping_sub(1); - - loop { - let raw = self.sample_u64(); - - let sample_check_lo = (raw & LOWER_MASK) * u64::from(length.get()); - - #[allow(clippy::cast_possible_truncation)] - if (sample_check_lo as u32) <= acceptance_zone { - return (sample_check_lo >> 32) as u32; - } - - let sample_check_hi = (raw >> 32) * u64::from(length.get()); - - #[allow(clippy::cast_possible_truncation)] - if (sample_check_hi as u32) <= acceptance_zone { - return (sample_check_hi >> 32) as u32; - } - } - } - - #[must_use] - #[inline] - #[debug_ensures(ret < length.get(), "samples U(0, length - 1)")] - fn sample_index_u64(&mut self, length: NonZeroU64) -> u64 { - // Adapted from: - // https://docs.rs/rand/0.8.4/rand/distributions/uniform/trait.UniformSampler.html#method.sample_single - - // Conservative approximation of the acceptance zone - let acceptance_zone = (length.get() << length.leading_zeros()).wrapping_sub(1); - - loop { - let raw = self.sample_u64(); - - let sample_check = u128::from(raw) * u128::from(length.get()); - - #[allow(clippy::cast_possible_truncation)] - if (sample_check as u64) <= acceptance_zone { - return (sample_check >> 64) as u64; - } - } - } - - #[must_use] - #[inline] - #[debug_ensures(ret < length.get(), "samples U(0, length - 1)")] - fn sample_index_u128(&mut self, length: NonZeroU128) -> u128 { - // Adapted from: - // https://docs.rs/rand/0.8.4/rand/distributions/uniform/trait.UniformSampler.html#method.sample_single - - const LOWER_MASK: u128 = !0 >> 64; - - // Conservative approximation of the acceptance zone - let acceptance_zone = (length.get() << length.leading_zeros()).wrapping_sub(1); - - loop { - let raw_hi = u128::from(self.sample_u64()); - let raw_lo = u128::from(self.sample_u64()); - - // 256-bit multiplication (hi, lo) = (raw_hi, raw_lo) * length - let mut low = raw_lo * (length.get() & LOWER_MASK); - let mut t = low >> 64; - low &= LOWER_MASK; - t += raw_hi * (length.get() & LOWER_MASK); - low += (t & LOWER_MASK) << 64; - let mut high = t >> 64; - t = low >> 64; - low &= LOWER_MASK; - t += (length.get() >> 64) * raw_lo; - low += (t & LOWER_MASK) << 64; - high += t >> 64; - high += raw_hi * (length.get() >> 64); - - let sample = high; - let check = low; - - if check <= acceptance_zone { - return sample; - } - } - } - - #[must_use] - #[inline] - fn sample_exponential(&mut self, lambda: PositiveF64) -> NonNegativeF64 { - // Inverse transform sample: X = -ln(U(0,1]) / lambda - -self.sample_uniform_open_closed().ln::() / lambda - } - - #[must_use] - #[inline] - fn sample_event(&mut self, probability: ClosedUnitF64) -> bool { - // if probability == 1, then U[0, 1) always < 1.0 - // if probability == 0, then U[0, 1) never < 0.0 - self.sample_uniform_closed_open() < probability - } - - #[must_use] - #[inline] - fn sample_2d_standard_normal(&mut self) -> (f64, f64) { - // Basic Box-Muller transform - let u0 = self.sample_uniform_open_closed(); - let u1 = self.sample_uniform_closed_open(); - - let r = M::sqrt(-2.0_f64 * M::ln(u0.get())); - let theta = -core::f64::consts::TAU * u1.get(); - - (r * M::sin(theta), r * M::cos(theta)) - } - - #[must_use] - #[inline] - fn sample_2d_normal(&mut self, mu: f64, sigma: NonNegativeF64) -> (f64, f64) { - let (z0, z1) = self.sample_2d_standard_normal(); - - (z0 * sigma.get() + mu, z1 * sigma.get() + mu) + fn sample_with(&mut self, params: D::Parameters) -> D::Sample { + self.with_rng(|rng, samplers| samplers.sample_with(rng, samplers, params)) } } - -impl> RngSampler for R {}*/ diff --git a/necsim/impls/cuda/src/cogs/rng.rs b/necsim/impls/cuda/src/cogs/rng.rs index 6f04b14e2..8c29ba2b7 100644 --- a/necsim/impls/cuda/src/cogs/rng.rs +++ b/necsim/impls/cuda/src/cogs/rng.rs @@ -1,6 +1,6 @@ use core::marker::PhantomData; -use necsim_core::cogs::{Distribution, DistributionSampler, MathsCore, Rng, RngCore}; +use necsim_core::cogs::{MathsCore, Rng, RngCore}; use const_type_layout::TypeGraphLayout; use rust_cuda::safety::StackOnly; @@ -38,9 +38,7 @@ impl + StackOnly + ~const TypeGraphLayout> From for C } } -impl + StackOnly + ~const TypeGraphLayout> RngCore - for CudaRng -{ +impl + StackOnly + ~const TypeGraphLayout> RngCore for CudaRng { type Seed = ::Seed; #[must_use] @@ -76,11 +74,8 @@ impl + StackOnly + ~const TypeGraphLayout> Rng for Cu } } - fn sample_with(&mut self, params: D::Parameters) -> D::Sample - where - Self::Sampler: DistributionSampler, - { - self.inner.sample_with(params) + fn with_rng Q, Q>(&mut self, inner: F) -> Q { + self.inner.with_rng(inner) } } @@ -90,7 +85,9 @@ impl + StackOnly + ~const TypeGraphLayout> Serialize for } } -impl<'de, M: MathsCore, R: Rng + StackOnly + ~const TypeGraphLayout> Deserialize<'de> for CudaRng { +impl<'de, M: MathsCore, R: Rng + StackOnly + ~const TypeGraphLayout> Deserialize<'de> + for CudaRng +{ fn deserialize>(deserializer: D) -> Result { let inner = R::deserialize(deserializer)?; diff --git a/necsim/impls/no-std/src/alias/mod.rs b/necsim/impls/no-std/src/alias/mod.rs index cbabed87c..1dca499f4 100644 --- a/necsim/impls/no-std/src/alias/mod.rs +++ b/necsim/impls/no-std/src/alias/mod.rs @@ -3,8 +3,8 @@ use core::num::NonZeroUsize; use alloc::vec::Vec; use necsim_core::cogs::{ - rng::{Event, IndexUsize, Length}, - DistributionSampler, MathsCore, Rng, + distribution::{Bernoulli, IndexUsize, Length}, + MathsCore, Rng, SampledDistribution, Samples, }; use necsim_core_bond::{ClosedUnitF64, NonNegativeF64}; @@ -94,18 +94,20 @@ impl AliasMethodSampler { } #[debug_ensures(self.Es.contains(&ret), "returns one of the weighted events")] - pub fn sample_event>(&self, rng: &mut G) -> E - where - G::Sampler: DistributionSampler - + DistributionSampler, - { + pub fn sample_event< + M: MathsCore, + G: Rng + Samples + Samples, + >( + &self, + rng: &mut G, + ) -> E { // Safety: Es is non-empty by the precondition on construction let length = unsafe { NonZeroUsize::new_unchecked(self.Es.len()) }; - let i = rng.sample_with::(Length(length)); // index into events + let i = IndexUsize::sample_with(rng, Length(length)); // index into events // Select Es[i] over Ks[i] according to its bucket percentage Us[i] - if rng.sample_with::(self.Us[i]) { + if Bernoulli::sample_with(rng, self.Us[i]) { self.Es[i] } else { self.Ks[i] diff --git a/necsim/impls/no-std/src/alias/packed.rs b/necsim/impls/no-std/src/alias/packed.rs index fcc0aab9a..fe1a797f1 100644 --- a/necsim/impls/no-std/src/alias/packed.rs +++ b/necsim/impls/no-std/src/alias/packed.rs @@ -3,8 +3,8 @@ use core::{cmp::Ordering, num::NonZeroUsize}; use alloc::vec::Vec; use necsim_core::cogs::{ - rng::{Event, IndexUsize, Length}, - DistributionSampler, MathsCore, Rng, + distribution::{Bernoulli, IndexUsize, Length}, + DistributionSampler, MathsCore, Rng, SampledDistribution, }; use necsim_core_bond::{ClosedUnitF64, NonNegativeF64}; @@ -117,17 +117,17 @@ impl AliasMethodSamplerAtom { ) -> E where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { // Safety: alias_samplers is non-empty by the precondition let length = unsafe { NonZeroUsize::new_unchecked(alias_samplers.len()) }; - let i = rng.sample_with::(Length(length)); // index into events + let i = IndexUsize::sample_with(rng, Length(length)); // index into events let sample = &alias_samplers[i]; // Select E over K according to its bucket percentage U - if rng.sample_with::(sample.u) { + if Bernoulli::sample_with(rng, sample.u) { sample.e } else { sample.k diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs index 490784d5c..4e3eeca67 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs @@ -4,7 +4,7 @@ use core::{fmt, marker::PhantomData}; use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_core::cogs::{ - rng::{Exponential, IndexU128, IndexU64, IndexUsize}, + distribution::{Exponential, IndexU128, IndexU64, IndexUsize}, Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, EmigrationExit, EventSampler, Habitat, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs index cf56e5058..004b09ddc 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs @@ -2,10 +2,10 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ - rng::{Exponential, IndexU128, IndexU64, IndexUsize, Lambda}, + distribution::{Exponential, IndexU128, IndexU64, IndexUsize, Lambda}, ActiveLineageSampler, CoalescenceSampler, DispersalSampler, DistributionSampler, EmigrationExit, EventSampler, Habitat, ImmigrationEntry, LocallyCoherentLineageStore, - MathsCore, Rng, SpeciationProbability, TurnoverRate, + MathsCore, Rng, SampledDistribution, SpeciationProbability, TurnoverRate, }, lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation, @@ -69,7 +69,7 @@ where let total_rate = self.alias_sampler.total_weight(); if let Ok(lambda) = PositiveF64::new(total_rate.get()) { - let event_time = self.last_event_time + rng.sample_with::(Lambda(lambda)); + let event_time = self.last_event_time + Exponential::sample_with(rng, Lambda(lambda)); let next_event_time = PositiveF64::max_after(self.last_event_time, event_time); diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs index 34ed04bd0..5ab2d9e69 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs @@ -5,7 +5,7 @@ use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_core::{ cogs::{ - rng::{Exponential, IndexU128, IndexU64, IndexUsize}, + distribution::{Exponential, IndexU128, IndexU64, IndexUsize}, Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, EmigrationExit, GloballyCoherentLineageStore, Habitat, ImmigrationEntry, MathsCore, Rng, SpeciationProbability, TurnoverRate, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs index ca1717dad..cc67138de 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs @@ -2,10 +2,10 @@ use core::{num::NonZeroUsize, ops::ControlFlow}; use necsim_core::{ cogs::{ - rng::{Exponential, IndexU128, IndexU64, IndexUsize, Lambda, Length}, + distribution::{Exponential, IndexU128, IndexU64, IndexUsize, Lambda, Length}, ActiveLineageSampler, Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, EmigrationExit, GloballyCoherentLineageStore, Habitat, ImmigrationEntry, MathsCore, Rng, - SpeciationProbability, TurnoverRate, + SampledDistribution, SpeciationProbability, TurnoverRate, }, lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation, @@ -76,7 +76,7 @@ where let total_rate = self.alias_sampler.total_weight(); if let Ok(lambda) = PositiveF64::new(total_rate.get()) { - let event_time = self.last_event_time + rng.sample_with::(Lambda(lambda)); + let event_time = self.last_event_time + Exponential::sample_with(rng, Lambda(lambda)); let next_event_time = PositiveF64::max_after(self.last_event_time, event_time); @@ -99,9 +99,10 @@ where // Safety: `lineages_at_location` must be >0 since // `chosen_active_location` can only be selected in that case - let chosen_lineage_index_at_location = rng.sample_with::(Length(unsafe { - NonZeroUsize::new_unchecked(lineages_at_location.len()) - })); + let chosen_lineage_index_at_location = IndexUsize::sample_with( + rng, + Length(unsafe { NonZeroUsize::new_unchecked(lineages_at_location.len()) }), + ); // Safety: reference clone is only used to then remove the lineage, which is // owned let chosen_lineage_reference = unsafe { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs index 6c5416b89..f1f24d996 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs @@ -11,8 +11,8 @@ use fnv::FnvBuildHasher; use hashbrown::HashMap; use necsim_core::cogs::{ - rng::{IndexU128, IndexU64, IndexUsize, Length}, - Backup, DistributionSampler, MathsCore, Rng, + distribution::{IndexU128, IndexU64, IndexUsize, Length}, + Backup, DistributionSampler, MathsCore, Rng, SampledDistribution, }; use necsim_core_bond::{NonNegativeF64, PositiveF64}; @@ -66,8 +66,10 @@ impl RejectionSamplingGroup { loop { // Safety: By construction, the group never contains zero elements - let index = rng - .sample_with::(Length(NonZeroUsize::new_unchecked(self.weights.len()))); + let index = IndexUsize::sample_with( + rng, + Length(NonZeroUsize::new_unchecked(self.weights.len())), + ); let height = rng.sample_u64() >> 11; // 53rd bit of weight is always 1, so sampling chance >= 50% @@ -207,9 +209,9 @@ impl DynamicAliasMethodIndexedSampler { let cdf_sample = if let [_group] = &self.groups[..] { 0_u128 } else if let Ok(total_weight) = NonZeroU64::try_from(total_weight) { - u128::from(rng.sample_with::(Length(total_weight))) + u128::from(IndexU64::sample_with(rng, Length(total_weight))) } else { - rng.sample_with::(Length(total_weight)) + IndexU128::sample_with(rng, Length(total_weight)) }; let mut cdf_acc = 0_u128; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs index 81bd218de..1d1e0872e 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs @@ -4,13 +4,16 @@ use core::num::{NonZeroU128, NonZeroU64, NonZeroUsize}; use hashbrown::HashMap; use necsim_core::cogs::{ - rng::{IndexU128, IndexU64, IndexUsize, Length, SimpleRng}, - Backup, Distribution, DistributionSampler, Rng, RngCore, SeedableRng, + distribution::{IndexU128, IndexU64, IndexUsize, Length}, + Backup, DistributionSampler, Rng, RngCore, SeedableRng, }; use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_core_maths::MathsCore; -use crate::cogs::{maths::intrinsics::IntrinsicsMathsCore, rng::wyhash::WyHash}; +use crate::cogs::{ + maths::intrinsics::IntrinsicsMathsCore, + rng::{simple::SimpleRng, wyhash::WyHash}, +}; use super::{ super::decompose_weight, DynamicAliasMethodIndexedSampler, EventLocation, @@ -1120,13 +1123,10 @@ impl Rng for DummyRng { map(self) } - fn sample_with(&mut self, params: D::Parameters) -> D::Sample - where - Self::Sampler: DistributionSampler, - { + fn with_rng Q, Q>(&mut self, inner: F) -> Q { let samplers = DummyDistributionSamplers; - samplers.sample_with(self, &samplers, params) + inner(self, &samplers) } } diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs index 5ce8675bb..9760fcc69 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs @@ -8,8 +8,8 @@ use core::{ }; use necsim_core::cogs::{ - rng::{IndexU128, IndexU64, IndexUsize, Length}, - Backup, DistributionSampler, MathsCore, Rng, + distribution::{IndexU128, IndexU64, IndexUsize, Length}, + Backup, DistributionSampler, MathsCore, Rng, SampledDistribution, }; use necsim_core_bond::{NonNegativeF64, PositiveF64}; @@ -59,8 +59,10 @@ impl RejectionSamplingGroup { loop { // Safety: By construction, the group never contains zero elements - let index = rng - .sample_with::(Length(NonZeroUsize::new_unchecked(self.weights.len()))); + let index = IndexUsize::sample_with( + rng, + Length(NonZeroUsize::new_unchecked(self.weights.len())), + ); let height = rng.sample_u64() >> 11; // 53rd bit of weight is always 1, so sampling chance >= 50% @@ -141,9 +143,9 @@ impl DynamicAliasMethodStackSampler { let cdf_sample = if let [_group] = &self.groups[..] { 0_u128 } else if let Ok(total_weight) = NonZeroU64::try_from(total_weight) { - u128::from(rng.sample_with::(Length(total_weight))) + u128::from(IndexU64::sample_with(rng, Length(total_weight))) } else { - rng.sample_with::(Length(total_weight)) + IndexU128::sample_with(rng, Length(total_weight)) }; let mut cdf_acc = 0_u128; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs index f9486183d..10715637c 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs @@ -3,13 +3,16 @@ use core::num::{NonZeroU128, NonZeroU64, NonZeroUsize}; use alloc::{vec, vec::Vec}; use necsim_core::cogs::{ - rng::{IndexU128, IndexU64, IndexUsize, Length, SimpleRng}, - Backup, Distribution, DistributionSampler, Rng, RngCore, SeedableRng, + distribution::{IndexU128, IndexU64, IndexUsize, Length}, + Backup, DistributionSampler, Rng, RngCore, SeedableRng, }; use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_core_maths::MathsCore; -use crate::cogs::{maths::intrinsics::IntrinsicsMathsCore, rng::wyhash::WyHash}; +use crate::cogs::{ + maths::intrinsics::IntrinsicsMathsCore, + rng::{simple::SimpleRng, wyhash::WyHash}, +}; use super::{super::decompose_weight, DynamicAliasMethodStackSampler, RejectionSamplingGroup}; @@ -619,13 +622,10 @@ impl Rng for DummyRng { map(self) } - fn sample_with(&mut self, params: D::Parameters) -> D::Sample - where - Self::Sampler: DistributionSampler, - { + fn with_rng Q, Q>(&mut self, inner: F) -> Q { let samplers = DummyDistributionSamplers; - samplers.sample_with(self, &samplers, params) + inner(self, &samplers) } } diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs index 339fa1036..50f26fc53 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs @@ -2,7 +2,7 @@ use alloc::vec::Vec; use core::marker::PhantomData; use necsim_core::cogs::{ - rng::{Event, Exponential, IndexUsize, UniformClosedOpenUnit}, + distribution::{Bernoulli, Exponential, IndexUsize, UniformClosedOpenUnit}, Backup, DispersalSampler, DistributionSampler, EmigrationExit, Habitat, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, }; @@ -29,7 +29,7 @@ pub struct ClassicalActiveLineageSampler< > where G::Sampler: DistributionSampler + DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler, { active_lineage_references: Vec, @@ -51,7 +51,7 @@ impl< where G::Sampler: DistributionSampler + DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler, { #[must_use] @@ -147,7 +147,7 @@ impl< where G::Sampler: DistributionSampler + DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs index 3512b9ca3..24f6fbe49 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs @@ -5,9 +5,10 @@ use core::{ use necsim_core::{ cogs::{ - rng::{Event, Exponential, IndexUsize, Lambda, Length, UniformClosedOpenUnit}, + distribution::{Bernoulli, Exponential, IndexUsize, Lambda, Length, UniformClosedOpenUnit}, ActiveLineageSampler, DispersalSampler, DistributionSampler, EmigrationExit, Habitat, - ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, + ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, SampledDistribution, + SpeciationProbability, }, lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation, @@ -59,7 +60,7 @@ impl< where G::Sampler: DistributionSampler + DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler, { type LineageIterator<'a> = impl Iterator where H: 'a, G: 'a, S: 'a, X: 'a, D: 'a, N: 'a, I: 'a; @@ -117,7 +118,7 @@ where let lambda = simulation.turnover_rate.get_uniform_turnover_rate() * PositiveF64::from(number_active_lineages); - let event_time = self.last_event_time + rng.sample_with::(Lambda(lambda)); + let event_time = self.last_event_time + Exponential::sample_with(rng, Lambda(lambda)); let next_event_time = PositiveF64::max_after(self.last_event_time, event_time); @@ -129,9 +130,12 @@ where // Safety: The outer if statement has already shown that the number // of remaining lineages is non-zero - let chosen_lineage_index = rng.sample_with::(Length(unsafe { - NonZeroUsize::new_unchecked(self.active_lineage_references.len()) - })); + let chosen_lineage_index = IndexUsize::sample_with( + rng, + Length(unsafe { + NonZeroUsize::new_unchecked(self.active_lineage_references.len()) + }), + ); let chosen_lineage_reference = self .active_lineage_references .swap_remove(chosen_lineage_index); diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/const.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/const.rs index 312603e7d..b6db567ba 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/const.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/const.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{Habitat, HabitatPrimeableRng, MathsCore, PrimeableRng, Rng, TurnoverRate}, + cogs::{rng::HabitatPrimeableRng, Habitat, MathsCore, PrimeableRng, Rng, TurnoverRate}, landscape::IndexedLocation, }; use necsim_core_bond::{NonNegativeF64, PositiveF64}; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs index 002de74bb..ea48c2660 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs @@ -1,7 +1,8 @@ use necsim_core::{ cogs::{ - rng::{Exponential, Lambda}, - DistributionSampler, Habitat, HabitatPrimeableRng, MathsCore, PrimeableRng, Rng, + distribution::{Exponential, Lambda}, + rng::HabitatPrimeableRng, + DistributionSampler, Habitat, MathsCore, PrimeableRng, Rng, SampledDistribution, TurnoverRate, }, landscape::IndexedLocation, @@ -67,7 +68,7 @@ where let mut sub_index: u64 = 0; loop { - event_time += rng.sample_with::(Lambda(lambda)); + event_time += Exponential::sample_with(rng, Lambda(lambda)); sub_index = sub_index.wrapping_add(INV_PHI); diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/fixed.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/fixed.rs index 386738869..08844e755 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/fixed.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/fixed.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{Habitat, HabitatPrimeableRng, MathsCore, PrimeableRng, Rng, TurnoverRate}, + cogs::{rng::HabitatPrimeableRng, Habitat, MathsCore, PrimeableRng, Rng, TurnoverRate}, landscape::IndexedLocation, }; use necsim_core_bond::NonNegativeF64; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs index e7e635446..6c3996ccc 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs @@ -1,7 +1,7 @@ use necsim_core::{ cogs::{ - rng::Event, DistributionSampler, Habitat, HabitatPrimeableRng, MathsCore, PrimeableRng, - Rng, TurnoverRate, + distribution::Bernoulli, rng::HabitatPrimeableRng, DistributionSampler, Habitat, MathsCore, + PrimeableRng, Rng, SampledDistribution, TurnoverRate, }, landscape::IndexedLocation, }; @@ -27,7 +27,7 @@ impl GeometricEventTimeSampler { impl, G: Rng, T: TurnoverRate> EventTimeSampler for GeometricEventTimeSampler where - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler, { #[inline] fn next_event_time_at_indexed_location_weakly_after( @@ -52,7 +52,7 @@ where rng.generator() .prime_with_habitat(habitat, indexed_location, time_step); - if rng.sample_with::(event_probability_per_step) { + if Bernoulli::sample_with(rng, event_probability_per_step) { break; } diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs index 0eb959300..5efdbc631 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs @@ -1,7 +1,8 @@ use necsim_core::{ cogs::{ - rng::{Normal, Normal2D, UniformClosedOpenUnit}, - DistributionSampler, Habitat, HabitatPrimeableRng, MathsCore, PrimeableRng, Rng, + distribution::{Normal, Normal2D, UniformClosedOpenUnit}, + rng::HabitatPrimeableRng, + DistributionSampler, Habitat, MathsCore, PrimeableRng, Rng, SampledDistribution, TurnoverRate, }, landscape::IndexedLocation, @@ -62,7 +63,7 @@ where let mut prod = no_event_probability_per_step; let mut acc = no_event_probability_per_step; - let u = rng.sample::(); + let u = UniformClosedOpenUnit::sample(rng); while u > acc && prod > 0.0_f64 { poisson += 1; @@ -74,13 +75,15 @@ where } else { // Fallback in case no_event_probability_per_step underflows #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] - let normal_as_poisson = rng - .sample_with::(Normal { + let normal_as_poisson = Normal2D::sample_with( + rng, + Normal { mu: lambda_per_step.get(), sigma: lambda_per_step.sqrt::(), - }) - .0 - .max(0.0_f64) as u32; + }, + ) + .0 + .max(0.0_f64) as u32; normal_as_poisson }; @@ -90,7 +93,7 @@ where for event_index in 0..number_events_at_time_steps { #[allow(clippy::cast_precision_loss)] let event_time = (NonNegativeF64::from(time_step) - + NonNegativeF64::from(rng.sample::())) + + NonNegativeF64::from(UniformClosedOpenUnit::sample(rng))) * self.delta_t; if event_time > time { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/mod.rs index 9642d7979..739ebc498 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/mod.rs @@ -3,8 +3,8 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ - rng::UniformClosedOpenUnit, Backup, DispersalSampler, DistributionSampler, EmigrationExit, - Habitat, MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, + distribution::UniformClosedOpenUnit, Backup, DispersalSampler, DistributionSampler, + EmigrationExit, Habitat, MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, }, lineage::Lineage, }; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/sampler.rs index fb951a52a..b0a4beccf 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/sampler.rs @@ -2,8 +2,9 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ - rng::UniformClosedOpenUnit, ActiveLineageSampler, DispersalSampler, DistributionSampler, - EmigrationExit, Habitat, MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, + distribution::UniformClosedOpenUnit, ActiveLineageSampler, DispersalSampler, + DistributionSampler, EmigrationExit, Habitat, MathsCore, PrimeableRng, Rng, + SpeciationProbability, TurnoverRate, }, lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/singular.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/singular.rs index 1e197de68..2962f86ac 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/singular.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/singular.rs @@ -1,6 +1,6 @@ use necsim_core::cogs::{ - rng::UniformClosedOpenUnit, DispersalSampler, DistributionSampler, EmigrationExit, Habitat, - MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, + distribution::UniformClosedOpenUnit, DispersalSampler, DistributionSampler, EmigrationExit, + Habitat, MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, }; use necsim_core::lineage::Lineage; diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs index cb1242313..a1a939361 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs @@ -2,8 +2,9 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ - rng::{Normal, Normal2D}, - Backup, DispersalSampler, DistributionSampler, MathsCore, Rng, SeparableDispersalSampler, + distribution::{Normal, Normal2D}, + Backup, DispersalSampler, DistributionSampler, MathsCore, Rng, SampledDistribution, + SeparableDispersalSampler, }, landscape::Location, }; @@ -77,10 +78,13 @@ where ) -> Location { const WRAP: i64 = 1 << 32; - let (dx, dy): (f64, f64) = rng.sample_with::(Normal { - mu: 0.0_f64, - sigma: self.sigma, - }); + let (dx, dy): (f64, f64) = Normal2D::sample_with( + rng, + Normal { + mu: 0.0_f64, + sigma: self.sigma, + }, + ); // Discrete dispersal assumes lineage positions are centred on (0.5, 0.5), // i.e. |dispersal| >= 0.5 changes the cell diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/dispersal.rs index 302921b3e..c7302f79d 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/dispersal.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - rng::{Event, IndexUsize}, + distribution::{Bernoulli, IndexUsize}, DispersalSampler, DistributionSampler, Habitat, MathsCore, Rng, }, landscape::Location, @@ -13,7 +13,7 @@ impl, G: Rng> DispersalSampler for InMemoryAliasDispersalSampler where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { #[must_use] fn sample_dispersal_from_location( diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/mod.rs index 87dda5998..494bb6735 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/mod.rs @@ -4,7 +4,7 @@ use alloc::vec::Vec; use necsim_core::{ cogs::{ - rng::{Event, IndexUsize}, + distribution::{Bernoulli, IndexUsize}, Backup, DistributionSampler, Habitat, MathsCore, Rng, }, landscape::Location, @@ -23,7 +23,7 @@ mod dispersal; pub struct InMemoryAliasDispersalSampler, G: Rng> where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { alias_dispersal: Array2D>>, marker: PhantomData<(M, H, G)>, @@ -34,7 +34,7 @@ impl, G: Rng> InMemoryDispersalSampler for InMemoryAliasDispersalSampler where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { /// Creates a new `InMemoryAliasDispersalSampler` from the /// `dispersal` map and extent of the habitat map. @@ -90,7 +90,7 @@ where impl, G: Rng> Backup for InMemoryAliasDispersalSampler where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/contract.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/contract.rs index cc0f41401..36ceb64bd 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/contract.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/contract.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{rng::UniformClosedOpenUnit, DistributionSampler, Habitat, MathsCore, Rng}, + cogs::{distribution::UniformClosedOpenUnit, DistributionSampler, Habitat, MathsCore, Rng}, landscape::Location, }; diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/dispersal.rs index 9ca1dadec..7cfacdd37 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/dispersal.rs @@ -1,6 +1,7 @@ use necsim_core::{ cogs::{ - rng::UniformClosedOpenUnit, DispersalSampler, DistributionSampler, Habitat, MathsCore, Rng, + distribution::UniformClosedOpenUnit, DispersalSampler, DistributionSampler, Habitat, + MathsCore, Rng, SampledDistribution, }, landscape::Location, }; @@ -30,7 +31,7 @@ where let cumulative_dispersals_at_location = &self.cumulative_dispersal [location_index * habitat_area..(location_index + 1) * habitat_area]; - let cumulative_percentage_sample = rng.sample::().into(); + let cumulative_percentage_sample = UniformClosedOpenUnit::sample(rng).into(); let dispersal_target_index = usize::min( match cumulative_dispersals_at_location.binary_search(&cumulative_percentage_sample) { diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/mod.rs index 7a658eb1b..47f0fd148 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/mod.rs @@ -3,7 +3,9 @@ use core::marker::PhantomData; use alloc::{boxed::Box, vec}; use necsim_core::{ - cogs::{rng::UniformClosedOpenUnit, Backup, DistributionSampler, Habitat, MathsCore, Rng}, + cogs::{ + distribution::UniformClosedOpenUnit, Backup, DistributionSampler, Habitat, MathsCore, Rng, + }, landscape::Location, }; use necsim_core_bond::{ClosedUnitF64, NonNegativeF64}; diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/dispersal.rs index 06189f91a..6c3892329 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/dispersal.rs @@ -2,7 +2,7 @@ use core::ops::Range; use necsim_core::{ cogs::{ - rng::{Event, IndexUsize}, + distribution::{Bernoulli, IndexUsize}, DispersalSampler, DistributionSampler, Habitat, MathsCore, Rng, }, landscape::Location, @@ -17,7 +17,7 @@ impl, G: Rng> DispersalSampler for InMemoryPackedAliasDispersalSampler where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { #[must_use] fn sample_dispersal_from_location( diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs index ec27a0fa1..0c2c079dc 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs @@ -6,7 +6,7 @@ use r#final::Final; use necsim_core::{ cogs::{ - rng::{Event, IndexUsize}, + distribution::{Bernoulli, IndexUsize}, Backup, DistributionSampler, Habitat, MathsCore, Rng, }, landscape::Location, @@ -48,7 +48,7 @@ impl From for Range { pub struct InMemoryPackedAliasDispersalSampler, G: Rng> where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { #[cfg_attr(feature = "cuda", cuda(embed))] alias_dispersal_ranges: Final>, @@ -62,7 +62,7 @@ impl, G: Rng> InMemoryDispersalSampler for InMemoryPackedAliasDispersalSampler where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { /// Creates a new `InMemoryPackedAliasDispersalSampler` from the /// `dispersal` map and extent of the habitat map. @@ -126,7 +126,7 @@ impl, G: Rng> core::fmt::Debug for InMemoryPackedAliasDispersalSampler where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { f.debug_struct(stringify!(InMemoryPackedAliasDispersalSampler)) @@ -147,7 +147,7 @@ where impl, G: Rng> Backup for InMemoryPackedAliasDispersalSampler where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs index 437ec6bb2..7e254f244 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs @@ -1,7 +1,8 @@ use necsim_core::{ cogs::{ - rng::{Event, IndexUsize}, - DispersalSampler, DistributionSampler, Habitat, MathsCore, Rng, SeparableDispersalSampler, + distribution::{Bernoulli, IndexUsize}, + DispersalSampler, DistributionSampler, Habitat, MathsCore, Rng, SampledDistribution, + SeparableDispersalSampler, }, landscape::Location, }; @@ -14,7 +15,7 @@ impl, G: Rng> DispersalSampler for InMemorySeparableAliasDispersalSampler where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { #[must_use] fn sample_dispersal_from_location( @@ -31,7 +32,7 @@ where } if self_dispersal_at_location > 0.0_f64 - && rng.sample_with::(self_dispersal_at_location) + && Bernoulli::sample_with(rng, self_dispersal_at_location) { return location.clone(); } @@ -45,7 +46,7 @@ impl, G: Rng> SeparableDispersalSampler for InMemorySeparableAliasDispersalSampler where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { #[must_use] fn sample_non_self_dispersal_from_location( diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/mod.rs index 0d6604292..f5c313d8d 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/mod.rs @@ -4,7 +4,7 @@ use alloc::vec::Vec; use necsim_core::{ cogs::{ - rng::{Event, IndexUsize}, + distribution::{Bernoulli, IndexUsize}, Backup, DistributionSampler, Habitat, MathsCore, Rng, }, landscape::Location, @@ -23,7 +23,7 @@ mod dispersal; pub struct InMemorySeparableAliasDispersalSampler, G: Rng> where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { alias_dispersal: Array2D>>, self_dispersal: Array2D, @@ -35,7 +35,7 @@ impl, G: Rng> InMemoryDispersalSampler for InMemorySeparableAliasDispersalSampler where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { /// Creates a new `InMemorySeparableAliasDispersalSampler` from the /// `dispersal` map and extent of the habitat map. @@ -126,7 +126,7 @@ impl, G: Rng> Backup for InMemorySeparableAliasDispersalSampler where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/non_spatial.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/non_spatial.rs index 7be0ddfd3..90d300035 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/non_spatial.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/non_spatial.rs @@ -2,9 +2,9 @@ use core::{marker::PhantomData, num::NonZeroU64}; use necsim_core::{ cogs::{ - rng::{IndexU64, Length}, + distribution::{IndexU64, Length}, Backup, DispersalSampler, DistributionSampler, Habitat, MathsCore, Rng, - SeparableDispersalSampler, + SampledDistribution, SeparableDispersalSampler, }, landscape::Location, }; @@ -65,9 +65,10 @@ where habitat.get_extent().width().get() * habitat.get_extent().height().get(); // Safety: habitat width and height are both > 0 - let dispersal_target_index = rng.sample_with::(Length(unsafe { - NonZeroU64::new_unchecked(habitat_index_max) - })); + let dispersal_target_index = IndexU64::sample_with( + rng, + Length(unsafe { NonZeroU64::new_unchecked(habitat_index_max) }), + ); #[allow(clippy::cast_possible_truncation)] Location::new( @@ -106,9 +107,10 @@ where let dispersal_target_index = { // Safety: by PRE, `habitat_index_max` > 1 - let dispersal_target_index = rng.sample_with::(Length(unsafe { - NonZeroU64::new_unchecked(habitat_index_max - 1) - })); + let dispersal_target_index = IndexU64::sample_with( + rng, + Length(unsafe { NonZeroU64::new_unchecked(habitat_index_max - 1) }), + ); if dispersal_target_index >= current_location_index { dispersal_target_index + 1 diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs index f8c442481..df10d55bd 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs @@ -1,8 +1,8 @@ use necsim_core::{ cogs::{ - rng::{Event, IndexU64}, + distribution::{Bernoulli, IndexU64}, Backup, DispersalSampler, DistributionSampler, Habitat, MathsCore, Rng, - SeparableDispersalSampler, + SampledDistribution, SeparableDispersalSampler, }, landscape::Location, }; @@ -20,7 +20,7 @@ use crate::cogs::{ pub struct SpatiallyImplicitDispersalSampler> where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { #[cfg_attr(feature = "cuda", cuda(embed))] local: NonSpatialDispersalSampler, @@ -32,7 +32,7 @@ where impl> SpatiallyImplicitDispersalSampler where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { #[must_use] pub fn new(local_migration_probability_per_generation: PositiveUnitF64) -> Self { @@ -48,7 +48,7 @@ where impl> Backup for SpatiallyImplicitDispersalSampler where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { @@ -65,7 +65,7 @@ impl> DispersalSampler, G for SpatiallyImplicitDispersalSampler where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { #[must_use] #[debug_ensures(habitat.meta().get_extent().contains(&ret) || ( @@ -84,7 +84,7 @@ where // By PRE, location must be habitable, i.e. either in the local or the meta // habitat if habitat.local().get_extent().contains(location) { - if rng.sample_with::(self.local_migration_probability_per_generation.into()) { + if Bernoulli::sample_with(rng, self.local_migration_probability_per_generation.into()) { // Provide a dummpy Location in the meta community to disperse from self.meta.sample_dispersal_from_location( &Location::new( @@ -110,7 +110,7 @@ impl> SeparableDispersalSampler where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { #[must_use] #[debug_ensures(habitat.meta().get_extent().contains(&ret) || ( @@ -129,7 +129,7 @@ where // By PRE, location must be habitable, i.e. either in the local or the meta // habitat if habitat.local().get_extent().contains(location) { - if rng.sample_with::(self.local_migration_probability_per_generation.into()) { + if Bernoulli::sample_with(rng, self.local_migration_probability_per_generation.into()) { // Provide a dummpy Location in the meta community to disperse from // As the individual is dispersing to a different community, // we can use standard dispersal in the meta community diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/wrapping_noise.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/wrapping_noise.rs index 22c70b7eb..e34611409 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/wrapping_noise.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/wrapping_noise.rs @@ -1,7 +1,8 @@ use necsim_core::{ cogs::{ - Backup, DispersalSampler, Habitat, MathsCore, Rng, - SeparableDispersalSampler, DistributionSampler, rng::{Normal2D, Event}, + distribution::{Bernoulli, Normal2D}, + Backup, DispersalSampler, DistributionSampler, Habitat, MathsCore, Rng, + SampledDistribution, SeparableDispersalSampler, }, landscape::Location, }; @@ -18,8 +19,8 @@ use crate::cogs::{ #[cfg_attr(feature = "cuda", cuda(free = "M"))] pub struct WrappingNoiseApproximateNormalDispersalSampler> where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler, { #[cfg_attr(feature = "cuda", cuda(embed))] inner: AlmostInfiniteNormalDispersalSampler, @@ -27,8 +28,8 @@ where impl> WrappingNoiseApproximateNormalDispersalSampler where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler, { #[must_use] pub fn new(sigma: NonNegativeF64) -> Self { @@ -41,8 +42,8 @@ where #[contract_trait] impl> Backup for WrappingNoiseApproximateNormalDispersalSampler where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { @@ -55,8 +56,8 @@ where impl> DispersalSampler, G> for WrappingNoiseApproximateNormalDispersalSampler where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler, { #[must_use] #[inline] @@ -71,7 +72,10 @@ where // targets are rejected. // If seperable dispersal is not required, this can be implemented as a // direct rejection sampling loop instead. - if rng.sample_with::(self.get_self_dispersal_probability_at_location(location, habitat)) { + if Bernoulli::sample_with( + rng, + self.get_self_dispersal_probability_at_location(location, habitat), + ) { location.clone() } else { self.sample_non_self_dispersal_from_location(location, habitat, rng) @@ -83,8 +87,8 @@ where impl> SeparableDispersalSampler, G> for WrappingNoiseApproximateNormalDispersalSampler where - G::Sampler: DistributionSampler, - G::Sampler: DistributionSampler, + G::Sampler: DistributionSampler + + DistributionSampler, { #[must_use] fn sample_non_self_dispersal_from_location( diff --git a/necsim/impls/no-std/src/cogs/emigration_exit/domain.rs b/necsim/impls/no-std/src/cogs/emigration_exit/domain.rs index 969a16cd7..4ad3d10ba 100644 --- a/necsim/impls/no-std/src/cogs/emigration_exit/domain.rs +++ b/necsim/impls/no-std/src/cogs/emigration_exit/domain.rs @@ -5,7 +5,7 @@ use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_core::{ cogs::{ - coalescence_sampler::CoalescenceRngSample, rng::UniformClosedOpenUnit, Backup, + coalescence_sampler::CoalescenceRngSample, distribution::UniformClosedOpenUnit, Backup, DistributionSampler, EmigrationExit, Habitat, LocallyCoherentLineageStore, MathsCore, Rng, }, landscape::{IndexedLocation, Location}, diff --git a/necsim/impls/no-std/src/cogs/emigration_exit/independent/mod.rs b/necsim/impls/no-std/src/cogs/emigration_exit/independent/mod.rs index 661d30b8b..ed5a2c8b6 100644 --- a/necsim/impls/no-std/src/cogs/emigration_exit/independent/mod.rs +++ b/necsim/impls/no-std/src/cogs/emigration_exit/independent/mod.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ - coalescence_sampler::CoalescenceRngSample, rng::UniformClosedOpenUnit, Backup, + coalescence_sampler::CoalescenceRngSample, distribution::UniformClosedOpenUnit, Backup, DistributionSampler, EmigrationExit, Habitat, MathsCore, Rng, }, landscape::{IndexedLocation, Location}, diff --git a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/mod.rs b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/mod.rs index 39c5d85db..4249a52ca 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/mod.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/mod.rs @@ -2,10 +2,10 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ - coalescence_sampler::CoalescenceRngSample, event_sampler::EventHandler, - rng::UniformClosedOpenUnit, Backup, CoalescenceSampler, DistributionSampler, + coalescence_sampler::CoalescenceRngSample, distribution::UniformClosedOpenUnit, + event_sampler::EventHandler, Backup, CoalescenceSampler, DistributionSampler, EmigrationExit, EventSampler, GloballyCoherentLineageStore, Habitat, MathsCore, Rng, - SeparableDispersalSampler, SpeciationProbability, TurnoverRate, + SampledDistribution, SeparableDispersalSampler, SpeciationProbability, TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, landscape::Location, @@ -143,7 +143,7 @@ where false, ); - let event_sample = probability_at_location.total() * rng.sample::(); + let event_sample = probability_at_location.total() * UniformClosedOpenUnit::sample(rng); if event_sample < probability_at_location.speciation() { // Speciation Event diff --git a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs index 07eb9c646..8877a9ffe 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs @@ -3,11 +3,11 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ coalescence_sampler::CoalescenceRngSample, + distribution::{Bernoulli, UniformClosedOpenUnit}, event_sampler::EventHandler, - rng::{Event, UniformClosedOpenUnit}, Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, EmigrationExit, - EventSampler, GloballyCoherentLineageStore, Habitat, MathsCore, Rng, SpeciationProbability, - TurnoverRate, + EventSampler, GloballyCoherentLineageStore, Habitat, MathsCore, Rng, SampledDistribution, + SpeciationProbability, TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, landscape::Location, @@ -31,7 +31,7 @@ pub struct UnconditionalGillespieEventSampler< T: TurnoverRate, N: SpeciationProbability, > where - G::Sampler: DistributionSampler + G::Sampler: DistributionSampler + DistributionSampler, { #[allow(clippy::type_complexity)] @@ -50,7 +50,7 @@ impl< N: SpeciationProbability, > Default for UnconditionalGillespieEventSampler where - G::Sampler: DistributionSampler + G::Sampler: DistributionSampler + DistributionSampler, { fn default() -> Self { @@ -73,7 +73,7 @@ impl< N: SpeciationProbability, > Backup for UnconditionalGillespieEventSampler where - G::Sampler: DistributionSampler + G::Sampler: DistributionSampler + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { @@ -97,7 +97,7 @@ impl< > EventSampler for UnconditionalGillespieEventSampler where - G::Sampler: DistributionSampler + G::Sampler: DistributionSampler + DistributionSampler, { #[must_use] @@ -124,7 +124,8 @@ where }: EventHandler, auxiliary: Aux, ) -> Q { - if rng.sample_with::( + if Bernoulli::sample_with( + rng, simulation .speciation_probability .get_speciation_probability_at_location( @@ -207,7 +208,7 @@ impl< > GillespieEventSampler for UnconditionalGillespieEventSampler where - G::Sampler: DistributionSampler + G::Sampler: DistributionSampler + DistributionSampler, { #[must_use] diff --git a/necsim/impls/no-std/src/cogs/event_sampler/independent.rs b/necsim/impls/no-std/src/cogs/event_sampler/independent.rs index 6592ebdf8..9a35ff8b2 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/independent.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/independent.rs @@ -2,10 +2,10 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ - coalescence_sampler::CoalescenceRngSample, event_sampler::EventHandler, - rng::UniformClosedOpenUnit, Backup, CoalescenceSampler, DispersalSampler, + coalescence_sampler::CoalescenceRngSample, distribution::UniformClosedOpenUnit, + event_sampler::EventHandler, Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, EmigrationExit, EventSampler, Habitat, MathsCore, Rng, - SpeciationProbability, TurnoverRate, + SampledDistribution, SpeciationProbability, TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, lineage::Lineage, @@ -156,7 +156,7 @@ where }: EventHandler, auxiliary: Aux, ) -> Q { - let speciation_sample = rng.sample::(); + let speciation_sample = UniformClosedOpenUnit::sample(rng); SpeciationSample::update_min( &mut self.min_spec_sample, diff --git a/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs b/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs index 2b6da1505..3081e0ab4 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs @@ -3,11 +3,11 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ coalescence_sampler::CoalescenceRngSample, + distribution::{Bernoulli, UniformClosedOpenUnit}, event_sampler::EventHandler, - rng::{Event, UniformClosedOpenUnit}, Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, EmigrationExit, - EventSampler, Habitat, LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, - TurnoverRate, + EventSampler, Habitat, LocallyCoherentLineageStore, MathsCore, Rng, SampledDistribution, + SpeciationProbability, TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, lineage::Lineage, @@ -28,7 +28,7 @@ pub struct UnconditionalEventSampler< T: TurnoverRate, N: SpeciationProbability, > where - G::Sampler: DistributionSampler + G::Sampler: DistributionSampler + DistributionSampler, { #[allow(clippy::type_complexity)] @@ -47,7 +47,7 @@ impl< N: SpeciationProbability, > Default for UnconditionalEventSampler where - G::Sampler: DistributionSampler + G::Sampler: DistributionSampler + DistributionSampler, { fn default() -> Self { @@ -70,7 +70,7 @@ impl< N: SpeciationProbability, > Backup for UnconditionalEventSampler where - G::Sampler: DistributionSampler + G::Sampler: DistributionSampler + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { @@ -94,7 +94,7 @@ impl< > EventSampler for UnconditionalEventSampler where - G::Sampler: DistributionSampler + G::Sampler: DistributionSampler + DistributionSampler, { #[must_use] @@ -121,7 +121,8 @@ where }: EventHandler, auxiliary: Aux, ) -> Q { - if rng.sample_with::( + if Bernoulli::sample_with( + rng, simulation .speciation_probability .get_speciation_probability_at_location( diff --git a/necsim/impls/no-std/src/cogs/habitat/in_memory.rs b/necsim/impls/no-std/src/cogs/habitat/in_memory.rs index 146b8ed81..4249f254b 100644 --- a/necsim/impls/no-std/src/cogs/habitat/in_memory.rs +++ b/necsim/impls/no-std/src/cogs/habitat/in_memory.rs @@ -6,8 +6,9 @@ use r#final::Final; use necsim_core::{ cogs::{ - rng::{IndexU64, Length}, - Backup, DistributionSampler, Habitat, MathsCore, Rng, UniformlySampleableHabitat, + distribution::{IndexU64, Length}, + Backup, DistributionSampler, Habitat, MathsCore, Rng, SampledDistribution, + UniformlySampleableHabitat, }, landscape::{IndexedLocation, LandscapeExtent, Location}, }; @@ -117,7 +118,7 @@ where #[inline] fn sample_habitable_indexed_location(&self, rng: &mut G) -> IndexedLocation { let indexed_location_index = - rng.sample_with::(Length(self.get_total_habitat().into())); + IndexU64::sample_with(rng, Length(self.get_total_habitat().into())); let location_index = match self.u64_injection.binary_search(&indexed_location_index) { Ok(index) => index, diff --git a/necsim/impls/no-std/src/cogs/habitat/non_spatial.rs b/necsim/impls/no-std/src/cogs/habitat/non_spatial.rs index 03d421a42..b4a900fc8 100644 --- a/necsim/impls/no-std/src/cogs/habitat/non_spatial.rs +++ b/necsim/impls/no-std/src/cogs/habitat/non_spatial.rs @@ -5,8 +5,9 @@ use core::{ use necsim_core::{ cogs::{ - rng::{IndexU64, Length}, - Backup, DistributionSampler, Habitat, MathsCore, Rng, UniformlySampleableHabitat, + distribution::{IndexU64, Length}, + Backup, DistributionSampler, Habitat, MathsCore, Rng, SampledDistribution, + UniformlySampleableHabitat, }, landscape::{IndexedLocation, LandscapeExtent, Location}, }; @@ -130,9 +131,10 @@ where self.extent.width().get() * self.extent.height().get() * u64::from(self.deme.get()); // Safety: habitat width, height, and deme are all > 0 - let mut dispersal_target_index = rng.sample_with::(Length(unsafe { - NonZeroU64::new_unchecked(habitat_index_max) - })); + let mut dispersal_target_index = IndexU64::sample_with( + rng, + Length(unsafe { NonZeroU64::new_unchecked(habitat_index_max) }), + ); #[allow(clippy::cast_possible_truncation)] let index = (dispersal_target_index % u64::from(self.deme.get())) as u32; dispersal_target_index /= u64::from(self.deme.get()); diff --git a/necsim/impls/no-std/src/cogs/habitat/spatially_implicit.rs b/necsim/impls/no-std/src/cogs/habitat/spatially_implicit.rs index e029edf6c..964eb63a4 100644 --- a/necsim/impls/no-std/src/cogs/habitat/spatially_implicit.rs +++ b/necsim/impls/no-std/src/cogs/habitat/spatially_implicit.rs @@ -2,7 +2,7 @@ use core::num::NonZeroU32; use necsim_core::{ cogs::{ - rng::IndexU64, Backup, DistributionSampler, Habitat, MathsCore, Rng, + distribution::IndexU64, Backup, DistributionSampler, Habitat, MathsCore, Rng, UniformlySampleableHabitat, }, landscape::{IndexedLocation, LandscapeExtent, Location}, diff --git a/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/mod.rs b/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/mod.rs index 5d87ec583..a3765b19f 100644 --- a/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/mod.rs +++ b/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/mod.rs @@ -10,7 +10,7 @@ mod opensimplex_noise; use opensimplex_noise::OpenSimplexNoise; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, Rng, UniformlySampleableHabitat, RngCore}, + cogs::{Backup, Habitat, MathsCore, Rng, RngCore, UniformlySampleableHabitat}, landscape::{IndexedLocation, LandscapeExtent, Location}, }; diff --git a/necsim/impls/no-std/src/cogs/rng/mod.rs b/necsim/impls/no-std/src/cogs/rng/mod.rs index 43c2bf6e6..62fe40a87 100644 --- a/necsim/impls/no-std/src/cogs/rng/mod.rs +++ b/necsim/impls/no-std/src/cogs/rng/mod.rs @@ -1,3 +1,4 @@ pub mod rand; pub mod seahash; +pub mod simple; pub mod wyhash; diff --git a/necsim/impls/no-std/src/cogs/rng/simple.rs b/necsim/impls/no-std/src/cogs/rng/simple.rs new file mode 100644 index 000000000..010aa98af --- /dev/null +++ b/necsim/impls/no-std/src/cogs/rng/simple.rs @@ -0,0 +1,553 @@ +use core::{ + marker::PhantomData, + num::{NonZeroU128, NonZeroU32, NonZeroU64, NonZeroUsize}, +}; + +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +use necsim_core::cogs::{ + distribution::{ + Bernoulli, Exponential, IndexU128, IndexU32, IndexU64, IndexUsize, Lambda, Length, Normal, + Normal2D, Poisson, StandardNormal2D, UniformClosedOpenUnit, UniformOpenClosedUnit, + }, + Backup, DistributionSampler, MathsCore, Rng, RngCore, +}; +use necsim_core_bond::{ClosedOpenUnitF64, ClosedUnitF64, NonNegativeF64, OpenClosedUnitF64}; + +#[derive(Clone, Debug, TypeLayout)] +#[allow(clippy::module_name_repetitions)] +#[layout(free = "M")] +#[repr(transparent)] +pub struct SimpleRng { + inner: R, + marker: PhantomData, +} + +impl Serialize for SimpleRng { + fn serialize(&self, serializer: S) -> Result { + self.inner.serialize(serializer) + } +} + +impl<'de, M: MathsCore, R: RngCore> Deserialize<'de> for SimpleRng { + fn deserialize>(deserializer: D) -> Result { + let inner = R::deserialize(deserializer)?; + + Ok(Self { + inner, + marker: PhantomData::, + }) + } +} + +#[contract_trait] +impl Backup for SimpleRng { + unsafe fn backup_unchecked(&self) -> Self { + Self { + inner: self.inner.backup_unchecked(), + marker: PhantomData::, + } + } +} + +impl RngCore for SimpleRng { + type Seed = R::Seed; + + #[must_use] + fn from_seed(seed: Self::Seed) -> Self { + Self { + inner: R::from_seed(seed), + marker: PhantomData::, + } + } + + #[must_use] + fn sample_u64(&mut self) -> u64 { + self.inner.sample_u64() + } +} + +impl Rng for SimpleRng { + type Generator = R; + type Sampler = SimplerDistributionSamplers; + + fn generator(&mut self) -> &mut Self::Generator { + &mut self.inner + } + + fn map_generator Self::Generator>(self, map: F) -> Self { + let SimpleRng { inner, marker } = self; + + SimpleRng { + inner: map(inner), + marker, + } + } + + fn with_rng Q, Q>(&mut self, inner: F) -> Q { + let samplers = SimplerDistributionSamplers { + _marker: PhantomData::<(M, R)>, + }; + + inner(&mut self.inner, &samplers) + } +} + +#[allow(clippy::module_name_repetitions)] +pub struct SimplerDistributionSamplers { + _marker: PhantomData<(M, R)>, +} + +impl DistributionSampler + for SimplerDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with(&self, rng: &mut R, _samplers: &S, _params: ()) -> ClosedOpenUnitF64 { + // http://prng.di.unimi.it -> Generating uniform doubles in the unit interval + #[allow(clippy::cast_precision_loss)] + let u01 = ((rng.sample_u64() >> 11) as f64) * f64::from_bits(0x3CA0_0000_0000_0000_u64); // 0x1.0p-53 + + unsafe { ClosedOpenUnitF64::new_unchecked(u01) } + } +} + +impl DistributionSampler + for SimplerDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with(&self, rng: &mut R, _samplers: &S, _params: ()) -> OpenClosedUnitF64 { + // http://prng.di.unimi.it -> Generating uniform doubles in the unit interval + #[allow(clippy::cast_precision_loss)] + let u01 = + (((rng.sample_u64() >> 11) + 1) as f64) * f64::from_bits(0x3CA0_0000_0000_0000_u64); // 0x1.0p-53 + + unsafe { OpenClosedUnitF64::new_unchecked(u01) } + } +} + +impl> + DistributionSampler for SimplerDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with(&self, rng: &mut R, samplers: &S, params: Length) -> usize { + let length = params.0; + + let u01: ClosedOpenUnitF64 = samplers.sample(rng, samplers); + + #[allow( + clippy::cast_precision_loss, + clippy::cast_possible_truncation, + clippy::cast_sign_loss + )] + let index = M::floor(u01.get() * (length.get() as f64)) as usize; + + // Safety in case of f64 rounding errors + index.min(length.get() - 1) + } +} + +impl> + DistributionSampler for SimplerDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with(&self, rng: &mut R, samplers: &S, params: Length) -> u32 { + let length = params.0; + + let u01: ClosedOpenUnitF64 = samplers.sample(rng, samplers); + + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + let index = M::floor(u01.get() * f64::from(length.get())) as u32; + + // Safety in case of f64 rounding errors + index.min(length.get() - 1) + } +} + +impl> + DistributionSampler for SimplerDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with(&self, rng: &mut R, samplers: &S, params: Length) -> u64 { + let length = params.0; + + let u01: ClosedOpenUnitF64 = samplers.sample(rng, samplers); + + #[allow( + clippy::cast_precision_loss, + clippy::cast_possible_truncation, + clippy::cast_sign_loss + )] + let index = M::floor(u01.get() * (length.get() as f64)) as u64; + + // Safety in case of f64 rounding errors + index.min(length.get() - 1) + } +} + +impl> + DistributionSampler for SimplerDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with(&self, rng: &mut R, samplers: &S, params: Length) -> u128 { + let length = params.0; + + let u01: ClosedOpenUnitF64 = samplers.sample(rng, samplers); + + #[allow( + clippy::cast_precision_loss, + clippy::cast_possible_truncation, + clippy::cast_sign_loss + )] + let index = M::floor(u01.get() * (length.get() as f64)) as u128; + + // Safety in case of f64 rounding errors + index.min(length.get() - 1) + } +} + +impl> + DistributionSampler for SimplerDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with(&self, rng: &mut R, samplers: &S, params: Lambda) -> NonNegativeF64 { + let lambda = params.0; + + let u01: OpenClosedUnitF64 = samplers.sample(rng, samplers); + + // Inverse transform sample: X = -ln(U(0,1]) / lambda + -u01.ln::() / lambda + } +} + +impl< + M: MathsCore, + R: RngCore, + S: DistributionSampler + + DistributionSampler, + > DistributionSampler for SimplerDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with(&self, rng: &mut R, samplers: &S, params: Lambda) -> usize { + let lambda = params.0; + let no_event_probability = M::exp(-lambda.get()); + + if no_event_probability <= 0.0_f64 { + // Fallback in case no_event_probability_per_step underflows + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + let normal_as_poisson = DistributionSampler::::sample_with( + samplers, + rng, + samplers, + Normal { + mu: lambda.get(), + sigma: NonNegativeF64::from(lambda).sqrt::(), + }, + ) + .0 + .max(0.0_f64) as usize; + + return normal_as_poisson; + } + + // https://en.wikipedia.org/wiki/Poisson_distribution#cite_ref-Devroye1986_54-0 + let mut poisson = 0_usize; + let mut prod = no_event_probability; + let mut acc = no_event_probability; + + let u = + DistributionSampler::::sample(samplers, rng, samplers); + + #[allow(clippy::cast_precision_loss)] + while u > acc && prod > 0.0_f64 { + poisson += 1; + prod *= lambda.get() / (poisson as f64); + acc += prod; + } + + poisson + } +} + +impl> + DistributionSampler for SimplerDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with(&self, rng: &mut R, samplers: &S, params: ClosedUnitF64) -> bool { + let probability = params; + + let u01: ClosedOpenUnitF64 = samplers.sample(rng, samplers); + + // if probability == 1, then U[0, 1) always < 1.0 + // if probability == 0, then U[0, 1) never < 0.0 + u01 < probability + } +} + +impl< + M: MathsCore, + R: RngCore, + S: DistributionSampler + + DistributionSampler, + > DistributionSampler for SimplerDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with(&self, rng: &mut R, samplers: &S, _params: ()) -> (f64, f64) { + // Basic Box-Muller transform + let u0 = + DistributionSampler::::sample(samplers, rng, samplers); + let u1 = + DistributionSampler::::sample(samplers, rng, samplers); + + let r = M::sqrt(-2.0_f64 * M::ln(u0.get())); + let theta = -core::f64::consts::TAU * u1.get(); + + (r * M::sin(theta), r * M::cos(theta)) + } +} + +impl> + DistributionSampler for SimplerDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_with(&self, rng: &mut R, samplers: &S, params: Normal) -> (f64, f64) { + let (z0, z1) = samplers.sample(rng, samplers); + + ( + z0 * params.sigma.get() + params.mu, + z1 * params.sigma.get() + params.mu, + ) + } +} + +/*#[allow(clippy::inline_always, clippy::inline_fn_without_body)] +#[allow(clippy::module_name_repetitions)] +#[contract_trait] +pub trait RngSampler: RngCore { + #[must_use] + #[inline] + /// Samples a uniform sample within `[0.0, 1.0)`, i.e. `0.0 <= X < 1.0` + fn sample_uniform_closed_open(&mut self) -> ClosedOpenUnitF64 { + // http://prng.di.unimi.it -> Generating uniform doubles in the unit interval + #[allow(clippy::cast_precision_loss)] + let u01 = ((self.sample_u64() >> 11) as f64) * f64::from_bits(0x3CA0_0000_0000_0000_u64); // 0x1.0p-53 + + unsafe { ClosedOpenUnitF64::new_unchecked(u01) } + } + + #[must_use] + #[inline] + /// Samples a uniform sample within `(0.0, 1.0]`, i.e. `0.0 < X <= 1.0` + fn sample_uniform_open_closed(&mut self) -> OpenClosedUnitF64 { + // http://prng.di.unimi.it -> Generating uniform doubles in the unit interval + #[allow(clippy::cast_precision_loss)] + let u01 = + (((self.sample_u64() >> 11) + 1) as f64) * f64::from_bits(0x3CA0_0000_0000_0000_u64); // 0x1.0p-53 + + unsafe { OpenClosedUnitF64::new_unchecked(u01) } + } + + #[must_use] + #[inline] + #[debug_ensures(ret < length.get(), "samples U(0, length - 1)")] + fn sample_index(&mut self, length: NonZeroUsize) -> usize { + #[cfg(target_pointer_width = "32")] + #[allow(clippy::cast_possible_truncation)] + { + self.sample_index_u32(unsafe { NonZeroU32::new_unchecked(length.get() as u32) }) + as usize + } + #[cfg(target_pointer_width = "64")] + #[allow(clippy::cast_possible_truncation)] + { + self.sample_index_u64(unsafe { NonZeroU64::new_unchecked(length.get() as u64) }) + as usize + } + } + + #[must_use] + #[inline] + #[debug_ensures(ret < length.get(), "samples U(0, length - 1)")] + fn sample_index_u32(&mut self, length: NonZeroU32) -> u32 { + // TODO: Check if delegation to `sample_index_u64` is faster + + // Adapted from: + // https://docs.rs/rand/0.8.4/rand/distributions/uniform/trait.UniformSampler.html#method.sample_single + + const LOWER_MASK: u64 = !0 >> 32; + + // Conservative approximation of the acceptance zone + let acceptance_zone = (length.get() << length.leading_zeros()).wrapping_sub(1); + + loop { + let raw = self.sample_u64(); + + let sample_check_lo = (raw & LOWER_MASK) * u64::from(length.get()); + + #[allow(clippy::cast_possible_truncation)] + if (sample_check_lo as u32) <= acceptance_zone { + return (sample_check_lo >> 32) as u32; + } + + let sample_check_hi = (raw >> 32) * u64::from(length.get()); + + #[allow(clippy::cast_possible_truncation)] + if (sample_check_hi as u32) <= acceptance_zone { + return (sample_check_hi >> 32) as u32; + } + } + } + + #[must_use] + #[inline] + #[debug_ensures(ret < length.get(), "samples U(0, length - 1)")] + fn sample_index_u64(&mut self, length: NonZeroU64) -> u64 { + // Adapted from: + // https://docs.rs/rand/0.8.4/rand/distributions/uniform/trait.UniformSampler.html#method.sample_single + + // Conservative approximation of the acceptance zone + let acceptance_zone = (length.get() << length.leading_zeros()).wrapping_sub(1); + + loop { + let raw = self.sample_u64(); + + let sample_check = u128::from(raw) * u128::from(length.get()); + + #[allow(clippy::cast_possible_truncation)] + if (sample_check as u64) <= acceptance_zone { + return (sample_check >> 64) as u64; + } + } + } + + #[must_use] + #[inline] + #[debug_ensures(ret < length.get(), "samples U(0, length - 1)")] + fn sample_index_u128(&mut self, length: NonZeroU128) -> u128 { + // Adapted from: + // https://docs.rs/rand/0.8.4/rand/distributions/uniform/trait.UniformSampler.html#method.sample_single + + const LOWER_MASK: u128 = !0 >> 64; + + // Conservative approximation of the acceptance zone + let acceptance_zone = (length.get() << length.leading_zeros()).wrapping_sub(1); + + loop { + let raw_hi = u128::from(self.sample_u64()); + let raw_lo = u128::from(self.sample_u64()); + + // 256-bit multiplication (hi, lo) = (raw_hi, raw_lo) * length + let mut low = raw_lo * (length.get() & LOWER_MASK); + let mut t = low >> 64; + low &= LOWER_MASK; + t += raw_hi * (length.get() & LOWER_MASK); + low += (t & LOWER_MASK) << 64; + let mut high = t >> 64; + t = low >> 64; + low &= LOWER_MASK; + t += (length.get() >> 64) * raw_lo; + low += (t & LOWER_MASK) << 64; + high += t >> 64; + high += raw_hi * (length.get() >> 64); + + let sample = high; + let check = low; + + if check <= acceptance_zone { + return sample; + } + } + } + + #[must_use] + #[inline] + fn sample_exponential(&mut self, lambda: PositiveF64) -> NonNegativeF64 { + // Inverse transform sample: X = -ln(U(0,1]) / lambda + -self.sample_uniform_open_closed().ln::() / lambda + } + + #[must_use] + #[inline] + fn sample_event(&mut self, probability: ClosedUnitF64) -> bool { + // if probability == 1, then U[0, 1) always < 1.0 + // if probability == 0, then U[0, 1) never < 0.0 + self.sample_uniform_closed_open() < probability + } + + #[must_use] + #[inline] + fn sample_2d_standard_normal(&mut self) -> (f64, f64) { + // Basic Box-Muller transform + let u0 = self.sample_uniform_open_closed(); + let u1 = self.sample_uniform_closed_open(); + + let r = M::sqrt(-2.0_f64 * M::ln(u0.get())); + let theta = -core::f64::consts::TAU * u1.get(); + + (r * M::sin(theta), r * M::cos(theta)) + } + + #[must_use] + #[inline] + fn sample_2d_normal(&mut self, mu: f64, sigma: NonNegativeF64) -> (f64, f64) { + let (z0, z1) = self.sample_2d_standard_normal(); + + (z0 * sigma.get() + mu, z1 * sigma.get() + mu) + } +} + +impl> RngSampler for R {}*/ diff --git a/necsim/impls/no-std/src/parallelisation/independent/individuals.rs b/necsim/impls/no-std/src/parallelisation/independent/individuals.rs index a442883df..f01b3032f 100644 --- a/necsim/impls/no-std/src/parallelisation/independent/individuals.rs +++ b/necsim/impls/no-std/src/parallelisation/independent/individuals.rs @@ -9,8 +9,8 @@ use necsim_core_bond::NonNegativeF64; use necsim_core::{ cogs::{ - rng::UniformClosedOpenUnit, DispersalSampler, DistributionSampler, Habitat, MathsCore, - PrimeableRng, Rng, SpeciationProbability, TurnoverRate, + distribution::UniformClosedOpenUnit, DispersalSampler, DistributionSampler, Habitat, + MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, }, lineage::Lineage, reporter::Reporter, diff --git a/necsim/impls/no-std/src/parallelisation/independent/landscape.rs b/necsim/impls/no-std/src/parallelisation/independent/landscape.rs index 292e6f78f..63eab7f35 100644 --- a/necsim/impls/no-std/src/parallelisation/independent/landscape.rs +++ b/necsim/impls/no-std/src/parallelisation/independent/landscape.rs @@ -9,8 +9,8 @@ use necsim_core_bond::NonNegativeF64; use necsim_core::{ cogs::{ - rng::UniformClosedOpenUnit, DispersalSampler, DistributionSampler, Habitat, MathsCore, - PrimeableRng, Rng, SpeciationProbability, TurnoverRate, + distribution::UniformClosedOpenUnit, DispersalSampler, DistributionSampler, Habitat, + MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, }, event::DispersalEvent, landscape::IndexedLocation, diff --git a/necsim/impls/no-std/src/parallelisation/independent/monolithic/mod.rs b/necsim/impls/no-std/src/parallelisation/independent/monolithic/mod.rs index b7508aaf1..a2e753bc3 100644 --- a/necsim/impls/no-std/src/parallelisation/independent/monolithic/mod.rs +++ b/necsim/impls/no-std/src/parallelisation/independent/monolithic/mod.rs @@ -8,8 +8,8 @@ use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_core::{ cogs::{ - rng::UniformClosedOpenUnit, DispersalSampler, DistributionSampler, Habitat, MathsCore, - PrimeableRng, Rng, SpeciationProbability, TurnoverRate, + distribution::UniformClosedOpenUnit, DispersalSampler, DistributionSampler, Habitat, + MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, }, lineage::Lineage, reporter::{boolean::Boolean, Reporter}, diff --git a/necsim/impls/no-std/src/parallelisation/monolithic/averaging.rs b/necsim/impls/no-std/src/parallelisation/monolithic/averaging.rs index c535f74b9..58e69d69e 100644 --- a/necsim/impls/no-std/src/parallelisation/monolithic/averaging.rs +++ b/necsim/impls/no-std/src/parallelisation/monolithic/averaging.rs @@ -2,9 +2,9 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ - rng::UniformClosedOpenUnit, ActiveLineageSampler, CoalescenceSampler, DispersalSampler, - DistributionSampler, EventSampler, Habitat, LocallyCoherentLineageStore, MathsCore, Rng, - SpeciationProbability, TurnoverRate, + distribution::UniformClosedOpenUnit, ActiveLineageSampler, CoalescenceSampler, + DispersalSampler, DistributionSampler, EventSampler, Habitat, LocallyCoherentLineageStore, + MathsCore, Rng, SpeciationProbability, TurnoverRate, }, reporter::Reporter, simulation::Simulation, diff --git a/necsim/impls/no-std/src/parallelisation/monolithic/lockstep.rs b/necsim/impls/no-std/src/parallelisation/monolithic/lockstep.rs index deebee9a9..3450fc1d7 100644 --- a/necsim/impls/no-std/src/parallelisation/monolithic/lockstep.rs +++ b/necsim/impls/no-std/src/parallelisation/monolithic/lockstep.rs @@ -2,9 +2,9 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ - rng::UniformClosedOpenUnit, ActiveLineageSampler, CoalescenceSampler, DispersalSampler, - DistributionSampler, EventSampler, Habitat, LocallyCoherentLineageStore, MathsCore, Rng, - SpeciationProbability, TurnoverRate, + distribution::UniformClosedOpenUnit, ActiveLineageSampler, CoalescenceSampler, + DispersalSampler, DistributionSampler, EventSampler, Habitat, LocallyCoherentLineageStore, + MathsCore, Rng, SpeciationProbability, TurnoverRate, }, reporter::{NullReporter, Reporter}, simulation::Simulation, diff --git a/necsim/impls/no-std/src/parallelisation/monolithic/optimistic.rs b/necsim/impls/no-std/src/parallelisation/monolithic/optimistic.rs index 3924e6ffd..a0b6838cd 100644 --- a/necsim/impls/no-std/src/parallelisation/monolithic/optimistic.rs +++ b/necsim/impls/no-std/src/parallelisation/monolithic/optimistic.rs @@ -3,7 +3,7 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ - backup::BackedUp, rng::UniformClosedOpenUnit, ActiveLineageSampler, Backup, + backup::BackedUp, distribution::UniformClosedOpenUnit, ActiveLineageSampler, Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, EventSampler, Habitat, LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, }, diff --git a/necsim/impls/no-std/src/parallelisation/monolithic/optimistic_lockstep.rs b/necsim/impls/no-std/src/parallelisation/monolithic/optimistic_lockstep.rs index acc862bf6..789568ab4 100644 --- a/necsim/impls/no-std/src/parallelisation/monolithic/optimistic_lockstep.rs +++ b/necsim/impls/no-std/src/parallelisation/monolithic/optimistic_lockstep.rs @@ -2,7 +2,7 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ - rng::UniformClosedOpenUnit, ActiveLineageSampler, Backup, CoalescenceSampler, + distribution::UniformClosedOpenUnit, ActiveLineageSampler, Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, EventSampler, Habitat, LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, }, diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs b/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs index 255da478e..8a342b4a4 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs @@ -34,7 +34,7 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_core::cogs::rng::SimpleRng< + necsim_impls_no_std::cogs::rng::simple::SimpleRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, @@ -56,7 +56,7 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_core::cogs::rng::SimpleRng< + necsim_impls_no_std::cogs::rng::simple::SimpleRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, @@ -72,7 +72,7 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_core::cogs::rng::SimpleRng< + necsim_impls_no_std::cogs::rng::simple::SimpleRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, @@ -92,7 +92,7 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_core::cogs::rng::SimpleRng< + necsim_impls_no_std::cogs::rng::simple::SimpleRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, @@ -107,7 +107,7 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_core::cogs::rng::SimpleRng< + necsim_impls_no_std::cogs::rng::simple::SimpleRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, @@ -118,7 +118,7 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_core::cogs::rng::SimpleRng< + necsim_impls_no_std::cogs::rng::simple::SimpleRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, @@ -136,7 +136,7 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_core::cogs::rng::SimpleRng< + necsim_impls_no_std::cogs::rng::simple::SimpleRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, @@ -147,7 +147,7 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_core::cogs::rng::SimpleRng< + necsim_impls_no_std::cogs::rng::simple::SimpleRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, @@ -158,7 +158,7 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_core::cogs::rng::SimpleRng< + necsim_impls_no_std::cogs::rng::simple::SimpleRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, @@ -174,7 +174,7 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_core::cogs::rng::SimpleRng< + necsim_impls_no_std::cogs::rng::simple::SimpleRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, @@ -185,7 +185,7 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_core::cogs::rng::SimpleRng< + necsim_impls_no_std::cogs::rng::simple::SimpleRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, @@ -196,7 +196,7 @@ macro_rules! link_kernel { $habitat, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_core::cogs::rng::SimpleRng< + necsim_impls_no_std::cogs::rng::simple::SimpleRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, @@ -221,7 +221,7 @@ link_kernel!( necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_core::cogs::rng::SimpleRng< + necsim_impls_no_std::cogs::rng::simple::SimpleRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, @@ -239,7 +239,7 @@ link_kernel!( necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_core::cogs::rng::SimpleRng< + necsim_impls_no_std::cogs::rng::simple::SimpleRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, @@ -257,7 +257,7 @@ link_kernel!( necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_core::cogs::rng::SimpleRng< + necsim_impls_no_std::cogs::rng::simple::SimpleRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, @@ -278,7 +278,7 @@ link_kernel!( >, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_core::cogs::rng::SimpleRng< + necsim_impls_no_std::cogs::rng::simple::SimpleRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, @@ -299,7 +299,7 @@ link_kernel!( >, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_core::cogs::rng::SimpleRng< + necsim_impls_no_std::cogs::rng::simple::SimpleRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, @@ -317,9 +317,7 @@ link_kernel!( necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_impls_no_std::cogs::rng::wyhash::WyHash< - necsim_impls_cuda::cogs::maths::NvptxMathsCore - >, + necsim_impls_no_std::cogs::rng::wyhash::WyHash, >, >, necsim_impls_no_std::cogs::turnover_rate::uniform::UniformTurnoverRate, diff --git a/rustcoalescence/algorithms/cuda/src/initialiser/fixup.rs b/rustcoalescence/algorithms/cuda/src/initialiser/fixup.rs index ab03e1758..fd7620ecb 100644 --- a/rustcoalescence/algorithms/cuda/src/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/cuda/src/initialiser/fixup.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - rng::{Event, IndexUsize, UniformClosedOpenUnit}, + distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, DistributionSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, }, lineage::Lineage, @@ -55,7 +55,7 @@ where O::TurnoverRate: RustToCuda, O::SpeciationProbability: RustToCuda, G::Sampler: DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler, { type ActiveLineageSampler< diff --git a/rustcoalescence/algorithms/cuda/src/initialiser/genesis.rs b/rustcoalescence/algorithms/cuda/src/initialiser/genesis.rs index 499f2d0f4..a0d5c5188 100644 --- a/rustcoalescence/algorithms/cuda/src/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/cuda/src/initialiser/genesis.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - rng::{Event, IndexUsize, UniformClosedOpenUnit}, + distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, DistributionSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, }, lineage::Lineage, @@ -34,7 +34,7 @@ where O::TurnoverRate: RustToCuda, O::SpeciationProbability: RustToCuda, G::Sampler: DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler, { type ActiveLineageSampler< diff --git a/rustcoalescence/algorithms/cuda/src/initialiser/mod.rs b/rustcoalescence/algorithms/cuda/src/initialiser/mod.rs index 09f931146..3ebb5b28e 100644 --- a/rustcoalescence/algorithms/cuda/src/initialiser/mod.rs +++ b/rustcoalescence/algorithms/cuda/src/initialiser/mod.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - rng::{Event, IndexUsize, UniformClosedOpenUnit}, + distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, DispersalSampler, DistributionSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, }, lineage::Lineage, @@ -40,7 +40,7 @@ pub trait CudaLineageStoreSampleInitialiser< O::TurnoverRate: RustToCuda, O::SpeciationProbability: RustToCuda, G::Sampler: DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler, { type DispersalSampler: DispersalSampler + RustToCuda; diff --git a/rustcoalescence/algorithms/cuda/src/initialiser/resume.rs b/rustcoalescence/algorithms/cuda/src/initialiser/resume.rs index 417bbb08e..77228019f 100644 --- a/rustcoalescence/algorithms/cuda/src/initialiser/resume.rs +++ b/rustcoalescence/algorithms/cuda/src/initialiser/resume.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - rng::{Event, IndexUsize, UniformClosedOpenUnit}, + distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, DistributionSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, }, lineage::Lineage, @@ -44,7 +44,7 @@ where O::TurnoverRate: RustToCuda, O::SpeciationProbability: RustToCuda, G::Sampler: DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler, { type ActiveLineageSampler< diff --git a/rustcoalescence/algorithms/cuda/src/launch.rs b/rustcoalescence/algorithms/cuda/src/launch.rs index 90cbc9350..e1a7fc747 100644 --- a/rustcoalescence/algorithms/cuda/src/launch.rs +++ b/rustcoalescence/algorithms/cuda/src/launch.rs @@ -1,10 +1,6 @@ use std::marker::PhantomData; -use necsim_core::{ - cogs::{rng::SimpleRng, MathsCore}, - reporter::Reporter, - simulation::SimulationBuilder, -}; +use necsim_core::{cogs::MathsCore, reporter::Reporter, simulation::SimulationBuilder}; use necsim_core_bond::NonNegativeF64; use necsim_impls_cuda::cogs::rng::CudaRng; @@ -20,7 +16,7 @@ use necsim_impls_no_std::{ origin_sampler::{ decomposition::DecompositionOriginSampler, pre_sampler::OriginPreSampler, }, - rng::wyhash::WyHash, + rng::{simple::SimpleRng, wyhash::WyHash}, }, parallelisation::Status, }; diff --git a/rustcoalescence/algorithms/cuda/src/lib.rs b/rustcoalescence/algorithms/cuda/src/lib.rs index a88d58a51..df9cc279f 100644 --- a/rustcoalescence/algorithms/cuda/src/lib.rs +++ b/rustcoalescence/algorithms/cuda/src/lib.rs @@ -6,11 +6,7 @@ #[macro_use] extern crate serde_derive_state; -use necsim_core::{ - cogs::{rng::SimpleRng, MathsCore}, - lineage::Lineage, - reporter::Reporter, -}; +use necsim_core::{cogs::MathsCore, lineage::Lineage, reporter::Reporter}; use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_impls_cuda::cogs::{maths::NvptxMathsCore, rng::CudaRng}; @@ -31,7 +27,7 @@ use necsim_impls_no_std::cogs::{ immigration_entry::never::NeverImmigrationEntry, lineage_store::independent::IndependentLineageStore, origin_sampler::pre_sampler::OriginPreSampler, - rng::wyhash::WyHash, + rng::{simple::SimpleRng, wyhash::WyHash}, }; use necsim_partitioning_core::{partition::Partition, LocalPartition}; diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/fixup.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/fixup.rs index 1b05a8d52..4a4f1bf86 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/fixup.rs @@ -1,6 +1,8 @@ use necsim_core::{ cogs::{ - rng::{Event, Exponential, IndexU128, IndexU64, IndexUsize, UniformClosedOpenUnit}, + distribution::{ + Bernoulli, Exponential, IndexU128, IndexU64, IndexUsize, UniformClosedOpenUnit, + }, DistributionSampler, EmigrationExit, GloballyCoherentLineageStore, ImmigrationEntry, MathsCore, Rng, SeparableDispersalSampler, }, @@ -52,7 +54,7 @@ where O::DispersalSampler>: SeparableDispersalSampler, G::Sampler: DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler + DistributionSampler + DistributionSampler diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/genesis.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/genesis.rs index 8229dd02c..1438086de 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/genesis.rs @@ -1,6 +1,8 @@ use necsim_core::{ cogs::{ - rng::{Event, Exponential, IndexU128, IndexU64, IndexUsize, UniformClosedOpenUnit}, + distribution::{ + Bernoulli, Exponential, IndexU128, IndexU64, IndexUsize, UniformClosedOpenUnit, + }, DistributionSampler, EmigrationExit, GloballyCoherentLineageStore, ImmigrationEntry, MathsCore, Rng, SeparableDispersalSampler, }, @@ -29,7 +31,7 @@ where O::DispersalSampler>: SeparableDispersalSampler, G::Sampler: DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler + DistributionSampler + DistributionSampler diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/mod.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/mod.rs index 537dc8e76..4b66a3f9e 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/mod.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - rng::{Event, IndexUsize, UniformClosedOpenUnit}, + distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, ActiveLineageSampler, DistributionSampler, EmigrationExit, GloballyCoherentLineageStore, ImmigrationEntry, MathsCore, Rng, SeparableDispersalSampler, }, @@ -31,7 +31,7 @@ pub trait EventSkippingLineageStoreSampleInitialiser< O::DispersalSampler>: SeparableDispersalSampler, G::Sampler: DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler, { type DispersalSampler: SeparableDispersalSampler; diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/resume.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/resume.rs index a2ba351e6..c386ab160 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/resume.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/resume.rs @@ -1,6 +1,8 @@ use necsim_core::{ cogs::{ - rng::{Event, Exponential, IndexU128, IndexU64, IndexUsize, UniformClosedOpenUnit}, + distribution::{ + Bernoulli, Exponential, IndexU128, IndexU64, IndexUsize, UniformClosedOpenUnit, + }, DistributionSampler, EmigrationExit, GloballyCoherentLineageStore, ImmigrationEntry, MathsCore, Rng, SeparableDispersalSampler, }, @@ -36,7 +38,7 @@ where O::DispersalSampler>: SeparableDispersalSampler, G::Sampler: DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler + DistributionSampler + DistributionSampler diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs index a8dc76277..5752ee4f6 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs @@ -2,7 +2,7 @@ use std::{hint::unreachable_unchecked, marker::PhantomData}; use necsim_core::{ cogs::{ - rng::{Event, IndexUsize, UniformClosedOpenUnit}, + distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, ActiveLineageSampler, DistributionSampler, GloballyCoherentLineageStore, MathsCore, Rng, SeparableDispersalSampler, SplittableRng, }, @@ -60,7 +60,7 @@ where O::DispersalSampler>: SeparableDispersalSampler, G::Sampler: DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler, { match args.parallelism_mode { diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/mod.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/mod.rs index f67f83e60..457b87692 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/mod.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{rng::SimpleRng, GloballyCoherentLineageStore, MathsCore, SeparableDispersalSampler}, + cogs::{GloballyCoherentLineageStore, MathsCore, SeparableDispersalSampler}, lineage::Lineage, reporter::Reporter, }; @@ -9,6 +9,7 @@ use necsim_impls_no_std::cogs::{ dispersal_sampler::in_memory::separable_alias::InMemorySeparableAliasDispersalSampler, lineage_store::coherent::globally::gillespie::GillespieLineageStore, maths::intrinsics::IntrinsicsMathsCore, origin_sampler::pre_sampler::OriginPreSampler, + rng::simple::SimpleRng, }; use necsim_impls_std::cogs::rng::pcg::Pcg; use necsim_partitioning_core::{partition::Partition, LocalPartition}; diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs index 16121c022..004e71036 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - rng::{Event, Exponential, IndexUsize, UniformClosedOpenUnit}, + distribution::{Bernoulli, Exponential, IndexUsize, UniformClosedOpenUnit}, DistributionSampler, EmigrationExit, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, }, @@ -51,7 +51,7 @@ impl, M: MathsCore, G: Rng, O: Scenario< ClassicalLineageStoreSampleInitialiser> for FixUpInitialiser where G::Sampler: DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler + DistributionSampler, { diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/genesis.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/genesis.rs index f6ba30fdc..f1c629bf1 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/genesis.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - rng::{Event, Exponential, IndexUsize, UniformClosedOpenUnit}, + distribution::{Bernoulli, Exponential, IndexUsize, UniformClosedOpenUnit}, DistributionSampler, EmigrationExit, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, }, @@ -25,7 +25,7 @@ impl, O: Scenario> ClassicalLineageStoreSampleInit for GenesisInitialiser where G::Sampler: DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler + DistributionSampler, { diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/mod.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/mod.rs index f5226dbe3..f8459676d 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/mod.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - rng::{Event, IndexUsize, UniformClosedOpenUnit}, + distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, ActiveLineageSampler, DispersalSampler, DistributionSampler, EmigrationExit, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, }, @@ -25,7 +25,7 @@ pub mod resume; pub trait ClassicalLineageStoreSampleInitialiser, O: Scenario, Error> where G::Sampler: DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler, { type DispersalSampler: DispersalSampler; diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/resume.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/resume.rs index 72254ed31..484f068a4 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/resume.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/resume.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - rng::{Event, Exponential, IndexUsize, UniformClosedOpenUnit}, + distribution::{Bernoulli, Exponential, IndexUsize, UniformClosedOpenUnit}, DistributionSampler, EmigrationExit, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, }, @@ -31,7 +31,7 @@ impl, M: MathsCore, G: Rng, O: Scenario< ClassicalLineageStoreSampleInitialiser> for ResumeInitialiser where G::Sampler: DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler + DistributionSampler, { diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs index 5321faaa8..298e5900a 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs @@ -2,7 +2,7 @@ use std::{hint::unreachable_unchecked, marker::PhantomData}; use necsim_core::{ cogs::{ - rng::{Event, IndexUsize, UniformClosedOpenUnit}, + distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, ActiveLineageSampler, DistributionSampler, LocallyCoherentLineageStore, MathsCore, Rng, SplittableRng, }, @@ -61,7 +61,7 @@ where O::LineageStore>: LocallyCoherentLineageStore, G::Sampler: DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler, { match args.parallelism_mode { diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/mod.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/mod.rs index a2fbf3f77..61b3b150d 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/mod.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{rng::SimpleRng, LocallyCoherentLineageStore, MathsCore}, + cogs::{LocallyCoherentLineageStore, MathsCore}, lineage::Lineage, reporter::Reporter, }; @@ -7,7 +7,8 @@ use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_impls_no_std::cogs::{ lineage_store::coherent::locally::classical::ClassicalLineageStore, - origin_sampler::pre_sampler::OriginPreSampler, turnover_rate::uniform::UniformTurnoverRate, + origin_sampler::pre_sampler::OriginPreSampler, rng::simple::SimpleRng, + turnover_rate::uniform::UniformTurnoverRate, }; use necsim_impls_std::cogs::rng::pcg::Pcg; use necsim_partitioning_core::LocalPartition; diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/fixup.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/fixup.rs index ed4797930..43d853008 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/fixup.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - rng::{Event, Exponential, IndexU128, IndexU64, IndexUsize}, + distribution::{Bernoulli, Exponential, IndexU128, IndexU64, IndexUsize}, CoalescenceSampler, DistributionSampler, EmigrationExit, EventSampler, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, }, @@ -48,7 +48,7 @@ impl, M: MathsCore, G: Rng, O: Scenario< GillespieLineageStoreSampleInitialiser> for FixUpInitialiser where G::Sampler: DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler + DistributionSampler + DistributionSampler, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/genesis.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/genesis.rs index 40704a80d..a0ce35c3e 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/genesis.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - rng::{Event, Exponential, IndexU128, IndexU64, IndexUsize}, + distribution::{Bernoulli, Exponential, IndexU128, IndexU64, IndexUsize}, CoalescenceSampler, DistributionSampler, EmigrationExit, EventSampler, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, }, @@ -25,7 +25,7 @@ impl, O: Scenario> GillespieLineageStoreSampleInit for GenesisInitialiser where G::Sampler: DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler + DistributionSampler + DistributionSampler, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/mod.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/mod.rs index eadba6dc8..20370ee6b 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/mod.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - rng::{Event, IndexUsize}, + distribution::{Bernoulli, IndexUsize}, ActiveLineageSampler, CoalescenceSampler, DispersalSampler, DistributionSampler, EmigrationExit, EventSampler, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, @@ -24,7 +24,7 @@ pub mod resume; pub trait GillespieLineageStoreSampleInitialiser, O: Scenario, Error> where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { type DispersalSampler: DispersalSampler; type ActiveLineageSampler< diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/resume.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/resume.rs index 060ae98a8..8618cd4e2 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/resume.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/resume.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - rng::{Event, Exponential, IndexU128, IndexU64, IndexUsize}, + distribution::{Bernoulli, Exponential, IndexU128, IndexU64, IndexUsize}, CoalescenceSampler, DistributionSampler, EmigrationExit, EventSampler, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, }, @@ -31,7 +31,7 @@ impl, M: MathsCore, G: Rng, O: Scenario< GillespieLineageStoreSampleInitialiser> for ResumeInitialiser where G::Sampler: DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler + DistributionSampler + DistributionSampler, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs index b106364b8..90c3db24d 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs @@ -2,7 +2,7 @@ use std::{hint::unreachable_unchecked, marker::PhantomData}; use necsim_core::{ cogs::{ - rng::{Event, IndexUsize, UniformClosedOpenUnit}, + distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, ActiveLineageSampler, DistributionSampler, LocallyCoherentLineageStore, MathsCore, Rng, SplittableRng, }, @@ -60,7 +60,7 @@ where O::LineageStore>: LocallyCoherentLineageStore, G::Sampler: DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler, { match args.parallelism_mode { diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/mod.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/mod.rs index 3aac781a1..728f34acf 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/mod.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{rng::SimpleRng, LocallyCoherentLineageStore, MathsCore}, + cogs::{LocallyCoherentLineageStore, MathsCore}, lineage::Lineage, reporter::Reporter, }; @@ -7,7 +7,7 @@ use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_impls_no_std::cogs::{ lineage_store::coherent::locally::classical::ClassicalLineageStore, - origin_sampler::pre_sampler::OriginPreSampler, + origin_sampler::pre_sampler::OriginPreSampler, rng::simple::SimpleRng, }; use necsim_impls_std::cogs::rng::pcg::Pcg; use necsim_partitioning_core::{partition::Partition, LocalPartition}; diff --git a/rustcoalescence/algorithms/independent/src/initialiser/fixup.rs b/rustcoalescence/algorithms/independent/src/initialiser/fixup.rs index ddca78463..563e4adb3 100644 --- a/rustcoalescence/algorithms/independent/src/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/independent/src/initialiser/fixup.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - rng::{Event, IndexUsize, UniformClosedOpenUnit}, + distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, DistributionSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, }, lineage::Lineage, @@ -48,7 +48,7 @@ impl< where G::Sampler: DistributionSampler + DistributionSampler - + DistributionSampler, + + DistributionSampler, { type ActiveLineageSampler< X: EmigrationExit>, diff --git a/rustcoalescence/algorithms/independent/src/initialiser/genesis.rs b/rustcoalescence/algorithms/independent/src/initialiser/genesis.rs index f00285217..88107b22b 100644 --- a/rustcoalescence/algorithms/independent/src/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/independent/src/initialiser/genesis.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - rng::{Event, IndexUsize, UniformClosedOpenUnit}, + distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, DistributionSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, }, lineage::Lineage, @@ -27,7 +27,7 @@ impl, O: Scenario> where G::Sampler: DistributionSampler + DistributionSampler - + DistributionSampler, + + DistributionSampler, { type ActiveLineageSampler< X: EmigrationExit>, diff --git a/rustcoalescence/algorithms/independent/src/initialiser/mod.rs b/rustcoalescence/algorithms/independent/src/initialiser/mod.rs index f54da064d..f3de92c3d 100644 --- a/rustcoalescence/algorithms/independent/src/initialiser/mod.rs +++ b/rustcoalescence/algorithms/independent/src/initialiser/mod.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - rng::{Event, IndexUsize, UniformClosedOpenUnit}, + distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, DispersalSampler, DistributionSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, }, lineage::Lineage, @@ -33,7 +33,7 @@ pub trait IndependentLineageStoreSampleInitialiser< > where G::Sampler: DistributionSampler + DistributionSampler - + DistributionSampler, + + DistributionSampler, { type DispersalSampler: DispersalSampler; type ActiveLineageSampler + DistributionSampler - + DistributionSampler, + + DistributionSampler, { type ActiveLineageSampler< X: EmigrationExit>, diff --git a/rustcoalescence/algorithms/independent/src/launch.rs b/rustcoalescence/algorithms/independent/src/launch.rs index bd0f88e53..fcbe5d1bd 100644 --- a/rustcoalescence/algorithms/independent/src/launch.rs +++ b/rustcoalescence/algorithms/independent/src/launch.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use necsim_core::{ cogs::{ - rng::{Event, IndexUsize, Normal2D, UniformClosedOpenUnit}, + distribution::{Bernoulli, IndexUsize, Normal2D, UniformClosedOpenUnit}, DistributionSampler, MathsCore, PrimeableRng, Rng, }, reporter::Reporter, @@ -68,7 +68,7 @@ pub fn initialise_and_simulate< where G::Sampler: DistributionSampler + DistributionSampler - + DistributionSampler + + DistributionSampler + DistributionSampler, { match args.parallelism_mode { diff --git a/rustcoalescence/algorithms/independent/src/lib.rs b/rustcoalescence/algorithms/independent/src/lib.rs index faa502de1..dff7dde25 100644 --- a/rustcoalescence/algorithms/independent/src/lib.rs +++ b/rustcoalescence/algorithms/independent/src/lib.rs @@ -5,16 +5,14 @@ #[macro_use] extern crate serde_derive_state; -use necsim_core::{ - cogs::{rng::SimpleRng, MathsCore}, - lineage::Lineage, - reporter::Reporter, -}; +use necsim_core::{cogs::MathsCore, lineage::Lineage, reporter::Reporter}; use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_impls_no_std::cogs::{ - lineage_store::independent::IndependentLineageStore, maths::intrinsics::IntrinsicsMathsCore, - origin_sampler::pre_sampler::OriginPreSampler, rng::wyhash::WyHash, + lineage_store::independent::IndependentLineageStore, + maths::intrinsics::IntrinsicsMathsCore, + origin_sampler::pre_sampler::OriginPreSampler, + rng::{simple::SimpleRng, wyhash::WyHash}, }; use necsim_partitioning_core::{partition::Partition, LocalPartition}; diff --git a/rustcoalescence/scenarios/src/almost_infinite.rs b/rustcoalescence/scenarios/src/almost_infinite.rs index 8d645589c..6636731c9 100644 --- a/rustcoalescence/scenarios/src/almost_infinite.rs +++ b/rustcoalescence/scenarios/src/almost_infinite.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use necsim_core::cogs::{ - rng::Normal2D, DispersalSampler, DistributionSampler, LineageStore, MathsCore, Rng, + distribution::Normal2D, DispersalSampler, DistributionSampler, LineageStore, MathsCore, Rng, }; use necsim_core_bond::{NonNegativeF64, OpenClosedUnitF64 as PositiveUnitF64}; use necsim_partitioning_core::partition::Partition; diff --git a/rustcoalescence/scenarios/src/non_spatial.rs b/rustcoalescence/scenarios/src/non_spatial.rs index 7bb043702..571d54f6b 100644 --- a/rustcoalescence/scenarios/src/non_spatial.rs +++ b/rustcoalescence/scenarios/src/non_spatial.rs @@ -3,7 +3,7 @@ use std::num::NonZeroU32; use serde::{Deserialize, Serialize}; use necsim_core::cogs::{ - rng::IndexU64, DispersalSampler, DistributionSampler, LineageStore, MathsCore, Rng, + distribution::IndexU64, DispersalSampler, DistributionSampler, LineageStore, MathsCore, Rng, }; use necsim_core_bond::{OffByOneU32, OpenClosedUnitF64 as PositiveUnitF64}; use necsim_partitioning_core::partition::Partition; diff --git a/rustcoalescence/scenarios/src/spatially_explicit/turnover/map.rs b/rustcoalescence/scenarios/src/spatially_explicit/turnover/map.rs index 973f888ab..a7d6157fd 100644 --- a/rustcoalescence/scenarios/src/spatially_explicit/turnover/map.rs +++ b/rustcoalescence/scenarios/src/spatially_explicit/turnover/map.rs @@ -3,7 +3,8 @@ use std::{convert::TryFrom, marker::PhantomData, path::PathBuf}; use serde::{Deserialize, Serialize, Serializer}; use necsim_core::cogs::{ - rng::IndexU64, DispersalSampler, DistributionSampler, Habitat, LineageStore, MathsCore, Rng, + distribution::IndexU64, DispersalSampler, DistributionSampler, Habitat, LineageStore, + MathsCore, Rng, }; use necsim_core_bond::{NonNegativeF64, OpenClosedUnitF64 as PositiveUnitF64}; use necsim_partitioning_core::partition::Partition; diff --git a/rustcoalescence/scenarios/src/spatially_explicit/turnover/uniform.rs b/rustcoalescence/scenarios/src/spatially_explicit/turnover/uniform.rs index fed318aa6..67c470e6c 100644 --- a/rustcoalescence/scenarios/src/spatially_explicit/turnover/uniform.rs +++ b/rustcoalescence/scenarios/src/spatially_explicit/turnover/uniform.rs @@ -3,7 +3,8 @@ use std::{convert::TryFrom, marker::PhantomData, path::PathBuf}; use serde::{Deserialize, Serialize, Serializer}; use necsim_core::cogs::{ - rng::IndexU64, DispersalSampler, DistributionSampler, Habitat, LineageStore, MathsCore, Rng, + distribution::IndexU64, DispersalSampler, DistributionSampler, Habitat, LineageStore, + MathsCore, Rng, }; use necsim_core_bond::{NonNegativeF64, OpenClosedUnitF64 as PositiveUnitF64, PositiveF64}; use necsim_partitioning_core::partition::Partition; diff --git a/rustcoalescence/scenarios/src/spatially_implicit.rs b/rustcoalescence/scenarios/src/spatially_implicit.rs index 37a64f123..5a29dcf51 100644 --- a/rustcoalescence/scenarios/src/spatially_implicit.rs +++ b/rustcoalescence/scenarios/src/spatially_implicit.rs @@ -3,7 +3,7 @@ use std::num::NonZeroU32; use serde::{Deserialize, Serialize}; use necsim_core::cogs::{ - rng::{Event, IndexU64}, + distribution::{Bernoulli, IndexU64}, DispersalSampler, DistributionSampler, LineageStore, MathsCore, Rng, }; use necsim_core_bond::{OffByOneU32, OpenClosedUnitF64 as PositiveUnitF64}; @@ -28,7 +28,7 @@ use crate::{Scenario, ScenarioParameters}; pub struct SpatiallyImplicitScenario> where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { habitat: SpatiallyImplicitHabitat, dispersal_sampler: SpatiallyImplicitDispersalSampler, @@ -51,7 +51,7 @@ pub struct SpatiallyImplicitArguments { impl> ScenarioParameters for SpatiallyImplicitScenario where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { type Arguments = SpatiallyImplicitArguments; type Error = !; @@ -60,7 +60,7 @@ where impl> Scenario for SpatiallyImplicitScenario where G::Sampler: DistributionSampler - + DistributionSampler, + + DistributionSampler, { type Decomposition = ModuloDecomposition; type DecompositionAuxiliary = (); diff --git a/rustcoalescence/scenarios/src/wrapping_noise.rs b/rustcoalescence/scenarios/src/wrapping_noise.rs index e5a954f0c..a83b1277a 100644 --- a/rustcoalescence/scenarios/src/wrapping_noise.rs +++ b/rustcoalescence/scenarios/src/wrapping_noise.rs @@ -3,7 +3,10 @@ use std::num::NonZeroUsize; use serde::{Deserialize, Serialize}; use necsim_core::{ - cogs::{DispersalSampler, LineageStore, MathsCore, RngCore}, + cogs::{ + distribution::{Bernoulli, Normal2D}, + DispersalSampler, DistributionSampler, LineageStore, MathsCore, Rng, + }, landscape::LandscapeExtent, }; use necsim_core_bond::{ClosedUnitF64, NonNegativeF64, OpenClosedUnitF64 as PositiveUnitF64}; @@ -26,7 +29,11 @@ use necsim_impls_no_std::{ use crate::{Scenario, ScenarioParameters}; #[allow(clippy::module_name_repetitions)] -pub struct WrappingNoiseScenario> { +pub struct WrappingNoiseScenario> +where + G::Sampler: DistributionSampler + + DistributionSampler, +{ sample: LandscapeExtent, habitat: WrappingNoiseHabitat, @@ -48,12 +55,20 @@ pub struct WrappingNoiseArguments { pub sigma: NonNegativeF64, } -impl> ScenarioParameters for WrappingNoiseScenario { +impl> ScenarioParameters for WrappingNoiseScenario +where + G::Sampler: DistributionSampler + + DistributionSampler, +{ type Arguments = WrappingNoiseArguments; type Error = !; } -impl> Scenario for WrappingNoiseScenario { +impl> Scenario for WrappingNoiseScenario +where + G::Sampler: DistributionSampler + + DistributionSampler, +{ type Decomposition = RadialDecomposition; type DecompositionAuxiliary = (); type DispersalSampler> = From e205e7cebe4489785ba376aa779650a2f7b838b8 Mon Sep 17 00:00:00 2001 From: Momo Langenstein Date: Thu, 19 May 2022 11:10:41 +0000 Subject: [PATCH 09/42] Backup of refactoring progress for Rng + Samples --- necsim/impls/no-std/src/alias/packed.rs | 13 +++-- .../alias/individual/mod.rs | 49 +++++++++--------- .../alias/individual/sampler.rs | 17 +++---- .../alias/location/mod.rs | 51 +++++++++---------- .../alias/location/sampler.rs | 13 +++-- .../alias/sampler/indexed/mod.rs | 29 +++++------ .../alias/sampler/stack/mod.rs | 30 +++++------ .../active_lineage_sampler/classical/mod.rs | 39 +++++++------- .../classical/sampler.rs | 15 +++--- .../independent/event_time_sampler/exp.rs | 13 ++--- .../event_time_sampler/geometric.rs | 14 ++--- .../independent/event_time_sampler/poisson.rs | 46 ++++------------- .../active_lineage_sampler/independent/mod.rs | 18 +++---- .../independent/sampler.rs | 8 ++- .../independent/singular.rs | 8 ++- .../almost_infinite_normal.rs | 27 ++++------ .../in_memory/alias/dispersal.rs | 9 ++-- .../dispersal_sampler/in_memory/alias/mod.rs | 25 ++++----- .../in_memory/cumulative/contract.rs | 7 ++- .../in_memory/cumulative/dispersal.rs | 10 ++-- .../in_memory/cumulative/mod.rs | 24 ++++----- .../in_memory/packed_alias/dispersal.rs | 9 ++-- .../in_memory/packed_alias/mod.rs | 32 +++++------- .../in_memory/separable_alias/dispersal.rs | 16 ++---- .../in_memory/separable_alias/mod.rs | 24 ++++----- .../src/cogs/dispersal_sampler/non_spatial.rs | 29 +++-------- .../dispersal_sampler/spatially_implicit.rs | 37 +++++--------- .../no-std/src/cogs/emigration_exit/domain.rs | 46 +++++++++-------- .../cogs/emigration_exit/independent/mod.rs | 41 ++++++++------- .../event_sampler/gillespie/unconditional.rs | 31 +++-------- .../src/cogs/event_sampler/independent.rs | 28 ++++------ .../src/cogs/event_sampler/unconditional.rs | 26 +++------- 32 files changed, 318 insertions(+), 466 deletions(-) diff --git a/necsim/impls/no-std/src/alias/packed.rs b/necsim/impls/no-std/src/alias/packed.rs index fe1a797f1..69e4f404f 100644 --- a/necsim/impls/no-std/src/alias/packed.rs +++ b/necsim/impls/no-std/src/alias/packed.rs @@ -4,7 +4,7 @@ use alloc::vec::Vec; use necsim_core::cogs::{ distribution::{Bernoulli, IndexUsize, Length}, - DistributionSampler, MathsCore, Rng, SampledDistribution, + MathsCore, Rng, SampledDistribution, Samples, }; use necsim_core_bond::{ClosedUnitF64, NonNegativeF64}; @@ -111,14 +111,13 @@ impl AliasMethodSamplerAtom { old(alias_samplers).iter().map(|s| s.e).any(|e| e == ret), "returns one of the weighted events" )] - pub fn sample_event>( + pub fn sample_event< + M: MathsCore, + G: Rng + Samples + Samples, + >( alias_samplers: &[AliasMethodSamplerAtom], rng: &mut G, - ) -> E - where - G::Sampler: DistributionSampler - + DistributionSampler, - { + ) -> E { // Safety: alias_samplers is non-empty by the precondition let length = unsafe { NonZeroUsize::new_unchecked(alias_samplers.len()) }; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs index 4e3eeca67..81cf824af 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs @@ -5,9 +5,9 @@ use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_core::cogs::{ distribution::{Exponential, IndexU128, IndexU64, IndexUsize}, - Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, EmigrationExit, - EventSampler, Habitat, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, - SpeciationProbability, TurnoverRate, + Backup, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, Habitat, + ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, Samples, SpeciationProbability, + TurnoverRate, }; use crate::cogs::{ @@ -23,7 +23,11 @@ mod sampler; pub struct IndividualAliasActiveLineageSampler< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + + Samples + + Samples + + Samples + + Samples, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -32,9 +36,7 @@ pub struct IndividualAliasActiveLineageSampler< N: SpeciationProbability, E: EventSampler, I: ImmigrationEntry, -> where - G::Sampler: DistributionSampler, -{ +> { alias_sampler: DynamicAliasMethodStackSampler, number_active_lineages: usize, last_event_time: NonNegativeF64, @@ -45,7 +47,11 @@ pub struct IndividualAliasActiveLineageSampler< impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + + Samples + + Samples + + Samples + + Samples, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -55,11 +61,6 @@ impl< E: EventSampler, I: ImmigrationEntry, > IndividualAliasActiveLineageSampler -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, { #[must_use] pub fn init_with_store<'h, O: TrustedOriginSampler<'h, M, Habitat = H>>( @@ -157,7 +158,11 @@ where impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + + Samples + + Samples + + Samples + + Samples, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -167,11 +172,6 @@ impl< E: EventSampler, I: ImmigrationEntry, > fmt::Debug for IndividualAliasActiveLineageSampler -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("IndividualAliasActiveLineageSampler") @@ -185,7 +185,11 @@ where impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + + Samples + + Samples + + Samples + + Samples, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -195,11 +199,6 @@ impl< E: EventSampler, I: ImmigrationEntry, > Backup for IndividualAliasActiveLineageSampler -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs index 004b09ddc..faeab2386 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs @@ -3,9 +3,9 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ distribution::{Exponential, IndexU128, IndexU64, IndexUsize, Lambda}, - ActiveLineageSampler, CoalescenceSampler, DispersalSampler, DistributionSampler, - EmigrationExit, EventSampler, Habitat, ImmigrationEntry, LocallyCoherentLineageStore, - MathsCore, Rng, SampledDistribution, SpeciationProbability, TurnoverRate, + ActiveLineageSampler, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, + Habitat, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, + SampledDistribution, Samples, SpeciationProbability, TurnoverRate, }, lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation, @@ -19,7 +19,11 @@ use super::IndividualAliasActiveLineageSampler; impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + + Samples + + Samples + + Samples + + Samples, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -30,11 +34,6 @@ impl< I: ImmigrationEntry, > ActiveLineageSampler for IndividualAliasActiveLineageSampler -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, { type LineageIterator<'a> = impl Iterator where H: 'a, G: 'a, S: 'a, X: 'a, D: 'a, C: 'a, T: 'a, N: 'a, E: 'a, I: 'a; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs index 5ab2d9e69..8956c2e8b 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs @@ -6,9 +6,8 @@ use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_core::{ cogs::{ distribution::{Exponential, IndexU128, IndexU64, IndexUsize}, - Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, EmigrationExit, - GloballyCoherentLineageStore, Habitat, ImmigrationEntry, MathsCore, Rng, - SpeciationProbability, TurnoverRate, + Backup, CoalescenceSampler, DispersalSampler, EmigrationExit, GloballyCoherentLineageStore, + Habitat, ImmigrationEntry, MathsCore, Rng, Samples, SpeciationProbability, TurnoverRate, }, landscape::Location, }; @@ -27,7 +26,11 @@ mod sampler; pub struct LocationAliasActiveLineageSampler< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + + Samples + + Samples + + Samples + + Samples, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -36,12 +39,7 @@ pub struct LocationAliasActiveLineageSampler< N: SpeciationProbability, E: GillespieEventSampler, I: ImmigrationEntry, -> where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, -{ +> { alias_sampler: DynamicAliasMethodIndexedSampler, number_active_lineages: usize, last_event_time: NonNegativeF64, @@ -52,7 +50,11 @@ pub struct LocationAliasActiveLineageSampler< impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + + Samples + + Samples + + Samples + + Samples, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -62,11 +64,6 @@ impl< E: GillespieEventSampler, I: ImmigrationEntry, > LocationAliasActiveLineageSampler -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, { #[must_use] pub fn init_with_store<'h, O: TrustedOriginSampler<'h, M, Habitat = H>>( @@ -211,7 +208,11 @@ where impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + + Samples + + Samples + + Samples + + Samples, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -221,11 +222,6 @@ impl< E: GillespieEventSampler, I: ImmigrationEntry, > core::fmt::Debug for LocationAliasActiveLineageSampler -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { f.debug_struct("LocationAliasActiveLineageSampler") @@ -239,7 +235,11 @@ where impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + + Samples + + Samples + + Samples + + Samples, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -249,11 +249,6 @@ impl< E: GillespieEventSampler, I: ImmigrationEntry, > Backup for LocationAliasActiveLineageSampler -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs index cc67138de..6b09f4a40 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs @@ -5,7 +5,7 @@ use necsim_core::{ distribution::{Exponential, IndexU128, IndexU64, IndexUsize, Lambda, Length}, ActiveLineageSampler, Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, EmigrationExit, GloballyCoherentLineageStore, Habitat, ImmigrationEntry, MathsCore, Rng, - SampledDistribution, SpeciationProbability, TurnoverRate, + SampledDistribution, Samples, SpeciationProbability, TurnoverRate, }, lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation, @@ -21,7 +21,11 @@ use super::LocationAliasActiveLineageSampler; impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + + Samples + + Samples + + Samples + + Samples, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -32,11 +36,6 @@ impl< I: ImmigrationEntry, > ActiveLineageSampler for LocationAliasActiveLineageSampler -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, { type LineageIterator<'a> = impl Iterator where H: 'a, G: 'a, S: 'a, X: 'a, D: 'a, C: 'a, T: 'a, N: 'a, E: 'a, I: 'a; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs index f1f24d996..29de8a550 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs @@ -12,7 +12,7 @@ use hashbrown::HashMap; use necsim_core::cogs::{ distribution::{IndexU128, IndexU64, IndexUsize, Length}, - Backup, DistributionSampler, MathsCore, Rng, SampledDistribution, + Backup, MathsCore, Rng, SampledDistribution, Samples, }; use necsim_core_bond::{NonNegativeF64, PositiveF64}; @@ -49,14 +49,11 @@ impl RejectionSamplingGroup { self.events.iter() } - unsafe fn sample_pop_inplace>( + unsafe fn sample_pop_inplace + Samples>( &mut self, lookup: &mut HashMap, rng: &mut G, - ) -> (Option<&mut Self>, E) - where - G::Sampler: DistributionSampler, - { + ) -> (Option<&mut Self>, E) { if let [event] = &self.events[..] { lookup.remove(event); @@ -94,14 +91,11 @@ impl RejectionSamplingGroup { } #[cfg(test)] - fn sample_pop>( + fn sample_pop + Samples>( mut self, lookup: &mut HashMap, rng: &mut G, - ) -> (Option, E) - where - G::Sampler: DistributionSampler, - { + ) -> (Option, E) { match unsafe { self.sample_pop_inplace(lookup, rng) } { (Some(_), event) => (Some(self), event), (None, event) => (None, event), @@ -199,12 +193,13 @@ impl DynamicAliasMethodIndexedSampler { self.groups.iter().flat_map(RejectionSamplingGroup::iter) } - pub fn sample_pop>(&mut self, rng: &mut G) -> Option - where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler, - { + pub fn sample_pop< + M: MathsCore, + G: Rng + Samples + Samples + Samples, + >( + &mut self, + rng: &mut G, + ) -> Option { if let Some(total_weight) = NonZeroU128::new(self.total_weight) { let cdf_sample = if let [_group] = &self.groups[..] { 0_u128 diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs index 9760fcc69..ef37863a8 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs @@ -9,7 +9,7 @@ use core::{ use necsim_core::cogs::{ distribution::{IndexU128, IndexU64, IndexUsize, Length}, - Backup, DistributionSampler, MathsCore, Rng, SampledDistribution, + Backup, MathsCore, Rng, SampledDistribution, Samples, }; use necsim_core_bond::{NonNegativeF64, PositiveF64}; @@ -45,13 +45,10 @@ impl RejectionSamplingGroup { self.events.iter() } - unsafe fn sample_pop_inplace>( + unsafe fn sample_pop_inplace + Samples>( &mut self, rng: &mut G, - ) -> (Option<&mut Self>, E) - where - G::Sampler: DistributionSampler, - { + ) -> (Option<&mut Self>, E) { if let [_event] = &self.events[..] { // Safety: If there is only one event, the pop must succeed return (None, self.events.pop().unwrap_unchecked()); @@ -79,10 +76,10 @@ impl RejectionSamplingGroup { } #[cfg(test)] - fn sample_pop>(mut self, rng: &mut G) -> (Option, E) - where - G::Sampler: DistributionSampler, - { + fn sample_pop + Samples>( + mut self, + rng: &mut G, + ) -> (Option, E) { match unsafe { self.sample_pop_inplace(rng) } { (Some(_), event) => (Some(self), event), (None, event) => (None, event), @@ -133,12 +130,13 @@ impl DynamicAliasMethodStackSampler { self.groups.iter().flat_map(RejectionSamplingGroup::iter) } - pub fn sample_pop>(&mut self, rng: &mut G) -> Option - where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler, - { + pub fn sample_pop< + M: MathsCore, + G: Rng + Samples + Samples + Samples, + >( + &mut self, + rng: &mut G, + ) -> Option { if let Some(total_weight) = NonZeroU128::new(self.total_weight) { let cdf_sample = if let [_group] = &self.groups[..] { 0_u128 diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs index 50f26fc53..e207e7c11 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs @@ -3,8 +3,8 @@ use core::marker::PhantomData; use necsim_core::cogs::{ distribution::{Bernoulli, Exponential, IndexUsize, UniformClosedOpenUnit}, - Backup, DispersalSampler, DistributionSampler, EmigrationExit, Habitat, ImmigrationEntry, - LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, + Backup, DispersalSampler, EmigrationExit, Habitat, ImmigrationEntry, + LocallyCoherentLineageStore, MathsCore, Rng, Samples, SpeciationProbability, }; use necsim_core_bond::NonNegativeF64; @@ -20,18 +20,17 @@ mod sampler; pub struct ClassicalActiveLineageSampler< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + + Samples + + Samples + + Samples + + Samples, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, N: SpeciationProbability, I: ImmigrationEntry, -> where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, -{ +> { active_lineage_references: Vec, last_event_time: NonNegativeF64, #[allow(clippy::type_complexity)] @@ -41,18 +40,17 @@ pub struct ClassicalActiveLineageSampler< impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + + Samples + + Samples + + Samples + + Samples, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, N: SpeciationProbability, I: ImmigrationEntry, > ClassicalActiveLineageSampler -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, { #[must_use] pub fn init_with_store<'h, O: TrustedOriginSampler<'h, M, Habitat = H>>( @@ -137,18 +135,17 @@ where impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + + Samples + + Samples + + Samples + + Samples, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, N: SpeciationProbability, I: ImmigrationEntry, > Backup for ClassicalActiveLineageSampler -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs index 24f6fbe49..315e2360d 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs @@ -6,8 +6,8 @@ use core::{ use necsim_core::{ cogs::{ distribution::{Bernoulli, Exponential, IndexUsize, Lambda, Length, UniformClosedOpenUnit}, - ActiveLineageSampler, DispersalSampler, DistributionSampler, EmigrationExit, Habitat, - ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, SampledDistribution, + ActiveLineageSampler, DispersalSampler, EmigrationExit, Habitat, ImmigrationEntry, + LocallyCoherentLineageStore, MathsCore, Rng, SampledDistribution, Samples, SpeciationProbability, }, lineage::Lineage, @@ -27,7 +27,11 @@ use super::ClassicalActiveLineageSampler; impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + + Samples + + Samples + + Samples + + Samples, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -57,11 +61,6 @@ impl< >, I, > for ClassicalActiveLineageSampler -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, { type LineageIterator<'a> = impl Iterator where H: 'a, G: 'a, S: 'a, X: 'a, D: 'a, N: 'a, I: 'a; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs index ea48c2660..1c909317b 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs @@ -2,8 +2,7 @@ use necsim_core::{ cogs::{ distribution::{Exponential, Lambda}, rng::HabitatPrimeableRng, - DistributionSampler, Habitat, MathsCore, PrimeableRng, Rng, SampledDistribution, - TurnoverRate, + Habitat, MathsCore, PrimeableRng, Rng, SampledDistribution, Samples, TurnoverRate, }, landscape::IndexedLocation, }; @@ -29,10 +28,12 @@ impl ExpEventTimeSampler { } #[contract_trait] -impl, G: Rng, T: TurnoverRate> - EventTimeSampler for ExpEventTimeSampler -where - G::Sampler: DistributionSampler, +impl< + M: MathsCore, + H: Habitat, + G: Rng + Samples, + T: TurnoverRate, + > EventTimeSampler for ExpEventTimeSampler { #[inline] fn next_event_time_at_indexed_location_weakly_after( diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs index 6c3996ccc..aaa1ac100 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs @@ -1,7 +1,7 @@ use necsim_core::{ cogs::{ - distribution::Bernoulli, rng::HabitatPrimeableRng, DistributionSampler, Habitat, MathsCore, - PrimeableRng, Rng, SampledDistribution, TurnoverRate, + distribution::Bernoulli, rng::HabitatPrimeableRng, Habitat, MathsCore, PrimeableRng, Rng, + SampledDistribution, Samples, TurnoverRate, }, landscape::IndexedLocation, }; @@ -24,10 +24,12 @@ impl GeometricEventTimeSampler { } #[contract_trait] -impl, G: Rng, T: TurnoverRate> - EventTimeSampler for GeometricEventTimeSampler -where - G::Sampler: DistributionSampler, +impl< + M: MathsCore, + H: Habitat, + G: Rng + Samples, + T: TurnoverRate, + > EventTimeSampler for GeometricEventTimeSampler { #[inline] fn next_event_time_at_indexed_location_weakly_after( diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs index 5efdbc631..d69de55d6 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs @@ -1,8 +1,8 @@ use necsim_core::{ cogs::{ - distribution::{Normal, Normal2D, UniformClosedOpenUnit}, + distribution::{Lambda, Poisson, UniformClosedOpenUnit}, rng::HabitatPrimeableRng, - DistributionSampler, Habitat, MathsCore, PrimeableRng, Rng, SampledDistribution, + DistributionSampler, Habitat, MathsCore, PrimeableRng, Rng, SampledDistribution, Samples, TurnoverRate, }, landscape::IndexedLocation, @@ -29,11 +29,12 @@ impl PoissonEventTimeSampler { } #[contract_trait] -impl, G: Rng, T: TurnoverRate> - EventTimeSampler for PoissonEventTimeSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, +impl< + M: MathsCore, + H: Habitat, + G: Rng + Samples, + T: TurnoverRate, + > EventTimeSampler for PoissonEventTimeSampler { #[inline] fn next_event_time_at_indexed_location_weakly_after( @@ -57,36 +58,7 @@ where rng.generator() .prime_with_habitat(habitat, indexed_location, time_step); - let number_events_at_time_steps = if no_event_probability_per_step > 0.0_f64 { - // https://en.wikipedia.org/wiki/Poisson_distribution#cite_ref-Devroye1986_54-0 - let mut poisson = 0_u32; - let mut prod = no_event_probability_per_step; - let mut acc = no_event_probability_per_step; - - let u = UniformClosedOpenUnit::sample(rng); - - while u > acc && prod > 0.0_f64 { - poisson += 1; - prod *= lambda_per_step.get() / f64::from(poisson); - acc += prod; - } - - poisson - } else { - // Fallback in case no_event_probability_per_step underflows - #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] - let normal_as_poisson = Normal2D::sample_with( - rng, - Normal { - mu: lambda_per_step.get(), - sigma: lambda_per_step.sqrt::(), - }, - ) - .0 - .max(0.0_f64) as u32; - - normal_as_poisson - }; + let number_events_at_time_steps = Poisson::sample_with(rng, Lambda(lambda_per_step)); let mut next_event = None; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/mod.rs index 739ebc498..931f80cab 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/mod.rs @@ -3,8 +3,8 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ - distribution::UniformClosedOpenUnit, Backup, DispersalSampler, DistributionSampler, - EmigrationExit, Habitat, MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, + distribution::UniformClosedOpenUnit, Backup, DispersalSampler, EmigrationExit, Habitat, + MathsCore, PrimeableRng, Rng, Samples, SpeciationProbability, TurnoverRate, }, lineage::Lineage, }; @@ -30,15 +30,13 @@ use event_time_sampler::EventTimeSampler; pub struct IndependentActiveLineageSampler< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, X: EmigrationExit>, D: DispersalSampler, T: TurnoverRate, N: SpeciationProbability, J: EventTimeSampler, -> where - G::Sampler: DistributionSampler, -{ +> { #[cfg_attr( feature = "cuda", cuda(embed = "Option>") @@ -54,15 +52,13 @@ pub struct IndependentActiveLineageSampler< impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, X: EmigrationExit>, D: DispersalSampler, T: TurnoverRate, N: SpeciationProbability, J: EventTimeSampler, > IndependentActiveLineageSampler -where - G::Sampler: DistributionSampler, { #[must_use] pub fn init_with_store_and_lineages<'h, O: TrustedOriginSampler<'h, M, Habitat = H>>( @@ -142,15 +138,13 @@ where impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, X: EmigrationExit>, D: DispersalSampler, T: TurnoverRate, N: SpeciationProbability, J: EventTimeSampler, > Backup for IndependentActiveLineageSampler -where - G::Sampler: DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/sampler.rs index b0a4beccf..786224b3c 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/sampler.rs @@ -3,8 +3,8 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ distribution::UniformClosedOpenUnit, ActiveLineageSampler, DispersalSampler, - DistributionSampler, EmigrationExit, Habitat, MathsCore, PrimeableRng, Rng, - SpeciationProbability, TurnoverRate, + EmigrationExit, Habitat, MathsCore, PrimeableRng, Rng, Samples, SpeciationProbability, + TurnoverRate, }, lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation, @@ -24,7 +24,7 @@ use super::{EventTimeSampler, IndependentActiveLineageSampler}; impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, X: EmigrationExit>, D: DispersalSampler, T: TurnoverRate, @@ -44,8 +44,6 @@ impl< IndependentEventSampler, NeverImmigrationEntry, > for IndependentActiveLineageSampler -where - G::Sampler: DistributionSampler, { type LineageIterator<'a> = impl Iterator where H: 'a, G: 'a, X: 'a, D: 'a, T: 'a, N: 'a, J: 'a; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/singular.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/singular.rs index 2962f86ac..203d7e38e 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/singular.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/singular.rs @@ -1,6 +1,6 @@ use necsim_core::cogs::{ - distribution::UniformClosedOpenUnit, DispersalSampler, DistributionSampler, EmigrationExit, - Habitat, MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, + distribution::UniformClosedOpenUnit, DispersalSampler, EmigrationExit, Habitat, MathsCore, + PrimeableRng, Rng, Samples, SpeciationProbability, TurnoverRate, }; use necsim_core::lineage::Lineage; @@ -19,7 +19,7 @@ use super::{EventTimeSampler, IndependentActiveLineageSampler}; impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, X: EmigrationExit>, D: DispersalSampler, T: TurnoverRate, @@ -39,8 +39,6 @@ impl< IndependentEventSampler, NeverImmigrationEntry, > for IndependentActiveLineageSampler -where - G::Sampler: DistributionSampler, { #[must_use] #[inline] diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs index a1a939361..344bd4a77 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ distribution::{Normal, Normal2D}, - Backup, DispersalSampler, DistributionSampler, MathsCore, Rng, SampledDistribution, + Backup, DispersalSampler, MathsCore, Rng, SampledDistribution, Samples, SeparableDispersalSampler, }, landscape::Location, @@ -16,19 +16,13 @@ use crate::cogs::habitat::almost_infinite::AlmostInfiniteHabitat; #[derive(Debug)] #[cfg_attr(feature = "cuda", derive(rust_cuda::common::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M", free = "G"))] -pub struct AlmostInfiniteNormalDispersalSampler> -where - G::Sampler: DistributionSampler, -{ +pub struct AlmostInfiniteNormalDispersalSampler + Samples> { sigma: NonNegativeF64, self_dispersal: ClosedUnitF64, marker: PhantomData<(M, G)>, } -impl> AlmostInfiniteNormalDispersalSampler -where - G::Sampler: DistributionSampler, -{ +impl + Samples> AlmostInfiniteNormalDispersalSampler { #[must_use] pub fn new(sigma: NonNegativeF64) -> Self { let self_dispersal_1d = if sigma > 0.0_f64 { @@ -50,9 +44,8 @@ where } #[contract_trait] -impl> Backup for AlmostInfiniteNormalDispersalSampler -where - G::Sampler: DistributionSampler, +impl + Samples> Backup + for AlmostInfiniteNormalDispersalSampler { unsafe fn backup_unchecked(&self) -> Self { Self { @@ -64,10 +57,9 @@ where } #[contract_trait] -impl> DispersalSampler, G> +impl + Samples> + DispersalSampler, G> for AlmostInfiniteNormalDispersalSampler -where - G::Sampler: DistributionSampler, { #[must_use] fn sample_dispersal_from_location( @@ -104,10 +96,9 @@ where } #[contract_trait] -impl> SeparableDispersalSampler, G> +impl + Samples> + SeparableDispersalSampler, G> for AlmostInfiniteNormalDispersalSampler -where - G::Sampler: DistributionSampler, { #[must_use] fn sample_non_self_dispersal_from_location( diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/dispersal.rs index c7302f79d..2970e3c62 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/dispersal.rs @@ -1,7 +1,7 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexUsize}, - DispersalSampler, DistributionSampler, Habitat, MathsCore, Rng, + DispersalSampler, Habitat, MathsCore, Rng, Samples, }, landscape::Location, }; @@ -9,11 +9,8 @@ use necsim_core::{ use super::InMemoryAliasDispersalSampler; #[contract_trait] -impl, G: Rng> DispersalSampler - for InMemoryAliasDispersalSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, +impl, G: Rng + Samples + Samples> + DispersalSampler for InMemoryAliasDispersalSampler { #[must_use] fn sample_dispersal_from_location( diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/mod.rs index 494bb6735..559ba2d23 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/mod.rs @@ -5,7 +5,7 @@ use alloc::vec::Vec; use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexUsize}, - Backup, DistributionSampler, Habitat, MathsCore, Rng, + Backup, Habitat, MathsCore, Rng, Samples, }, landscape::Location, }; @@ -20,21 +20,18 @@ mod dispersal; #[allow(clippy::module_name_repetitions)] #[derive(Debug)] -pub struct InMemoryAliasDispersalSampler, G: Rng> -where - G::Sampler: DistributionSampler - + DistributionSampler, -{ +pub struct InMemoryAliasDispersalSampler< + M: MathsCore, + H: Habitat, + G: Rng + Samples + Samples, +> { alias_dispersal: Array2D>>, marker: PhantomData<(M, H, G)>, } #[contract_trait] -impl, G: Rng> InMemoryDispersalSampler - for InMemoryAliasDispersalSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, +impl, G: Rng + Samples + Samples> + InMemoryDispersalSampler for InMemoryAliasDispersalSampler { /// Creates a new `InMemoryAliasDispersalSampler` from the /// `dispersal` map and extent of the habitat map. @@ -87,10 +84,8 @@ where } #[contract_trait] -impl, G: Rng> Backup for InMemoryAliasDispersalSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, +impl, G: Rng + Samples + Samples> Backup + for InMemoryAliasDispersalSampler { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/contract.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/contract.rs index 36ceb64bd..fb5115b21 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/contract.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/contract.rs @@ -1,13 +1,12 @@ use necsim_core::{ - cogs::{distribution::UniformClosedOpenUnit, DistributionSampler, Habitat, MathsCore, Rng}, + cogs::{distribution::UniformClosedOpenUnit, Habitat, MathsCore, Rng, Samples}, landscape::Location, }; use super::InMemoryCumulativeDispersalSampler; -impl, G: Rng> InMemoryCumulativeDispersalSampler -where - G::Sampler: DistributionSampler, +impl, G: Rng + Samples> + InMemoryCumulativeDispersalSampler { pub(super) fn explicit_only_valid_targets_dispersal_contract(&self, habitat: &H) -> bool { let habitat_width = habitat.get_extent().width(); diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/dispersal.rs index 7cfacdd37..5d4986abd 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/dispersal.rs @@ -1,7 +1,7 @@ use necsim_core::{ cogs::{ - distribution::UniformClosedOpenUnit, DispersalSampler, DistributionSampler, Habitat, - MathsCore, Rng, SampledDistribution, + distribution::UniformClosedOpenUnit, DispersalSampler, Habitat, MathsCore, Rng, + SampledDistribution, Samples, }, landscape::Location, }; @@ -9,10 +9,8 @@ use necsim_core::{ use super::InMemoryCumulativeDispersalSampler; #[contract_trait] -impl, G: Rng> DispersalSampler - for InMemoryCumulativeDispersalSampler -where - G::Sampler: DistributionSampler, +impl, G: Rng + Samples> + DispersalSampler for InMemoryCumulativeDispersalSampler { #[must_use] fn sample_dispersal_from_location( diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/mod.rs index 47f0fd148..eb1d6622c 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/mod.rs @@ -3,9 +3,7 @@ use core::marker::PhantomData; use alloc::{boxed::Box, vec}; use necsim_core::{ - cogs::{ - distribution::UniformClosedOpenUnit, Backup, DistributionSampler, Habitat, MathsCore, Rng, - }, + cogs::{distribution::UniformClosedOpenUnit, Backup, Habitat, MathsCore, Rng, Samples}, landscape::Location, }; use necsim_core_bond::{ClosedUnitF64, NonNegativeF64}; @@ -17,20 +15,19 @@ mod dispersal; #[allow(clippy::module_name_repetitions)] #[derive(Debug)] -pub struct InMemoryCumulativeDispersalSampler, G: Rng> -where - G::Sampler: DistributionSampler, -{ +pub struct InMemoryCumulativeDispersalSampler< + M: MathsCore, + H: Habitat, + G: Rng + Samples, +> { cumulative_dispersal: Box<[ClosedUnitF64]>, valid_dispersal_targets: Box<[Option]>, marker: PhantomData<(M, H, G)>, } #[contract_trait] -impl, G: Rng> InMemoryDispersalSampler - for InMemoryCumulativeDispersalSampler -where - G::Sampler: DistributionSampler, +impl, G: Rng + Samples> + InMemoryDispersalSampler for InMemoryCumulativeDispersalSampler { /// Creates a new `InMemoryCumulativeDispersalSampler` from the /// `dispersal` map and extent of the habitat map. @@ -112,9 +109,8 @@ where } #[contract_trait] -impl, G: Rng> Backup for InMemoryCumulativeDispersalSampler -where - G::Sampler: DistributionSampler, +impl, G: Rng + Samples> Backup + for InMemoryCumulativeDispersalSampler { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/dispersal.rs index 6c3892329..47bd76cd4 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/dispersal.rs @@ -3,7 +3,7 @@ use core::ops::Range; use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexUsize}, - DispersalSampler, DistributionSampler, Habitat, MathsCore, Rng, + DispersalSampler, Habitat, MathsCore, Rng, Samples, }, landscape::Location, }; @@ -13,11 +13,8 @@ use crate::alias::packed::AliasMethodSamplerAtom; use super::InMemoryPackedAliasDispersalSampler; #[contract_trait] -impl, G: Rng> DispersalSampler - for InMemoryPackedAliasDispersalSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, +impl, G: Rng + Samples + Samples> + DispersalSampler for InMemoryPackedAliasDispersalSampler { #[must_use] fn sample_dispersal_from_location( diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs index 0c2c079dc..0a07e3ad0 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs @@ -7,7 +7,7 @@ use r#final::Final; use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexUsize}, - Backup, DistributionSampler, Habitat, MathsCore, Rng, + Backup, Habitat, MathsCore, Rng, Samples, }, landscape::Location, }; @@ -45,11 +45,11 @@ impl From for Range { #[allow(clippy::module_name_repetitions)] #[cfg_attr(feature = "cuda", derive(rust_cuda::common::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M", free = "H", free = "G"))] -pub struct InMemoryPackedAliasDispersalSampler, G: Rng> -where - G::Sampler: DistributionSampler - + DistributionSampler, -{ +pub struct InMemoryPackedAliasDispersalSampler< + M: MathsCore, + H: Habitat, + G: Rng + Samples + Samples, +> { #[cfg_attr(feature = "cuda", cuda(embed))] alias_dispersal_ranges: Final>, #[cfg_attr(feature = "cuda", cuda(embed))] @@ -58,11 +58,8 @@ where } #[contract_trait] -impl, G: Rng> InMemoryDispersalSampler - for InMemoryPackedAliasDispersalSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, +impl, G: Rng + Samples + Samples> + InMemoryDispersalSampler for InMemoryPackedAliasDispersalSampler { /// Creates a new `InMemoryPackedAliasDispersalSampler` from the /// `dispersal` map and extent of the habitat map. @@ -122,11 +119,8 @@ where } } -impl, G: Rng> core::fmt::Debug - for InMemoryPackedAliasDispersalSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, +impl, G: Rng + Samples + Samples> + core::fmt::Debug for InMemoryPackedAliasDispersalSampler { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { f.debug_struct(stringify!(InMemoryPackedAliasDispersalSampler)) @@ -144,10 +138,8 @@ where } #[contract_trait] -impl, G: Rng> Backup for InMemoryPackedAliasDispersalSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, +impl, G: Rng + Samples + Samples> Backup + for InMemoryPackedAliasDispersalSampler { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs index 7e254f244..5ec6db546 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs @@ -1,7 +1,7 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexUsize}, - DispersalSampler, DistributionSampler, Habitat, MathsCore, Rng, SampledDistribution, + DispersalSampler, Habitat, MathsCore, Rng, SampledDistribution, Samples, SeparableDispersalSampler, }, landscape::Location, @@ -11,11 +11,8 @@ use necsim_core_bond::ClosedUnitF64; use super::InMemorySeparableAliasDispersalSampler; #[contract_trait] -impl, G: Rng> DispersalSampler - for InMemorySeparableAliasDispersalSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, +impl, G: Rng + Samples + Samples> + DispersalSampler for InMemorySeparableAliasDispersalSampler { #[must_use] fn sample_dispersal_from_location( @@ -42,11 +39,8 @@ where } #[contract_trait] -impl, G: Rng> SeparableDispersalSampler - for InMemorySeparableAliasDispersalSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, +impl, G: Rng + Samples + Samples> + SeparableDispersalSampler for InMemorySeparableAliasDispersalSampler { #[must_use] fn sample_non_self_dispersal_from_location( diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/mod.rs index f5c313d8d..0610d8920 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/mod.rs @@ -5,7 +5,7 @@ use alloc::vec::Vec; use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexUsize}, - Backup, DistributionSampler, Habitat, MathsCore, Rng, + Backup, Habitat, MathsCore, Rng, Samples, }, landscape::Location, }; @@ -20,22 +20,19 @@ mod dispersal; #[allow(clippy::module_name_repetitions)] #[derive(Debug)] -pub struct InMemorySeparableAliasDispersalSampler, G: Rng> -where - G::Sampler: DistributionSampler - + DistributionSampler, -{ +pub struct InMemorySeparableAliasDispersalSampler< + M: MathsCore, + H: Habitat, + G: Rng + Samples + Samples, +> { alias_dispersal: Array2D>>, self_dispersal: Array2D, _marker: PhantomData<(M, H, G)>, } #[contract_trait] -impl, G: Rng> InMemoryDispersalSampler - for InMemorySeparableAliasDispersalSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, +impl, G: Rng + Samples + Samples> + InMemoryDispersalSampler for InMemorySeparableAliasDispersalSampler { /// Creates a new `InMemorySeparableAliasDispersalSampler` from the /// `dispersal` map and extent of the habitat map. @@ -122,11 +119,8 @@ where } #[contract_trait] -impl, G: Rng> Backup +impl, G: Rng + Samples + Samples> Backup for InMemorySeparableAliasDispersalSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/non_spatial.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/non_spatial.rs index 90d300035..f35dfa5ea 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/non_spatial.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/non_spatial.rs @@ -3,8 +3,8 @@ use core::{marker::PhantomData, num::NonZeroU64}; use necsim_core::{ cogs::{ distribution::{IndexU64, Length}, - Backup, DispersalSampler, DistributionSampler, Habitat, MathsCore, Rng, - SampledDistribution, SeparableDispersalSampler, + Backup, DispersalSampler, Habitat, MathsCore, Rng, SampledDistribution, Samples, + SeparableDispersalSampler, }, landscape::Location, }; @@ -16,17 +16,11 @@ use crate::cogs::habitat::non_spatial::NonSpatialHabitat; #[derive(Debug)] #[cfg_attr(feature = "cuda", derive(rust_cuda::common::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M", free = "G"))] -pub struct NonSpatialDispersalSampler> -where - G::Sampler: DistributionSampler, -{ +pub struct NonSpatialDispersalSampler + Samples> { marker: PhantomData<(M, G)>, } -impl> Default for NonSpatialDispersalSampler -where - G::Sampler: DistributionSampler, -{ +impl + Samples> Default for NonSpatialDispersalSampler { #[must_use] fn default() -> Self { Self { @@ -36,10 +30,7 @@ where } #[contract_trait] -impl> Backup for NonSpatialDispersalSampler -where - G::Sampler: DistributionSampler, -{ +impl + Samples> Backup for NonSpatialDispersalSampler { unsafe fn backup_unchecked(&self) -> Self { Self { marker: PhantomData::<(M, G)>, @@ -48,10 +39,8 @@ where } #[contract_trait] -impl> DispersalSampler, G> +impl + Samples> DispersalSampler, G> for NonSpatialDispersalSampler -where - G::Sampler: DistributionSampler, { #[must_use] #[inline] @@ -85,10 +74,8 @@ where } #[contract_trait] -impl> SeparableDispersalSampler, G> - for NonSpatialDispersalSampler -where - G::Sampler: DistributionSampler, +impl + Samples> + SeparableDispersalSampler, G> for NonSpatialDispersalSampler { #[must_use] #[debug_requires(( diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs index df10d55bd..44f2846e3 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs @@ -1,8 +1,8 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexU64}, - Backup, DispersalSampler, DistributionSampler, Habitat, MathsCore, Rng, - SampledDistribution, SeparableDispersalSampler, + Backup, DispersalSampler, Habitat, MathsCore, Rng, SampledDistribution, Samples, + SeparableDispersalSampler, }, landscape::Location, }; @@ -17,11 +17,10 @@ use crate::cogs::{ #[derive(Debug)] #[cfg_attr(feature = "cuda", derive(rust_cuda::common::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M"))] -pub struct SpatiallyImplicitDispersalSampler> -where - G::Sampler: DistributionSampler - + DistributionSampler, -{ +pub struct SpatiallyImplicitDispersalSampler< + M: MathsCore, + G: Rng + Samples + Samples, +> { #[cfg_attr(feature = "cuda", cuda(embed))] local: NonSpatialDispersalSampler, #[cfg_attr(feature = "cuda", cuda(embed))] @@ -29,10 +28,8 @@ where local_migration_probability_per_generation: PositiveUnitF64, } -impl> SpatiallyImplicitDispersalSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, +impl + Samples + Samples> + SpatiallyImplicitDispersalSampler { #[must_use] pub fn new(local_migration_probability_per_generation: PositiveUnitF64) -> Self { @@ -45,10 +42,8 @@ where } #[contract_trait] -impl> Backup for SpatiallyImplicitDispersalSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, +impl + Samples + Samples> Backup + for SpatiallyImplicitDispersalSampler { unsafe fn backup_unchecked(&self) -> Self { Self { @@ -61,11 +56,9 @@ where } #[contract_trait] -impl> DispersalSampler, G> +impl + Samples + Samples> + DispersalSampler, G> for SpatiallyImplicitDispersalSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, { #[must_use] #[debug_ensures(habitat.meta().get_extent().contains(&ret) || ( @@ -106,11 +99,9 @@ where } #[contract_trait] -impl> SeparableDispersalSampler, G> +impl + Samples + Samples> + SeparableDispersalSampler, G> for SpatiallyImplicitDispersalSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, { #[must_use] #[debug_ensures(habitat.meta().get_extent().contains(&ret) || ( diff --git a/necsim/impls/no-std/src/cogs/emigration_exit/domain.rs b/necsim/impls/no-std/src/cogs/emigration_exit/domain.rs index 4ad3d10ba..1be33636b 100644 --- a/necsim/impls/no-std/src/cogs/emigration_exit/domain.rs +++ b/necsim/impls/no-std/src/cogs/emigration_exit/domain.rs @@ -6,7 +6,7 @@ use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_core::{ cogs::{ coalescence_sampler::CoalescenceRngSample, distribution::UniformClosedOpenUnit, Backup, - DistributionSampler, EmigrationExit, Habitat, LocallyCoherentLineageStore, MathsCore, Rng, + EmigrationExit, Habitat, LocallyCoherentLineageStore, MathsCore, Rng, Samples, }, landscape::{IndexedLocation, Location}, lineage::{GlobalLineageReference, MigratingLineage, TieBreaker}, @@ -17,20 +17,24 @@ use crate::decomposition::Decomposition; #[allow(clippy::module_name_repetitions)] #[derive(Debug)] -pub struct DomainEmigrationExit, G: Rng, C: Decomposition> -where - G::Sampler: DistributionSampler, -{ +pub struct DomainEmigrationExit< + M: MathsCore, + H: Habitat, + G: Rng + Samples, + C: Decomposition, +> { decomposition: C, emigrants: Vec<(u32, MigratingLineage)>, _marker: PhantomData<(M, H, G)>, } #[contract_trait] -impl, G: Rng, C: Decomposition> Backup - for DomainEmigrationExit -where - G::Sampler: DistributionSampler, +impl< + M: MathsCore, + H: Habitat, + G: Rng + Samples, + C: Decomposition, + > Backup for DomainEmigrationExit { unsafe fn backup_unchecked(&self) -> Self { Self { @@ -52,11 +56,9 @@ impl< M: MathsCore, H: Habitat, C: Decomposition, - G: Rng, + G: Rng + Samples, S: LocallyCoherentLineageStore, > EmigrationExit for DomainEmigrationExit -where - G::Sampler: DistributionSampler, { #[must_use] #[debug_ensures(ret.is_some() == ( @@ -115,10 +117,12 @@ where } } -impl, G: Rng, C: Decomposition> - DomainEmigrationExit -where - G::Sampler: DistributionSampler, +impl< + M: MathsCore, + H: Habitat, + G: Rng + Samples, + C: Decomposition, + > DomainEmigrationExit { #[must_use] pub fn new(decomposition: C) -> Self { @@ -138,10 +142,12 @@ where } } -impl, G: Rng, C: Decomposition> Iterator - for DomainEmigrationExit -where - G::Sampler: DistributionSampler, +impl< + M: MathsCore, + H: Habitat, + G: Rng + Samples, + C: Decomposition, + > Iterator for DomainEmigrationExit { type Item = (u32, MigratingLineage); diff --git a/necsim/impls/no-std/src/cogs/emigration_exit/independent/mod.rs b/necsim/impls/no-std/src/cogs/emigration_exit/independent/mod.rs index ed5a2c8b6..179ea74b0 100644 --- a/necsim/impls/no-std/src/cogs/emigration_exit/independent/mod.rs +++ b/necsim/impls/no-std/src/cogs/emigration_exit/independent/mod.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ coalescence_sampler::CoalescenceRngSample, distribution::UniformClosedOpenUnit, Backup, - DistributionSampler, EmigrationExit, Habitat, MathsCore, Rng, + EmigrationExit, Habitat, MathsCore, Rng, Samples, }, landscape::{IndexedLocation, Location}, lineage::{GlobalLineageReference, MigratingLineage, TieBreaker}, @@ -23,12 +23,10 @@ use choice::EmigrationChoice; pub struct IndependentEmigrationExit< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, C: Decomposition, E: EmigrationChoice, -> where - G::Sampler: DistributionSampler, -{ +> { decomposition: C, choice: E, emigrant: Option<(u32, MigratingLineage)>, @@ -36,10 +34,13 @@ pub struct IndependentEmigrationExit< } #[contract_trait] -impl, G: Rng, C: Decomposition, E: EmigrationChoice> - Backup for IndependentEmigrationExit -where - G::Sampler: DistributionSampler, +impl< + M: MathsCore, + H: Habitat, + G: Rng + Samples, + C: Decomposition, + E: EmigrationChoice, + > Backup for IndependentEmigrationExit { unsafe fn backup_unchecked(&self) -> Self { Self { @@ -57,11 +58,14 @@ where } #[contract_trait] -impl, G: Rng, C: Decomposition, E: EmigrationChoice> - EmigrationExit> +impl< + M: MathsCore, + H: Habitat, + G: Rng + Samples, + C: Decomposition, + E: EmigrationChoice, + > EmigrationExit> for IndependentEmigrationExit -where - G::Sampler: DistributionSampler, { #[must_use] #[inline] @@ -134,10 +138,13 @@ where } } -impl, G: Rng, C: Decomposition, E: EmigrationChoice> - IndependentEmigrationExit -where - G::Sampler: DistributionSampler, +impl< + M: MathsCore, + H: Habitat, + G: Rng + Samples, + C: Decomposition, + E: EmigrationChoice, + > IndependentEmigrationExit { #[must_use] pub fn new(decomposition: C, choice: E) -> Self { diff --git a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs index 8877a9ffe..f99db3fef 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs @@ -5,8 +5,8 @@ use necsim_core::{ coalescence_sampler::CoalescenceRngSample, distribution::{Bernoulli, UniformClosedOpenUnit}, event_sampler::EventHandler, - Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, EmigrationExit, - EventSampler, GloballyCoherentLineageStore, Habitat, MathsCore, Rng, SampledDistribution, + Backup, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, + GloballyCoherentLineageStore, Habitat, MathsCore, Rng, SampledDistribution, Samples, SpeciationProbability, TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, @@ -23,17 +23,14 @@ use super::GillespieEventSampler; pub struct UnconditionalGillespieEventSampler< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples + Samples, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, C: CoalescenceSampler, T: TurnoverRate, N: SpeciationProbability, -> where - G::Sampler: DistributionSampler - + DistributionSampler, -{ +> { #[allow(clippy::type_complexity)] marker: PhantomData<(M, H, G, S, X, D, C, T, N)>, } @@ -41,7 +38,7 @@ pub struct UnconditionalGillespieEventSampler< impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples + Samples, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -49,9 +46,6 @@ impl< T: TurnoverRate, N: SpeciationProbability, > Default for UnconditionalGillespieEventSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, { fn default() -> Self { Self { @@ -64,7 +58,7 @@ where impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples + Samples, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -72,9 +66,6 @@ impl< T: TurnoverRate, N: SpeciationProbability, > Backup for UnconditionalGillespieEventSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { @@ -87,7 +78,7 @@ where impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples + Samples, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -96,9 +87,6 @@ impl< N: SpeciationProbability, > EventSampler for UnconditionalGillespieEventSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, { #[must_use] fn sample_event_for_lineage_at_event_time_or_emigrate< @@ -198,7 +186,7 @@ where impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples + Samples, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -207,9 +195,6 @@ impl< N: SpeciationProbability, > GillespieEventSampler for UnconditionalGillespieEventSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, { #[must_use] fn get_event_rate_at_location( diff --git a/necsim/impls/no-std/src/cogs/event_sampler/independent.rs b/necsim/impls/no-std/src/cogs/event_sampler/independent.rs index 9a35ff8b2..64e8ef1cb 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/independent.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/independent.rs @@ -3,9 +3,9 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ coalescence_sampler::CoalescenceRngSample, distribution::UniformClosedOpenUnit, - event_sampler::EventHandler, Backup, CoalescenceSampler, DispersalSampler, - DistributionSampler, EmigrationExit, EventSampler, Habitat, MathsCore, Rng, - SampledDistribution, SpeciationProbability, TurnoverRate, + event_sampler::EventHandler, Backup, CoalescenceSampler, DispersalSampler, EmigrationExit, + EventSampler, Habitat, MathsCore, Rng, SampledDistribution, Samples, SpeciationProbability, + TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, lineage::Lineage, @@ -38,14 +38,12 @@ use super::tracking::{MinSpeciationTrackingEventSampler, SpeciationSample}; pub struct IndependentEventSampler< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, X: EmigrationExit>, D: DispersalSampler, T: TurnoverRate, N: SpeciationProbability, -> where - G::Sampler: DistributionSampler, -{ +> { #[cfg_attr( feature = "cuda", cuda( @@ -59,14 +57,12 @@ pub struct IndependentEventSampler< impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, X: EmigrationExit>, D: DispersalSampler, T: TurnoverRate, N: SpeciationProbability, > Default for IndependentEventSampler -where - G::Sampler: DistributionSampler, { fn default() -> Self { Self { @@ -80,14 +76,12 @@ where impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, X: EmigrationExit>, D: DispersalSampler, T: TurnoverRate, N: SpeciationProbability, > Backup for IndependentEventSampler -where - G::Sampler: DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { @@ -101,7 +95,7 @@ where impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, X: EmigrationExit>, D: DispersalSampler, T: TurnoverRate, @@ -118,8 +112,6 @@ impl< T, N, > for IndependentEventSampler -where - G::Sampler: DistributionSampler, { #[must_use] #[inline] @@ -237,7 +229,7 @@ where impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, X: EmigrationExit>, D: DispersalSampler, T: TurnoverRate, @@ -254,8 +246,6 @@ impl< T, N, > for IndependentEventSampler -where - G::Sampler: DistributionSampler, { fn replace_min_speciation( &mut self, diff --git a/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs b/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs index 3081e0ab4..aca02a3c6 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs @@ -5,8 +5,8 @@ use necsim_core::{ coalescence_sampler::CoalescenceRngSample, distribution::{Bernoulli, UniformClosedOpenUnit}, event_sampler::EventHandler, - Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, EmigrationExit, - EventSampler, Habitat, LocallyCoherentLineageStore, MathsCore, Rng, SampledDistribution, + Backup, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, Habitat, + LocallyCoherentLineageStore, MathsCore, Rng, SampledDistribution, Samples, SpeciationProbability, TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, @@ -20,17 +20,14 @@ use necsim_core_bond::PositiveF64; pub struct UnconditionalEventSampler< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples + Samples, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, C: CoalescenceSampler, T: TurnoverRate, N: SpeciationProbability, -> where - G::Sampler: DistributionSampler - + DistributionSampler, -{ +> { #[allow(clippy::type_complexity)] marker: PhantomData<(M, H, G, S, X, D, C, T, N)>, } @@ -38,7 +35,7 @@ pub struct UnconditionalEventSampler< impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples + Samples, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -46,9 +43,6 @@ impl< T: TurnoverRate, N: SpeciationProbability, > Default for UnconditionalEventSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, { fn default() -> Self { Self { @@ -61,7 +55,7 @@ where impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples + Samples, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -69,9 +63,6 @@ impl< T: TurnoverRate, N: SpeciationProbability, > Backup for UnconditionalEventSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { @@ -84,7 +75,7 @@ where impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples + Samples, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -93,9 +84,6 @@ impl< N: SpeciationProbability, > EventSampler for UnconditionalEventSampler -where - G::Sampler: DistributionSampler - + DistributionSampler, { #[must_use] fn sample_event_for_lineage_at_event_time_or_emigrate< From b452796e996111500c4082e1409b1bd86cffda51 Mon Sep 17 00:00:00 2001 From: Momo Langenstein Date: Thu, 19 May 2022 13:33:30 +0000 Subject: [PATCH 10/42] Finished refactoring into Rng + Samples --- necsim/core/src/cogs/coalescence_sampler.rs | 4 +- necsim/core/src/cogs/distribution.rs | 38 +++++++++---------- necsim/core/src/cogs/mod.rs | 2 +- necsim/core/src/cogs/rng.rs | 8 ++-- necsim/impls/no-std/src/alias/mod.rs | 2 +- necsim/impls/no-std/src/alias/packed.rs | 2 +- .../alias/individual/sampler.rs | 6 +-- .../alias/location/sampler.rs | 4 +- .../alias/sampler/indexed/mod.rs | 2 +- .../alias/sampler/stack/mod.rs | 2 +- .../classical/sampler.rs | 4 +- .../independent/event_time_sampler/exp.rs | 2 +- .../event_time_sampler/geometric.rs | 4 +- .../independent/event_time_sampler/poisson.rs | 12 +++--- .../almost_infinite_normal.rs | 3 +- .../in_memory/cumulative/dispersal.rs | 4 +- .../in_memory/separable_alias/dispersal.rs | 2 +- .../src/cogs/dispersal_sampler/non_spatial.rs | 2 +- .../dispersal_sampler/spatially_implicit.rs | 2 +- .../gillespie/conditional/mod.rs | 28 +++++--------- .../event_sampler/gillespie/unconditional.rs | 6 +-- .../src/cogs/event_sampler/independent.rs | 4 +- .../src/cogs/event_sampler/unconditional.rs | 6 +-- .../no-std/src/cogs/habitat/in_memory.rs | 8 ++-- .../no-std/src/cogs/habitat/non_spatial.rs | 8 ++-- .../src/cogs/habitat/spatially_implicit.rs | 7 ++-- necsim/impls/no-std/src/cogs/rng/simple.rs | 6 +-- .../independent/individuals.rs | 11 ++---- .../parallelisation/independent/landscape.rs | 11 ++---- .../independent/monolithic/mod.rs | 11 ++---- .../parallelisation/monolithic/averaging.rs | 11 ++---- .../parallelisation/monolithic/lockstep.rs | 11 ++---- .../parallelisation/monolithic/optimistic.rs | 11 ++---- .../monolithic/optimistic_lockstep.rs | 11 ++---- .../algorithms/cuda/src/initialiser/fixup.rs | 11 +++--- .../cuda/src/initialiser/genesis.rs | 16 +++++--- .../algorithms/cuda/src/initialiser/mod.rs | 11 +++--- .../algorithms/cuda/src/initialiser/resume.rs | 11 +++--- .../src/event_skipping/initialiser/fixup.rs | 24 +++++++----- .../src/event_skipping/initialiser/genesis.rs | 23 ++++++----- .../src/event_skipping/initialiser/mod.rs | 9 ++--- .../src/event_skipping/initialiser/resume.rs | 24 +++++++----- .../gillespie/src/event_skipping/launch.rs | 10 ++--- .../gillespie/classical/initialiser/fixup.rs | 20 +++++----- .../classical/initialiser/genesis.rs | 19 +++++----- .../gillespie/classical/initialiser/mod.rs | 15 ++++---- .../gillespie/classical/initialiser/resume.rs | 20 +++++----- .../src/gillespie/classical/launch.rs | 11 +++--- .../gillespie/turnover/initialiser/fixup.rs | 23 ++++++----- .../gillespie/turnover/initialiser/genesis.rs | 22 ++++++----- .../src/gillespie/turnover/initialiser/mod.rs | 15 ++++---- .../gillespie/turnover/initialiser/resume.rs | 23 ++++++----- .../src/gillespie/turnover/launch.rs | 11 +++--- .../independent/src/initialiser/fixup.rs | 11 +++--- .../independent/src/initialiser/genesis.rs | 16 ++++---- .../independent/src/initialiser/mod.rs | 12 +++--- .../independent/src/initialiser/resume.rs | 11 +++--- .../algorithms/independent/src/launch.rs | 18 ++++----- .../scenarios/src/almost_infinite.rs | 17 +++------ rustcoalescence/scenarios/src/non_spatial.rs | 17 +++------ .../src/spatially_explicit/turnover/map.rs | 18 +++------ .../spatially_explicit/turnover/uniform.rs | 17 +++------ .../scenarios/src/spatially_implicit.rs | 23 +++++------ 63 files changed, 347 insertions(+), 386 deletions(-) diff --git a/necsim/core/src/cogs/coalescence_sampler.rs b/necsim/core/src/cogs/coalescence_sampler.rs index 6af72afa7..2f2eed5b3 100644 --- a/necsim/core/src/cogs/coalescence_sampler.rs +++ b/necsim/core/src/cogs/coalescence_sampler.rs @@ -6,8 +6,8 @@ use serde::{Deserialize, Serialize}; use crate::{ cogs::{ - distribution::UniformClosedOpenUnit, Backup, Habitat, LineageStore, MathsCore, Rng, - SampledDistribution, Samples, + distribution::UniformClosedOpenUnit, Backup, Distribution, Habitat, LineageStore, + MathsCore, Rng, Samples, }, landscape::{IndexedLocation, Location}, lineage::LineageInteraction, diff --git a/necsim/core/src/cogs/distribution.rs b/necsim/core/src/cogs/distribution.rs index f59cdf509..525f1689d 100644 --- a/necsim/core/src/cogs/distribution.rs +++ b/necsim/core/src/cogs/distribution.rs @@ -6,13 +6,13 @@ use necsim_core_bond::{ use crate::cogs::{MathsCore, RngCore, Samples}; -pub trait Distribution { +#[allow(clippy::module_name_repetitions)] +pub trait DistributionCore { type Parameters; type Sample; } -#[allow(clippy::module_name_repetitions)] -pub trait SampledDistribution: Distribution { +pub trait Distribution: DistributionCore { fn sample_with>( rng: &mut R, params: Self::Parameters, @@ -20,13 +20,13 @@ pub trait SampledDistribution: Distribution { fn sample>(rng: &mut R) -> Self::Sample where - Self: Distribution, + Self: DistributionCore, { Self::sample_with(rng, ()) } } -impl SampledDistribution for D { +impl Distribution for D { fn sample_with>( rng: &mut R, params: Self::Parameters, @@ -36,7 +36,7 @@ impl SampledDistribution for D { } #[allow(clippy::module_name_repetitions)] -pub trait DistributionSampler { +pub trait DistributionSampler { type ConcreteSampler: DistributionSampler; #[must_use] @@ -48,7 +48,7 @@ pub trait DistributionSampler { #[must_use] fn sample(&self, rng: &mut R, samplers: &S) -> D::Sample where - D: Distribution, + D: DistributionCore, { self.sample_with(rng, samplers, ()) } @@ -56,14 +56,14 @@ pub trait DistributionSampler { pub enum UniformClosedOpenUnit {} -impl Distribution for UniformClosedOpenUnit { +impl DistributionCore for UniformClosedOpenUnit { type Parameters = (); type Sample = ClosedOpenUnitF64; } pub enum UniformOpenClosedUnit {} -impl Distribution for UniformOpenClosedUnit { +impl DistributionCore for UniformOpenClosedUnit { type Parameters = (); type Sample = OpenClosedUnitF64; } @@ -72,28 +72,28 @@ pub enum IndexUsize {} pub struct Length(pub T); -impl Distribution for IndexUsize { +impl DistributionCore for IndexUsize { type Parameters = Length; type Sample = usize; } pub enum IndexU32 {} -impl Distribution for IndexU32 { +impl DistributionCore for IndexU32 { type Parameters = Length; type Sample = u32; } pub enum IndexU64 {} -impl Distribution for IndexU64 { +impl DistributionCore for IndexU64 { type Parameters = Length; type Sample = u64; } pub enum IndexU128 {} -impl Distribution for IndexU128 { +impl DistributionCore for IndexU128 { type Parameters = Length; type Sample = u128; } @@ -102,28 +102,28 @@ pub struct Lambda(pub PositiveF64); pub enum Exponential {} -impl Distribution for Exponential { +impl DistributionCore for Exponential { type Parameters = Lambda; type Sample = NonNegativeF64; } pub enum Poisson {} -impl Distribution for Poisson { +impl DistributionCore for Poisson { type Parameters = Lambda; - type Sample = usize; + type Sample = u64; } pub enum Bernoulli {} -impl Distribution for Bernoulli { +impl DistributionCore for Bernoulli { type Parameters = ClosedUnitF64; type Sample = bool; } pub enum StandardNormal2D {} -impl Distribution for StandardNormal2D { +impl DistributionCore for StandardNormal2D { type Parameters = (); type Sample = (f64, f64); } @@ -135,7 +135,7 @@ pub struct Normal { pub enum Normal2D {} -impl Distribution for Normal2D { +impl DistributionCore for Normal2D { type Parameters = Normal; type Sample = (f64, f64); } diff --git a/necsim/core/src/cogs/mod.rs b/necsim/core/src/cogs/mod.rs index 80324d2f8..125592868 100644 --- a/necsim/core/src/cogs/mod.rs +++ b/necsim/core/src/cogs/mod.rs @@ -13,7 +13,7 @@ pub mod rng; pub use rng::{PrimeableRng, Rng, RngCore, Samples, SeedableRng, SplittableRng}; pub mod distribution; -pub use distribution::{Distribution, DistributionSampler, SampledDistribution}; +pub use distribution::{Distribution, DistributionCore, DistributionSampler}; pub mod dispersal_sampler; pub use dispersal_sampler::{DispersalSampler, SeparableDispersalSampler}; diff --git a/necsim/core/src/cogs/rng.rs b/necsim/core/src/cogs/rng.rs index 3075e6424..dbdf9dd27 100644 --- a/necsim/core/src/cogs/rng.rs +++ b/necsim/core/src/cogs/rng.rs @@ -3,7 +3,7 @@ use core::{convert::AsMut, ptr::copy_nonoverlapping}; use serde::{de::DeserializeOwned, Serialize}; use crate::{ - cogs::{Distribution, DistributionSampler, Habitat, MathsCore}, + cogs::{DistributionCore, DistributionSampler, Habitat, MathsCore}, landscape::IndexedLocation, }; @@ -102,20 +102,20 @@ pub trait SplittableRng: RngCore { fn split_to_stream(self, stream: u64) -> Self; } -pub trait Samples: Rng { +pub trait Samples: Rng { #[must_use] fn sample_with(&mut self, params: D::Parameters) -> D::Sample; #[must_use] fn sample(&mut self) -> D::Sample where - D: Distribution, + D: DistributionCore, { self.sample_with(()) } } -impl> Samples for R +impl> Samples for R where R::Sampler: DistributionSampler, { diff --git a/necsim/impls/no-std/src/alias/mod.rs b/necsim/impls/no-std/src/alias/mod.rs index 1dca499f4..437c52346 100644 --- a/necsim/impls/no-std/src/alias/mod.rs +++ b/necsim/impls/no-std/src/alias/mod.rs @@ -4,7 +4,7 @@ use alloc::vec::Vec; use necsim_core::cogs::{ distribution::{Bernoulli, IndexUsize, Length}, - MathsCore, Rng, SampledDistribution, Samples, + Distribution, MathsCore, Rng, Samples, }; use necsim_core_bond::{ClosedUnitF64, NonNegativeF64}; diff --git a/necsim/impls/no-std/src/alias/packed.rs b/necsim/impls/no-std/src/alias/packed.rs index 69e4f404f..f7019c08d 100644 --- a/necsim/impls/no-std/src/alias/packed.rs +++ b/necsim/impls/no-std/src/alias/packed.rs @@ -4,7 +4,7 @@ use alloc::vec::Vec; use necsim_core::cogs::{ distribution::{Bernoulli, IndexUsize, Length}, - MathsCore, Rng, SampledDistribution, Samples, + Distribution, MathsCore, Rng, Samples, }; use necsim_core_bond::{ClosedUnitF64, NonNegativeF64}; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs index faeab2386..722a6ef81 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs @@ -3,9 +3,9 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ distribution::{Exponential, IndexU128, IndexU64, IndexUsize, Lambda}, - ActiveLineageSampler, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, - Habitat, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, - SampledDistribution, Samples, SpeciationProbability, TurnoverRate, + ActiveLineageSampler, CoalescenceSampler, DispersalSampler, Distribution, EmigrationExit, + EventSampler, Habitat, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, + Samples, SpeciationProbability, TurnoverRate, }, lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs index 6b09f4a40..44c958c08 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs @@ -3,9 +3,9 @@ use core::{num::NonZeroUsize, ops::ControlFlow}; use necsim_core::{ cogs::{ distribution::{Exponential, IndexU128, IndexU64, IndexUsize, Lambda, Length}, - ActiveLineageSampler, Backup, CoalescenceSampler, DispersalSampler, DistributionSampler, + ActiveLineageSampler, Backup, CoalescenceSampler, DispersalSampler, Distribution, EmigrationExit, GloballyCoherentLineageStore, Habitat, ImmigrationEntry, MathsCore, Rng, - SampledDistribution, Samples, SpeciationProbability, TurnoverRate, + Samples, SpeciationProbability, TurnoverRate, }, lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs index 29de8a550..4416760b6 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs @@ -12,7 +12,7 @@ use hashbrown::HashMap; use necsim_core::cogs::{ distribution::{IndexU128, IndexU64, IndexUsize, Length}, - Backup, MathsCore, Rng, SampledDistribution, Samples, + Backup, Distribution, MathsCore, Rng, Samples, }; use necsim_core_bond::{NonNegativeF64, PositiveF64}; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs index ef37863a8..857121d1b 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs @@ -9,7 +9,7 @@ use core::{ use necsim_core::cogs::{ distribution::{IndexU128, IndexU64, IndexUsize, Length}, - Backup, MathsCore, Rng, SampledDistribution, Samples, + Backup, Distribution, MathsCore, Rng, Samples, }; use necsim_core_bond::{NonNegativeF64, PositiveF64}; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs index 315e2360d..60a2c9a29 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs @@ -6,8 +6,8 @@ use core::{ use necsim_core::{ cogs::{ distribution::{Bernoulli, Exponential, IndexUsize, Lambda, Length, UniformClosedOpenUnit}, - ActiveLineageSampler, DispersalSampler, EmigrationExit, Habitat, ImmigrationEntry, - LocallyCoherentLineageStore, MathsCore, Rng, SampledDistribution, Samples, + ActiveLineageSampler, DispersalSampler, Distribution, EmigrationExit, Habitat, + ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, Samples, SpeciationProbability, }, lineage::Lineage, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs index 1c909317b..d9b38f040 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs @@ -2,7 +2,7 @@ use necsim_core::{ cogs::{ distribution::{Exponential, Lambda}, rng::HabitatPrimeableRng, - Habitat, MathsCore, PrimeableRng, Rng, SampledDistribution, Samples, TurnoverRate, + Distribution, Habitat, MathsCore, PrimeableRng, Rng, Samples, TurnoverRate, }, landscape::IndexedLocation, }; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs index aaa1ac100..2a8355407 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs @@ -1,7 +1,7 @@ use necsim_core::{ cogs::{ - distribution::Bernoulli, rng::HabitatPrimeableRng, Habitat, MathsCore, PrimeableRng, Rng, - SampledDistribution, Samples, TurnoverRate, + distribution::Bernoulli, rng::HabitatPrimeableRng, Distribution, Habitat, MathsCore, + PrimeableRng, Rng, Samples, TurnoverRate, }, landscape::IndexedLocation, }; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs index d69de55d6..457c72b52 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs @@ -2,8 +2,7 @@ use necsim_core::{ cogs::{ distribution::{Lambda, Poisson, UniformClosedOpenUnit}, rng::HabitatPrimeableRng, - DistributionSampler, Habitat, MathsCore, PrimeableRng, Rng, SampledDistribution, Samples, - TurnoverRate, + Distribution, Habitat, MathsCore, PrimeableRng, Rng, Samples, TurnoverRate, }, landscape::IndexedLocation, }; @@ -32,7 +31,7 @@ impl PoissonEventTimeSampler { impl< M: MathsCore, H: Habitat, - G: Rng + Samples, + G: Rng + Samples + Samples, T: TurnoverRate, > EventTimeSampler for PoissonEventTimeSampler { @@ -47,8 +46,9 @@ impl< ) -> NonNegativeF64 { let lambda = turnover_rate.get_turnover_rate_at_location(indexed_location.location(), habitat); - let lambda_per_step = lambda * self.delta_t; - let no_event_probability_per_step = M::exp(-lambda_per_step.get()); + // Safety: lambda is already >= 0, cannot be 0 if an event occurs at this + // location + let lambda_per_step = unsafe { PositiveF64::new_unchecked(lambda.get()) } * self.delta_t; #[allow(clippy::cast_possible_truncation)] #[allow(clippy::cast_sign_loss)] @@ -88,7 +88,7 @@ impl< rng.generator().prime_with_habitat( habitat, indexed_location, - time_step + INV_PHI.wrapping_mul(u64::from(event_index + 1)), + time_step + INV_PHI.wrapping_mul(event_index + 1), ); event_time diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs index 344bd4a77..8df4339f3 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs @@ -3,8 +3,7 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ distribution::{Normal, Normal2D}, - Backup, DispersalSampler, MathsCore, Rng, SampledDistribution, Samples, - SeparableDispersalSampler, + Backup, DispersalSampler, Distribution, MathsCore, Rng, Samples, SeparableDispersalSampler, }, landscape::Location, }; diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/dispersal.rs index 5d4986abd..adcc11f75 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/cumulative/dispersal.rs @@ -1,7 +1,7 @@ use necsim_core::{ cogs::{ - distribution::UniformClosedOpenUnit, DispersalSampler, Habitat, MathsCore, Rng, - SampledDistribution, Samples, + distribution::UniformClosedOpenUnit, DispersalSampler, Distribution, Habitat, MathsCore, + Rng, Samples, }, landscape::Location, }; diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs index 5ec6db546..e4d99a7a2 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs @@ -1,7 +1,7 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexUsize}, - DispersalSampler, Habitat, MathsCore, Rng, SampledDistribution, Samples, + DispersalSampler, Distribution, Habitat, MathsCore, Rng, Samples, SeparableDispersalSampler, }, landscape::Location, diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/non_spatial.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/non_spatial.rs index f35dfa5ea..2daf80bc2 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/non_spatial.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/non_spatial.rs @@ -3,7 +3,7 @@ use core::{marker::PhantomData, num::NonZeroU64}; use necsim_core::{ cogs::{ distribution::{IndexU64, Length}, - Backup, DispersalSampler, Habitat, MathsCore, Rng, SampledDistribution, Samples, + Backup, DispersalSampler, Distribution, Habitat, MathsCore, Rng, Samples, SeparableDispersalSampler, }, landscape::Location, diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs index 44f2846e3..edfdbf4e3 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs @@ -1,7 +1,7 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexU64}, - Backup, DispersalSampler, Habitat, MathsCore, Rng, SampledDistribution, Samples, + Backup, DispersalSampler, Distribution, Habitat, MathsCore, Rng, Samples, SeparableDispersalSampler, }, landscape::Location, diff --git a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/mod.rs b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/mod.rs index 4249a52ca..2d8162825 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/mod.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/conditional/mod.rs @@ -3,9 +3,9 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ coalescence_sampler::CoalescenceRngSample, distribution::UniformClosedOpenUnit, - event_sampler::EventHandler, Backup, CoalescenceSampler, DistributionSampler, - EmigrationExit, EventSampler, GloballyCoherentLineageStore, Habitat, MathsCore, Rng, - SampledDistribution, SeparableDispersalSampler, SpeciationProbability, TurnoverRate, + event_sampler::EventHandler, Backup, CoalescenceSampler, Distribution, EmigrationExit, + EventSampler, GloballyCoherentLineageStore, Habitat, MathsCore, Rng, Samples, + SeparableDispersalSampler, SpeciationProbability, TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, landscape::Location, @@ -28,15 +28,13 @@ use probability::ProbabilityAtLocation; pub struct ConditionalGillespieEventSampler< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, S: GloballyCoherentLineageStore, X: EmigrationExit, D: SeparableDispersalSampler, T: TurnoverRate, N: SpeciationProbability, -> where - G::Sampler: DistributionSampler, -{ +> { #[allow(clippy::type_complexity)] marker: PhantomData<(M, H, G, S, X, D, T, N)>, } @@ -44,15 +42,13 @@ pub struct ConditionalGillespieEventSampler< impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, S: GloballyCoherentLineageStore, X: EmigrationExit, D: SeparableDispersalSampler, T: TurnoverRate, N: SpeciationProbability, > Default for ConditionalGillespieEventSampler -where - G::Sampler: DistributionSampler, { fn default() -> Self { Self { @@ -65,15 +61,13 @@ where impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, S: GloballyCoherentLineageStore, X: EmigrationExit, D: SeparableDispersalSampler, T: TurnoverRate, N: SpeciationProbability, > Backup for ConditionalGillespieEventSampler -where - G::Sampler: DistributionSampler, { unsafe fn backup_unchecked(&self) -> Self { Self { @@ -86,7 +80,7 @@ where impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, S: GloballyCoherentLineageStore, X: EmigrationExit, D: SeparableDispersalSampler, @@ -94,8 +88,6 @@ impl< N: SpeciationProbability, > EventSampler, T, N> for ConditionalGillespieEventSampler -where - G::Sampler: DistributionSampler, { #[must_use] fn sample_event_for_lineage_at_event_time_or_emigrate< @@ -240,7 +232,7 @@ where impl< M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, S: GloballyCoherentLineageStore, X: EmigrationExit, D: SeparableDispersalSampler, @@ -248,8 +240,6 @@ impl< N: SpeciationProbability, > GillespieEventSampler, T, N> for ConditionalGillespieEventSampler -where - G::Sampler: DistributionSampler, { #[must_use] fn get_event_rate_at_location( diff --git a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs index f99db3fef..ac7342ce6 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs @@ -5,9 +5,9 @@ use necsim_core::{ coalescence_sampler::CoalescenceRngSample, distribution::{Bernoulli, UniformClosedOpenUnit}, event_sampler::EventHandler, - Backup, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, - GloballyCoherentLineageStore, Habitat, MathsCore, Rng, SampledDistribution, Samples, - SpeciationProbability, TurnoverRate, + Backup, CoalescenceSampler, DispersalSampler, Distribution, EmigrationExit, EventSampler, + GloballyCoherentLineageStore, Habitat, MathsCore, Rng, Samples, SpeciationProbability, + TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, landscape::Location, diff --git a/necsim/impls/no-std/src/cogs/event_sampler/independent.rs b/necsim/impls/no-std/src/cogs/event_sampler/independent.rs index 64e8ef1cb..ffca1715d 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/independent.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/independent.rs @@ -3,8 +3,8 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ coalescence_sampler::CoalescenceRngSample, distribution::UniformClosedOpenUnit, - event_sampler::EventHandler, Backup, CoalescenceSampler, DispersalSampler, EmigrationExit, - EventSampler, Habitat, MathsCore, Rng, SampledDistribution, Samples, SpeciationProbability, + event_sampler::EventHandler, Backup, CoalescenceSampler, DispersalSampler, Distribution, + EmigrationExit, EventSampler, Habitat, MathsCore, Rng, Samples, SpeciationProbability, TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, diff --git a/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs b/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs index aca02a3c6..e8ae14594 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs @@ -5,9 +5,9 @@ use necsim_core::{ coalescence_sampler::CoalescenceRngSample, distribution::{Bernoulli, UniformClosedOpenUnit}, event_sampler::EventHandler, - Backup, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, Habitat, - LocallyCoherentLineageStore, MathsCore, Rng, SampledDistribution, Samples, - SpeciationProbability, TurnoverRate, + Backup, CoalescenceSampler, DispersalSampler, Distribution, EmigrationExit, EventSampler, + Habitat, LocallyCoherentLineageStore, MathsCore, Rng, Samples, SpeciationProbability, + TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, lineage::Lineage, diff --git a/necsim/impls/no-std/src/cogs/habitat/in_memory.rs b/necsim/impls/no-std/src/cogs/habitat/in_memory.rs index 4249f254b..e7960e8bb 100644 --- a/necsim/impls/no-std/src/cogs/habitat/in_memory.rs +++ b/necsim/impls/no-std/src/cogs/habitat/in_memory.rs @@ -7,8 +7,7 @@ use r#final::Final; use necsim_core::{ cogs::{ distribution::{IndexU64, Length}, - Backup, DistributionSampler, Habitat, MathsCore, Rng, SampledDistribution, - UniformlySampleableHabitat, + Backup, Distribution, Habitat, MathsCore, Rng, Samples, UniformlySampleableHabitat, }, landscape::{IndexedLocation, LandscapeExtent, Location}, }; @@ -110,9 +109,8 @@ impl Habitat for InMemoryHabitat { } #[contract_trait] -impl> UniformlySampleableHabitat for InMemoryHabitat -where - G::Sampler: DistributionSampler, +impl + Samples> UniformlySampleableHabitat + for InMemoryHabitat { #[must_use] #[inline] diff --git a/necsim/impls/no-std/src/cogs/habitat/non_spatial.rs b/necsim/impls/no-std/src/cogs/habitat/non_spatial.rs index b4a900fc8..c0ec679c5 100644 --- a/necsim/impls/no-std/src/cogs/habitat/non_spatial.rs +++ b/necsim/impls/no-std/src/cogs/habitat/non_spatial.rs @@ -6,8 +6,7 @@ use core::{ use necsim_core::{ cogs::{ distribution::{IndexU64, Length}, - Backup, DistributionSampler, Habitat, MathsCore, Rng, SampledDistribution, - UniformlySampleableHabitat, + Backup, Distribution, Habitat, MathsCore, Rng, Samples, UniformlySampleableHabitat, }, landscape::{IndexedLocation, LandscapeExtent, Location}, }; @@ -120,9 +119,8 @@ impl Habitat for NonSpatialHabitat { } #[contract_trait] -impl> UniformlySampleableHabitat for NonSpatialHabitat -where - G::Sampler: DistributionSampler, +impl + Samples> UniformlySampleableHabitat + for NonSpatialHabitat { #[must_use] #[inline] diff --git a/necsim/impls/no-std/src/cogs/habitat/spatially_implicit.rs b/necsim/impls/no-std/src/cogs/habitat/spatially_implicit.rs index 964eb63a4..bcc3c2495 100644 --- a/necsim/impls/no-std/src/cogs/habitat/spatially_implicit.rs +++ b/necsim/impls/no-std/src/cogs/habitat/spatially_implicit.rs @@ -2,7 +2,7 @@ use core::num::NonZeroU32; use necsim_core::{ cogs::{ - distribution::IndexU64, Backup, DistributionSampler, Habitat, MathsCore, Rng, + distribution::IndexU64, Backup, Habitat, MathsCore, Rng, Samples, UniformlySampleableHabitat, }, landscape::{IndexedLocation, LandscapeExtent, Location}, @@ -131,9 +131,8 @@ impl Habitat for SpatiallyImplicitHabitat { } #[contract_trait] -impl> UniformlySampleableHabitat for SpatiallyImplicitHabitat -where - G::Sampler: DistributionSampler, +impl + Samples> UniformlySampleableHabitat + for SpatiallyImplicitHabitat { #[must_use] #[inline] diff --git a/necsim/impls/no-std/src/cogs/rng/simple.rs b/necsim/impls/no-std/src/cogs/rng/simple.rs index 010aa98af..9604ccbfb 100644 --- a/necsim/impls/no-std/src/cogs/rng/simple.rs +++ b/necsim/impls/no-std/src/cogs/rng/simple.rs @@ -267,7 +267,7 @@ impl< self } - fn sample_with(&self, rng: &mut R, samplers: &S, params: Lambda) -> usize { + fn sample_with(&self, rng: &mut R, samplers: &S, params: Lambda) -> u64 { let lambda = params.0; let no_event_probability = M::exp(-lambda.get()); @@ -284,13 +284,13 @@ impl< }, ) .0 - .max(0.0_f64) as usize; + .max(0.0_f64) as u64; return normal_as_poisson; } // https://en.wikipedia.org/wiki/Poisson_distribution#cite_ref-Devroye1986_54-0 - let mut poisson = 0_usize; + let mut poisson = 0_u64; let mut prod = no_event_probability; let mut acc = no_event_probability; diff --git a/necsim/impls/no-std/src/parallelisation/independent/individuals.rs b/necsim/impls/no-std/src/parallelisation/independent/individuals.rs index f01b3032f..d8c87e19b 100644 --- a/necsim/impls/no-std/src/parallelisation/independent/individuals.rs +++ b/necsim/impls/no-std/src/parallelisation/independent/individuals.rs @@ -9,8 +9,8 @@ use necsim_core_bond::NonNegativeF64; use necsim_core::{ cogs::{ - distribution::UniformClosedOpenUnit, DispersalSampler, DistributionSampler, Habitat, - MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, + distribution::UniformClosedOpenUnit, DispersalSampler, Habitat, MathsCore, PrimeableRng, + Rng, Samples, SpeciationProbability, TurnoverRate, }, lineage::Lineage, reporter::Reporter, @@ -40,7 +40,7 @@ pub fn simulate< 'p, M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, D: DispersalSampler, T: TurnoverRate, N: SpeciationProbability, @@ -84,10 +84,7 @@ pub fn simulate< NonNegativeF64, u64, impl IntoIterator, -) -where - G::Sampler: DistributionSampler, -{ +) { let mut lineages = VecDeque::from_iter(lineages); let mut proxy = IgnoreProgressReporterProxy::from(local_partition); let mut min_spec_samples = dedup_cache.construct(lineages.len()); diff --git a/necsim/impls/no-std/src/parallelisation/independent/landscape.rs b/necsim/impls/no-std/src/parallelisation/independent/landscape.rs index 63eab7f35..a76569904 100644 --- a/necsim/impls/no-std/src/parallelisation/independent/landscape.rs +++ b/necsim/impls/no-std/src/parallelisation/independent/landscape.rs @@ -9,8 +9,8 @@ use necsim_core_bond::NonNegativeF64; use necsim_core::{ cogs::{ - distribution::UniformClosedOpenUnit, DispersalSampler, DistributionSampler, Habitat, - MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, + distribution::UniformClosedOpenUnit, DispersalSampler, Habitat, MathsCore, PrimeableRng, + Rng, Samples, SpeciationProbability, TurnoverRate, }, event::DispersalEvent, landscape::IndexedLocation, @@ -45,7 +45,7 @@ pub fn simulate< H: Habitat, C: Decomposition, E: EmigrationChoice, - G: Rng, + G: Rng + Samples, D: DispersalSampler, T: TurnoverRate, N: SpeciationProbability, @@ -89,10 +89,7 @@ pub fn simulate< NonNegativeF64, u64, impl IntoIterator, -) -where - G::Sampler: DistributionSampler, -{ +) { let mut lineages = VecDeque::from_iter(lineages); let mut proxy = IgnoreProgressReporterProxy::from(local_partition); let mut min_spec_samples = dedup_cache.construct(lineages.len()); diff --git a/necsim/impls/no-std/src/parallelisation/independent/monolithic/mod.rs b/necsim/impls/no-std/src/parallelisation/independent/monolithic/mod.rs index a2e753bc3..db9f7b2c9 100644 --- a/necsim/impls/no-std/src/parallelisation/independent/monolithic/mod.rs +++ b/necsim/impls/no-std/src/parallelisation/independent/monolithic/mod.rs @@ -8,8 +8,8 @@ use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_core::{ cogs::{ - distribution::UniformClosedOpenUnit, DispersalSampler, DistributionSampler, Habitat, - MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, + distribution::UniformClosedOpenUnit, DispersalSampler, Habitat, MathsCore, PrimeableRng, + Rng, Samples, SpeciationProbability, TurnoverRate, }, lineage::Lineage, reporter::{boolean::Boolean, Reporter}, @@ -45,7 +45,7 @@ pub fn simulate< 'p, M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, D: DispersalSampler, T: TurnoverRate, N: SpeciationProbability, @@ -91,10 +91,7 @@ pub fn simulate< NonNegativeF64, u64, impl IntoIterator, -) -where - G::Sampler: DistributionSampler, -{ +) { let mut slow_lineages = lineages .into_iter() .map(|lineage| { diff --git a/necsim/impls/no-std/src/parallelisation/monolithic/averaging.rs b/necsim/impls/no-std/src/parallelisation/monolithic/averaging.rs index 58e69d69e..9d049ba09 100644 --- a/necsim/impls/no-std/src/parallelisation/monolithic/averaging.rs +++ b/necsim/impls/no-std/src/parallelisation/monolithic/averaging.rs @@ -3,8 +3,8 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ distribution::UniformClosedOpenUnit, ActiveLineageSampler, CoalescenceSampler, - DispersalSampler, DistributionSampler, EventSampler, Habitat, LocallyCoherentLineageStore, - MathsCore, Rng, SpeciationProbability, TurnoverRate, + DispersalSampler, EventSampler, Habitat, LocallyCoherentLineageStore, MathsCore, Rng, + Samples, SpeciationProbability, TurnoverRate, }, reporter::Reporter, simulation::Simulation, @@ -27,7 +27,7 @@ pub fn simulate< 'p, M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, S: LocallyCoherentLineageStore, D: DispersalSampler, C: CoalescenceSampler, @@ -67,10 +67,7 @@ pub fn simulate< >, independent_time_slice: PositiveF64, local_partition: &mut L, -) -> (Status, NonNegativeF64, u64) -where - G::Sampler: DistributionSampler, -{ +) -> (Status, NonNegativeF64, u64) { // Ensure that the progress bar starts with the expected target local_partition.report_progress_sync(simulation.get_balanced_remaining_work().0); diff --git a/necsim/impls/no-std/src/parallelisation/monolithic/lockstep.rs b/necsim/impls/no-std/src/parallelisation/monolithic/lockstep.rs index 3450fc1d7..96cdd81cd 100644 --- a/necsim/impls/no-std/src/parallelisation/monolithic/lockstep.rs +++ b/necsim/impls/no-std/src/parallelisation/monolithic/lockstep.rs @@ -3,8 +3,8 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ distribution::UniformClosedOpenUnit, ActiveLineageSampler, CoalescenceSampler, - DispersalSampler, DistributionSampler, EventSampler, Habitat, LocallyCoherentLineageStore, - MathsCore, Rng, SpeciationProbability, TurnoverRate, + DispersalSampler, EventSampler, Habitat, LocallyCoherentLineageStore, MathsCore, Rng, + Samples, SpeciationProbability, TurnoverRate, }, reporter::{NullReporter, Reporter}, simulation::Simulation, @@ -27,7 +27,7 @@ pub fn simulate< 'p, M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, S: LocallyCoherentLineageStore, D: DispersalSampler, C: CoalescenceSampler, @@ -66,10 +66,7 @@ pub fn simulate< A, >, local_partition: &mut L, -) -> (Status, NonNegativeF64, u64) -where - G::Sampler: DistributionSampler, -{ +) -> (Status, NonNegativeF64, u64) { // Ensure that the progress bar starts with the expected target local_partition.report_progress_sync(simulation.get_balanced_remaining_work().0); diff --git a/necsim/impls/no-std/src/parallelisation/monolithic/optimistic.rs b/necsim/impls/no-std/src/parallelisation/monolithic/optimistic.rs index a0b6838cd..78c5e4105 100644 --- a/necsim/impls/no-std/src/parallelisation/monolithic/optimistic.rs +++ b/necsim/impls/no-std/src/parallelisation/monolithic/optimistic.rs @@ -4,8 +4,8 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ backup::BackedUp, distribution::UniformClosedOpenUnit, ActiveLineageSampler, Backup, - CoalescenceSampler, DispersalSampler, DistributionSampler, EventSampler, Habitat, - LocallyCoherentLineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, + CoalescenceSampler, DispersalSampler, EventSampler, Habitat, LocallyCoherentLineageStore, + MathsCore, Rng, Samples, SpeciationProbability, TurnoverRate, }, lineage::MigratingLineage, reporter::Reporter, @@ -31,7 +31,7 @@ pub fn simulate< 'p, M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, S: LocallyCoherentLineageStore, D: DispersalSampler, C: CoalescenceSampler, @@ -71,10 +71,7 @@ pub fn simulate< >, independent_time_slice: PositiveF64, local_partition: &mut L, -) -> (Status, NonNegativeF64, u64) -where - G::Sampler: DistributionSampler, -{ +) -> (Status, NonNegativeF64, u64) { // Ensure that the progress bar starts with the expected target local_partition.report_progress_sync(simulation.get_balanced_remaining_work().0); diff --git a/necsim/impls/no-std/src/parallelisation/monolithic/optimistic_lockstep.rs b/necsim/impls/no-std/src/parallelisation/monolithic/optimistic_lockstep.rs index 789568ab4..9b51f5c26 100644 --- a/necsim/impls/no-std/src/parallelisation/monolithic/optimistic_lockstep.rs +++ b/necsim/impls/no-std/src/parallelisation/monolithic/optimistic_lockstep.rs @@ -3,8 +3,8 @@ use core::ops::ControlFlow; use necsim_core::{ cogs::{ distribution::UniformClosedOpenUnit, ActiveLineageSampler, Backup, CoalescenceSampler, - DispersalSampler, DistributionSampler, EventSampler, Habitat, LocallyCoherentLineageStore, - MathsCore, Rng, SpeciationProbability, TurnoverRate, + DispersalSampler, EventSampler, Habitat, LocallyCoherentLineageStore, MathsCore, Rng, + Samples, SpeciationProbability, TurnoverRate, }, reporter::{NullReporter, Reporter}, simulation::Simulation, @@ -27,7 +27,7 @@ pub fn simulate< 'p, M: MathsCore, H: Habitat, - G: Rng, + G: Rng + Samples, S: LocallyCoherentLineageStore, D: DispersalSampler, C: CoalescenceSampler, @@ -66,10 +66,7 @@ pub fn simulate< A, >, local_partition: &mut L, -) -> (Status, NonNegativeF64, u64) -where - G::Sampler: DistributionSampler, -{ +) -> (Status, NonNegativeF64, u64) { // Ensure that the progress bar starts with the expected target local_partition.report_progress_sync(simulation.get_balanced_remaining_work().0); diff --git a/rustcoalescence/algorithms/cuda/src/initialiser/fixup.rs b/rustcoalescence/algorithms/cuda/src/initialiser/fixup.rs index fd7620ecb..115791b4f 100644 --- a/rustcoalescence/algorithms/cuda/src/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/cuda/src/initialiser/fixup.rs @@ -1,7 +1,7 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, - DistributionSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, + EmigrationExit, MathsCore, PrimeableRng, Rng, Samples, }, lineage::Lineage, }; @@ -46,7 +46,11 @@ pub struct FixUpInitialiser> { impl< L: ExactSizeIterator, M: MathsCore, - G: Rng + RustToCuda, + G: Rng + + Samples + + Samples + + Samples + + RustToCuda, O: Scenario, > CudaLineageStoreSampleInitialiser> for FixUpInitialiser where @@ -54,9 +58,6 @@ where O::DispersalSampler>: RustToCuda, O::TurnoverRate: RustToCuda, O::SpeciationProbability: RustToCuda, - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler, { type ActiveLineageSampler< X: EmigrationExit> + RustToCuda, diff --git a/rustcoalescence/algorithms/cuda/src/initialiser/genesis.rs b/rustcoalescence/algorithms/cuda/src/initialiser/genesis.rs index a0d5c5188..96055414b 100644 --- a/rustcoalescence/algorithms/cuda/src/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/cuda/src/initialiser/genesis.rs @@ -1,7 +1,7 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, - DistributionSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, + EmigrationExit, MathsCore, PrimeableRng, Rng, Samples, }, lineage::Lineage, }; @@ -26,16 +26,20 @@ use super::CudaLineageStoreSampleInitialiser; #[allow(clippy::module_name_repetitions)] pub struct GenesisInitialiser; -impl + RustToCuda, O: Scenario> - CudaLineageStoreSampleInitialiser for GenesisInitialiser +impl< + M: MathsCore, + G: Rng + + Samples + + Samples + + Samples + + RustToCuda, + O: Scenario, + > CudaLineageStoreSampleInitialiser for GenesisInitialiser where O::Habitat: RustToCuda, O::DispersalSampler>: RustToCuda, O::TurnoverRate: RustToCuda, O::SpeciationProbability: RustToCuda, - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler, { type ActiveLineageSampler< X: EmigrationExit> + RustToCuda, diff --git a/rustcoalescence/algorithms/cuda/src/initialiser/mod.rs b/rustcoalescence/algorithms/cuda/src/initialiser/mod.rs index 3ebb5b28e..7bebde14e 100644 --- a/rustcoalescence/algorithms/cuda/src/initialiser/mod.rs +++ b/rustcoalescence/algorithms/cuda/src/initialiser/mod.rs @@ -1,7 +1,7 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, - DispersalSampler, DistributionSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, + DispersalSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, Samples, }, lineage::Lineage, }; @@ -31,7 +31,11 @@ pub mod resume; #[allow(clippy::module_name_repetitions)] pub trait CudaLineageStoreSampleInitialiser< M: MathsCore, - G: Rng + RustToCuda, + G: Rng + + Samples + + Samples + + Samples + + RustToCuda, O: Scenario, Error: From, > where @@ -39,9 +43,6 @@ pub trait CudaLineageStoreSampleInitialiser< O::DispersalSampler>: RustToCuda, O::TurnoverRate: RustToCuda, O::SpeciationProbability: RustToCuda, - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler, { type DispersalSampler: DispersalSampler + RustToCuda; type ActiveLineageSampler< diff --git a/rustcoalescence/algorithms/cuda/src/initialiser/resume.rs b/rustcoalescence/algorithms/cuda/src/initialiser/resume.rs index 77228019f..936bd6d65 100644 --- a/rustcoalescence/algorithms/cuda/src/initialiser/resume.rs +++ b/rustcoalescence/algorithms/cuda/src/initialiser/resume.rs @@ -1,7 +1,7 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, - DistributionSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, + EmigrationExit, MathsCore, PrimeableRng, Rng, Samples, }, lineage::Lineage, }; @@ -35,7 +35,11 @@ pub struct ResumeInitialiser> { impl< L: ExactSizeIterator, M: MathsCore, - G: Rng + RustToCuda, + G: Rng + + Samples + + Samples + + Samples + + RustToCuda, O: Scenario, > CudaLineageStoreSampleInitialiser> for ResumeInitialiser where @@ -43,9 +47,6 @@ where O::DispersalSampler>: RustToCuda, O::TurnoverRate: RustToCuda, O::SpeciationProbability: RustToCuda, - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler, { type ActiveLineageSampler< X: EmigrationExit> + RustToCuda, diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/fixup.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/fixup.rs index 4a4f1bf86..2fed583c6 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/fixup.rs @@ -3,8 +3,8 @@ use necsim_core::{ distribution::{ Bernoulli, Exponential, IndexU128, IndexU64, IndexUsize, UniformClosedOpenUnit, }, - DistributionSampler, EmigrationExit, GloballyCoherentLineageStore, ImmigrationEntry, - MathsCore, Rng, SeparableDispersalSampler, + EmigrationExit, GloballyCoherentLineageStore, ImmigrationEntry, MathsCore, Rng, Samples, + SeparableDispersalSampler, }, event::DispersalEvent, lineage::{Lineage, LineageInteraction}, @@ -48,17 +48,21 @@ pub struct FixUpInitialiser> { pub fixup_strategy: RestartFixUpStrategy, } -impl, M: MathsCore, G: Rng, O: Scenario> - EventSkippingLineageStoreSampleInitialiser> for FixUpInitialiser +impl< + L: ExactSizeIterator, + M: MathsCore, + G: Rng + + Samples + + Samples + + Samples + + Samples + + Samples + + Samples, + O: Scenario, + > EventSkippingLineageStoreSampleInitialiser> for FixUpInitialiser where O::DispersalSampler>: SeparableDispersalSampler, - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, { type ActiveLineageSampler< S: GloballyCoherentLineageStore, diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/genesis.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/genesis.rs index 1438086de..b464810b7 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/genesis.rs @@ -3,8 +3,8 @@ use necsim_core::{ distribution::{ Bernoulli, Exponential, IndexU128, IndexU64, IndexUsize, UniformClosedOpenUnit, }, - DistributionSampler, EmigrationExit, GloballyCoherentLineageStore, ImmigrationEntry, - MathsCore, Rng, SeparableDispersalSampler, + EmigrationExit, GloballyCoherentLineageStore, ImmigrationEntry, MathsCore, Rng, Samples, + SeparableDispersalSampler, }, reporter::Reporter, }; @@ -25,17 +25,20 @@ use super::EventSkippingLineageStoreSampleInitialiser; #[allow(clippy::module_name_repetitions)] pub struct GenesisInitialiser; -impl, O: Scenario> - EventSkippingLineageStoreSampleInitialiser for GenesisInitialiser +impl< + M: MathsCore, + G: Rng + + Samples + + Samples + + Samples + + Samples + + Samples + + Samples, + O: Scenario, + > EventSkippingLineageStoreSampleInitialiser for GenesisInitialiser where O::DispersalSampler>: SeparableDispersalSampler, - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, { type ActiveLineageSampler< S: GloballyCoherentLineageStore, diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/mod.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/mod.rs index 4b66a3f9e..61e2f386f 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/mod.rs @@ -1,8 +1,8 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, - ActiveLineageSampler, DistributionSampler, EmigrationExit, GloballyCoherentLineageStore, - ImmigrationEntry, MathsCore, Rng, SeparableDispersalSampler, + ActiveLineageSampler, EmigrationExit, GloballyCoherentLineageStore, ImmigrationEntry, + MathsCore, Rng, Samples, SeparableDispersalSampler, }, reporter::Reporter, }; @@ -24,15 +24,12 @@ pub mod resume; #[allow(clippy::module_name_repetitions)] pub trait EventSkippingLineageStoreSampleInitialiser< M: MathsCore, - G: Rng, + G: Rng + Samples + Samples + Samples, O: Scenario, Error, > where O::DispersalSampler>: SeparableDispersalSampler, - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler, { type DispersalSampler: SeparableDispersalSampler; type ActiveLineageSampler< diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/resume.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/resume.rs index c386ab160..aa93e90d6 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/resume.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/resume.rs @@ -3,8 +3,8 @@ use necsim_core::{ distribution::{ Bernoulli, Exponential, IndexU128, IndexU64, IndexUsize, UniformClosedOpenUnit, }, - DistributionSampler, EmigrationExit, GloballyCoherentLineageStore, ImmigrationEntry, - MathsCore, Rng, SeparableDispersalSampler, + EmigrationExit, GloballyCoherentLineageStore, ImmigrationEntry, MathsCore, Rng, Samples, + SeparableDispersalSampler, }, lineage::Lineage, reporter::Reporter, @@ -32,17 +32,21 @@ pub struct ResumeInitialiser> { } #[allow(clippy::type_complexity)] -impl, M: MathsCore, G: Rng, O: Scenario> - EventSkippingLineageStoreSampleInitialiser> for ResumeInitialiser +impl< + L: ExactSizeIterator, + M: MathsCore, + G: Rng + + Samples + + Samples + + Samples + + Samples + + Samples + + Samples, + O: Scenario, + > EventSkippingLineageStoreSampleInitialiser> for ResumeInitialiser where O::DispersalSampler>: SeparableDispersalSampler, - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, { type ActiveLineageSampler< S: GloballyCoherentLineageStore, diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs index 5752ee4f6..22c2e794b 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs @@ -3,7 +3,7 @@ use std::{hint::unreachable_unchecked, marker::PhantomData}; use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, - ActiveLineageSampler, DistributionSampler, GloballyCoherentLineageStore, MathsCore, Rng, + ActiveLineageSampler, GloballyCoherentLineageStore, MathsCore, Rng, Samples, SeparableDispersalSampler, SplittableRng, }, reporter::Reporter, @@ -38,7 +38,10 @@ use crate::arguments::{ pub fn initialise_and_simulate< 'p, M: MathsCore, - G: Rng, + G: Rng + + Samples + + Samples + + Samples, O: Scenario, R: Reporter, P: LocalPartition<'p, R>, @@ -59,9 +62,6 @@ where GloballyCoherentLineageStore, O::DispersalSampler>: SeparableDispersalSampler, - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler, { match args.parallelism_mode { ParallelismMode::Monolithic => { diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs index 004e71036..ecca829c7 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs @@ -1,8 +1,7 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, Exponential, IndexUsize, UniformClosedOpenUnit}, - DistributionSampler, EmigrationExit, ImmigrationEntry, LocallyCoherentLineageStore, - MathsCore, Rng, + EmigrationExit, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, Samples, }, event::DispersalEvent, lineage::{Lineage, LineageInteraction}, @@ -47,13 +46,16 @@ pub struct FixUpInitialiser> { pub fixup_strategy: RestartFixUpStrategy, } -impl, M: MathsCore, G: Rng, O: Scenario> - ClassicalLineageStoreSampleInitialiser> for FixUpInitialiser -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, +impl< + L: ExactSizeIterator, + M: MathsCore, + G: Rng + + Samples + + Samples + + Samples + + Samples, + O: Scenario, + > ClassicalLineageStoreSampleInitialiser> for FixUpInitialiser { type ActiveLineageSampler< S: LocallyCoherentLineageStore, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/genesis.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/genesis.rs index f1c629bf1..1df6aac38 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/genesis.rs @@ -1,8 +1,7 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, Exponential, IndexUsize, UniformClosedOpenUnit}, - DistributionSampler, EmigrationExit, ImmigrationEntry, LocallyCoherentLineageStore, - MathsCore, Rng, + EmigrationExit, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, Samples, }, reporter::Reporter, }; @@ -21,13 +20,15 @@ use super::ClassicalLineageStoreSampleInitialiser; #[allow(clippy::module_name_repetitions)] pub struct GenesisInitialiser; -impl, O: Scenario> ClassicalLineageStoreSampleInitialiser - for GenesisInitialiser -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, +impl< + M: MathsCore, + G: Rng + + Samples + + Samples + + Samples + + Samples, + O: Scenario, + > ClassicalLineageStoreSampleInitialiser for GenesisInitialiser { type ActiveLineageSampler< S: LocallyCoherentLineageStore, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/mod.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/mod.rs index f8459676d..6f694b803 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/mod.rs @@ -1,8 +1,8 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, - ActiveLineageSampler, DispersalSampler, DistributionSampler, EmigrationExit, - ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, + ActiveLineageSampler, DispersalSampler, EmigrationExit, ImmigrationEntry, + LocallyCoherentLineageStore, MathsCore, Rng, Samples, }, reporter::Reporter, }; @@ -22,11 +22,12 @@ pub mod genesis; pub mod resume; #[allow(clippy::module_name_repetitions)] -pub trait ClassicalLineageStoreSampleInitialiser, O: Scenario, Error> -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler, +pub trait ClassicalLineageStoreSampleInitialiser< + M: MathsCore, + G: Rng + Samples + Samples + Samples, + O: Scenario, + Error, +> { type DispersalSampler: DispersalSampler; type ActiveLineageSampler< diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/resume.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/resume.rs index 484f068a4..458177523 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/resume.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/resume.rs @@ -1,8 +1,7 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, Exponential, IndexUsize, UniformClosedOpenUnit}, - DistributionSampler, EmigrationExit, ImmigrationEntry, LocallyCoherentLineageStore, - MathsCore, Rng, + EmigrationExit, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, Samples, }, lineage::Lineage, reporter::Reporter, @@ -27,13 +26,16 @@ pub struct ResumeInitialiser> { pub resume_after: Option, } -impl, M: MathsCore, G: Rng, O: Scenario> - ClassicalLineageStoreSampleInitialiser> for ResumeInitialiser -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, +impl< + L: ExactSizeIterator, + M: MathsCore, + G: Rng + + Samples + + Samples + + Samples + + Samples, + O: Scenario, + > ClassicalLineageStoreSampleInitialiser> for ResumeInitialiser { type ActiveLineageSampler< S: LocallyCoherentLineageStore, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs index 298e5900a..db147badb 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs @@ -3,8 +3,7 @@ use std::{hint::unreachable_unchecked, marker::PhantomData}; use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, - ActiveLineageSampler, DistributionSampler, LocallyCoherentLineageStore, MathsCore, Rng, - SplittableRng, + ActiveLineageSampler, LocallyCoherentLineageStore, MathsCore, Rng, Samples, SplittableRng, }, reporter::Reporter, simulation::SimulationBuilder, @@ -41,7 +40,10 @@ use super::initialiser::ClassicalLineageStoreSampleInitialiser; pub fn initialise_and_simulate< 'p, M: MathsCore, - G: Rng, + G: Rng + + Samples + + Samples + + Samples, O: Scenario, R: Reporter, P: LocalPartition<'p, R>, @@ -60,9 +62,6 @@ pub fn initialise_and_simulate< where O::LineageStore>: LocallyCoherentLineageStore, - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler, { match args.parallelism_mode { ParallelismMode::Monolithic => { diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/fixup.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/fixup.rs index 43d853008..aa6d3d57a 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/fixup.rs @@ -1,8 +1,8 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, Exponential, IndexU128, IndexU64, IndexUsize}, - CoalescenceSampler, DistributionSampler, EmigrationExit, EventSampler, ImmigrationEntry, - LocallyCoherentLineageStore, MathsCore, Rng, + CoalescenceSampler, EmigrationExit, EventSampler, ImmigrationEntry, + LocallyCoherentLineageStore, MathsCore, Rng, Samples, }, event::DispersalEvent, lineage::{Lineage, LineageInteraction}, @@ -44,14 +44,17 @@ pub struct FixUpInitialiser> { pub fixup_strategy: RestartFixUpStrategy, } -impl, M: MathsCore, G: Rng, O: Scenario> - GillespieLineageStoreSampleInitialiser> for FixUpInitialiser -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, +impl< + L: ExactSizeIterator, + M: MathsCore, + G: Rng + + Samples + + Samples + + Samples + + Samples + + Samples, + O: Scenario, + > GillespieLineageStoreSampleInitialiser> for FixUpInitialiser { type ActiveLineageSampler< S: LocallyCoherentLineageStore, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/genesis.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/genesis.rs index a0ce35c3e..6f9ae9605 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/genesis.rs @@ -1,8 +1,8 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, Exponential, IndexU128, IndexU64, IndexUsize}, - CoalescenceSampler, DistributionSampler, EmigrationExit, EventSampler, ImmigrationEntry, - LocallyCoherentLineageStore, MathsCore, Rng, + CoalescenceSampler, EmigrationExit, EventSampler, ImmigrationEntry, + LocallyCoherentLineageStore, MathsCore, Rng, Samples, }, reporter::Reporter, }; @@ -21,14 +21,16 @@ use super::GillespieLineageStoreSampleInitialiser; #[allow(clippy::module_name_repetitions)] pub struct GenesisInitialiser; -impl, O: Scenario> GillespieLineageStoreSampleInitialiser - for GenesisInitialiser -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, +impl< + M: MathsCore, + G: Rng + + Samples + + Samples + + Samples + + Samples + + Samples, + O: Scenario, + > GillespieLineageStoreSampleInitialiser for GenesisInitialiser { type ActiveLineageSampler< S: LocallyCoherentLineageStore, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/mod.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/mod.rs index 20370ee6b..cb8fd7bc2 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/mod.rs @@ -1,9 +1,8 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexUsize}, - ActiveLineageSampler, CoalescenceSampler, DispersalSampler, DistributionSampler, - EmigrationExit, EventSampler, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, - Rng, + ActiveLineageSampler, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, + ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, Samples, }, reporter::Reporter, }; @@ -21,10 +20,12 @@ pub mod genesis; pub mod resume; #[allow(clippy::module_name_repetitions)] -pub trait GillespieLineageStoreSampleInitialiser, O: Scenario, Error> -where - G::Sampler: DistributionSampler - + DistributionSampler, +pub trait GillespieLineageStoreSampleInitialiser< + M: MathsCore, + G: Rng + Samples + Samples, + O: Scenario, + Error, +> { type DispersalSampler: DispersalSampler; type ActiveLineageSampler< diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/resume.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/resume.rs index 8618cd4e2..281635014 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/resume.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/resume.rs @@ -1,8 +1,8 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, Exponential, IndexU128, IndexU64, IndexUsize}, - CoalescenceSampler, DistributionSampler, EmigrationExit, EventSampler, ImmigrationEntry, - LocallyCoherentLineageStore, MathsCore, Rng, + CoalescenceSampler, EmigrationExit, EventSampler, ImmigrationEntry, + LocallyCoherentLineageStore, MathsCore, Rng, Samples, }, lineage::Lineage, reporter::Reporter, @@ -27,14 +27,17 @@ pub struct ResumeInitialiser> { pub resume_after: Option, } -impl, M: MathsCore, G: Rng, O: Scenario> - GillespieLineageStoreSampleInitialiser> for ResumeInitialiser -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, +impl< + L: ExactSizeIterator, + M: MathsCore, + G: Rng + + Samples + + Samples + + Samples + + Samples + + Samples, + O: Scenario, + > GillespieLineageStoreSampleInitialiser> for ResumeInitialiser { type ActiveLineageSampler< S: LocallyCoherentLineageStore, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs index 90c3db24d..86d90adb4 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs @@ -3,8 +3,7 @@ use std::{hint::unreachable_unchecked, marker::PhantomData}; use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, - ActiveLineageSampler, DistributionSampler, LocallyCoherentLineageStore, MathsCore, Rng, - SplittableRng, + ActiveLineageSampler, LocallyCoherentLineageStore, MathsCore, Rng, Samples, SplittableRng, }, reporter::Reporter, simulation::SimulationBuilder, @@ -40,7 +39,10 @@ use super::initialiser::GillespieLineageStoreSampleInitialiser; pub fn initialise_and_simulate< 'p, M: MathsCore, - G: Rng, + G: Rng + + Samples + + Samples + + Samples, O: Scenario, R: Reporter, P: LocalPartition<'p, R>, @@ -59,9 +61,6 @@ pub fn initialise_and_simulate< where O::LineageStore>: LocallyCoherentLineageStore, - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler, { match args.parallelism_mode { ParallelismMode::Monolithic => { diff --git a/rustcoalescence/algorithms/independent/src/initialiser/fixup.rs b/rustcoalescence/algorithms/independent/src/initialiser/fixup.rs index 563e4adb3..76ecab2b0 100644 --- a/rustcoalescence/algorithms/independent/src/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/independent/src/initialiser/fixup.rs @@ -1,7 +1,7 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, - DistributionSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, + EmigrationExit, MathsCore, PrimeableRng, Rng, Samples, }, lineage::Lineage, }; @@ -42,13 +42,12 @@ pub struct FixUpInitialiser> { impl< L: ExactSizeIterator, M: MathsCore, - G: Rng, + G: Rng + + Samples + + Samples + + Samples, O: Scenario, > IndependentLineageStoreSampleInitialiser> for FixUpInitialiser -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler, { type ActiveLineageSampler< X: EmigrationExit>, diff --git a/rustcoalescence/algorithms/independent/src/initialiser/genesis.rs b/rustcoalescence/algorithms/independent/src/initialiser/genesis.rs index 88107b22b..730c5e3ad 100644 --- a/rustcoalescence/algorithms/independent/src/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/independent/src/initialiser/genesis.rs @@ -1,7 +1,7 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, - DistributionSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, + EmigrationExit, MathsCore, PrimeableRng, Rng, Samples, }, lineage::Lineage, }; @@ -22,12 +22,14 @@ use super::IndependentLineageStoreSampleInitialiser; #[allow(clippy::module_name_repetitions)] pub struct GenesisInitialiser; -impl, O: Scenario> - IndependentLineageStoreSampleInitialiser for GenesisInitialiser -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler, +impl< + M: MathsCore, + G: Rng + + Samples + + Samples + + Samples, + O: Scenario, + > IndependentLineageStoreSampleInitialiser for GenesisInitialiser { type ActiveLineageSampler< X: EmigrationExit>, diff --git a/rustcoalescence/algorithms/independent/src/initialiser/mod.rs b/rustcoalescence/algorithms/independent/src/initialiser/mod.rs index f3de92c3d..e599e6501 100644 --- a/rustcoalescence/algorithms/independent/src/initialiser/mod.rs +++ b/rustcoalescence/algorithms/independent/src/initialiser/mod.rs @@ -1,7 +1,7 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, - DispersalSampler, DistributionSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, + DispersalSampler, EmigrationExit, MathsCore, PrimeableRng, Rng, Samples, }, lineage::Lineage, }; @@ -27,13 +27,13 @@ pub mod resume; #[allow(clippy::module_name_repetitions)] pub trait IndependentLineageStoreSampleInitialiser< M: MathsCore, - G: Rng, + G: Rng + + Samples + + Samples + + Samples, O: Scenario, Error, -> where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler, +> { type DispersalSampler: DispersalSampler; type ActiveLineageSampler> { impl< L: ExactSizeIterator, M: MathsCore, - G: Rng, + G: Rng + + Samples + + Samples + + Samples, O: Scenario, > IndependentLineageStoreSampleInitialiser> for ResumeInitialiser -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler, { type ActiveLineageSampler< X: EmigrationExit>, diff --git a/rustcoalescence/algorithms/independent/src/launch.rs b/rustcoalescence/algorithms/independent/src/launch.rs index fcbe5d1bd..2d13ad2a1 100644 --- a/rustcoalescence/algorithms/independent/src/launch.rs +++ b/rustcoalescence/algorithms/independent/src/launch.rs @@ -2,8 +2,8 @@ use std::marker::PhantomData; use necsim_core::{ cogs::{ - distribution::{Bernoulli, IndexUsize, Normal2D, UniformClosedOpenUnit}, - DistributionSampler, MathsCore, PrimeableRng, Rng, + distribution::{Bernoulli, IndexUsize, Poisson, UniformClosedOpenUnit}, + MathsCore, PrimeableRng, Rng, Samples, }, reporter::Reporter, simulation::SimulationBuilder, @@ -49,7 +49,11 @@ use crate::{ pub fn initialise_and_simulate< 'p, M: MathsCore, - G: Rng, + G: Rng + + Samples + + Samples + + Samples + + Samples, O: Scenario, R: Reporter, P: LocalPartition<'p, R>, @@ -64,13 +68,7 @@ pub fn initialise_and_simulate< pause_before: Option, local_partition: &mut P, lineage_store_sampler_initialiser: L, -) -> Result, Error> -where - G::Sampler: DistributionSampler - + DistributionSampler - + DistributionSampler - + DistributionSampler, -{ +) -> Result, Error> { match args.parallelism_mode { ParallelismMode::Monolithic(MonolithicParallelismMode { event_slice }) | ParallelismMode::IsolatedIndividuals(IsolatedParallelismMode { event_slice, .. }) diff --git a/rustcoalescence/scenarios/src/almost_infinite.rs b/rustcoalescence/scenarios/src/almost_infinite.rs index 6636731c9..e908c497c 100644 --- a/rustcoalescence/scenarios/src/almost_infinite.rs +++ b/rustcoalescence/scenarios/src/almost_infinite.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use necsim_core::cogs::{ - distribution::Normal2D, DispersalSampler, DistributionSampler, LineageStore, MathsCore, Rng, + distribution::Normal2D, DispersalSampler, LineageStore, MathsCore, Rng, Samples, }; use necsim_core_bond::{NonNegativeF64, OpenClosedUnitF64 as PositiveUnitF64}; use necsim_partitioning_core::partition::Partition; @@ -23,10 +23,7 @@ use necsim_impls_no_std::{ use crate::{Scenario, ScenarioParameters}; #[allow(clippy::module_name_repetitions)] -pub struct AlmostInfiniteScenario> -where - G::Sampler: DistributionSampler, -{ +pub struct AlmostInfiniteScenario + Samples> { radius: u16, habitat: AlmostInfiniteHabitat, @@ -43,17 +40,15 @@ pub struct AlmostInfiniteArguments { pub sigma: NonNegativeF64, } -impl> ScenarioParameters for AlmostInfiniteScenario -where - G::Sampler: DistributionSampler, +impl + Samples> ScenarioParameters + for AlmostInfiniteScenario { type Arguments = AlmostInfiniteArguments; type Error = !; } -impl> Scenario for AlmostInfiniteScenario -where - G::Sampler: DistributionSampler, +impl + Samples> Scenario + for AlmostInfiniteScenario { type Decomposition = RadialDecomposition; type DecompositionAuxiliary = (); diff --git a/rustcoalescence/scenarios/src/non_spatial.rs b/rustcoalescence/scenarios/src/non_spatial.rs index 571d54f6b..07df10df9 100644 --- a/rustcoalescence/scenarios/src/non_spatial.rs +++ b/rustcoalescence/scenarios/src/non_spatial.rs @@ -3,7 +3,7 @@ use std::num::NonZeroU32; use serde::{Deserialize, Serialize}; use necsim_core::cogs::{ - distribution::IndexU64, DispersalSampler, DistributionSampler, LineageStore, MathsCore, Rng, + distribution::IndexU64, DispersalSampler, LineageStore, MathsCore, Rng, Samples, }; use necsim_core_bond::{OffByOneU32, OpenClosedUnitF64 as PositiveUnitF64}; use necsim_partitioning_core::partition::Partition; @@ -22,10 +22,7 @@ use necsim_impls_no_std::{ use crate::{Scenario, ScenarioParameters}; #[allow(clippy::module_name_repetitions)] -pub struct NonSpatialScenario> -where - G::Sampler: DistributionSampler, -{ +pub struct NonSpatialScenario + Samples> { habitat: NonSpatialHabitat, dispersal_sampler: NonSpatialDispersalSampler, turnover_rate: UniformTurnoverRate, @@ -39,18 +36,14 @@ pub struct NonSpatialArguments { pub deme: NonZeroU32, } -impl> ScenarioParameters for NonSpatialScenario -where - G::Sampler: DistributionSampler, +impl + Samples> ScenarioParameters + for NonSpatialScenario { type Arguments = NonSpatialArguments; type Error = !; } -impl> Scenario for NonSpatialScenario -where - G::Sampler: DistributionSampler, -{ +impl + Samples> Scenario for NonSpatialScenario { type Decomposition = ModuloDecomposition; type DecompositionAuxiliary = (); type DispersalSampler> = diff --git a/rustcoalescence/scenarios/src/spatially_explicit/turnover/map.rs b/rustcoalescence/scenarios/src/spatially_explicit/turnover/map.rs index a7d6157fd..f19cb079c 100644 --- a/rustcoalescence/scenarios/src/spatially_explicit/turnover/map.rs +++ b/rustcoalescence/scenarios/src/spatially_explicit/turnover/map.rs @@ -3,8 +3,7 @@ use std::{convert::TryFrom, marker::PhantomData, path::PathBuf}; use serde::{Deserialize, Serialize, Serializer}; use necsim_core::cogs::{ - distribution::IndexU64, DispersalSampler, DistributionSampler, Habitat, LineageStore, - MathsCore, Rng, + distribution::IndexU64, DispersalSampler, Habitat, LineageStore, MathsCore, Rng, Samples, }; use necsim_core_bond::{NonNegativeF64, OpenClosedUnitF64 as PositiveUnitF64}; use necsim_partitioning_core::partition::Partition; @@ -41,10 +40,7 @@ pub enum SpatiallyExplicitTurnoverMapScenarioError { } #[allow(clippy::module_name_repetitions)] -pub struct SpatiallyExplicitTurnoverMapScenario> -where - G::Sampler: DistributionSampler, -{ +pub struct SpatiallyExplicitTurnoverMapScenario + Samples> { habitat: InMemoryHabitat, dispersal_map: Array2D, turnover_rate: InMemoryTurnoverRate, @@ -52,17 +48,15 @@ where _marker: PhantomData, } -impl> ScenarioParameters for SpatiallyExplicitTurnoverMapScenario -where - G::Sampler: DistributionSampler, +impl + Samples> ScenarioParameters + for SpatiallyExplicitTurnoverMapScenario { type Arguments = SpatiallyExplicitTurnoverMapArguments; type Error = SpatiallyExplicitTurnoverMapScenarioError; } -impl> Scenario for SpatiallyExplicitTurnoverMapScenario -where - G::Sampler: DistributionSampler, +impl + Samples> Scenario + for SpatiallyExplicitTurnoverMapScenario { type Decomposition = EqualDecomposition; type DecompositionAuxiliary = (); diff --git a/rustcoalescence/scenarios/src/spatially_explicit/turnover/uniform.rs b/rustcoalescence/scenarios/src/spatially_explicit/turnover/uniform.rs index 67c470e6c..e19aade26 100644 --- a/rustcoalescence/scenarios/src/spatially_explicit/turnover/uniform.rs +++ b/rustcoalescence/scenarios/src/spatially_explicit/turnover/uniform.rs @@ -3,8 +3,7 @@ use std::{convert::TryFrom, marker::PhantomData, path::PathBuf}; use serde::{Deserialize, Serialize, Serializer}; use necsim_core::cogs::{ - distribution::IndexU64, DispersalSampler, DistributionSampler, Habitat, LineageStore, - MathsCore, Rng, + distribution::IndexU64, DispersalSampler, Habitat, LineageStore, MathsCore, Rng, Samples, }; use necsim_core_bond::{NonNegativeF64, OpenClosedUnitF64 as PositiveUnitF64, PositiveF64}; use necsim_partitioning_core::partition::Partition; @@ -39,9 +38,7 @@ pub enum SpatiallyExplicitUniformTurnoverScenarioError { } #[allow(clippy::module_name_repetitions)] -pub struct SpatiallyExplicitUniformTurnoverScenario> -where - G::Sampler: DistributionSampler, +pub struct SpatiallyExplicitUniformTurnoverScenario + Samples> { habitat: InMemoryHabitat, dispersal_map: Array2D, @@ -50,17 +47,15 @@ where _marker: PhantomData, } -impl> ScenarioParameters for SpatiallyExplicitUniformTurnoverScenario -where - G::Sampler: DistributionSampler, +impl + Samples> ScenarioParameters + for SpatiallyExplicitUniformTurnoverScenario { type Arguments = SpatiallyExplicitUniformTurnoverArguments; type Error = SpatiallyExplicitUniformTurnoverScenarioError; } -impl> Scenario for SpatiallyExplicitUniformTurnoverScenario -where - G::Sampler: DistributionSampler, +impl + Samples> Scenario + for SpatiallyExplicitUniformTurnoverScenario { type Decomposition = EqualDecomposition; type DecompositionAuxiliary = (); diff --git a/rustcoalescence/scenarios/src/spatially_implicit.rs b/rustcoalescence/scenarios/src/spatially_implicit.rs index 5a29dcf51..4933bd6f7 100644 --- a/rustcoalescence/scenarios/src/spatially_implicit.rs +++ b/rustcoalescence/scenarios/src/spatially_implicit.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use necsim_core::cogs::{ distribution::{Bernoulli, IndexU64}, - DispersalSampler, DistributionSampler, LineageStore, MathsCore, Rng, + DispersalSampler, LineageStore, MathsCore, Rng, Samples, }; use necsim_core_bond::{OffByOneU32, OpenClosedUnitF64 as PositiveUnitF64}; use necsim_partitioning_core::partition::Partition; @@ -25,11 +25,10 @@ use necsim_impls_no_std::{ use crate::{Scenario, ScenarioParameters}; #[allow(clippy::module_name_repetitions)] -pub struct SpatiallyImplicitScenario> -where - G::Sampler: DistributionSampler - + DistributionSampler, -{ +pub struct SpatiallyImplicitScenario< + M: MathsCore, + G: Rng + Samples + Samples, +> { habitat: SpatiallyImplicitHabitat, dispersal_sampler: SpatiallyImplicitDispersalSampler, turnover_rate: UniformTurnoverRate, @@ -48,19 +47,15 @@ pub struct SpatiallyImplicitArguments { pub migration_probability_per_generation: PositiveUnitF64, } -impl> ScenarioParameters for SpatiallyImplicitScenario -where - G::Sampler: DistributionSampler - + DistributionSampler, +impl + Samples + Samples> ScenarioParameters + for SpatiallyImplicitScenario { type Arguments = SpatiallyImplicitArguments; type Error = !; } -impl> Scenario for SpatiallyImplicitScenario -where - G::Sampler: DistributionSampler - + DistributionSampler, +impl + Samples + Samples> Scenario + for SpatiallyImplicitScenario { type Decomposition = ModuloDecomposition; type DecompositionAuxiliary = (); From fb639bbba1f6306c084dedb32de79c98e1e10a83 Mon Sep 17 00:00:00 2001 From: Momo Langenstein Date: Thu, 19 May 2022 14:55:30 +0000 Subject: [PATCH 11/42] Backup of partial refactoring of Rng not a subtrait of RngCore --- necsim/core/src/cogs/rng.rs | 8 ++-- necsim/impls/cuda/src/cogs/rng.rs | 46 +++--------------- .../alias/sampler/indexed/mod.rs | 4 +- .../alias/sampler/indexed/tests.rs | 10 ++-- .../alias/sampler/stack/mod.rs | 4 +- .../alias/sampler/stack/tests.rs | 10 ++-- .../src/cogs/habitat/almost_infinite.rs | 4 +- necsim/impls/no-std/src/cogs/rng/simple.rs | 41 ++++------------ rustcoalescence/algorithms/cuda/src/launch.rs | 9 ++-- rustcoalescence/algorithms/cuda/src/lib.rs | 18 ++++--- .../src/gillespie/classical/launch.rs | 22 ++++----- .../gillespie/src/gillespie/classical/mod.rs | 14 +++--- .../algorithms/independent/src/launch.rs | 31 +++++------- .../algorithms/independent/src/lib.rs | 18 ++++--- rustcoalescence/algorithms/src/lib.rs | 12 ++--- rustcoalescence/algorithms/src/result.rs | 10 ++-- rustcoalescence/src/args/config/rng/mod.rs | 47 +++++++------------ .../src/cli/simulate/dispatch/valid/rng.rs | 7 ++- rustcoalescence/src/cli/simulate/parse/rng.rs | 11 ++--- 19 files changed, 127 insertions(+), 199 deletions(-) diff --git a/necsim/core/src/cogs/rng.rs b/necsim/core/src/cogs/rng.rs index dbdf9dd27..956cae27b 100644 --- a/necsim/core/src/cogs/rng.rs +++ b/necsim/core/src/cogs/rng.rs @@ -3,11 +3,11 @@ use core::{convert::AsMut, ptr::copy_nonoverlapping}; use serde::{de::DeserializeOwned, Serialize}; use crate::{ - cogs::{DistributionCore, DistributionSampler, Habitat, MathsCore}, + cogs::{Backup, DistributionCore, DistributionSampler, Habitat, MathsCore}, landscape::IndexedLocation, }; -pub trait Rng: RngCore { +pub trait Rng: Backup + Clone + core::fmt::Debug { type Generator: RngCore; type Sampler; @@ -17,7 +17,7 @@ pub trait Rng: RngCore { #[must_use] fn map_generator Self::Generator>(self, map: F) -> Self; - fn with_rng Q, Q>(&mut self, inner: F) -> Q; + fn with Q, Q>(&mut self, inner: F) -> Q; } #[allow(clippy::module_name_repetitions)] @@ -121,6 +121,6 @@ where { #[must_use] fn sample_with(&mut self, params: D::Parameters) -> D::Sample { - self.with_rng(|rng, samplers| samplers.sample_with(rng, samplers, params)) + self.with(|rng, samplers| samplers.sample_with(rng, samplers, params)) } } diff --git a/necsim/impls/cuda/src/cogs/rng.rs b/necsim/impls/cuda/src/cogs/rng.rs index 8c29ba2b7..99d7df48a 100644 --- a/necsim/impls/cuda/src/cogs/rng.rs +++ b/necsim/impls/cuda/src/cogs/rng.rs @@ -1,11 +1,9 @@ use core::marker::PhantomData; -use necsim_core::cogs::{MathsCore, Rng, RngCore}; - use const_type_layout::TypeGraphLayout; use rust_cuda::safety::StackOnly; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use necsim_core::cogs::{MathsCore, Rng}; #[allow(clippy::module_name_repetitions)] #[derive(Debug, rust_cuda::common::LendRustToCuda)] @@ -38,22 +36,9 @@ impl + StackOnly + ~const TypeGraphLayout> From for C } } -impl + StackOnly + ~const TypeGraphLayout> RngCore for CudaRng { - type Seed = ::Seed; - - #[must_use] - #[inline] - fn from_seed(seed: Self::Seed) -> Self { - Self { - inner: R::from_seed(seed), - marker: PhantomData::, - } - } - - #[must_use] - #[inline] - fn sample_u64(&mut self) -> u64 { - self.inner.sample_u64() +impl + StackOnly + ~const TypeGraphLayout> CudaRng { + pub fn into(self) -> R { + self.inner } } @@ -74,26 +59,7 @@ impl + StackOnly + ~const TypeGraphLayout> Rng for Cu } } - fn with_rng Q, Q>(&mut self, inner: F) -> Q { - self.inner.with_rng(inner) - } -} - -impl + StackOnly + ~const TypeGraphLayout> Serialize for CudaRng { - fn serialize(&self, serializer: S) -> Result { - self.inner.serialize(serializer) - } -} - -impl<'de, M: MathsCore, R: Rng + StackOnly + ~const TypeGraphLayout> Deserialize<'de> - for CudaRng -{ - fn deserialize>(deserializer: D) -> Result { - let inner = R::deserialize(deserializer)?; - - Ok(Self { - inner, - marker: PhantomData::, - }) + fn with Q, Q>(&mut self, inner: F) -> Q { + self.inner.with(inner) } } diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs index 4416760b6..19d5ac095 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs @@ -12,7 +12,7 @@ use hashbrown::HashMap; use necsim_core::cogs::{ distribution::{IndexU128, IndexU64, IndexUsize, Length}, - Backup, Distribution, MathsCore, Rng, Samples, + Backup, Distribution, MathsCore, Rng, RngCore, Samples, }; use necsim_core_bond::{NonNegativeF64, PositiveF64}; @@ -67,7 +67,7 @@ impl RejectionSamplingGroup { rng, Length(NonZeroUsize::new_unchecked(self.weights.len())), ); - let height = rng.sample_u64() >> 11; + let height = rng.generator().sample_u64() >> 11; // 53rd bit of weight is always 1, so sampling chance >= 50% if height < self.weights[index] { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs index 1d1e0872e..ae4187417 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs @@ -191,7 +191,7 @@ fn sample_single_group() { let mut tally = [0_u64; 6]; - let mut rng = SimpleRng::::seed_from_u64(24897); + let mut rng = SimpleRng::::from(WyHash::seed_from_u64(24897)); for _ in 0..N { let (maybe_group, sample) = group.sample_pop(&mut lookup, &mut rng); @@ -906,7 +906,7 @@ fn add_update_event_full() { fn sample_single_group_full() { const N: usize = 10_000_000; - let mut rng = SimpleRng::::seed_from_u64(471_093); + let mut rng = SimpleRng::::from(WyHash::seed_from_u64(471_093)); let mut sampler = DynamicAliasMethodIndexedSampler::with_capacity(6); @@ -955,7 +955,7 @@ fn sample_single_group_full() { fn sample_three_groups_full() { const N: usize = 10_000_000; - let mut rng = SimpleRng::::seed_from_u64(739_139); + let mut rng = SimpleRng::::from(WyHash::seed_from_u64(739_139)); let mut sampler = DynamicAliasMethodIndexedSampler::with_capacity(6); @@ -1001,7 +1001,7 @@ fn sample_three_groups_full() { fn sample_three_groups_full_reverse() { const N: usize = 10_000_000; - let mut rng = SimpleRng::::seed_from_u64(248_971); + let mut rng = SimpleRng::::from(WyHash::seed_from_u64(248_971)); let mut sampler = DynamicAliasMethodIndexedSampler::with_capacity(6); @@ -1123,7 +1123,7 @@ impl Rng for DummyRng { map(self) } - fn with_rng Q, Q>(&mut self, inner: F) -> Q { + fn with Q, Q>(&mut self, inner: F) -> Q { let samplers = DummyDistributionSamplers; inner(self, &samplers) diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs index 857121d1b..4f7fc1475 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs @@ -9,7 +9,7 @@ use core::{ use necsim_core::cogs::{ distribution::{IndexU128, IndexU64, IndexUsize, Length}, - Backup, Distribution, MathsCore, Rng, Samples, + Backup, Distribution, MathsCore, Rng, RngCore, Samples, }; use necsim_core_bond::{NonNegativeF64, PositiveF64}; @@ -60,7 +60,7 @@ impl RejectionSamplingGroup { rng, Length(NonZeroUsize::new_unchecked(self.weights.len())), ); - let height = rng.sample_u64() >> 11; + let height = rng.generator().sample_u64() >> 11; // 53rd bit of weight is always 1, so sampling chance >= 50% if height < self.weights[index] { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs index 10715637c..7a2dcc1f5 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs @@ -105,7 +105,7 @@ fn sample_single_group() { let mut tally = [0_u64; 6]; - let mut rng = SimpleRng::::seed_from_u64(24897); + let mut rng = SimpleRng::::from(WyHash::seed_from_u64(24897)); for _ in 0..N { let (maybe_group, sample) = group.sample_pop(&mut rng); @@ -405,7 +405,7 @@ fn add_remove_event_full() { fn sample_single_group_full() { const N: usize = 10_000_000; - let mut rng = SimpleRng::::seed_from_u64(471_093); + let mut rng = SimpleRng::::from(WyHash::seed_from_u64(471_093)); let mut sampler = DynamicAliasMethodStackSampler::with_capacity(6); @@ -454,7 +454,7 @@ fn sample_single_group_full() { fn sample_three_groups_full() { const N: usize = 10_000_000; - let mut rng = SimpleRng::::seed_from_u64(739_139); + let mut rng = SimpleRng::::from(WyHash::seed_from_u64(739_139)); let mut sampler = DynamicAliasMethodStackSampler::with_capacity(6); @@ -500,7 +500,7 @@ fn sample_three_groups_full() { fn sample_three_groups_full_reverse() { const N: usize = 10_000_000; - let mut rng = SimpleRng::::seed_from_u64(248_971); + let mut rng = SimpleRng::::from(WyHash::seed_from_u64(248_971)); let mut sampler = DynamicAliasMethodStackSampler::with_capacity(6); @@ -622,7 +622,7 @@ impl Rng for DummyRng { map(self) } - fn with_rng Q, Q>(&mut self, inner: F) -> Q { + fn with Q, Q>(&mut self, inner: F) -> Q { let samplers = DummyDistributionSamplers; inner(self, &samplers) diff --git a/necsim/impls/no-std/src/cogs/habitat/almost_infinite.rs b/necsim/impls/no-std/src/cogs/habitat/almost_infinite.rs index 84c668f9d..ce74e49d1 100644 --- a/necsim/impls/no-std/src/cogs/habitat/almost_infinite.rs +++ b/necsim/impls/no-std/src/cogs/habitat/almost_infinite.rs @@ -1,7 +1,7 @@ use core::{fmt, marker::PhantomData}; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, Rng, UniformlySampleableHabitat}, + cogs::{Backup, Habitat, MathsCore, Rng, RngCore, UniformlySampleableHabitat}, landscape::{IndexedLocation, LandscapeExtent, Location}, }; use necsim_core_bond::{OffByOneU32, OffByOneU64}; @@ -82,7 +82,7 @@ impl> UniformlySampleableHabitat for AlmostInfinit #[must_use] #[inline] fn sample_habitable_indexed_location(&self, rng: &mut G) -> IndexedLocation { - let index = rng.sample_u64(); + let index = rng.generator().sample_u64(); IndexedLocation::new( Location::new( diff --git a/necsim/impls/no-std/src/cogs/rng/simple.rs b/necsim/impls/no-std/src/cogs/rng/simple.rs index 9604ccbfb..68656055b 100644 --- a/necsim/impls/no-std/src/cogs/rng/simple.rs +++ b/necsim/impls/no-std/src/cogs/rng/simple.rs @@ -3,8 +3,6 @@ use core::{ num::{NonZeroU128, NonZeroU32, NonZeroU64, NonZeroUsize}, }; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - use necsim_core::cogs::{ distribution::{ Bernoulli, Exponential, IndexU128, IndexU32, IndexU64, IndexUsize, Lambda, Length, Normal, @@ -23,20 +21,18 @@ pub struct SimpleRng { marker: PhantomData, } -impl Serialize for SimpleRng { - fn serialize(&self, serializer: S) -> Result { - self.inner.serialize(serializer) +impl From for SimpleRng { + fn from(inner: R) -> Self { + Self { + inner, + marker: PhantomData::, + } } } -impl<'de, M: MathsCore, R: RngCore> Deserialize<'de> for SimpleRng { - fn deserialize>(deserializer: D) -> Result { - let inner = R::deserialize(deserializer)?; - - Ok(Self { - inner, - marker: PhantomData::, - }) +impl SimpleRng { + pub fn into(self) -> R { + self.inner } } @@ -50,23 +46,6 @@ impl Backup for SimpleRng { } } -impl RngCore for SimpleRng { - type Seed = R::Seed; - - #[must_use] - fn from_seed(seed: Self::Seed) -> Self { - Self { - inner: R::from_seed(seed), - marker: PhantomData::, - } - } - - #[must_use] - fn sample_u64(&mut self) -> u64 { - self.inner.sample_u64() - } -} - impl Rng for SimpleRng { type Generator = R; type Sampler = SimplerDistributionSamplers; @@ -84,7 +63,7 @@ impl Rng for SimpleRng { } } - fn with_rng Q, Q>(&mut self, inner: F) -> Q { + fn with Q, Q>(&mut self, inner: F) -> Q { let samplers = SimplerDistributionSamplers { _marker: PhantomData::<(M, R)>, }; diff --git a/rustcoalescence/algorithms/cuda/src/launch.rs b/rustcoalescence/algorithms/cuda/src/launch.rs index e1a7fc747..b8bf930cc 100644 --- a/rustcoalescence/algorithms/cuda/src/launch.rs +++ b/rustcoalescence/algorithms/cuda/src/launch.rs @@ -58,13 +58,13 @@ pub fn initialise_and_simulate< Error: From, >( args: &CudaArguments, - rng: CudaRng>, + rng: WyHash, scenario: O, pre_sampler: OriginPreSampler, pause_before: Option, local_partition: &mut P, lineage_store_sampler_initialiser: L, -) -> Result>>, Error> +) -> Result, Error> where O::Habitat: RustToCuda, O::DispersalSampler< @@ -120,6 +120,8 @@ where R::ReportDispersal, >, { + let rng = CudaRng::from(SimpleRng::from(rng)); + let ( habitat, dispersal_sampler, @@ -236,8 +238,7 @@ where .into_iter() .chain(passthrough.into_iter()) .collect(), - rng: simulation.rng_mut().clone(), - marker: PhantomData::, + rng: simulation.rng_mut().clone().into().into(), }), } } diff --git a/rustcoalescence/algorithms/cuda/src/lib.rs b/rustcoalescence/algorithms/cuda/src/lib.rs index df9cc279f..eada0dbab 100644 --- a/rustcoalescence/algorithms/cuda/src/lib.rs +++ b/rustcoalescence/algorithms/cuda/src/lib.rs @@ -6,7 +6,11 @@ #[macro_use] extern crate serde_derive_state; -use necsim_core::{cogs::MathsCore, lineage::Lineage, reporter::Reporter}; +use necsim_core::{ + cogs::{MathsCore, Rng}, + lineage::Lineage, + reporter::Reporter, +}; use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_impls_cuda::cogs::{maths::NvptxMathsCore, rng::CudaRng}; @@ -348,12 +352,12 @@ where fn initialise_and_simulate>( args: Self::Arguments, - rng: Self::Rng, + rng: >::Generator, scenario: O, pre_sampler: OriginPreSampler, pause_before: Option, local_partition: &mut P, - ) -> Result, Self::Error> { + ) -> Result>::Generator>, Self::Error> { launch::initialise_and_simulate( &args, rng, @@ -372,14 +376,14 @@ where #[allow(clippy::too_many_lines)] fn resume_and_simulate, L: ExactSizeIterator>( args: Self::Arguments, - rng: Self::Rng, + rng: >::Generator, scenario: O, pre_sampler: OriginPreSampler, lineages: L, resume_after: Option, pause_before: Option, local_partition: &mut P, - ) -> Result, ResumeError> { + ) -> Result>::Generator>, ResumeError> { launch::initialise_and_simulate( &args, rng, @@ -401,14 +405,14 @@ where #[allow(clippy::too_many_lines)] fn fixup_for_restart, L: ExactSizeIterator>( args: Self::Arguments, - rng: Self::Rng, + rng: >::Generator, scenario: O, pre_sampler: OriginPreSampler, lineages: L, restart_at: PositiveF64, fixup_strategy: RestartFixUpStrategy, local_partition: &mut P, - ) -> Result, ResumeError> { + ) -> Result>::Generator>, ResumeError> { launch::initialise_and_simulate( &args, rng, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs index db147badb..47e68151a 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs @@ -1,10 +1,7 @@ use std::{hint::unreachable_unchecked, marker::PhantomData}; use necsim_core::{ - cogs::{ - distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, - ActiveLineageSampler, LocallyCoherentLineageStore, MathsCore, Rng, Samples, SplittableRng, - }, + cogs::{ActiveLineageSampler, LocallyCoherentLineageStore, MathsCore, Rng, SplittableRng}, reporter::Reporter, simulation::SimulationBuilder, }; @@ -21,6 +18,7 @@ use necsim_impls_no_std::{ origin_sampler::{ decomposition::DecompositionOriginSampler, pre_sampler::OriginPreSampler, }, + rng::simple::SimpleRng, turnover_rate::uniform::UniformTurnoverRate, }, parallelisation::{self, Status}, @@ -40,15 +38,12 @@ use super::initialiser::ClassicalLineageStoreSampleInitialiser; pub fn initialise_and_simulate< 'p, M: MathsCore, - G: Rng - + Samples - + Samples - + Samples, - O: Scenario, + G: SplittableRng, + O: Scenario, TurnoverRate = UniformTurnoverRate>, R: Reporter, P: LocalPartition<'p, R>, I: Iterator, - L: ClassicalLineageStoreSampleInitialiser, + L: ClassicalLineageStoreSampleInitialiser, O, Error>, Error, >( args: GillespieArguments, @@ -58,11 +53,13 @@ pub fn initialise_and_simulate< pause_before: Option, local_partition: &mut P, lineage_store_sampler_initialiser: L, -) -> Result, Error> +) -> Result, Error> where O::LineageStore>: LocallyCoherentLineageStore, { + let rng = SimpleRng::from(rng); + match args.parallelism_mode { ParallelismMode::Monolithic => { let ( @@ -72,7 +69,7 @@ where speciation_probability, origin_sampler_auxiliary, _decomposition_auxiliary, - ) = scenario.build::>(); + ) = scenario.build::>>(); let coalescence_sampler = UnconditionalCoalescenceSampler::default(); let event_sampler = UnconditionalEventSampler::default(); @@ -125,7 +122,6 @@ where .cloned() .collect(), rng: simulation.rng_mut().clone(), - marker: PhantomData::, }), } }, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/mod.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/mod.rs index 61b3b150d..f9c63710a 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/mod.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{LocallyCoherentLineageStore, MathsCore}, + cogs::{LocallyCoherentLineageStore, MathsCore, Rng}, lineage::Lineage, reporter::Reporter, }; @@ -44,12 +44,12 @@ where #[allow(clippy::too_many_lines)] fn initialise_and_simulate>( args: Self::Arguments, - rng: Self::Rng, + rng: >::Generator, scenario: O, pre_sampler: OriginPreSampler, pause_before: Option, local_partition: &mut P, - ) -> Result, Self::Error> { + ) -> Result>::Generator>, Self::Error> { launch::initialise_and_simulate( args, rng, @@ -67,14 +67,14 @@ where /// simulation failed fn resume_and_simulate, L: ExactSizeIterator>( args: Self::Arguments, - rng: Self::Rng, + rng: >::Generator, scenario: O, pre_sampler: OriginPreSampler, lineages: L, resume_after: Option, pause_before: Option, local_partition: &mut P, - ) -> Result, ResumeError> { + ) -> Result>::Generator>, ResumeError> { launch::initialise_and_simulate( args, rng, @@ -96,14 +96,14 @@ where #[allow(clippy::too_many_lines)] fn fixup_for_restart, L: ExactSizeIterator>( args: Self::Arguments, - rng: Self::Rng, + rng: >::Generator, scenario: O, pre_sampler: OriginPreSampler, lineages: L, restart_at: PositiveF64, fixup_strategy: RestartFixUpStrategy, local_partition: &mut P, - ) -> Result, ResumeError> { + ) -> Result>::Generator>, ResumeError> { launch::initialise_and_simulate( args, rng, diff --git a/rustcoalescence/algorithms/independent/src/launch.rs b/rustcoalescence/algorithms/independent/src/launch.rs index 2d13ad2a1..4ff08b8e5 100644 --- a/rustcoalescence/algorithms/independent/src/launch.rs +++ b/rustcoalescence/algorithms/independent/src/launch.rs @@ -1,10 +1,7 @@ use std::marker::PhantomData; use necsim_core::{ - cogs::{ - distribution::{Bernoulli, IndexUsize, Poisson, UniformClosedOpenUnit}, - MathsCore, PrimeableRng, Rng, Samples, - }, + cogs::{MathsCore, PrimeableRng}, reporter::Reporter, simulation::SimulationBuilder, }; @@ -29,6 +26,7 @@ use necsim_impls_no_std::{ origin_sampler::{ decomposition::DecompositionOriginSampler, pre_sampler::OriginPreSampler, }, + rng::simple::SimpleRng, }, parallelisation::{self, Status}, }; @@ -49,16 +47,12 @@ use crate::{ pub fn initialise_and_simulate< 'p, M: MathsCore, - G: Rng - + Samples - + Samples - + Samples - + Samples, - O: Scenario, + G: PrimeableRng, + O: Scenario>, R: Reporter, P: LocalPartition<'p, R>, I: Iterator, - L: IndependentLineageStoreSampleInitialiser, + L: IndependentLineageStoreSampleInitialiser, O, Error>, Error, >( args: &IndependentArguments, @@ -68,7 +62,9 @@ pub fn initialise_and_simulate< pause_before: Option, local_partition: &mut P, lineage_store_sampler_initialiser: L, -) -> Result, Error> { +) -> Result, Error> { + let rng = SimpleRng::from(rng); + match args.parallelism_mode { ParallelismMode::Monolithic(MonolithicParallelismMode { event_slice }) | ParallelismMode::IsolatedIndividuals(IsolatedParallelismMode { event_slice, .. }) @@ -80,7 +76,7 @@ pub fn initialise_and_simulate< speciation_probability, origin_sampler_auxiliary, decomposition_auxiliary, - ) = scenario.build::>(); + ) = scenario.build::>>(); let coalescence_sampler = IndependentCoalescenceSampler::default(); let event_sampler = IndependentEventSampler::default(); @@ -163,8 +159,7 @@ pub fn initialise_and_simulate< .into_iter() .chain(passthrough.into_iter()) .collect(), - rng: simulation.rng_mut().clone(), - marker: PhantomData::, + rng: simulation.rng_mut().clone().into(), }), } }, @@ -176,7 +171,7 @@ pub fn initialise_and_simulate< speciation_probability, origin_sampler_auxiliary, _decomposition_auxiliary, - ) = scenario.build::>(); + ) = scenario.build::>>(); let coalescence_sampler = IndependentCoalescenceSampler::default(); let event_sampler = IndependentEventSampler::default(); @@ -231,7 +226,7 @@ pub fn initialise_and_simulate< speciation_probability, origin_sampler_auxiliary, decomposition_auxiliary, - ) = scenario.build::>(); + ) = scenario.build::>>(); let coalescence_sampler = IndependentCoalescenceSampler::default(); let event_sampler = IndependentEventSampler::default(); @@ -294,7 +289,7 @@ pub fn initialise_and_simulate< speciation_probability, origin_sampler_auxiliary, decomposition_auxiliary, - ) = scenario.build::>(); + ) = scenario.build::>>(); let coalescence_sampler = IndependentCoalescenceSampler::default(); let event_sampler = IndependentEventSampler::default(); diff --git a/rustcoalescence/algorithms/independent/src/lib.rs b/rustcoalescence/algorithms/independent/src/lib.rs index dff7dde25..3783060ee 100644 --- a/rustcoalescence/algorithms/independent/src/lib.rs +++ b/rustcoalescence/algorithms/independent/src/lib.rs @@ -5,7 +5,11 @@ #[macro_use] extern crate serde_derive_state; -use necsim_core::{cogs::MathsCore, lineage::Lineage, reporter::Reporter}; +use necsim_core::{ + cogs::{MathsCore, Rng}, + lineage::Lineage, + reporter::Reporter, +}; use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_impls_no_std::cogs::{ @@ -70,12 +74,12 @@ impl< fn initialise_and_simulate>( args: Self::Arguments, - rng: Self::Rng, + rng: >::Generator, scenario: O, pre_sampler: OriginPreSampler, pause_before: Option, local_partition: &mut P, - ) -> Result, Self::Error> { + ) -> Result>::Generator>, Self::Error> { launch::initialise_and_simulate( &args, rng, @@ -93,14 +97,14 @@ impl< /// simulation failed fn resume_and_simulate, L: ExactSizeIterator>( args: Self::Arguments, - rng: Self::Rng, + rng: >::Generator, scenario: O, pre_sampler: OriginPreSampler, lineages: L, resume_after: Option, pause_before: Option, local_partition: &mut P, - ) -> Result, ResumeError> { + ) -> Result>::Generator>, ResumeError> { launch::initialise_and_simulate( &args, rng, @@ -122,14 +126,14 @@ impl< #[allow(clippy::too_many_lines)] fn fixup_for_restart, L: ExactSizeIterator>( args: Self::Arguments, - rng: Self::Rng, + rng: >::Generator, scenario: O, pre_sampler: OriginPreSampler, lineages: L, restart_at: PositiveF64, fixup_strategy: RestartFixUpStrategy, local_partition: &mut P, - ) -> Result, ResumeError> { + ) -> Result>::Generator>, ResumeError> { launch::initialise_and_simulate( &args, rng, diff --git a/rustcoalescence/algorithms/src/lib.rs b/rustcoalescence/algorithms/src/lib.rs index 2c1138524..3298b4958 100644 --- a/rustcoalescence/algorithms/src/lib.rs +++ b/rustcoalescence/algorithms/src/lib.rs @@ -48,12 +48,12 @@ pub trait Algorithm< /// the algorithm failed fn initialise_and_simulate>( args: Self::Arguments, - rng: Self::Rng, + rng: >::Generator, scenario: O, pre_sampler: OriginPreSampler, pause_before: Option, local_partition: &mut P, - ) -> Result, Self::Error>; + ) -> Result>::Generator>, Self::Error>; /// # Errors /// @@ -62,14 +62,14 @@ pub trait Algorithm< #[allow(clippy::type_complexity, clippy::too_many_arguments)] fn resume_and_simulate, L: ExactSizeIterator>( args: Self::Arguments, - rng: Self::Rng, + rng: >::Generator, scenario: O, pre_sampler: OriginPreSampler, lineages: L, resume_after: Option, pause_before: Option, local_partition: &mut P, - ) -> Result, ResumeError>; + ) -> Result>::Generator>, ResumeError>; /// # Errors /// @@ -78,12 +78,12 @@ pub trait Algorithm< #[allow(clippy::type_complexity, clippy::too_many_arguments)] fn fixup_for_restart, L: ExactSizeIterator>( args: Self::Arguments, - rng: Self::Rng, + rng: >::Generator, scenario: O, pre_sampler: OriginPreSampler, lineages: L, restart_at: PositiveF64, fixup_strategy: RestartFixUpStrategy, local_partition: &mut P, - ) -> Result, ResumeError>; + ) -> Result>::Generator>, ResumeError>; } diff --git a/rustcoalescence/algorithms/src/result.rs b/rustcoalescence/algorithms/src/result.rs index cf1c7c98d..9399bc50b 100644 --- a/rustcoalescence/algorithms/src/result.rs +++ b/rustcoalescence/algorithms/src/result.rs @@ -1,14 +1,11 @@ -use std::{error::Error as StdError, fmt, marker::PhantomData}; +use std::{error::Error as StdError, fmt}; -use necsim_core::{ - cogs::{MathsCore, Rng}, - lineage::Lineage, -}; +use necsim_core::{cogs::RngCore, lineage::Lineage}; use necsim_core_bond::NonNegativeF64; use necsim_impls_no_std::cogs::active_lineage_sampler::resuming::lineage::ExceptionalLineage; -pub enum SimulationOutcome> { +pub enum SimulationOutcome { Done { time: NonNegativeF64, steps: u64, @@ -18,7 +15,6 @@ pub enum SimulationOutcome> { steps: u64, lineages: Vec, rng: G, - marker: PhantomData, }, } diff --git a/rustcoalescence/src/args/config/rng/mod.rs b/rustcoalescence/src/args/config/rng/mod.rs index 406800030..511a55826 100644 --- a/rustcoalescence/src/args/config/rng/mod.rs +++ b/rustcoalescence/src/args/config/rng/mod.rs @@ -1,9 +1,9 @@ -use std::{fmt, marker::PhantomData}; +use std::fmt; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_state::DeserializeState; -use necsim_core::cogs::{MathsCore, Rng}; +use necsim_core::cogs::RngCore; use necsim_partitioning_core::partition::Partition; mod base32; @@ -11,27 +11,25 @@ mod base32; use self::base32::Base32String; #[derive(Debug, Serialize)] -#[serde(bound = "")] #[serde(rename = "Rng")] #[allow(clippy::module_name_repetitions)] -pub enum RngConfig> { +pub enum RngConfig { Seed(u64), Sponge(Base32String), - State(Base32RngState), + State(Base32RngState), } #[allow(dead_code)] -pub struct Base32RngState> { +pub struct Base32RngState { rng: G, - marker: PhantomData, } -impl<'de, M: MathsCore, G: Rng> DeserializeState<'de, Partition> for RngConfig { +impl<'de, G: RngCore> DeserializeState<'de, Partition> for RngConfig { fn deserialize_state>( partition: &mut Partition, deserializer: D, ) -> Result { - let raw = RngRaw::::deserialize(deserializer)?; + let raw = RngRaw::::deserialize(deserializer)?; let rng = match raw { RngRaw::Entropy => { @@ -62,10 +60,7 @@ impl<'de, M: MathsCore, G: Rng> DeserializeState<'de, Partition> for RngConfi RngRaw::State(state) => Self::State(state), RngRaw::StateElseSponge(state) => { match bincode::Options::deserialize(bincode::options(), &state) { - Ok(rng) => Self::State(Base32RngState { - rng, - marker: PhantomData::, - }), + Ok(rng) => Self::State(Base32RngState { rng }), Err(_) => Self::Sponge(state), } }, @@ -75,16 +70,13 @@ impl<'de, M: MathsCore, G: Rng> DeserializeState<'de, Partition> for RngConfi } } -impl> From for Base32RngState { +impl From for Base32RngState { fn from(rng: G) -> Self { - Self { - rng, - marker: PhantomData::, - } + Self { rng } } } -impl> Base32RngState { +impl Base32RngState { #[must_use] #[allow(dead_code)] pub fn into(self) -> G { @@ -92,7 +84,7 @@ impl> Base32RngState { } } -impl> fmt::Debug for Base32RngState { +impl fmt::Debug for Base32RngState { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match ProtectedState::serialize(&self.rng) { Ok(state) => Base32String::new(&state).fmt(fmt), @@ -101,7 +93,7 @@ impl> fmt::Debug for Base32RngState { } } -impl> Serialize for Base32RngState { +impl Serialize for Base32RngState { fn serialize(&self, serializer: S) -> Result { let state = ProtectedState::serialize(&self.rng).map_err(serde::ser::Error::custom)?; @@ -109,16 +101,13 @@ impl> Serialize for Base32RngState { } } -impl<'de, M: MathsCore, G: Rng> Deserialize<'de> for Base32RngState { +impl<'de, G: RngCore> Deserialize<'de> for Base32RngState { fn deserialize>(deserializer: D) -> Result { let state = Base32String::deserialize(deserializer)?; if let Some(state) = ProtectedState::from_bytes(&state) { if let Ok(rng) = ProtectedState::deserialize(state) { - return Ok(Self { - rng, - marker: PhantomData::, - }); + return Ok(Self { rng }); } } @@ -129,14 +118,14 @@ impl<'de, M: MathsCore, G: Rng> Deserialize<'de> for Base32RngState { } #[derive(Debug, Deserialize)] -#[serde(bound = "")] #[serde(rename = "Rng")] -enum RngRaw> { +#[serde(bound = "")] +enum RngRaw { Entropy, Seed(u64), #[serde(deserialize_with = "deserialize_rng_sponge")] Sponge(Base32String), - State(Base32RngState), + State(Base32RngState), #[serde(deserialize_with = "deserialize_rng_state_else_sponge")] StateElseSponge(Base32String), } diff --git a/rustcoalescence/src/cli/simulate/dispatch/valid/rng.rs b/rustcoalescence/src/cli/simulate/dispatch/valid/rng.rs index 542611cb9..ebfa386ab 100644 --- a/rustcoalescence/src/cli/simulate/dispatch/valid/rng.rs +++ b/rustcoalescence/src/cli/simulate/dispatch/valid/rng.rs @@ -3,7 +3,7 @@ use tiny_keccak::{Hasher, Keccak}; use rustcoalescence_algorithms::{result::SimulationOutcome as AlgorithmOutcome, Algorithm}; use necsim_core::{ - cogs::{MathsCore, RngCore, SeedableRng}, + cogs::{MathsCore, Rng, RngCore, SeedableRng}, reporter::Reporter, }; use necsim_core_bond::NonNegativeF64; @@ -46,14 +46,14 @@ where Result, A::Error>: anyhow::Context, A::Error>, { - let rng: A::Rng = match parse::rng::parse_and_normalise( + let rng: >::Generator = match parse::rng::parse_and_normalise( ron_args, normalised_args, &mut A::get_logical_partition(&algorithm_args, &local_partition), )? { RngConfig::Seed(seed) => SeedableRng::seed_from_u64(seed), RngConfig::Sponge(bytes) => { - let mut seed = ::Seed::default(); + let mut seed = <>::Generator as RngCore>::Seed::default(); let mut sponge = Keccak::v256(); sponge.update(&bytes); @@ -81,7 +81,6 @@ where steps, lineages, rng: paused_rng, - .. } => { normalised_args.rng(&RngConfig::State(Base32RngState::from(paused_rng))); diff --git a/rustcoalescence/src/cli/simulate/parse/rng.rs b/rustcoalescence/src/cli/simulate/parse/rng.rs index b059a2223..399fda49c 100644 --- a/rustcoalescence/src/cli/simulate/parse/rng.rs +++ b/rustcoalescence/src/cli/simulate/parse/rng.rs @@ -1,4 +1,4 @@ -use necsim_core::cogs::{MathsCore, Rng}; +use necsim_core::cogs::RngCore; use necsim_partitioning_core::partition::Partition; use crate::args::{config::rng::RngConfig, utils::parse::try_parse_state}; @@ -6,11 +6,11 @@ use crate::args::{config::rng::RngConfig, utils::parse::try_parse_state}; use super::super::BufferingSimulateArgsBuilder; #[allow(dead_code)] -pub(in super::super) fn parse_and_normalise>( +pub(in super::super) fn parse_and_normalise( ron_args: &str, normalised_args: &mut BufferingSimulateArgsBuilder, partition: &mut Partition, -) -> anyhow::Result> { +) -> anyhow::Result> { let SimulateArgsRngOnly { rng } = try_parse_state("simulate", ron_args, partition)?; normalised_args.rng(&rng); @@ -19,11 +19,10 @@ pub(in super::super) fn parse_and_normalise>( } #[derive(DeserializeState)] -#[serde(bound = "")] #[serde(rename = "Simulate")] #[serde(deserialize_state = "Partition")] -struct SimulateArgsRngOnly> { +struct SimulateArgsRngOnly { #[serde(alias = "randomness")] #[serde(deserialize_state)] - rng: RngConfig, + rng: RngConfig, } From 5892205dcab30a32e8e5b7f255bbbddbca8206c6 Mon Sep 17 00:00:00 2001 From: Momo Langenstein Date: Fri, 20 May 2022 06:32:52 +0000 Subject: [PATCH 12/42] Finished refactoring of Rng not a subtrait of RngCore --- .../gillespie/src/event_skipping/launch.rs | 30 +++++++++---------- .../gillespie/src/event_skipping/mod.rs | 14 ++++----- .../src/gillespie/classical/launch.rs | 4 +-- .../src/gillespie/turnover/launch.rs | 26 +++++++--------- .../gillespie/src/gillespie/turnover/mod.rs | 14 ++++----- .../src/cli/simulate/dispatch/valid/info.rs | 10 +++---- .../src/cli/simulate/dispatch/valid/launch.rs | 9 ++++-- .../src/cli/simulate/dispatch/valid/rng.rs | 4 +-- 8 files changed, 55 insertions(+), 56 deletions(-) diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs index 22c2e794b..ea9803bc8 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs @@ -2,8 +2,7 @@ use std::{hint::unreachable_unchecked, marker::PhantomData}; use necsim_core::{ cogs::{ - distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, - ActiveLineageSampler, GloballyCoherentLineageStore, MathsCore, Rng, Samples, + ActiveLineageSampler, GloballyCoherentLineageStore, MathsCore, Rng, SeparableDispersalSampler, SplittableRng, }, reporter::Reporter, @@ -21,6 +20,7 @@ use necsim_impls_no_std::{ origin_sampler::{ decomposition::DecompositionOriginSampler, pre_sampler::OriginPreSampler, }, + rng::simple::SimpleRng, }, parallelisation::{self, Status}, }; @@ -38,15 +38,12 @@ use crate::arguments::{ pub fn initialise_and_simulate< 'p, M: MathsCore, - G: Rng - + Samples - + Samples - + Samples, - O: Scenario, + G: SplittableRng, + O: Scenario>, R: Reporter, P: LocalPartition<'p, R>, I: Iterator, - L: EventSkippingLineageStoreSampleInitialiser, + L: EventSkippingLineageStoreSampleInitialiser, O, Error>, Error, >( args: GillespieArguments, @@ -56,13 +53,15 @@ pub fn initialise_and_simulate< pause_before: Option, local_partition: &mut P, lineage_store_sampler_initialiser: L, -) -> Result, Error> +) -> Result, Error> where O::LineageStore>: GloballyCoherentLineageStore, - O::DispersalSampler>: - SeparableDispersalSampler, + O::DispersalSampler>>: + SeparableDispersalSampler>, { + let rng = SimpleRng::from(rng); + match args.parallelism_mode { ParallelismMode::Monolithic => { let ( @@ -72,7 +71,8 @@ where speciation_probability, origin_sampler_auxiliary, _decomposition_auxiliary, - ) = scenario.build::>(); + ) = scenario + .build::>>(); let coalescence_sampler = ConditionalCoalescenceSampler::default(); let (lineage_store, dispersal_sampler, event_sampler, active_lineage_sampler): ( @@ -127,8 +127,7 @@ where ) .cloned() .collect(), - rng: simulation.rng_mut().clone(), - marker: PhantomData::, + rng: simulation.rng_mut().clone().into(), }), } }, @@ -144,7 +143,8 @@ where speciation_probability, origin_sampler_auxiliary, decomposition_auxiliary, - ) = scenario.build::>(); + ) = scenario + .build::>>(); let coalescence_sampler = ConditionalCoalescenceSampler::default(); let decomposition = O::decompose( diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/mod.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/mod.rs index 457b87692..2c473fa3a 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/mod.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{GloballyCoherentLineageStore, MathsCore, SeparableDispersalSampler}, + cogs::{GloballyCoherentLineageStore, MathsCore, Rng, SeparableDispersalSampler}, lineage::Lineage, reporter::Reporter, }; @@ -64,12 +64,12 @@ where fn initialise_and_simulate>( args: Self::Arguments, - rng: Self::Rng, + rng: >::Generator, scenario: O, pre_sampler: OriginPreSampler, pause_before: Option, local_partition: &mut P, - ) -> Result, Self::Error> { + ) -> Result>::Generator>, Self::Error> { launch::initialise_and_simulate( args, rng, @@ -87,14 +87,14 @@ where /// simulation failed fn resume_and_simulate, L: ExactSizeIterator>( args: Self::Arguments, - rng: Self::Rng, + rng: >::Generator, scenario: O, pre_sampler: OriginPreSampler, lineages: L, resume_after: Option, pause_before: Option, local_partition: &mut P, - ) -> Result, ResumeError> { + ) -> Result>::Generator>, ResumeError> { launch::initialise_and_simulate( args, rng, @@ -115,14 +115,14 @@ where /// simulation (incl. running the algorithm) failed fn fixup_for_restart, L: ExactSizeIterator>( args: Self::Arguments, - rng: Self::Rng, + rng: >::Generator, scenario: O, pre_sampler: OriginPreSampler, lineages: L, restart_at: PositiveF64, fixup_strategy: RestartFixUpStrategy, local_partition: &mut P, - ) -> Result, ResumeError> { + ) -> Result>::Generator>, ResumeError> { launch::initialise_and_simulate( args, rng, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs index 47e68151a..8156b0203 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs @@ -121,7 +121,7 @@ where ) .cloned() .collect(), - rng: simulation.rng_mut().clone(), + rng: simulation.rng_mut().clone().into(), }), } }, @@ -137,7 +137,7 @@ where speciation_probability, origin_sampler_auxiliary, decomposition_auxiliary, - ) = scenario.build::>(); + ) = scenario.build::>>(); let coalescence_sampler = UnconditionalCoalescenceSampler::default(); let event_sampler = UnconditionalEventSampler::default(); diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs index 86d90adb4..ffd8fefa8 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs @@ -1,10 +1,7 @@ use std::{hint::unreachable_unchecked, marker::PhantomData}; use necsim_core::{ - cogs::{ - distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, - ActiveLineageSampler, LocallyCoherentLineageStore, MathsCore, Rng, Samples, SplittableRng, - }, + cogs::{ActiveLineageSampler, LocallyCoherentLineageStore, MathsCore, Rng, SplittableRng}, reporter::Reporter, simulation::SimulationBuilder, }; @@ -21,6 +18,7 @@ use necsim_impls_no_std::{ origin_sampler::{ decomposition::DecompositionOriginSampler, pre_sampler::OriginPreSampler, }, + rng::simple::SimpleRng, }, parallelisation::{self, Status}, }; @@ -39,15 +37,12 @@ use super::initialiser::GillespieLineageStoreSampleInitialiser; pub fn initialise_and_simulate< 'p, M: MathsCore, - G: Rng - + Samples - + Samples - + Samples, - O: Scenario, + G: SplittableRng, + O: Scenario>, R: Reporter, P: LocalPartition<'p, R>, I: Iterator, - L: GillespieLineageStoreSampleInitialiser, + L: GillespieLineageStoreSampleInitialiser, O, Error>, Error, >( args: GillespieArguments, @@ -57,11 +52,13 @@ pub fn initialise_and_simulate< pause_before: Option, local_partition: &mut P, lineage_store_sampler_initialiser: L, -) -> Result, Error> +) -> Result, Error> where O::LineageStore>: LocallyCoherentLineageStore, { + let rng = SimpleRng::from(rng); + match args.parallelism_mode { ParallelismMode::Monolithic => { let ( @@ -71,7 +68,7 @@ where speciation_probability, origin_sampler_auxiliary, _decomposition_auxiliary, - ) = scenario.build::>(); + ) = scenario.build::>>(); let coalescence_sampler = UnconditionalCoalescenceSampler::default(); let event_sampler = UnconditionalEventSampler::default(); @@ -124,8 +121,7 @@ where ) .cloned() .collect(), - rng: simulation.rng_mut().clone(), - marker: PhantomData::, + rng: simulation.rng_mut().clone().into(), }), } }, @@ -141,7 +137,7 @@ where speciation_probability, origin_sampler_auxiliary, decomposition_auxiliary, - ) = scenario.build::>(); + ) = scenario.build::>>(); let coalescence_sampler = UnconditionalCoalescenceSampler::default(); let event_sampler = UnconditionalEventSampler::default(); diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/mod.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/mod.rs index 728f34acf..e78723512 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/mod.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{LocallyCoherentLineageStore, MathsCore}, + cogs::{LocallyCoherentLineageStore, MathsCore, Rng}, lineage::Lineage, reporter::Reporter, }; @@ -52,12 +52,12 @@ where #[allow(clippy::shadow_unrelated, clippy::too_many_lines)] default fn initialise_and_simulate>( args: Self::Arguments, - rng: Self::Rng, + rng: >::Generator, scenario: O, pre_sampler: OriginPreSampler, pause_before: Option, local_partition: &mut P, - ) -> Result, Self::Error> { + ) -> Result>::Generator>, Self::Error> { launch::initialise_and_simulate( args, rng, @@ -79,14 +79,14 @@ where L: ExactSizeIterator, >( args: Self::Arguments, - rng: Self::Rng, + rng: >::Generator, scenario: O, pre_sampler: OriginPreSampler, lineages: L, resume_after: Option, pause_before: Option, local_partition: &mut P, - ) -> Result, ResumeError> { + ) -> Result>::Generator>, ResumeError> { launch::initialise_and_simulate( args, rng, @@ -108,14 +108,14 @@ where #[allow(clippy::too_many_lines)] default fn fixup_for_restart, L: ExactSizeIterator>( args: Self::Arguments, - rng: Self::Rng, + rng: >::Generator, scenario: O, pre_sampler: OriginPreSampler, lineages: L, restart_at: PositiveF64, fixup_strategy: RestartFixUpStrategy, local_partition: &mut P, - ) -> Result, ResumeError> { + ) -> Result>::Generator>, ResumeError> { launch::initialise_and_simulate( args, rng, diff --git a/rustcoalescence/src/cli/simulate/dispatch/valid/info.rs b/rustcoalescence/src/cli/simulate/dispatch/valid/info.rs index aac4223c9..00fcc3f73 100644 --- a/rustcoalescence/src/cli/simulate/dispatch/valid/info.rs +++ b/rustcoalescence/src/cli/simulate/dispatch/valid/info.rs @@ -5,7 +5,7 @@ use anyhow::{Context, Result}; use rustcoalescence_algorithms::{result::SimulationOutcome, Algorithm}; use necsim_core::{ - cogs::MathsCore, + cogs::{MathsCore, Rng}, reporter::{boolean::Boolean, Reporter}, }; use necsim_core_bond::NonNegativeF64; @@ -31,17 +31,17 @@ pub(super) fn dispatch< P: LocalPartition<'p, R>, >( algorithm_args: A::Arguments, - rng: A::Rng, + rng: >::Generator, scenario: O, sample: Sample, pause_before: Option, mut local_partition: P, normalised_args: &BufferingSimulateArgsBuilder, -) -> anyhow::Result> +) -> anyhow::Result>::Generator>> where - Result, A::Error>: - anyhow::Context, A::Error>, + Result>::Generator>, A::Error>: + anyhow::Context>::Generator>, A::Error>, { let config_str = normalised_args .build() diff --git a/rustcoalescence/src/cli/simulate/dispatch/valid/launch.rs b/rustcoalescence/src/cli/simulate/dispatch/valid/launch.rs index e070202d6..1512b8ef0 100644 --- a/rustcoalescence/src/cli/simulate/dispatch/valid/launch.rs +++ b/rustcoalescence/src/cli/simulate/dispatch/valid/launch.rs @@ -2,7 +2,10 @@ use anyhow::Context; use rustcoalescence_algorithms::{result::SimulationOutcome, Algorithm}; -use necsim_core::{cogs::MathsCore, reporter::Reporter}; +use necsim_core::{ + cogs::{MathsCore, Rng}, + reporter::Reporter, +}; use necsim_core_bond::{NonNegativeF64, PositiveF64}; use necsim_impls_no_std::cogs::origin_sampler::pre_sampler::OriginPreSampler; use necsim_partitioning_core::LocalPartition; @@ -20,12 +23,12 @@ pub(super) fn simulate< P: LocalPartition<'p, R>, >( algorithm_args: A::Arguments, - rng: A::Rng, + rng: >::Generator, scenario: O, sample: Sample, pause_before: Option, local_partition: &mut P, -) -> anyhow::Result> { +) -> anyhow::Result>::Generator>> { let lineages = match sample.origin { SampleOrigin::Habitat => { return A::initialise_and_simulate( diff --git a/rustcoalescence/src/cli/simulate/dispatch/valid/rng.rs b/rustcoalescence/src/cli/simulate/dispatch/valid/rng.rs index ebfa386ab..6433fc54c 100644 --- a/rustcoalescence/src/cli/simulate/dispatch/valid/rng.rs +++ b/rustcoalescence/src/cli/simulate/dispatch/valid/rng.rs @@ -43,8 +43,8 @@ pub(super) fn dispatch< normalised_args: &mut BufferingSimulateArgsBuilder, ) -> anyhow::Result where - Result, A::Error>: - anyhow::Context, A::Error>, + Result>::Generator>, A::Error>: + anyhow::Context>::Generator>, A::Error>, { let rng: >::Generator = match parse::rng::parse_and_normalise( ron_args, From d87a919d719c668fd198f7c5f885a1ef698cdb6d Mon Sep 17 00:00:00 2001 From: Momo Langenstein Date: Fri, 20 May 2022 09:33:53 +0000 Subject: [PATCH 13/42] Added RawDistribution for better DistributionSampler impl self-documentation --- necsim/core/src/cogs/distribution.rs | 41 ++++++++++---- necsim/core/src/cogs/rng.rs | 2 +- .../alias/sampler/indexed/tests.rs | 6 +- .../alias/sampler/stack/tests.rs | 6 +- necsim/impls/no-std/src/cogs/rng/simple.rs | 56 ++++++++++--------- 5 files changed, 67 insertions(+), 44 deletions(-) diff --git a/necsim/core/src/cogs/distribution.rs b/necsim/core/src/cogs/distribution.rs index 525f1689d..9bbd95f68 100644 --- a/necsim/core/src/cogs/distribution.rs +++ b/necsim/core/src/cogs/distribution.rs @@ -36,22 +36,43 @@ impl Distribution for D { } #[allow(clippy::module_name_repetitions)] -pub trait DistributionSampler { +pub trait RawDistribution: DistributionCore { + fn sample_raw_with>( + rng: &mut R, + samplers: &S, + params: Self::Parameters, + ) -> Self::Sample; + + fn sample_raw>( + rng: &mut R, + samplers: &S, + ) -> Self::Sample + where + Self: DistributionCore, + { + Self::sample_raw_with(rng, samplers, ()) + } +} + +impl RawDistribution for D { + fn sample_raw_with>( + rng: &mut R, + samplers: &S, + params: Self::Parameters, + ) -> Self::Sample { + samplers.sample_distribution(rng, samplers, params) + } +} + +#[allow(clippy::module_name_repetitions)] +pub trait DistributionSampler { type ConcreteSampler: DistributionSampler; #[must_use] fn concrete(&self) -> &Self::ConcreteSampler; #[must_use] - fn sample_with(&self, rng: &mut R, samplers: &S, params: D::Parameters) -> D::Sample; - - #[must_use] - fn sample(&self, rng: &mut R, samplers: &S) -> D::Sample - where - D: DistributionCore, - { - self.sample_with(rng, samplers, ()) - } + fn sample_distribution(&self, rng: &mut R, samplers: &S, params: D::Parameters) -> D::Sample; } pub enum UniformClosedOpenUnit {} diff --git a/necsim/core/src/cogs/rng.rs b/necsim/core/src/cogs/rng.rs index 956cae27b..1a728becc 100644 --- a/necsim/core/src/cogs/rng.rs +++ b/necsim/core/src/cogs/rng.rs @@ -121,6 +121,6 @@ where { #[must_use] fn sample_with(&mut self, params: D::Parameters) -> D::Sample { - self.with(|rng, samplers| samplers.sample_with(rng, samplers, params)) + self.with(|rng, samplers| samplers.sample_distribution(rng, samplers, params)) } } diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs index ae4187417..098ca2861 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs @@ -1141,7 +1141,7 @@ impl DistributionSampler DistributionSampler ClosedOpenUnitF64 { + fn sample_distribution(&self, rng: &mut R, _samplers: &S, _params: ()) -> ClosedOpenUnitF64 { // http://prng.di.unimi.it -> Generating uniform doubles in the unit interval #[allow(clippy::cast_precision_loss)] let u01 = ((rng.sample_u64() >> 11) as f64) * f64::from_bits(0x3CA0_0000_0000_0000_u64); // 0x1.0p-53 @@ -104,7 +105,7 @@ impl DistributionSampler OpenClosedUnitF64 { + fn sample_distribution(&self, rng: &mut R, _samplers: &S, _params: ()) -> OpenClosedUnitF64 { // http://prng.di.unimi.it -> Generating uniform doubles in the unit interval #[allow(clippy::cast_precision_loss)] let u01 = @@ -123,10 +124,15 @@ impl) -> usize { + fn sample_distribution( + &self, + rng: &mut R, + samplers: &S, + params: Length, + ) -> usize { let length = params.0; - let u01: ClosedOpenUnitF64 = samplers.sample(rng, samplers); + let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); #[allow( clippy::cast_precision_loss, @@ -149,10 +155,10 @@ impl) -> u32 { + fn sample_distribution(&self, rng: &mut R, samplers: &S, params: Length) -> u32 { let length = params.0; - let u01: ClosedOpenUnitF64 = samplers.sample(rng, samplers); + let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] let index = M::floor(u01.get() * f64::from(length.get())) as u32; @@ -171,10 +177,10 @@ impl) -> u64 { + fn sample_distribution(&self, rng: &mut R, samplers: &S, params: Length) -> u64 { let length = params.0; - let u01: ClosedOpenUnitF64 = samplers.sample(rng, samplers); + let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); #[allow( clippy::cast_precision_loss, @@ -197,10 +203,10 @@ impl) -> u128 { + fn sample_distribution(&self, rng: &mut R, samplers: &S, params: Length) -> u128 { let length = params.0; - let u01: ClosedOpenUnitF64 = samplers.sample(rng, samplers); + let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); #[allow( clippy::cast_precision_loss, @@ -223,10 +229,10 @@ impl NonNegativeF64 { + fn sample_distribution(&self, rng: &mut R, samplers: &S, params: Lambda) -> NonNegativeF64 { let lambda = params.0; - let u01: OpenClosedUnitF64 = samplers.sample(rng, samplers); + let u01 = UniformOpenClosedUnit::sample_raw(rng, samplers); // Inverse transform sample: X = -ln(U(0,1]) / lambda -u01.ln::() / lambda @@ -246,15 +252,14 @@ impl< self } - fn sample_with(&self, rng: &mut R, samplers: &S, params: Lambda) -> u64 { + fn sample_distribution(&self, rng: &mut R, samplers: &S, params: Lambda) -> u64 { let lambda = params.0; let no_event_probability = M::exp(-lambda.get()); if no_event_probability <= 0.0_f64 { // Fallback in case no_event_probability_per_step underflows #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] - let normal_as_poisson = DistributionSampler::::sample_with( - samplers, + let normal_as_poisson = Normal2D::sample_raw_with( rng, samplers, Normal { @@ -273,8 +278,7 @@ impl< let mut prod = no_event_probability; let mut acc = no_event_probability; - let u = - DistributionSampler::::sample(samplers, rng, samplers); + let u = UniformClosedOpenUnit::sample_raw(rng, samplers); #[allow(clippy::cast_precision_loss)] while u > acc && prod > 0.0_f64 { @@ -296,10 +300,10 @@ impl bool { + fn sample_distribution(&self, rng: &mut R, samplers: &S, params: ClosedUnitF64) -> bool { let probability = params; - let u01: ClosedOpenUnitF64 = samplers.sample(rng, samplers); + let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); // if probability == 1, then U[0, 1) always < 1.0 // if probability == 0, then U[0, 1) never < 0.0 @@ -320,12 +324,10 @@ impl< self } - fn sample_with(&self, rng: &mut R, samplers: &S, _params: ()) -> (f64, f64) { + fn sample_distribution(&self, rng: &mut R, samplers: &S, _params: ()) -> (f64, f64) { // Basic Box-Muller transform - let u0 = - DistributionSampler::::sample(samplers, rng, samplers); - let u1 = - DistributionSampler::::sample(samplers, rng, samplers); + let u0 = UniformOpenClosedUnit::sample_raw(rng, samplers); + let u1 = UniformClosedOpenUnit::sample_raw(rng, samplers); let r = M::sqrt(-2.0_f64 * M::ln(u0.get())); let theta = -core::f64::consts::TAU * u1.get(); @@ -343,8 +345,8 @@ impl self } - fn sample_with(&self, rng: &mut R, samplers: &S, params: Normal) -> (f64, f64) { - let (z0, z1) = samplers.sample(rng, samplers); + fn sample_distribution(&self, rng: &mut R, samplers: &S, params: Normal) -> (f64, f64) { + let (z0, z1) = StandardNormal2D::sample_raw(rng, samplers); ( z0 * params.sigma.get() + params.mu, From 855d02e93d1888f5673949b023d821bf2a8a38f4 Mon Sep 17 00:00:00 2001 From: Momo Langenstein Date: Sat, 21 May 2022 08:46:49 +0000 Subject: [PATCH 14/42] Refactored Rng+RngCore without Clone --- .../core/src/cogs/active_lineage_sampler.rs | 6 +- necsim/core/src/cogs/coalescence_sampler.rs | 2 +- necsim/core/src/cogs/dispersal_sampler.rs | 4 +- necsim/core/src/cogs/emigration_exit.rs | 4 +- necsim/core/src/cogs/event_sampler.rs | 6 +- necsim/core/src/cogs/habitat.rs | 4 +- necsim/core/src/cogs/immigration_entry.rs | 4 +- necsim/core/src/cogs/lineage_reference.rs | 4 +- necsim/core/src/cogs/lineage_store.rs | 6 +- necsim/core/src/cogs/rng.rs | 6 +- .../core/src/cogs/speciation_probability.rs | 6 +- necsim/core/src/cogs/turnover_rate.rs | 6 +- necsim/core/src/simulation/builder.rs | 33 +++++++ necsim/impls/cuda/src/cogs/rng.rs | 23 ++--- necsim/impls/cuda/src/lib.rs | 2 +- .../alias/sampler/indexed/tests.rs | 2 +- .../alias/sampler/stack/tests.rs | 2 +- .../no-std/src/cogs/origin_sampler/mod.rs | 6 +- necsim/impls/no-std/src/cogs/rng/rand.rs | 6 +- necsim/impls/no-std/src/cogs/rng/seahash.rs | 9 +- necsim/impls/no-std/src/cogs/rng/simple.rs | 4 +- necsim/impls/no-std/src/cogs/rng/wyhash.rs | 7 +- necsim/impls/no-std/src/decomposition/mod.rs | 2 +- necsim/impls/std/src/cogs/rng/pcg.rs | 94 ++++++++++--------- rustcoalescence/algorithms/cuda/src/launch.rs | 2 +- .../gillespie/src/event_skipping/launch.rs | 2 +- .../src/gillespie/classical/launch.rs | 2 +- .../src/gillespie/turnover/launch.rs | 2 +- .../algorithms/independent/src/launch.rs | 2 +- rustcoalescence/algorithms/src/lib.rs | 2 +- 30 files changed, 148 insertions(+), 112 deletions(-) diff --git a/necsim/core/src/cogs/active_lineage_sampler.rs b/necsim/core/src/cogs/active_lineage_sampler.rs index bb8b2cc76..218c0e3de 100644 --- a/necsim/core/src/cogs/active_lineage_sampler.rs +++ b/necsim/core/src/cogs/active_lineage_sampler.rs @@ -3,8 +3,8 @@ use core::ops::ControlFlow; use necsim_core_bond::{NonNegativeF64, PositiveF64}; use super::{ - CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, Habitat, ImmigrationEntry, - LineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, + Backup, CoalescenceSampler, DispersalSampler, EmigrationExit, EventSampler, Habitat, + ImmigrationEntry, LineageStore, MathsCore, Rng, SpeciationProbability, TurnoverRate, }; use crate::{lineage::Lineage, simulation::partial::active_lineage_sampler::PartialSimulation}; @@ -24,7 +24,7 @@ pub trait ActiveLineageSampler< N: SpeciationProbability, E: EventSampler, I: ImmigrationEntry, ->: crate::cogs::Backup + core::fmt::Debug +>: Backup + core::fmt::Debug { type LineageIterator<'a>: Iterator where diff --git a/necsim/core/src/cogs/coalescence_sampler.rs b/necsim/core/src/cogs/coalescence_sampler.rs index 2f2eed5b3..eae990435 100644 --- a/necsim/core/src/cogs/coalescence_sampler.rs +++ b/necsim/core/src/cogs/coalescence_sampler.rs @@ -16,7 +16,7 @@ use crate::{ #[allow(clippy::inline_always, clippy::inline_fn_without_body)] #[contract_trait] pub trait CoalescenceSampler, S: LineageStore>: - crate::cogs::Backup + core::fmt::Debug + Backup + core::fmt::Debug { #[must_use] #[debug_requires(habitat.get_habitat_at_location(&location) > 0, "location is habitable")] diff --git a/necsim/core/src/cogs/dispersal_sampler.rs b/necsim/core/src/cogs/dispersal_sampler.rs index 5d6a817e7..709c80c23 100644 --- a/necsim/core/src/cogs/dispersal_sampler.rs +++ b/necsim/core/src/cogs/dispersal_sampler.rs @@ -1,7 +1,7 @@ use necsim_core_bond::ClosedUnitF64; use crate::{ - cogs::{MathsCore, Rng}, + cogs::{Backup, MathsCore, Rng}, landscape::Location, }; @@ -12,7 +12,7 @@ use super::Habitat; #[allow(clippy::module_name_repetitions)] #[contract_trait] pub trait DispersalSampler, G: Rng>: - crate::cogs::Backup + core::fmt::Debug + Backup + core::fmt::Debug { #[must_use] #[debug_requires(habitat.is_location_habitable(location), "location is habitable")] diff --git a/necsim/core/src/cogs/emigration_exit.rs b/necsim/core/src/cogs/emigration_exit.rs index 3812eee63..be1b71117 100644 --- a/necsim/core/src/cogs/emigration_exit.rs +++ b/necsim/core/src/cogs/emigration_exit.rs @@ -1,7 +1,7 @@ use necsim_core_bond::{NonNegativeF64, PositiveF64}; use crate::{ - cogs::{Habitat, LineageStore, MathsCore, Rng}, + cogs::{Backup, Habitat, LineageStore, MathsCore, Rng}, landscape::{IndexedLocation, Location}, lineage::GlobalLineageReference, simulation::partial::emigration_exit::PartialSimulation, @@ -15,7 +15,7 @@ use crate::{ #[allow(clippy::no_effect_underscore_binding)] #[contract_trait] pub trait EmigrationExit, G: Rng, S: LineageStore>: - crate::cogs::Backup + core::fmt::Debug + Backup + core::fmt::Debug { #[must_use] #[debug_ensures(match &ret { diff --git a/necsim/core/src/cogs/event_sampler.rs b/necsim/core/src/cogs/event_sampler.rs index 7aecda59f..1ab2caac8 100644 --- a/necsim/core/src/cogs/event_sampler.rs +++ b/necsim/core/src/cogs/event_sampler.rs @@ -1,8 +1,8 @@ use necsim_core_bond::PositiveF64; use super::{ - CoalescenceSampler, DispersalSampler, EmigrationExit, Habitat, LineageStore, MathsCore, Rng, - SpeciationProbability, TurnoverRate, + Backup, CoalescenceSampler, DispersalSampler, EmigrationExit, Habitat, LineageStore, MathsCore, + Rng, SpeciationProbability, TurnoverRate, }; use crate::{ event::{DispersalEvent, SpeciationEvent}, @@ -28,7 +28,7 @@ pub trait EventSampler< C: CoalescenceSampler, T: TurnoverRate, N: SpeciationProbability, ->: crate::cogs::Backup + core::fmt::Debug +>: Backup + core::fmt::Debug { #[must_use] fn sample_event_for_lineage_at_event_time_or_emigrate< diff --git a/necsim/core/src/cogs/habitat.rs b/necsim/core/src/cogs/habitat.rs index 1442637ad..f9093db76 100644 --- a/necsim/core/src/cogs/habitat.rs +++ b/necsim/core/src/cogs/habitat.rs @@ -2,7 +2,7 @@ use necsim_core_bond::OffByOneU64; use crate::landscape::{IndexedLocation, LandscapeExtent, Location}; -use super::{MathsCore, Rng}; +use super::{Backup, MathsCore, Rng}; #[allow( clippy::inline_always, @@ -10,7 +10,7 @@ use super::{MathsCore, Rng}; clippy::no_effect_underscore_binding )] #[contract_trait] -pub trait Habitat: crate::cogs::Backup + core::fmt::Debug + Sized { +pub trait Habitat: Backup + core::fmt::Debug { type LocationIterator<'a>: Iterator + 'a where Self: 'a; diff --git a/necsim/core/src/cogs/immigration_entry.rs b/necsim/core/src/cogs/immigration_entry.rs index 03d4d8fbe..c900a1dcd 100644 --- a/necsim/core/src/cogs/immigration_entry.rs +++ b/necsim/core/src/cogs/immigration_entry.rs @@ -1,10 +1,10 @@ use crate::lineage::MigratingLineage; -use super::MathsCore; +use super::{Backup, MathsCore}; #[allow(clippy::inline_always, clippy::inline_fn_without_body)] #[contract_trait] -pub trait ImmigrationEntry: crate::cogs::Backup + core::fmt::Debug { +pub trait ImmigrationEntry: Backup + core::fmt::Debug { #[must_use] fn next_optional_immigration(&mut self) -> Option; diff --git a/necsim/core/src/cogs/lineage_reference.rs b/necsim/core/src/cogs/lineage_reference.rs index 162dfe93c..eeea41e1b 100644 --- a/necsim/core/src/cogs/lineage_reference.rs +++ b/necsim/core/src/cogs/lineage_reference.rs @@ -1,9 +1,9 @@ use core::hash::Hash; -use super::{Habitat, MathsCore}; +use super::{Backup, Habitat, MathsCore}; #[allow(clippy::module_name_repetitions)] pub trait LineageReference>: - crate::cogs::Backup + PartialEq + Eq + Hash + core::fmt::Debug + Backup + PartialEq + Eq + Hash + core::fmt::Debug { } diff --git a/necsim/core/src/cogs/lineage_store.rs b/necsim/core/src/cogs/lineage_store.rs index afc0d319d..70b49cdb7 100644 --- a/necsim/core/src/cogs/lineage_store.rs +++ b/necsim/core/src/cogs/lineage_store.rs @@ -1,6 +1,6 @@ use core::ops::Index; -use super::{Habitat, LineageReference, MathsCore}; +use super::{Backup, Habitat, LineageReference, MathsCore}; use crate::{ landscape::{IndexedLocation, Location}, lineage::{GlobalLineageReference, Lineage}, @@ -8,9 +8,7 @@ use crate::{ #[allow(clippy::inline_always, clippy::inline_fn_without_body)] #[contract_trait] -pub trait LineageStore>: - crate::cogs::Backup + Sized + core::fmt::Debug -{ +pub trait LineageStore>: Backup + Sized + core::fmt::Debug { type LocalLineageReference: LineageReference; #[must_use] diff --git a/necsim/core/src/cogs/rng.rs b/necsim/core/src/cogs/rng.rs index 1a728becc..008718dc3 100644 --- a/necsim/core/src/cogs/rng.rs +++ b/necsim/core/src/cogs/rng.rs @@ -7,7 +7,7 @@ use crate::{ landscape::IndexedLocation, }; -pub trait Rng: Backup + Clone + core::fmt::Debug { +pub trait Rng: Backup + core::fmt::Debug { type Generator: RngCore; type Sampler; @@ -21,9 +21,7 @@ pub trait Rng: Backup + Clone + core::fmt::Debug { } #[allow(clippy::module_name_repetitions)] -pub trait RngCore: - crate::cogs::Backup + Sized + Clone + core::fmt::Debug + Serialize + DeserializeOwned -{ +pub trait RngCore: Backup + Sized + core::fmt::Debug + Serialize + DeserializeOwned { type Seed: AsMut<[u8]> + Default + Sized; #[must_use] diff --git a/necsim/core/src/cogs/speciation_probability.rs b/necsim/core/src/cogs/speciation_probability.rs index 8584228d6..7800c55fa 100644 --- a/necsim/core/src/cogs/speciation_probability.rs +++ b/necsim/core/src/cogs/speciation_probability.rs @@ -1,15 +1,13 @@ use necsim_core_bond::ClosedUnitF64; use crate::{ - cogs::{Habitat, MathsCore}, + cogs::{Backup, Habitat, MathsCore}, landscape::Location, }; #[allow(clippy::inline_always, clippy::inline_fn_without_body)] #[contract_trait] -pub trait SpeciationProbability>: - crate::cogs::Backup + core::fmt::Debug -{ +pub trait SpeciationProbability>: Backup + core::fmt::Debug { #[must_use] #[debug_requires( habitat.is_location_habitable(location), diff --git a/necsim/core/src/cogs/turnover_rate.rs b/necsim/core/src/cogs/turnover_rate.rs index fce772b01..b06081c4d 100644 --- a/necsim/core/src/cogs/turnover_rate.rs +++ b/necsim/core/src/cogs/turnover_rate.rs @@ -1,15 +1,13 @@ use necsim_core_bond::NonNegativeF64; use crate::{ - cogs::{Habitat, MathsCore}, + cogs::{Backup, Habitat, MathsCore}, landscape::Location, }; #[allow(clippy::inline_always, clippy::inline_fn_without_body)] #[contract_trait] -pub trait TurnoverRate>: - crate::cogs::Backup + core::fmt::Debug -{ +pub trait TurnoverRate>: Backup + core::fmt::Debug { #[must_use] #[debug_requires( habitat.is_location_habitable(location), diff --git a/necsim/core/src/simulation/builder.rs b/necsim/core/src/simulation/builder.rs index 4c8111f89..4be829b0d 100644 --- a/necsim/core/src/simulation/builder.rs +++ b/necsim/core/src/simulation/builder.rs @@ -287,4 +287,37 @@ impl< pub fn immigration_entry_mut(&mut self) -> &mut I { &mut self.immigration_entry } + + pub fn deconstruct(self) -> SimulationBuilder { + let Simulation { + maths, + habitat, + lineage_store, + dispersal_sampler, + coalescence_sampler, + turnover_rate, + speciation_probability, + emigration_exit, + event_sampler, + active_lineage_sampler, + rng, + immigration_entry, + migration_balance: _, + } = self; + + SimulationBuilder { + maths, + habitat, + lineage_store, + dispersal_sampler, + coalescence_sampler, + turnover_rate, + speciation_probability, + emigration_exit, + event_sampler, + active_lineage_sampler, + rng, + immigration_entry, + } + } } diff --git a/necsim/impls/cuda/src/cogs/rng.rs b/necsim/impls/cuda/src/cogs/rng.rs index 99d7df48a..7a8b17c8e 100644 --- a/necsim/impls/cuda/src/cogs/rng.rs +++ b/necsim/impls/cuda/src/cogs/rng.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use const_type_layout::TypeGraphLayout; use rust_cuda::safety::StackOnly; -use necsim_core::cogs::{MathsCore, Rng}; +use necsim_core::cogs::{Backup, MathsCore, Rng}; #[allow(clippy::module_name_repetitions)] #[derive(Debug, rust_cuda::common::LendRustToCuda)] @@ -16,15 +16,6 @@ where marker: PhantomData, } -impl + StackOnly + ~const TypeGraphLayout> Clone for CudaRng { - fn clone(&self) -> Self { - Self { - inner: self.inner.clone(), - marker: PhantomData::, - } - } -} - impl + StackOnly + ~const TypeGraphLayout> From for CudaRng { #[must_use] #[inline] @@ -37,11 +28,21 @@ impl + StackOnly + ~const TypeGraphLayout> From for C } impl + StackOnly + ~const TypeGraphLayout> CudaRng { - pub fn into(self) -> R { + pub fn into_inner(self) -> R { self.inner } } +#[contract_trait] +impl + StackOnly + ~const TypeGraphLayout> Backup for CudaRng { + unsafe fn backup_unchecked(&self) -> Self { + Self { + inner: self.inner.backup_unchecked(), + marker: PhantomData::, + } + } +} + impl + StackOnly + ~const TypeGraphLayout> Rng for CudaRng { type Generator = R::Generator; type Sampler = R::Sampler; diff --git a/necsim/impls/cuda/src/lib.rs b/necsim/impls/cuda/src/lib.rs index 44c4c984d..95d9711d9 100644 --- a/necsim/impls/cuda/src/lib.rs +++ b/necsim/impls/cuda/src/lib.rs @@ -16,7 +16,7 @@ extern crate alloc; #[macro_use] extern crate const_type_layout; -#[cfg_attr(target_os = "cuda", macro_use)] +#[macro_use] extern crate contracts; pub mod cogs; diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs index 098ca2861..ac1d8c1b9 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs @@ -1079,7 +1079,7 @@ fn debug_display_sampler() { } // GRCOV_EXCL_START -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, serde::Serialize, serde::Deserialize)] struct DummyRng(Vec); impl DummyRng { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs index 0505a4e83..169ab8870 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs @@ -578,7 +578,7 @@ fn debug_display_sampler() { } // GRCOV_EXCL_START -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, serde::Serialize, serde::Deserialize)] struct DummyRng(Vec); impl DummyRng { diff --git a/necsim/impls/no-std/src/cogs/origin_sampler/mod.rs b/necsim/impls/no-std/src/cogs/origin_sampler/mod.rs index 94a751d8d..a61a2a877 100644 --- a/necsim/impls/no-std/src/cogs/origin_sampler/mod.rs +++ b/necsim/impls/no-std/src/cogs/origin_sampler/mod.rs @@ -20,16 +20,14 @@ use pre_sampler::OriginPreSampler; /// `Lineage`s produced by the sampler's iterator must have /// * unique global references pub trait UntrustedOriginSampler<'h, M: MathsCore>: - core::fmt::Debug + core::iter::Iterator + Sized + core::fmt::Debug + core::iter::Iterator { type Habitat: 'h + Habitat; type PreSampler: Iterator; fn habitat(&self) -> &'h Self::Habitat; - fn into_pre_sampler(self) -> OriginPreSampler - where - Self: Sized; + fn into_pre_sampler(self) -> OriginPreSampler; fn full_upper_bound_size_hint(&self) -> u64; } diff --git a/necsim/impls/no-std/src/cogs/rng/rand.rs b/necsim/impls/no-std/src/cogs/rng/rand.rs index bd09e7755..0c2a11d59 100644 --- a/necsim/impls/no-std/src/cogs/rng/rand.rs +++ b/necsim/impls/no-std/src/cogs/rng/rand.rs @@ -6,7 +6,7 @@ use rand_core::{RngCore as RandRngCore, SeedableRng as RandSeedableRng}; use serde::{de::DeserializeOwned, Deserialize, Deserializer, Serialize, Serializer}; #[allow(clippy::module_name_repetitions)] -#[derive(Clone, TypeLayout)] +#[derive(TypeLayout)] #[repr(transparent)] pub struct RandRng { inner: G, @@ -58,7 +58,9 @@ impl Ba for RandRng { unsafe fn backup_unchecked(&self) -> Self { - self.clone() + Self { + inner: self.inner.clone(), + } } } diff --git a/necsim/impls/no-std/src/cogs/rng/seahash.rs b/necsim/impls/no-std/src/cogs/rng/seahash.rs index ea316ce72..c2f670ad1 100644 --- a/necsim/impls/no-std/src/cogs/rng/seahash.rs +++ b/necsim/impls/no-std/src/cogs/rng/seahash.rs @@ -3,7 +3,7 @@ use necsim_core::cogs::{Backup, PrimeableRng, RngCore}; use serde::{Deserialize, Serialize}; #[allow(clippy::module_name_repetitions, clippy::unsafe_derive_deserialize)] -#[derive(Clone, Debug, Serialize, Deserialize, TypeLayout)] +#[derive(Debug, Serialize, Deserialize, TypeLayout)] #[serde(deny_unknown_fields)] pub struct SeaHash { seed: u64, @@ -15,7 +15,12 @@ pub struct SeaHash { #[contract_trait] impl Backup for SeaHash { unsafe fn backup_unchecked(&self) -> Self { - self.clone() + Self { + seed: self.seed, + location: self.location, + time: self.time, + offset: self.offset, + } } } diff --git a/necsim/impls/no-std/src/cogs/rng/simple.rs b/necsim/impls/no-std/src/cogs/rng/simple.rs index dc4dfec89..e6dcb57f9 100644 --- a/necsim/impls/no-std/src/cogs/rng/simple.rs +++ b/necsim/impls/no-std/src/cogs/rng/simple.rs @@ -13,7 +13,7 @@ use necsim_core::cogs::{ }; use necsim_core_bond::{ClosedOpenUnitF64, ClosedUnitF64, NonNegativeF64, OpenClosedUnitF64}; -#[derive(Clone, Debug, TypeLayout)] +#[derive(Debug, TypeLayout)] #[allow(clippy::module_name_repetitions)] #[layout(free = "M")] #[repr(transparent)] @@ -32,7 +32,7 @@ impl From for SimpleRng { } impl SimpleRng { - pub fn into(self) -> R { + pub fn into_inner(self) -> R { self.inner } } diff --git a/necsim/impls/no-std/src/cogs/rng/wyhash.rs b/necsim/impls/no-std/src/cogs/rng/wyhash.rs index d1fa184fa..e3eb997fb 100644 --- a/necsim/impls/no-std/src/cogs/rng/wyhash.rs +++ b/necsim/impls/no-std/src/cogs/rng/wyhash.rs @@ -10,7 +10,7 @@ const P2: u64 = 0x8ebc_6af0_9c88_c6e3; const P5: u64 = 0xeb44_acca_b455_d165; #[allow(clippy::module_name_repetitions, clippy::unsafe_derive_deserialize)] -#[derive(Clone, Debug, Serialize, Deserialize, TypeLayout)] +#[derive(Debug, Serialize, Deserialize, TypeLayout)] #[serde(deny_unknown_fields)] #[repr(C)] pub struct WyHash { @@ -21,7 +21,10 @@ pub struct WyHash { #[contract_trait] impl Backup for WyHash { unsafe fn backup_unchecked(&self) -> Self { - self.clone() + Self { + seed: self.seed, + state: self.state, + } } } diff --git a/necsim/impls/no-std/src/decomposition/mod.rs b/necsim/impls/no-std/src/decomposition/mod.rs index 7791d99c5..a7ad6a889 100644 --- a/necsim/impls/no-std/src/decomposition/mod.rs +++ b/necsim/impls/no-std/src/decomposition/mod.rs @@ -11,7 +11,7 @@ pub mod radial; #[allow(clippy::inline_always, clippy::inline_fn_without_body)] #[contract_trait] -pub trait Decomposition>: Backup + Sized + core::fmt::Debug { +pub trait Decomposition>: Backup + core::fmt::Debug { fn get_subdomain(&self) -> Partition; #[debug_requires(habitat.is_location_habitable(location), "location is habitable")] diff --git a/necsim/impls/std/src/cogs/rng/pcg.rs b/necsim/impls/std/src/cogs/rng/pcg.rs index 81664a89f..42f053e83 100644 --- a/necsim/impls/std/src/cogs/rng/pcg.rs +++ b/necsim/impls/std/src/cogs/rng/pcg.rs @@ -2,25 +2,14 @@ use std::fmt; use pcg_rand::{seeds::PcgSeeder, PCGStateInfo, Pcg64}; use rand_core::{RngCore as _, SeedableRng}; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use necsim_core::cogs::{RngCore, SplittableRng}; +use necsim_core::cogs::{Backup, RngCore, SplittableRng}; -#[allow(clippy::module_name_repetitions)] -#[derive(Serialize, Deserialize)] -#[serde(from = "PcgState", into = "PcgState")] pub struct Pcg { inner: Pcg64, } -impl Clone for Pcg { - fn clone(&self) -> Self { - Self { - inner: Pcg64::restore_state_with_no_verification(self.inner.get_state()), - } - } -} - impl fmt::Debug for Pcg { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let state = self.inner.get_state(); @@ -32,6 +21,52 @@ impl fmt::Debug for Pcg { } } +impl Serialize for Pcg { + fn serialize(&self, serializer: S) -> Result { + let state_info = self.inner.get_state(); + + let state = PcgState { + state: state_info.state, + increment: state_info.increment, + }; + + state.serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for Pcg { + fn deserialize>(deserializer: D) -> Result { + use pcg_rand::{ + multiplier::{DefaultMultiplier, Multiplier}, + outputmix::{DXsMMixin, OutputMixin}, + }; + + let state = PcgState::deserialize(deserializer)?; + + let state_info = PCGStateInfo { + state: state.state, + increment: state.increment, + multiplier: DefaultMultiplier::multiplier(), + internal_width: u128::BITS as usize, + output_width: u64::BITS as usize, + output_mixin: >::SERIALIZER_ID.into(), + }; + + Ok(Self { + inner: Pcg64::restore_state_with_no_verification(state_info), + }) + } +} + +#[contract_trait] +impl Backup for Pcg { + unsafe fn backup_unchecked(&self) -> Self { + Self { + inner: Pcg64::restore_state_with_no_verification(self.inner.get_state()), + } + } +} + impl RngCore for Pcg { type Seed = [u8; 16]; @@ -89,36 +124,3 @@ struct PcgState { state: u128, increment: u128, } - -impl From for PcgState { - fn from(rng: Pcg) -> Self { - let state_info = rng.inner.get_state(); - - Self { - state: state_info.state, - increment: state_info.increment, - } - } -} - -impl From for Pcg { - fn from(state: PcgState) -> Self { - use pcg_rand::{ - multiplier::{DefaultMultiplier, Multiplier}, - outputmix::{DXsMMixin, OutputMixin}, - }; - - let state_info = PCGStateInfo { - state: state.state, - increment: state.increment, - multiplier: DefaultMultiplier::multiplier(), - internal_width: u128::BITS as usize, - output_width: u64::BITS as usize, - output_mixin: >::SERIALIZER_ID.into(), - }; - - Self { - inner: Pcg64::restore_state_with_no_verification(state_info), - } - } -} diff --git a/rustcoalescence/algorithms/cuda/src/launch.rs b/rustcoalescence/algorithms/cuda/src/launch.rs index b8bf930cc..352754b45 100644 --- a/rustcoalescence/algorithms/cuda/src/launch.rs +++ b/rustcoalescence/algorithms/cuda/src/launch.rs @@ -238,7 +238,7 @@ where .into_iter() .chain(passthrough.into_iter()) .collect(), - rng: simulation.rng_mut().clone().into().into(), + rng: simulation.deconstruct().rng.into_inner().into_inner(), }), } } diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs index ea9803bc8..207e1d979 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs @@ -127,7 +127,7 @@ where ) .cloned() .collect(), - rng: simulation.rng_mut().clone().into(), + rng: simulation.deconstruct().rng.into_inner(), }), } }, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs index 8156b0203..0fe808f96 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs @@ -121,7 +121,7 @@ where ) .cloned() .collect(), - rng: simulation.rng_mut().clone().into(), + rng: simulation.deconstruct().rng.into_inner(), }), } }, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs index ffd8fefa8..e44ad62c9 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs @@ -121,7 +121,7 @@ where ) .cloned() .collect(), - rng: simulation.rng_mut().clone().into(), + rng: simulation.deconstruct().rng.into_inner(), }), } }, diff --git a/rustcoalescence/algorithms/independent/src/launch.rs b/rustcoalescence/algorithms/independent/src/launch.rs index 4ff08b8e5..4b6da3948 100644 --- a/rustcoalescence/algorithms/independent/src/launch.rs +++ b/rustcoalescence/algorithms/independent/src/launch.rs @@ -159,7 +159,7 @@ pub fn initialise_and_simulate< .into_iter() .chain(passthrough.into_iter()) .collect(), - rng: simulation.rng_mut().clone().into(), + rng: simulation.deconstruct().rng.into_inner(), }), } }, diff --git a/rustcoalescence/algorithms/src/lib.rs b/rustcoalescence/algorithms/src/lib.rs index 3298b4958..b56749b60 100644 --- a/rustcoalescence/algorithms/src/lib.rs +++ b/rustcoalescence/algorithms/src/lib.rs @@ -35,7 +35,7 @@ pub trait Algorithm< O: Scenario, R: Reporter, P: LocalPartition<'p, R>, ->: Sized + AlgorithmParamters + AlgorithmDefaults +>: AlgorithmParamters + AlgorithmDefaults { type Rng: Rng; type LineageStore: LineageStore; From 61eb5441772c728cb04510b16f6c6e7dc93cbc40 Mon Sep 17 00:00:00 2001 From: Momo Langenstein Date: Sat, 21 May 2022 14:32:30 +0000 Subject: [PATCH 15/42] Implemented the RandRng sampler based on rand_distr --- Cargo.lock | 12 + necsim/impls/no-std/Cargo.toml | 1 + necsim/impls/no-std/src/cogs/rng/rand.rs | 445 ++++++++++++++++++++- necsim/impls/no-std/src/cogs/rng/simple.rs | 235 ++--------- 4 files changed, 477 insertions(+), 216 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 981674d3b..337889ed9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1052,6 +1052,7 @@ dependencies = [ "necsim-core-maths", "necsim-partitioning-core", "rand_core", + "rand_distr", "rust-cuda", "serde", "slab", @@ -1226,6 +1227,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -1398,6 +1400,16 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand", +] + [[package]] name = "regex" version = "1.10.2" diff --git a/necsim/impls/no-std/Cargo.toml b/necsim/impls/no-std/Cargo.toml index d6ae51e71..19628f69b 100644 --- a/necsim/impls/no-std/Cargo.toml +++ b/necsim/impls/no-std/Cargo.toml @@ -28,6 +28,7 @@ displaydoc = { version = "0.2", default-features = false, features = [] } final = "0.1.1" fnv = { version = "1.0", default-features = false, features = [] } rand_core = "0.6" +rand_distr = { version = "0.4", default-features = false, features = [] } [target.'cfg(target_os = "cuda")'.dependencies] rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "5d5cd02", features = ["derive"], optional = true } diff --git a/necsim/impls/no-std/src/cogs/rng/rand.rs b/necsim/impls/no-std/src/cogs/rng/rand.rs index 0c2a11d59..c5a698844 100644 --- a/necsim/impls/no-std/src/cogs/rng/rand.rs +++ b/necsim/impls/no-std/src/cogs/rng/rand.rs @@ -1,26 +1,44 @@ -use core::fmt; +use core::{ + fmt, + marker::PhantomData, + num::{NonZeroU128, NonZeroU32, NonZeroU64, NonZeroUsize}, +}; -use necsim_core::cogs::{Backup, RngCore}; +use necsim_core::cogs::{ + distribution::{ + Bernoulli, Exponential, IndexU128, IndexU32, IndexU64, IndexUsize, Lambda, Length, Normal, + Normal2D, Poisson, StandardNormal2D, UniformClosedOpenUnit, UniformOpenClosedUnit, + }, + Backup, DistributionSampler, MathsCore, Rng, RngCore, +}; +use necsim_core_bond::{ClosedOpenUnitF64, ClosedUnitF64, NonNegativeF64, OpenClosedUnitF64}; -use rand_core::{RngCore as RandRngCore, SeedableRng as RandSeedableRng}; +use rand_core::{Error, RngCore as RandRngCore, SeedableRng as RandSeedableRng}; +use rand_distr::{ + uniform::{UniformInt, UniformSampler}, + Bernoulli as RandBernoulli, Distribution as RandDistribution, Exp1 as RandExp1, + OpenClosed01 as RandOpenClosed01, Poisson as RandPoisson, Standard as RandStandard, + StandardNormal as RandStandardNormal, +}; use serde::{de::DeserializeOwned, Deserialize, Deserializer, Serialize, Serializer}; #[allow(clippy::module_name_repetitions)] #[derive(TypeLayout)] #[repr(transparent)] -pub struct RandRng { +pub struct RandAsRng { inner: G, } impl From - for RandRng + for RandAsRng { + #[inline] fn from(inner: G) -> Self { Self { inner } } } -impl RandRng { +impl RandAsRng { #[must_use] pub fn into_inner(self) -> G { self.inner @@ -28,7 +46,7 @@ impl Ra } impl fmt::Debug - for RandRng + for RandAsRng { default fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { struct InnerRng(&'static str); @@ -39,23 +57,23 @@ impl fm } } - fmt.debug_tuple("RandRng") + fmt.debug_tuple("RandAsRng") .field(&InnerRng(core::any::type_name::())) .finish() } } impl - fmt::Debug for RandRng + fmt::Debug for RandAsRng { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_tuple("RandRng").field(&self.inner).finish() + fmt.debug_tuple("RandAsRng").field(&self.inner).finish() } } #[contract_trait] impl Backup - for RandRng + for RandAsRng { unsafe fn backup_unchecked(&self) -> Self { Self { @@ -65,7 +83,7 @@ impl Ba } impl Serialize - for RandRng + for RandAsRng { fn serialize(&self, serializer: S) -> Result { self.inner.serialize(serializer) @@ -73,7 +91,7 @@ impl Se } impl<'de, G: RandRngCore + RandSeedableRng + Clone + Serialize + DeserializeOwned> Deserialize<'de> - for RandRng + for RandAsRng { fn deserialize>(deserializer: D) -> Result { let inner = G::deserialize(deserializer)?; @@ -83,7 +101,7 @@ impl<'de, G: RandRngCore + RandSeedableRng + Clone + Serialize + DeserializeOwne } impl RngCore - for RandRng + for RandAsRng { type Seed = G::Seed; @@ -101,3 +119,402 @@ impl Rn self.inner.next_u64() } } + +#[allow(clippy::module_name_repetitions)] +#[derive(TypeLayout)] +#[repr(transparent)] +pub struct RngAsRand { + inner: G, +} + +impl From for RngAsRand { + #[inline] + fn from(inner: G) -> Self { + Self { inner } + } +} + +impl RngAsRand { + #[must_use] + pub fn into_inner(self) -> G { + self.inner + } +} + +impl fmt::Debug for RngAsRand { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_tuple("RngAsRand").field(&self.inner).finish() + } +} + +#[contract_trait] +impl Backup for RngAsRand { + unsafe fn backup_unchecked(&self) -> Self { + Self { + inner: self.inner.backup_unchecked(), + } + } +} + +impl Serialize for RngAsRand { + fn serialize(&self, serializer: S) -> Result { + self.inner.serialize(serializer) + } +} + +impl<'de, G: RngCore> Deserialize<'de> for RngAsRand { + fn deserialize>(deserializer: D) -> Result { + let inner = G::deserialize(deserializer)?; + + Ok(Self { inner }) + } +} + +impl RngCore for RngAsRand { + type Seed = G::Seed; + + #[must_use] + #[inline] + fn from_seed(seed: Self::Seed) -> Self { + Self { + inner: G::from_seed(seed), + } + } + + #[must_use] + #[inline] + fn sample_u64(&mut self) -> u64 { + self.inner.sample_u64() + } +} + +impl RandSeedableRng for RngAsRand { + type Seed = G::Seed; + + #[inline] + fn from_seed(seed: Self::Seed) -> Self { + Self { + inner: G::from_seed(seed), + } + } +} + +impl RandRngCore for RngAsRand { + #[inline] + default fn next_u32(&mut self) -> u32 { + // Note: The most significant bits are often a bit more random + (self.sample_u64() >> 32) as u32 + } + + #[inline] + default fn next_u64(&mut self) -> u64 { + self.sample_u64() + } + + #[inline] + default fn fill_bytes(&mut self, dest: &mut [u8]) { + rand_core::impls::fill_bytes_via_next(self, dest); + } + + #[inline] + #[allow(clippy::unit_arg)] + default fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} + +impl RandRngCore for RngAsRand { + #[inline] + fn next_u32(&mut self) -> u32 { + self.inner.next_u32() + } + + #[inline] + fn next_u64(&mut self) -> u64 { + self.inner.next_u64() + } + + #[inline] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.inner.fill_bytes(dest); + } + + #[inline] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.inner.try_fill_bytes(dest) + } +} + +#[derive(Debug, TypeLayout)] +#[allow(clippy::module_name_repetitions)] +#[repr(transparent)] +pub struct RandRng { + inner: R, + marker: PhantomData, +} + +impl From for RandRng { + fn from(inner: R) -> Self { + Self { + inner, + marker: PhantomData::, + } + } +} + +impl RandRng { + pub fn into_inner(self) -> R { + self.inner + } +} + +#[contract_trait] +impl Backup for RandRng { + unsafe fn backup_unchecked(&self) -> Self { + Self { + inner: self.inner.backup_unchecked(), + marker: PhantomData::, + } + } +} + +impl Rng for RandRng { + type Generator = R; + type Sampler = RandDistributionSamplers; + + fn generator(&mut self) -> &mut Self::Generator { + &mut self.inner + } + + fn map_generator Self::Generator>(self, map: F) -> Self { + let RandRng { inner, marker } = self; + + RandRng { + inner: map(inner), + marker, + } + } + + fn with Q, Q>(&mut self, inner: F) -> Q { + let samplers = RandDistributionSamplers { + _marker: PhantomData::<(M, R)>, + }; + + inner(&mut self.inner, &samplers) + } +} + +#[allow(clippy::module_name_repetitions)] +pub struct RandDistributionSamplers { + _marker: PhantomData<(M, R)>, +} + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution(&self, rng: &mut R, _samplers: &S, _params: ()) -> ClosedOpenUnitF64 { + let u01: f64 = RandStandard.sample(rng); + + // Safety: Standard samples from [0, 1) + unsafe { ClosedOpenUnitF64::new_unchecked(u01) } + } +} + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution(&self, rng: &mut R, _samplers: &S, _params: ()) -> OpenClosedUnitF64 { + let u01: f64 = RandOpenClosed01.sample(rng); + + // Safety: OpenClosed01 samples from (0, 1] + unsafe { OpenClosedUnitF64::new_unchecked(u01) } + } +} + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + _samplers: &S, + Length(length): Length, + ) -> usize { + UniformInt::::sample_single(0, length.get(), rng) + } +} + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + _samplers: &S, + Length(length): Length, + ) -> u32 { + UniformInt::::sample_single(0, length.get(), rng) + } +} + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + _samplers: &S, + Length(length): Length, + ) -> u64 { + UniformInt::::sample_single(0, length.get(), rng) + } +} + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + _samplers: &S, + Length(length): Length, + ) -> u128 { + UniformInt::::sample_single(0, length.get(), rng) + } +} + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + _samplers: &S, + Lambda(lambda): Lambda, + ) -> NonNegativeF64 { + let exp1: f64 = RandExp1.sample(rng); + + // Safety: Exp1 samples from [0, +inf) + (unsafe { NonNegativeF64::new_unchecked(exp1) }) / lambda + } +} + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution(&self, rng: &mut R, _samplers: &S, Lambda(lambda): Lambda) -> u64 { + // Safety: PositiveF64 asserts that lambda > 0 + let poisson = unsafe { RandPoisson::new(lambda.get()).unwrap_unchecked() }; + + #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)] + { + poisson.sample(rng) as u64 + } + } +} + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution(&self, rng: &mut R, _samplers: &S, probability: ClosedUnitF64) -> bool { + // Safety: ClosedUnitF64 asserts that probability is in [0.0, 1.0] + let bernoulli = unsafe { RandBernoulli::new(probability.get()).unwrap_unchecked() }; + + bernoulli.sample(rng) + } +} + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution(&self, rng: &mut R, _samplers: &S, _params: ()) -> (f64, f64) { + ( + RandStandardNormal.sample(rng), + RandStandardNormal.sample(rng), + ) + } +} + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + _samplers: &S, + Normal { mu, sigma }: Normal, + ) -> (f64, f64) { + let (z0, z1): (f64, f64) = ( + RandStandardNormal.sample(rng), + RandStandardNormal.sample(rng), + ); + + (z0 * sigma.get() + mu, z1 * sigma.get() + mu) + } +} diff --git a/necsim/impls/no-std/src/cogs/rng/simple.rs b/necsim/impls/no-std/src/cogs/rng/simple.rs index e6dcb57f9..0d0d609e3 100644 --- a/necsim/impls/no-std/src/cogs/rng/simple.rs +++ b/necsim/impls/no-std/src/cogs/rng/simple.rs @@ -128,10 +128,8 @@ impl, + Length(length): Length, ) -> usize { - let length = params.0; - let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); #[allow( @@ -155,9 +153,12 @@ impl) -> u32 { - let length = params.0; - + fn sample_distribution( + &self, + rng: &mut R, + samplers: &S, + Length(length): Length, + ) -> u32 { let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] @@ -177,9 +178,12 @@ impl) -> u64 { - let length = params.0; - + fn sample_distribution( + &self, + rng: &mut R, + samplers: &S, + Length(length): Length, + ) -> u64 { let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); #[allow( @@ -203,9 +207,12 @@ impl) -> u128 { - let length = params.0; - + fn sample_distribution( + &self, + rng: &mut R, + samplers: &S, + Length(length): Length, + ) -> u128 { let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); #[allow( @@ -229,9 +236,12 @@ impl NonNegativeF64 { - let lambda = params.0; - + fn sample_distribution( + &self, + rng: &mut R, + samplers: &S, + Lambda(lambda): Lambda, + ) -> NonNegativeF64 { let u01 = UniformOpenClosedUnit::sample_raw(rng, samplers); // Inverse transform sample: X = -ln(U(0,1]) / lambda @@ -252,8 +262,7 @@ impl< self } - fn sample_distribution(&self, rng: &mut R, samplers: &S, params: Lambda) -> u64 { - let lambda = params.0; + fn sample_distribution(&self, rng: &mut R, samplers: &S, Lambda(lambda): Lambda) -> u64 { let no_event_probability = M::exp(-lambda.get()); if no_event_probability <= 0.0_f64 { @@ -300,9 +309,7 @@ impl bool { - let probability = params; - + fn sample_distribution(&self, rng: &mut R, samplers: &S, probability: ClosedUnitF64) -> bool { let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); // if probability == 1, then U[0, 1) always < 1.0 @@ -345,190 +352,14 @@ impl self } - fn sample_distribution(&self, rng: &mut R, samplers: &S, params: Normal) -> (f64, f64) { + fn sample_distribution( + &self, + rng: &mut R, + samplers: &S, + Normal { mu, sigma }: Normal, + ) -> (f64, f64) { let (z0, z1) = StandardNormal2D::sample_raw(rng, samplers); - ( - z0 * params.sigma.get() + params.mu, - z1 * params.sigma.get() + params.mu, - ) - } -} - -/*#[allow(clippy::inline_always, clippy::inline_fn_without_body)] -#[allow(clippy::module_name_repetitions)] -#[contract_trait] -pub trait RngSampler: RngCore { - #[must_use] - #[inline] - /// Samples a uniform sample within `[0.0, 1.0)`, i.e. `0.0 <= X < 1.0` - fn sample_uniform_closed_open(&mut self) -> ClosedOpenUnitF64 { - // http://prng.di.unimi.it -> Generating uniform doubles in the unit interval - #[allow(clippy::cast_precision_loss)] - let u01 = ((self.sample_u64() >> 11) as f64) * f64::from_bits(0x3CA0_0000_0000_0000_u64); // 0x1.0p-53 - - unsafe { ClosedOpenUnitF64::new_unchecked(u01) } - } - - #[must_use] - #[inline] - /// Samples a uniform sample within `(0.0, 1.0]`, i.e. `0.0 < X <= 1.0` - fn sample_uniform_open_closed(&mut self) -> OpenClosedUnitF64 { - // http://prng.di.unimi.it -> Generating uniform doubles in the unit interval - #[allow(clippy::cast_precision_loss)] - let u01 = - (((self.sample_u64() >> 11) + 1) as f64) * f64::from_bits(0x3CA0_0000_0000_0000_u64); // 0x1.0p-53 - - unsafe { OpenClosedUnitF64::new_unchecked(u01) } - } - - #[must_use] - #[inline] - #[debug_ensures(ret < length.get(), "samples U(0, length - 1)")] - fn sample_index(&mut self, length: NonZeroUsize) -> usize { - #[cfg(target_pointer_width = "32")] - #[allow(clippy::cast_possible_truncation)] - { - self.sample_index_u32(unsafe { NonZeroU32::new_unchecked(length.get() as u32) }) - as usize - } - #[cfg(target_pointer_width = "64")] - #[allow(clippy::cast_possible_truncation)] - { - self.sample_index_u64(unsafe { NonZeroU64::new_unchecked(length.get() as u64) }) - as usize - } - } - - #[must_use] - #[inline] - #[debug_ensures(ret < length.get(), "samples U(0, length - 1)")] - fn sample_index_u32(&mut self, length: NonZeroU32) -> u32 { - // TODO: Check if delegation to `sample_index_u64` is faster - - // Adapted from: - // https://docs.rs/rand/0.8.4/rand/distributions/uniform/trait.UniformSampler.html#method.sample_single - - const LOWER_MASK: u64 = !0 >> 32; - - // Conservative approximation of the acceptance zone - let acceptance_zone = (length.get() << length.leading_zeros()).wrapping_sub(1); - - loop { - let raw = self.sample_u64(); - - let sample_check_lo = (raw & LOWER_MASK) * u64::from(length.get()); - - #[allow(clippy::cast_possible_truncation)] - if (sample_check_lo as u32) <= acceptance_zone { - return (sample_check_lo >> 32) as u32; - } - - let sample_check_hi = (raw >> 32) * u64::from(length.get()); - - #[allow(clippy::cast_possible_truncation)] - if (sample_check_hi as u32) <= acceptance_zone { - return (sample_check_hi >> 32) as u32; - } - } - } - - #[must_use] - #[inline] - #[debug_ensures(ret < length.get(), "samples U(0, length - 1)")] - fn sample_index_u64(&mut self, length: NonZeroU64) -> u64 { - // Adapted from: - // https://docs.rs/rand/0.8.4/rand/distributions/uniform/trait.UniformSampler.html#method.sample_single - - // Conservative approximation of the acceptance zone - let acceptance_zone = (length.get() << length.leading_zeros()).wrapping_sub(1); - - loop { - let raw = self.sample_u64(); - - let sample_check = u128::from(raw) * u128::from(length.get()); - - #[allow(clippy::cast_possible_truncation)] - if (sample_check as u64) <= acceptance_zone { - return (sample_check >> 64) as u64; - } - } - } - - #[must_use] - #[inline] - #[debug_ensures(ret < length.get(), "samples U(0, length - 1)")] - fn sample_index_u128(&mut self, length: NonZeroU128) -> u128 { - // Adapted from: - // https://docs.rs/rand/0.8.4/rand/distributions/uniform/trait.UniformSampler.html#method.sample_single - - const LOWER_MASK: u128 = !0 >> 64; - - // Conservative approximation of the acceptance zone - let acceptance_zone = (length.get() << length.leading_zeros()).wrapping_sub(1); - - loop { - let raw_hi = u128::from(self.sample_u64()); - let raw_lo = u128::from(self.sample_u64()); - - // 256-bit multiplication (hi, lo) = (raw_hi, raw_lo) * length - let mut low = raw_lo * (length.get() & LOWER_MASK); - let mut t = low >> 64; - low &= LOWER_MASK; - t += raw_hi * (length.get() & LOWER_MASK); - low += (t & LOWER_MASK) << 64; - let mut high = t >> 64; - t = low >> 64; - low &= LOWER_MASK; - t += (length.get() >> 64) * raw_lo; - low += (t & LOWER_MASK) << 64; - high += t >> 64; - high += raw_hi * (length.get() >> 64); - - let sample = high; - let check = low; - - if check <= acceptance_zone { - return sample; - } - } - } - - #[must_use] - #[inline] - fn sample_exponential(&mut self, lambda: PositiveF64) -> NonNegativeF64 { - // Inverse transform sample: X = -ln(U(0,1]) / lambda - -self.sample_uniform_open_closed().ln::() / lambda - } - - #[must_use] - #[inline] - fn sample_event(&mut self, probability: ClosedUnitF64) -> bool { - // if probability == 1, then U[0, 1) always < 1.0 - // if probability == 0, then U[0, 1) never < 0.0 - self.sample_uniform_closed_open() < probability - } - - #[must_use] - #[inline] - fn sample_2d_standard_normal(&mut self) -> (f64, f64) { - // Basic Box-Muller transform - let u0 = self.sample_uniform_open_closed(); - let u1 = self.sample_uniform_closed_open(); - - let r = M::sqrt(-2.0_f64 * M::ln(u0.get())); - let theta = -core::f64::consts::TAU * u1.get(); - - (r * M::sin(theta), r * M::cos(theta)) - } - - #[must_use] - #[inline] - fn sample_2d_normal(&mut self, mu: f64, sigma: NonNegativeF64) -> (f64, f64) { - let (z0, z1) = self.sample_2d_standard_normal(); - (z0 * sigma.get() + mu, z1 * sigma.get() + mu) } } - -impl> RngSampler for R {}*/ From d6e0dee38ae7b9727b9408f190445fe89bdea2f4 Mon Sep 17 00:00:00 2001 From: Momo Langenstein Date: Sat, 21 May 2022 22:08:34 +0000 Subject: [PATCH 16/42] Small optimisations of rng usage --- necsim/core/src/cogs/coalescence_sampler.rs | 38 ++++---- .../alias/sampler/indexed/tests.rs | 66 +++++++------- .../alias/sampler/stack/tests.rs | 66 +++++++------- .../active_lineage_sampler/classical/mod.rs | 20 +---- .../classical/sampler.rs | 8 +- .../independent/event_time_sampler/exp.rs | 2 +- .../independent/event_time_sampler/fixed.rs | 4 +- .../event_time_sampler/geometric.rs | 4 +- .../independent/event_time_sampler/poisson.rs | 4 +- .../cogs/coalescence_sampler/conditional.rs | 8 +- .../cogs/coalescence_sampler/independent.rs | 8 +- .../optional_coalescence.rs | 10 ++- .../almost_infinite_normal.rs | 5 +- .../cogs/dispersal_sampler/wrapping_noise.rs | 2 +- .../event_sampler/gillespie/unconditional.rs | 20 ++--- .../src/cogs/event_sampler/unconditional.rs | 18 ++-- .../src/cogs/habitat/wrapping_noise/mod.rs | 2 +- necsim/impls/no-std/src/cogs/rng/rand.rs | 1 + necsim/impls/no-std/src/cogs/rng/simple.rs | 87 +++++++++++-------- .../no-std/src/decomposition/equal/mod.rs | 15 ++-- .../impls/no-std/src/decomposition/radial.rs | 12 ++- necsim/impls/no-std/src/lib.rs | 1 + .../parallelisation/independent/landscape.rs | 17 ++-- .../src/parallelisation/independent/mod.rs | 2 + .../gillespie/classical/initialiser/fixup.rs | 8 +- .../classical/initialiser/genesis.rs | 8 +- .../gillespie/classical/initialiser/mod.rs | 4 +- .../gillespie/classical/initialiser/resume.rs | 8 +- 28 files changed, 230 insertions(+), 218 deletions(-) diff --git a/necsim/core/src/cogs/coalescence_sampler.rs b/necsim/core/src/cogs/coalescence_sampler.rs index eae990435..4095e1313 100644 --- a/necsim/core/src/cogs/coalescence_sampler.rs +++ b/necsim/core/src/cogs/coalescence_sampler.rs @@ -1,14 +1,12 @@ -use core::cmp::{Ord, Ordering}; - -use necsim_core_bond::ClosedOpenUnitF64; +use core::{ + cmp::{Ord, Ordering}, + num::NonZeroU32, +}; use serde::{Deserialize, Serialize}; use crate::{ - cogs::{ - distribution::UniformClosedOpenUnit, Backup, Distribution, Habitat, LineageStore, - MathsCore, Rng, Samples, - }, + cogs::{Backup, Habitat, LineageStore, MathsCore, Rng, RngCore}, landscape::{IndexedLocation, Location}, lineage::LineageInteraction, }; @@ -32,7 +30,7 @@ pub trait CoalescenceSampler, S: LineageStore> #[allow(clippy::unsafe_derive_deserialize)] #[derive(Debug, PartialEq, Serialize, Deserialize, TypeLayout)] #[repr(transparent)] -pub struct CoalescenceRngSample(ClosedOpenUnitF64); +pub struct CoalescenceRngSample(u64); #[contract_trait] impl Backup for CoalescenceRngSample { @@ -58,22 +56,20 @@ impl Eq for CoalescenceRngSample {} impl CoalescenceRngSample { #[must_use] #[inline] - pub fn new + Samples>(rng: &mut G) -> Self { - Self(UniformClosedOpenUnit::sample(rng)) + pub fn new>(rng: &mut G) -> Self { + Self(rng.generator().sample_u64()) } #[must_use] #[inline] - #[debug_ensures(ret < length, "samples U(0, length - 1)")] - pub fn sample_coalescence_index(self, length: u32) -> u32 { - // attributes on expressions are experimental - // see https://github.com/rust-lang/rust/issues/15701 - #[allow( - clippy::cast_precision_loss, - clippy::cast_possible_truncation, - clippy::cast_sign_loss - )] - let index = M::floor(self.0.get() * f64::from(length)) as u32; - index + #[debug_ensures(ret < length.get(), "samples U(0, length - 1)")] + pub fn sample_coalescence_index(self, length: NonZeroU32) -> u32 { + // Sample U(0, length - 1) using a widening multiplication + // Note: Some slight bias is traded for only needing one u64 sample + // Note: Should optimise to a single 64 bit (high-only) multiplication + #[allow(clippy::cast_possible_truncation)] + { + (((u128::from(self.0) * u128::from(length.get())) >> 64) & u128::from(!0_u32)) as u32 + } } } diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs index ac1d8c1b9..4a95671e1 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs @@ -1145,19 +1145,25 @@ impl DistributionSampler, + Length(length): Length, ) -> usize { - let length = params.0; - - #[allow( - clippy::cast_precision_loss, - clippy::cast_possible_truncation, - clippy::cast_sign_loss - )] - let index = IntrinsicsMathsCore::floor(rng.sample_f64() * (length.get() as f64)) as usize; - - // Safety in case of f64 rounding errors - index.min(length.get() - 1) + let u01 = rng.sample_f64(); + + // Safety: U[0, 1) * length in [0, 2^[32/64]) is a valid [u32/u64] + // since (1 - 2^-53) * 2^[32/64] <= (2^[32/64] - 1) + #[allow(clippy::cast_precision_loss)] + let index = unsafe { + IntrinsicsMathsCore::floor(u01 * (length.get() as f64)).to_int_unchecked::() + }; + + if cfg!(target_pointer_width = "32") { + // Note: [0, 2^32) is losslessly represented in f64 + index + } else { + // Note: Ensure index < length despite + // usize->f64->usize precision loss + index.min(length.get() - 1) + } } } @@ -1174,18 +1180,18 @@ impl DistributionSampler, + Length(length): Length, ) -> u64 { - let length = params.0; + let u01 = rng.sample_f64(); - #[allow( - clippy::cast_precision_loss, - clippy::cast_possible_truncation, - clippy::cast_sign_loss - )] - let index = IntrinsicsMathsCore::floor(rng.sample_f64() * (length.get() as f64)) as u64; + // Safety: U[0, 1) * length in [0, 2^64) is a valid u64 + // since (1 - 2^-53) * 2^64 <= (2^64 - 1) + #[allow(clippy::cast_precision_loss)] + let index = unsafe { + IntrinsicsMathsCore::floor(u01 * (length.get() as f64)).to_int_unchecked::() + }; - // Safety in case of f64 rounding errors + // Note: Ensure index < length despite u64->f64->u64 precision loss index.min(length.get() - 1) } } @@ -1203,18 +1209,18 @@ impl DistributionSampler, + Length(length): Length, ) -> u128 { - let length = params.0; + let u01 = rng.sample_f64(); - #[allow( - clippy::cast_precision_loss, - clippy::cast_possible_truncation, - clippy::cast_sign_loss - )] - let index = IntrinsicsMathsCore::floor(rng.sample_f64() * (length.get() as f64)) as u128; + // Safety: U[0, 1) * length in [0, 2^128) is a valid u128 + // since (1 - 2^-53) * 2^128 <= (2^128 - 1) + #[allow(clippy::cast_precision_loss)] + let index = unsafe { + IntrinsicsMathsCore::floor(u01 * (length.get() as f64)).to_int_unchecked::() + }; - // Safety in case of f64 rounding errors + // Note: Ensure index < length despite u128->f64->u128 precision loss index.min(length.get() - 1) } } diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs index 169ab8870..aa0258506 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs @@ -644,19 +644,25 @@ impl DistributionSampler, + Length(length): Length, ) -> usize { - let length = params.0; - - #[allow( - clippy::cast_precision_loss, - clippy::cast_possible_truncation, - clippy::cast_sign_loss - )] - let index = IntrinsicsMathsCore::floor(rng.sample_f64() * (length.get() as f64)) as usize; - - // Safety in case of f64 rounding errors - index.min(length.get() - 1) + let u01 = rng.sample_f64(); + + // Safety: U[0, 1) * length in [0, 2^[32/64]) is a valid [u32/u64] + // since (1 - 2^-53) * 2^[32/64] <= (2^[32/64] - 1) + #[allow(clippy::cast_precision_loss)] + let index = unsafe { + IntrinsicsMathsCore::floor(u01 * (length.get() as f64)).to_int_unchecked::() + }; + + if cfg!(target_pointer_width = "32") { + // Note: [0, 2^32) is losslessly represented in f64 + index + } else { + // Note: Ensure index < length despite + // usize->f64->usize precision loss + index.min(length.get() - 1) + } } } @@ -673,18 +679,18 @@ impl DistributionSampler, + Length(length): Length, ) -> u64 { - let length = params.0; + let u01 = rng.sample_f64(); - #[allow( - clippy::cast_precision_loss, - clippy::cast_possible_truncation, - clippy::cast_sign_loss - )] - let index = IntrinsicsMathsCore::floor(rng.sample_f64() * (length.get() as f64)) as u64; + // Safety: U[0, 1) * length in [0, 2^64) is a valid u64 + // since (1 - 2^-53) * 2^64 <= (2^64 - 1) + #[allow(clippy::cast_precision_loss)] + let index = unsafe { + IntrinsicsMathsCore::floor(u01 * (length.get() as f64)).to_int_unchecked::() + }; - // Safety in case of f64 rounding errors + // Note: Ensure index < length despite u64->f64->u64 precision loss index.min(length.get() - 1) } } @@ -702,18 +708,18 @@ impl DistributionSampler, + Length(length): Length, ) -> u128 { - let length = params.0; + let u01 = rng.sample_f64(); - #[allow( - clippy::cast_precision_loss, - clippy::cast_possible_truncation, - clippy::cast_sign_loss - )] - let index = IntrinsicsMathsCore::floor(rng.sample_f64() * (length.get() as f64)) as u128; + // Safety: U[0, 1) * length in [0, 2^128) is a valid u128 + // since (1 - 2^-53) * 2^128 <= (2^128 - 1) + #[allow(clippy::cast_precision_loss)] + let index = unsafe { + IntrinsicsMathsCore::floor(u01 * (length.get() as f64)).to_int_unchecked::() + }; - // Safety in case of f64 rounding errors + // Note: Ensure index < length despite u128->f64->u128 precision loss index.min(length.get() - 1) } } diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs index e207e7c11..a70d0b65e 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs @@ -2,7 +2,7 @@ use alloc::vec::Vec; use core::marker::PhantomData; use necsim_core::cogs::{ - distribution::{Bernoulli, Exponential, IndexUsize, UniformClosedOpenUnit}, + distribution::{Bernoulli, Exponential, IndexUsize}, Backup, DispersalSampler, EmigrationExit, Habitat, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, Samples, SpeciationProbability, }; @@ -20,11 +20,7 @@ mod sampler; pub struct ClassicalActiveLineageSampler< M: MathsCore, H: Habitat, - G: Rng - + Samples - + Samples - + Samples - + Samples, + G: Rng + Samples + Samples + Samples, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -40,11 +36,7 @@ pub struct ClassicalActiveLineageSampler< impl< M: MathsCore, H: Habitat, - G: Rng - + Samples - + Samples - + Samples - + Samples, + G: Rng + Samples + Samples + Samples, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -135,11 +127,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: Rng - + Samples - + Samples - + Samples - + Samples, + G: Rng + Samples + Samples + Samples, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs index 60a2c9a29..2caa6dbea 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs @@ -5,7 +5,7 @@ use core::{ use necsim_core::{ cogs::{ - distribution::{Bernoulli, Exponential, IndexUsize, Lambda, Length, UniformClosedOpenUnit}, + distribution::{Bernoulli, Exponential, IndexUsize, Lambda, Length}, ActiveLineageSampler, DispersalSampler, Distribution, EmigrationExit, Habitat, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, Samples, SpeciationProbability, @@ -27,11 +27,7 @@ use super::ClassicalActiveLineageSampler; impl< M: MathsCore, H: Habitat, - G: Rng - + Samples - + Samples - + Samples - + Samples, + G: Rng + Samples + Samples + Samples, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs index d9b38f040..ef89f407e 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/exp.rs @@ -56,13 +56,13 @@ impl< ) }; + // Note: rust clamps f64 as u64 to [0, 2^64 - 1] #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] let mut time_step = M::floor(time.get() / self.delta_t.get()) as u64; let mut event_time = NonNegativeF64::from(time_step) * self.delta_t; let mut time_slice_end = NonNegativeF64::from(time_step + 1) * self.delta_t; - #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] rng.generator() .prime_with_habitat(habitat, indexed_location, time_step); diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/fixed.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/fixed.rs index 08844e755..1b964412e 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/fixed.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/fixed.rs @@ -27,8 +27,8 @@ impl, G: Rng, T: Turnove let lambda = turnover_rate.get_turnover_rate_at_location(indexed_location.location(), habitat); - #[allow(clippy::cast_possible_truncation)] - #[allow(clippy::cast_sign_loss)] + // Note: rust clamps f64 as u64 to [0, 2^64 - 1] + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] let time_step = M::floor(time.get() * lambda.get()) as u64 + 1; rng.generator() diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs index 2a8355407..270a48016 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/geometric.rs @@ -46,8 +46,8 @@ impl< .neg_exp::() .one_minus(); - #[allow(clippy::cast_possible_truncation)] - #[allow(clippy::cast_sign_loss)] + // Note: rust clamps f64 as u64 to [0, 2^64 - 1] + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] let mut time_step = M::floor(time.get() / self.delta_t.get()) as u64 + 1; loop { diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs index 457c72b52..22388e81b 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs @@ -50,8 +50,8 @@ impl< // location let lambda_per_step = unsafe { PositiveF64::new_unchecked(lambda.get()) } * self.delta_t; - #[allow(clippy::cast_possible_truncation)] - #[allow(clippy::cast_sign_loss)] + // Note: rust clamps f64 as u64 to [0, 2^64 - 1] + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] let mut time_step = M::floor(time.get() / self.delta_t.get()) as u64; let (event_time, event_index) = loop { diff --git a/necsim/impls/no-std/src/cogs/coalescence_sampler/conditional.rs b/necsim/impls/no-std/src/cogs/coalescence_sampler/conditional.rs index e1109422a..493f48c15 100644 --- a/necsim/impls/no-std/src/cogs/coalescence_sampler/conditional.rs +++ b/necsim/impls/no-std/src/cogs/coalescence_sampler/conditional.rs @@ -1,4 +1,4 @@ -use core::marker::PhantomData; +use core::{marker::PhantomData, num::NonZeroU32}; use necsim_core::{ cogs::{ @@ -73,11 +73,11 @@ impl, S: GloballyCoherentLineageStore> let lineages_at_location = lineage_store.get_local_lineage_references_at_location_unordered(&location, habitat); + // Safety: individuals can only occupy habitable locations #[allow(clippy::cast_possible_truncation)] - let population = lineages_at_location.len() as u32; + let population = unsafe { NonZeroU32::new_unchecked(lineages_at_location.len() as u32) }; - let chosen_coalescence_index = - coalescence_rng_sample.sample_coalescence_index::(population); + let chosen_coalescence_index = coalescence_rng_sample.sample_coalescence_index(population); let chosen_coalescence = &lineages_at_location[chosen_coalescence_index as usize]; let lineage = &lineage_store[chosen_coalescence]; diff --git a/necsim/impls/no-std/src/cogs/coalescence_sampler/independent.rs b/necsim/impls/no-std/src/cogs/coalescence_sampler/independent.rs index 0e9a16f6a..f387ab9a2 100644 --- a/necsim/impls/no-std/src/cogs/coalescence_sampler/independent.rs +++ b/necsim/impls/no-std/src/cogs/coalescence_sampler/independent.rs @@ -1,4 +1,4 @@ -use core::marker::PhantomData; +use core::{marker::PhantomData, num::NonZeroU32}; use necsim_core::{ cogs::{ @@ -45,10 +45,12 @@ impl> CoalescenceSampler, coalescence_rng_sample: CoalescenceRngSample, ) -> (IndexedLocation, LineageInteraction) { - let population = habitat.get_habitat_at_location(&location); + // Safety: individuals can only occupy habitable locations + let habitat_at_location = + unsafe { NonZeroU32::new_unchecked(habitat.get_habitat_at_location(&location)) }; let chosen_coalescence_index = - coalescence_rng_sample.sample_coalescence_index::(population); + coalescence_rng_sample.sample_coalescence_index(habitat_at_location); let indexed_location = IndexedLocation::new(location, chosen_coalescence_index); diff --git a/necsim/impls/no-std/src/cogs/coalescence_sampler/optional_coalescence.rs b/necsim/impls/no-std/src/cogs/coalescence_sampler/optional_coalescence.rs index 94d8190cf..247a13244 100644 --- a/necsim/impls/no-std/src/cogs/coalescence_sampler/optional_coalescence.rs +++ b/necsim/impls/no-std/src/cogs/coalescence_sampler/optional_coalescence.rs @@ -1,3 +1,5 @@ +use core::num::NonZeroU32; + use necsim_core::{ cogs::{ coalescence_sampler::CoalescenceRngSample, Habitat, LocallyCoherentLineageStore, MathsCore, @@ -17,8 +19,12 @@ pub fn sample_interaction_at_location< lineage_store: &S, coalescence_rng_sample: CoalescenceRngSample, ) -> (IndexedLocation, LineageInteraction) { - let chosen_coalescence_index = coalescence_rng_sample - .sample_coalescence_index::(habitat.get_habitat_at_location(&location)); + // Safety: individuals can only occupy habitable locations + let habitat_at_location = + unsafe { NonZeroU32::new_unchecked(habitat.get_habitat_at_location(&location)) }; + + let chosen_coalescence_index = + coalescence_rng_sample.sample_coalescence_index(habitat_at_location); let indexed_location = IndexedLocation::new(location, chosen_coalescence_index); diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs index 8df4339f3..54d0dea04 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_normal.rs @@ -78,8 +78,9 @@ impl + Samples> ); // Discrete dispersal assumes lineage positions are centred on (0.5, 0.5), - // i.e. |dispersal| >= 0.5 changes the cell - // (dx and dy must be rounded to nearest int away from 0.0) + // i.e. |dispersal| >= 0.5 changes the cell + // dx and dy must be rounded to nearest int away from 0.0 + // Note: rust clamps f64 as i64 to [-2^-63, 2^63 - 1] #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] let (dx, dy): (i64, i64) = (M::round(dx) as i64, M::round(dy) as i64); diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/wrapping_noise.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/wrapping_noise.rs index e34611409..09e86bd3a 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/wrapping_noise.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/wrapping_noise.rs @@ -2,7 +2,7 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, Normal2D}, Backup, DispersalSampler, DistributionSampler, Habitat, MathsCore, Rng, - SampledDistribution, SeparableDispersalSampler, + Distribution, SeparableDispersalSampler, }, landscape::Location, }; diff --git a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs index ac7342ce6..f1d9464ef 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/gillespie/unconditional.rs @@ -2,12 +2,10 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ - coalescence_sampler::CoalescenceRngSample, - distribution::{Bernoulli, UniformClosedOpenUnit}, - event_sampler::EventHandler, - Backup, CoalescenceSampler, DispersalSampler, Distribution, EmigrationExit, EventSampler, - GloballyCoherentLineageStore, Habitat, MathsCore, Rng, Samples, SpeciationProbability, - TurnoverRate, + coalescence_sampler::CoalescenceRngSample, distribution::Bernoulli, + event_sampler::EventHandler, Backup, CoalescenceSampler, DispersalSampler, Distribution, + EmigrationExit, EventSampler, GloballyCoherentLineageStore, Habitat, MathsCore, Rng, + Samples, SpeciationProbability, TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, landscape::Location, @@ -23,7 +21,7 @@ use super::GillespieEventSampler; pub struct UnconditionalGillespieEventSampler< M: MathsCore, H: Habitat, - G: Rng + Samples + Samples, + G: Rng + Samples, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -38,7 +36,7 @@ pub struct UnconditionalGillespieEventSampler< impl< M: MathsCore, H: Habitat, - G: Rng + Samples + Samples, + G: Rng + Samples, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -58,7 +56,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: Rng + Samples + Samples, + G: Rng + Samples, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -78,7 +76,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: Rng + Samples + Samples, + G: Rng + Samples, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -186,7 +184,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: Rng + Samples + Samples, + G: Rng + Samples, S: GloballyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, diff --git a/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs b/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs index e8ae14594..07d37bfb6 100644 --- a/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs +++ b/necsim/impls/no-std/src/cogs/event_sampler/unconditional.rs @@ -2,12 +2,10 @@ use core::marker::PhantomData; use necsim_core::{ cogs::{ - coalescence_sampler::CoalescenceRngSample, - distribution::{Bernoulli, UniformClosedOpenUnit}, - event_sampler::EventHandler, - Backup, CoalescenceSampler, DispersalSampler, Distribution, EmigrationExit, EventSampler, - Habitat, LocallyCoherentLineageStore, MathsCore, Rng, Samples, SpeciationProbability, - TurnoverRate, + coalescence_sampler::CoalescenceRngSample, distribution::Bernoulli, + event_sampler::EventHandler, Backup, CoalescenceSampler, DispersalSampler, Distribution, + EmigrationExit, EventSampler, Habitat, LocallyCoherentLineageStore, MathsCore, Rng, + Samples, SpeciationProbability, TurnoverRate, }, event::{DispersalEvent, SpeciationEvent}, lineage::Lineage, @@ -20,7 +18,7 @@ use necsim_core_bond::PositiveF64; pub struct UnconditionalEventSampler< M: MathsCore, H: Habitat, - G: Rng + Samples + Samples, + G: Rng + Samples, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -35,7 +33,7 @@ pub struct UnconditionalEventSampler< impl< M: MathsCore, H: Habitat, - G: Rng + Samples + Samples, + G: Rng + Samples, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -55,7 +53,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: Rng + Samples + Samples, + G: Rng + Samples, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, @@ -75,7 +73,7 @@ impl< impl< M: MathsCore, H: Habitat, - G: Rng + Samples + Samples, + G: Rng + Samples, S: LocallyCoherentLineageStore, X: EmigrationExit, D: DispersalSampler, diff --git a/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/mod.rs b/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/mod.rs index a3765b19f..eac3ce204 100644 --- a/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/mod.rs +++ b/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/mod.rs @@ -196,7 +196,7 @@ impl> UniformlySampleableHabitat for WrappingNoise fn sample_habitable_indexed_location(&self, rng: &mut G) -> IndexedLocation { // Rejection sample until a habitable location is found let location = loop { - let index = rng.sample_u64(); + let index = rng.generator().sample_u64(); let location = Location::new( (index & 0xFFFF_FFFF) as u32, diff --git a/necsim/impls/no-std/src/cogs/rng/rand.rs b/necsim/impls/no-std/src/cogs/rng/rand.rs index c5a698844..bf234c255 100644 --- a/necsim/impls/no-std/src/cogs/rng/rand.rs +++ b/necsim/impls/no-std/src/cogs/rng/rand.rs @@ -454,6 +454,7 @@ impl DistributionSampler 0 let poisson = unsafe { RandPoisson::new(lambda.get()).unwrap_unchecked() }; + // Note: rust clamps f64 as u64 to [0, 2^64 - 1] #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)] { poisson.sample(rng) as u64 diff --git a/necsim/impls/no-std/src/cogs/rng/simple.rs b/necsim/impls/no-std/src/cogs/rng/simple.rs index 0d0d609e3..521d3ac01 100644 --- a/necsim/impls/no-std/src/cogs/rng/simple.rs +++ b/necsim/impls/no-std/src/cogs/rng/simple.rs @@ -124,6 +124,7 @@ impl usize { let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); - #[allow( - clippy::cast_precision_loss, - clippy::cast_possible_truncation, - clippy::cast_sign_loss - )] - let index = M::floor(u01.get() * (length.get() as f64)) as usize; - - // Safety in case of f64 rounding errors - index.min(length.get() - 1) + // Safety: U[0, 1) * length in [0, 2^[32/64]) is a valid [u32/u64] + // since (1 - 2^-53) * 2^[32/64] <= (2^[32/64] - 1) + #[allow(clippy::cast_precision_loss)] + let index = + unsafe { M::floor(u01.get() * (length.get() as f64)).to_int_unchecked::() }; + + if cfg!(target_pointer_width = "32") { + // Note: [0, 2^32) is losslessly represented in f64 + index + } else { + // Note: Ensure index < length despite + // usize->f64->usize precision loss + index.min(length.get() - 1) + } } } @@ -161,11 +167,9 @@ impl u32 { let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); - #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] - let index = M::floor(u01.get() * f64::from(length.get())) as u32; - - // Safety in case of f64 rounding errors - index.min(length.get() - 1) + // Safety: U[0, 1) * length in [0, 2^32) is losslessly represented + // in both f64 and u32 + unsafe { M::floor(u01.get() * f64::from(length.get())).to_int_unchecked::() } } } @@ -186,14 +190,13 @@ impl u64 { let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); - #[allow( - clippy::cast_precision_loss, - clippy::cast_possible_truncation, - clippy::cast_sign_loss - )] - let index = M::floor(u01.get() * (length.get() as f64)) as u64; + // Safety: U[0, 1) * length in [0, 2^64) is a valid u64 + // since (1 - 2^-53) * 2^64 <= (2^64 - 1) + #[allow(clippy::cast_precision_loss)] + let index = + unsafe { M::floor(u01.get() * (length.get() as f64)).to_int_unchecked::() }; - // Safety in case of f64 rounding errors + // Note: Ensure index < length despite u64->f64->u64 precision loss index.min(length.get() - 1) } } @@ -215,14 +218,13 @@ impl u128 { let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); - #[allow( - clippy::cast_precision_loss, - clippy::cast_possible_truncation, - clippy::cast_sign_loss - )] - let index = M::floor(u01.get() * (length.get() as f64)) as u128; + // Safety: U[0, 1) * length in [0, 2^128) is a valid u128 + // since (1 - 2^-53) * 2^128 <= (2^128 - 1) + #[allow(clippy::cast_precision_loss)] + let index = + unsafe { M::floor(u01.get() * (length.get() as f64)).to_int_unchecked::() }; - // Safety in case of f64 rounding errors + // Note: Ensure index < length despite u128->f64->u128 precision loss index.min(length.get() - 1) } } @@ -267,6 +269,7 @@ impl< if no_event_probability <= 0.0_f64 { // Fallback in case no_event_probability_per_step underflows + // Note: rust clamps f64 as u64 to [0, 2^64 - 1] #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] let normal_as_poisson = Normal2D::sample_raw_with( rng, @@ -276,8 +279,7 @@ impl< sigma: NonNegativeF64::from(lambda).sqrt::(), }, ) - .0 - .max(0.0_f64) as u64; + .0 as u64; return normal_as_poisson; } @@ -300,8 +302,8 @@ impl< } } -impl> - DistributionSampler for SimplerDistributionSamplers +impl DistributionSampler + for SimplerDistributionSamplers { type ConcreteSampler = Self; @@ -309,12 +311,21 @@ impl bool { - let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); - - // if probability == 1, then U[0, 1) always < 1.0 - // if probability == 0, then U[0, 1) never < 0.0 - u01 < probability + fn sample_distribution(&self, rng: &mut R, _samplers: &S, probability: ClosedUnitF64) -> bool { + #[allow(clippy::cast_precision_loss)] + const SCALE: f64 = 2.0 * (1u64 << 63) as f64; + + // Safety: + // (a) 0 <= probability < 1: probability * SCALE is in [0, 2^64) + // since 1 - 2^-53 is before 1.0 + // (b) probability == 1 : p_u64 is undefined + // this case is checked for in the return + let p_u64 = unsafe { (probability.get() * SCALE).to_int_unchecked::() }; + + #[allow(clippy::float_cmp)] + { + (rng.sample_u64() < p_u64) || (probability == 1.0_f64) + } } } diff --git a/necsim/impls/no-std/src/decomposition/equal/mod.rs b/necsim/impls/no-std/src/decomposition/equal/mod.rs index 885c88103..531d775ef 100644 --- a/necsim/impls/no-std/src/decomposition/equal/mod.rs +++ b/necsim/impls/no-std/src/decomposition/equal/mod.rs @@ -68,12 +68,15 @@ impl> Decomposition for EqualDecomposition> EqualDecomposition { fn next_log2(coord: OffByOneU32) -> u8 { - #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] - if coord.get() > 1 { - M::ceil(M::ln(f64::from(coord)) / core::f64::consts::LN_2) as u8 - } else { - 0 - } + // OffByOneU32 holds [1, 2^32] + // with leading zeros [63, 31] + // with next log2 [0, 32] + + #[allow(clippy::cast_possible_truncation)] + let log2_floor = (u64::BITS - coord.get().leading_zeros() - 1) as u8; + let round_up = (coord.get() & (coord.get() - 1)) != 0; + + log2_floor + u8::from(round_up) } fn map_x_y_to_morton(mut morton_x: u8, mut morton_y: u8, mut dx: u32, mut dy: u32) -> u64 { diff --git a/necsim/impls/no-std/src/decomposition/radial.rs b/necsim/impls/no-std/src/decomposition/radial.rs index e1786f672..5027042ff 100644 --- a/necsim/impls/no-std/src/decomposition/radial.rs +++ b/necsim/impls/no-std/src/decomposition/radial.rs @@ -37,6 +37,8 @@ impl> Decomposition for RadialDecomposition { } fn map_location_to_subdomain_rank(&self, location: &Location, habitat: &H) -> u32 { + const BELOW_ONE: f64 = f64::from_bits(0x3FEF_FFFF_FFFF_FFFF_u64); + let extent = habitat.get_extent(); let neutral_x = location.x().wrapping_sub(extent.x()); @@ -50,10 +52,12 @@ impl> Decomposition for RadialDecomposition { * 0.5_f64) + 0.5_f64; - #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] - { - (M::floor(f64::from(self.subdomain.size().get()) * fraction) as u32) - .min(self.subdomain.size().get() - 1) + let fraction = fraction.clamp(0.0_f64, BELOW_ONE); + + // Safety: [0, 1) * subdomain.size in [0, 2^32) is losslessly + // represented in both f64 and u32 + unsafe { + M::floor(fraction * f64::from(self.subdomain.size().get())).to_int_unchecked::() } } } diff --git a/necsim/impls/no-std/src/lib.rs b/necsim/impls/no-std/src/lib.rs index fda8c949f..8f1617714 100644 --- a/necsim/impls/no-std/src/lib.rs +++ b/necsim/impls/no-std/src/lib.rs @@ -11,6 +11,7 @@ #![feature(negative_impls)] #![feature(impl_trait_in_assoc_type)] #![feature(associated_type_bounds)] +#![feature(const_float_bits_conv)] #![allow(incomplete_features)] #![feature(specialization)] diff --git a/necsim/impls/no-std/src/parallelisation/independent/landscape.rs b/necsim/impls/no-std/src/parallelisation/independent/landscape.rs index a76569904..122f7d7b7 100644 --- a/necsim/impls/no-std/src/parallelisation/independent/landscape.rs +++ b/necsim/impls/no-std/src/parallelisation/independent/landscape.rs @@ -1,7 +1,7 @@ use alloc::{collections::VecDeque, vec::Vec}; use core::{ iter::FromIterator, - num::{NonZeroU64, Wrapping}, + num::{NonZeroU32, NonZeroU64, Wrapping}, ops::ControlFlow, }; @@ -184,12 +184,17 @@ pub fn simulate< tie_breaker: _, } = immigrant; + // Safety: immigrant can only migrate to habitable target + let habitat_at_location = unsafe { + NonZeroU32::new_unchecked( + simulation + .habitat() + .get_habitat_at_location(&dispersal_target), + ) + }; + // Finish sampling the dispersal of the immigrating individual - let target_index = coalescence_rng_sample.sample_coalescence_index::( - simulation - .habitat() - .get_habitat_at_location(&dispersal_target), - ); + let target_index = coalescence_rng_sample.sample_coalescence_index(habitat_at_location); let dispersal_target = IndexedLocation::new(dispersal_target, target_index); // Cache the immigration event diff --git a/necsim/impls/no-std/src/parallelisation/independent/mod.rs b/necsim/impls/no-std/src/parallelisation/independent/mod.rs index 2af9e12e5..fa1db0b53 100644 --- a/necsim/impls/no-std/src/parallelisation/independent/mod.rs +++ b/necsim/impls/no-std/src/parallelisation/independent/mod.rs @@ -40,6 +40,7 @@ impl DedupCache { DirectMappedCache::with_capacity(match self { DedupCache::Absolute(AbsoluteCapacity { capacity }) => capacity.get(), DedupCache::Relative(RelativeCapacity { factor }) => { + // Note: rust clamps f64 as usize to [0, 2^[32/64] - 1] #[allow( clippy::cast_precision_loss, clippy::cast_sign_loss, @@ -67,6 +68,7 @@ impl EventSlice { match self { EventSlice::Absolute(AbsoluteCapacity { capacity }) => capacity, EventSlice::Relative(RelativeCapacity { factor }) => { + // Note: rust clamps f64 as usize to [0, 2^[32/64] - 1] #[allow( clippy::cast_precision_loss, clippy::cast_sign_loss, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs index ecca829c7..7d052e903 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - distribution::{Bernoulli, Exponential, IndexUsize, UniformClosedOpenUnit}, + distribution::{Bernoulli, Exponential, IndexUsize}, EmigrationExit, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, Samples, }, event::DispersalEvent, @@ -49,11 +49,7 @@ pub struct FixUpInitialiser> { impl< L: ExactSizeIterator, M: MathsCore, - G: Rng - + Samples - + Samples - + Samples - + Samples, + G: Rng + Samples + Samples + Samples, O: Scenario, > ClassicalLineageStoreSampleInitialiser> for FixUpInitialiser { diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/genesis.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/genesis.rs index 1df6aac38..1528cf6ba 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/genesis.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - distribution::{Bernoulli, Exponential, IndexUsize, UniformClosedOpenUnit}, + distribution::{Bernoulli, Exponential, IndexUsize}, EmigrationExit, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, Samples, }, reporter::Reporter, @@ -22,11 +22,7 @@ pub struct GenesisInitialiser; impl< M: MathsCore, - G: Rng - + Samples - + Samples - + Samples - + Samples, + G: Rng + Samples + Samples + Samples, O: Scenario, > ClassicalLineageStoreSampleInitialiser for GenesisInitialiser { diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/mod.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/mod.rs index 6f694b803..6ef6014ba 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/mod.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - distribution::{Bernoulli, IndexUsize, UniformClosedOpenUnit}, + distribution::{Bernoulli, IndexUsize}, ActiveLineageSampler, DispersalSampler, EmigrationExit, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, Samples, }, @@ -24,7 +24,7 @@ pub mod resume; #[allow(clippy::module_name_repetitions)] pub trait ClassicalLineageStoreSampleInitialiser< M: MathsCore, - G: Rng + Samples + Samples + Samples, + G: Rng + Samples + Samples, O: Scenario, Error, > diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/resume.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/resume.rs index 458177523..d7ab6eceb 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/resume.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/resume.rs @@ -1,6 +1,6 @@ use necsim_core::{ cogs::{ - distribution::{Bernoulli, Exponential, IndexUsize, UniformClosedOpenUnit}, + distribution::{Bernoulli, Exponential, IndexUsize}, EmigrationExit, ImmigrationEntry, LocallyCoherentLineageStore, MathsCore, Rng, Samples, }, lineage::Lineage, @@ -29,11 +29,7 @@ pub struct ResumeInitialiser> { impl< L: ExactSizeIterator, M: MathsCore, - G: Rng - + Samples - + Samples - + Samples - + Samples, + G: Rng + Samples + Samples + Samples, O: Scenario, > ClassicalLineageStoreSampleInitialiser> for ResumeInitialiser { From ce753112765ce9aa5cc0591b75a9f8a150a37db4 Mon Sep 17 00:00:00 2001 From: Momo Langenstein Date: Sun, 22 May 2022 08:48:47 +0000 Subject: [PATCH 17/42] Implemented untested modular distribution samplers --- necsim/core/bond/src/closed_open_unit_f64.rs | 8 + necsim/core/bond/src/open_closed_unit_f64.rs | 10 +- .../src/cogs/distribution/bernoulli_64b.rs | 32 ++ .../cogs/distribution/bernoulli_from_unit.rs | 24 ++ .../src/cogs/distribution/exp_inversion.rs | 30 ++ .../src/cogs/distribution/index_from_unit.rs | 124 +++++++ .../src/cogs/distribution/index_from_wide.rs | 135 ++++++++ .../src/cogs/distribution/index_rejection.rs | 166 +++++++++ .../impls/no-std/src/cogs/distribution/mod.rs | 12 + .../no-std/src/cogs/distribution/normal2d.rs | 28 ++ .../cogs/distribution/poisson_inversion.rs | 59 ++++ .../no-std/src/cogs/distribution/rand.rs | 233 +++++++++++++ .../distribution/std_normal2d_box_muller.rs | 33 ++ .../src/cogs/distribution/uniform_53b_unit.rs | 47 +++ .../cogs/distribution/uniform_binexp_unit.rs | 105 ++++++ necsim/impls/no-std/src/cogs/mod.rs | 1 + necsim/impls/no-std/src/cogs/rng/rand.rs | 249 +------------ necsim/impls/no-std/src/cogs/rng/simple.rs | 326 ++++++++---------- necsim/impls/no-std/src/lib.rs | 1 + 19 files changed, 1191 insertions(+), 432 deletions(-) create mode 100644 necsim/impls/no-std/src/cogs/distribution/bernoulli_64b.rs create mode 100644 necsim/impls/no-std/src/cogs/distribution/bernoulli_from_unit.rs create mode 100644 necsim/impls/no-std/src/cogs/distribution/exp_inversion.rs create mode 100644 necsim/impls/no-std/src/cogs/distribution/index_from_unit.rs create mode 100644 necsim/impls/no-std/src/cogs/distribution/index_from_wide.rs create mode 100644 necsim/impls/no-std/src/cogs/distribution/index_rejection.rs create mode 100644 necsim/impls/no-std/src/cogs/distribution/mod.rs create mode 100644 necsim/impls/no-std/src/cogs/distribution/normal2d.rs create mode 100644 necsim/impls/no-std/src/cogs/distribution/poisson_inversion.rs create mode 100644 necsim/impls/no-std/src/cogs/distribution/rand.rs create mode 100644 necsim/impls/no-std/src/cogs/distribution/std_normal2d_box_muller.rs create mode 100644 necsim/impls/no-std/src/cogs/distribution/uniform_53b_unit.rs create mode 100644 necsim/impls/no-std/src/cogs/distribution/uniform_binexp_unit.rs diff --git a/necsim/core/bond/src/closed_open_unit_f64.rs b/necsim/core/bond/src/closed_open_unit_f64.rs index ebadc9f85..d31b90c15 100644 --- a/necsim/core/bond/src/closed_open_unit_f64.rs +++ b/necsim/core/bond/src/closed_open_unit_f64.rs @@ -45,6 +45,14 @@ impl From for f64 { } } +impl TryFrom for ClosedOpenUnitF64 { + type Error = ClosedOpenUnitF64Error; + + fn try_from(value: ClosedUnitF64) -> Result { + Self::new(value.get()) + } +} + impl fmt::Debug for ClosedOpenUnitF64 { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { struct ClosedOpenUnitF64Range(f64); diff --git a/necsim/core/bond/src/open_closed_unit_f64.rs b/necsim/core/bond/src/open_closed_unit_f64.rs index ef151be16..b60397e26 100644 --- a/necsim/core/bond/src/open_closed_unit_f64.rs +++ b/necsim/core/bond/src/open_closed_unit_f64.rs @@ -8,7 +8,7 @@ use core::{ use necsim_core_maths::MathsCore; use serde::{Deserialize, Serialize}; -use crate::NonPositiveF64; +use crate::{ClosedUnitF64, NonPositiveF64}; #[derive(Debug)] #[allow(clippy::module_name_repetitions)] @@ -46,6 +46,14 @@ impl From for f64 { } } +impl TryFrom for OpenClosedUnitF64 { + type Error = OpenClosedUnitF64Error; + + fn try_from(value: ClosedUnitF64) -> Result { + Self::new(value.get()) + } +} + impl fmt::Debug for OpenClosedUnitF64 { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { struct OpenClosedUnitF64Range(f64); diff --git a/necsim/impls/no-std/src/cogs/distribution/bernoulli_64b.rs b/necsim/impls/no-std/src/cogs/distribution/bernoulli_64b.rs new file mode 100644 index 000000000..b4222a20e --- /dev/null +++ b/necsim/impls/no-std/src/cogs/distribution/bernoulli_64b.rs @@ -0,0 +1,32 @@ +use necsim_core::cogs::{distribution::Bernoulli, DistributionSampler, MathsCore, RngCore}; +use necsim_core_bond::ClosedUnitF64; + +#[allow(clippy::module_name_repetitions)] +pub struct Bernoulli64BitSampler; + +impl DistributionSampler + for Bernoulli64BitSampler +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution(&self, rng: &mut R, _samplers: &S, probability: ClosedUnitF64) -> bool { + #[allow(clippy::cast_precision_loss)] + const SCALE: f64 = 2.0 * (1u64 << 63) as f64; + + // Safety: + // (a) 0 <= probability < 1: probability * SCALE is in [0, 2^64) + // since 1 - 2^-53 is before 1.0 + // (b) probability == 1 : p_u64 is undefined + // this case is checked for in the return + let p_u64 = unsafe { (probability.get() * SCALE).to_int_unchecked::() }; + + #[allow(clippy::float_cmp)] + { + (rng.sample_u64() < p_u64) || (probability == 1.0_f64) + } + } +} diff --git a/necsim/impls/no-std/src/cogs/distribution/bernoulli_from_unit.rs b/necsim/impls/no-std/src/cogs/distribution/bernoulli_from_unit.rs new file mode 100644 index 000000000..df98880c0 --- /dev/null +++ b/necsim/impls/no-std/src/cogs/distribution/bernoulli_from_unit.rs @@ -0,0 +1,24 @@ +use necsim_core::cogs::{ + distribution::{Bernoulli, RawDistribution, UniformClosedOpenUnit}, + DistributionSampler, MathsCore, RngCore, +}; +use necsim_core_bond::ClosedUnitF64; + +#[allow(clippy::module_name_repetitions)] +pub struct BernoulliFromUnitSampler; + +impl> + DistributionSampler for BernoulliFromUnitSampler +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution(&self, rng: &mut R, samplers: &S, probability: ClosedUnitF64) -> bool { + // if probability == 1, then U[0, 1) always < 1.0 + // if probability == 0, then U[0, 1) never < 0.0 + UniformClosedOpenUnit::sample_raw(rng, samplers) < probability + } +} diff --git a/necsim/impls/no-std/src/cogs/distribution/exp_inversion.rs b/necsim/impls/no-std/src/cogs/distribution/exp_inversion.rs new file mode 100644 index 000000000..1e076ad78 --- /dev/null +++ b/necsim/impls/no-std/src/cogs/distribution/exp_inversion.rs @@ -0,0 +1,30 @@ +use necsim_core::cogs::{ + distribution::{Exponential, Lambda, RawDistribution, UniformOpenClosedUnit}, + DistributionSampler, MathsCore, RngCore, +}; +use necsim_core_bond::NonNegativeF64; + +#[allow(clippy::module_name_repetitions)] +pub struct ExponentialInverseTransformSampler; + +impl> + DistributionSampler for ExponentialInverseTransformSampler +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + samplers: &S, + Lambda(lambda): Lambda, + ) -> NonNegativeF64 { + let u01 = UniformOpenClosedUnit::sample_raw(rng, samplers); + + // Inverse transform sample: X = -ln(U(0,1]) / lambda + -u01.ln::() / lambda + } +} diff --git a/necsim/impls/no-std/src/cogs/distribution/index_from_unit.rs b/necsim/impls/no-std/src/cogs/distribution/index_from_unit.rs new file mode 100644 index 000000000..eac54edb9 --- /dev/null +++ b/necsim/impls/no-std/src/cogs/distribution/index_from_unit.rs @@ -0,0 +1,124 @@ +use core::num::{NonZeroU128, NonZeroU32, NonZeroU64, NonZeroUsize}; + +use necsim_core::cogs::{ + distribution::{ + IndexU128, IndexU32, IndexU64, IndexUsize, Length, RawDistribution, UniformClosedOpenUnit, + }, + DistributionSampler, MathsCore, RngCore, +}; + +#[allow(clippy::module_name_repetitions)] +pub struct IndexFromUnitSampler; + +impl> + DistributionSampler for IndexFromUnitSampler +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + samplers: &S, + Length(length): Length, + ) -> usize { + let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); + + // Safety: U[0, 1) * length in [0, 2^[32/64]) is a valid [u32/u64] + // since (1 - 2^-53) * 2^[32/64] <= (2^[32/64] - 1) + #[allow(clippy::cast_precision_loss)] + let index = + unsafe { M::floor(u01.get() * (length.get() as f64)).to_int_unchecked::() }; + + if cfg!(target_pointer_width = "32") { + // Note: [0, 2^32) is losslessly represented in f64 + index + } else { + // Note: Ensure index < length despite + // usize->f64->usize precision loss + index.min(length.get() - 1) + } + } +} + +impl> + DistributionSampler for IndexFromUnitSampler +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + samplers: &S, + Length(length): Length, + ) -> u32 { + let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); + + // Safety: U[0, 1) * length in [0, 2^32) is losslessly represented + // in both f64 and u32 + unsafe { M::floor(u01.get() * f64::from(length.get())).to_int_unchecked::() } + } +} + +impl> + DistributionSampler for IndexFromUnitSampler +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + samplers: &S, + Length(length): Length, + ) -> u64 { + let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); + + // Safety: U[0, 1) * length in [0, 2^64) is a valid u64 + // since (1 - 2^-53) * 2^64 <= (2^64 - 1) + #[allow(clippy::cast_precision_loss)] + let index = + unsafe { M::floor(u01.get() * (length.get() as f64)).to_int_unchecked::() }; + + // Note: Ensure index < length despite u64->f64->u64 precision loss + index.min(length.get() - 1) + } +} + +impl> + DistributionSampler for IndexFromUnitSampler +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + samplers: &S, + Length(length): Length, + ) -> u128 { + let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); + + // Safety: U[0, 1) * length in [0, 2^128) is a valid u128 + // since (1 - 2^-53) * 2^128 <= (2^128 - 1) + #[allow(clippy::cast_precision_loss)] + let index = + unsafe { M::floor(u01.get() * (length.get() as f64)).to_int_unchecked::() }; + + // Note: Ensure index < length despite u128->f64->u128 precision loss + index.min(length.get() - 1) + } +} diff --git a/necsim/impls/no-std/src/cogs/distribution/index_from_wide.rs b/necsim/impls/no-std/src/cogs/distribution/index_from_wide.rs new file mode 100644 index 000000000..514e5a641 --- /dev/null +++ b/necsim/impls/no-std/src/cogs/distribution/index_from_wide.rs @@ -0,0 +1,135 @@ +use core::num::{NonZeroU128, NonZeroU32, NonZeroU64, NonZeroUsize}; + +use necsim_core::cogs::{ + distribution::{IndexU128, IndexU32, IndexU64, IndexUsize, Length, RawDistribution}, + DistributionSampler, MathsCore, RngCore, +}; + +#[allow(clippy::module_name_repetitions)] +pub struct IndexFromWideMulSampler; + +impl DistributionSampler + for IndexFromWideMulSampler +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + #[inline] + fn sample_distribution( + &self, + rng: &mut R, + _samplers: &S, + Length(length): Length, + ) -> usize { + #[allow(clippy::cast_possible_truncation)] + if cfg!(target_pointer_width = "32") { + IndexU32::sample_raw_with::( + rng, + self, + Length(unsafe { NonZeroU32::new_unchecked(length.get() as u32) }), + ) as usize + } else { + IndexU64::sample_raw_with::( + rng, + self, + Length(unsafe { NonZeroU64::new_unchecked(length.get() as u64) }), + ) as usize + } + } +} + +impl DistributionSampler + for IndexFromWideMulSampler +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + _samplers: &S, + Length(length): Length, + ) -> u32 { + // Sample U(0, length - 1) using a widening multiplication + // Note: Some slight bias is traded for only needing one u64 sample + // Note: Should optimise to a single 64 bit (high-only) multiplication + #[allow(clippy::cast_possible_truncation)] + { + (((u128::from(rng.sample_u64()) * u128::from(length.get())) >> 64) & u128::from(!0_u32)) + as u32 + } + } +} + +impl DistributionSampler + for IndexFromWideMulSampler +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + _samplers: &S, + Length(length): Length, + ) -> u64 { + // Sample U(0, length - 1) using a widening multiplication + // Note: Some slight bias is traded for only needing one u64 sample + // Note: Should optimise to a single 64 bit (high-only) multiplication + #[allow(clippy::cast_possible_truncation)] + { + (((u128::from(rng.sample_u64()) * u128::from(length.get())) >> 64) & u128::from(!0_u64)) + as u64 + } + } +} + +impl DistributionSampler + for IndexFromWideMulSampler +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + _samplers: &S, + Length(length): Length, + ) -> u128 { + // Sample U(0, length - 1) using a widening multiplication + // Note: Some slight bias is traded for only needing one u128 sample + + const LOWER_MASK: u128 = !0 >> 64; + + let raw_hi = u128::from(rng.sample_u64()); + let raw_lo = u128::from(rng.sample_u64()); + + // 256-bit multiplication (hi, lo) = (raw_hi, raw_lo) * length + let mut low = raw_lo * (length.get() & LOWER_MASK); + let mut t = low >> 64; + low &= LOWER_MASK; + t += raw_hi * (length.get() & LOWER_MASK); + low += (t & LOWER_MASK) << 64; + let mut high = t >> 64; + t = low >> 64; + // low-only: low &= LOWER_MASK; + t += (length.get() >> 64) * raw_lo; + // low-only: low += (t & LOWER_MASK) << 64; + high += t >> 64; + high += raw_hi * (length.get() >> 64); + + high + } +} diff --git a/necsim/impls/no-std/src/cogs/distribution/index_rejection.rs b/necsim/impls/no-std/src/cogs/distribution/index_rejection.rs new file mode 100644 index 000000000..7d5f3cbcb --- /dev/null +++ b/necsim/impls/no-std/src/cogs/distribution/index_rejection.rs @@ -0,0 +1,166 @@ +use core::num::{NonZeroU128, NonZeroU32, NonZeroU64, NonZeroUsize}; + +use necsim_core::cogs::{ + distribution::{IndexU128, IndexU32, IndexU64, IndexUsize, Length, RawDistribution}, + DistributionSampler, MathsCore, RngCore, +}; + +#[allow(clippy::module_name_repetitions)] +pub struct IndexRejectionSampler; + +impl DistributionSampler + for IndexRejectionSampler +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + #[inline] + fn sample_distribution( + &self, + rng: &mut R, + _samplers: &S, + Length(length): Length, + ) -> usize { + #[allow(clippy::cast_possible_truncation)] + if cfg!(target_pointer_width = "32") { + IndexU32::sample_raw_with::( + rng, + self, + Length(unsafe { NonZeroU32::new_unchecked(length.get() as u32) }), + ) as usize + } else { + IndexU64::sample_raw_with::( + rng, + self, + Length(unsafe { NonZeroU64::new_unchecked(length.get() as u64) }), + ) as usize + } + } +} + +impl DistributionSampler for IndexRejectionSampler { + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + _samplers: &S, + Length(length): Length, + ) -> u32 { + // Adapted from: + // https://docs.rs/rand/0.8.4/rand/distributions/uniform/trait.UniformSampler.html#method.sample_single + + const LOWER_MASK: u64 = !0 >> 32; + + // Conservative approximation of the acceptance zone + let acceptance_zone = (length.get() << length.leading_zeros()).wrapping_sub(1); + + loop { + let raw = rng.sample_u64(); + + let sample_check_lo = (raw & LOWER_MASK) * u64::from(length.get()); + + #[allow(clippy::cast_possible_truncation)] + if (sample_check_lo as u32) <= acceptance_zone { + return (sample_check_lo >> 32) as u32; + } + + let sample_check_hi = (raw >> 32) * u64::from(length.get()); + + #[allow(clippy::cast_possible_truncation)] + if (sample_check_hi as u32) <= acceptance_zone { + return (sample_check_hi >> 32) as u32; + } + } + } +} + +impl DistributionSampler for IndexRejectionSampler { + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + _samplers: &S, + Length(length): Length, + ) -> u64 { + // Adapted from: + // https://docs.rs/rand/0.8.4/rand/distributions/uniform/trait.UniformSampler.html#method.sample_single + + // Conservative approximation of the acceptance zone + let acceptance_zone = (length.get() << length.leading_zeros()).wrapping_sub(1); + + loop { + let raw = rng.sample_u64(); + + let sample_check = u128::from(raw) * u128::from(length.get()); + + #[allow(clippy::cast_possible_truncation)] + if (sample_check as u64) <= acceptance_zone { + return (sample_check >> 64) as u64; + } + } + } +} + +impl DistributionSampler + for IndexRejectionSampler +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + _samplers: &S, + Length(length): Length, + ) -> u128 { + // Adapted from: + // https://docs.rs/rand/0.8.4/rand/distributions/uniform/trait.UniformSampler.html#method.sample_single + + const LOWER_MASK: u128 = !0 >> 64; + + // Conservative approximation of the acceptance zone + let acceptance_zone = (length.get() << length.leading_zeros()).wrapping_sub(1); + + loop { + let raw_hi = u128::from(rng.sample_u64()); + let raw_lo = u128::from(rng.sample_u64()); + + // 256-bit multiplication (hi, lo) = (raw_hi, raw_lo) * length + let mut low = raw_lo * (length.get() & LOWER_MASK); + let mut t = low >> 64; + low &= LOWER_MASK; + t += raw_hi * (length.get() & LOWER_MASK); + low += (t & LOWER_MASK) << 64; + let mut high = t >> 64; + t = low >> 64; + low &= LOWER_MASK; + t += (length.get() >> 64) * raw_lo; + low += (t & LOWER_MASK) << 64; + high += t >> 64; + high += raw_hi * (length.get() >> 64); + + let sample = high; + let check = low; + + if check <= acceptance_zone { + return sample; + } + } + } +} diff --git a/necsim/impls/no-std/src/cogs/distribution/mod.rs b/necsim/impls/no-std/src/cogs/distribution/mod.rs new file mode 100644 index 000000000..99ee5f380 --- /dev/null +++ b/necsim/impls/no-std/src/cogs/distribution/mod.rs @@ -0,0 +1,12 @@ +pub mod bernoulli_64b; +pub mod bernoulli_from_unit; +pub mod exp_inversion; +pub mod index_from_unit; +pub mod index_from_wide; +pub mod index_rejection; +pub mod normal2d; +pub mod poisson_inversion; +pub mod rand; +pub mod std_normal2d_box_muller; +pub mod uniform_53b_unit; +pub mod uniform_binexp_unit; diff --git a/necsim/impls/no-std/src/cogs/distribution/normal2d.rs b/necsim/impls/no-std/src/cogs/distribution/normal2d.rs new file mode 100644 index 000000000..f8b3dd5e9 --- /dev/null +++ b/necsim/impls/no-std/src/cogs/distribution/normal2d.rs @@ -0,0 +1,28 @@ +use necsim_core::cogs::{ + distribution::{Normal, Normal2D, RawDistribution, StandardNormal2D}, + DistributionSampler, MathsCore, RngCore, +}; + +#[allow(clippy::module_name_repetitions)] +pub struct Normal2dSampler; + +impl> + DistributionSampler for Normal2dSampler +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + samplers: &S, + Normal { mu, sigma }: Normal, + ) -> (f64, f64) { + let (z0, z1) = StandardNormal2D::sample_raw(rng, samplers); + + (z0 * sigma.get() + mu, z1 * sigma.get() + mu) + } +} diff --git a/necsim/impls/no-std/src/cogs/distribution/poisson_inversion.rs b/necsim/impls/no-std/src/cogs/distribution/poisson_inversion.rs new file mode 100644 index 000000000..416aae8e5 --- /dev/null +++ b/necsim/impls/no-std/src/cogs/distribution/poisson_inversion.rs @@ -0,0 +1,59 @@ +use necsim_core::cogs::{ + distribution::{Lambda, Normal, Normal2D, Poisson, RawDistribution, UniformClosedOpenUnit}, + DistributionSampler, MathsCore, RngCore, +}; +use necsim_core_bond::NonNegativeF64; + +#[allow(clippy::module_name_repetitions)] +pub struct PoissonInverseTransformOrNormalSampler; + +impl< + M: MathsCore, + R: RngCore, + S: DistributionSampler + + DistributionSampler, + > DistributionSampler for PoissonInverseTransformOrNormalSampler +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution(&self, rng: &mut R, samplers: &S, Lambda(lambda): Lambda) -> u64 { + let no_event_probability = M::exp(-lambda.get()); + + if no_event_probability <= 0.0_f64 { + // Fallback in case no_event_probability_per_step underflows + // Note: rust clamps f64 as u64 to [0, 2^64 - 1] + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + let normal_as_poisson = Normal2D::sample_raw_with( + rng, + samplers, + Normal { + mu: lambda.get(), + sigma: NonNegativeF64::from(lambda).sqrt::(), + }, + ) + .0 as u64; + + return normal_as_poisson; + } + + // https://en.wikipedia.org/w/index.php?title=Poisson_distribution&oldid=1088559556#cite_ref-Devroye1986_61-0 + let mut poisson = 0_u64; + let mut prod = no_event_probability; + let mut acc = no_event_probability; + + let u = UniformClosedOpenUnit::sample_raw(rng, samplers); + + #[allow(clippy::cast_precision_loss)] + while u > acc && prod > 0.0_f64 { + poisson += 1; + prod *= lambda.get() / (poisson as f64); + acc += prod; + } + + poisson + } +} diff --git a/necsim/impls/no-std/src/cogs/distribution/rand.rs b/necsim/impls/no-std/src/cogs/distribution/rand.rs new file mode 100644 index 000000000..7445c4dd5 --- /dev/null +++ b/necsim/impls/no-std/src/cogs/distribution/rand.rs @@ -0,0 +1,233 @@ +use core::num::{NonZeroU128, NonZeroU32, NonZeroU64, NonZeroUsize}; + +use necsim_core::cogs::{ + distribution::{ + Bernoulli, Exponential, IndexU128, IndexU32, IndexU64, IndexUsize, Lambda, Length, Normal, + Normal2D, Poisson, StandardNormal2D, UniformClosedOpenUnit, UniformOpenClosedUnit, + }, + DistributionSampler, MathsCore, RngCore, +}; +use necsim_core_bond::{ClosedOpenUnitF64, ClosedUnitF64, NonNegativeF64, OpenClosedUnitF64}; + +use rand_core::RngCore as RandRngCore; +use rand_distr::{ + uniform::{UniformInt as RandUniformInt, UniformSampler as RandUniformSampler}, + Bernoulli as RandBernoulli, Distribution as RandDistribution, Exp1 as RandExp1, + OpenClosed01 as RandOpenClosed01, Poisson as RandPoisson, Standard as RandStandard, + StandardNormal as RandStandardNormal, +}; + +#[allow(clippy::module_name_repetitions)] +pub struct RandDistributionSamplers; + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution(&self, rng: &mut R, _samplers: &S, _params: ()) -> ClosedOpenUnitF64 { + let u01: f64 = RandStandard.sample(rng); + + // Safety: Standard samples from [0, 1) + unsafe { ClosedOpenUnitF64::new_unchecked(u01) } + } +} + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution(&self, rng: &mut R, _samplers: &S, _params: ()) -> OpenClosedUnitF64 { + let u01: f64 = RandOpenClosed01.sample(rng); + + // Safety: OpenClosed01 samples from (0, 1] + unsafe { OpenClosedUnitF64::new_unchecked(u01) } + } +} + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + _samplers: &S, + Length(length): Length, + ) -> usize { + RandUniformInt::::sample_single(0, length.get(), rng) + } +} + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + _samplers: &S, + Length(length): Length, + ) -> u32 { + RandUniformInt::::sample_single(0, length.get(), rng) + } +} + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + _samplers: &S, + Length(length): Length, + ) -> u64 { + RandUniformInt::::sample_single(0, length.get(), rng) + } +} + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + _samplers: &S, + Length(length): Length, + ) -> u128 { + RandUniformInt::::sample_single(0, length.get(), rng) + } +} + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution( + &self, + rng: &mut R, + _samplers: &S, + Lambda(lambda): Lambda, + ) -> NonNegativeF64 { + let exp1: f64 = RandExp1.sample(rng); + + // Safety: Exp1 samples from [0, +inf) + (unsafe { NonNegativeF64::new_unchecked(exp1) }) / lambda + } +} + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution(&self, rng: &mut R, _samplers: &S, Lambda(lambda): Lambda) -> u64 { + // Safety: PositiveF64 asserts that lambda > 0 + let poisson = unsafe { RandPoisson::new(lambda.get()).unwrap_unchecked() }; + + // Note: rust clamps f64 as u64 to [0, 2^64 - 1] + #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)] + { + poisson.sample(rng) as u64 + } + } +} + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution(&self, rng: &mut R, _samplers: &S, probability: ClosedUnitF64) -> bool { + // Safety: ClosedUnitF64 asserts that probability is in [0.0, 1.0] + let bernoulli = unsafe { RandBernoulli::new(probability.get()).unwrap_unchecked() }; + + bernoulli.sample(rng) + } +} + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution(&self, rng: &mut R, _samplers: &S, _params: ()) -> (f64, f64) { + ( + RandStandardNormal.sample(rng), + RandStandardNormal.sample(rng), + ) + } +} + +impl DistributionSampler + for RandDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + #[inline] + fn sample_distribution( + &self, + rng: &mut R, + _samplers: &S, + Normal { mu, sigma }: Normal, + ) -> (f64, f64) { + let (z0, z1): (f64, f64) = ( + RandStandardNormal.sample(rng), + RandStandardNormal.sample(rng), + ); + + (z0 * sigma.get() + mu, z1 * sigma.get() + mu) + } +} diff --git a/necsim/impls/no-std/src/cogs/distribution/std_normal2d_box_muller.rs b/necsim/impls/no-std/src/cogs/distribution/std_normal2d_box_muller.rs new file mode 100644 index 000000000..ff8ab645f --- /dev/null +++ b/necsim/impls/no-std/src/cogs/distribution/std_normal2d_box_muller.rs @@ -0,0 +1,33 @@ +use necsim_core::cogs::{ + distribution::{ + RawDistribution, StandardNormal2D, UniformClosedOpenUnit, UniformOpenClosedUnit, + }, + DistributionSampler, MathsCore, RngCore, +}; + +pub struct StandardNormal2DBoxMullerSampler; + +impl< + M: MathsCore, + R: RngCore, + S: DistributionSampler + + DistributionSampler, + > DistributionSampler for StandardNormal2DBoxMullerSampler +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution(&self, rng: &mut R, samplers: &S, _params: ()) -> (f64, f64) { + // Basic Box-Muller transform + let u0 = UniformOpenClosedUnit::sample_raw(rng, samplers); + let u1 = UniformClosedOpenUnit::sample_raw(rng, samplers); + + let r = M::sqrt(-2.0_f64 * M::ln(u0.get())); + let theta = -core::f64::consts::TAU * u1.get(); + + (r * M::sin(theta), r * M::cos(theta)) + } +} diff --git a/necsim/impls/no-std/src/cogs/distribution/uniform_53b_unit.rs b/necsim/impls/no-std/src/cogs/distribution/uniform_53b_unit.rs new file mode 100644 index 000000000..5a43ba35c --- /dev/null +++ b/necsim/impls/no-std/src/cogs/distribution/uniform_53b_unit.rs @@ -0,0 +1,47 @@ +use necsim_core::cogs::{ + distribution::{UniformClosedOpenUnit, UniformOpenClosedUnit}, + DistributionSampler, MathsCore, RngCore, +}; +use necsim_core_bond::{ClosedOpenUnitF64, OpenClosedUnitF64}; + +#[allow(clippy::module_name_repetitions)] +pub struct Uniform53BitUnitSampler; + +impl DistributionSampler + for Uniform53BitUnitSampler +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution(&self, rng: &mut R, _samplers: &S, _params: ()) -> ClosedOpenUnitF64 { + // http://prng.di.unimi.it -> Generating uniform doubles in the unit interval + // Copyright (c) 2014, Taylor R Campbell + #[allow(clippy::cast_precision_loss)] + let u01 = ((rng.sample_u64() >> 11) as f64) * f64::from_bits(0x3CA0_0000_0000_0000_u64); // 0x1.0p-53 + + unsafe { ClosedOpenUnitF64::new_unchecked(u01) } + } +} + +impl DistributionSampler + for Uniform53BitUnitSampler +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution(&self, rng: &mut R, _samplers: &S, _params: ()) -> OpenClosedUnitF64 { + // http://prng.di.unimi.it -> Generating uniform doubles in the unit interval + // Copyright (c) 2014, Taylor R Campbell + #[allow(clippy::cast_precision_loss)] + let u01 = + (((rng.sample_u64() >> 11) + 1) as f64) * f64::from_bits(0x3CA0_0000_0000_0000_u64); // 0x1.0p-53 + + unsafe { OpenClosedUnitF64::new_unchecked(u01) } + } +} diff --git a/necsim/impls/no-std/src/cogs/distribution/uniform_binexp_unit.rs b/necsim/impls/no-std/src/cogs/distribution/uniform_binexp_unit.rs new file mode 100644 index 000000000..81c2100cc --- /dev/null +++ b/necsim/impls/no-std/src/cogs/distribution/uniform_binexp_unit.rs @@ -0,0 +1,105 @@ +use core::{ + convert::TryFrom, + intrinsics::{likely, unlikely}, +}; + +use necsim_core::cogs::{ + distribution::{UniformClosedOpenUnit, UniformOpenClosedUnit}, + DistributionSampler, MathsCore, RngCore, +}; +use necsim_core_bond::{ClosedOpenUnitF64, ClosedUnitF64, OpenClosedUnitF64}; + +pub struct UniformUnitBinaryExpansionSampler; + +impl DistributionSampler + for UniformUnitBinaryExpansionSampler +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution(&self, rng: &mut R, _samplers: &S, _params: ()) -> ClosedOpenUnitF64 { + loop { + // Rejection-sample to transform U[0, 1] -> U[0, 1) + if let Ok(u01) = ClosedOpenUnitF64::try_from(sample_closed_unit_f64(rng)) { + return u01; + } + } + } +} + +impl DistributionSampler + for UniformUnitBinaryExpansionSampler +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + fn sample_distribution(&self, rng: &mut R, _samplers: &S, _params: ()) -> OpenClosedUnitF64 { + loop { + // Rejection-sample to transform U[0, 1] -> U(0, 1] + if let Ok(u01) = OpenClosedUnitF64::try_from(sample_closed_unit_f64(rng)) { + return u01; + } + } + } +} + +// https://prng.di.unimi.it/random_real.c -> random_real +// Copyright (c) 2014, Taylor R Campbell +fn sample_closed_unit_f64(rng: &mut R) -> ClosedUnitF64 { + let mut exponent = -64_i32; + let mut significand: u64; + + // Read zeros into the exponent until we hit a one; + // the rest will go into the significand. + loop { + significand = rng.sample_u64(); + + if likely(significand != 0) { + break; + } + + exponent -= 64; + + // If the exponent falls below -1074 = emin + 1 - p, + // the exponent of the smallest subnormal, we are + // guaranteed the result will be rounded to zero. + if unlikely(exponent < -1074) { + return ClosedUnitF64::zero(); + } + } + + // There is a 1 somewhere in significand, not necessarily in + // the most significant position. + // If there are leading zeros, shift them into the exponent + // and refill the less-significant bits of the significand. + #[allow(clippy::cast_possible_wrap)] + let shift = significand.leading_zeros() as i32; + + if shift != 0 { + exponent -= shift; + significand <<= shift; + significand |= rng.sample_u64() >> (64 - shift); + } + + // Set the sticky bit, since there is almost certainly another 1 + // in the bit stream. + // Otherwise, we might round what looks like a tie to even when, + // almost certainly, were we to look further in the bit stream, + // there would be a 1 breaking the tie. + significand |= 1; + + // Finally, convert to double (rounding) and scale by 2^exponent. + #[allow(clippy::cast_precision_loss)] + let u01 = libm::ldexp(significand as f64, exponent); + + // Safety: + // (a) (2^64 - 1) == 2^64 in f64 -> (2^64 - 1) / 2^64 is 1.0 + // (b) 0 / 2^64 is 0.0 + unsafe { ClosedUnitF64::new_unchecked(u01) } +} diff --git a/necsim/impls/no-std/src/cogs/mod.rs b/necsim/impls/no-std/src/cogs/mod.rs index cc94d1886..e221628ae 100644 --- a/necsim/impls/no-std/src/cogs/mod.rs +++ b/necsim/impls/no-std/src/cogs/mod.rs @@ -1,6 +1,7 @@ pub mod active_lineage_sampler; pub mod coalescence_sampler; pub mod dispersal_sampler; +pub mod distribution; pub mod emigration_exit; pub mod event_sampler; pub mod habitat; diff --git a/necsim/impls/no-std/src/cogs/rng/rand.rs b/necsim/impls/no-std/src/cogs/rng/rand.rs index bf234c255..52d828d9a 100644 --- a/necsim/impls/no-std/src/cogs/rng/rand.rs +++ b/necsim/impls/no-std/src/cogs/rng/rand.rs @@ -1,27 +1,12 @@ -use core::{ - fmt, - marker::PhantomData, - num::{NonZeroU128, NonZeroU32, NonZeroU64, NonZeroUsize}, -}; - -use necsim_core::cogs::{ - distribution::{ - Bernoulli, Exponential, IndexU128, IndexU32, IndexU64, IndexUsize, Lambda, Length, Normal, - Normal2D, Poisson, StandardNormal2D, UniformClosedOpenUnit, UniformOpenClosedUnit, - }, - Backup, DistributionSampler, MathsCore, Rng, RngCore, -}; -use necsim_core_bond::{ClosedOpenUnitF64, ClosedUnitF64, NonNegativeF64, OpenClosedUnitF64}; +use core::{fmt, marker::PhantomData}; + +use necsim_core::cogs::{Backup, MathsCore, Rng, RngCore}; use rand_core::{Error, RngCore as RandRngCore, SeedableRng as RandSeedableRng}; -use rand_distr::{ - uniform::{UniformInt, UniformSampler}, - Bernoulli as RandBernoulli, Distribution as RandDistribution, Exp1 as RandExp1, - OpenClosed01 as RandOpenClosed01, Poisson as RandPoisson, Standard as RandStandard, - StandardNormal as RandStandardNormal, -}; use serde::{de::DeserializeOwned, Deserialize, Deserializer, Serialize, Serializer}; +use crate::cogs::distribution::rand::RandDistributionSamplers; + #[allow(clippy::module_name_repetitions)] #[derive(TypeLayout)] #[repr(transparent)] @@ -280,7 +265,7 @@ impl Backup for RandRng { impl Rng for RandRng { type Generator = R; - type Sampler = RandDistributionSamplers; + type Sampler = RandDistributionSamplers; fn generator(&mut self) -> &mut Self::Generator { &mut self.inner @@ -296,226 +281,6 @@ impl Rng for RandRng { } fn with Q, Q>(&mut self, inner: F) -> Q { - let samplers = RandDistributionSamplers { - _marker: PhantomData::<(M, R)>, - }; - - inner(&mut self.inner, &samplers) - } -} - -#[allow(clippy::module_name_repetitions)] -pub struct RandDistributionSamplers { - _marker: PhantomData<(M, R)>, -} - -impl DistributionSampler - for RandDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_distribution(&self, rng: &mut R, _samplers: &S, _params: ()) -> ClosedOpenUnitF64 { - let u01: f64 = RandStandard.sample(rng); - - // Safety: Standard samples from [0, 1) - unsafe { ClosedOpenUnitF64::new_unchecked(u01) } - } -} - -impl DistributionSampler - for RandDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_distribution(&self, rng: &mut R, _samplers: &S, _params: ()) -> OpenClosedUnitF64 { - let u01: f64 = RandOpenClosed01.sample(rng); - - // Safety: OpenClosed01 samples from (0, 1] - unsafe { OpenClosedUnitF64::new_unchecked(u01) } - } -} - -impl DistributionSampler - for RandDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_distribution( - &self, - rng: &mut R, - _samplers: &S, - Length(length): Length, - ) -> usize { - UniformInt::::sample_single(0, length.get(), rng) - } -} - -impl DistributionSampler - for RandDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_distribution( - &self, - rng: &mut R, - _samplers: &S, - Length(length): Length, - ) -> u32 { - UniformInt::::sample_single(0, length.get(), rng) - } -} - -impl DistributionSampler - for RandDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_distribution( - &self, - rng: &mut R, - _samplers: &S, - Length(length): Length, - ) -> u64 { - UniformInt::::sample_single(0, length.get(), rng) - } -} - -impl DistributionSampler - for RandDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_distribution( - &self, - rng: &mut R, - _samplers: &S, - Length(length): Length, - ) -> u128 { - UniformInt::::sample_single(0, length.get(), rng) - } -} - -impl DistributionSampler - for RandDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_distribution( - &self, - rng: &mut R, - _samplers: &S, - Lambda(lambda): Lambda, - ) -> NonNegativeF64 { - let exp1: f64 = RandExp1.sample(rng); - - // Safety: Exp1 samples from [0, +inf) - (unsafe { NonNegativeF64::new_unchecked(exp1) }) / lambda - } -} - -impl DistributionSampler - for RandDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_distribution(&self, rng: &mut R, _samplers: &S, Lambda(lambda): Lambda) -> u64 { - // Safety: PositiveF64 asserts that lambda > 0 - let poisson = unsafe { RandPoisson::new(lambda.get()).unwrap_unchecked() }; - - // Note: rust clamps f64 as u64 to [0, 2^64 - 1] - #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)] - { - poisson.sample(rng) as u64 - } - } -} - -impl DistributionSampler - for RandDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_distribution(&self, rng: &mut R, _samplers: &S, probability: ClosedUnitF64) -> bool { - // Safety: ClosedUnitF64 asserts that probability is in [0.0, 1.0] - let bernoulli = unsafe { RandBernoulli::new(probability.get()).unwrap_unchecked() }; - - bernoulli.sample(rng) - } -} - -impl DistributionSampler - for RandDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_distribution(&self, rng: &mut R, _samplers: &S, _params: ()) -> (f64, f64) { - ( - RandStandardNormal.sample(rng), - RandStandardNormal.sample(rng), - ) - } -} - -impl DistributionSampler - for RandDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_distribution( - &self, - rng: &mut R, - _samplers: &S, - Normal { mu, sigma }: Normal, - ) -> (f64, f64) { - let (z0, z1): (f64, f64) = ( - RandStandardNormal.sample(rng), - RandStandardNormal.sample(rng), - ); - - (z0 * sigma.get() + mu, z1 * sigma.get() + mu) + inner(&mut self.inner, &RandDistributionSamplers) } } diff --git a/necsim/impls/no-std/src/cogs/rng/simple.rs b/necsim/impls/no-std/src/cogs/rng/simple.rs index 521d3ac01..972af8c6f 100644 --- a/necsim/impls/no-std/src/cogs/rng/simple.rs +++ b/necsim/impls/no-std/src/cogs/rng/simple.rs @@ -6,13 +6,20 @@ use core::{ use necsim_core::cogs::{ distribution::{ Bernoulli, Exponential, IndexU128, IndexU32, IndexU64, IndexUsize, Lambda, Length, Normal, - Normal2D, Poisson, RawDistribution, StandardNormal2D, UniformClosedOpenUnit, - UniformOpenClosedUnit, + Normal2D, Poisson, StandardNormal2D, UniformClosedOpenUnit, UniformOpenClosedUnit, }, Backup, DistributionSampler, MathsCore, Rng, RngCore, }; use necsim_core_bond::{ClosedOpenUnitF64, ClosedUnitF64, NonNegativeF64, OpenClosedUnitF64}; +use crate::cogs::distribution::{ + bernoulli_64b::Bernoulli64BitSampler, exp_inversion::ExponentialInverseTransformSampler, + index_from_unit::IndexFromUnitSampler, normal2d::Normal2dSampler, + poisson_inversion::PoissonInverseTransformOrNormalSampler, + std_normal2d_box_muller::StandardNormal2DBoxMullerSampler, + uniform_53b_unit::Uniform53BitUnitSampler, +}; + #[derive(Debug, TypeLayout)] #[allow(clippy::module_name_repetitions)] #[layout(free = "M")] @@ -49,7 +56,7 @@ impl Backup for SimpleRng { impl Rng for SimpleRng { type Generator = R; - type Sampler = SimplerDistributionSamplers; + type Sampler = SimpleDistributionSamplers; fn generator(&mut self) -> &mut Self::Generator { &mut self.inner @@ -65,7 +72,14 @@ impl Rng for SimpleRng { } fn with Q, Q>(&mut self, inner: F) -> Q { - let samplers = SimplerDistributionSamplers { + let samplers = SimpleDistributionSamplers { + u01: Uniform53BitUnitSampler, + index: IndexFromUnitSampler, + exp: ExponentialInverseTransformSampler, + poisson: PoissonInverseTransformOrNormalSampler, + bernoulli: Bernoulli64BitSampler, + std_normal_2d: StandardNormal2DBoxMullerSampler, + normal_2d: Normal2dSampler, _marker: PhantomData::<(M, R)>, }; @@ -74,54 +88,58 @@ impl Rng for SimpleRng { } #[allow(clippy::module_name_repetitions)] -pub struct SimplerDistributionSamplers { +pub struct SimpleDistributionSamplers { + u01: Uniform53BitUnitSampler, + index: IndexFromUnitSampler, + exp: ExponentialInverseTransformSampler, + poisson: PoissonInverseTransformOrNormalSampler, + bernoulli: Bernoulli64BitSampler, + std_normal_2d: StandardNormal2DBoxMullerSampler, + normal_2d: Normal2dSampler, _marker: PhantomData<(M, R)>, } impl DistributionSampler - for SimplerDistributionSamplers + for SimpleDistributionSamplers { - type ConcreteSampler = Self; + type ConcreteSampler = Uniform53BitUnitSampler; fn concrete(&self) -> &Self::ConcreteSampler { - self + &self.u01 } - fn sample_distribution(&self, rng: &mut R, _samplers: &S, _params: ()) -> ClosedOpenUnitF64 { - // http://prng.di.unimi.it -> Generating uniform doubles in the unit interval - #[allow(clippy::cast_precision_loss)] - let u01 = ((rng.sample_u64() >> 11) as f64) * f64::from_bits(0x3CA0_0000_0000_0000_u64); // 0x1.0p-53 - - unsafe { ClosedOpenUnitF64::new_unchecked(u01) } + #[inline] + fn sample_distribution(&self, rng: &mut R, samplers: &S, params: ()) -> ClosedOpenUnitF64 { + DistributionSampler::::sample_distribution( + &self.u01, rng, samplers, params, + ) } } impl DistributionSampler - for SimplerDistributionSamplers + for SimpleDistributionSamplers { - type ConcreteSampler = Self; + type ConcreteSampler = Uniform53BitUnitSampler; fn concrete(&self) -> &Self::ConcreteSampler { - self + &self.u01 } - fn sample_distribution(&self, rng: &mut R, _samplers: &S, _params: ()) -> OpenClosedUnitF64 { - // http://prng.di.unimi.it -> Generating uniform doubles in the unit interval - #[allow(clippy::cast_precision_loss)] - let u01 = - (((rng.sample_u64() >> 11) + 1) as f64) * f64::from_bits(0x3CA0_0000_0000_0000_u64); // 0x1.0p-53 - - unsafe { OpenClosedUnitF64::new_unchecked(u01) } + #[inline] + fn sample_distribution(&self, rng: &mut R, samplers: &S, params: ()) -> OpenClosedUnitF64 { + DistributionSampler::::sample_distribution( + &self.u01, rng, samplers, params, + ) } } impl> - DistributionSampler for SimplerDistributionSamplers + DistributionSampler for SimpleDistributionSamplers { - type ConcreteSampler = Self; + type ConcreteSampler = IndexFromUnitSampler; fn concrete(&self) -> &Self::ConcreteSampler { - self + &self.index } #[inline] @@ -129,125 +147,91 @@ impl, + params: Length, ) -> usize { - let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); - - // Safety: U[0, 1) * length in [0, 2^[32/64]) is a valid [u32/u64] - // since (1 - 2^-53) * 2^[32/64] <= (2^[32/64] - 1) - #[allow(clippy::cast_precision_loss)] - let index = - unsafe { M::floor(u01.get() * (length.get() as f64)).to_int_unchecked::() }; - - if cfg!(target_pointer_width = "32") { - // Note: [0, 2^32) is losslessly represented in f64 - index - } else { - // Note: Ensure index < length despite - // usize->f64->usize precision loss - index.min(length.get() - 1) - } + DistributionSampler::::sample_distribution( + &self.index, + rng, + samplers, + params, + ) } } impl> - DistributionSampler for SimplerDistributionSamplers + DistributionSampler for SimpleDistributionSamplers { - type ConcreteSampler = Self; + type ConcreteSampler = IndexFromUnitSampler; fn concrete(&self) -> &Self::ConcreteSampler { - self + &self.index } - fn sample_distribution( - &self, - rng: &mut R, - samplers: &S, - Length(length): Length, - ) -> u32 { - let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); - - // Safety: U[0, 1) * length in [0, 2^32) is losslessly represented - // in both f64 and u32 - unsafe { M::floor(u01.get() * f64::from(length.get())).to_int_unchecked::() } + #[inline] + fn sample_distribution(&self, rng: &mut R, samplers: &S, params: Length) -> u32 { + DistributionSampler::::sample_distribution( + &self.index, + rng, + samplers, + params, + ) } } impl> - DistributionSampler for SimplerDistributionSamplers + DistributionSampler for SimpleDistributionSamplers { - type ConcreteSampler = Self; + type ConcreteSampler = IndexFromUnitSampler; fn concrete(&self) -> &Self::ConcreteSampler { - self + &self.index } - fn sample_distribution( - &self, - rng: &mut R, - samplers: &S, - Length(length): Length, - ) -> u64 { - let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); - - // Safety: U[0, 1) * length in [0, 2^64) is a valid u64 - // since (1 - 2^-53) * 2^64 <= (2^64 - 1) - #[allow(clippy::cast_precision_loss)] - let index = - unsafe { M::floor(u01.get() * (length.get() as f64)).to_int_unchecked::() }; - - // Note: Ensure index < length despite u64->f64->u64 precision loss - index.min(length.get() - 1) + #[inline] + fn sample_distribution(&self, rng: &mut R, samplers: &S, params: Length) -> u64 { + DistributionSampler::::sample_distribution( + &self.index, + rng, + samplers, + params, + ) } } impl> - DistributionSampler for SimplerDistributionSamplers + DistributionSampler for SimpleDistributionSamplers { - type ConcreteSampler = Self; + type ConcreteSampler = IndexFromUnitSampler; fn concrete(&self) -> &Self::ConcreteSampler { - self + &self.index } - fn sample_distribution( - &self, - rng: &mut R, - samplers: &S, - Length(length): Length, - ) -> u128 { - let u01 = UniformClosedOpenUnit::sample_raw(rng, samplers); - - // Safety: U[0, 1) * length in [0, 2^128) is a valid u128 - // since (1 - 2^-53) * 2^128 <= (2^128 - 1) - #[allow(clippy::cast_precision_loss)] - let index = - unsafe { M::floor(u01.get() * (length.get() as f64)).to_int_unchecked::() }; - - // Note: Ensure index < length despite u128->f64->u128 precision loss - index.min(length.get() - 1) + #[inline] + fn sample_distribution(&self, rng: &mut R, samplers: &S, params: Length) -> u128 { + DistributionSampler::::sample_distribution( + &self.index, + rng, + samplers, + params, + ) } } impl> - DistributionSampler for SimplerDistributionSamplers + DistributionSampler for SimpleDistributionSamplers { - type ConcreteSampler = Self; + type ConcreteSampler = ExponentialInverseTransformSampler; fn concrete(&self) -> &Self::ConcreteSampler { - self + &self.exp } - fn sample_distribution( - &self, - rng: &mut R, - samplers: &S, - Lambda(lambda): Lambda, - ) -> NonNegativeF64 { - let u01 = UniformOpenClosedUnit::sample_raw(rng, samplers); - - // Inverse transform sample: X = -ln(U(0,1]) / lambda - -u01.ln::() / lambda + #[inline] + fn sample_distribution(&self, rng: &mut R, samplers: &S, params: Lambda) -> NonNegativeF64 { + DistributionSampler::::sample_distribution( + &self.exp, rng, samplers, params, + ) } } @@ -256,76 +240,42 @@ impl< R: RngCore, S: DistributionSampler + DistributionSampler, - > DistributionSampler for SimplerDistributionSamplers + > DistributionSampler for SimpleDistributionSamplers { - type ConcreteSampler = Self; + type ConcreteSampler = PoissonInverseTransformOrNormalSampler; fn concrete(&self) -> &Self::ConcreteSampler { - self + &self.poisson } - fn sample_distribution(&self, rng: &mut R, samplers: &S, Lambda(lambda): Lambda) -> u64 { - let no_event_probability = M::exp(-lambda.get()); - - if no_event_probability <= 0.0_f64 { - // Fallback in case no_event_probability_per_step underflows - // Note: rust clamps f64 as u64 to [0, 2^64 - 1] - #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] - let normal_as_poisson = Normal2D::sample_raw_with( - rng, - samplers, - Normal { - mu: lambda.get(), - sigma: NonNegativeF64::from(lambda).sqrt::(), - }, - ) - .0 as u64; - - return normal_as_poisson; - } - - // https://en.wikipedia.org/wiki/Poisson_distribution#cite_ref-Devroye1986_54-0 - let mut poisson = 0_u64; - let mut prod = no_event_probability; - let mut acc = no_event_probability; - - let u = UniformClosedOpenUnit::sample_raw(rng, samplers); - - #[allow(clippy::cast_precision_loss)] - while u > acc && prod > 0.0_f64 { - poisson += 1; - prod *= lambda.get() / (poisson as f64); - acc += prod; - } - - poisson + #[inline] + fn sample_distribution(&self, rng: &mut R, samplers: &S, params: Lambda) -> u64 { + DistributionSampler::::sample_distribution( + &self.poisson, + rng, + samplers, + params, + ) } } impl DistributionSampler - for SimplerDistributionSamplers + for SimpleDistributionSamplers { - type ConcreteSampler = Self; + type ConcreteSampler = Bernoulli64BitSampler; fn concrete(&self) -> &Self::ConcreteSampler { - self + &self.bernoulli } - fn sample_distribution(&self, rng: &mut R, _samplers: &S, probability: ClosedUnitF64) -> bool { - #[allow(clippy::cast_precision_loss)] - const SCALE: f64 = 2.0 * (1u64 << 63) as f64; - - // Safety: - // (a) 0 <= probability < 1: probability * SCALE is in [0, 2^64) - // since 1 - 2^-53 is before 1.0 - // (b) probability == 1 : p_u64 is undefined - // this case is checked for in the return - let p_u64 = unsafe { (probability.get() * SCALE).to_int_unchecked::() }; - - #[allow(clippy::float_cmp)] - { - (rng.sample_u64() < p_u64) || (probability == 1.0_f64) - } + #[inline] + fn sample_distribution(&self, rng: &mut R, samplers: &S, params: ClosedUnitF64) -> bool { + DistributionSampler::::sample_distribution( + &self.bernoulli, + rng, + samplers, + params, + ) } } @@ -334,43 +284,41 @@ impl< R: RngCore, S: DistributionSampler + DistributionSampler, - > DistributionSampler for SimplerDistributionSamplers + > DistributionSampler for SimpleDistributionSamplers { - type ConcreteSampler = Self; + type ConcreteSampler = StandardNormal2DBoxMullerSampler; fn concrete(&self) -> &Self::ConcreteSampler { - self + &self.std_normal_2d } - fn sample_distribution(&self, rng: &mut R, samplers: &S, _params: ()) -> (f64, f64) { - // Basic Box-Muller transform - let u0 = UniformOpenClosedUnit::sample_raw(rng, samplers); - let u1 = UniformClosedOpenUnit::sample_raw(rng, samplers); - - let r = M::sqrt(-2.0_f64 * M::ln(u0.get())); - let theta = -core::f64::consts::TAU * u1.get(); - - (r * M::sin(theta), r * M::cos(theta)) + #[inline] + fn sample_distribution(&self, rng: &mut R, samplers: &S, params: ()) -> (f64, f64) { + DistributionSampler::::sample_distribution( + &self.std_normal_2d, + rng, + samplers, + params, + ) } } impl> - DistributionSampler for SimplerDistributionSamplers + DistributionSampler for SimpleDistributionSamplers { - type ConcreteSampler = Self; + type ConcreteSampler = Normal2dSampler; fn concrete(&self) -> &Self::ConcreteSampler { - self + &self.normal_2d } - fn sample_distribution( - &self, - rng: &mut R, - samplers: &S, - Normal { mu, sigma }: Normal, - ) -> (f64, f64) { - let (z0, z1) = StandardNormal2D::sample_raw(rng, samplers); - - (z0 * sigma.get() + mu, z1 * sigma.get() + mu) + #[inline] + fn sample_distribution(&self, rng: &mut R, samplers: &S, params: Normal) -> (f64, f64) { + DistributionSampler::::sample_distribution( + &self.normal_2d, + rng, + samplers, + params, + ) } } diff --git a/necsim/impls/no-std/src/lib.rs b/necsim/impls/no-std/src/lib.rs index 8f1617714..f74a06f61 100644 --- a/necsim/impls/no-std/src/lib.rs +++ b/necsim/impls/no-std/src/lib.rs @@ -12,6 +12,7 @@ #![feature(impl_trait_in_assoc_type)] #![feature(associated_type_bounds)] #![feature(const_float_bits_conv)] +#![feature(core_intrinsics)] #![allow(incomplete_features)] #![feature(specialization)] From 1163b6334a27aa2e3ce867150af825a879a57608 Mon Sep 17 00:00:00 2001 From: Momo Langenstein Date: Sun, 22 May 2022 09:14:17 +0000 Subject: [PATCH 18/42] Switch alias sampler tests to modular distribution sampling --- .../alias/sampler/indexed/tests.rs | 159 +---------------- .../alias/sampler/stack/tests.rs | 161 +----------------- .../alias/sampler/tests.rs | 158 ++++++++++++++++- 3 files changed, 165 insertions(+), 313 deletions(-) diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs index 4a95671e1..3186f1623 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/tests.rs @@ -1,14 +1,9 @@ use alloc::{vec, vec::Vec}; -use core::num::{NonZeroU128, NonZeroU64, NonZeroUsize}; use hashbrown::HashMap; -use necsim_core::cogs::{ - distribution::{IndexU128, IndexU64, IndexUsize, Length}, - Backup, DistributionSampler, Rng, RngCore, SeedableRng, -}; +use necsim_core::cogs::{Backup, SeedableRng}; use necsim_core_bond::{NonNegativeF64, PositiveF64}; -use necsim_core_maths::MathsCore; use crate::cogs::{ maths::intrinsics::IntrinsicsMathsCore, @@ -16,8 +11,8 @@ use crate::cogs::{ }; use super::{ - super::decompose_weight, DynamicAliasMethodIndexedSampler, EventLocation, - RejectionSamplingGroup, + super::{decompose_weight, tests::DummyRng}, + DynamicAliasMethodIndexedSampler, EventLocation, RejectionSamplingGroup, }; #[test] @@ -1077,151 +1072,3 @@ fn debug_display_sampler() { "DynamicAliasMethodIndexedSampler { exponents: [2, 1], total_weight: 20.0 }" ); } - -// GRCOV_EXCL_START -#[derive(Debug, serde::Serialize, serde::Deserialize)] -struct DummyRng(Vec); - -impl DummyRng { - fn new(mut vec: Vec) -> Self { - vec.reverse(); - - Self(vec) - } - - fn sample_f64(&mut self) -> f64 { - self.0.pop().unwrap() - } -} - -impl RngCore for DummyRng { - type Seed = [u8; 0]; - - #[must_use] - fn from_seed(_seed: Self::Seed) -> Self { - Self(Vec::new()) - } - - #[must_use] - fn sample_u64(&mut self) -> u64 { - #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] - { - ((self.sample_f64() / f64::from_bits(0x3CA0_0000_0000_0000_u64)) as u64) << 11 - } - } -} - -impl Rng for DummyRng { - type Generator = Self; - type Sampler = DummyDistributionSamplers; - - fn generator(&mut self) -> &mut Self::Generator { - self - } - - fn map_generator Self::Generator>(self, map: F) -> Self { - map(self) - } - - fn with Q, Q>(&mut self, inner: F) -> Q { - let samplers = DummyDistributionSamplers; - - inner(self, &samplers) - } -} - -struct DummyDistributionSamplers; - -impl DistributionSampler - for DummyDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_distribution( - &self, - rng: &mut DummyRng, - _samplers: &DummyDistributionSamplers, - Length(length): Length, - ) -> usize { - let u01 = rng.sample_f64(); - - // Safety: U[0, 1) * length in [0, 2^[32/64]) is a valid [u32/u64] - // since (1 - 2^-53) * 2^[32/64] <= (2^[32/64] - 1) - #[allow(clippy::cast_precision_loss)] - let index = unsafe { - IntrinsicsMathsCore::floor(u01 * (length.get() as f64)).to_int_unchecked::() - }; - - if cfg!(target_pointer_width = "32") { - // Note: [0, 2^32) is losslessly represented in f64 - index - } else { - // Note: Ensure index < length despite - // usize->f64->usize precision loss - index.min(length.get() - 1) - } - } -} - -impl DistributionSampler - for DummyDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_distribution( - &self, - rng: &mut DummyRng, - _samplers: &DummyDistributionSamplers, - Length(length): Length, - ) -> u64 { - let u01 = rng.sample_f64(); - - // Safety: U[0, 1) * length in [0, 2^64) is a valid u64 - // since (1 - 2^-53) * 2^64 <= (2^64 - 1) - #[allow(clippy::cast_precision_loss)] - let index = unsafe { - IntrinsicsMathsCore::floor(u01 * (length.get() as f64)).to_int_unchecked::() - }; - - // Note: Ensure index < length despite u64->f64->u64 precision loss - index.min(length.get() - 1) - } -} - -impl DistributionSampler - for DummyDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_distribution( - &self, - rng: &mut DummyRng, - _samplers: &DummyDistributionSamplers, - Length(length): Length, - ) -> u128 { - let u01 = rng.sample_f64(); - - // Safety: U[0, 1) * length in [0, 2^128) is a valid u128 - // since (1 - 2^-53) * 2^128 <= (2^128 - 1) - #[allow(clippy::cast_precision_loss)] - let index = unsafe { - IntrinsicsMathsCore::floor(u01 * (length.get() as f64)).to_int_unchecked::() - }; - - // Note: Ensure index < length despite u128->f64->u128 precision loss - index.min(length.get() - 1) - } -} -// GRCOV_EXCL_STOP diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs index aa0258506..651d18053 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs @@ -1,20 +1,17 @@ -use core::num::{NonZeroU128, NonZeroU64, NonZeroUsize}; - use alloc::{vec, vec::Vec}; -use necsim_core::cogs::{ - distribution::{IndexU128, IndexU64, IndexUsize, Length}, - Backup, DistributionSampler, Rng, RngCore, SeedableRng, -}; +use necsim_core::cogs::{Backup, SeedableRng}; use necsim_core_bond::{NonNegativeF64, PositiveF64}; -use necsim_core_maths::MathsCore; use crate::cogs::{ maths::intrinsics::IntrinsicsMathsCore, rng::{simple::SimpleRng, wyhash::WyHash}, }; -use super::{super::decompose_weight, DynamicAliasMethodStackSampler, RejectionSamplingGroup}; +use super::{ + super::{decompose_weight, tests::DummyRng}, + DynamicAliasMethodStackSampler, RejectionSamplingGroup, +}; #[test] fn singular_event_group() { @@ -576,151 +573,3 @@ fn debug_display_sampler() { "DynamicAliasMethodStackSampler { exponents: [2, 1], total_weight: 20.0 }" ); } - -// GRCOV_EXCL_START -#[derive(Debug, serde::Serialize, serde::Deserialize)] -struct DummyRng(Vec); - -impl DummyRng { - fn new(mut vec: Vec) -> Self { - vec.reverse(); - - Self(vec) - } - - fn sample_f64(&mut self) -> f64 { - self.0.pop().unwrap() - } -} - -impl RngCore for DummyRng { - type Seed = [u8; 0]; - - #[must_use] - fn from_seed(_seed: Self::Seed) -> Self { - Self(Vec::new()) - } - - #[must_use] - fn sample_u64(&mut self) -> u64 { - #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] - { - ((self.sample_f64() / f64::from_bits(0x3CA0_0000_0000_0000_u64)) as u64) << 11 - } - } -} - -impl Rng for DummyRng { - type Generator = Self; - type Sampler = DummyDistributionSamplers; - - fn generator(&mut self) -> &mut Self::Generator { - self - } - - fn map_generator Self::Generator>(self, map: F) -> Self { - map(self) - } - - fn with Q, Q>(&mut self, inner: F) -> Q { - let samplers = DummyDistributionSamplers; - - inner(self, &samplers) - } -} - -struct DummyDistributionSamplers; - -impl DistributionSampler - for DummyDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_distribution( - &self, - rng: &mut DummyRng, - _samplers: &DummyDistributionSamplers, - Length(length): Length, - ) -> usize { - let u01 = rng.sample_f64(); - - // Safety: U[0, 1) * length in [0, 2^[32/64]) is a valid [u32/u64] - // since (1 - 2^-53) * 2^[32/64] <= (2^[32/64] - 1) - #[allow(clippy::cast_precision_loss)] - let index = unsafe { - IntrinsicsMathsCore::floor(u01 * (length.get() as f64)).to_int_unchecked::() - }; - - if cfg!(target_pointer_width = "32") { - // Note: [0, 2^32) is losslessly represented in f64 - index - } else { - // Note: Ensure index < length despite - // usize->f64->usize precision loss - index.min(length.get() - 1) - } - } -} - -impl DistributionSampler - for DummyDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_distribution( - &self, - rng: &mut DummyRng, - _samplers: &DummyDistributionSamplers, - Length(length): Length, - ) -> u64 { - let u01 = rng.sample_f64(); - - // Safety: U[0, 1) * length in [0, 2^64) is a valid u64 - // since (1 - 2^-53) * 2^64 <= (2^64 - 1) - #[allow(clippy::cast_precision_loss)] - let index = unsafe { - IntrinsicsMathsCore::floor(u01 * (length.get() as f64)).to_int_unchecked::() - }; - - // Note: Ensure index < length despite u64->f64->u64 precision loss - index.min(length.get() - 1) - } -} - -impl DistributionSampler - for DummyDistributionSamplers -{ - type ConcreteSampler = Self; - - fn concrete(&self) -> &Self::ConcreteSampler { - self - } - - fn sample_distribution( - &self, - rng: &mut DummyRng, - _samplers: &DummyDistributionSamplers, - Length(length): Length, - ) -> u128 { - let u01 = rng.sample_f64(); - - // Safety: U[0, 1) * length in [0, 2^128) is a valid u128 - // since (1 - 2^-53) * 2^128 <= (2^128 - 1) - #[allow(clippy::cast_precision_loss)] - let index = unsafe { - IntrinsicsMathsCore::floor(u01 * (length.get() as f64)).to_int_unchecked::() - }; - - // Note: Ensure index < length despite u128->f64->u128 precision loss - index.min(length.get() - 1) - } -} -// GRCOV_EXCL_STOP diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/tests.rs index 12e94d9ce..931e7345f 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/tests.rs @@ -1,4 +1,16 @@ -use necsim_core_bond::{NonNegativeF64, PositiveF64}; +use alloc::vec::Vec; +use core::num::{NonZeroU128, NonZeroU64, NonZeroUsize}; + +use necsim_core::cogs::{ + distribution::{IndexU128, IndexU64, IndexUsize, Length, UniformClosedOpenUnit}, + DistributionSampler, Rng, RngCore, +}; +use necsim_core_bond::{ClosedOpenUnitF64, NonNegativeF64, PositiveF64}; +use necsim_core_maths::MathsCore; + +use crate::cogs::{ + distribution::index_from_unit::IndexFromUnitSampler, maths::intrinsics::IntrinsicsMathsCore, +}; use super::{compose_weight, decompose_weight, PositiveF64Decomposed}; @@ -143,3 +155,147 @@ fn compose_weights() { compose_weight(-1020, 0x0010_0000_0000_0000_u128) ); } + +// GRCOV_EXCL_START +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub struct DummyRng(Vec); + +impl DummyRng { + pub fn new(mut vec: Vec) -> Self { + vec.reverse(); + + Self(vec) + } + + fn sample_f64(&mut self) -> f64 { + self.0.pop().unwrap() + } +} + +impl RngCore for DummyRng { + type Seed = [u8; 0]; + + #[must_use] + fn from_seed(_seed: Self::Seed) -> Self { + Self(Vec::new()) + } + + #[must_use] + fn sample_u64(&mut self) -> u64 { + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + { + ((self.sample_f64() / f64::from_bits(0x3CA0_0000_0000_0000_u64)) as u64) << 11 + } + } +} + +impl Rng for DummyRng { + type Generator = Self; + type Sampler = DummyDistributionSamplers; + + fn generator(&mut self) -> &mut Self::Generator { + self + } + + fn map_generator Self::Generator>(self, map: F) -> Self { + map(self) + } + + fn with Q, Q>(&mut self, inner: F) -> Q { + let samplers = DummyDistributionSamplers { + index: IndexFromUnitSampler, + }; + + inner(self, &samplers) + } +} + +pub struct DummyDistributionSamplers { + index: IndexFromUnitSampler, +} + +impl DistributionSampler + for DummyDistributionSamplers +{ + type ConcreteSampler = Self; + + fn concrete(&self) -> &Self::ConcreteSampler { + self + } + + #[inline] + fn sample_distribution( + &self, + rng: &mut DummyRng, + _samplers: &S, + _params: (), + ) -> ClosedOpenUnitF64 { + ClosedOpenUnitF64::new(rng.sample_f64()).unwrap() + } +} + +impl> + DistributionSampler for DummyDistributionSamplers +{ + type ConcreteSampler = IndexFromUnitSampler; + + fn concrete(&self) -> &Self::ConcreteSampler { + &self.index + } + + #[inline] + fn sample_distribution( + &self, + rng: &mut R, + samplers: &S, + params: Length, + ) -> usize { + DistributionSampler::::sample_distribution( + &self.index, + rng, + samplers, + params, + ) + } +} + +impl> + DistributionSampler for DummyDistributionSamplers +{ + type ConcreteSampler = IndexFromUnitSampler; + + fn concrete(&self) -> &Self::ConcreteSampler { + &self.index + } + + #[inline] + fn sample_distribution(&self, rng: &mut R, samplers: &S, params: Length) -> u64 { + DistributionSampler::::sample_distribution( + &self.index, + rng, + samplers, + params, + ) + } +} + +impl> + DistributionSampler for DummyDistributionSamplers +{ + type ConcreteSampler = IndexFromUnitSampler; + + fn concrete(&self) -> &Self::ConcreteSampler { + &self.index + } + + #[inline] + fn sample_distribution(&self, rng: &mut R, samplers: &S, params: Length) -> u128 { + DistributionSampler::::sample_distribution( + &self.index, + rng, + samplers, + params, + ) + } +} +// GRCOV_EXCL_STOP From c10953afba6db178639297263560fdd2b24444ed Mon Sep 17 00:00:00 2001 From: Momo Langenstein Date: Mon, 23 May 2022 07:02:50 +0000 Subject: [PATCH 19/42] Removed MathsCore usage from OriginSampler --- .../alias/sampler/tests.rs | 9 ++++- .../cogs/origin_sampler/almost_infinite.rs | 19 +++++----- .../src/cogs/origin_sampler/decomposition.rs | 4 +- .../src/cogs/origin_sampler/in_memory.rs | 8 ++-- .../no-std/src/cogs/origin_sampler/mod.rs | 5 ++- .../src/cogs/origin_sampler/non_spatial.rs | 8 ++-- .../src/cogs/origin_sampler/pre_sampler.rs | 37 +++++++++---------- .../src/cogs/origin_sampler/resuming.rs | 18 +++++---- .../cogs/origin_sampler/spatially_implicit.rs | 9 ++--- .../impls/no-std/src/decomposition/radial.rs | 4 +- rustcoalescence/algorithms/cuda/src/launch.rs | 2 +- rustcoalescence/algorithms/cuda/src/lib.rs | 6 +-- .../gillespie/src/event_skipping/launch.rs | 2 +- .../gillespie/src/event_skipping/mod.rs | 6 +-- .../src/gillespie/classical/launch.rs | 2 +- .../gillespie/src/gillespie/classical/mod.rs | 6 +-- .../src/gillespie/turnover/launch.rs | 2 +- .../gillespie/src/gillespie/turnover/mod.rs | 6 +-- .../algorithms/independent/src/launch.rs | 2 +- .../algorithms/independent/src/lib.rs | 6 +-- rustcoalescence/algorithms/src/lib.rs | 6 +-- .../scenarios/src/almost_infinite.rs | 2 +- rustcoalescence/scenarios/src/lib.rs | 2 +- rustcoalescence/scenarios/src/non_spatial.rs | 2 +- .../src/spatially_explicit/turnover/map.rs | 2 +- .../spatially_explicit/turnover/uniform.rs | 2 +- .../scenarios/src/spatially_implicit.rs | 2 +- 27 files changed, 97 insertions(+), 82 deletions(-) diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/tests.rs index 931e7345f..bce58597d 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/tests.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/tests.rs @@ -3,7 +3,7 @@ use core::num::{NonZeroU128, NonZeroU64, NonZeroUsize}; use necsim_core::cogs::{ distribution::{IndexU128, IndexU64, IndexUsize, Length, UniformClosedOpenUnit}, - DistributionSampler, Rng, RngCore, + Backup, DistributionSampler, Rng, RngCore, }; use necsim_core_bond::{ClosedOpenUnitF64, NonNegativeF64, PositiveF64}; use necsim_core_maths::MathsCore; @@ -189,6 +189,13 @@ impl RngCore for DummyRng { } } +#[contract_trait] +impl Backup for DummyRng { + unsafe fn backup_unchecked(&self) -> Self { + Self(self.0.clone()) + } +} + impl Rng for DummyRng { type Generator = Self; type Sampler = DummyDistributionSamplers; diff --git a/necsim/impls/no-std/src/cogs/origin_sampler/almost_infinite.rs b/necsim/impls/no-std/src/cogs/origin_sampler/almost_infinite.rs index c18c4a745..7d8c23442 100644 --- a/necsim/impls/no-std/src/cogs/origin_sampler/almost_infinite.rs +++ b/necsim/impls/no-std/src/cogs/origin_sampler/almost_infinite.rs @@ -15,9 +15,11 @@ use super::{TrustedOriginSampler, UntrustedOriginSampler}; const HABITAT_CENTRE: u32 = u32::MAX / 2; +// Note: The MathsCore should not be utilised in the origin sampler +// to improve compatibility #[allow(clippy::module_name_repetitions)] pub struct AlmostInfiniteOriginSampler<'h, M: MathsCore, I: Iterator> { - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, last_index: u64, location_iterator: LocationIterator, radius_squared: u64, @@ -43,7 +45,7 @@ impl<'h, M: MathsCore, I: Iterator> fmt::Debug impl<'h, M: MathsCore, I: Iterator> AlmostInfiniteOriginSampler<'h, M, I> { #[must_use] pub fn new( - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, habitat: &'h AlmostInfiniteHabitat, radius: u16, ) -> Self { @@ -60,12 +62,11 @@ impl<'h, M: MathsCore, I: Iterator> AlmostInfiniteOriginSampler<'h, ); #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] - let upper_bound_size_hint = M::ceil( - f64::from(radius) - * f64::from(radius) - * core::f64::consts::PI - * pre_sampler.get_sample_proportion().get(), - ) as u64; + let upper_bound_size_hint = (f64::from(radius) + * f64::from(radius) + * core::f64::consts::PI + * pre_sampler.get_sample_proportion().get() + + 1.0_f64) as u64; Self { pre_sampler, @@ -89,7 +90,7 @@ impl<'h, M: MathsCore, I: Iterator> UntrustedOriginSampler<'h, M> self.habitat } - fn into_pre_sampler(self) -> OriginPreSampler { + fn into_pre_sampler(self) -> OriginPreSampler { self.pre_sampler } diff --git a/necsim/impls/no-std/src/cogs/origin_sampler/decomposition.rs b/necsim/impls/no-std/src/cogs/origin_sampler/decomposition.rs index 518e26a61..103c36769 100644 --- a/necsim/impls/no-std/src/cogs/origin_sampler/decomposition.rs +++ b/necsim/impls/no-std/src/cogs/origin_sampler/decomposition.rs @@ -12,6 +12,8 @@ use crate::{ decomposition::Decomposition, }; +// Note: The MathsCore should not be utilised in the origin sampler +// (only in the decomposition) to improve compatibility #[allow(clippy::module_name_repetitions)] #[derive(Debug)] pub struct DecompositionOriginSampler< @@ -49,7 +51,7 @@ impl<'d, M: MathsCore, O: UntrustedOriginSampler<'d, M>, D: Decomposition OriginPreSampler { + fn into_pre_sampler(self) -> OriginPreSampler { self.origin_sampler.into_pre_sampler() } diff --git a/necsim/impls/no-std/src/cogs/origin_sampler/in_memory.rs b/necsim/impls/no-std/src/cogs/origin_sampler/in_memory.rs index 4ea417586..7d24dd29d 100644 --- a/necsim/impls/no-std/src/cogs/origin_sampler/in_memory.rs +++ b/necsim/impls/no-std/src/cogs/origin_sampler/in_memory.rs @@ -16,9 +16,11 @@ use crate::cogs::{ use super::{TrustedOriginSampler, UntrustedOriginSampler}; +// Note: The MathsCore should not be utilised in the origin sampler +// to improve compatibility #[allow(clippy::module_name_repetitions)] pub struct InMemoryOriginSampler<'h, M: MathsCore, I: Iterator> { - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, last_index: u64, location_iterator: Peekable, next_location_index: u32, @@ -39,7 +41,7 @@ impl<'h, M: MathsCore, I: Iterator> fmt::Debug for InMemoryOriginSam impl<'h, M: MathsCore, I: Iterator> InMemoryOriginSampler<'h, M, I> { #[must_use] - pub fn new(pre_sampler: OriginPreSampler, habitat: &'h InMemoryHabitat) -> Self { + pub fn new(pre_sampler: OriginPreSampler, habitat: &'h InMemoryHabitat) -> Self { Self { pre_sampler, last_index: 0_u64, @@ -61,7 +63,7 @@ impl<'h, M: MathsCore, I: Iterator> UntrustedOriginSampler<'h, M> self.habitat } - fn into_pre_sampler(self) -> OriginPreSampler { + fn into_pre_sampler(self) -> OriginPreSampler { self.pre_sampler } diff --git a/necsim/impls/no-std/src/cogs/origin_sampler/mod.rs b/necsim/impls/no-std/src/cogs/origin_sampler/mod.rs index a61a2a877..72b08f416 100644 --- a/necsim/impls/no-std/src/cogs/origin_sampler/mod.rs +++ b/necsim/impls/no-std/src/cogs/origin_sampler/mod.rs @@ -19,6 +19,9 @@ use pre_sampler::OriginPreSampler; #[allow(clippy::module_name_repetitions)] /// `Lineage`s produced by the sampler's iterator must have /// * unique global references +/// +/// Note: The MathsCore should not be utilised in the origin sampler +/// to improve compatibility pub trait UntrustedOriginSampler<'h, M: MathsCore>: Sized + core::fmt::Debug + core::iter::Iterator { @@ -27,7 +30,7 @@ pub trait UntrustedOriginSampler<'h, M: MathsCore>: fn habitat(&self) -> &'h Self::Habitat; - fn into_pre_sampler(self) -> OriginPreSampler; + fn into_pre_sampler(self) -> OriginPreSampler; fn full_upper_bound_size_hint(&self) -> u64; } diff --git a/necsim/impls/no-std/src/cogs/origin_sampler/non_spatial.rs b/necsim/impls/no-std/src/cogs/origin_sampler/non_spatial.rs index 8cebb7036..a22e55ad4 100644 --- a/necsim/impls/no-std/src/cogs/origin_sampler/non_spatial.rs +++ b/necsim/impls/no-std/src/cogs/origin_sampler/non_spatial.rs @@ -16,9 +16,11 @@ use crate::cogs::{ use super::{TrustedOriginSampler, UntrustedOriginSampler}; +// Note: The MathsCore should not be utilised in the origin sampler +// to improve compatibility #[allow(clippy::module_name_repetitions)] pub struct NonSpatialOriginSampler<'h, M: MathsCore, I: Iterator> { - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, last_index: u64, location_iterator: Peekable, next_location_index: u32, @@ -39,7 +41,7 @@ impl<'h, M: MathsCore, I: Iterator> fmt::Debug for NonSpatialOriginS impl<'h, M: MathsCore, I: Iterator> NonSpatialOriginSampler<'h, M, I> { #[must_use] - pub fn new(pre_sampler: OriginPreSampler, habitat: &'h NonSpatialHabitat) -> Self { + pub fn new(pre_sampler: OriginPreSampler, habitat: &'h NonSpatialHabitat) -> Self { Self { pre_sampler, last_index: 0_u64, @@ -61,7 +63,7 @@ impl<'h, M: MathsCore, I: Iterator> UntrustedOriginSampler<'h, M> self.habitat } - fn into_pre_sampler(self) -> OriginPreSampler { + fn into_pre_sampler(self) -> OriginPreSampler { self.pre_sampler } diff --git a/necsim/impls/no-std/src/cogs/origin_sampler/pre_sampler.rs b/necsim/impls/no-std/src/cogs/origin_sampler/pre_sampler.rs index d2a133e71..5594c025b 100644 --- a/necsim/impls/no-std/src/cogs/origin_sampler/pre_sampler.rs +++ b/necsim/impls/no-std/src/cogs/origin_sampler/pre_sampler.rs @@ -1,30 +1,27 @@ use core::{ fmt, iter::Empty, - marker::PhantomData, ops::{Deref, DerefMut, RangeFrom}, }; -use necsim_core::cogs::MathsCore; use necsim_core_bond::ClosedUnitF64; use necsim_partitioning_core::partition::Partition; const INV_PHI: f64 = 6.180_339_887_498_949e-1_f64; #[allow(clippy::module_name_repetitions)] -pub struct OriginPreSampler> { +pub struct OriginPreSampler> { inner: I, proportion: ClosedUnitF64, - _marker: PhantomData, } -impl> OriginPreSampler { +impl> OriginPreSampler { pub fn get_sample_proportion(&self) -> ClosedUnitF64 { self.proportion } } -impl> Deref for OriginPreSampler { +impl> Deref for OriginPreSampler { type Target = I; fn deref(&self) -> &Self::Target { @@ -32,13 +29,13 @@ impl> Deref for OriginPreSampler { } } -impl> DerefMut for OriginPreSampler { +impl> DerefMut for OriginPreSampler { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } } -impl> fmt::Debug for OriginPreSampler { +impl> fmt::Debug for OriginPreSampler { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct(stringify!(OriginPreSampler)) .field("proportion", &self.proportion) @@ -46,35 +43,33 @@ impl> fmt::Debug for OriginPreSampler OriginPreSampler> { +impl OriginPreSampler> { #[must_use] pub fn all() -> Self { Self { inner: 0.., proportion: ClosedUnitF64::one(), - _marker: PhantomData::, } } } -impl OriginPreSampler> { +impl OriginPreSampler> { #[must_use] pub fn none() -> Self { Self { inner: core::iter::empty(), proportion: ClosedUnitF64::zero(), - _marker: PhantomData::, } } } -impl> OriginPreSampler { +impl> OriginPreSampler { #[must_use] pub fn percentage( mut self, percentage: ClosedUnitF64, - ) -> OriginPreSampler> { - let inv_geometric_sample_rate = M::ln(1.0_f64 - percentage.get()).recip(); + ) -> OriginPreSampler> { + let inv_geometric_sample_rate = libm::log(1.0_f64 - percentage.get()).recip(); OriginPreSampler { proportion: self.proportion * percentage, @@ -89,27 +84,29 @@ impl> OriginPreSampler { // q = (q + INV_PHI) % 1 where q >= 0 *quasi_random += INV_PHI; - *quasi_random -= M::floor(*quasi_random); + *quasi_random -= if *quasi_random >= 1.0_f64 { + 1.0_f64 + } else { + 0.0_f64 + }; #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)] - let skip = M::floor(M::ln(*quasi_random) * inv_geometric_sample_rate) as usize; + let skip = (libm::log(*quasi_random) * inv_geometric_sample_rate) as usize; self.nth(skip) }), - _marker: PhantomData::, } } pub fn partition( mut self, partition: Partition, - ) -> OriginPreSampler> { + ) -> OriginPreSampler> { let _ = self.advance_by(partition.rank() as usize); OriginPreSampler { proportion: self.proportion / partition.size(), inner: self.inner.step_by(partition.size().get() as usize), - _marker: PhantomData::, } } } diff --git a/necsim/impls/no-std/src/cogs/origin_sampler/resuming.rs b/necsim/impls/no-std/src/cogs/origin_sampler/resuming.rs index 72e6fcf1e..7b8981a5b 100644 --- a/necsim/impls/no-std/src/cogs/origin_sampler/resuming.rs +++ b/necsim/impls/no-std/src/cogs/origin_sampler/resuming.rs @@ -1,4 +1,4 @@ -use core::{fmt, iter::ExactSizeIterator}; +use core::{fmt, iter::ExactSizeIterator, marker::PhantomData}; use necsim_core::{ cogs::{Habitat, MathsCore}, @@ -9,6 +9,8 @@ use crate::cogs::origin_sampler::{pre_sampler::OriginPreSampler, TrustedOriginSa use super::UntrustedOriginSampler; +// Note: The MathsCore should not be utilised in the origin sampler +// to improve compatibility #[allow(clippy::module_name_repetitions)] pub struct ResumingOriginSampler< 'h, @@ -18,9 +20,10 @@ pub struct ResumingOriginSampler< I: Iterator, > { lineage_iterator: L, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, last_index: u64, habitat: &'h H, + marker: PhantomData, } impl< @@ -49,12 +52,13 @@ impl< > ResumingOriginSampler<'h, M, H, L, I> { #[must_use] - pub fn new(habitat: &'h H, pre_sampler: OriginPreSampler, lineage_iterator: L) -> Self { + pub fn new(habitat: &'h H, pre_sampler: OriginPreSampler, lineage_iterator: L) -> Self { Self { lineage_iterator, pre_sampler, last_index: 0_u64, habitat, + marker: PhantomData::, } } } @@ -75,7 +79,7 @@ impl< self.habitat } - fn into_pre_sampler(self) -> OriginPreSampler { + fn into_pre_sampler(self) -> OriginPreSampler { self.pre_sampler } @@ -85,9 +89,9 @@ impl< clippy::cast_possible_truncation, clippy::cast_sign_loss )] - let upper_bound_size_hint = M::ceil( - (self.lineage_iterator.len() as f64) * self.pre_sampler.get_sample_proportion().get(), - ) as u64; + let upper_bound_size_hint = ((self.lineage_iterator.len() as f64) + * self.pre_sampler.get_sample_proportion().get()) + as u64; upper_bound_size_hint } diff --git a/necsim/impls/no-std/src/cogs/origin_sampler/spatially_implicit.rs b/necsim/impls/no-std/src/cogs/origin_sampler/spatially_implicit.rs index 30fe6915b..65b69fe62 100644 --- a/necsim/impls/no-std/src/cogs/origin_sampler/spatially_implicit.rs +++ b/necsim/impls/no-std/src/cogs/origin_sampler/spatially_implicit.rs @@ -9,6 +9,8 @@ use crate::cogs::{ use super::{TrustedOriginSampler, UntrustedOriginSampler}; +// Note: The MathsCore should not be utilised in the origin sampler +// to improve compatibility #[allow(clippy::module_name_repetitions)] pub struct SpatiallyImplicitOriginSampler<'h, M: MathsCore, I: Iterator> { local_iterator: NonSpatialOriginSampler<'h, M, I>, @@ -28,10 +30,7 @@ impl<'h, M: MathsCore, I: Iterator> fmt::Debug impl<'h, M: MathsCore, I: Iterator> SpatiallyImplicitOriginSampler<'h, M, I> { #[must_use] - pub fn new( - pre_sampler: OriginPreSampler, - habitat: &'h SpatiallyImplicitHabitat, - ) -> Self { + pub fn new(pre_sampler: OriginPreSampler, habitat: &'h SpatiallyImplicitHabitat) -> Self { Self { local_iterator: NonSpatialOriginSampler::new(pre_sampler, habitat.local()), habitat, @@ -50,7 +49,7 @@ impl<'h, M: MathsCore, I: Iterator> UntrustedOriginSampler<'h, M> self.habitat } - fn into_pre_sampler(self) -> OriginPreSampler { + fn into_pre_sampler(self) -> OriginPreSampler { self.local_iterator.into_pre_sampler() } diff --git a/necsim/impls/no-std/src/decomposition/radial.rs b/necsim/impls/no-std/src/decomposition/radial.rs index 5027042ff..13ae4d0d3 100644 --- a/necsim/impls/no-std/src/decomposition/radial.rs +++ b/necsim/impls/no-std/src/decomposition/radial.rs @@ -1,5 +1,3 @@ -use libm::atan2; - use necsim_core::{ cogs::{Backup, Habitat, MathsCore}, landscape::Location, @@ -45,7 +43,7 @@ impl> Decomposition for RadialDecomposition { let neutral_y = location.y().wrapping_sub(extent.y()); #[allow(clippy::cast_precision_loss)] - let fraction = (atan2( + let fraction = (libm::atan2( (i64::from(neutral_y) - i64::from(extent.height()) / 2) as f64, (i64::from(neutral_x) - i64::from(extent.width()) / 2) as f64, ) * core::f64::consts::FRAC_1_PI diff --git a/rustcoalescence/algorithms/cuda/src/launch.rs b/rustcoalescence/algorithms/cuda/src/launch.rs index 352754b45..22ec158a6 100644 --- a/rustcoalescence/algorithms/cuda/src/launch.rs +++ b/rustcoalescence/algorithms/cuda/src/launch.rs @@ -60,7 +60,7 @@ pub fn initialise_and_simulate< args: &CudaArguments, rng: WyHash, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, pause_before: Option, local_partition: &mut P, lineage_store_sampler_initialiser: L, diff --git a/rustcoalescence/algorithms/cuda/src/lib.rs b/rustcoalescence/algorithms/cuda/src/lib.rs index eada0dbab..1b25d2543 100644 --- a/rustcoalescence/algorithms/cuda/src/lib.rs +++ b/rustcoalescence/algorithms/cuda/src/lib.rs @@ -354,7 +354,7 @@ where args: Self::Arguments, rng: >::Generator, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, pause_before: Option, local_partition: &mut P, ) -> Result>::Generator>, Self::Error> { @@ -378,7 +378,7 @@ where args: Self::Arguments, rng: >::Generator, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, lineages: L, resume_after: Option, pause_before: Option, @@ -407,7 +407,7 @@ where args: Self::Arguments, rng: >::Generator, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, lineages: L, restart_at: PositiveF64, fixup_strategy: RestartFixUpStrategy, diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs index 207e1d979..43136455f 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/launch.rs @@ -49,7 +49,7 @@ pub fn initialise_and_simulate< args: GillespieArguments, rng: G, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, pause_before: Option, local_partition: &mut P, lineage_store_sampler_initialiser: L, diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/mod.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/mod.rs index 2c473fa3a..fd4c687e2 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/mod.rs @@ -66,7 +66,7 @@ where args: Self::Arguments, rng: >::Generator, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, pause_before: Option, local_partition: &mut P, ) -> Result>::Generator>, Self::Error> { @@ -89,7 +89,7 @@ where args: Self::Arguments, rng: >::Generator, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, lineages: L, resume_after: Option, pause_before: Option, @@ -117,7 +117,7 @@ where args: Self::Arguments, rng: >::Generator, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, lineages: L, restart_at: PositiveF64, fixup_strategy: RestartFixUpStrategy, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs index 0fe808f96..71f3973df 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/launch.rs @@ -49,7 +49,7 @@ pub fn initialise_and_simulate< args: GillespieArguments, rng: G, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, pause_before: Option, local_partition: &mut P, lineage_store_sampler_initialiser: L, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/mod.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/mod.rs index f9c63710a..5d7dab641 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/mod.rs @@ -46,7 +46,7 @@ where args: Self::Arguments, rng: >::Generator, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, pause_before: Option, local_partition: &mut P, ) -> Result>::Generator>, Self::Error> { @@ -69,7 +69,7 @@ where args: Self::Arguments, rng: >::Generator, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, lineages: L, resume_after: Option, pause_before: Option, @@ -98,7 +98,7 @@ where args: Self::Arguments, rng: >::Generator, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, lineages: L, restart_at: PositiveF64, fixup_strategy: RestartFixUpStrategy, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs index e44ad62c9..cf351df41 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/launch.rs @@ -48,7 +48,7 @@ pub fn initialise_and_simulate< args: GillespieArguments, rng: G, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, pause_before: Option, local_partition: &mut P, lineage_store_sampler_initialiser: L, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/mod.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/mod.rs index e78723512..a6d83bfd4 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/mod.rs @@ -54,7 +54,7 @@ where args: Self::Arguments, rng: >::Generator, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, pause_before: Option, local_partition: &mut P, ) -> Result>::Generator>, Self::Error> { @@ -81,7 +81,7 @@ where args: Self::Arguments, rng: >::Generator, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, lineages: L, resume_after: Option, pause_before: Option, @@ -110,7 +110,7 @@ where args: Self::Arguments, rng: >::Generator, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, lineages: L, restart_at: PositiveF64, fixup_strategy: RestartFixUpStrategy, diff --git a/rustcoalescence/algorithms/independent/src/launch.rs b/rustcoalescence/algorithms/independent/src/launch.rs index 4b6da3948..8a91f9910 100644 --- a/rustcoalescence/algorithms/independent/src/launch.rs +++ b/rustcoalescence/algorithms/independent/src/launch.rs @@ -58,7 +58,7 @@ pub fn initialise_and_simulate< args: &IndependentArguments, rng: G, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, pause_before: Option, local_partition: &mut P, lineage_store_sampler_initialiser: L, diff --git a/rustcoalescence/algorithms/independent/src/lib.rs b/rustcoalescence/algorithms/independent/src/lib.rs index 3783060ee..7bc961d63 100644 --- a/rustcoalescence/algorithms/independent/src/lib.rs +++ b/rustcoalescence/algorithms/independent/src/lib.rs @@ -76,7 +76,7 @@ impl< args: Self::Arguments, rng: >::Generator, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, pause_before: Option, local_partition: &mut P, ) -> Result>::Generator>, Self::Error> { @@ -99,7 +99,7 @@ impl< args: Self::Arguments, rng: >::Generator, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, lineages: L, resume_after: Option, pause_before: Option, @@ -128,7 +128,7 @@ impl< args: Self::Arguments, rng: >::Generator, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, lineages: L, restart_at: PositiveF64, fixup_strategy: RestartFixUpStrategy, diff --git a/rustcoalescence/algorithms/src/lib.rs b/rustcoalescence/algorithms/src/lib.rs index b56749b60..c706a9f5f 100644 --- a/rustcoalescence/algorithms/src/lib.rs +++ b/rustcoalescence/algorithms/src/lib.rs @@ -50,7 +50,7 @@ pub trait Algorithm< args: Self::Arguments, rng: >::Generator, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, pause_before: Option, local_partition: &mut P, ) -> Result>::Generator>, Self::Error>; @@ -64,7 +64,7 @@ pub trait Algorithm< args: Self::Arguments, rng: >::Generator, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, lineages: L, resume_after: Option, pause_before: Option, @@ -80,7 +80,7 @@ pub trait Algorithm< args: Self::Arguments, rng: >::Generator, scenario: O, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, lineages: L, restart_at: PositiveF64, fixup_strategy: RestartFixUpStrategy, diff --git a/rustcoalescence/scenarios/src/almost_infinite.rs b/rustcoalescence/scenarios/src/almost_infinite.rs index e908c497c..7327640eb 100644 --- a/rustcoalescence/scenarios/src/almost_infinite.rs +++ b/rustcoalescence/scenarios/src/almost_infinite.rs @@ -104,7 +104,7 @@ impl + Samples> Scenario fn sample_habitat<'h, I: Iterator>( habitat: &'h Self::Habitat, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, (radius,): Self::OriginSamplerAuxiliary, ) -> Self::OriginSampler<'h, I> where diff --git a/rustcoalescence/scenarios/src/lib.rs b/rustcoalescence/scenarios/src/lib.rs index 05bd7a7ac..9d78ed422 100644 --- a/rustcoalescence/scenarios/src/lib.rs +++ b/rustcoalescence/scenarios/src/lib.rs @@ -78,7 +78,7 @@ pub trait Scenario>: Sized + ScenarioParameters { fn sample_habitat<'h, I: Iterator>( habitat: &'h Self::Habitat, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, auxiliary: Self::OriginSamplerAuxiliary, ) -> Self::OriginSampler<'h, I> where diff --git a/rustcoalescence/scenarios/src/non_spatial.rs b/rustcoalescence/scenarios/src/non_spatial.rs index 07df10df9..8e4e5a0a9 100644 --- a/rustcoalescence/scenarios/src/non_spatial.rs +++ b/rustcoalescence/scenarios/src/non_spatial.rs @@ -95,7 +95,7 @@ impl + Samples> Scenario for NonSpati fn sample_habitat<'h, I: Iterator>( habitat: &'h Self::Habitat, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, _auxiliary: Self::OriginSamplerAuxiliary, ) -> Self::OriginSampler<'h, I> where diff --git a/rustcoalescence/scenarios/src/spatially_explicit/turnover/map.rs b/rustcoalescence/scenarios/src/spatially_explicit/turnover/map.rs index f19cb079c..09d0ef43f 100644 --- a/rustcoalescence/scenarios/src/spatially_explicit/turnover/map.rs +++ b/rustcoalescence/scenarios/src/spatially_explicit/turnover/map.rs @@ -130,7 +130,7 @@ impl + Samples> Scenario fn sample_habitat<'h, I: Iterator>( habitat: &'h Self::Habitat, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, _auxiliary: Self::OriginSamplerAuxiliary, ) -> Self::OriginSampler<'h, I> where diff --git a/rustcoalescence/scenarios/src/spatially_explicit/turnover/uniform.rs b/rustcoalescence/scenarios/src/spatially_explicit/turnover/uniform.rs index e19aade26..2faaa8e3c 100644 --- a/rustcoalescence/scenarios/src/spatially_explicit/turnover/uniform.rs +++ b/rustcoalescence/scenarios/src/spatially_explicit/turnover/uniform.rs @@ -128,7 +128,7 @@ impl + Samples> Scenario fn sample_habitat<'h, I: Iterator>( habitat: &'h Self::Habitat, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, _auxiliary: Self::OriginSamplerAuxiliary, ) -> Self::OriginSampler<'h, I> where diff --git a/rustcoalescence/scenarios/src/spatially_implicit.rs b/rustcoalescence/scenarios/src/spatially_implicit.rs index 4933bd6f7..276fddea7 100644 --- a/rustcoalescence/scenarios/src/spatially_implicit.rs +++ b/rustcoalescence/scenarios/src/spatially_implicit.rs @@ -114,7 +114,7 @@ impl + Samples + Samples> Sce fn sample_habitat<'h, I: Iterator>( habitat: &'h Self::Habitat, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, _auxiliary: Self::OriginSamplerAuxiliary, ) -> Self::OriginSampler<'h, I> where From f444ce0dfa9308ed910990f8a18ce1a43058b1d5 Mon Sep 17 00:00:00 2001 From: Juniper Langenstein Date: Sat, 13 Aug 2022 10:04:25 +0000 Subject: [PATCH 20/42] Fixed new 1.63 lints --- necsim/impls/no-std/src/alias/mod.rs | 1 + necsim/impls/no-std/src/alias/packed.rs | 1 + .../src/cogs/active_lineage_sampler/alias/individual/mod.rs | 4 ++++ .../cogs/active_lineage_sampler/alias/individual/sampler.rs | 1 + .../src/cogs/active_lineage_sampler/alias/location/mod.rs | 4 ++++ .../cogs/active_lineage_sampler/alias/location/sampler.rs | 1 + .../active_lineage_sampler/alias/sampler/indexed/mod.rs | 1 + .../cogs/active_lineage_sampler/alias/sampler/stack/mod.rs | 1 + .../no-std/src/cogs/active_lineage_sampler/classical/mod.rs | 3 +++ .../src/cogs/active_lineage_sampler/classical/sampler.rs | 1 + .../independent/event_time_sampler/poisson.rs | 1 + .../src/cogs/dispersal_sampler/in_memory/alias/dispersal.rs | 1 + .../src/cogs/dispersal_sampler/in_memory/alias/mod.rs | 3 +++ .../dispersal_sampler/in_memory/packed_alias/dispersal.rs | 1 + .../cogs/dispersal_sampler/in_memory/packed_alias/mod.rs | 5 +++++ .../in_memory/separable_alias/dispersal.rs | 2 ++ .../cogs/dispersal_sampler/in_memory/separable_alias/mod.rs | 3 +++ .../no-std/src/cogs/dispersal_sampler/spatially_implicit.rs | 6 ++++++ .../impls/no-std/src/cogs/distribution/poisson_inversion.rs | 1 + .../no-std/src/cogs/distribution/std_normal2d_box_muller.rs | 1 + necsim/impls/no-std/src/cogs/rng/simple.rs | 2 ++ rustcoalescence/algorithms/cuda/src/initialiser/fixup.rs | 1 + rustcoalescence/algorithms/cuda/src/initialiser/genesis.rs | 1 + rustcoalescence/algorithms/cuda/src/initialiser/mod.rs | 1 + rustcoalescence/algorithms/cuda/src/initialiser/resume.rs | 1 + .../gillespie/src/event_skipping/initialiser/fixup.rs | 1 + .../gillespie/src/event_skipping/initialiser/genesis.rs | 1 + .../gillespie/src/event_skipping/initialiser/mod.rs | 1 + .../gillespie/src/event_skipping/initialiser/resume.rs | 1 + .../gillespie/src/gillespie/classical/initialiser/fixup.rs | 1 + .../src/gillespie/classical/initialiser/genesis.rs | 1 + .../gillespie/src/gillespie/classical/initialiser/mod.rs | 1 + .../gillespie/src/gillespie/classical/initialiser/resume.rs | 1 + .../gillespie/src/gillespie/turnover/initialiser/fixup.rs | 1 + .../gillespie/src/gillespie/turnover/initialiser/genesis.rs | 1 + .../gillespie/src/gillespie/turnover/initialiser/mod.rs | 1 + .../gillespie/src/gillespie/turnover/initialiser/resume.rs | 1 + .../algorithms/independent/src/initialiser/fixup.rs | 1 + .../algorithms/independent/src/initialiser/genesis.rs | 1 + .../algorithms/independent/src/initialiser/mod.rs | 1 + .../algorithms/independent/src/initialiser/resume.rs | 1 + rustcoalescence/scenarios/src/spatially_implicit.rs | 3 +++ 42 files changed, 67 insertions(+) diff --git a/necsim/impls/no-std/src/alias/mod.rs b/necsim/impls/no-std/src/alias/mod.rs index 437c52346..54707702a 100644 --- a/necsim/impls/no-std/src/alias/mod.rs +++ b/necsim/impls/no-std/src/alias/mod.rs @@ -93,6 +93,7 @@ impl AliasMethodSampler { Self { Us, Es, Ks } } + #[allow(clippy::trait_duplication_in_bounds)] #[debug_ensures(self.Es.contains(&ret), "returns one of the weighted events")] pub fn sample_event< M: MathsCore, diff --git a/necsim/impls/no-std/src/alias/packed.rs b/necsim/impls/no-std/src/alias/packed.rs index f7019c08d..d9f162d6a 100644 --- a/necsim/impls/no-std/src/alias/packed.rs +++ b/necsim/impls/no-std/src/alias/packed.rs @@ -106,6 +106,7 @@ impl AliasMethodSamplerAtom { } #[allow(clippy::no_effect_underscore_binding)] + #[allow(clippy::trait_duplication_in_bounds)] #[debug_requires(!alias_samplers.is_empty(), "alias_samplers is non-empty")] #[debug_ensures( old(alias_samplers).iter().map(|s| s.e).any(|e| e == ret), diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs index 81cf824af..f95a1f541 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/mod.rs @@ -20,6 +20,7 @@ use super::sampler::stack::DynamicAliasMethodStackSampler; mod sampler; #[allow(clippy::module_name_repetitions)] +#[allow(clippy::trait_duplication_in_bounds)] pub struct IndividualAliasActiveLineageSampler< M: MathsCore, H: Habitat, @@ -44,6 +45,7 @@ pub struct IndividualAliasActiveLineageSampler< marker: PhantomData<(M, H, G, S, X, D, C, T, N, E, I)>, } +#[allow(clippy::trait_duplication_in_bounds)] impl< M: MathsCore, H: Habitat, @@ -155,6 +157,7 @@ impl< } } +#[allow(clippy::trait_duplication_in_bounds)] impl< M: MathsCore, H: Habitat, @@ -181,6 +184,7 @@ impl< } } +#[allow(clippy::trait_duplication_in_bounds)] #[contract_trait] impl< M: MathsCore, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs index 722a6ef81..c8488aac7 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/individual/sampler.rs @@ -15,6 +15,7 @@ use necsim_core_bond::{NonNegativeF64, PositiveF64}; use super::IndividualAliasActiveLineageSampler; +#[allow(clippy::trait_duplication_in_bounds)] #[contract_trait] impl< M: MathsCore, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs index 8956c2e8b..3b096bbba 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/mod.rs @@ -23,6 +23,7 @@ use super::sampler::indexed::DynamicAliasMethodIndexedSampler; mod sampler; #[allow(clippy::module_name_repetitions)] +#[allow(clippy::trait_duplication_in_bounds)] pub struct LocationAliasActiveLineageSampler< M: MathsCore, H: Habitat, @@ -47,6 +48,7 @@ pub struct LocationAliasActiveLineageSampler< marker: PhantomData<(M, H, G, S, X, D, C, T, N, E, I)>, } +#[allow(clippy::trait_duplication_in_bounds)] impl< M: MathsCore, H: Habitat, @@ -205,6 +207,7 @@ impl< } } +#[allow(clippy::trait_duplication_in_bounds)] impl< M: MathsCore, H: Habitat, @@ -231,6 +234,7 @@ impl< } } +#[allow(clippy::trait_duplication_in_bounds)] #[contract_trait] impl< M: MathsCore, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs index 44c958c08..4e7bd0b47 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/location/sampler.rs @@ -17,6 +17,7 @@ use crate::cogs::event_sampler::gillespie::GillespieEventSampler; use super::LocationAliasActiveLineageSampler; +#[allow(clippy::trait_duplication_in_bounds)] #[contract_trait] impl< M: MathsCore, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs index 19d5ac095..063ec393b 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/indexed/mod.rs @@ -193,6 +193,7 @@ impl DynamicAliasMethodIndexedSampler { self.groups.iter().flat_map(RejectionSamplingGroup::iter) } + #[allow(clippy::trait_duplication_in_bounds)] pub fn sample_pop< M: MathsCore, G: Rng + Samples + Samples + Samples, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs index 4f7fc1475..5eec48515 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/mod.rs @@ -130,6 +130,7 @@ impl DynamicAliasMethodStackSampler { self.groups.iter().flat_map(RejectionSamplingGroup::iter) } + #[allow(clippy::trait_duplication_in_bounds)] pub fn sample_pop< M: MathsCore, G: Rng + Samples + Samples + Samples, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs index a70d0b65e..654d2696c 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/mod.rs @@ -16,6 +16,7 @@ use crate::cogs::{ mod sampler; #[allow(clippy::module_name_repetitions)] +#[allow(clippy::trait_duplication_in_bounds)] #[derive(Debug)] pub struct ClassicalActiveLineageSampler< M: MathsCore, @@ -33,6 +34,7 @@ pub struct ClassicalActiveLineageSampler< _marker: PhantomData<(M, H, G, S, X, D, N, I)>, } +#[allow(clippy::trait_duplication_in_bounds)] impl< M: MathsCore, H: Habitat, @@ -123,6 +125,7 @@ impl< } } +#[allow(clippy::trait_duplication_in_bounds)] #[contract_trait] impl< M: MathsCore, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs index 2caa6dbea..188c58c3c 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/classical/sampler.rs @@ -23,6 +23,7 @@ use crate::cogs::{ use super::ClassicalActiveLineageSampler; +#[allow(clippy::trait_duplication_in_bounds)] #[contract_trait] impl< M: MathsCore, diff --git a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs index 22388e81b..ef29cd4c7 100644 --- a/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs +++ b/necsim/impls/no-std/src/cogs/active_lineage_sampler/independent/event_time_sampler/poisson.rs @@ -27,6 +27,7 @@ impl PoissonEventTimeSampler { } } +#[allow(clippy::trait_duplication_in_bounds)] #[contract_trait] impl< M: MathsCore, diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/dispersal.rs index 2970e3c62..3441c0827 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/dispersal.rs @@ -8,6 +8,7 @@ use necsim_core::{ use super::InMemoryAliasDispersalSampler; +#[allow(clippy::trait_duplication_in_bounds)] #[contract_trait] impl, G: Rng + Samples + Samples> DispersalSampler for InMemoryAliasDispersalSampler diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/mod.rs index 559ba2d23..18a65c1a4 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/alias/mod.rs @@ -19,6 +19,7 @@ use crate::{ mod dispersal; #[allow(clippy::module_name_repetitions)] +#[allow(clippy::trait_duplication_in_bounds)] #[derive(Debug)] pub struct InMemoryAliasDispersalSampler< M: MathsCore, @@ -29,6 +30,7 @@ pub struct InMemoryAliasDispersalSampler< marker: PhantomData<(M, H, G)>, } +#[allow(clippy::trait_duplication_in_bounds)] #[contract_trait] impl, G: Rng + Samples + Samples> InMemoryDispersalSampler for InMemoryAliasDispersalSampler @@ -83,6 +85,7 @@ impl, G: Rng + Samples + Samples, G: Rng + Samples + Samples> Backup for InMemoryAliasDispersalSampler diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/dispersal.rs index 47bd76cd4..07eef5178 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/dispersal.rs @@ -12,6 +12,7 @@ use crate::alias::packed::AliasMethodSamplerAtom; use super::InMemoryPackedAliasDispersalSampler; +#[allow(clippy::trait_duplication_in_bounds)] #[contract_trait] impl, G: Rng + Samples + Samples> DispersalSampler for InMemoryPackedAliasDispersalSampler diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs index 0a07e3ad0..108294c73 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs @@ -1,3 +1,5 @@ +#![allow(clippy::trait_duplication_in_bounds)] + use alloc::{boxed::Box, vec::Vec}; use core::{marker::PhantomData, ops::Range}; use necsim_core_bond::NonNegativeF64; @@ -57,6 +59,7 @@ pub struct InMemoryPackedAliasDispersalSampler< marker: PhantomData<(M, H, G)>, } +#[allow(clippy::trait_duplication_in_bounds)] #[contract_trait] impl, G: Rng + Samples + Samples> InMemoryDispersalSampler for InMemoryPackedAliasDispersalSampler @@ -119,6 +122,7 @@ impl, G: Rng + Samples + Samples, G: Rng + Samples + Samples> core::fmt::Debug for InMemoryPackedAliasDispersalSampler { @@ -137,6 +141,7 @@ impl, G: Rng + Samples + Samples, G: Rng + Samples + Samples> Backup for InMemoryPackedAliasDispersalSampler diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs index e4d99a7a2..5a6b9af31 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/dispersal.rs @@ -10,6 +10,7 @@ use necsim_core_bond::ClosedUnitF64; use super::InMemorySeparableAliasDispersalSampler; +#[allow(clippy::trait_duplication_in_bounds)] #[contract_trait] impl, G: Rng + Samples + Samples> DispersalSampler for InMemorySeparableAliasDispersalSampler @@ -38,6 +39,7 @@ impl, G: Rng + Samples + Samples, G: Rng + Samples + Samples> SeparableDispersalSampler for InMemorySeparableAliasDispersalSampler diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/mod.rs index 0610d8920..d2d15b0dd 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/separable_alias/mod.rs @@ -19,6 +19,7 @@ use crate::{ mod dispersal; #[allow(clippy::module_name_repetitions)] +#[allow(clippy::trait_duplication_in_bounds)] #[derive(Debug)] pub struct InMemorySeparableAliasDispersalSampler< M: MathsCore, @@ -30,6 +31,7 @@ pub struct InMemorySeparableAliasDispersalSampler< _marker: PhantomData<(M, H, G)>, } +#[allow(clippy::trait_duplication_in_bounds)] #[contract_trait] impl, G: Rng + Samples + Samples> InMemoryDispersalSampler for InMemorySeparableAliasDispersalSampler @@ -118,6 +120,7 @@ impl, G: Rng + Samples + Samples, G: Rng + Samples + Samples> Backup for InMemorySeparableAliasDispersalSampler diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs index edfdbf4e3..e8cede3e0 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/spatially_implicit.rs @@ -1,3 +1,5 @@ +#![allow(clippy::trait_duplication_in_bounds)] + use necsim_core::{ cogs::{ distribution::{Bernoulli, IndexU64}, @@ -28,6 +30,7 @@ pub struct SpatiallyImplicitDispersalSampler< local_migration_probability_per_generation: PositiveUnitF64, } +#[allow(clippy::trait_duplication_in_bounds)] impl + Samples + Samples> SpatiallyImplicitDispersalSampler { @@ -41,6 +44,7 @@ impl + Samples + Samples> } } +#[allow(clippy::trait_duplication_in_bounds)] #[contract_trait] impl + Samples + Samples> Backup for SpatiallyImplicitDispersalSampler @@ -55,6 +59,7 @@ impl + Samples + Samples> Bac } } +#[allow(clippy::trait_duplication_in_bounds)] #[contract_trait] impl + Samples + Samples> DispersalSampler, G> @@ -98,6 +103,7 @@ impl + Samples + Samples> } } +#[allow(clippy::trait_duplication_in_bounds)] #[contract_trait] impl + Samples + Samples> SeparableDispersalSampler, G> diff --git a/necsim/impls/no-std/src/cogs/distribution/poisson_inversion.rs b/necsim/impls/no-std/src/cogs/distribution/poisson_inversion.rs index 416aae8e5..aa31b655d 100644 --- a/necsim/impls/no-std/src/cogs/distribution/poisson_inversion.rs +++ b/necsim/impls/no-std/src/cogs/distribution/poisson_inversion.rs @@ -7,6 +7,7 @@ use necsim_core_bond::NonNegativeF64; #[allow(clippy::module_name_repetitions)] pub struct PoissonInverseTransformOrNormalSampler; +#[allow(clippy::trait_duplication_in_bounds)] impl< M: MathsCore, R: RngCore, diff --git a/necsim/impls/no-std/src/cogs/distribution/std_normal2d_box_muller.rs b/necsim/impls/no-std/src/cogs/distribution/std_normal2d_box_muller.rs index ff8ab645f..6b3596a8f 100644 --- a/necsim/impls/no-std/src/cogs/distribution/std_normal2d_box_muller.rs +++ b/necsim/impls/no-std/src/cogs/distribution/std_normal2d_box_muller.rs @@ -7,6 +7,7 @@ use necsim_core::cogs::{ pub struct StandardNormal2DBoxMullerSampler; +#[allow(clippy::trait_duplication_in_bounds)] impl< M: MathsCore, R: RngCore, diff --git a/necsim/impls/no-std/src/cogs/rng/simple.rs b/necsim/impls/no-std/src/cogs/rng/simple.rs index 972af8c6f..4bf49ee77 100644 --- a/necsim/impls/no-std/src/cogs/rng/simple.rs +++ b/necsim/impls/no-std/src/cogs/rng/simple.rs @@ -235,6 +235,7 @@ impl DistributionSampler } } +#[allow(clippy::trait_duplication_in_bounds)] impl< M: MathsCore, R: RngCore, diff --git a/rustcoalescence/algorithms/cuda/src/initialiser/fixup.rs b/rustcoalescence/algorithms/cuda/src/initialiser/fixup.rs index 115791b4f..e609816bd 100644 --- a/rustcoalescence/algorithms/cuda/src/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/cuda/src/initialiser/fixup.rs @@ -43,6 +43,7 @@ pub struct FixUpInitialiser> { pub fixup_strategy: RestartFixUpStrategy, } +#[allow(clippy::trait_duplication_in_bounds)] impl< L: ExactSizeIterator, M: MathsCore, diff --git a/rustcoalescence/algorithms/cuda/src/initialiser/genesis.rs b/rustcoalescence/algorithms/cuda/src/initialiser/genesis.rs index 96055414b..d932f189d 100644 --- a/rustcoalescence/algorithms/cuda/src/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/cuda/src/initialiser/genesis.rs @@ -26,6 +26,7 @@ use super::CudaLineageStoreSampleInitialiser; #[allow(clippy::module_name_repetitions)] pub struct GenesisInitialiser; +#[allow(clippy::trait_duplication_in_bounds)] impl< M: MathsCore, G: Rng diff --git a/rustcoalescence/algorithms/cuda/src/initialiser/mod.rs b/rustcoalescence/algorithms/cuda/src/initialiser/mod.rs index 7bebde14e..bd624a7b0 100644 --- a/rustcoalescence/algorithms/cuda/src/initialiser/mod.rs +++ b/rustcoalescence/algorithms/cuda/src/initialiser/mod.rs @@ -29,6 +29,7 @@ pub mod genesis; pub mod resume; #[allow(clippy::module_name_repetitions)] +#[allow(clippy::trait_duplication_in_bounds)] pub trait CudaLineageStoreSampleInitialiser< M: MathsCore, G: Rng diff --git a/rustcoalescence/algorithms/cuda/src/initialiser/resume.rs b/rustcoalescence/algorithms/cuda/src/initialiser/resume.rs index 936bd6d65..649e1687e 100644 --- a/rustcoalescence/algorithms/cuda/src/initialiser/resume.rs +++ b/rustcoalescence/algorithms/cuda/src/initialiser/resume.rs @@ -32,6 +32,7 @@ pub struct ResumeInitialiser> { pub resume_after: Option, } +#[allow(clippy::trait_duplication_in_bounds)] impl< L: ExactSizeIterator, M: MathsCore, diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/fixup.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/fixup.rs index 2fed583c6..0e361bd03 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/fixup.rs @@ -48,6 +48,7 @@ pub struct FixUpInitialiser> { pub fixup_strategy: RestartFixUpStrategy, } +#[allow(clippy::trait_duplication_in_bounds)] impl< L: ExactSizeIterator, M: MathsCore, diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/genesis.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/genesis.rs index b464810b7..9f5ea65d1 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/genesis.rs @@ -25,6 +25,7 @@ use super::EventSkippingLineageStoreSampleInitialiser; #[allow(clippy::module_name_repetitions)] pub struct GenesisInitialiser; +#[allow(clippy::trait_duplication_in_bounds)] impl< M: MathsCore, G: Rng diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/mod.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/mod.rs index 61e2f386f..99e617f7a 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/mod.rs @@ -22,6 +22,7 @@ pub mod genesis; pub mod resume; #[allow(clippy::module_name_repetitions)] +#[allow(clippy::trait_duplication_in_bounds)] pub trait EventSkippingLineageStoreSampleInitialiser< M: MathsCore, G: Rng + Samples + Samples + Samples, diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/resume.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/resume.rs index aa93e90d6..ee7099fc1 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/resume.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/resume.rs @@ -32,6 +32,7 @@ pub struct ResumeInitialiser> { } #[allow(clippy::type_complexity)] +#[allow(clippy::trait_duplication_in_bounds)] impl< L: ExactSizeIterator, M: MathsCore, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs index 7d052e903..e0b90e2f4 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs @@ -46,6 +46,7 @@ pub struct FixUpInitialiser> { pub fixup_strategy: RestartFixUpStrategy, } +#[allow(clippy::trait_duplication_in_bounds)] impl< L: ExactSizeIterator, M: MathsCore, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/genesis.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/genesis.rs index 1528cf6ba..b6cd74ee8 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/genesis.rs @@ -20,6 +20,7 @@ use super::ClassicalLineageStoreSampleInitialiser; #[allow(clippy::module_name_repetitions)] pub struct GenesisInitialiser; +#[allow(clippy::trait_duplication_in_bounds)] impl< M: MathsCore, G: Rng + Samples + Samples + Samples, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/mod.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/mod.rs index 6ef6014ba..dd7c0e210 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/mod.rs @@ -22,6 +22,7 @@ pub mod genesis; pub mod resume; #[allow(clippy::module_name_repetitions)] +#[allow(clippy::trait_duplication_in_bounds)] pub trait ClassicalLineageStoreSampleInitialiser< M: MathsCore, G: Rng + Samples + Samples, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/resume.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/resume.rs index d7ab6eceb..a715c7fc0 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/resume.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/resume.rs @@ -26,6 +26,7 @@ pub struct ResumeInitialiser> { pub resume_after: Option, } +#[allow(clippy::trait_duplication_in_bounds)] impl< L: ExactSizeIterator, M: MathsCore, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/fixup.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/fixup.rs index aa6d3d57a..efffb65ff 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/fixup.rs @@ -44,6 +44,7 @@ pub struct FixUpInitialiser> { pub fixup_strategy: RestartFixUpStrategy, } +#[allow(clippy::trait_duplication_in_bounds)] impl< L: ExactSizeIterator, M: MathsCore, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/genesis.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/genesis.rs index 6f9ae9605..91e3b3dea 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/genesis.rs @@ -21,6 +21,7 @@ use super::GillespieLineageStoreSampleInitialiser; #[allow(clippy::module_name_repetitions)] pub struct GenesisInitialiser; +#[allow(clippy::trait_duplication_in_bounds)] impl< M: MathsCore, G: Rng diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/mod.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/mod.rs index cb8fd7bc2..7ed78ef26 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/mod.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/mod.rs @@ -20,6 +20,7 @@ pub mod genesis; pub mod resume; #[allow(clippy::module_name_repetitions)] +#[allow(clippy::trait_duplication_in_bounds)] pub trait GillespieLineageStoreSampleInitialiser< M: MathsCore, G: Rng + Samples + Samples, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/resume.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/resume.rs index 281635014..5ed8fae85 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/resume.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/resume.rs @@ -27,6 +27,7 @@ pub struct ResumeInitialiser> { pub resume_after: Option, } +#[allow(clippy::trait_duplication_in_bounds)] impl< L: ExactSizeIterator, M: MathsCore, diff --git a/rustcoalescence/algorithms/independent/src/initialiser/fixup.rs b/rustcoalescence/algorithms/independent/src/initialiser/fixup.rs index 76ecab2b0..d0f3e70d9 100644 --- a/rustcoalescence/algorithms/independent/src/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/independent/src/initialiser/fixup.rs @@ -39,6 +39,7 @@ pub struct FixUpInitialiser> { pub fixup_strategy: RestartFixUpStrategy, } +#[allow(clippy::trait_duplication_in_bounds)] impl< L: ExactSizeIterator, M: MathsCore, diff --git a/rustcoalescence/algorithms/independent/src/initialiser/genesis.rs b/rustcoalescence/algorithms/independent/src/initialiser/genesis.rs index 730c5e3ad..ac01ccb5d 100644 --- a/rustcoalescence/algorithms/independent/src/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/independent/src/initialiser/genesis.rs @@ -22,6 +22,7 @@ use super::IndependentLineageStoreSampleInitialiser; #[allow(clippy::module_name_repetitions)] pub struct GenesisInitialiser; +#[allow(clippy::trait_duplication_in_bounds)] impl< M: MathsCore, G: Rng diff --git a/rustcoalescence/algorithms/independent/src/initialiser/mod.rs b/rustcoalescence/algorithms/independent/src/initialiser/mod.rs index e599e6501..d3ec398b8 100644 --- a/rustcoalescence/algorithms/independent/src/initialiser/mod.rs +++ b/rustcoalescence/algorithms/independent/src/initialiser/mod.rs @@ -25,6 +25,7 @@ pub mod genesis; pub mod resume; #[allow(clippy::module_name_repetitions)] +#[allow(clippy::trait_duplication_in_bounds)] pub trait IndependentLineageStoreSampleInitialiser< M: MathsCore, G: Rng diff --git a/rustcoalescence/algorithms/independent/src/initialiser/resume.rs b/rustcoalescence/algorithms/independent/src/initialiser/resume.rs index bccdd8fab..8ca52ef60 100644 --- a/rustcoalescence/algorithms/independent/src/initialiser/resume.rs +++ b/rustcoalescence/algorithms/independent/src/initialiser/resume.rs @@ -28,6 +28,7 @@ pub struct ResumeInitialiser> { pub resume_after: Option, } +#[allow(clippy::trait_duplication_in_bounds)] impl< L: ExactSizeIterator, M: MathsCore, diff --git a/rustcoalescence/scenarios/src/spatially_implicit.rs b/rustcoalescence/scenarios/src/spatially_implicit.rs index 276fddea7..f46865daa 100644 --- a/rustcoalescence/scenarios/src/spatially_implicit.rs +++ b/rustcoalescence/scenarios/src/spatially_implicit.rs @@ -25,6 +25,7 @@ use necsim_impls_no_std::{ use crate::{Scenario, ScenarioParameters}; #[allow(clippy::module_name_repetitions)] +#[allow(clippy::trait_duplication_in_bounds)] pub struct SpatiallyImplicitScenario< M: MathsCore, G: Rng + Samples + Samples, @@ -47,6 +48,7 @@ pub struct SpatiallyImplicitArguments { pub migration_probability_per_generation: PositiveUnitF64, } +#[allow(clippy::trait_duplication_in_bounds)] impl + Samples + Samples> ScenarioParameters for SpatiallyImplicitScenario { @@ -54,6 +56,7 @@ impl + Samples + Samples> Sce type Error = !; } +#[allow(clippy::trait_duplication_in_bounds)] impl + Samples + Samples> Scenario for SpatiallyImplicitScenario { From 517e39083177bce8f1bbf7dba9edd7f3266d03ea Mon Sep 17 00:00:00 2001 From: Juniper Langenstein Date: Wed, 28 Dec 2022 13:33:06 +0000 Subject: [PATCH 21/42] Fixed new WrappingHabitat for improved Rng --- .../no-std/src/cogs/dispersal_sampler/wrapping_noise.rs | 4 ++-- .../impls/no-std/src/cogs/origin_sampler/wrapping_noise.rs | 6 +++--- rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs | 5 ++++- rustcoalescence/scenarios/src/wrapping_noise.rs | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/wrapping_noise.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/wrapping_noise.rs index 09e86bd3a..399b75443 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/wrapping_noise.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/wrapping_noise.rs @@ -1,8 +1,8 @@ use necsim_core::{ cogs::{ distribution::{Bernoulli, Normal2D}, - Backup, DispersalSampler, DistributionSampler, Habitat, MathsCore, Rng, - Distribution, SeparableDispersalSampler, + Backup, DispersalSampler, Distribution, DistributionSampler, Habitat, MathsCore, Rng, + SeparableDispersalSampler, }, landscape::Location, }; diff --git a/necsim/impls/no-std/src/cogs/origin_sampler/wrapping_noise.rs b/necsim/impls/no-std/src/cogs/origin_sampler/wrapping_noise.rs index d2412c3ac..fff2c7fb0 100644 --- a/necsim/impls/no-std/src/cogs/origin_sampler/wrapping_noise.rs +++ b/necsim/impls/no-std/src/cogs/origin_sampler/wrapping_noise.rs @@ -16,7 +16,7 @@ use crate::cogs::{ #[allow(clippy::module_name_repetitions)] pub struct WrappingNoiseOriginSampler<'h, M: MathsCore, I: Iterator> { - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, last_index: u64, location_iterator: Peekable, habitat: &'h WrappingNoiseHabitat, @@ -40,7 +40,7 @@ impl<'h, M: MathsCore, I: Iterator> fmt::Debug impl<'h, M: MathsCore, I: Iterator> WrappingNoiseOriginSampler<'h, M, I> { #[must_use] pub fn new( - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, habitat: &'h WrappingNoiseHabitat, sample: LandscapeExtent, ) -> Self { @@ -65,7 +65,7 @@ impl<'h, M: MathsCore, I: Iterator> UntrustedOriginSampler<'h, M> self.habitat } - fn into_pre_sampler(self) -> OriginPreSampler { + fn into_pre_sampler(self) -> OriginPreSampler { self.pre_sampler } diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs b/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs index 8a342b4a4..e869cff72 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs @@ -317,7 +317,10 @@ link_kernel!( necsim_impls_cuda::cogs::maths::NvptxMathsCore, necsim_impls_cuda::cogs::rng::CudaRng< necsim_impls_cuda::cogs::maths::NvptxMathsCore, - necsim_impls_no_std::cogs::rng::wyhash::WyHash, + necsim_impls_no_std::cogs::rng::simple::SimpleRng< + necsim_impls_cuda::cogs::maths::NvptxMathsCore, + necsim_impls_no_std::cogs::rng::wyhash::WyHash, + >, >, >, necsim_impls_no_std::cogs::turnover_rate::uniform::UniformTurnoverRate, diff --git a/rustcoalescence/scenarios/src/wrapping_noise.rs b/rustcoalescence/scenarios/src/wrapping_noise.rs index a83b1277a..71835de9f 100644 --- a/rustcoalescence/scenarios/src/wrapping_noise.rs +++ b/rustcoalescence/scenarios/src/wrapping_noise.rs @@ -130,7 +130,7 @@ where fn sample_habitat<'h, I: Iterator>( habitat: &'h Self::Habitat, - pre_sampler: OriginPreSampler, + pre_sampler: OriginPreSampler, (sample,): Self::OriginSamplerAuxiliary, ) -> Self::OriginSampler<'_, I> where From 7a1632050150331258fd30997b4a724a03589e31 Mon Sep 17 00:00:00 2001 From: Juniper Langenstein Date: Sat, 19 Nov 2022 20:33:06 +0000 Subject: [PATCH 22/42] Pipeline CUDA mem transfer with async --- Cargo.lock | 48 ++++++++----- necsim/core/Cargo.toml | 4 +- necsim/impls/cuda/Cargo.toml | 4 +- necsim/impls/no-std/Cargo.toml | 4 +- necsim/impls/no-std/src/array2d.rs | 1 + .../in_memory/packed_alias/mod.rs | 1 + .../no-std/src/cogs/habitat/in_memory.rs | 1 + .../src/cogs/habitat/wrapping_noise/mod.rs | 1 + .../src/cogs/turnover_rate/in_memory.rs | 1 + rustcoalescence/algorithms/cuda/Cargo.toml | 2 +- .../algorithms/cuda/cpu-kernel/Cargo.toml | 2 +- .../algorithms/cuda/cpu-kernel/src/lib.rs | 10 +-- .../algorithms/cuda/cpu-kernel/src/patch.rs | 24 ++++--- .../algorithms/cuda/gpu-kernel/Cargo.toml | 2 +- rustcoalescence/algorithms/cuda/src/launch.rs | 5 +- .../cuda/src/parallelisation/monolithic.rs | 69 +++++++++++++------ 16 files changed, 111 insertions(+), 68 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 337889ed9..e614da75f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -406,12 +406,31 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "const-type-layout" +version = "0.1.0" +source = "git+https://github.com/MomoLangenstein/const-type-layout?rev=aa5ad03#aa5ad0303eb195e931ad055d9d4fd70fdc9b80c6" +dependencies = [ + "const-type-layout-derive 0.1.0 (git+https://github.com/MomoLangenstein/const-type-layout?rev=aa5ad03)", +] + [[package]] name = "const-type-layout" version = "0.1.0" source = "git+https://github.com/juntyr/const-type-layout?rev=e163b36#e163b364827a8402a6f55a9ac64414c849051ffd" dependencies = [ - "const-type-layout-derive", + "const-type-layout-derive 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=e163b36)", +] + +[[package]] +name = "const-type-layout-derive" +version = "0.1.0" +source = "git+https://github.com/MomoLangenstein/const-type-layout?rev=aa5ad03#aa5ad0303eb195e931ad055d9d4fd70fdc9b80c6" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1003,7 +1022,7 @@ dependencies = [ name = "necsim-core" version = "0.1.0" dependencies = [ - "const-type-layout", + "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=e163b36)", "contracts", "necsim-core-bond", "necsim-core-maths", @@ -1015,7 +1034,7 @@ dependencies = [ name = "necsim-core-bond" version = "0.1.0" dependencies = [ - "const-type-layout", + "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=e163b36)", "necsim-core-maths", "serde", ] @@ -1028,7 +1047,7 @@ version = "0.1.0" name = "necsim-impls-cuda" version = "0.1.0" dependencies = [ - "const-type-layout", + "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=e163b36)", "contracts", "necsim-core", "rust-cuda", @@ -1039,7 +1058,7 @@ dependencies = [ name = "necsim-impls-no-std" version = "0.1.0" dependencies = [ - "const-type-layout", + "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=e163b36)", "contracts", "displaydoc", "final", @@ -1349,7 +1368,7 @@ dependencies = [ [[package]] name = "ptx-builder" version = "0.5.3" -source = "git+https://github.com/juntyr/rust-ptx-builder?rev=1f1f49d#1f1f49df761e919f721ef234722ee7b2cfcf9104" +source = "git+https://github.com/MomoLangenstein/rust-ptx-builder?rev=1f1f49d#1f1f49df761e919f721ef234722ee7b2cfcf9104" dependencies = [ "anyhow", "colored", @@ -1468,9 +1487,9 @@ dependencies = [ [[package]] name = "rust-cuda" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=5d5cd02#5d5cd02ea0bca23390785ef5284397124fa3bfbf" +source = "git+https://github.com/juntyr/rust-cuda?rev=f18ae16#f18ae16cd00ca0ccdf7b4032aaee8edc1a1d9b52" dependencies = [ - "const-type-layout", + "const-type-layout 0.1.0 (git+https://github.com/MomoLangenstein/const-type-layout?rev=aa5ad03)", "final", "rust-cuda-derive", "rust-cuda-ptx-jit", @@ -1482,7 +1501,7 @@ dependencies = [ [[package]] name = "rust-cuda-derive" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=5d5cd02#5d5cd02ea0bca23390785ef5284397124fa3bfbf" +source = "git+https://github.com/juntyr/rust-cuda?rev=f18ae16#f18ae16cd00ca0ccdf7b4032aaee8edc1a1d9b52" dependencies = [ "cargo_metadata", "colored", @@ -1501,7 +1520,7 @@ dependencies = [ [[package]] name = "rust-cuda-ptx-jit" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=5d5cd02#5d5cd02ea0bca23390785ef5284397124fa3bfbf" +source = "git+https://github.com/juntyr/rust-cuda?rev=f18ae16#f18ae16cd00ca0ccdf7b4032aaee8edc1a1d9b52" dependencies = [ "lazy_static", "regex", @@ -1511,8 +1530,7 @@ dependencies = [ [[package]] name = "rustacuda" version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47208516ab5338b592d63560e90eaef405d0ec880347eaf7742d893b0a31e228" +source = "git+https://github.com/MomoLangenstein/RustaCUDA?rev=fa4bf52#fa4bf52b7f941ecaf40748d3ce137d1b490403e4" dependencies = [ "bitflags 1.3.2", "cuda-driver-sys", @@ -1523,14 +1541,12 @@ dependencies = [ [[package]] name = "rustacuda_core" version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3858b08976dc2f860c5efbbb48cdcb0d4fafca92a6ac0898465af16c0dbe848" +source = "git+https://github.com/MomoLangenstein/RustaCUDA?rev=fa4bf52#fa4bf52b7f941ecaf40748d3ce137d1b490403e4" [[package]] name = "rustacuda_derive" version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ce8670a1a1d0fc2514a3b846dacdb65646f9bd494b6674cfacbb4ce430bd7e" +source = "git+https://github.com/MomoLangenstein/RustaCUDA?rev=fa4bf52#fa4bf52b7f941ecaf40748d3ce137d1b490403e4" dependencies = [ "proc-macro2", "quote", diff --git a/necsim/core/Cargo.toml b/necsim/core/Cargo.toml index 5d092f9e7..e27a73d95 100644 --- a/necsim/core/Cargo.toml +++ b/necsim/core/Cargo.toml @@ -20,7 +20,7 @@ contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "5d5cd02", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "f18ae16", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "5d5cd02", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "f18ae16", features = ["derive", "host"], optional = true } diff --git a/necsim/impls/cuda/Cargo.toml b/necsim/impls/cuda/Cargo.toml index 411450d79..64255f60f 100644 --- a/necsim/impls/cuda/Cargo.toml +++ b/necsim/impls/cuda/Cargo.toml @@ -15,7 +15,7 @@ contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "5d5cd02", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "f18ae16", features = ["derive"] } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "5d5cd02", features = ["derive", "host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "f18ae16", features = ["derive", "host"] } diff --git a/necsim/impls/no-std/Cargo.toml b/necsim/impls/no-std/Cargo.toml index 19628f69b..e8f9218f3 100644 --- a/necsim/impls/no-std/Cargo.toml +++ b/necsim/impls/no-std/Cargo.toml @@ -31,7 +31,7 @@ rand_core = "0.6" rand_distr = { version = "0.4", default-features = false, features = [] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "5d5cd02", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "f18ae16", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "5d5cd02", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "f18ae16", features = ["derive", "host"], optional = true } diff --git a/necsim/impls/no-std/src/array2d.rs b/necsim/impls/no-std/src/array2d.rs index 281c479f8..e910ba21b 100644 --- a/necsim/impls/no-std/src/array2d.rs +++ b/necsim/impls/no-std/src/array2d.rs @@ -11,6 +11,7 @@ use core::ops::{Index, IndexMut}; /// A fixed sized two-dimensional array. #[derive(Clone, Eq, PartialEq)] #[cfg_attr(feature = "cuda", derive(rust_cuda::common::LendRustToCuda))] +#[cfg_attr(feature = "cuda", cuda(async = false))] #[cfg_attr( feature = "cuda", cuda( diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs index 108294c73..37fdf5302 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs @@ -47,6 +47,7 @@ impl From for Range { #[allow(clippy::module_name_repetitions)] #[cfg_attr(feature = "cuda", derive(rust_cuda::common::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M", free = "H", free = "G"))] +#[cfg_attr(feature = "cuda", cuda(async = false))] pub struct InMemoryPackedAliasDispersalSampler< M: MathsCore, H: Habitat, diff --git a/necsim/impls/no-std/src/cogs/habitat/in_memory.rs b/necsim/impls/no-std/src/cogs/habitat/in_memory.rs index e7960e8bb..7f48f5352 100644 --- a/necsim/impls/no-std/src/cogs/habitat/in_memory.rs +++ b/necsim/impls/no-std/src/cogs/habitat/in_memory.rs @@ -19,6 +19,7 @@ use crate::array2d::Array2D; #[derive(Debug)] #[cfg_attr(feature = "cuda", derive(rust_cuda::common::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M"))] +#[cfg_attr(feature = "cuda", cuda(async = false))] pub struct InMemoryHabitat { #[cfg_attr(feature = "cuda", cuda(embed))] habitat: Final>, diff --git a/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/mod.rs b/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/mod.rs index eac3ce204..1a31f357c 100644 --- a/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/mod.rs +++ b/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/mod.rs @@ -22,6 +22,7 @@ use crate::cogs::{ #[allow(clippy::module_name_repetitions)] #[cfg_attr(feature = "cuda", derive(rust_cuda::common::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M"))] +#[cfg_attr(feature = "cuda", cuda(async = false))] pub struct WrappingNoiseHabitat { #[cfg_attr(feature = "cuda", cuda(embed))] inner: AlmostInfiniteHabitat, diff --git a/necsim/impls/no-std/src/cogs/turnover_rate/in_memory.rs b/necsim/impls/no-std/src/cogs/turnover_rate/in_memory.rs index 6b83d35be..4ce878f64 100644 --- a/necsim/impls/no-std/src/cogs/turnover_rate/in_memory.rs +++ b/necsim/impls/no-std/src/cogs/turnover_rate/in_memory.rs @@ -13,6 +13,7 @@ use crate::{array2d::Array2D, cogs::habitat::in_memory::InMemoryHabitat}; #[allow(clippy::module_name_repetitions)] #[derive(Debug)] #[cfg_attr(feature = "cuda", derive(rust_cuda::common::LendRustToCuda))] +#[cfg_attr(feature = "cuda", cuda(async = false))] pub struct InMemoryTurnoverRate { #[cfg_attr(feature = "cuda", cuda(embed))] turnover_rate: Final>, diff --git a/rustcoalescence/algorithms/cuda/Cargo.toml b/rustcoalescence/algorithms/cuda/Cargo.toml index c014fdd0b..1b1ec84fa 100644 --- a/rustcoalescence/algorithms/cuda/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/Cargo.toml @@ -23,4 +23,4 @@ thiserror = "1.0" serde = { version = "1.0", features = ["derive"] } serde_state = "0.4" serde_derive_state = "0.4" -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "5d5cd02", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "f18ae16", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml index b2d7e69e9..c441eb52f 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml @@ -14,4 +14,4 @@ necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["c necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } rustcoalescence-algorithms-cuda-gpu-kernel = { path = "../gpu-kernel" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "5d5cd02", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "f18ae16", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs b/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs index 1caa2d456..c6a456736 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs @@ -20,11 +20,10 @@ use necsim_impls_no_std::cogs::{ use rust_cuda::{ common::RustToCuda, - host::{CudaDropWrapper, LaunchConfig, LaunchPackage, Launcher, TypedKernel}, + host::{LaunchConfig, LaunchPackage, Launcher, TypedKernel}, rustacuda::{ error::CudaResult, function::{BlockSize, Function, GridSize}, - stream::Stream, }, }; @@ -71,7 +70,6 @@ pub struct SimulationKernel< ReportDispersal, >, >, - stream: CudaDropWrapper, grid: GridSize, block: BlockSize, ptx_jit: bool, @@ -99,7 +97,6 @@ impl< /// /// Returns a `CudaError` if loading the CUDA kernel failed. pub fn try_new( - stream: Stream, grid: GridSize, block: BlockSize, ptx_jit: bool, @@ -123,12 +120,10 @@ impl< ReportDispersal, >, { - let stream = CudaDropWrapper::from(stream); let kernel = Self::new_kernel()?; Ok(Self { kernel, - stream, grid, block, ptx_jit, @@ -181,10 +176,7 @@ impl< shared_memory_size: 0_u32, ptx_jit: self.ptx_jit, }, - kernel: &mut self.kernel, - stream: &mut self.stream, - watcher: &mut self.watcher, } } diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs b/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs index f0d63342c..2a1e40c1a 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs @@ -18,8 +18,8 @@ use necsim_impls_no_std::cogs::{ use rust_cuda::{ common::{DeviceAccessible, RustToCuda}, - host::{HostAndDeviceConstRef, HostAndDeviceMutRef, TypedKernel}, - rustacuda::error::CudaResult, + host::{HostAndDeviceConstRefAsync, HostAndDeviceMutRefAsync, TypedKernel}, + rustacuda::{error::CudaResult, stream::Stream}, utils::device_copy::SafeDeviceCopyWrapper, }; @@ -91,8 +91,9 @@ where unsafe { unreachable_cuda_simulation_linking_reporter() } } - default fn simulate( + default fn simulate<'stream>( &mut self, + _stream: &'stream Stream, _simulation: &mut Simulation, _task_list: &mut ValueBuffer, _event_buffer_reporter: &mut EventBuffer, @@ -106,33 +107,34 @@ where unsafe { unreachable_cuda_simulation_linking_reporter() } } - default fn simulate_raw( + default fn simulate_async<'stream>( &mut self, - _simulation: HostAndDeviceMutRef< + _stream: &'stream Stream, + _simulation: HostAndDeviceMutRefAsync< DeviceAccessible< as RustToCuda>::CudaRepresentation, >, >, - _task_list: HostAndDeviceMutRef< + _task_list: HostAndDeviceMutRefAsync< DeviceAccessible< as RustToCuda>::CudaRepresentation>, >, - _event_buffer_reporter: HostAndDeviceMutRef< + _event_buffer_reporter: HostAndDeviceMutRefAsync< DeviceAccessible< as RustToCuda>::CudaRepresentation, >, >, - _min_spec_sample_buffer: HostAndDeviceMutRef< + _min_spec_sample_buffer: HostAndDeviceMutRefAsync< DeviceAccessible< as RustToCuda>::CudaRepresentation, >, >, - _next_event_time_buffer: HostAndDeviceMutRef< + _next_event_time_buffer: HostAndDeviceMutRefAsync< DeviceAccessible< as RustToCuda>::CudaRepresentation, >, >, - _total_time_max: HostAndDeviceConstRef>, - _total_steps_sum: HostAndDeviceConstRef>, + _total_time_max: HostAndDeviceConstRefAsync>, + _total_steps_sum: HostAndDeviceConstRefAsync>, _max_steps: SafeDeviceCopyWrapper, _max_next_event_time: SafeDeviceCopyWrapper, ) -> CudaResult<()> { diff --git a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml index 7c4e59bcd..13fc08a75 100644 --- a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml @@ -16,4 +16,4 @@ necsim-core-bond = { path = "../../../../necsim/core/bond" } necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["cuda"] } necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "5d5cd02", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "f18ae16", features = ["derive"] } diff --git a/rustcoalescence/algorithms/cuda/src/launch.rs b/rustcoalescence/algorithms/cuda/src/launch.rs index 22ec158a6..a40023038 100644 --- a/rustcoalescence/algorithms/cuda/src/launch.rs +++ b/rustcoalescence/algorithms/cuda/src/launch.rs @@ -30,6 +30,7 @@ use rustcoalescence_algorithms_cuda_gpu_kernel::SimulatableKernel; use rust_cuda::{ common::RustToCuda, + host::CudaDropWrapper, rustacuda::{ function::{BlockSize, GridSize}, prelude::{Stream, StreamFlags}, @@ -202,8 +203,9 @@ where }; let (mut status, time, steps, lineages) = with_initialised_cuda(args.device, || { + let stream = CudaDropWrapper::from(Stream::new(StreamFlags::NON_BLOCKING, None)?); + let kernel = SimulationKernel::try_new( - Stream::new(StreamFlags::NON_BLOCKING, None)?, grid_size.clone(), block_size.clone(), args.ptx_jit, @@ -217,6 +219,7 @@ where &mut simulation, kernel, (grid_size, block_size, args.dedup_cache, args.step_slice), + &stream, lineages, event_slice, pause_before, diff --git a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs index 7b55fcb89..6d6c4fa25 100644 --- a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs +++ b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs @@ -3,7 +3,10 @@ use std::{collections::VecDeque, convert::TryInto, num::NonZeroU64, sync::atomic use rust_cuda::{ common::RustToCuda, host::{HostAndDeviceMutRef, LendToCuda}, - rustacuda::function::{BlockSize, GridSize}, + rustacuda::{ + function::{BlockSize, GridSize}, + stream::Stream, + }, utils::exchange::wrapper::ExchangeWrapperOnHost, }; @@ -44,10 +47,15 @@ use crate::error::CudaError; type Result = std::result::Result; -#[allow(clippy::type_complexity, clippy::too_many_lines)] +#[allow( + clippy::type_complexity, + clippy::too_many_lines, + clippy::too_many_arguments +)] pub fn simulate< 'l, 'p, + 'stream, M: MathsCore, H: Habitat + RustToCuda, G: Rng + RustToCuda, @@ -83,6 +91,7 @@ pub fn simulate< <>::WaterLevelReporter as Reporter>::ReportDispersal, >, config: (GridSize, BlockSize, DedupCache, NonZeroU64), + stream: &'stream Stream, lineages: LI, event_slice: EventSlice, pause_before: Option, @@ -195,8 +204,14 @@ pub fn simulate< HostAndDeviceMutRef::with_new(&mut total_time_max, |total_time_max| -> Result<()> { HostAndDeviceMutRef::with_new(&mut total_steps_sum, |total_steps_sum| -> Result<()> { - // TODO: Pipeline async launches and callbacks of simulation/event analysis simulation.lend_to_cuda_mut(|mut simulation_cuda_repr| -> Result<()> { + // Move the event buffer and min speciation sample buffer to CUDA + let mut event_buffer_cuda = event_buffer.move_to_device_async(stream)?; + let mut min_spec_sample_buffer_cuda = + min_spec_sample_buffer.move_to_device_async(stream)?; + let mut next_event_time_buffer_cuda = + next_event_time_buffer.move_to_device_async(stream)?; + while !slow_lineages.is_empty() && pause_before.map_or(true, |pause_before| level_time < pause_before) { @@ -263,29 +278,32 @@ pub fn simulate< // Move the task list, event buffer and min speciation sample buffer // to CUDA - let mut event_buffer_cuda = event_buffer.move_to_device()?; - let mut min_spec_sample_buffer_cuda = - min_spec_sample_buffer.move_to_device()?; - let mut next_event_time_buffer_cuda = - next_event_time_buffer.move_to_device()?; - let mut task_list_cuda = task_list.move_to_device()?; - - kernel.simulate_raw( - simulation_cuda_repr.as_mut(), - task_list_cuda.as_mut(), - event_buffer_cuda.as_mut(), - min_spec_sample_buffer_cuda.as_mut(), - next_event_time_buffer_cuda.as_mut(), - total_time_max.as_ref(), - total_steps_sum.as_ref(), + let mut task_list_cuda = task_list.move_to_device_async(stream)?; + + // TODO: Investigate distributing over several streams + kernel.simulate_async( + stream, + simulation_cuda_repr.as_mut().as_async(), + task_list_cuda.as_mut_async(), + event_buffer_cuda.as_mut_async(), + min_spec_sample_buffer_cuda.as_mut_async(), + next_event_time_buffer_cuda.as_mut_async(), + total_time_max.as_ref().as_async(), + total_steps_sum.as_ref().as_async(), step_slice.get().into(), level_time.into(), )?; - min_spec_sample_buffer = min_spec_sample_buffer_cuda.move_to_host()?; - next_event_time_buffer = next_event_time_buffer_cuda.move_to_host()?; - task_list = task_list_cuda.move_to_host()?; - event_buffer = event_buffer_cuda.move_to_host()?; + let min_spec_sample_buffer_host = + min_spec_sample_buffer_cuda.move_to_host_async(stream)?; + let next_event_time_buffer_host = + next_event_time_buffer_cuda.move_to_host_async(stream)?; + let task_list_host = task_list_cuda.move_to_host_async(stream)?; + let event_buffer_host = event_buffer_cuda.move_to_host_async(stream)?; + + min_spec_sample_buffer = min_spec_sample_buffer_host.sync_to_host()?; + next_event_time_buffer = next_event_time_buffer_host.sync_to_host()?; + task_list = task_list_host.sync_to_host()?; // Fetch the completion of the tasks for ((mut spec_sample, mut next_event_time), mut task) in @@ -314,7 +332,14 @@ pub fn simulate< } } + min_spec_sample_buffer_cuda = + min_spec_sample_buffer.move_to_device_async(stream)?; + next_event_time_buffer_cuda = + next_event_time_buffer.move_to_device_async(stream)?; + + event_buffer = event_buffer_host.sync_to_host()?; event_buffer.report_events_unordered(&mut proxy); + event_buffer_cuda = event_buffer.move_to_device_async(stream)?; proxy.local_partition().get_reporter().report_progress( &((slow_lineages.len() as u64) + (fast_lineages.len() as u64)).into(), From bc42ae328b71a84bf9688019780f87415370906f Mon Sep 17 00:00:00 2001 From: Juniper Tyree Date: Sun, 20 Nov 2022 06:55:12 -0800 Subject: [PATCH 23/42] Initial first fixes to get CUDA running again --- Cargo.lock | 12 ++++++------ necsim/core/Cargo.toml | 4 ++-- necsim/impls/cuda/Cargo.toml | 4 ++-- necsim/impls/cuda/src/cogs/maths.rs | 2 +- necsim/impls/cuda/src/lib.rs | 2 -- necsim/impls/no-std/Cargo.toml | 4 ++-- rustcoalescence/algorithms/cuda/Cargo.toml | 2 +- .../algorithms/cuda/cpu-kernel/Cargo.toml | 2 +- .../algorithms/cuda/gpu-kernel/Cargo.toml | 2 +- 9 files changed, 16 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e614da75f..807daabe4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1487,7 +1487,7 @@ dependencies = [ [[package]] name = "rust-cuda" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=f18ae16#f18ae16cd00ca0ccdf7b4032aaee8edc1a1d9b52" +source = "git+https://github.com/juntyr/rust-cuda?rev=56f7f2fe#56f7f2feaba13c033332fa803d4cd89674bd73f1" dependencies = [ "const-type-layout 0.1.0 (git+https://github.com/MomoLangenstein/const-type-layout?rev=aa5ad03)", "final", @@ -1501,7 +1501,7 @@ dependencies = [ [[package]] name = "rust-cuda-derive" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=f18ae16#f18ae16cd00ca0ccdf7b4032aaee8edc1a1d9b52" +source = "git+https://github.com/juntyr/rust-cuda?rev=56f7f2fe#56f7f2feaba13c033332fa803d4cd89674bd73f1" dependencies = [ "cargo_metadata", "colored", @@ -1520,7 +1520,7 @@ dependencies = [ [[package]] name = "rust-cuda-ptx-jit" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=f18ae16#f18ae16cd00ca0ccdf7b4032aaee8edc1a1d9b52" +source = "git+https://github.com/juntyr/rust-cuda?rev=56f7f2fe#56f7f2feaba13c033332fa803d4cd89674bd73f1" dependencies = [ "lazy_static", "regex", @@ -1530,7 +1530,7 @@ dependencies = [ [[package]] name = "rustacuda" version = "0.1.3" -source = "git+https://github.com/MomoLangenstein/RustaCUDA?rev=fa4bf52#fa4bf52b7f941ecaf40748d3ce137d1b490403e4" +source = "git+https://github.com/MomoLangenstein/RustaCUDA?rev=c6ea7cc#c6ea7ccf24b15c4edbd5576852a8dcdc7df272b0" dependencies = [ "bitflags 1.3.2", "cuda-driver-sys", @@ -1541,12 +1541,12 @@ dependencies = [ [[package]] name = "rustacuda_core" version = "0.1.2" -source = "git+https://github.com/MomoLangenstein/RustaCUDA?rev=fa4bf52#fa4bf52b7f941ecaf40748d3ce137d1b490403e4" +source = "git+https://github.com/MomoLangenstein/RustaCUDA?rev=c6ea7cc#c6ea7ccf24b15c4edbd5576852a8dcdc7df272b0" [[package]] name = "rustacuda_derive" version = "0.1.2" -source = "git+https://github.com/MomoLangenstein/RustaCUDA?rev=fa4bf52#fa4bf52b7f941ecaf40748d3ce137d1b490403e4" +source = "git+https://github.com/MomoLangenstein/RustaCUDA?rev=c6ea7cc#c6ea7ccf24b15c4edbd5576852a8dcdc7df272b0" dependencies = [ "proc-macro2", "quote", diff --git a/necsim/core/Cargo.toml b/necsim/core/Cargo.toml index e27a73d95..ef7c57ac5 100644 --- a/necsim/core/Cargo.toml +++ b/necsim/core/Cargo.toml @@ -20,7 +20,7 @@ contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "f18ae16", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "56f7f2fe", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "f18ae16", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "56f7f2fe", features = ["derive", "host"], optional = true } diff --git a/necsim/impls/cuda/Cargo.toml b/necsim/impls/cuda/Cargo.toml index 64255f60f..b8b09147e 100644 --- a/necsim/impls/cuda/Cargo.toml +++ b/necsim/impls/cuda/Cargo.toml @@ -15,7 +15,7 @@ contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "f18ae16", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "56f7f2fe", features = ["derive"] } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "f18ae16", features = ["derive", "host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "56f7f2fe", features = ["derive", "host"] } diff --git a/necsim/impls/cuda/src/cogs/maths.rs b/necsim/impls/cuda/src/cogs/maths.rs index 209e64be6..6326ffa2a 100644 --- a/necsim/impls/cuda/src/cogs/maths.rs +++ b/necsim/impls/cuda/src/cogs/maths.rs @@ -134,7 +134,7 @@ impl MathsCore for NvptxMathsCore { #[cfg(target_os = "cuda")] unsafe { - core::arch::asm!("copysign.f64 {}, {}, {};", out(reg64) offset, in(reg64) x, const ROUND_TRUNC_OFFSET.to_bits(), options(pure, nomem, nostack)); + core::arch::asm!("copysign.f64 {}, {}, {};", out(reg64) offset, in(reg64) x, in(reg64) ROUND_TRUNC_OFFSET, options(pure, nomem, nostack)); } #[cfg(not(target_os = "cuda"))] unsafe { diff --git a/necsim/impls/cuda/src/lib.rs b/necsim/impls/cuda/src/lib.rs index 95d9711d9..1ba363a8b 100644 --- a/necsim/impls/cuda/src/lib.rs +++ b/necsim/impls/cuda/src/lib.rs @@ -6,8 +6,6 @@ #![feature(const_mut_refs)] #![feature(const_refs_to_cell)] #![cfg_attr(target_os = "cuda", feature(asm_experimental_arch))] -#![cfg_attr(target_os = "cuda", feature(asm_const))] -#![cfg_attr(target_os = "cuda", feature(const_float_bits_conv))] #![allow(incomplete_features)] #![feature(specialization)] diff --git a/necsim/impls/no-std/Cargo.toml b/necsim/impls/no-std/Cargo.toml index e8f9218f3..96e5a6f17 100644 --- a/necsim/impls/no-std/Cargo.toml +++ b/necsim/impls/no-std/Cargo.toml @@ -31,7 +31,7 @@ rand_core = "0.6" rand_distr = { version = "0.4", default-features = false, features = [] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "f18ae16", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "56f7f2fe", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "f18ae16", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "56f7f2fe", features = ["derive", "host"], optional = true } diff --git a/rustcoalescence/algorithms/cuda/Cargo.toml b/rustcoalescence/algorithms/cuda/Cargo.toml index 1b1ec84fa..b0db2be74 100644 --- a/rustcoalescence/algorithms/cuda/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/Cargo.toml @@ -23,4 +23,4 @@ thiserror = "1.0" serde = { version = "1.0", features = ["derive"] } serde_state = "0.4" serde_derive_state = "0.4" -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "f18ae16", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "56f7f2fe", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml index c441eb52f..1c77485b2 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml @@ -14,4 +14,4 @@ necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["c necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } rustcoalescence-algorithms-cuda-gpu-kernel = { path = "../gpu-kernel" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "f18ae16", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "56f7f2fe", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml index 13fc08a75..1d9f62c6f 100644 --- a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml @@ -16,4 +16,4 @@ necsim-core-bond = { path = "../../../../necsim/core/bond" } necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["cuda"] } necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "f18ae16", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "56f7f2fe", features = ["derive"] } From 9cd9db7922927dc6bf4b375883eac589ceb96f0f Mon Sep 17 00:00:00 2001 From: Juniper Tyree Date: Sun, 20 Nov 2022 12:45:14 -0800 Subject: [PATCH 24/42] Fixed CUDA algorithm with spatially explicit habitat --- .../src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs index 37fdf5302..47d1799f0 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_alias/mod.rs @@ -33,7 +33,7 @@ impl From> for AliasSamplerRange { fn from(range: Range) -> Self { Self { start: range.start, - end: range.start, + end: range.end, } } } From 4d30084396ea2247e6be6e163b870005b28bef89 Mon Sep 17 00:00:00 2001 From: Juniper Langenstein Date: Thu, 24 Nov 2022 07:40:28 +0000 Subject: [PATCH 25/42] Upgraded to latest const-type-layout and rust-cuda --- Cargo.lock | 28 +++++++++---------- necsim/core/Cargo.toml | 6 ++-- necsim/core/bond/Cargo.toml | 2 +- necsim/impls/cuda/Cargo.toml | 6 ++-- necsim/impls/no-std/Cargo.toml | 6 ++-- rustcoalescence/algorithms/cuda/Cargo.toml | 2 +- .../algorithms/cuda/cpu-kernel/Cargo.toml | 2 +- .../algorithms/cuda/gpu-kernel/Cargo.toml | 2 +- 8 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 807daabe4..9e50b5b2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -409,23 +409,23 @@ dependencies = [ [[package]] name = "const-type-layout" version = "0.1.0" -source = "git+https://github.com/MomoLangenstein/const-type-layout?rev=aa5ad03#aa5ad0303eb195e931ad055d9d4fd70fdc9b80c6" +source = "git+https://github.com/juntyr/const-type-layout?rev=49aa113#49aa113140ad1976df5b3d24e04c794665f3097b" dependencies = [ - "const-type-layout-derive 0.1.0 (git+https://github.com/MomoLangenstein/const-type-layout?rev=aa5ad03)", + "const-type-layout-derive 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=49aa113)", ] [[package]] name = "const-type-layout" version = "0.1.0" -source = "git+https://github.com/juntyr/const-type-layout?rev=e163b36#e163b364827a8402a6f55a9ac64414c849051ffd" +source = "git+https://github.com/MomoLangenstein/const-type-layout?rev=49aa113#49aa113140ad1976df5b3d24e04c794665f3097b" dependencies = [ - "const-type-layout-derive 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=e163b36)", + "const-type-layout-derive 0.1.0 (git+https://github.com/MomoLangenstein/const-type-layout?rev=49aa113)", ] [[package]] name = "const-type-layout-derive" version = "0.1.0" -source = "git+https://github.com/MomoLangenstein/const-type-layout?rev=aa5ad03#aa5ad0303eb195e931ad055d9d4fd70fdc9b80c6" +source = "git+https://github.com/juntyr/const-type-layout?rev=49aa113#49aa113140ad1976df5b3d24e04c794665f3097b" dependencies = [ "proc-macro-error", "proc-macro2", @@ -436,7 +436,7 @@ dependencies = [ [[package]] name = "const-type-layout-derive" version = "0.1.0" -source = "git+https://github.com/juntyr/const-type-layout?rev=e163b36#e163b364827a8402a6f55a9ac64414c849051ffd" +source = "git+https://github.com/MomoLangenstein/const-type-layout?rev=49aa113#49aa113140ad1976df5b3d24e04c794665f3097b" dependencies = [ "proc-macro-error", "proc-macro2", @@ -1022,7 +1022,7 @@ dependencies = [ name = "necsim-core" version = "0.1.0" dependencies = [ - "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=e163b36)", + "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=49aa113)", "contracts", "necsim-core-bond", "necsim-core-maths", @@ -1034,7 +1034,7 @@ dependencies = [ name = "necsim-core-bond" version = "0.1.0" dependencies = [ - "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=e163b36)", + "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=49aa113)", "necsim-core-maths", "serde", ] @@ -1047,7 +1047,7 @@ version = "0.1.0" name = "necsim-impls-cuda" version = "0.1.0" dependencies = [ - "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=e163b36)", + "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=49aa113)", "contracts", "necsim-core", "rust-cuda", @@ -1058,7 +1058,7 @@ dependencies = [ name = "necsim-impls-no-std" version = "0.1.0" dependencies = [ - "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=e163b36)", + "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=49aa113)", "contracts", "displaydoc", "final", @@ -1487,9 +1487,9 @@ dependencies = [ [[package]] name = "rust-cuda" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=56f7f2fe#56f7f2feaba13c033332fa803d4cd89674bd73f1" +source = "git+https://github.com/juntyr/rust-cuda?rev=ef510e4#ef510e4954c3cd81bd90e2bce39b208ede280b42" dependencies = [ - "const-type-layout 0.1.0 (git+https://github.com/MomoLangenstein/const-type-layout?rev=aa5ad03)", + "const-type-layout 0.1.0 (git+https://github.com/MomoLangenstein/const-type-layout?rev=49aa113)", "final", "rust-cuda-derive", "rust-cuda-ptx-jit", @@ -1501,7 +1501,7 @@ dependencies = [ [[package]] name = "rust-cuda-derive" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=56f7f2fe#56f7f2feaba13c033332fa803d4cd89674bd73f1" +source = "git+https://github.com/juntyr/rust-cuda?rev=ef510e4#ef510e4954c3cd81bd90e2bce39b208ede280b42" dependencies = [ "cargo_metadata", "colored", @@ -1520,7 +1520,7 @@ dependencies = [ [[package]] name = "rust-cuda-ptx-jit" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=56f7f2fe#56f7f2feaba13c033332fa803d4cd89674bd73f1" +source = "git+https://github.com/juntyr/rust-cuda?rev=ef510e4#ef510e4954c3cd81bd90e2bce39b208ede280b42" dependencies = [ "lazy_static", "regex", diff --git a/necsim/core/Cargo.toml b/necsim/core/Cargo.toml index ef7c57ac5..e27f83acb 100644 --- a/necsim/core/Cargo.toml +++ b/necsim/core/Cargo.toml @@ -15,12 +15,12 @@ cuda = ["rust-cuda"] necsim-core-maths = { path = "maths" } necsim-core-bond = { path = "bond" } -const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "e163b36" } +const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "49aa113" } contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "56f7f2fe", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "ef510e4", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "56f7f2fe", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "ef510e4", features = ["derive", "host"], optional = true } diff --git a/necsim/core/bond/Cargo.toml b/necsim/core/bond/Cargo.toml index 06c647f03..a8c16247a 100644 --- a/necsim/core/bond/Cargo.toml +++ b/necsim/core/bond/Cargo.toml @@ -13,5 +13,5 @@ default = [] [dependencies] necsim-core-maths = { path = "../maths" } -const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "e163b36" } +const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "49aa113" } serde = { version = "1.0", default-features = false, features = ["derive"] } diff --git a/necsim/impls/cuda/Cargo.toml b/necsim/impls/cuda/Cargo.toml index b8b09147e..6d0b8a7c3 100644 --- a/necsim/impls/cuda/Cargo.toml +++ b/necsim/impls/cuda/Cargo.toml @@ -10,12 +10,12 @@ edition = "2018" [dependencies] necsim-core = { path = "../../core", features = ["cuda"] } -const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "e163b36" } +const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "49aa113" } contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "56f7f2fe", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "ef510e4", features = ["derive"] } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "56f7f2fe", features = ["derive", "host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "ef510e4", features = ["derive", "host"] } diff --git a/necsim/impls/no-std/Cargo.toml b/necsim/impls/no-std/Cargo.toml index 96e5a6f17..9b757de75 100644 --- a/necsim/impls/no-std/Cargo.toml +++ b/necsim/impls/no-std/Cargo.toml @@ -17,7 +17,7 @@ necsim-core-maths = { path = "../../core/maths" } necsim-core-bond = { path = "../../core/bond" } necsim-partitioning-core = { path = "../../partitioning/core" } -const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "e163b36" } +const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "49aa113" } contracts = "0.6.3" libm = "0.2" hashbrown = "0.13" @@ -31,7 +31,7 @@ rand_core = "0.6" rand_distr = { version = "0.4", default-features = false, features = [] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "56f7f2fe", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "ef510e4", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "56f7f2fe", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "ef510e4", features = ["derive", "host"], optional = true } diff --git a/rustcoalescence/algorithms/cuda/Cargo.toml b/rustcoalescence/algorithms/cuda/Cargo.toml index b0db2be74..6651099e7 100644 --- a/rustcoalescence/algorithms/cuda/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/Cargo.toml @@ -23,4 +23,4 @@ thiserror = "1.0" serde = { version = "1.0", features = ["derive"] } serde_state = "0.4" serde_derive_state = "0.4" -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "56f7f2fe", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "ef510e4", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml index 1c77485b2..30551f6be 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml @@ -14,4 +14,4 @@ necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["c necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } rustcoalescence-algorithms-cuda-gpu-kernel = { path = "../gpu-kernel" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "56f7f2fe", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "ef510e4", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml index 1d9f62c6f..9a2555d80 100644 --- a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml @@ -16,4 +16,4 @@ necsim-core-bond = { path = "../../../../necsim/core/bond" } necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["cuda"] } necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "56f7f2fe", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "ef510e4", features = ["derive"] } From 1e3ac5c4c4a3e1a2b11728f3cea5a12cdc004e81 Mon Sep 17 00:00:00 2001 From: Juniper Tyree Date: Sun, 27 Nov 2022 05:09:05 -0800 Subject: [PATCH 26/42] Backup of on-device sorting progress --- Cargo.lock | 6 +- necsim/core/Cargo.toml | 4 +- necsim/core/src/event.rs | 63 ++++ necsim/impls/cuda/Cargo.toml | 4 +- necsim/impls/cuda/src/event_buffer.rs | 324 +++++++++++++++++- necsim/impls/cuda/src/utils.rs | 1 - necsim/impls/no-std/Cargo.toml | 4 +- rustcoalescence/algorithms/cuda/Cargo.toml | 2 +- .../algorithms/cuda/cpu-kernel/Cargo.toml | 2 +- .../algorithms/cuda/cpu-kernel/src/lib.rs | 62 +++- .../algorithms/cuda/cpu-kernel/src/link.rs | 23 +- .../algorithms/cuda/cpu-kernel/src/patch.rs | 48 ++- .../algorithms/cuda/gpu-kernel/Cargo.toml | 2 +- .../algorithms/cuda/gpu-kernel/src/lib.rs | 20 ++ .../cuda/src/parallelisation/monolithic.rs | 21 ++ 15 files changed, 555 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9e50b5b2f..ebeb726b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1487,7 +1487,7 @@ dependencies = [ [[package]] name = "rust-cuda" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=ef510e4#ef510e4954c3cd81bd90e2bce39b208ede280b42" +source = "git+https://github.com/juntyr/rust-cuda?rev=be31ebda#be31ebdacb0734cbc6509b91dab499cc173ebbf4" dependencies = [ "const-type-layout 0.1.0 (git+https://github.com/MomoLangenstein/const-type-layout?rev=49aa113)", "final", @@ -1501,7 +1501,7 @@ dependencies = [ [[package]] name = "rust-cuda-derive" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=ef510e4#ef510e4954c3cd81bd90e2bce39b208ede280b42" +source = "git+https://github.com/juntyr/rust-cuda?rev=be31ebda#be31ebdacb0734cbc6509b91dab499cc173ebbf4" dependencies = [ "cargo_metadata", "colored", @@ -1520,7 +1520,7 @@ dependencies = [ [[package]] name = "rust-cuda-ptx-jit" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=ef510e4#ef510e4954c3cd81bd90e2bce39b208ede280b42" +source = "git+https://github.com/juntyr/rust-cuda?rev=be31ebda#be31ebdacb0734cbc6509b91dab499cc173ebbf4" dependencies = [ "lazy_static", "regex", diff --git a/necsim/core/Cargo.toml b/necsim/core/Cargo.toml index e27f83acb..b5b8fd55a 100644 --- a/necsim/core/Cargo.toml +++ b/necsim/core/Cargo.toml @@ -20,7 +20,7 @@ contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "ef510e4", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "be31ebda", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "ef510e4", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "be31ebda", features = ["derive", "host"], optional = true } diff --git a/necsim/core/src/event.rs b/necsim/core/src/event.rs index 40108ae85..25f760fa6 100644 --- a/necsim/core/src/event.rs +++ b/necsim/core/src/event.rs @@ -307,6 +307,35 @@ impl PartialEq for SpeciationEvent { } } +impl Ord for SpeciationEvent { + fn cmp(&self, other: &Self) -> Ordering { + // Order `Event`s in lexicographical order: + // (1) event_time different events + // (2) origin different events + // (3) prior_time parent + offspring + // (4) global_lineage_reference + + ( + &self.event_time, + &self.origin, + &self.prior_time, + &self.global_lineage_reference, + ) + .cmp(&( + &other.event_time, + &other.origin, + &other.prior_time, + &other.global_lineage_reference, + )) + } +} + +impl PartialOrd for SpeciationEvent { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + impl Eq for DispersalEvent {} impl PartialEq for DispersalEvent { @@ -353,3 +382,37 @@ mod tests { assert_eq!((-24.0_f64).make_negative().to_bits(), (-24.0_f64).to_bits()); } } + +impl Ord for DispersalEvent { + fn cmp(&self, other: &Self) -> Ordering { + // Order `Event`s in lexicographical order: + // (1) event_time /=\ + // (2) origin different | events + // (3) target and interaction \=/ + // (4) prior_time parent + offspring + // (5) global_lineage_reference + + ( + &self.event_time, + &self.origin, + &self.target, + &self.interaction, + &self.prior_time, + &self.global_lineage_reference, + ) + .cmp(&( + &other.event_time, + &other.origin, + &other.target, + &other.interaction, + &other.prior_time, + &other.global_lineage_reference, + )) + } +} + +impl PartialOrd for DispersalEvent { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} diff --git a/necsim/impls/cuda/Cargo.toml b/necsim/impls/cuda/Cargo.toml index 6d0b8a7c3..8c380677b 100644 --- a/necsim/impls/cuda/Cargo.toml +++ b/necsim/impls/cuda/Cargo.toml @@ -15,7 +15,7 @@ contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "ef510e4", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "be31ebda", features = ["derive"] } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "ef510e4", features = ["derive", "host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "be31ebda", features = ["derive", "host"] } diff --git a/necsim/impls/cuda/src/event_buffer.rs b/necsim/impls/cuda/src/event_buffer.rs index fec5a6aaa..8b70c21bb 100644 --- a/necsim/impls/cuda/src/event_buffer.rs +++ b/necsim/impls/cuda/src/event_buffer.rs @@ -129,26 +129,324 @@ impl where P: Reporter, { - for (mask, event) in self.event_mask.iter_mut().zip(self.event_buffer.iter()) { - if *mask.read() { - let event: TypedEvent = unsafe { event.read().assume_some_read() }.into(); + if ReportDispersal::VALUE { + for (mask, dispersal) in self + .dispersal_mask + .iter_mut() + .zip(self.dispersal_buffer.iter()) + { + if *mask.read() { + reporter.report_dispersal(unsafe { dispersal.read().assume_some_ref() }.into()); + } - match event { - TypedEvent::Speciation(ref speciation) => { - reporter.report_speciation(speciation.into()); - }, - TypedEvent::Dispersal(ref dispersal) => { - reporter.report_dispersal(dispersal.into()); - }, + mask.write(false); + } + } + + if ReportSpeciation::VALUE { + for (mask, speciation) in self + .speciation_mask + .iter_mut() + .zip(self.speciation_buffer.iter()) + { + if *mask.read() { + reporter + .report_speciation(unsafe { speciation.read().assume_some_ref() }.into()); + } + + mask.write(false); + } + } + } +} + +#[cfg(not(target_os = "cuda"))] +impl + EventBuffer +{ + pub fn sort_events(&mut self) { + if ReportDispersal::VALUE { + let mut events: alloc::vec::Vec = alloc::vec::Vec::new(); + + for (mask, dispersal) in self + .dispersal_mask + .iter_mut() + .zip(self.dispersal_buffer.iter()) + { + if *mask.read() { + events.push(unsafe { dispersal.read().assume_some_read() }); + } + + mask.write(false); + } + + events.sort_unstable(); + + for ((event, mask), dispersal) in events + .into_iter() + .zip(self.dispersal_mask.iter_mut()) + .zip(self.dispersal_buffer.iter_mut()) + { + *dispersal.as_scratch_mut() = MaybeSome::Some(event); + mask.write(true); + } + } + + if ReportSpeciation::VALUE { + let mut events: alloc::vec::Vec = alloc::vec::Vec::new(); + + for (mask, speciation) in self + .speciation_mask + .iter_mut() + .zip(self.speciation_buffer.iter()) + { + if *mask.read() { + events.push(unsafe { speciation.read().assume_some_read() }); } + + mask.write(false); } - mask.write(false); + events.sort_unstable(); + + for ((event, mask), speciation) in events + .into_iter() + .zip(self.speciation_mask.iter_mut()) + .zip(self.speciation_buffer.iter_mut()) + { + *speciation.as_scratch_mut() = MaybeSome::Some(event); + mask.write(true); + } } } +} + +#[cfg(target_os = "cuda")] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum SortStepDirection { + Less, + Greater, +} + +#[cfg(target_os = "cuda")] +impl + EventBuffer +{ + #[allow(clippy::too_many_lines)] + /// # Safety + /// + /// All CUDA threads must call this method with the same size, stride, and + /// direction arguments. Only one call per kernel launch is safe without + /// further synchronisation. + pub unsafe fn sort_events_step( + &mut self, + size: usize, + stride: usize, + direction: SortStepDirection, + ) { + use core::cmp::Ordering; + + if ReportDispersal::VALUE { + let idx = rust_cuda::device::utils::index(); + + // odd-even merge position + let pos = 2 * idx - (idx & (stride - 1)); + + let (pos_a, pos_b) = if stride < (size / 2) { + (pos - stride, pos) + } else { + (pos, pos + stride) + }; + + let offset = idx & ((size / 2) - 1); + + if (stride >= (size / 2)) || (offset >= stride) { + let mask_a: bool = *self.dispersal_mask.alias_unchecked()[pos_a].read(); + let mask_b: bool = *self.dispersal_mask.alias_unchecked()[pos_b].read(); + + let cmp = match (mask_a, mask_b) { + (false, false) => Ordering::Equal, + (false, true) => Ordering::Greater, + (true, false) => Ordering::Less, + (true, true) => { + // Safety: both masks indicate that the two events exist + let event_a: &DispersalEvent = unsafe { + self.dispersal_buffer.alias_unchecked()[pos_a] + .as_uninit() + .assume_init_ref() + .assume_some_ref() + }; + let event_b: &DispersalEvent = unsafe { + self.dispersal_buffer.alias_unchecked()[pos_b] + .as_uninit() + .assume_init_ref() + .assume_some_ref() + }; + + event_a.cmp(event_b) + }, + }; + + if let (SortStepDirection::Greater, Ordering::Greater) + | (SortStepDirection::Less, Ordering::Less) = (direction, cmp) + { + self.dispersal_mask.alias_mut_unchecked()[pos_a].write(mask_b); + self.dispersal_mask.alias_mut_unchecked()[pos_b].write(mask_a); + + match (mask_a, mask_b) { + (false, false) => (), + (false, true) => { + let event_b: DispersalEvent = unsafe { + self.dispersal_buffer.alias_unchecked()[pos_b] + .as_uninit() + .assume_init_ref() + .assume_some_read() + }; + + unsafe { + self.dispersal_buffer.alias_mut_unchecked()[pos_a] + .write(MaybeSome::Some(event_b)); + } + }, + (true, false) => { + let event_a: DispersalEvent = unsafe { + self.dispersal_buffer.alias_unchecked()[pos_a] + .as_uninit() + .assume_init_ref() + .assume_some_read() + }; + + unsafe { + self.dispersal_buffer.alias_mut_unchecked()[pos_b] + .write(MaybeSome::Some(event_a)); + } + }, + (true, true) => { + let event_a: DispersalEvent = unsafe { + self.dispersal_buffer.alias_unchecked()[pos_a] + .as_uninit() + .assume_init_ref() + .assume_some_read() + }; + let event_b: DispersalEvent = unsafe { + self.dispersal_buffer.alias_unchecked()[pos_b] + .as_uninit() + .assume_init_ref() + .assume_some_read() + }; + + unsafe { + self.dispersal_buffer.alias_mut_unchecked()[pos_a] + .write(MaybeSome::Some(event_b)); + self.dispersal_buffer.alias_mut_unchecked()[pos_b] + .write(MaybeSome::Some(event_a)); + } + }, + } + } + } + } - pub fn max_events_per_individual(&self) -> usize { - self.max_events + if ReportSpeciation::VALUE { + let idx = rust_cuda::device::utils::index(); + + // odd-even merge position + let pos = 2 * idx - (idx & (stride - 1)); + + let (pos_a, pos_b) = if stride < (size / 2) { + (pos - stride, pos) + } else { + (pos, pos + stride) + }; + + let offset = idx & ((size / 2) - 1); + + if (stride >= (size / 2)) || (offset >= stride) { + let mask_a: bool = *self.speciation_mask.alias_unchecked()[pos_a].read(); + let mask_b: bool = *self.speciation_mask.alias_unchecked()[pos_b].read(); + + let cmp = match (mask_a, mask_b) { + (false, false) => Ordering::Equal, + (false, true) => Ordering::Greater, + (true, false) => Ordering::Less, + (true, true) => { + // Safety: both masks indicate that the two events exist + let event_a: &SpeciationEvent = unsafe { + self.speciation_buffer.alias_unchecked()[pos_a] + .as_uninit() + .assume_init_ref() + .assume_some_ref() + }; + let event_b: &SpeciationEvent = unsafe { + self.speciation_buffer.alias_unchecked()[pos_b] + .as_uninit() + .assume_init_ref() + .assume_some_ref() + }; + + event_a.cmp(event_b) + }, + }; + + if let (SortStepDirection::Greater, Ordering::Greater) + | (SortStepDirection::Less, Ordering::Less) = (direction, cmp) + { + self.speciation_mask.alias_mut_unchecked()[pos_a].write(mask_b); + self.speciation_mask.alias_mut_unchecked()[pos_b].write(mask_a); + + match (mask_a, mask_b) { + (false, false) => (), + (false, true) => { + let event_b: SpeciationEvent = unsafe { + self.speciation_buffer.alias_unchecked()[pos_b] + .as_uninit() + .assume_init_ref() + .assume_some_read() + }; + + unsafe { + self.speciation_buffer.alias_mut_unchecked()[pos_a] + .write(MaybeSome::Some(event_b)); + } + }, + (true, false) => { + let event_a: SpeciationEvent = unsafe { + self.speciation_buffer.alias_unchecked()[pos_a] + .as_uninit() + .assume_init_ref() + .assume_some_read() + }; + + unsafe { + self.speciation_buffer.alias_mut_unchecked()[pos_b] + .write(MaybeSome::Some(event_a)); + } + }, + (true, true) => { + let event_a: SpeciationEvent = unsafe { + self.speciation_buffer.alias_unchecked()[pos_a] + .as_uninit() + .assume_init_ref() + .assume_some_read() + }; + let event_b: SpeciationEvent = unsafe { + self.speciation_buffer.alias_unchecked()[pos_b] + .as_uninit() + .assume_init_ref() + .assume_some_read() + }; + + unsafe { + self.speciation_buffer.alias_mut_unchecked()[pos_a] + .write(MaybeSome::Some(event_b)); + self.speciation_buffer.alias_mut_unchecked()[pos_b] + .write(MaybeSome::Some(event_a)); + } + }, + } + } + } + } } } diff --git a/necsim/impls/cuda/src/utils.rs b/necsim/impls/cuda/src/utils.rs index 8ff8033a5..123f9288e 100644 --- a/necsim/impls/cuda/src/utils.rs +++ b/necsim/impls/cuda/src/utils.rs @@ -21,7 +21,6 @@ impl MaybeSome { self.0.assume_init_read() } - #[cfg(not(target_os = "cuda"))] pub(crate) unsafe fn assume_some_ref(&self) -> &T { self.0.assume_init_ref() } diff --git a/necsim/impls/no-std/Cargo.toml b/necsim/impls/no-std/Cargo.toml index 9b757de75..394876ebe 100644 --- a/necsim/impls/no-std/Cargo.toml +++ b/necsim/impls/no-std/Cargo.toml @@ -31,7 +31,7 @@ rand_core = "0.6" rand_distr = { version = "0.4", default-features = false, features = [] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "ef510e4", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "be31ebda", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "ef510e4", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "be31ebda", features = ["derive", "host"], optional = true } diff --git a/rustcoalescence/algorithms/cuda/Cargo.toml b/rustcoalescence/algorithms/cuda/Cargo.toml index 6651099e7..b92b95f68 100644 --- a/rustcoalescence/algorithms/cuda/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/Cargo.toml @@ -23,4 +23,4 @@ thiserror = "1.0" serde = { version = "1.0", features = ["derive"] } serde_state = "0.4" serde_derive_state = "0.4" -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "ef510e4", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "be31ebda", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml index 30551f6be..bd8f12ed3 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml @@ -14,4 +14,4 @@ necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["c necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } rustcoalescence-algorithms-cuda-gpu-kernel = { path = "../gpu-kernel" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "ef510e4", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "be31ebda", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs b/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs index c6a456736..547f3ec15 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs @@ -27,7 +27,7 @@ use rust_cuda::{ }, }; -use rustcoalescence_algorithms_cuda_gpu_kernel::SimulatableKernel; +use rustcoalescence_algorithms_cuda_gpu_kernel::{SimulatableKernel, SortableKernel}; mod link; mod patch; @@ -185,3 +185,63 @@ impl< (watcher)(kernel) } } + +pub struct SortKernel { + #[allow(clippy::type_complexity)] + kernel: TypedKernel>, + grid: GridSize, + block: BlockSize, + ptx_jit: bool, + watcher: Box, +} + +impl + SortKernel +{ + /// # Errors + /// + /// Returns a `CudaError` if loading the CUDA kernel failed. + pub fn try_new( + grid: GridSize, + block: BlockSize, + ptx_jit: bool, + on_compile: Box, + ) -> CudaResult + where + Self: SortableKernel, + { + let kernel = Self::new_kernel()?; + + Ok(Self { + kernel, + grid, + block, + ptx_jit, + watcher: on_compile, + }) + } +} + +impl Launcher + for SortKernel +{ + type CompilationWatcher = Box; + type KernelTraitObject = dyn SortableKernel; + + fn get_launch_package(&mut self) -> LaunchPackage { + LaunchPackage { + config: LaunchConfig { + grid: self.grid.clone(), + block: self.block.clone(), + shared_memory_size: 0_u32, + ptx_jit: self.ptx_jit, + }, + kernel: &mut self.kernel, + watcher: &mut self.watcher, + } + } + + fn on_compile(kernel: &Function, watcher: &mut Self::CompilationWatcher) -> CudaResult<()> { + (watcher)(kernel) + } +} diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs b/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs index e869cff72..70f50f491 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs @@ -1,6 +1,8 @@ -use rustcoalescence_algorithms_cuda_gpu_kernel::{SimulatableKernel, SimulationKernelArgs}; +use rustcoalescence_algorithms_cuda_gpu_kernel::{ + SimulatableKernel, SimulationKernelArgs, SortKernelArgs, SortableKernel, +}; -use crate::SimulationKernel; +use crate::{SimulationKernel, SortKernel}; macro_rules! link_kernel { ($habitat:ty, $dispersal:ty, $turnover:ty, $speciation:ty) => { @@ -326,3 +328,20 @@ link_kernel!( necsim_impls_no_std::cogs::turnover_rate::uniform::UniformTurnoverRate, necsim_impls_no_std::cogs::speciation_probability::uniform::UniformSpeciationProbability ); + +rustcoalescence_algorithms_cuda_gpu_kernel::link_sort_kernel!( + necsim_core::reporter::boolean::False, + necsim_core::reporter::boolean::False, +); +rustcoalescence_algorithms_cuda_gpu_kernel::link_sort_kernel!( + necsim_core::reporter::boolean::False, + necsim_core::reporter::boolean::True, +); +rustcoalescence_algorithms_cuda_gpu_kernel::link_sort_kernel!( + necsim_core::reporter::boolean::True, + necsim_core::reporter::boolean::False, +); +rustcoalescence_algorithms_cuda_gpu_kernel::link_sort_kernel!( + necsim_core::reporter::boolean::True, + necsim_core::reporter::boolean::True, +); diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs b/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs index 2a1e40c1a..0a7fff6dc 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs @@ -23,9 +23,9 @@ use rust_cuda::{ utils::device_copy::SafeDeviceCopyWrapper, }; -use rustcoalescence_algorithms_cuda_gpu_kernel::SimulatableKernel; +use rustcoalescence_algorithms_cuda_gpu_kernel::{SimulatableKernel, SortableKernel}; -use crate::SimulationKernel; +use crate::{SimulationKernel, SortKernel}; // If `Kernel` is implemented for `ReportSpeciation` x `ReportDispersal`, i.e. // for {`False`, `True`} x {`False`, `True`} then it is implemented for all @@ -141,3 +141,47 @@ where unsafe { unreachable_cuda_simulation_linking_reporter() } } } + +#[allow(clippy::trait_duplication_in_bounds)] +unsafe impl + SortableKernel + for SortKernel +where + SortKernel: SortableKernel, + SortKernel: SortableKernel, + SortKernel: SortableKernel, + SortKernel: SortableKernel, +{ + default fn get_ptx_str() -> &'static str { + unsafe { unreachable_cuda_simulation_linking_reporter() } + } + + default fn new_kernel( + ) -> CudaResult>> { + unsafe { unreachable_cuda_simulation_linking_reporter() } + } + + default fn sort_events<'stream>( + &mut self, + _stream: &'stream Stream, + _event_buffer_reporter: &mut EventBuffer, + _size: usize, + _stride: usize, + ) -> CudaResult<()> { + unsafe { unreachable_cuda_simulation_linking_reporter() } + } + + default fn sort_events_async<'stream>( + &mut self, + _stream: &'stream Stream, + _event_buffer_reporter: HostAndDeviceMutRefAsync< + DeviceAccessible< + as RustToCuda>::CudaRepresentation, + >, + >, + _size: SafeDeviceCopyWrapper, + _stride: SafeDeviceCopyWrapper, + ) -> CudaResult<()> { + unsafe { unreachable_cuda_simulation_linking_reporter() } + } +} diff --git a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml index 9a2555d80..a4be7ce1b 100644 --- a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml @@ -16,4 +16,4 @@ necsim-core-bond = { path = "../../../../necsim/core/bond" } necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["cuda"] } necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "ef510e4", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "be31ebda", features = ["derive"] } diff --git a/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs b/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs index 24cf141e0..a6f994027 100644 --- a/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs +++ b/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs @@ -132,6 +132,26 @@ pub fn simulate< }); } +#[rust_cuda::common::kernel( + pub use link_sort_kernel! as impl SortableKernel for SortKernel +)] +pub fn sort_events( + #[kernel(pass = LendRustToCuda, jit)] event_buffer_reporter: &mut ShallowCopy< + necsim_impls_cuda::event_buffer::EventBuffer, + >, + #[kernel(pass = SafeDeviceCopy)] size: usize, + #[kernel(pass = SafeDeviceCopy)] stride: usize, +) { + // Safety: size, stride, and direction are the same on every CUDA thread + unsafe { + event_buffer_reporter.sort_events_step( + size, + stride, + necsim_impls_cuda::event_buffer::SortStepDirection::Greater, + ); + } +} + #[cfg(target_os = "cuda")] mod cuda_prelude { use core::arch::nvptx; diff --git a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs index 6d6c4fa25..bab657eb2 100644 --- a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs +++ b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs @@ -259,6 +259,8 @@ pub fn simulate< // Simulate all slow lineages until they have finished or exceeded the // new water level while !slow_lineages.is_empty() { + let mut num_tasks = 0_usize; + // Upload the new tasks from the front of the task queue for mut task in task_list.iter_mut() { let next_slow_lineage = loop { @@ -274,6 +276,7 @@ pub fn simulate< }; task.replace(next_slow_lineage); + num_tasks += 1; } // Move the task list, event buffer and min speciation sample buffer @@ -301,6 +304,23 @@ pub fn simulate< let task_list_host = task_list_cuda.move_to_host_async(stream)?; let event_buffer_host = event_buffer_cuda.move_to_host_async(stream)?; + let mut size = 2; + + // TODO: dispersal and speciation have different buffer lengths + while size <= num_tasks { + let mut stride = size / 2; + + while stride > 0 { + // oddEvenMergeGlobal<<<(batchSize * arrayLength) / 512, 256>>>( + // d_DstKey, d_DstVal, d_DstKey, d_DstVal, arrayLength, size, stride, + // dir); + + stride >>= 1; + } + + size <<= 1; + } + min_spec_sample_buffer = min_spec_sample_buffer_host.sync_to_host()?; next_event_time_buffer = next_event_time_buffer_host.sync_to_host()?; task_list = task_list_host.sync_to_host()?; @@ -338,6 +358,7 @@ pub fn simulate< next_event_time_buffer.move_to_device_async(stream)?; event_buffer = event_buffer_host.sync_to_host()?; + // event_buffer.sort_events(); event_buffer.report_events_unordered(&mut proxy); event_buffer_cuda = event_buffer.move_to_device_async(stream)?; From 2b1a72d0a27d09a87078ce0de27d23154bd01e0e Mon Sep 17 00:00:00 2001 From: Juniper Tyree Date: Mon, 28 Nov 2022 00:26:43 -0800 Subject: [PATCH 27/42] First running sorting impl, efficiency untested --- necsim/impls/cuda/src/event_buffer.rs | 26 ++++++++++++- .../algorithms/cuda/cpu-kernel/src/lib.rs | 5 +++ rustcoalescence/algorithms/cuda/src/info.rs | 4 +- rustcoalescence/algorithms/cuda/src/launch.rs | 15 ++++++- .../cuda/src/parallelisation/monolithic.rs | 39 ++++++++++++++----- 5 files changed, 74 insertions(+), 15 deletions(-) diff --git a/necsim/impls/cuda/src/event_buffer.rs b/necsim/impls/cuda/src/event_buffer.rs index 8b70c21bb..ea05a41ec 100644 --- a/necsim/impls/cuda/src/event_buffer.rs +++ b/necsim/impls/cuda/src/event_buffer.rs @@ -158,6 +158,22 @@ impl } } } + + pub fn max_events_per_type_individual(&self) -> usize { + #[allow(clippy::bool_to_int_with_if)] + let max_speciation_events = if ReportSpeciation::VALUE { + 1_usize + } else { + 0_usize + }; + let max_dispersal_events = if ReportDispersal::VALUE { + self.max_events + } else { + 0_usize + }; + + max_speciation_events.max(max_dispersal_events) + } } #[cfg(not(target_os = "cuda"))] @@ -260,7 +276,10 @@ impl let offset = idx & ((size / 2) - 1); - if (stride >= (size / 2)) || (offset >= stride) { + if (pos_a < self.dispersal_mask.alias_unchecked().len()) + && (pos_b < self.dispersal_mask.alias_unchecked().len()) + && ((stride >= (size / 2)) || (offset >= stride)) + { let mask_a: bool = *self.dispersal_mask.alias_unchecked()[pos_a].read(); let mask_b: bool = *self.dispersal_mask.alias_unchecked()[pos_b].read(); @@ -361,7 +380,10 @@ impl let offset = idx & ((size / 2) - 1); - if (stride >= (size / 2)) || (offset >= stride) { + if (pos_a < self.speciation_mask.alias_unchecked().len()) + && (pos_b < self.speciation_mask.alias_unchecked().len()) + && ((stride >= (size / 2)) || (offset >= stride)) + { let mask_a: bool = *self.speciation_mask.alias_unchecked()[pos_a].read(); let mask_b: bool = *self.speciation_mask.alias_unchecked()[pos_b].read(); diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs b/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs index 547f3ec15..58d49e344 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs @@ -220,6 +220,11 @@ impl watcher: on_compile, }) } + + pub fn with_grid(&mut self, grid: GridSize) -> &mut Self { + self.grid = grid; + self + } } impl Launcher diff --git a/rustcoalescence/algorithms/cuda/src/info.rs b/rustcoalescence/algorithms/cuda/src/info.rs index 5bd3866aa..1abf4ec07 100644 --- a/rustcoalescence/algorithms/cuda/src/info.rs +++ b/rustcoalescence/algorithms/cuda/src/info.rs @@ -34,8 +34,8 @@ pub fn print_context_resource_limits() { println!("{:=^80}", ""); } -pub fn print_kernel_function_attributes(function: &Function) { - println!("{:=^80}", " Kernel Function Attributes "); +pub fn print_kernel_function_attributes(name: &str, function: &Function) { + println!("{:=^80}", format!(" {name} Kernel Function Attributes ")); println!( "MaxThreadsPerBlock: {:?}", diff --git a/rustcoalescence/algorithms/cuda/src/launch.rs b/rustcoalescence/algorithms/cuda/src/launch.rs index a40023038..f6f8b1d2f 100644 --- a/rustcoalescence/algorithms/cuda/src/launch.rs +++ b/rustcoalescence/algorithms/cuda/src/launch.rs @@ -25,7 +25,7 @@ use necsim_partitioning_core::LocalPartition; use rustcoalescence_algorithms::result::SimulationOutcome; use rustcoalescence_scenarios::Scenario; -use rustcoalescence_algorithms_cuda_cpu_kernel::SimulationKernel; +use rustcoalescence_algorithms_cuda_cpu_kernel::{SimulationKernel, SortKernel}; use rustcoalescence_algorithms_cuda_gpu_kernel::SimulatableKernel; use rust_cuda::{ @@ -210,7 +210,17 @@ where block_size.clone(), args.ptx_jit, Box::new(|kernel| { - crate::info::print_kernel_function_attributes(kernel); + crate::info::print_kernel_function_attributes("Simulation", kernel); + Ok(()) + }), + )?; + + let sort_kernel = SortKernel::try_new( + GridSize::from(0), + BlockSize::from(256), + args.ptx_jit, + Box::new(|kernel| { + crate::info::print_kernel_function_attributes("Sorting", kernel); Ok(()) }), )?; @@ -218,6 +228,7 @@ where parallelisation::monolithic::simulate( &mut simulation, kernel, + sort_kernel, (grid_size, block_size, args.dedup_cache, args.step_slice), &stream, lineages, diff --git a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs index bab657eb2..b517db887 100644 --- a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs +++ b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs @@ -1,4 +1,9 @@ -use std::{collections::VecDeque, convert::TryInto, num::NonZeroU64, sync::atomic::AtomicU64}; +use std::{ + collections::VecDeque, + convert::{TryFrom, TryInto}, + num::NonZeroU64, + sync::atomic::AtomicU64, +}; use rust_cuda::{ common::RustToCuda, @@ -40,8 +45,8 @@ use necsim_partitioning_core::LocalPartition; use necsim_impls_cuda::{event_buffer::EventBuffer, value_buffer::ValueBuffer}; -use rustcoalescence_algorithms_cuda_cpu_kernel::SimulationKernel; -use rustcoalescence_algorithms_cuda_gpu_kernel::SimulatableKernel; +use rustcoalescence_algorithms_cuda_cpu_kernel::{SimulationKernel, SortKernel}; +use rustcoalescence_algorithms_cuda_gpu_kernel::{SimulatableKernel, SortableKernel}; use crate::error::CudaError; @@ -90,6 +95,10 @@ pub fn simulate< <>::WaterLevelReporter as Reporter>::ReportSpeciation, <>::WaterLevelReporter as Reporter>::ReportDispersal, >, + mut sort_kernel: SortKernel< + <>::WaterLevelReporter as Reporter>::ReportSpeciation, + <>::WaterLevelReporter as Reporter>::ReportDispersal, + >, config: (GridSize, BlockSize, DedupCache, NonZeroU64), stream: &'stream Stream, lineages: LI, @@ -189,6 +198,8 @@ pub fn simulate< let mut next_event_time_buffer = ExchangeWrapperOnHost::new(ValueBuffer::new(&block_size, &grid_size)?)?; + let max_events_per_type_individual = event_buffer.max_events_per_type_individual(); + let mut min_spec_samples = dedup_cache.construct(slow_lineages.len()); #[allow(clippy::or_fun_call)] @@ -302,18 +313,26 @@ pub fn simulate< let next_event_time_buffer_host = next_event_time_buffer_cuda.move_to_host_async(stream)?; let task_list_host = task_list_cuda.move_to_host_async(stream)?; - let event_buffer_host = event_buffer_cuda.move_to_host_async(stream)?; let mut size = 2; - // TODO: dispersal and speciation have different buffer lengths - while size <= num_tasks { + while size <= num_tasks * max_events_per_type_individual { let mut stride = size / 2; while stride > 0 { - // oddEvenMergeGlobal<<<(batchSize * arrayLength) / 512, 256>>>( - // d_DstKey, d_DstVal, d_DstKey, d_DstVal, arrayLength, size, stride, - // dir); + let grid = u32::try_from( + num_tasks * max_events_per_type_individual / 512, + ) + .map_err(|_| { + rust_cuda::rustacuda::error::CudaError::LaunchOutOfResources + })?; + + sort_kernel.with_grid(grid.into()).sort_events_async( + stream, + event_buffer_cuda.as_mut_async(), + size.into(), + stride.into(), + )?; stride >>= 1; } @@ -321,6 +340,8 @@ pub fn simulate< size <<= 1; } + let event_buffer_host = event_buffer_cuda.move_to_host_async(stream)?; + min_spec_sample_buffer = min_spec_sample_buffer_host.sync_to_host()?; next_event_time_buffer = next_event_time_buffer_host.sync_to_host()?; task_list = task_list_host.sync_to_host()?; From 727dd770e5b5a5116682d1afc380f127b8aacd94 Mon Sep 17 00:00:00 2001 From: Juniper Tyree Date: Mon, 28 Nov 2022 15:40:19 -0800 Subject: [PATCH 28/42] some progress on CUDA event sorting, still buggy --- necsim/impls/cuda/src/event_buffer.rs | 18 +++++++++++++++++- .../cuda/src/parallelisation/monolithic.rs | 10 +++++++--- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/necsim/impls/cuda/src/event_buffer.rs b/necsim/impls/cuda/src/event_buffer.rs index ea05a41ec..9ef83a310 100644 --- a/necsim/impls/cuda/src/event_buffer.rs +++ b/necsim/impls/cuda/src/event_buffer.rs @@ -130,26 +130,42 @@ impl P: Reporter, { if ReportDispersal::VALUE { + let mut last_time = 0.0_f64; + // let mut times = alloc::vec::Vec::new(); + for (mask, dispersal) in self .dispersal_mask .iter_mut() .zip(self.dispersal_buffer.iter()) { if *mask.read() { + let new_time: f64 = unsafe { dispersal.read().assume_some_ref() }.event_time.get(); + // times.push(Some(new_time)); + assert!(new_time >= last_time, "{} {}", new_time, last_time); + last_time = new_time; reporter.report_dispersal(unsafe { dispersal.read().assume_some_ref() }.into()); - } + } // else { + // times.push(None); + // } mask.write(false); } + + // panic!("{:?}", times); } if ReportSpeciation::VALUE { + let mut last_time = 0.0_f64; + for (mask, speciation) in self .speciation_mask .iter_mut() .zip(self.speciation_buffer.iter()) { if *mask.read() { + let new_time: f64 = unsafe { speciation.read().assume_some_ref() }.event_time.get(); + assert!(new_time >= last_time, "{} {}", new_time, last_time); + last_time = new_time; reporter .report_speciation(unsafe { speciation.read().assume_some_ref() }.into()); } diff --git a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs index b517db887..0e52ada7c 100644 --- a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs +++ b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs @@ -316,12 +316,12 @@ pub fn simulate< let mut size = 2; - while size <= num_tasks * max_events_per_type_individual { - let mut stride = size / 2; + loop { + let mut stride = size >> 1; while stride > 0 { let grid = u32::try_from( - num_tasks * max_events_per_type_individual / 512, + (num_tasks * max_events_per_type_individual + 511) / 512, ) .map_err(|_| { rust_cuda::rustacuda::error::CudaError::LaunchOutOfResources @@ -337,6 +337,10 @@ pub fn simulate< stride >>= 1; } + if size >= (num_tasks * max_events_per_type_individual) { + break; + } + size <<= 1; } From 5784307ad764bb20c5848c51a424d5e522024349 Mon Sep 17 00:00:00 2001 From: Juniper Tyree Date: Wed, 30 Nov 2022 07:17:55 -0800 Subject: [PATCH 29/42] Upgrade to 2021 edition + better GPU-event-sorting --- docs/simulate.ron | 5 + necsim/core/Cargo.toml | 2 +- necsim/core/bond/Cargo.toml | 2 +- necsim/core/maths/Cargo.toml | 2 +- necsim/impls/cuda/Cargo.toml | 2 +- necsim/impls/cuda/src/event_buffer.rs | 455 ++++++------------ necsim/impls/cuda/src/lib.rs | 1 + necsim/impls/no-std/Cargo.toml | 2 +- necsim/impls/std/Cargo.toml | 2 +- necsim/partitioning/core/Cargo.toml | 2 +- necsim/partitioning/monolithic/Cargo.toml | 2 +- necsim/partitioning/mpi/Cargo.toml | 2 +- necsim/plugins/common/Cargo.toml | 2 +- necsim/plugins/core/Cargo.toml | 2 +- necsim/plugins/csv/Cargo.toml | 2 +- necsim/plugins/metacommunity/Cargo.toml | 2 +- necsim/plugins/species/Cargo.toml | 2 +- necsim/plugins/statistics/Cargo.toml | 2 +- necsim/plugins/tskit/Cargo.toml | 2 +- rustcoalescence/Cargo.toml | 2 +- rustcoalescence/algorithms/Cargo.toml | 2 +- rustcoalescence/algorithms/cuda/Cargo.toml | 2 +- .../algorithms/cuda/cpu-kernel/Cargo.toml | 2 +- .../algorithms/cuda/cpu-kernel/src/patch.rs | 4 +- .../algorithms/cuda/gpu-kernel/Cargo.toml | 2 +- .../algorithms/cuda/gpu-kernel/src/lib.rs | 8 +- .../algorithms/cuda/src/arguments.rs | 18 +- rustcoalescence/algorithms/cuda/src/launch.rs | 16 +- .../cuda/src/parallelisation/monolithic.rs | 63 +-- .../algorithms/gillespie/Cargo.toml | 2 +- .../algorithms/independent/Cargo.toml | 2 +- rustcoalescence/scenarios/Cargo.toml | 2 +- 32 files changed, 231 insertions(+), 387 deletions(-) diff --git a/docs/simulate.ron b/docs/simulate.ron index 90409129a..a2bab19de 100644 --- a/docs/simulate.ron +++ b/docs/simulate.ron @@ -522,9 +522,14 @@ /* CUDA thread grid 1D size, should be a power of 2 * optional, default = 64 */ grid_size: (u32), + /* CUDA event sorting thread block 1D size, should be a power of 2 + * optional, default = 512 */ + sort_block_size: (u32), /* number of steps which an individual performs on the GPU without supervision * -> shorter slices enable quicker termination of single individuals * -> longer slices incur less overhead from kernel launches + * -> if step_slice = a * 2^b, i.e. aligned to some power of two, + * slightly less sorting needs to be performed * optional, default = 150 */ step_slice: (0 < u64), /* selection of the mode of the individual deduplication cache diff --git a/necsim/core/Cargo.toml b/necsim/core/Cargo.toml index b5b8fd55a..c8d0eda89 100644 --- a/necsim/core/Cargo.toml +++ b/necsim/core/Cargo.toml @@ -3,7 +3,7 @@ name = "necsim-core" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/necsim/core/bond/Cargo.toml b/necsim/core/bond/Cargo.toml index a8c16247a..7b2ab3aa5 100644 --- a/necsim/core/bond/Cargo.toml +++ b/necsim/core/bond/Cargo.toml @@ -3,7 +3,7 @@ name = "necsim-core-bond" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/necsim/core/maths/Cargo.toml b/necsim/core/maths/Cargo.toml index cabab1e5f..7bf9cfcd8 100644 --- a/necsim/core/maths/Cargo.toml +++ b/necsim/core/maths/Cargo.toml @@ -3,7 +3,7 @@ name = "necsim-core-maths" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/necsim/impls/cuda/Cargo.toml b/necsim/impls/cuda/Cargo.toml index 8c380677b..784b0bfee 100644 --- a/necsim/impls/cuda/Cargo.toml +++ b/necsim/impls/cuda/Cargo.toml @@ -3,7 +3,7 @@ name = "necsim-impls-cuda" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/necsim/impls/cuda/src/event_buffer.rs b/necsim/impls/cuda/src/event_buffer.rs index 9ef83a310..2b8eca46f 100644 --- a/necsim/impls/cuda/src/event_buffer.rs +++ b/necsim/impls/cuda/src/event_buffer.rs @@ -41,13 +41,31 @@ pub struct EventBuffer { event_counter: usize, } +mod sealed { + struct Assert; + trait AssertTrue {} + impl AssertTrue for Assert {} + + pub trait AlignedToU64 {} + impl AlignedToU64 for T + where + Assert<{ core::mem::size_of::() % 8 == 0 }>: AssertTrue, + Assert<{ core::mem::align_of::() == 8 }>: AssertTrue, + { + } +} + +pub trait AlignedToU64: sealed::AlignedToU64 {} +impl AlignedToU64 for T {} + pub trait EventType { - type Event: 'static - + ~const rust_cuda::const_type_layout::TypeGraphLayout + type Event: ~const rust_cuda::const_type_layout::TypeGraphLayout + rust_cuda::safety::StackOnly + Into + Into - + Clone; + + Ord + + Clone + + AlignedToU64; } impl EventType @@ -125,70 +143,40 @@ impl }) } + #[allow(clippy::missing_panics_doc)] // TODO: remove pub fn report_events_unordered

(&mut self, reporter: &mut P) where P: Reporter, { - if ReportDispersal::VALUE { - let mut last_time = 0.0_f64; - // let mut times = alloc::vec::Vec::new(); - - for (mask, dispersal) in self - .dispersal_mask - .iter_mut() - .zip(self.dispersal_buffer.iter()) - { - if *mask.read() { - let new_time: f64 = unsafe { dispersal.read().assume_some_ref() }.event_time.get(); - // times.push(Some(new_time)); - assert!(new_time >= last_time, "{} {}", new_time, last_time); - last_time = new_time; - reporter.report_dispersal(unsafe { dispersal.read().assume_some_ref() }.into()); - } // else { - // times.push(None); - // } - - mask.write(false); - } - - // panic!("{:?}", times); - } - - if ReportSpeciation::VALUE { - let mut last_time = 0.0_f64; - - for (mask, speciation) in self - .speciation_mask - .iter_mut() - .zip(self.speciation_buffer.iter()) - { - if *mask.read() { - let new_time: f64 = unsafe { speciation.read().assume_some_ref() }.event_time.get(); - assert!(new_time >= last_time, "{} {}", new_time, last_time); - last_time = new_time; - reporter - .report_speciation(unsafe { speciation.read().assume_some_ref() }.into()); + let mut last_time = 0.0_f64; + + for (mask, event) in self.event_mask.iter_mut().zip(self.event_buffer.iter()) { + if *mask.read() { + let event: TypedEvent = unsafe { event.read().assume_some_read() }.into(); + let new_time: f64 = match &event { + TypedEvent::Speciation(speciation) => speciation.event_time, + TypedEvent::Dispersal(dispersal) => dispersal.event_time, } + .get(); + assert!(new_time >= last_time, "{new_time} {last_time}"); + last_time = new_time; - mask.write(false); + match event { + TypedEvent::Speciation(ref speciation) => { + reporter.report_speciation(speciation.into()); + }, + TypedEvent::Dispersal(ref dispersal) => { + reporter.report_dispersal(dispersal.into()); + }, + } } + + mask.write(false); } } - pub fn max_events_per_type_individual(&self) -> usize { - #[allow(clippy::bool_to_int_with_if)] - let max_speciation_events = if ReportSpeciation::VALUE { - 1_usize - } else { - 0_usize - }; - let max_dispersal_events = if ReportDispersal::VALUE { - self.max_events - } else { - 0_usize - }; - - max_speciation_events.max(max_dispersal_events) + pub fn max_events_per_individual(&self) -> usize { + self.max_events } } @@ -197,69 +185,29 @@ impl EventBuffer { pub fn sort_events(&mut self) { - if ReportDispersal::VALUE { - let mut events: alloc::vec::Vec = alloc::vec::Vec::new(); - - for (mask, dispersal) in self - .dispersal_mask - .iter_mut() - .zip(self.dispersal_buffer.iter()) - { - if *mask.read() { - events.push(unsafe { dispersal.read().assume_some_read() }); - } + let mut events: alloc::vec::Vec<::Event> = alloc::vec::Vec::new(); - mask.write(false); + for (mask, event) in self.event_mask.iter_mut().zip(self.event_buffer.iter()) { + if *mask.read() { + events.push(unsafe { event.read().assume_some_read() }); } - events.sort_unstable(); - - for ((event, mask), dispersal) in events - .into_iter() - .zip(self.dispersal_mask.iter_mut()) - .zip(self.dispersal_buffer.iter_mut()) - { - *dispersal.as_scratch_mut() = MaybeSome::Some(event); - mask.write(true); - } + mask.write(false); } - if ReportSpeciation::VALUE { - let mut events: alloc::vec::Vec = alloc::vec::Vec::new(); - - for (mask, speciation) in self - .speciation_mask - .iter_mut() - .zip(self.speciation_buffer.iter()) - { - if *mask.read() { - events.push(unsafe { speciation.read().assume_some_read() }); - } - - mask.write(false); - } - - events.sort_unstable(); + events.sort_unstable(); - for ((event, mask), speciation) in events - .into_iter() - .zip(self.speciation_mask.iter_mut()) - .zip(self.speciation_buffer.iter_mut()) - { - *speciation.as_scratch_mut() = MaybeSome::Some(event); - mask.write(true); - } + for ((event, mask), scratch) in events + .into_iter() + .zip(self.event_mask.iter_mut()) + .zip(self.event_buffer.iter_mut()) + { + *scratch.as_scratch_mut() = MaybeSome::Some(event); + mask.write(true); } } } -#[cfg(target_os = "cuda")] -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum SortStepDirection { - Less, - Greater, -} - #[cfg(target_os = "cuda")] impl EventBuffer @@ -270,218 +218,95 @@ impl /// All CUDA threads must call this method with the same size, stride, and /// direction arguments. Only one call per kernel launch is safe without /// further synchronisation. - pub unsafe fn sort_events_step( - &mut self, - size: usize, - stride: usize, - direction: SortStepDirection, - ) { + pub unsafe fn sort_events_step(&mut self, size: usize, stride: usize) { use core::cmp::Ordering; - if ReportDispersal::VALUE { - let idx = rust_cuda::device::utils::index(); - - // odd-even merge position - let pos = 2 * idx - (idx & (stride - 1)); - - let (pos_a, pos_b) = if stride < (size / 2) { - (pos - stride, pos) - } else { - (pos, pos + stride) - }; - - let offset = idx & ((size / 2) - 1); - - if (pos_a < self.dispersal_mask.alias_unchecked().len()) - && (pos_b < self.dispersal_mask.alias_unchecked().len()) - && ((stride >= (size / 2)) || (offset >= stride)) - { - let mask_a: bool = *self.dispersal_mask.alias_unchecked()[pos_a].read(); - let mask_b: bool = *self.dispersal_mask.alias_unchecked()[pos_b].read(); - - let cmp = match (mask_a, mask_b) { - (false, false) => Ordering::Equal, - (false, true) => Ordering::Greater, - (true, false) => Ordering::Less, - (true, true) => { - // Safety: both masks indicate that the two events exist - let event_a: &DispersalEvent = unsafe { - self.dispersal_buffer.alias_unchecked()[pos_a] - .as_uninit() - .assume_init_ref() - .assume_some_ref() - }; - let event_b: &DispersalEvent = unsafe { - self.dispersal_buffer.alias_unchecked()[pos_b] - .as_uninit() - .assume_init_ref() - .assume_some_ref() - }; - - event_a.cmp(event_b) - }, - }; - - if let (SortStepDirection::Greater, Ordering::Greater) - | (SortStepDirection::Less, Ordering::Less) = (direction, cmp) - { - self.dispersal_mask.alias_mut_unchecked()[pos_a].write(mask_b); - self.dispersal_mask.alias_mut_unchecked()[pos_b].write(mask_a); - - match (mask_a, mask_b) { - (false, false) => (), - (false, true) => { - let event_b: DispersalEvent = unsafe { - self.dispersal_buffer.alias_unchecked()[pos_b] - .as_uninit() - .assume_init_ref() - .assume_some_read() - }; - - unsafe { - self.dispersal_buffer.alias_mut_unchecked()[pos_a] - .write(MaybeSome::Some(event_b)); - } - }, - (true, false) => { - let event_a: DispersalEvent = unsafe { - self.dispersal_buffer.alias_unchecked()[pos_a] - .as_uninit() - .assume_init_ref() - .assume_some_read() - }; - - unsafe { - self.dispersal_buffer.alias_mut_unchecked()[pos_b] - .write(MaybeSome::Some(event_a)); - } - }, - (true, true) => { - let event_a: DispersalEvent = unsafe { - self.dispersal_buffer.alias_unchecked()[pos_a] - .as_uninit() - .assume_init_ref() - .assume_some_read() - }; - let event_b: DispersalEvent = unsafe { - self.dispersal_buffer.alias_unchecked()[pos_b] - .as_uninit() - .assume_init_ref() - .assume_some_read() - }; - - unsafe { - self.dispersal_buffer.alias_mut_unchecked()[pos_a] - .write(MaybeSome::Some(event_b)); - self.dispersal_buffer.alias_mut_unchecked()[pos_b] - .write(MaybeSome::Some(event_a)); - } - }, - } - } - } - } + let idx = rust_cuda::device::utils::index(); - if ReportSpeciation::VALUE { - let idx = rust_cuda::device::utils::index(); + // Odd-Even merge based on + // https://github.com/NVIDIA/cuda-samples/blob/81992093d2b8c33cab22dbf6852c070c330f1715/Samples/2_Concepts_and_Techniques/sortingNetworks/oddEvenMergeSort.cu#L95-L137 + let pos = 2 * idx - (idx & (stride - 1)); - // odd-even merge position - let pos = 2 * idx - (idx & (stride - 1)); + let (pos_a, pos_b) = if stride < (size / 2) { + (pos.wrapping_sub(stride), pos) + } else { + (pos, pos + stride) + }; - let (pos_a, pos_b) = if stride < (size / 2) { - (pos - stride, pos) - } else { - (pos, pos + stride) + let offset = idx & ((size / 2) - 1); + + if (pos_a < self.event_mask.alias_unchecked().len()) + && (pos_b < self.event_mask.alias_unchecked().len()) + && ((stride >= (size / 2)) || (offset >= stride)) + { + let mask_a: bool = *self + .event_mask + .alias_unchecked() + .get_unchecked(pos_a) + .read(); + let mask_b: bool = *self + .event_mask + .alias_unchecked() + .get_unchecked(pos_b) + .read(); + + let cmp = match (mask_a, mask_b) { + (false, false) => Ordering::Equal, + (false, true) => Ordering::Greater, + (true, false) => Ordering::Less, + (true, true) => { + // Safety: both masks indicate that the two events exist + let event_a: &::Event = unsafe { + self.event_buffer + .alias_unchecked() + .get_unchecked(pos_a) + .as_uninit() + .assume_init_ref() + .assume_some_ref() + }; + let event_b: &::Event = unsafe { + self.event_buffer + .alias_unchecked() + .get_unchecked(pos_b) + .as_uninit() + .assume_init_ref() + .assume_some_ref() + }; + + event_a.cmp(event_b) + }, }; - let offset = idx & ((size / 2) - 1); - - if (pos_a < self.speciation_mask.alias_unchecked().len()) - && (pos_b < self.speciation_mask.alias_unchecked().len()) - && ((stride >= (size / 2)) || (offset >= stride)) - { - let mask_a: bool = *self.speciation_mask.alias_unchecked()[pos_a].read(); - let mask_b: bool = *self.speciation_mask.alias_unchecked()[pos_b].read(); - - let cmp = match (mask_a, mask_b) { - (false, false) => Ordering::Equal, - (false, true) => Ordering::Greater, - (true, false) => Ordering::Less, - (true, true) => { - // Safety: both masks indicate that the two events exist - let event_a: &SpeciationEvent = unsafe { - self.speciation_buffer.alias_unchecked()[pos_a] - .as_uninit() - .assume_init_ref() - .assume_some_ref() - }; - let event_b: &SpeciationEvent = unsafe { - self.speciation_buffer.alias_unchecked()[pos_b] - .as_uninit() - .assume_init_ref() - .assume_some_ref() - }; - - event_a.cmp(event_b) - }, - }; - - if let (SortStepDirection::Greater, Ordering::Greater) - | (SortStepDirection::Less, Ordering::Less) = (direction, cmp) - { - self.speciation_mask.alias_mut_unchecked()[pos_a].write(mask_b); - self.speciation_mask.alias_mut_unchecked()[pos_b].write(mask_a); - - match (mask_a, mask_b) { - (false, false) => (), - (false, true) => { - let event_b: SpeciationEvent = unsafe { - self.speciation_buffer.alias_unchecked()[pos_b] - .as_uninit() - .assume_init_ref() - .assume_some_read() - }; - - unsafe { - self.speciation_buffer.alias_mut_unchecked()[pos_a] - .write(MaybeSome::Some(event_b)); - } - }, - (true, false) => { - let event_a: SpeciationEvent = unsafe { - self.speciation_buffer.alias_unchecked()[pos_a] - .as_uninit() - .assume_init_ref() - .assume_some_read() - }; - - unsafe { - self.speciation_buffer.alias_mut_unchecked()[pos_b] - .write(MaybeSome::Some(event_a)); - } - }, - (true, true) => { - let event_a: SpeciationEvent = unsafe { - self.speciation_buffer.alias_unchecked()[pos_a] - .as_uninit() - .assume_init_ref() - .assume_some_read() - }; - let event_b: SpeciationEvent = unsafe { - self.speciation_buffer.alias_unchecked()[pos_b] - .as_uninit() - .assume_init_ref() - .assume_some_read() - }; - - unsafe { - self.speciation_buffer.alias_mut_unchecked()[pos_a] - .write(MaybeSome::Some(event_b)); - self.speciation_buffer.alias_mut_unchecked()[pos_b] - .write(MaybeSome::Some(event_a)); - } - }, - } + if let Ordering::Greater = cmp { + self.event_mask + .alias_mut_unchecked() + .get_unchecked_mut(pos_a) + .write(mask_b); + self.event_mask + .alias_mut_unchecked() + .get_unchecked_mut(pos_b) + .write(mask_a); + + let ptr_a: *mut u64 = self + .event_buffer + .alias_mut_unchecked() + .as_mut_ptr() + .add(pos_a) + .cast(); + let ptr_b: *mut u64 = self + .event_buffer + .alias_mut_unchecked() + .as_mut_ptr() + .add(pos_b) + .cast(); + + // Manual swap implementation that can be unrolled without local memory + // Safety: AlignedToU64 guarantees that both events are aligned to u64 + // and can be copied as multiples of u64 + for i in 0..(core::mem::size_of::<::Event>() / 8) { + let swap = *ptr_a.add(i); + *ptr_a.add(i) = *ptr_b.add(i); + *ptr_b.add(i) = swap; } } } diff --git a/necsim/impls/cuda/src/lib.rs b/necsim/impls/cuda/src/lib.rs index 1ba363a8b..882796be7 100644 --- a/necsim/impls/cuda/src/lib.rs +++ b/necsim/impls/cuda/src/lib.rs @@ -5,6 +5,7 @@ #![feature(const_type_name)] #![feature(const_mut_refs)] #![feature(const_refs_to_cell)] +#![feature(generic_const_exprs)] #![cfg_attr(target_os = "cuda", feature(asm_experimental_arch))] #![allow(incomplete_features)] #![feature(specialization)] diff --git a/necsim/impls/no-std/Cargo.toml b/necsim/impls/no-std/Cargo.toml index 394876ebe..3ea654b0b 100644 --- a/necsim/impls/no-std/Cargo.toml +++ b/necsim/impls/no-std/Cargo.toml @@ -3,7 +3,7 @@ name = "necsim-impls-no-std" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/necsim/impls/std/Cargo.toml b/necsim/impls/std/Cargo.toml index 9e7db8f7e..4a1626026 100644 --- a/necsim/impls/std/Cargo.toml +++ b/necsim/impls/std/Cargo.toml @@ -3,7 +3,7 @@ name = "necsim-impls-std" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/necsim/partitioning/core/Cargo.toml b/necsim/partitioning/core/Cargo.toml index ab5292bd8..ad52d3dd9 100644 --- a/necsim/partitioning/core/Cargo.toml +++ b/necsim/partitioning/core/Cargo.toml @@ -3,7 +3,7 @@ name = "necsim-partitioning-core" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/necsim/partitioning/monolithic/Cargo.toml b/necsim/partitioning/monolithic/Cargo.toml index f81c7ecc7..a4b96c672 100644 --- a/necsim/partitioning/monolithic/Cargo.toml +++ b/necsim/partitioning/monolithic/Cargo.toml @@ -3,7 +3,7 @@ name = "necsim-partitioning-monolithic" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/necsim/partitioning/mpi/Cargo.toml b/necsim/partitioning/mpi/Cargo.toml index 254c8d23f..d392f8e1b 100644 --- a/necsim/partitioning/mpi/Cargo.toml +++ b/necsim/partitioning/mpi/Cargo.toml @@ -3,7 +3,7 @@ name = "necsim-partitioning-mpi" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/necsim/plugins/common/Cargo.toml b/necsim/plugins/common/Cargo.toml index fa08f3923..6e7d4e24c 100644 --- a/necsim/plugins/common/Cargo.toml +++ b/necsim/plugins/common/Cargo.toml @@ -3,7 +3,7 @@ name = "necsim-plugins-common" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" [lib] crate-type = ["cdylib", "lib"] diff --git a/necsim/plugins/core/Cargo.toml b/necsim/plugins/core/Cargo.toml index 84e37a4f4..d9c179082 100644 --- a/necsim/plugins/core/Cargo.toml +++ b/necsim/plugins/core/Cargo.toml @@ -3,7 +3,7 @@ name = "necsim-plugins-core" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/necsim/plugins/csv/Cargo.toml b/necsim/plugins/csv/Cargo.toml index bfa0d1f5b..b6363d3cf 100644 --- a/necsim/plugins/csv/Cargo.toml +++ b/necsim/plugins/csv/Cargo.toml @@ -3,7 +3,7 @@ name = "necsim-plugins-csv" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" [lib] crate-type = ["cdylib"] diff --git a/necsim/plugins/metacommunity/Cargo.toml b/necsim/plugins/metacommunity/Cargo.toml index 27e186e9a..ecab1b606 100644 --- a/necsim/plugins/metacommunity/Cargo.toml +++ b/necsim/plugins/metacommunity/Cargo.toml @@ -3,7 +3,7 @@ name = "necsim-plugins-metacommunity" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" [lib] crate-type = ["cdylib"] diff --git a/necsim/plugins/species/Cargo.toml b/necsim/plugins/species/Cargo.toml index cdc56d5cc..96543ed6d 100644 --- a/necsim/plugins/species/Cargo.toml +++ b/necsim/plugins/species/Cargo.toml @@ -3,7 +3,7 @@ name = "necsim-plugins-species" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" [lib] crate-type = ["cdylib"] diff --git a/necsim/plugins/statistics/Cargo.toml b/necsim/plugins/statistics/Cargo.toml index f2f57e266..6f3c8202e 100644 --- a/necsim/plugins/statistics/Cargo.toml +++ b/necsim/plugins/statistics/Cargo.toml @@ -3,7 +3,7 @@ name = "necsim-plugins-statistics" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" [lib] crate-type = ["cdylib"] diff --git a/necsim/plugins/tskit/Cargo.toml b/necsim/plugins/tskit/Cargo.toml index 8f973944a..4eff8f963 100644 --- a/necsim/plugins/tskit/Cargo.toml +++ b/necsim/plugins/tskit/Cargo.toml @@ -3,7 +3,7 @@ name = "necsim-plugins-tskit" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" [lib] crate-type = ["cdylib"] diff --git a/rustcoalescence/Cargo.toml b/rustcoalescence/Cargo.toml index d1639ed89..ebf41fc18 100644 --- a/rustcoalescence/Cargo.toml +++ b/rustcoalescence/Cargo.toml @@ -3,7 +3,7 @@ name = "rustcoalescence" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/rustcoalescence/algorithms/Cargo.toml b/rustcoalescence/algorithms/Cargo.toml index a78d5aa56..48f1d4f3b 100644 --- a/rustcoalescence/algorithms/Cargo.toml +++ b/rustcoalescence/algorithms/Cargo.toml @@ -3,7 +3,7 @@ name = "rustcoalescence-algorithms" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/rustcoalescence/algorithms/cuda/Cargo.toml b/rustcoalescence/algorithms/cuda/Cargo.toml index b92b95f68..56ed1150e 100644 --- a/rustcoalescence/algorithms/cuda/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/Cargo.toml @@ -3,7 +3,7 @@ name = "rustcoalescence-algorithms-cuda" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml index bd8f12ed3..34f038825 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml @@ -3,7 +3,7 @@ name = "rustcoalescence-algorithms-cuda-cpu-kernel" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs b/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs index 0a7fff6dc..74889fafd 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs @@ -161,7 +161,7 @@ where unsafe { unreachable_cuda_simulation_linking_reporter() } } - default fn sort_events<'stream>( + default fn sort_events_step<'stream>( &mut self, _stream: &'stream Stream, _event_buffer_reporter: &mut EventBuffer, @@ -171,7 +171,7 @@ where unsafe { unreachable_cuda_simulation_linking_reporter() } } - default fn sort_events_async<'stream>( + default fn sort_events_step_async<'stream>( &mut self, _stream: &'stream Stream, _event_buffer_reporter: HostAndDeviceMutRefAsync< diff --git a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml index a4be7ce1b..778f4448b 100644 --- a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml @@ -3,7 +3,7 @@ name = "rustcoalescence-algorithms-cuda-gpu-kernel" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" [lib] crate-type = ["cdylib", "rlib"] diff --git a/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs b/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs index a6f994027..24c8f4094 100644 --- a/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs +++ b/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs @@ -135,7 +135,7 @@ pub fn simulate< #[rust_cuda::common::kernel( pub use link_sort_kernel! as impl SortableKernel for SortKernel )] -pub fn sort_events( +pub fn sort_events_step( #[kernel(pass = LendRustToCuda, jit)] event_buffer_reporter: &mut ShallowCopy< necsim_impls_cuda::event_buffer::EventBuffer, >, @@ -144,11 +144,7 @@ pub fn sort_events( ) { // Safety: size, stride, and direction are the same on every CUDA thread unsafe { - event_buffer_reporter.sort_events_step( - size, - stride, - necsim_impls_cuda::event_buffer::SortStepDirection::Greater, - ); + event_buffer_reporter.sort_events_step(size, stride); } } diff --git a/rustcoalescence/algorithms/cuda/src/arguments.rs b/rustcoalescence/algorithms/cuda/src/arguments.rs index 94cd9ff21..1f7331b04 100644 --- a/rustcoalescence/algorithms/cuda/src/arguments.rs +++ b/rustcoalescence/algorithms/cuda/src/arguments.rs @@ -1,4 +1,4 @@ -use std::num::NonZeroU64; +use std::num::{NonZeroU32, NonZeroU64}; use serde::{Deserialize, Serialize}; use serde_state::DeserializeState; @@ -59,8 +59,9 @@ pub struct CudaArguments { pub device: u32, pub ptx_jit: bool, pub delta_t: PositiveF64, - pub block_size: u32, - pub grid_size: u32, + pub block_size: NonZeroU32, + pub grid_size: NonZeroU32, + pub sort_block_size: NonZeroU32, pub step_slice: NonZeroU64, pub dedup_cache: DedupCache, pub parallelism_mode: ParallelismMode, @@ -93,6 +94,7 @@ impl<'de> DeserializeState<'de, Partition> for CudaArguments { delta_t: raw.delta_t, block_size: raw.block_size, grid_size: raw.grid_size, + sort_block_size: raw.sort_block_size, step_slice: raw.step_slice, dedup_cache: raw.dedup_cache, parallelism_mode, @@ -107,8 +109,9 @@ pub struct CudaArgumentsRaw { pub device: u32, pub ptx_jit: bool, pub delta_t: PositiveF64, - pub block_size: u32, - pub grid_size: u32, + pub block_size: NonZeroU32, + pub grid_size: NonZeroU32, + pub sort_block_size: NonZeroU32, pub step_slice: NonZeroU64, pub dedup_cache: DedupCache, #[serde(deserialize_state)] @@ -121,8 +124,9 @@ impl Default for CudaArgumentsRaw { device: 0_u32, ptx_jit: true, delta_t: PositiveF64::new(3.0_f64).unwrap(), - block_size: 64_u32, - grid_size: 64_u32, + block_size: NonZeroU32::new(64_u32).unwrap(), + grid_size: NonZeroU32::new(64_u32).unwrap(), + sort_block_size: NonZeroU32::new(512_u32).unwrap(), step_slice: NonZeroU64::new(150_u64).unwrap(), dedup_cache: DedupCache::Relative(RelativeCapacity { factor: PositiveF64::new(0.1_f64).unwrap(), diff --git a/rustcoalescence/algorithms/cuda/src/launch.rs b/rustcoalescence/algorithms/cuda/src/launch.rs index f6f8b1d2f..6bc459d10 100644 --- a/rustcoalescence/algorithms/cuda/src/launch.rs +++ b/rustcoalescence/algorithms/cuda/src/launch.rs @@ -191,8 +191,8 @@ where .build(); // Note: It seems to be more performant to spawn smaller blocks - let block_size = BlockSize::x(args.block_size); - let grid_size = GridSize::x(args.grid_size); + let block_size = BlockSize::x(args.block_size.get()); + let grid_size = GridSize::x(args.grid_size.get()); let event_slice = match args.parallelism_mode { ParallelismMode::Monolithic(MonolithicParallelismMode { event_slice }) @@ -216,8 +216,8 @@ where )?; let sort_kernel = SortKernel::try_new( - GridSize::from(0), - BlockSize::from(256), + GridSize::x(0), + BlockSize::x(args.sort_block_size.get()), args.ptx_jit, Box::new(|kernel| { crate::info::print_kernel_function_attributes("Sorting", kernel); @@ -229,7 +229,13 @@ where &mut simulation, kernel, sort_kernel, - (grid_size, block_size, args.dedup_cache, args.step_slice), + ( + grid_size, + block_size, + args.dedup_cache, + args.step_slice, + args.sort_block_size.get() as usize, + ), &stream, lineages, event_slice, diff --git a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs index 0e52ada7c..5cdc725e0 100644 --- a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs +++ b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs @@ -99,7 +99,7 @@ pub fn simulate< <>::WaterLevelReporter as Reporter>::ReportSpeciation, <>::WaterLevelReporter as Reporter>::ReportDispersal, >, - config: (GridSize, BlockSize, DedupCache, NonZeroU64), + config: (GridSize, BlockSize, DedupCache, NonZeroU64, usize), stream: &'stream Stream, lineages: LI, event_slice: EventSlice, @@ -161,7 +161,7 @@ pub fn simulate< L, >>::WaterLevelReporter::new(event_slice.get(), local_partition); - let (grid_size, block_size, dedup_cache, step_slice) = config; + let (grid_size, block_size, dedup_cache, step_slice, sort_block_size) = config; #[allow(clippy::or_fun_call)] let intial_max_time = slow_lineages @@ -198,7 +198,7 @@ pub fn simulate< let mut next_event_time_buffer = ExchangeWrapperOnHost::new(ValueBuffer::new(&block_size, &grid_size)?)?; - let max_events_per_type_individual = event_buffer.max_events_per_type_individual(); + let max_events_per_individual = event_buffer.max_events_per_individual(); let mut min_spec_samples = dedup_cache.construct(slow_lineages.len()); @@ -314,34 +314,41 @@ pub fn simulate< next_event_time_buffer_cuda.move_to_host_async(stream)?; let task_list_host = task_list_cuda.move_to_host_async(stream)?; - let mut size = 2; - - loop { - let mut stride = size >> 1; + if max_events_per_individual > 0 { + // Each individual generates its events in sorted order + // If the number of events per individual is aligned to some + // power of two, these first sorting steps can be skipped + let mut size = 2.max(0x1 << max_events_per_individual.trailing_zeros()); + + loop { + let mut stride = size >> 1; + + while stride > 0 { + let grid = u32::try_from( + (num_tasks * max_events_per_individual + sort_block_size + - 1) + / sort_block_size, + ) + .map_err(|_| { + rust_cuda::rustacuda::error::CudaError::LaunchOutOfResources + })?; + + sort_kernel.with_grid(grid.into()).sort_events_step_async( + stream, + event_buffer_cuda.as_mut_async(), + size.into(), + stride.into(), + )?; + + stride >>= 1; + } - while stride > 0 { - let grid = u32::try_from( - (num_tasks * max_events_per_type_individual + 511) / 512, - ) - .map_err(|_| { - rust_cuda::rustacuda::error::CudaError::LaunchOutOfResources - })?; - - sort_kernel.with_grid(grid.into()).sort_events_async( - stream, - event_buffer_cuda.as_mut_async(), - size.into(), - stride.into(), - )?; - - stride >>= 1; - } + if size >= (num_tasks * max_events_per_individual) { + break; + } - if size >= (num_tasks * max_events_per_type_individual) { - break; + size <<= 1; } - - size <<= 1; } let event_buffer_host = event_buffer_cuda.move_to_host_async(stream)?; diff --git a/rustcoalescence/algorithms/gillespie/Cargo.toml b/rustcoalescence/algorithms/gillespie/Cargo.toml index a2ec0a594..d63a4facb 100644 --- a/rustcoalescence/algorithms/gillespie/Cargo.toml +++ b/rustcoalescence/algorithms/gillespie/Cargo.toml @@ -3,7 +3,7 @@ name = "rustcoalescence-algorithms-gillespie" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/rustcoalescence/algorithms/independent/Cargo.toml b/rustcoalescence/algorithms/independent/Cargo.toml index 82fd8bc61..7a92e142b 100644 --- a/rustcoalescence/algorithms/independent/Cargo.toml +++ b/rustcoalescence/algorithms/independent/Cargo.toml @@ -3,7 +3,7 @@ name = "rustcoalescence-algorithms-independent" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/rustcoalescence/scenarios/Cargo.toml b/rustcoalescence/scenarios/Cargo.toml index ffe3731e6..455dc3a23 100644 --- a/rustcoalescence/scenarios/Cargo.toml +++ b/rustcoalescence/scenarios/Cargo.toml @@ -3,7 +3,7 @@ name = "rustcoalescence-scenarios" version = "0.1.0" authors = ["Juniper Tyree "] license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From dc198d0dcd8befb0d23a9ea5f0f3e9589de9591e Mon Sep 17 00:00:00 2001 From: Juniper Tyree Date: Wed, 30 Nov 2022 07:23:38 -0800 Subject: [PATCH 30/42] Upgrade to latest const-type-layout and rust-cuda --- Cargo.lock | 28 +++++++++---------- necsim/core/Cargo.toml | 6 ++-- necsim/core/bond/Cargo.toml | 2 +- necsim/impls/cuda/Cargo.toml | 6 ++-- necsim/impls/no-std/Cargo.toml | 6 ++-- rustcoalescence/algorithms/cuda/Cargo.toml | 2 +- .../algorithms/cuda/cpu-kernel/Cargo.toml | 2 +- .../algorithms/cuda/gpu-kernel/Cargo.toml | 2 +- 8 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ebeb726b8..8f27e68c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -409,23 +409,23 @@ dependencies = [ [[package]] name = "const-type-layout" version = "0.1.0" -source = "git+https://github.com/juntyr/const-type-layout?rev=49aa113#49aa113140ad1976df5b3d24e04c794665f3097b" +source = "git+https://github.com/juntyr/const-type-layout?rev=8c7d721#8c7d721643c9013bba0a8b01020a37d8352b5808" dependencies = [ - "const-type-layout-derive 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=49aa113)", + "const-type-layout-derive 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=8c7d721)", ] [[package]] name = "const-type-layout" version = "0.1.0" -source = "git+https://github.com/MomoLangenstein/const-type-layout?rev=49aa113#49aa113140ad1976df5b3d24e04c794665f3097b" +source = "git+https://github.com/MomoLangenstein/const-type-layout?rev=8c7d721#8c7d721643c9013bba0a8b01020a37d8352b5808" dependencies = [ - "const-type-layout-derive 0.1.0 (git+https://github.com/MomoLangenstein/const-type-layout?rev=49aa113)", + "const-type-layout-derive 0.1.0 (git+https://github.com/MomoLangenstein/const-type-layout?rev=8c7d721)", ] [[package]] name = "const-type-layout-derive" version = "0.1.0" -source = "git+https://github.com/juntyr/const-type-layout?rev=49aa113#49aa113140ad1976df5b3d24e04c794665f3097b" +source = "git+https://github.com/juntyr/const-type-layout?rev=8c7d721#8c7d721643c9013bba0a8b01020a37d8352b5808" dependencies = [ "proc-macro-error", "proc-macro2", @@ -436,7 +436,7 @@ dependencies = [ [[package]] name = "const-type-layout-derive" version = "0.1.0" -source = "git+https://github.com/MomoLangenstein/const-type-layout?rev=49aa113#49aa113140ad1976df5b3d24e04c794665f3097b" +source = "git+https://github.com/MomoLangenstein/const-type-layout?rev=8c7d721#8c7d721643c9013bba0a8b01020a37d8352b5808" dependencies = [ "proc-macro-error", "proc-macro2", @@ -1022,7 +1022,7 @@ dependencies = [ name = "necsim-core" version = "0.1.0" dependencies = [ - "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=49aa113)", + "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=8c7d721)", "contracts", "necsim-core-bond", "necsim-core-maths", @@ -1034,7 +1034,7 @@ dependencies = [ name = "necsim-core-bond" version = "0.1.0" dependencies = [ - "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=49aa113)", + "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=8c7d721)", "necsim-core-maths", "serde", ] @@ -1047,7 +1047,7 @@ version = "0.1.0" name = "necsim-impls-cuda" version = "0.1.0" dependencies = [ - "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=49aa113)", + "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=8c7d721)", "contracts", "necsim-core", "rust-cuda", @@ -1058,7 +1058,7 @@ dependencies = [ name = "necsim-impls-no-std" version = "0.1.0" dependencies = [ - "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=49aa113)", + "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=8c7d721)", "contracts", "displaydoc", "final", @@ -1487,9 +1487,9 @@ dependencies = [ [[package]] name = "rust-cuda" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=be31ebda#be31ebdacb0734cbc6509b91dab499cc173ebbf4" +source = "git+https://github.com/juntyr/rust-cuda?rev=d5dfd114#d5dfd114e5d1c54dae4d358d8cc4bc8f5ea62f2a" dependencies = [ - "const-type-layout 0.1.0 (git+https://github.com/MomoLangenstein/const-type-layout?rev=49aa113)", + "const-type-layout 0.1.0 (git+https://github.com/MomoLangenstein/const-type-layout?rev=8c7d721)", "final", "rust-cuda-derive", "rust-cuda-ptx-jit", @@ -1501,7 +1501,7 @@ dependencies = [ [[package]] name = "rust-cuda-derive" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=be31ebda#be31ebdacb0734cbc6509b91dab499cc173ebbf4" +source = "git+https://github.com/juntyr/rust-cuda?rev=d5dfd114#d5dfd114e5d1c54dae4d358d8cc4bc8f5ea62f2a" dependencies = [ "cargo_metadata", "colored", @@ -1520,7 +1520,7 @@ dependencies = [ [[package]] name = "rust-cuda-ptx-jit" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=be31ebda#be31ebdacb0734cbc6509b91dab499cc173ebbf4" +source = "git+https://github.com/juntyr/rust-cuda?rev=d5dfd114#d5dfd114e5d1c54dae4d358d8cc4bc8f5ea62f2a" dependencies = [ "lazy_static", "regex", diff --git a/necsim/core/Cargo.toml b/necsim/core/Cargo.toml index c8d0eda89..2531cbd25 100644 --- a/necsim/core/Cargo.toml +++ b/necsim/core/Cargo.toml @@ -15,12 +15,12 @@ cuda = ["rust-cuda"] necsim-core-maths = { path = "maths" } necsim-core-bond = { path = "bond" } -const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "49aa113" } +const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "8c7d721" } contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "be31ebda", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "d5dfd114", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "be31ebda", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "d5dfd114", features = ["derive", "host"], optional = true } diff --git a/necsim/core/bond/Cargo.toml b/necsim/core/bond/Cargo.toml index 7b2ab3aa5..927e37b4e 100644 --- a/necsim/core/bond/Cargo.toml +++ b/necsim/core/bond/Cargo.toml @@ -13,5 +13,5 @@ default = [] [dependencies] necsim-core-maths = { path = "../maths" } -const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "49aa113" } +const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "8c7d721" } serde = { version = "1.0", default-features = false, features = ["derive"] } diff --git a/necsim/impls/cuda/Cargo.toml b/necsim/impls/cuda/Cargo.toml index 784b0bfee..fc96d95cd 100644 --- a/necsim/impls/cuda/Cargo.toml +++ b/necsim/impls/cuda/Cargo.toml @@ -10,12 +10,12 @@ edition = "2021" [dependencies] necsim-core = { path = "../../core", features = ["cuda"] } -const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "49aa113" } +const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "8c7d721" } contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "be31ebda", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "d5dfd114", features = ["derive"] } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "be31ebda", features = ["derive", "host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "d5dfd114", features = ["derive", "host"] } diff --git a/necsim/impls/no-std/Cargo.toml b/necsim/impls/no-std/Cargo.toml index 3ea654b0b..2a83701f4 100644 --- a/necsim/impls/no-std/Cargo.toml +++ b/necsim/impls/no-std/Cargo.toml @@ -17,7 +17,7 @@ necsim-core-maths = { path = "../../core/maths" } necsim-core-bond = { path = "../../core/bond" } necsim-partitioning-core = { path = "../../partitioning/core" } -const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "49aa113" } +const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "8c7d721" } contracts = "0.6.3" libm = "0.2" hashbrown = "0.13" @@ -31,7 +31,7 @@ rand_core = "0.6" rand_distr = { version = "0.4", default-features = false, features = [] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "be31ebda", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "d5dfd114", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "be31ebda", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "d5dfd114", features = ["derive", "host"], optional = true } diff --git a/rustcoalescence/algorithms/cuda/Cargo.toml b/rustcoalescence/algorithms/cuda/Cargo.toml index 56ed1150e..0d6f15082 100644 --- a/rustcoalescence/algorithms/cuda/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/Cargo.toml @@ -23,4 +23,4 @@ thiserror = "1.0" serde = { version = "1.0", features = ["derive"] } serde_state = "0.4" serde_derive_state = "0.4" -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "be31ebda", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "d5dfd114", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml index 34f038825..a49d7e45b 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml @@ -14,4 +14,4 @@ necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["c necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } rustcoalescence-algorithms-cuda-gpu-kernel = { path = "../gpu-kernel" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "be31ebda", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "d5dfd114", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml index 778f4448b..a87b284dd 100644 --- a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml @@ -16,4 +16,4 @@ necsim-core-bond = { path = "../../../../necsim/core/bond" } necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["cuda"] } necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "be31ebda", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "d5dfd114", features = ["derive"] } From f78384e6a659a888081e4ba048c429b6caf77d95 Mon Sep 17 00:00:00 2001 From: Juniper Tyree Date: Wed, 30 Nov 2022 14:26:17 -0800 Subject: [PATCH 31/42] Start with bitonic sort implementation [wip] --- Cargo.lock | 6 +- necsim/core/Cargo.toml | 4 +- necsim/core/src/event.rs | 1 + necsim/impls/cuda/Cargo.toml | 4 +- necsim/impls/cuda/src/event_buffer.rs | 246 +++++++++++++++++- necsim/impls/cuda/src/lib.rs | 1 + necsim/impls/cuda/src/utils.rs | 1 - necsim/impls/no-std/Cargo.toml | 4 +- rustcoalescence/algorithms/cuda/Cargo.toml | 2 +- .../algorithms/cuda/cpu-kernel/Cargo.toml | 2 +- .../algorithms/cuda/gpu-kernel/Cargo.toml | 2 +- .../algorithms/cuda/gpu-kernel/src/lib.rs | 36 ++- .../cuda/src/parallelisation/monolithic.rs | 1 - 13 files changed, 287 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8f27e68c7..6ec5921a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1487,7 +1487,7 @@ dependencies = [ [[package]] name = "rust-cuda" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=d5dfd114#d5dfd114e5d1c54dae4d358d8cc4bc8f5ea62f2a" +source = "git+https://github.com/juntyr/rust-cuda?rev=c56d7f8f#c56d7f8fc372e51a8fe65926f7a52a72c73e8dc3" dependencies = [ "const-type-layout 0.1.0 (git+https://github.com/MomoLangenstein/const-type-layout?rev=8c7d721)", "final", @@ -1501,7 +1501,7 @@ dependencies = [ [[package]] name = "rust-cuda-derive" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=d5dfd114#d5dfd114e5d1c54dae4d358d8cc4bc8f5ea62f2a" +source = "git+https://github.com/juntyr/rust-cuda?rev=c56d7f8f#c56d7f8fc372e51a8fe65926f7a52a72c73e8dc3" dependencies = [ "cargo_metadata", "colored", @@ -1520,7 +1520,7 @@ dependencies = [ [[package]] name = "rust-cuda-ptx-jit" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=d5dfd114#d5dfd114e5d1c54dae4d358d8cc4bc8f5ea62f2a" +source = "git+https://github.com/juntyr/rust-cuda?rev=c56d7f8f#c56d7f8fc372e51a8fe65926f7a52a72c73e8dc3" dependencies = [ "lazy_static", "regex", diff --git a/necsim/core/Cargo.toml b/necsim/core/Cargo.toml index 2531cbd25..cce5b5ed7 100644 --- a/necsim/core/Cargo.toml +++ b/necsim/core/Cargo.toml @@ -20,7 +20,7 @@ contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "d5dfd114", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "c56d7f8f", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "d5dfd114", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "c56d7f8f", features = ["derive", "host"], optional = true } diff --git a/necsim/core/src/event.rs b/necsim/core/src/event.rs index 25f760fa6..e484fc158 100644 --- a/necsim/core/src/event.rs +++ b/necsim/core/src/event.rs @@ -255,6 +255,7 @@ impl PartialEq for PackedEvent { } impl Ord for PackedEvent { + #[inline] fn cmp(&self, other: &Self) -> Ordering { // Order `Event`s in lexicographical order: // (1) event_time /=\ diff --git a/necsim/impls/cuda/Cargo.toml b/necsim/impls/cuda/Cargo.toml index fc96d95cd..ba92b6485 100644 --- a/necsim/impls/cuda/Cargo.toml +++ b/necsim/impls/cuda/Cargo.toml @@ -15,7 +15,7 @@ contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "d5dfd114", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "c56d7f8f", features = ["derive"] } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "d5dfd114", features = ["derive", "host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "c56d7f8f", features = ["derive", "host"] } diff --git a/necsim/impls/cuda/src/event_buffer.rs b/necsim/impls/cuda/src/event_buffer.rs index 2b8eca46f..4c98ec036 100644 --- a/necsim/impls/cuda/src/event_buffer.rs +++ b/necsim/impls/cuda/src/event_buffer.rs @@ -59,35 +59,48 @@ pub trait AlignedToU64: sealed::AlignedToU64 {} impl AlignedToU64 for T {} pub trait EventType { - type Event: ~const rust_cuda::const_type_layout::TypeGraphLayout + type Event: 'static + + ~const rust_cuda::const_type_layout::TypeGraphLayout + rust_cuda::safety::StackOnly + Into + Into + Ord + Clone + AlignedToU64; + + const SHARED_LIMIT: usize; } impl EventType for EventBuffer { default type Event = PackedEvent; + + default const SHARED_LIMIT: usize = 0; } impl EventType for EventBuffer { type Event = PackedEvent; + + const SHARED_LIMIT: usize = ((48*1024 / core::mem::size_of::()) / 32) * 32; } impl EventType for EventBuffer { type Event = PackedEvent; + + const SHARED_LIMIT: usize = ((48*1024 / core::mem::size_of::()) / 32) * 32; } impl EventType for EventBuffer { type Event = SpeciationEvent; + + const SHARED_LIMIT: usize = ((48*1024 / core::mem::size_of::()) / 32) * 32; } impl EventType for EventBuffer { type Event = PackedEvent; + + const SHARED_LIMIT: usize = ((48*1024 / core::mem::size_of::()) / 32) * 32; } impl fmt::Debug @@ -212,19 +225,238 @@ impl impl EventBuffer { + /// Bitonic sort combined merge step for shared memory, based on + /// + /// + /// # Safety + /// + /// All CUDA threads must call this method with the same size argument. + /// Only one call per kernel launch is safe without further synchronisation. + /// + /// # Panics + /// + /// Panics if the thread block size does not equal `::SHARED_LIMIT`. + pub unsafe fn bitonic_sort_events_shared_step(&mut self, size: usize) where [(); ::SHARED_LIMIT]: { + use core::cmp::Ordering; + + let block_dim = rust_cuda::device::utils::block_dim(); + + rust_cuda::assert_eq!(block_dim.size() * 2, ::SHARED_LIMIT); + + let block_idx = rust_cuda::device::utils::block_idx().as_id(&rust_cuda::device::utils::grid_dim()); + let thread_idx = rust_cuda::device::utils::thread_idx().as_id(&block_dim); + + let idx = block_idx * ::SHARED_LIMIT + thread_idx; + + let shared_mask: rust_cuda::device::ThreadBlockShared< + [bool; ::SHARED_LIMIT] + > = rust_cuda::device::ThreadBlockShared::new_uninit(); + let shared_mask_array: *mut bool = shared_mask.get().cast(); + let shared_buffer: rust_cuda::device::ThreadBlockShared< + [MaybeSome<::Event>; ::SHARED_LIMIT] + > = rust_cuda::device::ThreadBlockShared::new_uninit(); + let shared_buffer_array: *mut MaybeSome<::Event> = shared_buffer.get().cast(); + + *shared_mask_array.add(thread_idx) = match self.event_mask.alias_unchecked().get(idx) { + None => false, + Some(mask) => *mask.read(), + }; + *shared_buffer_array.add(thread_idx) = match self.event_buffer.alias_unchecked().get(idx) { + None => MaybeSome::None, + Some(event) => event.as_uninit().assume_init_read(), + }; + *shared_mask_array.add(thread_idx + (::SHARED_LIMIT / 2)) = match self.event_mask.alias_unchecked().get(idx + (::SHARED_LIMIT / 2)) { + None => false, + Some(mask) => *mask.read(), + }; + *shared_buffer_array.add(thread_idx + (::SHARED_LIMIT / 2)) = match self.event_buffer.alias_unchecked().get(idx + (::SHARED_LIMIT / 2)) { + None => MaybeSome::None, + Some(event) => event.as_uninit().assume_init_read(), + }; + + let pos = (block_idx * block_dim.size() + thread_idx) & ((self.event_mask.alias_unchecked().len().next_power_of_two() / 2) - 1); + let dir = if (pos & (size / 2)) == 0 { + Ordering::Greater + } else { + Ordering::Less + }; + + let mut stride = ::SHARED_LIMIT >> 1; + + while stride > 0 { + ::core::arch::nvptx::_syncthreads(); + + let pos_a = 2 * thread_idx - (thread_idx & (stride - 1)); + let pos_b = pos_a + stride; + + let mask_a: bool = *shared_mask_array.add(pos_a); + let mask_b: bool = *shared_mask_array.add(pos_b); + + let cmp = match (mask_a, mask_b) { + (false, false) => Ordering::Equal, + (false, true) => Ordering::Greater, + (true, false) => Ordering::Less, + (true, true) => { + // Safety: both masks indicate that the two events exist + let event_a: &::Event = unsafe { + (*shared_buffer_array.add(pos_a)).assume_some_ref() + }; + let event_b: &::Event = unsafe { + (*shared_buffer_array.add(pos_b)).assume_some_ref() + }; + + event_a.cmp(event_b) + }, + }; + + if cmp == dir { + *shared_mask_array.add(pos_a) = mask_b; + *shared_mask_array.add(pos_b) = mask_a; + + let ptr_a: *mut u64 = shared_buffer_array.add(pos_a).cast(); + let ptr_b: *mut u64 = shared_buffer_array.add(pos_b).cast(); + + // Manual swap implementation that can be unrolled without local memory + // Safety: AlignedToU64 guarantees that both events are aligned to u64 + // and can be copied as multiples of u64 + for i in 0..(core::mem::size_of::<::Event>() / 8) { + let swap = *ptr_a.add(i); + *ptr_a.add(i) = *ptr_b.add(i); + *ptr_b.add(i) = swap; + } + } + + stride >>= 1; + } + + ::core::arch::nvptx::_syncthreads(); + + if let Some(mask) = self.event_mask.alias_mut_unchecked().get_mut(idx) { + mask.write(*shared_mask_array.add(thread_idx)); + } + if let Some(event) = self.event_buffer.alias_mut_unchecked().get_mut(idx) { + event.write(core::ptr::read(shared_buffer_array.add(thread_idx))); + } + if let Some(mask) = self.event_mask.alias_mut_unchecked().get_mut(idx + (::SHARED_LIMIT / 2)) { + mask.write(*shared_mask_array.add(thread_idx + (::SHARED_LIMIT / 2))); + } + if let Some(event) = self.event_buffer.alias_mut_unchecked().get_mut(idx + (::SHARED_LIMIT / 2)) { + event.write(core::ptr::read(shared_buffer_array.add(thread_idx + (::SHARED_LIMIT / 2)))); + } + } + + /// Bitonic sort single merge step for global memory, based on + /// + /// + /// # Safety + /// + /// All CUDA threads must call this method with the same size and stride arguments. + /// Only one call per kernel launch is safe without further synchronisation. + pub unsafe fn bitonic_sort_events_step(&mut self, size: usize, stride: usize) { + use core::cmp::Ordering; + + let idx = rust_cuda::device::utils::index(); + + let pos = idx & ((self.event_mask.alias_unchecked().len().next_power_of_two() / 2) - 1); + + let dir = if (pos & (size / 2)) == 0 { + Ordering::Greater + } else { + Ordering::Less + }; + + let pos_a = 2 * idx - (idx & (stride - 1)); + let pos_b = pos_a + stride; + + if (pos_a < self.event_mask.alias_unchecked().len()) + && (pos_b < self.event_mask.alias_unchecked().len()) + { + let mask_a: bool = *self + .event_mask + .alias_unchecked() + .get_unchecked(pos_a) + .read(); + let mask_b: bool = *self + .event_mask + .alias_unchecked() + .get_unchecked(pos_b) + .read(); + + let cmp = match (mask_a, mask_b) { + (false, false) => Ordering::Equal, + (false, true) => Ordering::Greater, + (true, false) => Ordering::Less, + (true, true) => { + // Safety: both masks indicate that the two events exist + let event_a: &::Event = unsafe { + self.event_buffer + .alias_unchecked() + .get_unchecked(pos_a) + .as_uninit() + .assume_init_ref() + .assume_some_ref() + }; + let event_b: &::Event = unsafe { + self.event_buffer + .alias_unchecked() + .get_unchecked(pos_b) + .as_uninit() + .assume_init_ref() + .assume_some_ref() + }; + + event_a.cmp(event_b) + }, + }; + + if cmp == dir { + self.event_mask + .alias_mut_unchecked() + .get_unchecked_mut(pos_a) + .write(mask_b); + self.event_mask + .alias_mut_unchecked() + .get_unchecked_mut(pos_b) + .write(mask_a); + + let ptr_a: *mut u64 = self + .event_buffer + .alias_mut_unchecked() + .as_mut_ptr() + .add(pos_a) + .cast(); + let ptr_b: *mut u64 = self + .event_buffer + .alias_mut_unchecked() + .as_mut_ptr() + .add(pos_b) + .cast(); + + // Manual swap implementation that can be unrolled without local memory + // Safety: AlignedToU64 guarantees that both events are aligned to u64 + // and can be copied as multiples of u64 + for i in 0..(core::mem::size_of::<::Event>() / 8) { + let swap = *ptr_a.add(i); + *ptr_a.add(i) = *ptr_b.add(i); + *ptr_b.add(i) = swap; + } + } + } + } + #[allow(clippy::too_many_lines)] + /// Odd-Even sort single merge step for global memory, based on + /// + /// /// # Safety /// - /// All CUDA threads must call this method with the same size, stride, and - /// direction arguments. Only one call per kernel launch is safe without - /// further synchronisation. - pub unsafe fn sort_events_step(&mut self, size: usize, stride: usize) { + /// All CUDA threads must call this method with the same size and stride arguments. + /// Only one call per kernel launch is safe without further synchronisation. + pub unsafe fn odd_even_sort_events_step(&mut self, size: usize, stride: usize) { use core::cmp::Ordering; let idx = rust_cuda::device::utils::index(); - // Odd-Even merge based on - // https://github.com/NVIDIA/cuda-samples/blob/81992093d2b8c33cab22dbf6852c070c330f1715/Samples/2_Concepts_and_Techniques/sortingNetworks/oddEvenMergeSort.cu#L95-L137 let pos = 2 * idx - (idx & (stride - 1)); let (pos_a, pos_b) = if stride < (size / 2) { diff --git a/necsim/impls/cuda/src/lib.rs b/necsim/impls/cuda/src/lib.rs index 882796be7..539bea2ea 100644 --- a/necsim/impls/cuda/src/lib.rs +++ b/necsim/impls/cuda/src/lib.rs @@ -7,6 +7,7 @@ #![feature(const_refs_to_cell)] #![feature(generic_const_exprs)] #![cfg_attr(target_os = "cuda", feature(asm_experimental_arch))] +#![cfg_attr(target_os = "cuda", feature(stdsimd))] #![allow(incomplete_features)] #![feature(specialization)] diff --git a/necsim/impls/cuda/src/utils.rs b/necsim/impls/cuda/src/utils.rs index 123f9288e..27583e729 100644 --- a/necsim/impls/cuda/src/utils.rs +++ b/necsim/impls/cuda/src/utils.rs @@ -8,7 +8,6 @@ use rust_cuda::safety::StackOnly; pub struct MaybeSome(MaybeUninit); impl MaybeSome { - #[cfg(not(target_os = "cuda"))] #[allow(non_upper_case_globals)] pub(crate) const None: Self = Self(MaybeUninit::uninit()); diff --git a/necsim/impls/no-std/Cargo.toml b/necsim/impls/no-std/Cargo.toml index 2a83701f4..53c8de71f 100644 --- a/necsim/impls/no-std/Cargo.toml +++ b/necsim/impls/no-std/Cargo.toml @@ -31,7 +31,7 @@ rand_core = "0.6" rand_distr = { version = "0.4", default-features = false, features = [] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "d5dfd114", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "c56d7f8f", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "d5dfd114", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "c56d7f8f", features = ["derive", "host"], optional = true } diff --git a/rustcoalescence/algorithms/cuda/Cargo.toml b/rustcoalescence/algorithms/cuda/Cargo.toml index 0d6f15082..c68752a16 100644 --- a/rustcoalescence/algorithms/cuda/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/Cargo.toml @@ -23,4 +23,4 @@ thiserror = "1.0" serde = { version = "1.0", features = ["derive"] } serde_state = "0.4" serde_derive_state = "0.4" -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "d5dfd114", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "c56d7f8f", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml index a49d7e45b..502c620e5 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml @@ -14,4 +14,4 @@ necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["c necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } rustcoalescence-algorithms-cuda-gpu-kernel = { path = "../gpu-kernel" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "d5dfd114", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "c56d7f8f", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml index a87b284dd..d36405c2c 100644 --- a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml @@ -16,4 +16,4 @@ necsim-core-bond = { path = "../../../../necsim/core/bond" } necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["cuda"] } necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "d5dfd114", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "c56d7f8f", features = ["derive"] } diff --git a/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs b/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs index 24c8f4094..738e561b1 100644 --- a/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs +++ b/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs @@ -142,12 +142,44 @@ pub fn sort_events_step( #[kernel(pass = SafeDeviceCopy)] size: usize, #[kernel(pass = SafeDeviceCopy)] stride: usize, ) { - // Safety: size, stride, and direction are the same on every CUDA thread + // Safety: size and stride are the same on every CUDA thread unsafe { - event_buffer_reporter.sort_events_step(size, stride); + event_buffer_reporter.odd_even_sort_events_step(size, stride); } } +// #[rust_cuda::common::kernel( +// pub use link_even_odd_sort_kernel! as impl EvenOddSortableKernel for EvenOddSortKernel +// )] +// pub fn even_odd_sort_events_step( +// #[kernel(pass = LendRustToCuda, jit)] event_buffer_reporter: &mut ShallowCopy< +// necsim_impls_cuda::event_buffer::EventBuffer, +// >, +// #[kernel(pass = SafeDeviceCopy)] size: usize, +// #[kernel(pass = SafeDeviceCopy)] stride: usize, +// ) { +// // Safety: size and stride are the same on every CUDA thread +// unsafe { +// event_buffer_reporter.odd_even_sort_events_step(size, stride); +// } +// } + +// #[rust_cuda::common::kernel( +// pub use link_bitonic_sort_kernel! as impl BitonicSortableKernel for BitonicSortKernel +// )] +// pub fn bitonic_sort_events_step( +// #[kernel(pass = LendRustToCuda, jit)] event_buffer_reporter: &mut ShallowCopy< +// necsim_impls_cuda::event_buffer::EventBuffer, +// >, +// #[kernel(pass = SafeDeviceCopy)] size: usize, +// #[kernel(pass = SafeDeviceCopy)] stride: usize, +// ) { +// // Safety: size and stride are the same on every CUDA thread +// unsafe { +// event_buffer_reporter.bitonic_sort_events_step(size, stride); +// } +// } + #[cfg(target_os = "cuda")] mod cuda_prelude { use core::arch::nvptx; diff --git a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs index 5cdc725e0..36e29a0c4 100644 --- a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs +++ b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs @@ -390,7 +390,6 @@ pub fn simulate< next_event_time_buffer.move_to_device_async(stream)?; event_buffer = event_buffer_host.sync_to_host()?; - // event_buffer.sort_events(); event_buffer.report_events_unordered(&mut proxy); event_buffer_cuda = event_buffer.move_to_device_async(stream)?; From 636a3e5e514cc889afc6a5ca240e6d3f15b5e305 Mon Sep 17 00:00:00 2001 From: Juniper Tyree Date: Thu, 1 Dec 2022 05:38:14 -0800 Subject: [PATCH 32/42] Added bitonic sort with shared memory, still much slower than CPU-only --- Cargo.lock | 6 +- necsim/core/Cargo.toml | 4 +- necsim/impls/cuda/Cargo.toml | 4 +- necsim/impls/cuda/src/event_buffer.rs | 391 +++++++++++++++--- necsim/impls/cuda/src/lib.rs | 1 + necsim/impls/cuda/src/utils.rs | 1 + necsim/impls/no-std/Cargo.toml | 4 +- rustcoalescence/algorithms/cuda/Cargo.toml | 2 +- .../algorithms/cuda/cpu-kernel/Cargo.toml | 2 +- .../algorithms/cuda/cpu-kernel/src/lib.rs | 229 +++++++++- .../algorithms/cuda/cpu-kernel/src/link.rs | 69 +++- .../algorithms/cuda/cpu-kernel/src/patch.rs | 157 ++++++- .../algorithms/cuda/gpu-kernel/Cargo.toml | 2 +- .../algorithms/cuda/gpu-kernel/src/lib.rs | 95 +++-- .../algorithms/cuda/src/arguments.rs | 12 + rustcoalescence/algorithms/cuda/src/launch.rs | 57 ++- .../cuda/src/parallelisation/monolithic.rs | 210 ++++++++-- 17 files changed, 1080 insertions(+), 166 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ec5921a0..b994f415a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1487,7 +1487,7 @@ dependencies = [ [[package]] name = "rust-cuda" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=c56d7f8f#c56d7f8fc372e51a8fe65926f7a52a72c73e8dc3" +source = "git+https://github.com/juntyr/rust-cuda?rev=6739fd0b#6739fd0bcbb212ed0c24c0cd5f3bfa8fc66af47d" dependencies = [ "const-type-layout 0.1.0 (git+https://github.com/MomoLangenstein/const-type-layout?rev=8c7d721)", "final", @@ -1501,7 +1501,7 @@ dependencies = [ [[package]] name = "rust-cuda-derive" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=c56d7f8f#c56d7f8fc372e51a8fe65926f7a52a72c73e8dc3" +source = "git+https://github.com/juntyr/rust-cuda?rev=6739fd0b#6739fd0bcbb212ed0c24c0cd5f3bfa8fc66af47d" dependencies = [ "cargo_metadata", "colored", @@ -1520,7 +1520,7 @@ dependencies = [ [[package]] name = "rust-cuda-ptx-jit" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=c56d7f8f#c56d7f8fc372e51a8fe65926f7a52a72c73e8dc3" +source = "git+https://github.com/juntyr/rust-cuda?rev=6739fd0b#6739fd0bcbb212ed0c24c0cd5f3bfa8fc66af47d" dependencies = [ "lazy_static", "regex", diff --git a/necsim/core/Cargo.toml b/necsim/core/Cargo.toml index cce5b5ed7..ca822fb09 100644 --- a/necsim/core/Cargo.toml +++ b/necsim/core/Cargo.toml @@ -20,7 +20,7 @@ contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "c56d7f8f", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6739fd0b", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "c56d7f8f", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6739fd0b", features = ["derive", "host"], optional = true } diff --git a/necsim/impls/cuda/Cargo.toml b/necsim/impls/cuda/Cargo.toml index ba92b6485..293954a88 100644 --- a/necsim/impls/cuda/Cargo.toml +++ b/necsim/impls/cuda/Cargo.toml @@ -15,7 +15,7 @@ contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "c56d7f8f", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6739fd0b", features = ["derive"] } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "c56d7f8f", features = ["derive", "host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6739fd0b", features = ["derive", "host"] } diff --git a/necsim/impls/cuda/src/event_buffer.rs b/necsim/impls/cuda/src/event_buffer.rs index 4c98ec036..4f50719a1 100644 --- a/necsim/impls/cuda/src/event_buffer.rs +++ b/necsim/impls/cuda/src/event_buffer.rs @@ -53,11 +53,39 @@ mod sealed { Assert<{ core::mem::align_of::() == 8 }>: AssertTrue, { } + + pub trait Array { + fn len() -> usize; + fn as_mut_ptr(self: *mut Self) -> *mut T; + } + impl Array for [T; N] { + fn len() -> usize { + N + } + + fn as_mut_ptr(self: *mut Self) -> *mut T { + self.cast() + } + } } pub trait AlignedToU64: sealed::AlignedToU64 {} impl AlignedToU64 for T {} +pub trait Array: sealed::Array { + fn len() -> usize; + fn as_mut_ptr(self: *mut Self) -> *mut T; +} +impl> Array for A { + fn len() -> usize { + >::len() + } + + fn as_mut_ptr(self: *mut Self) -> *mut T { + >::as_mut_ptr(self) + } +} + pub trait EventType { type Event: 'static + ~const rust_cuda::const_type_layout::TypeGraphLayout @@ -68,39 +96,50 @@ pub trait EventType { + Clone + AlignedToU64; - const SHARED_LIMIT: usize; + // const SHARED_LIMIT: usize; + + type SharedBuffer: 'static + Array; } impl EventType for EventBuffer { default type Event = PackedEvent; + // default const SHARED_LIMIT: usize = 0; + + default type SharedBuffer = [T; 0]; +} - default const SHARED_LIMIT: usize = 0; +const fn prev_power_of_two(x: usize) -> usize { + if x.is_power_of_two() { + x + } else { + x.next_power_of_two() / 2 + } } impl EventType for EventBuffer { type Event = PackedEvent; - - const SHARED_LIMIT: usize = ((48*1024 / core::mem::size_of::()) / 32) * 32; + type SharedBuffer = + [T; prev_power_of_two(48 * 1024 / (core::mem::size_of::() + 1))]; } impl EventType for EventBuffer { type Event = PackedEvent; - - const SHARED_LIMIT: usize = ((48*1024 / core::mem::size_of::()) / 32) * 32; + type SharedBuffer = + [T; prev_power_of_two(48 * 1024 / (core::mem::size_of::() + 1))]; } impl EventType for EventBuffer { type Event = SpeciationEvent; - - const SHARED_LIMIT: usize = ((48*1024 / core::mem::size_of::()) / 32) * 32; + type SharedBuffer = + [T; prev_power_of_two(48 * 1024 / (core::mem::size_of::() + 1))]; } impl EventType for EventBuffer { type Event = PackedEvent; - - const SHARED_LIMIT: usize = ((48*1024 / core::mem::size_of::()) / 32) * 32; + type SharedBuffer = + [T; prev_power_of_two(48 * 1024 / (core::mem::size_of::() + 1))]; } impl fmt::Debug @@ -161,18 +200,21 @@ impl where P: Reporter, { - let mut last_time = 0.0_f64; + // let mut last_time = 0.0_f64; + + // let mut times = alloc::vec::Vec::new(); for (mask, event) in self.event_mask.iter_mut().zip(self.event_buffer.iter()) { if *mask.read() { let event: TypedEvent = unsafe { event.read().assume_some_read() }.into(); - let new_time: f64 = match &event { - TypedEvent::Speciation(speciation) => speciation.event_time, - TypedEvent::Dispersal(dispersal) => dispersal.event_time, - } - .get(); - assert!(new_time >= last_time, "{new_time} {last_time}"); - last_time = new_time; + // let new_time: f64 = match &event { + // TypedEvent::Speciation(speciation) => speciation.event_time, + // TypedEvent::Dispersal(dispersal) => dispersal.event_time, + // } + // .get(); + // times.push(Some(new_time)); + // assert!(new_time >= last_time, "{new_time} {last_time}"); + // last_time = new_time; match event { TypedEvent::Speciation(ref speciation) => { @@ -182,10 +224,14 @@ impl reporter.report_dispersal(dispersal.into()); }, } - } + } /*else { + times.push(None); + }*/ mask.write(false); } + + // panic!("{:?}", times); } pub fn max_events_per_individual(&self) -> usize { @@ -225,63 +271,288 @@ impl impl EventBuffer { + /// Bitonic sort combined pre-sort for shared memory, based on + /// + /// + /// # Safety + /// + /// Only one call per kernel launch is safe without further synchronisation. + /// + /// # Panics + /// + /// Traps if the thread block size does not equal + /// `::SharedBuffer::<()>::len() / 2`. + #[allow(clippy::too_many_lines)] + pub unsafe fn bitonic_sort_events_shared_prep(&mut self) { + use core::cmp::Ordering; + + let shared_buffer_len = ::SharedBuffer::<()>::len(); + + let block_dim = rust_cuda::device::utils::block_dim(); + + if shared_buffer_len != (block_dim.size() * 2) { + core::arch::nvptx::trap(); + } + + let block_idx = + rust_cuda::device::utils::block_idx().as_id(&rust_cuda::device::utils::grid_dim()); + let thread_idx = rust_cuda::device::utils::thread_idx().as_id(&block_dim); + + let idx = block_idx * shared_buffer_len + thread_idx; + + let shared_mask: rust_cuda::device::ThreadBlockShared< + ::SharedBuffer, + > = rust_cuda::device::ThreadBlockShared::new_uninit(); + let shared_mask_array: *mut bool = shared_mask.get().as_mut_ptr(); + let shared_buffer: rust_cuda::device::ThreadBlockShared< + ::SharedBuffer::Event>>, + > = rust_cuda::device::ThreadBlockShared::new_uninit(); + let shared_buffer_array: *mut MaybeSome<::Event> = + shared_buffer.get().as_mut_ptr(); + + *shared_mask_array.add(thread_idx) = match self.event_mask.alias_unchecked().get(idx) { + None => false, + Some(mask) => *mask.read(), + }; + if let Some(event) = self.event_buffer.alias_unchecked().get(idx) { + let ptr_src = event.as_uninit().as_ptr(); + let ptr_dst = shared_buffer_array.add(thread_idx); + + core::ptr::copy_nonoverlapping(ptr_src, ptr_dst, 1); + }; + *shared_mask_array.add(thread_idx + (shared_buffer_len / 2)) = match self + .event_mask + .alias_unchecked() + .get(idx + (shared_buffer_len / 2)) + { + None => false, + Some(mask) => *mask.read(), + }; + if let Some(event) = self + .event_buffer + .alias_unchecked() + .get(idx + (shared_buffer_len / 2)) + { + let ptr_src = event.as_uninit().as_ptr(); + let ptr_dst = shared_buffer_array.add(thread_idx + (shared_buffer_len / 2)); + + core::ptr::copy_nonoverlapping(ptr_src, ptr_dst, 1); + }; + + let mut size = 2; + + while size < shared_buffer_len { + let dir = if (thread_idx & (size / 2)) == 0 { + Ordering::Less + } else { + Ordering::Greater + }; + + let mut stride = size >> 1; + + while stride > 0 { + ::core::arch::nvptx::_syncthreads(); + + let pos_a = 2 * thread_idx - (thread_idx & (stride - 1)); + let pos_b = pos_a + stride; + + let mask_a: bool = *shared_mask_array.add(pos_a); + let mask_b: bool = *shared_mask_array.add(pos_b); + + let cmp = match (mask_a, mask_b) { + (false, false) => Ordering::Equal, + (false, true) => Ordering::Greater, + (true, false) => Ordering::Less, + (true, true) => { + // Safety: both masks indicate that the two events exist + let event_a: &::Event = + unsafe { (*shared_buffer_array.add(pos_a)).assume_some_ref() }; + let event_b: &::Event = + unsafe { (*shared_buffer_array.add(pos_b)).assume_some_ref() }; + + event_a.cmp(event_b) + }, + }; + + if cmp == dir { + *shared_mask_array.add(pos_a) = mask_b; + *shared_mask_array.add(pos_b) = mask_a; + + let ptr_a: *mut u64 = shared_buffer_array.add(pos_a).cast(); + let ptr_b: *mut u64 = shared_buffer_array.add(pos_b).cast(); + + // Manual swap implementation that can be unrolled without local memory + // Safety: AlignedToU64 guarantees that both events are aligned to u64 + // and can be copied as multiples of u64 + for i in 0..(core::mem::size_of::<::Event>() / 8) { + let swap = *ptr_a.add(i); + *ptr_a.add(i) = *ptr_b.add(i); + *ptr_b.add(i) = swap; + } + } + + stride >>= 1; + } + + size <<= 1; + } + + let dir = if (block_idx & 1) == 0 { + Ordering::Less + } else { + Ordering::Greater + }; + + let mut stride = shared_buffer_len >> 1; + + while stride > 0 { + ::core::arch::nvptx::_syncthreads(); + + let pos_a = 2 * thread_idx - (thread_idx & (stride - 1)); + let pos_b = pos_a + stride; + + let mask_a: bool = *shared_mask_array.add(pos_a); + let mask_b: bool = *shared_mask_array.add(pos_b); + + let cmp = match (mask_a, mask_b) { + (false, false) => Ordering::Equal, + (false, true) => Ordering::Greater, + (true, false) => Ordering::Less, + (true, true) => { + // Safety: both masks indicate that the two events exist + let event_a: &::Event = + unsafe { (*shared_buffer_array.add(pos_a)).assume_some_ref() }; + let event_b: &::Event = + unsafe { (*shared_buffer_array.add(pos_b)).assume_some_ref() }; + + event_a.cmp(event_b) + }, + }; + + if cmp == dir { + *shared_mask_array.add(pos_a) = mask_b; + *shared_mask_array.add(pos_b) = mask_a; + + let ptr_a: *mut u64 = shared_buffer_array.add(pos_a).cast(); + let ptr_b: *mut u64 = shared_buffer_array.add(pos_b).cast(); + + // Manual swap implementation that can be unrolled without local memory + // Safety: AlignedToU64 guarantees that both events are aligned to u64 + // and can be copied as multiples of u64 + for i in 0..(core::mem::size_of::<::Event>() / 8) { + let swap = *ptr_a.add(i); + *ptr_a.add(i) = *ptr_b.add(i); + *ptr_b.add(i) = swap; + } + } + + stride >>= 1; + } + + ::core::arch::nvptx::_syncthreads(); + + if let Some(mask) = self.event_mask.alias_mut_unchecked().get_mut(idx) { + mask.write(*shared_mask_array.add(thread_idx)); + } + if let Some(event) = self.event_buffer.alias_mut_unchecked().get_mut(idx) { + event.write(core::ptr::read(shared_buffer_array.add(thread_idx))); + } + if let Some(mask) = self + .event_mask + .alias_mut_unchecked() + .get_mut(idx + (shared_buffer_len / 2)) + { + mask.write(*shared_mask_array.add(thread_idx + (shared_buffer_len / 2))); + } + if let Some(event) = self + .event_buffer + .alias_mut_unchecked() + .get_mut(idx + (shared_buffer_len / 2)) + { + event.write(core::ptr::read( + shared_buffer_array.add(thread_idx + (shared_buffer_len / 2)), + )); + } + } + /// Bitonic sort combined merge step for shared memory, based on /// - /// + /// /// # Safety /// /// All CUDA threads must call this method with the same size argument. /// Only one call per kernel launch is safe without further synchronisation. - /// + /// /// # Panics - /// - /// Panics if the thread block size does not equal `::SHARED_LIMIT`. - pub unsafe fn bitonic_sort_events_shared_step(&mut self, size: usize) where [(); ::SHARED_LIMIT]: { + /// + /// Traps if the thread block size does not equal + /// `::SharedBuffer::<()>::len() / 2`. + #[allow(clippy::too_many_lines)] + pub unsafe fn bitonic_sort_events_shared_step(&mut self, size: usize) { use core::cmp::Ordering; + let shared_buffer_len = ::SharedBuffer::<()>::len(); + let block_dim = rust_cuda::device::utils::block_dim(); - rust_cuda::assert_eq!(block_dim.size() * 2, ::SHARED_LIMIT); + if shared_buffer_len != (block_dim.size() * 2) { + core::arch::nvptx::trap(); + } - let block_idx = rust_cuda::device::utils::block_idx().as_id(&rust_cuda::device::utils::grid_dim()); + let block_idx = + rust_cuda::device::utils::block_idx().as_id(&rust_cuda::device::utils::grid_dim()); let thread_idx = rust_cuda::device::utils::thread_idx().as_id(&block_dim); - let idx = block_idx * ::SHARED_LIMIT + thread_idx; + let idx = block_idx * shared_buffer_len + thread_idx; let shared_mask: rust_cuda::device::ThreadBlockShared< - [bool; ::SHARED_LIMIT] + ::SharedBuffer, > = rust_cuda::device::ThreadBlockShared::new_uninit(); let shared_mask_array: *mut bool = shared_mask.get().cast(); let shared_buffer: rust_cuda::device::ThreadBlockShared< - [MaybeSome<::Event>; ::SHARED_LIMIT] + ::SharedBuffer::Event>>, > = rust_cuda::device::ThreadBlockShared::new_uninit(); - let shared_buffer_array: *mut MaybeSome<::Event> = shared_buffer.get().cast(); + let shared_buffer_array: *mut MaybeSome<::Event> = + shared_buffer.get().cast(); *shared_mask_array.add(thread_idx) = match self.event_mask.alias_unchecked().get(idx) { None => false, Some(mask) => *mask.read(), }; - *shared_buffer_array.add(thread_idx) = match self.event_buffer.alias_unchecked().get(idx) { - None => MaybeSome::None, - Some(event) => event.as_uninit().assume_init_read(), + if let Some(event) = self.event_buffer.alias_unchecked().get(idx) { + let ptr_src = event.as_uninit().as_ptr(); + let ptr_dst = shared_buffer_array.add(thread_idx); + + core::ptr::copy_nonoverlapping(ptr_src, ptr_dst, 1); }; - *shared_mask_array.add(thread_idx + (::SHARED_LIMIT / 2)) = match self.event_mask.alias_unchecked().get(idx + (::SHARED_LIMIT / 2)) { + *shared_mask_array.add(thread_idx + (shared_buffer_len / 2)) = match self + .event_mask + .alias_unchecked() + .get(idx + (shared_buffer_len / 2)) + { None => false, Some(mask) => *mask.read(), }; - *shared_buffer_array.add(thread_idx + (::SHARED_LIMIT / 2)) = match self.event_buffer.alias_unchecked().get(idx + (::SHARED_LIMIT / 2)) { - None => MaybeSome::None, - Some(event) => event.as_uninit().assume_init_read(), + if let Some(event) = self + .event_buffer + .alias_unchecked() + .get(idx + (shared_buffer_len / 2)) + { + let ptr_src = event.as_uninit().as_ptr(); + let ptr_dst = shared_buffer_array.add(thread_idx + (shared_buffer_len / 2)); + + core::ptr::copy_nonoverlapping(ptr_src, ptr_dst, 1); }; - let pos = (block_idx * block_dim.size() + thread_idx) & ((self.event_mask.alias_unchecked().len().next_power_of_two() / 2) - 1); + let pos = (block_idx * block_dim.size() + thread_idx) + & ((self.event_mask.alias_unchecked().len().next_power_of_two() / 2) - 1); let dir = if (pos & (size / 2)) == 0 { Ordering::Greater } else { Ordering::Less }; - let mut stride = ::SHARED_LIMIT >> 1; + let mut stride = shared_buffer_len >> 1; while stride > 0 { ::core::arch::nvptx::_syncthreads(); @@ -298,12 +569,10 @@ impl (true, false) => Ordering::Less, (true, true) => { // Safety: both masks indicate that the two events exist - let event_a: &::Event = unsafe { - (*shared_buffer_array.add(pos_a)).assume_some_ref() - }; - let event_b: &::Event = unsafe { - (*shared_buffer_array.add(pos_b)).assume_some_ref() - }; + let event_a: &::Event = + unsafe { (*shared_buffer_array.add(pos_a)).assume_some_ref() }; + let event_b: &::Event = + unsafe { (*shared_buffer_array.add(pos_b)).assume_some_ref() }; event_a.cmp(event_b) }, @@ -337,21 +606,32 @@ impl if let Some(event) = self.event_buffer.alias_mut_unchecked().get_mut(idx) { event.write(core::ptr::read(shared_buffer_array.add(thread_idx))); } - if let Some(mask) = self.event_mask.alias_mut_unchecked().get_mut(idx + (::SHARED_LIMIT / 2)) { - mask.write(*shared_mask_array.add(thread_idx + (::SHARED_LIMIT / 2))); + if let Some(mask) = self + .event_mask + .alias_mut_unchecked() + .get_mut(idx + (shared_buffer_len / 2)) + { + mask.write(*shared_mask_array.add(thread_idx + (shared_buffer_len / 2))); } - if let Some(event) = self.event_buffer.alias_mut_unchecked().get_mut(idx + (::SHARED_LIMIT / 2)) { - event.write(core::ptr::read(shared_buffer_array.add(thread_idx + (::SHARED_LIMIT / 2)))); + if let Some(event) = self + .event_buffer + .alias_mut_unchecked() + .get_mut(idx + (shared_buffer_len / 2)) + { + event.write(core::ptr::read( + shared_buffer_array.add(thread_idx + (shared_buffer_len / 2)), + )); } } /// Bitonic sort single merge step for global memory, based on /// - /// + /// /// # Safety /// - /// All CUDA threads must call this method with the same size and stride arguments. - /// Only one call per kernel launch is safe without further synchronisation. + /// All CUDA threads must call this method with the same size and stride + /// arguments. Only one call per kernel launch is safe without further + /// synchronisation. pub unsafe fn bitonic_sort_events_step(&mut self, size: usize, stride: usize) { use core::cmp::Ordering; @@ -447,11 +727,12 @@ impl #[allow(clippy::too_many_lines)] /// Odd-Even sort single merge step for global memory, based on /// - /// + /// /// # Safety /// - /// All CUDA threads must call this method with the same size and stride arguments. - /// Only one call per kernel launch is safe without further synchronisation. + /// All CUDA threads must call this method with the same size and stride + /// arguments. Only one call per kernel launch is safe without further + /// synchronisation. pub unsafe fn odd_even_sort_events_step(&mut self, size: usize, stride: usize) { use core::cmp::Ordering; diff --git a/necsim/impls/cuda/src/lib.rs b/necsim/impls/cuda/src/lib.rs index 539bea2ea..ac6fe62a9 100644 --- a/necsim/impls/cuda/src/lib.rs +++ b/necsim/impls/cuda/src/lib.rs @@ -6,6 +6,7 @@ #![feature(const_mut_refs)] #![feature(const_refs_to_cell)] #![feature(generic_const_exprs)] +#![feature(arbitrary_self_types)] #![cfg_attr(target_os = "cuda", feature(asm_experimental_arch))] #![cfg_attr(target_os = "cuda", feature(stdsimd))] #![allow(incomplete_features)] diff --git a/necsim/impls/cuda/src/utils.rs b/necsim/impls/cuda/src/utils.rs index 27583e729..123f9288e 100644 --- a/necsim/impls/cuda/src/utils.rs +++ b/necsim/impls/cuda/src/utils.rs @@ -8,6 +8,7 @@ use rust_cuda::safety::StackOnly; pub struct MaybeSome(MaybeUninit); impl MaybeSome { + #[cfg(not(target_os = "cuda"))] #[allow(non_upper_case_globals)] pub(crate) const None: Self = Self(MaybeUninit::uninit()); diff --git a/necsim/impls/no-std/Cargo.toml b/necsim/impls/no-std/Cargo.toml index 53c8de71f..02b026ec6 100644 --- a/necsim/impls/no-std/Cargo.toml +++ b/necsim/impls/no-std/Cargo.toml @@ -31,7 +31,7 @@ rand_core = "0.6" rand_distr = { version = "0.4", default-features = false, features = [] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "c56d7f8f", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6739fd0b", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "c56d7f8f", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6739fd0b", features = ["derive", "host"], optional = true } diff --git a/rustcoalescence/algorithms/cuda/Cargo.toml b/rustcoalescence/algorithms/cuda/Cargo.toml index c68752a16..d5ff316e4 100644 --- a/rustcoalescence/algorithms/cuda/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/Cargo.toml @@ -23,4 +23,4 @@ thiserror = "1.0" serde = { version = "1.0", features = ["derive"] } serde_state = "0.4" serde_derive_state = "0.4" -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "c56d7f8f", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6739fd0b", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml index 502c620e5..798196e14 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml @@ -14,4 +14,4 @@ necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["c necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } rustcoalescence-algorithms-cuda-gpu-kernel = { path = "../gpu-kernel" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "c56d7f8f", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6739fd0b", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs b/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs index 58d49e344..28d080561 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs @@ -4,6 +4,7 @@ #![feature(associated_type_bounds)] #![allow(incomplete_features)] #![feature(specialization)] +#![feature(generic_const_exprs)] use necsim_core::{ cogs::{ @@ -13,6 +14,7 @@ use necsim_core::{ reporter::boolean::Boolean, }; +use necsim_impls_cuda::event_buffer::{Array, EventBuffer, EventType}; use necsim_impls_no_std::cogs::{ active_lineage_sampler::singular::SingularActiveLineageSampler, event_sampler::tracking::MinSpeciationTrackingEventSampler, @@ -22,12 +24,15 @@ use rust_cuda::{ common::RustToCuda, host::{LaunchConfig, LaunchPackage, Launcher, TypedKernel}, rustacuda::{ - error::CudaResult, + error::{CudaError, CudaResult}, function::{BlockSize, Function, GridSize}, }, }; -use rustcoalescence_algorithms_cuda_gpu_kernel::{SimulatableKernel, SortableKernel}; +use rustcoalescence_algorithms_cuda_gpu_kernel::{ + BitonicGlobalSortSteppableKernel, BitonicSharedSortPreparableKernel, + BitonicSharedSortSteppableKernel, EvenOddSortableKernel, SimulatableKernel, +}; mod link; mod patch; @@ -186,9 +191,74 @@ impl< } } -pub struct SortKernel { +pub struct EvenOddSortKernel { + #[allow(clippy::type_complexity)] + kernel: TypedKernel>, + grid: GridSize, + block: BlockSize, + ptx_jit: bool, + watcher: Box, +} + +impl + EvenOddSortKernel +{ + /// # Errors + /// + /// Returns a `CudaError` if loading the CUDA kernel failed. + pub fn try_new( + grid: GridSize, + block: BlockSize, + ptx_jit: bool, + on_compile: Box, + ) -> CudaResult + where + Self: EvenOddSortableKernel, + { + let kernel = Self::new_kernel()?; + + Ok(Self { + kernel, + grid, + block, + ptx_jit, + watcher: on_compile, + }) + } + + pub fn with_grid(&mut self, grid: GridSize) -> &mut Self { + self.grid = grid; + self + } +} + +impl Launcher + for EvenOddSortKernel +{ + type CompilationWatcher = Box; + type KernelTraitObject = dyn EvenOddSortableKernel; + + fn get_launch_package(&mut self) -> LaunchPackage { + LaunchPackage { + config: LaunchConfig { + grid: self.grid.clone(), + block: self.block.clone(), + shared_memory_size: 0_u32, + ptx_jit: self.ptx_jit, + }, + kernel: &mut self.kernel, + watcher: &mut self.watcher, + } + } + + fn on_compile(kernel: &Function, watcher: &mut Self::CompilationWatcher) -> CudaResult<()> { + (watcher)(kernel) + } +} + +pub struct BitonicGlobalSortStepKernel { #[allow(clippy::type_complexity)] - kernel: TypedKernel>, + kernel: TypedKernel>, grid: GridSize, block: BlockSize, ptx_jit: bool, @@ -196,7 +266,7 @@ pub struct SortKernel { } impl - SortKernel + BitonicGlobalSortStepKernel { /// # Errors /// @@ -208,7 +278,7 @@ impl on_compile: Box, ) -> CudaResult where - Self: SortableKernel, + Self: BitonicGlobalSortSteppableKernel, { let kernel = Self::new_kernel()?; @@ -228,10 +298,153 @@ impl } impl Launcher - for SortKernel + for BitonicGlobalSortStepKernel +{ + type CompilationWatcher = Box; + type KernelTraitObject = + dyn BitonicGlobalSortSteppableKernel; + + fn get_launch_package(&mut self) -> LaunchPackage { + LaunchPackage { + config: LaunchConfig { + grid: self.grid.clone(), + block: self.block.clone(), + shared_memory_size: 0_u32, + ptx_jit: self.ptx_jit, + }, + kernel: &mut self.kernel, + watcher: &mut self.watcher, + } + } + + fn on_compile(kernel: &Function, watcher: &mut Self::CompilationWatcher) -> CudaResult<()> { + (watcher)(kernel) + } +} + +pub struct BitonicSharedSortStepKernel { + #[allow(clippy::type_complexity)] + kernel: TypedKernel>, + grid: GridSize, + block: BlockSize, + ptx_jit: bool, + watcher: Box, +} + +impl + BitonicSharedSortStepKernel +{ + /// # Errors + /// + /// Returns a `CudaError` if loading the CUDA kernel failed. + pub fn try_new( + grid: GridSize, + ptx_jit: bool, + on_compile: Box, + ) -> CudaResult + where + Self: BitonicSharedSortSteppableKernel, + { + let kernel = Self::new_kernel()?; + + let block_size = u32::try_from( + as EventType>::SharedBuffer::<()>::len( + ) / 2, + ) + .map_err(|_| CudaError::UnsupportedLimit)?; + + Ok(Self { + kernel, + grid, + block: BlockSize::x(block_size), + ptx_jit, + watcher: on_compile, + }) + } + + pub fn with_grid(&mut self, grid: GridSize) -> &mut Self { + self.grid = grid; + self + } +} + +impl Launcher + for BitonicSharedSortStepKernel +{ + type CompilationWatcher = Box; + type KernelTraitObject = + dyn BitonicSharedSortSteppableKernel; + + fn get_launch_package(&mut self) -> LaunchPackage { + LaunchPackage { + config: LaunchConfig { + grid: self.grid.clone(), + block: self.block.clone(), + shared_memory_size: 0_u32, + ptx_jit: self.ptx_jit, + }, + kernel: &mut self.kernel, + watcher: &mut self.watcher, + } + } + + fn on_compile(kernel: &Function, watcher: &mut Self::CompilationWatcher) -> CudaResult<()> { + (watcher)(kernel) + } +} + +pub struct BitonicSharedSortPrepKernel { + #[allow(clippy::type_complexity)] + kernel: TypedKernel>, + grid: GridSize, + block: BlockSize, + ptx_jit: bool, + watcher: Box, +} + +impl + BitonicSharedSortPrepKernel +{ + /// # Errors + /// + /// Returns a `CudaError` if loading the CUDA kernel failed. + pub fn try_new( + grid: GridSize, + ptx_jit: bool, + on_compile: Box, + ) -> CudaResult + where + Self: BitonicSharedSortPreparableKernel, + { + let kernel = Self::new_kernel()?; + + let block_size = u32::try_from( + as EventType>::SharedBuffer::<()>::len( + ) / 2, + ) + .map_err(|_| CudaError::UnsupportedLimit)?; + + Ok(Self { + kernel, + grid, + block: BlockSize::x(block_size), + ptx_jit, + watcher: on_compile, + }) + } + + pub fn with_grid(&mut self, grid: GridSize) -> &mut Self { + self.grid = grid; + self + } +} + +impl Launcher + for BitonicSharedSortPrepKernel { type CompilationWatcher = Box; - type KernelTraitObject = dyn SortableKernel; + type KernelTraitObject = + dyn BitonicSharedSortPreparableKernel; fn get_launch_package(&mut self) -> LaunchPackage { LaunchPackage { diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs b/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs index 70f50f491..436b74443 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs @@ -1,8 +1,14 @@ use rustcoalescence_algorithms_cuda_gpu_kernel::{ - SimulatableKernel, SimulationKernelArgs, SortKernelArgs, SortableKernel, + BitonicGlobalSortStepKernelArgs, BitonicGlobalSortSteppableKernel, + BitonicSharedSortPrepKernelArgs, BitonicSharedSortPreparableKernel, + BitonicSharedSortStepKernelArgs, BitonicSharedSortSteppableKernel, EvenOddSortKernelArgs, + EvenOddSortableKernel, SimulatableKernel, SimulationKernelArgs, }; -use crate::{SimulationKernel, SortKernel}; +use crate::{ + BitonicGlobalSortStepKernel, BitonicSharedSortPrepKernel, BitonicSharedSortStepKernel, + EvenOddSortKernel, SimulationKernel, +}; macro_rules! link_kernel { ($habitat:ty, $dispersal:ty, $turnover:ty, $speciation:ty) => { @@ -329,19 +335,70 @@ link_kernel!( necsim_impls_no_std::cogs::speciation_probability::uniform::UniformSpeciationProbability ); -rustcoalescence_algorithms_cuda_gpu_kernel::link_sort_kernel!( +rustcoalescence_algorithms_cuda_gpu_kernel::link_even_odd_sort_kernel!( + necsim_core::reporter::boolean::False, + necsim_core::reporter::boolean::False, +); +rustcoalescence_algorithms_cuda_gpu_kernel::link_even_odd_sort_kernel!( + necsim_core::reporter::boolean::False, + necsim_core::reporter::boolean::True, +); +rustcoalescence_algorithms_cuda_gpu_kernel::link_even_odd_sort_kernel!( + necsim_core::reporter::boolean::True, + necsim_core::reporter::boolean::False, +); +rustcoalescence_algorithms_cuda_gpu_kernel::link_even_odd_sort_kernel!( + necsim_core::reporter::boolean::True, + necsim_core::reporter::boolean::True, +); + +rustcoalescence_algorithms_cuda_gpu_kernel::link_bitonic_global_sort_step_kernel!( + necsim_core::reporter::boolean::False, + necsim_core::reporter::boolean::False, +); +rustcoalescence_algorithms_cuda_gpu_kernel::link_bitonic_global_sort_step_kernel!( + necsim_core::reporter::boolean::False, + necsim_core::reporter::boolean::True, +); +rustcoalescence_algorithms_cuda_gpu_kernel::link_bitonic_global_sort_step_kernel!( + necsim_core::reporter::boolean::True, + necsim_core::reporter::boolean::False, +); +rustcoalescence_algorithms_cuda_gpu_kernel::link_bitonic_global_sort_step_kernel!( + necsim_core::reporter::boolean::True, + necsim_core::reporter::boolean::True, +); + +rustcoalescence_algorithms_cuda_gpu_kernel::link_bitonic_shared_sort_prep_kernel!( + necsim_core::reporter::boolean::False, + necsim_core::reporter::boolean::False, +); +rustcoalescence_algorithms_cuda_gpu_kernel::link_bitonic_shared_sort_prep_kernel!( + necsim_core::reporter::boolean::False, + necsim_core::reporter::boolean::True, +); +rustcoalescence_algorithms_cuda_gpu_kernel::link_bitonic_shared_sort_prep_kernel!( + necsim_core::reporter::boolean::True, + necsim_core::reporter::boolean::False, +); +rustcoalescence_algorithms_cuda_gpu_kernel::link_bitonic_shared_sort_prep_kernel!( + necsim_core::reporter::boolean::True, + necsim_core::reporter::boolean::True, +); + +rustcoalescence_algorithms_cuda_gpu_kernel::link_bitonic_shared_sort_step_kernel!( necsim_core::reporter::boolean::False, necsim_core::reporter::boolean::False, ); -rustcoalescence_algorithms_cuda_gpu_kernel::link_sort_kernel!( +rustcoalescence_algorithms_cuda_gpu_kernel::link_bitonic_shared_sort_step_kernel!( necsim_core::reporter::boolean::False, necsim_core::reporter::boolean::True, ); -rustcoalescence_algorithms_cuda_gpu_kernel::link_sort_kernel!( +rustcoalescence_algorithms_cuda_gpu_kernel::link_bitonic_shared_sort_step_kernel!( necsim_core::reporter::boolean::True, necsim_core::reporter::boolean::False, ); -rustcoalescence_algorithms_cuda_gpu_kernel::link_sort_kernel!( +rustcoalescence_algorithms_cuda_gpu_kernel::link_bitonic_shared_sort_step_kernel!( necsim_core::reporter::boolean::True, necsim_core::reporter::boolean::True, ); diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs b/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs index 74889fafd..52a5a0629 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs @@ -23,9 +23,15 @@ use rust_cuda::{ utils::device_copy::SafeDeviceCopyWrapper, }; -use rustcoalescence_algorithms_cuda_gpu_kernel::{SimulatableKernel, SortableKernel}; +use rustcoalescence_algorithms_cuda_gpu_kernel::{ + BitonicGlobalSortSteppableKernel, BitonicSharedSortPreparableKernel, + BitonicSharedSortSteppableKernel, EvenOddSortableKernel, SimulatableKernel, +}; -use crate::{SimulationKernel, SortKernel}; +use crate::{ + BitonicGlobalSortStepKernel, BitonicSharedSortPrepKernel, BitonicSharedSortStepKernel, + EvenOddSortKernel, SimulationKernel, +}; // If `Kernel` is implemented for `ReportSpeciation` x `ReportDispersal`, i.e. // for {`False`, `True`} x {`False`, `True`} then it is implemented for all @@ -144,24 +150,69 @@ where #[allow(clippy::trait_duplication_in_bounds)] unsafe impl - SortableKernel - for SortKernel + EvenOddSortableKernel + for EvenOddSortKernel where - SortKernel: SortableKernel, - SortKernel: SortableKernel, - SortKernel: SortableKernel, - SortKernel: SortableKernel, + EvenOddSortKernel: EvenOddSortableKernel, + EvenOddSortKernel: EvenOddSortableKernel, + EvenOddSortKernel: EvenOddSortableKernel, + EvenOddSortKernel: EvenOddSortableKernel, { default fn get_ptx_str() -> &'static str { unsafe { unreachable_cuda_simulation_linking_reporter() } } default fn new_kernel( - ) -> CudaResult>> { + ) -> CudaResult>> { + unsafe { unreachable_cuda_simulation_linking_reporter() } + } + + default fn even_odd_sort_events_step<'stream>( + &mut self, + _stream: &'stream Stream, + _event_buffer_reporter: &mut EventBuffer, + _size: usize, + _stride: usize, + ) -> CudaResult<()> { + unsafe { unreachable_cuda_simulation_linking_reporter() } + } + + default fn even_odd_sort_events_step_async<'stream>( + &mut self, + _stream: &'stream Stream, + _event_buffer_reporter: HostAndDeviceMutRefAsync< + DeviceAccessible< + as RustToCuda>::CudaRepresentation, + >, + >, + _size: SafeDeviceCopyWrapper, + _stride: SafeDeviceCopyWrapper, + ) -> CudaResult<()> { + unsafe { unreachable_cuda_simulation_linking_reporter() } + } +} + +#[allow(clippy::trait_duplication_in_bounds)] +unsafe impl + BitonicGlobalSortSteppableKernel + for BitonicGlobalSortStepKernel +where + BitonicGlobalSortStepKernel: BitonicGlobalSortSteppableKernel, + BitonicGlobalSortStepKernel: BitonicGlobalSortSteppableKernel, + BitonicGlobalSortStepKernel: BitonicGlobalSortSteppableKernel, + BitonicGlobalSortStepKernel: BitonicGlobalSortSteppableKernel, +{ + default fn get_ptx_str() -> &'static str { unsafe { unreachable_cuda_simulation_linking_reporter() } } - default fn sort_events_step<'stream>( + default fn new_kernel() -> CudaResult< + TypedKernel>, + > { + unsafe { unreachable_cuda_simulation_linking_reporter() } + } + + default fn bitonic_global_sort_events_step<'stream>( &mut self, _stream: &'stream Stream, _event_buffer_reporter: &mut EventBuffer, @@ -171,7 +222,7 @@ where unsafe { unreachable_cuda_simulation_linking_reporter() } } - default fn sort_events_step_async<'stream>( + default fn bitonic_global_sort_events_step_async<'stream>( &mut self, _stream: &'stream Stream, _event_buffer_reporter: HostAndDeviceMutRefAsync< @@ -185,3 +236,87 @@ where unsafe { unreachable_cuda_simulation_linking_reporter() } } } + +#[allow(clippy::trait_duplication_in_bounds)] +unsafe impl + BitonicSharedSortSteppableKernel + for BitonicSharedSortStepKernel +where + BitonicSharedSortStepKernel: BitonicSharedSortSteppableKernel, + BitonicSharedSortStepKernel: BitonicSharedSortSteppableKernel, + BitonicSharedSortStepKernel: BitonicSharedSortSteppableKernel, + BitonicSharedSortStepKernel: BitonicSharedSortSteppableKernel, +{ + default fn get_ptx_str() -> &'static str { + unsafe { unreachable_cuda_simulation_linking_reporter() } + } + + default fn new_kernel() -> CudaResult< + TypedKernel>, + > { + unsafe { unreachable_cuda_simulation_linking_reporter() } + } + + default fn bitonic_shared_sort_events_step<'stream>( + &mut self, + _stream: &'stream Stream, + _event_buffer_reporter: &mut EventBuffer, + _size: usize, + ) -> CudaResult<()> { + unsafe { unreachable_cuda_simulation_linking_reporter() } + } + + default fn bitonic_shared_sort_events_step_async<'stream>( + &mut self, + _stream: &'stream Stream, + _event_buffer_reporter: HostAndDeviceMutRefAsync< + DeviceAccessible< + as RustToCuda>::CudaRepresentation, + >, + >, + _size: SafeDeviceCopyWrapper, + ) -> CudaResult<()> { + unsafe { unreachable_cuda_simulation_linking_reporter() } + } +} + +#[allow(clippy::trait_duplication_in_bounds)] +unsafe impl + BitonicSharedSortPreparableKernel + for BitonicSharedSortPrepKernel +where + BitonicSharedSortPrepKernel: BitonicSharedSortPreparableKernel, + BitonicSharedSortPrepKernel: BitonicSharedSortPreparableKernel, + BitonicSharedSortPrepKernel: BitonicSharedSortPreparableKernel, + BitonicSharedSortPrepKernel: BitonicSharedSortPreparableKernel, +{ + default fn get_ptx_str() -> &'static str { + unsafe { unreachable_cuda_simulation_linking_reporter() } + } + + default fn new_kernel() -> CudaResult< + TypedKernel>, + > { + unsafe { unreachable_cuda_simulation_linking_reporter() } + } + + default fn bitonic_shared_sort_events_prep<'stream>( + &mut self, + _stream: &'stream Stream, + _event_buffer_reporter: &mut EventBuffer, + ) -> CudaResult<()> { + unsafe { unreachable_cuda_simulation_linking_reporter() } + } + + default fn bitonic_shared_sort_events_prep_async<'stream>( + &mut self, + _stream: &'stream Stream, + _event_buffer_reporter: HostAndDeviceMutRefAsync< + DeviceAccessible< + as RustToCuda>::CudaRepresentation, + >, + >, + ) -> CudaResult<()> { + unsafe { unreachable_cuda_simulation_linking_reporter() } + } +} diff --git a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml index d36405c2c..a109a58b5 100644 --- a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml @@ -16,4 +16,4 @@ necsim-core-bond = { path = "../../../../necsim/core/bond" } necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["cuda"] } necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "c56d7f8f", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6739fd0b", features = ["derive"] } diff --git a/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs b/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs index 738e561b1..6ae7e7bb3 100644 --- a/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs +++ b/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs @@ -10,6 +10,8 @@ #![cfg_attr(target_os = "cuda", feature(asm_experimental_arch))] #![cfg_attr(target_os = "cuda", feature(stdsimd))] #![cfg_attr(target_os = "cuda", feature(control_flow_enum))] +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] extern crate alloc; @@ -132,10 +134,27 @@ pub fn simulate< }); } +// #[rust_cuda::common::kernel( +// pub use link_sort_kernel! as impl SortableKernel for +// SortKernel )] +// pub fn sort_events_step( +// #[kernel(pass = LendRustToCuda, jit)] event_buffer_reporter: &mut +// ShallowCopy< +// necsim_impls_cuda::event_buffer::EventBuffer, >, +// #[kernel(pass = SafeDeviceCopy)] size: usize, +// #[kernel(pass = SafeDeviceCopy)] stride: usize, +// ) { +// // Safety: size and stride are the same on every CUDA thread +// unsafe { +// event_buffer_reporter.odd_even_sort_events_step(size, stride); +// } +// } + #[rust_cuda::common::kernel( - pub use link_sort_kernel! as impl SortableKernel for SortKernel + pub use link_even_odd_sort_kernel! as impl EvenOddSortableKernel for EvenOddSortKernel )] -pub fn sort_events_step( +pub fn even_odd_sort_events_step( #[kernel(pass = LendRustToCuda, jit)] event_buffer_reporter: &mut ShallowCopy< necsim_impls_cuda::event_buffer::EventBuffer, >, @@ -148,37 +167,49 @@ pub fn sort_events_step( } } -// #[rust_cuda::common::kernel( -// pub use link_even_odd_sort_kernel! as impl EvenOddSortableKernel for EvenOddSortKernel -// )] -// pub fn even_odd_sort_events_step( -// #[kernel(pass = LendRustToCuda, jit)] event_buffer_reporter: &mut ShallowCopy< -// necsim_impls_cuda::event_buffer::EventBuffer, -// >, -// #[kernel(pass = SafeDeviceCopy)] size: usize, -// #[kernel(pass = SafeDeviceCopy)] stride: usize, -// ) { -// // Safety: size and stride are the same on every CUDA thread -// unsafe { -// event_buffer_reporter.odd_even_sort_events_step(size, stride); -// } -// } +#[rust_cuda::common::kernel( + pub use link_bitonic_global_sort_step_kernel! as impl BitonicGlobalSortSteppableKernel for BitonicGlobalSortStepKernel +)] +pub fn bitonic_global_sort_events_step( + #[kernel(pass = LendRustToCuda, jit)] event_buffer_reporter: &mut ShallowCopy< + necsim_impls_cuda::event_buffer::EventBuffer, + >, + #[kernel(pass = SafeDeviceCopy)] size: usize, + #[kernel(pass = SafeDeviceCopy)] stride: usize, +) { + // Safety: size and stride are the same on every CUDA thread + unsafe { + event_buffer_reporter.bitonic_sort_events_step(size, stride); + } +} -// #[rust_cuda::common::kernel( -// pub use link_bitonic_sort_kernel! as impl BitonicSortableKernel for BitonicSortKernel -// )] -// pub fn bitonic_sort_events_step( -// #[kernel(pass = LendRustToCuda, jit)] event_buffer_reporter: &mut ShallowCopy< -// necsim_impls_cuda::event_buffer::EventBuffer, -// >, -// #[kernel(pass = SafeDeviceCopy)] size: usize, -// #[kernel(pass = SafeDeviceCopy)] stride: usize, -// ) { -// // Safety: size and stride are the same on every CUDA thread -// unsafe { -// event_buffer_reporter.bitonic_sort_events_step(size, stride); -// } -// } +#[rust_cuda::common::kernel( + pub use link_bitonic_shared_sort_step_kernel! as impl BitonicSharedSortSteppableKernel for BitonicSharedSortStepKernel +)] +pub fn bitonic_shared_sort_events_step( + #[kernel(pass = LendRustToCuda, jit)] event_buffer_reporter: &mut ShallowCopy< + necsim_impls_cuda::event_buffer::EventBuffer, + >, + #[kernel(pass = SafeDeviceCopy)] size: usize, +) { + // Safety: size is the same on every CUDA thread + unsafe { + event_buffer_reporter.bitonic_sort_events_shared_step(size); + } +} + +#[rust_cuda::common::kernel( + pub use link_bitonic_shared_sort_prep_kernel! as impl BitonicSharedSortPreparableKernel for BitonicSharedSortPrepKernel +)] +pub fn bitonic_shared_sort_events_prep( + #[kernel(pass = LendRustToCuda, jit)] event_buffer_reporter: &mut ShallowCopy< + necsim_impls_cuda::event_buffer::EventBuffer, + >, +) { + unsafe { + event_buffer_reporter.bitonic_sort_events_shared_prep(); + } +} #[cfg(target_os = "cuda")] mod cuda_prelude { diff --git a/rustcoalescence/algorithms/cuda/src/arguments.rs b/rustcoalescence/algorithms/cuda/src/arguments.rs index 1f7331b04..0aad7af77 100644 --- a/rustcoalescence/algorithms/cuda/src/arguments.rs +++ b/rustcoalescence/algorithms/cuda/src/arguments.rs @@ -53,6 +53,14 @@ impl<'de> DeserializeState<'de, Partition> for ParallelismMode { } } +#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub enum SortMode { + None, + CpuOnly, + EvenOddGpu, + BitonicGpu, +} + #[derive(Debug, Serialize)] #[allow(clippy::module_name_repetitions)] pub struct CudaArguments { @@ -62,6 +70,7 @@ pub struct CudaArguments { pub block_size: NonZeroU32, pub grid_size: NonZeroU32, pub sort_block_size: NonZeroU32, + pub sort_mode: SortMode, pub step_slice: NonZeroU64, pub dedup_cache: DedupCache, pub parallelism_mode: ParallelismMode, @@ -95,6 +104,7 @@ impl<'de> DeserializeState<'de, Partition> for CudaArguments { block_size: raw.block_size, grid_size: raw.grid_size, sort_block_size: raw.sort_block_size, + sort_mode: raw.sort_mode, step_slice: raw.step_slice, dedup_cache: raw.dedup_cache, parallelism_mode, @@ -112,6 +122,7 @@ pub struct CudaArgumentsRaw { pub block_size: NonZeroU32, pub grid_size: NonZeroU32, pub sort_block_size: NonZeroU32, + pub sort_mode: SortMode, pub step_slice: NonZeroU64, pub dedup_cache: DedupCache, #[serde(deserialize_state)] @@ -127,6 +138,7 @@ impl Default for CudaArgumentsRaw { block_size: NonZeroU32::new(64_u32).unwrap(), grid_size: NonZeroU32::new(64_u32).unwrap(), sort_block_size: NonZeroU32::new(512_u32).unwrap(), + sort_mode: SortMode::None, step_slice: NonZeroU64::new(150_u64).unwrap(), dedup_cache: DedupCache::Relative(RelativeCapacity { factor: PositiveF64::new(0.1_f64).unwrap(), diff --git a/rustcoalescence/algorithms/cuda/src/launch.rs b/rustcoalescence/algorithms/cuda/src/launch.rs index 6bc459d10..d2e75cf6f 100644 --- a/rustcoalescence/algorithms/cuda/src/launch.rs +++ b/rustcoalescence/algorithms/cuda/src/launch.rs @@ -25,7 +25,10 @@ use necsim_partitioning_core::LocalPartition; use rustcoalescence_algorithms::result::SimulationOutcome; use rustcoalescence_scenarios::Scenario; -use rustcoalescence_algorithms_cuda_cpu_kernel::{SimulationKernel, SortKernel}; +use rustcoalescence_algorithms_cuda_cpu_kernel::{ + BitonicGlobalSortStepKernel, BitonicSharedSortPrepKernel, BitonicSharedSortStepKernel, + EvenOddSortKernel, SimulationKernel, +}; use rustcoalescence_algorithms_cuda_gpu_kernel::SimulatableKernel; use rust_cuda::{ @@ -215,12 +218,52 @@ where }), )?; - let sort_kernel = SortKernel::try_new( + let even_odd_sort_kernel = EvenOddSortKernel::try_new( GridSize::x(0), BlockSize::x(args.sort_block_size.get()), args.ptx_jit, Box::new(|kernel| { - crate::info::print_kernel_function_attributes("Sorting", kernel); + crate::info::print_kernel_function_attributes( + "Even Odd Sorting Global Step", + kernel, + ); + Ok(()) + }), + )?; + + let bitonic_sort_shared_prep_kernel = BitonicSharedSortPrepKernel::try_new( + GridSize::x(0), + args.ptx_jit, + Box::new(|kernel| { + crate::info::print_kernel_function_attributes( + "Bitonic Sorting Shared Prep", + kernel, + ); + Ok(()) + }), + )?; + + let bitonic_sort_shared_step_kernel = BitonicSharedSortStepKernel::try_new( + GridSize::x(0), + args.ptx_jit, + Box::new(|kernel| { + crate::info::print_kernel_function_attributes( + "Bitonic Sorting Shared Step", + kernel, + ); + Ok(()) + }), + )?; + + let bitonic_sort_global_step_kernel = BitonicGlobalSortStepKernel::try_new( + GridSize::x(0), + BlockSize::x(args.sort_block_size.get()), + args.ptx_jit, + Box::new(|kernel| { + crate::info::print_kernel_function_attributes( + "Bitonic Sorting Global Step", + kernel, + ); Ok(()) }), )?; @@ -228,13 +271,19 @@ where parallelisation::monolithic::simulate( &mut simulation, kernel, - sort_kernel, + ( + even_odd_sort_kernel, + bitonic_sort_shared_prep_kernel, + bitonic_sort_shared_step_kernel, + bitonic_sort_global_step_kernel, + ), ( grid_size, block_size, args.dedup_cache, args.step_slice, args.sort_block_size.get() as usize, + args.sort_mode, ), &stream, lineages, diff --git a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs index 36e29a0c4..117c1d6a5 100644 --- a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs +++ b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs @@ -43,12 +43,21 @@ use necsim_impls_no_std::{ }; use necsim_partitioning_core::LocalPartition; -use necsim_impls_cuda::{event_buffer::EventBuffer, value_buffer::ValueBuffer}; +use necsim_impls_cuda::{ + event_buffer::{Array, EventBuffer, EventType}, + value_buffer::ValueBuffer, +}; -use rustcoalescence_algorithms_cuda_cpu_kernel::{SimulationKernel, SortKernel}; -use rustcoalescence_algorithms_cuda_gpu_kernel::{SimulatableKernel, SortableKernel}; +use rustcoalescence_algorithms_cuda_cpu_kernel::{ + BitonicGlobalSortStepKernel, BitonicSharedSortPrepKernel, BitonicSharedSortStepKernel, + EvenOddSortKernel, SimulationKernel, +}; +use rustcoalescence_algorithms_cuda_gpu_kernel::{ + BitonicGlobalSortSteppableKernel, BitonicSharedSortPreparableKernel, + BitonicSharedSortSteppableKernel, EvenOddSortableKernel, SimulatableKernel, +}; -use crate::error::CudaError; +use crate::{arguments::SortMode, error::CudaError}; type Result = std::result::Result; @@ -95,11 +104,25 @@ pub fn simulate< <>::WaterLevelReporter as Reporter>::ReportSpeciation, <>::WaterLevelReporter as Reporter>::ReportDispersal, >, - mut sort_kernel: SortKernel< - <>::WaterLevelReporter as Reporter>::ReportSpeciation, - <>::WaterLevelReporter as Reporter>::ReportDispersal, - >, - config: (GridSize, BlockSize, DedupCache, NonZeroU64, usize), + (mut even_odd_sort_kernel, mut bitonic_shared_sort_prep_kernel, mut bitonic_shared_sort_step_kernel, mut bitonic_global_sort_step_kernel): ( + EvenOddSortKernel< + <>::WaterLevelReporter as Reporter>::ReportSpeciation, + <>::WaterLevelReporter as Reporter>::ReportDispersal, + >, + BitonicSharedSortPrepKernel< + <>::WaterLevelReporter as Reporter>::ReportSpeciation, + <>::WaterLevelReporter as Reporter>::ReportDispersal, + >, + BitonicSharedSortStepKernel< + <>::WaterLevelReporter as Reporter>::ReportSpeciation, + <>::WaterLevelReporter as Reporter>::ReportDispersal, + >, + BitonicGlobalSortStepKernel< + <>::WaterLevelReporter as Reporter>::ReportSpeciation, + <>::WaterLevelReporter as Reporter>::ReportDispersal, + >, + ), + config: (GridSize, BlockSize, DedupCache, NonZeroU64, usize, SortMode), stream: &'stream Stream, lineages: LI, event_slice: EventSlice, @@ -161,7 +184,7 @@ pub fn simulate< L, >>::WaterLevelReporter::new(event_slice.get(), local_partition); - let (grid_size, block_size, dedup_cache, step_slice, sort_block_size) = config; + let (grid_size, block_size, dedup_cache, step_slice, sort_block_size, sort_mode) = config; #[allow(clippy::or_fun_call)] let intial_max_time = slow_lineages @@ -314,40 +337,128 @@ pub fn simulate< next_event_time_buffer_cuda.move_to_host_async(stream)?; let task_list_host = task_list_cuda.move_to_host_async(stream)?; - if max_events_per_individual > 0 { - // Each individual generates its events in sorted order - // If the number of events per individual is aligned to some - // power of two, these first sorting steps can be skipped - let mut size = 2.max(0x1 << max_events_per_individual.trailing_zeros()); - - loop { - let mut stride = size >> 1; - - while stride > 0 { - let grid = u32::try_from( - (num_tasks * max_events_per_individual + sort_block_size - - 1) - / sort_block_size, - ) - .map_err(|_| { - rust_cuda::rustacuda::error::CudaError::LaunchOutOfResources - })?; - - sort_kernel.with_grid(grid.into()).sort_events_step_async( + let sort_grid = u32::try_from( + (num_tasks * max_events_per_individual + sort_block_size - 1) + / sort_block_size, + ) + .map_err(|_| { + rust_cuda::rustacuda::error::CudaError::LaunchOutOfResources + })?; + + if max_events_per_individual > 0 && match sort_mode { + SortMode::None | SortMode::CpuOnly => false, + SortMode::EvenOddGpu => true, + SortMode::BitonicGpu => (num_tasks * max_events_per_individual) + >= >::WaterLevelReporter as Reporter>::ReportSpeciation, + <>::WaterLevelReporter as Reporter>::ReportDispersal, + > as EventType>::SharedBuffer::<()>::len( + ), + } + /* && sort_grid > 1 */ + { + if let SortMode::EvenOddGpu = sort_mode { + // Each individual generates its events in sorted order + // If the number of events per individual is aligned to some + // power of two, these first sorting steps can be skipped + let mut size = + 2.max(0x1 << max_events_per_individual.trailing_zeros()); + + loop { + let mut stride = size >> 1; + + while stride > 0 { + even_odd_sort_kernel + .with_grid(sort_grid.into()) + .even_odd_sort_events_step_async( + stream, + event_buffer_cuda.as_mut_async(), + size.into(), + stride.into(), + )?; + + stride >>= 1; + } + + if size >= (num_tasks * max_events_per_individual) { + break; + } + + size <<= 1; + } + } else { + let shared_buffer_len = >::WaterLevelReporter as Reporter>::ReportSpeciation, + <>::WaterLevelReporter as Reporter>::ReportDispersal, + > as EventType>::SharedBuffer::<()>::len( + ); + + let pre_sort_grid = u32::try_from( + (num_tasks * max_events_per_individual + shared_buffer_len - 1) + / shared_buffer_len, + ) + .map_err(|_| { + rust_cuda::rustacuda::error::CudaError::LaunchOutOfResources + })?; + + bitonic_shared_sort_prep_kernel + .with_grid(pre_sort_grid.into()) + .bitonic_shared_sort_events_prep_async( stream, event_buffer_cuda.as_mut_async(), - size.into(), - stride.into(), )?; - stride >>= 1; - } + let mut size = 2 * shared_buffer_len; + + loop { + let mut stride = size >> 1; + + while stride > 0 { + if stride > shared_buffer_len { + bitonic_global_sort_step_kernel + .with_grid(sort_grid.into()) + .bitonic_global_sort_events_step_async( + stream, + event_buffer_cuda.as_mut_async(), + size.into(), + stride.into(), + )?; + } else { + bitonic_shared_sort_step_kernel + .with_grid(sort_grid.into()) + .bitonic_shared_sort_events_step_async( + stream, + event_buffer_cuda.as_mut_async(), + size.into(), + )?; + break; + } + + stride >>= 1; + } - if size >= (num_tasks * max_events_per_individual) { - break; - } + if size >= (num_tasks * max_events_per_individual) { + break; + } - size <<= 1; + size <<= 1; + } } } @@ -390,6 +501,29 @@ pub fn simulate< next_event_time_buffer.move_to_device_async(stream)?; event_buffer = event_buffer_host.sync_to_host()?; + + if match sort_mode { + SortMode::None | SortMode::EvenOddGpu => false, + SortMode::CpuOnly => true, + // SortMode::EvenOddGpu => sort_grid <= 1, + SortMode::BitonicGpu => (num_tasks * max_events_per_individual) + < >::WaterLevelReporter as Reporter>::ReportSpeciation, + <>::WaterLevelReporter as Reporter>::ReportDispersal, + > as EventType>::SharedBuffer::<()>::len( + ), // || sort_grid <= 1, + } { + event_buffer.sort_events(); + } + event_buffer.report_events_unordered(&mut proxy); event_buffer_cuda = event_buffer.move_to_device_async(stream)?; From 4365b41468913a4da55de1de5fe6db4397b4e041 Mon Sep 17 00:00:00 2001 From: Juniper Tyree Date: Sat, 10 Dec 2022 15:15:50 -0800 Subject: [PATCH 33/42] Experiment with incremental timsort inspired by std::slice::sort --- necsim/impls/no-std/src/lib.rs | 2 + .../independent/monolithic/mod.rs | 2 +- .../independent/monolithic/reporter/live.rs | 288 +++++++++++++++++- .../independent/monolithic/reporter/mod.rs | 6 +- .../monolithic/reporter/recorded.rs | 8 +- .../algorithms/cuda/src/arguments.rs | 6 +- rustcoalescence/algorithms/cuda/src/launch.rs | 1 + .../cuda/src/parallelisation/monolithic.rs | 23 +- 8 files changed, 311 insertions(+), 25 deletions(-) diff --git a/necsim/impls/no-std/src/lib.rs b/necsim/impls/no-std/src/lib.rs index f74a06f61..356521cf3 100644 --- a/necsim/impls/no-std/src/lib.rs +++ b/necsim/impls/no-std/src/lib.rs @@ -13,6 +13,8 @@ #![feature(associated_type_bounds)] #![feature(const_float_bits_conv)] #![feature(core_intrinsics)] +#![feature(ptr_sub_ptr)] +#![feature(is_sorted)] #![allow(incomplete_features)] #![feature(specialization)] diff --git a/necsim/impls/no-std/src/parallelisation/independent/monolithic/mod.rs b/necsim/impls/no-std/src/parallelisation/independent/monolithic/mod.rs index db9f7b2c9..e0439ebe4 100644 --- a/necsim/impls/no-std/src/parallelisation/independent/monolithic/mod.rs +++ b/necsim/impls/no-std/src/parallelisation/independent/monolithic/mod.rs @@ -115,7 +115,7 @@ pub fn simulate< P::IsLive, R, P, - >>::WaterLevelReporter::new(event_slice.get(), local_partition); + >>::WaterLevelReporter::new(event_slice.get(), local_partition, 100_000); // TODO: configure here as well let mut min_spec_samples = dedup_cache.construct(slow_lineages.len()); let mut total_steps = 0_u64; diff --git a/necsim/impls/no-std/src/parallelisation/independent/monolithic/reporter/live.rs b/necsim/impls/no-std/src/parallelisation/independent/monolithic/reporter/live.rs index a1f009efa..13083b4cd 100644 --- a/necsim/impls/no-std/src/parallelisation/independent/monolithic/reporter/live.rs +++ b/necsim/impls/no-std/src/parallelisation/independent/monolithic/reporter/live.rs @@ -1,5 +1,5 @@ -use alloc::vec::Vec; -use core::{fmt, marker::PhantomData}; +use alloc::{vec::Vec, collections::VecDeque}; +use core::{fmt, marker::PhantomData, ops::ControlFlow}; use necsim_core_bond::NonNegativeF64; use necsim_core::{ @@ -12,10 +12,21 @@ use necsim_partitioning_core::LocalPartition; use super::WaterLevelReporterProxy; +#[derive(Clone, Copy)] +struct Run { + start: usize, + len: usize, +} + #[allow(clippy::module_name_repetitions)] pub struct LiveWaterLevelReporterProxy<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> { water_level: NonNegativeF64, slow_events: Vec, + tmp_events: Vec, + run: Run, + runs: Vec, + overflow: VecDeque, + sort_batch_size: usize, fast_events: Vec, local_partition: &'l mut P, @@ -36,6 +47,8 @@ impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> fmt::Debug fmt.debug_struct(stringify!(LiveWaterLevelReporterProxy)) .field("water_level", &self.water_level) + .field("runs", &self.runs.len()) + .field("overflow", &self.overflow.len()) .field("slow_events", &EventBufferLen(self.slow_events.len())) .field("fast_events", &EventBufferLen(self.fast_events.len())) .finish() @@ -46,35 +59,248 @@ impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> Reporter for LiveWaterLevelReporterProxy<'l, 'p, R, P> { impl_report!(speciation(&mut self, speciation: MaybeUsed) { - if speciation.event_time < self.water_level { - self.slow_events.push(speciation.clone().into()); + let speciation: PackedEvent = speciation.clone().into(); + + if speciation.event_time() < self.water_level { + let new_run = self.run.len > self.sort_batch_size; // self.slow_events.last().map_or(true, |prev| prev > &speciation); + + if new_run { + let old_run = core::mem::replace(&mut self.run, Run { + start: self.slow_events.len(), + len: 1, + }); + self.overflow.push_back(old_run); + } else { + self.run.len += 1; + } + + self.slow_events.push(speciation); } else { - self.fast_events.push(speciation.clone().into()); + self.fast_events.push(speciation); } }); impl_report!(dispersal(&mut self, dispersal: MaybeUsed) { - if dispersal.event_time < self.water_level { - self.slow_events.push(dispersal.clone().into()); + let dispersal: PackedEvent = dispersal.clone().into(); + + if dispersal.event_time() < self.water_level { + let new_run = self.run.len > self.sort_batch_size; // self.slow_events.last().map_or(true, |prev| prev > &dispersal); + + if new_run { + let old_run = core::mem::replace(&mut self.run, Run { + start: self.slow_events.len(), + len: 1, + }); + self.overflow.push_back(old_run); + } else { + self.run.len += 1; + } + + self.slow_events.push(dispersal); } else { - self.fast_events.push(dispersal.clone().into()); + self.fast_events.push(dispersal); } }); impl_report!(progress(&mut self, _progress: Ignored) {}); } +impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> LiveWaterLevelReporterProxy<'l, 'p, R, P> { + #[inline] + fn collapse(&self, force_merge: bool) -> Option { + let n = self.runs.len(); + if n >= 2 + && (force_merge + || self.runs[n - 2].len <= self.runs[n - 1].len + || (n >= 3 && self.runs[n - 3].len <= self.runs[n - 2].len + self.runs[n - 1].len) + || (n >= 4 && self.runs[n - 4].len <= self.runs[n - 3].len + self.runs[n - 2].len)) + { + if n >= 3 && self.runs[n - 3].len < self.runs[n - 1].len { Some(n - 3) } else { Some(n - 2) } + } else { + None + } + } + + unsafe fn merge(v: &mut [T], mid: usize, buf: *mut T, is_less: &mut F) + where + F: FnMut(&T, &T) -> bool, + { + unsafe fn get_and_increment(ptr: &mut *mut T) -> *mut T { + let old = *ptr; + *ptr = unsafe { ptr.add(1) }; + old + } + + unsafe fn decrement_and_get(ptr: &mut *mut T) -> *mut T { + *ptr = unsafe { ptr.sub(1) }; + *ptr + } + + // When dropped, copies the range `start..end` into `dest..`. + struct MergeHole { + start: *mut T, + end: *mut T, + dest: *mut T, + } + + impl Drop for MergeHole { + fn drop(&mut self) { + // `T` is not a zero-sized type, and these are pointers into a slice's elements. + unsafe { + let len = self.end.sub_ptr(self.start); + core::ptr::copy_nonoverlapping(self.start, self.dest, len); + } + } + } + + let len = v.len(); + let v = v.as_mut_ptr(); + let (v_mid, v_end) = unsafe { (v.add(mid), v.add(len)) }; + + // The merge process first copies the shorter run into `buf`. Then it traces the newly copied + // run and the longer run forwards (or backwards), comparing their next unconsumed elements and + // copying the lesser (or greater) one into `v`. + // + // As soon as the shorter run is fully consumed, the process is done. If the longer run gets + // consumed first, then we must copy whatever is left of the shorter run into the remaining + // hole in `v`. + // + // Intermediate state of the process is always tracked by `hole`, which serves two purposes: + // 1. Protects integrity of `v` from panics in `is_less`. + // 2. Fills the remaining hole in `v` if the longer run gets consumed first. + // + // Panic safety: + // + // If `is_less` panics at any point during the process, `hole` will get dropped and fill the + // hole in `v` with the unconsumed range in `buf`, thus ensuring that `v` still holds every + // object it initially held exactly once. + let mut hole; + + if mid <= len - mid { + // The left run is shorter. + unsafe { + core::ptr::copy_nonoverlapping(v, buf, mid); + hole = MergeHole { start: buf, end: buf.add(mid), dest: v }; + } + + // Initially, these pointers point to the beginnings of their arrays. + let left = &mut hole.start; + let mut right = v_mid; + let out = &mut hole.dest; + + while *left < hole.end && right < v_end { + // Consume the lesser side. + // If equal, prefer the left run to maintain stability. + unsafe { + let to_copy = if is_less(&*right, &**left) { + get_and_increment(&mut right) + } else { + get_and_increment(left) + }; + core::ptr::copy_nonoverlapping(to_copy, get_and_increment(out), 1); + } + } + } else { + // The right run is shorter. + unsafe { + core::ptr::copy_nonoverlapping(v_mid, buf, len - mid); + hole = MergeHole { start: buf, end: buf.add(len - mid), dest: v_mid }; + } + + // Initially, these pointers point past the ends of their arrays. + let left = &mut hole.dest; + let right = &mut hole.end; + let mut out = v_end; + + while v < *left && buf < *right { + // Consume the greater side. + // If equal, prefer the right run to maintain stability. + unsafe { + let to_copy = if is_less(&*right.sub(1), &*left.sub(1)) { + decrement_and_get(left) + } else { + decrement_and_get(right) + }; + core::ptr::copy_nonoverlapping(to_copy, decrement_and_get(&mut out), 1); + } + } + } + // Finally, `hole` gets dropped. If the shorter run was not fully consumed, whatever remains of + // it will now be copied into the hole in `v`. + } + + fn sort_slow_events_step(&mut self, force_merge: bool) -> ControlFlow<()> { + let r = loop { + if let Some(r) = self.collapse(force_merge && self.overflow.is_empty()) { + break r; + } + + let next_run = match self.overflow.pop_front() { + Some(next_run) => next_run, + None if self.run.len > 0 => core::mem::replace(&mut self.run, Run { start: self.slow_events.len(), len: 0 }), + None => return ControlFlow::Break(()), + }; + + // let Some(mut next_run) = self.overflow.pop_front() else { + // return ControlFlow::Break(()); + // }; + + // if next_run.len < self.sort_batch_size { + // while next_run.len < self.sort_batch_size { + // let Some(extra_run) = self.overflow.pop_front() else { + // break; + // }; + // next_run.len += extra_run.len; + // } + // self.slow_events[next_run.start..next_run.start+next_run.len].sort_unstable(); + // } + + self.slow_events[next_run.start..next_run.start+next_run.len].sort_unstable(); + + self.runs.push(next_run); + }; + + let left = self.runs[r]; + let right = self.runs[r + 1]; + + let min_len = left.len.min(right.len); + + if min_len > self.tmp_events.capacity() { + self.tmp_events.reserve(min_len - self.tmp_events.capacity()); + } + + unsafe { + Self::merge( + &mut self.slow_events[left.start..right.start + right.len], + left.len, + self.tmp_events.as_mut_ptr(), + &mut core::cmp::PartialOrd::lt, + ); + } + + self.runs[r] = Run { start: left.start, len: left.len + right.len }; + self.runs.remove(r + 1); + + ControlFlow::Continue(()) + } +} + #[contract_trait] impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> WaterLevelReporterProxy<'l, 'p, R, P> for LiveWaterLevelReporterProxy<'l, 'p, R, P> { - fn new(capacity: usize, local_partition: &'l mut P) -> Self { + fn new(capacity: usize, local_partition: &'l mut P, sort_batch_size: usize) -> Self { info!("Events will be reported using the live water-level algorithm ..."); Self { water_level: NonNegativeF64::zero(), slow_events: Vec::with_capacity(capacity), + tmp_events: Vec::with_capacity(capacity), + run: Run { start: 0, len: 0 }, + runs: Vec::new(), + overflow: VecDeque::new(), fast_events: Vec::with_capacity(capacity), + sort_batch_size, local_partition, _marker: PhantomData::<(&'p (), R)>, @@ -85,9 +311,22 @@ impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> WaterLevelReporterProxy<'l, self.water_level } + fn partial_sort_step(&mut self) -> ControlFlow<()> { + self.sort_slow_events_step(false) + } + fn advance_water_level(&mut self, water_level: NonNegativeF64) { + let mut i = 0; + // Report all events below the water level in sorted order - self.slow_events.sort(); + while let ControlFlow::Continue(()) = self.sort_slow_events_step(true) { + if (i % 100) == 0 { + info!("{:?}", self); + } + i += 1; + } + + debug_assert!(self.slow_events.is_sorted()); for event in self.slow_events.drain(..) { match event.into() { @@ -104,14 +343,28 @@ impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> WaterLevelReporterProxy<'l, } } + self.runs.clear(); + self.run = Run { start: 0, len: 0 }; + // Update the water level self.water_level = water_level; // Move fast events below the new water level into slow events - self.slow_events.extend( - self.fast_events - .drain_filter(|event| event.event_time() < water_level), - ); + for event in self.fast_events.drain_filter(|event| event.event_time() < water_level) { + let new_run = self.run.len > self.sort_batch_size; // self.slow_events.last().map_or(true, |prev| prev > &event); + + if new_run { + let old_run = core::mem::replace(&mut self.run, Run { + start: self.slow_events.len(), + len: 1, + }); + self.overflow.push_back(old_run); + } else { + self.run.len += 1; + } + + self.slow_events.push(event); + } } fn local_partition(&mut self) -> &mut P { @@ -124,7 +377,9 @@ impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> Drop { fn drop(&mut self) { // Report all events below the water level in sorted order - self.slow_events.sort(); + while let ControlFlow::Continue(()) = self.sort_slow_events_step(true) {} + + debug_assert!(self.slow_events.is_sorted()); for event in self.slow_events.drain(..) { match event.into() { @@ -141,6 +396,9 @@ impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> Drop } } + self.runs.clear(); + self.run = Run { start: 0, len: 0 }; + // Report all events above the water level in sorted order self.fast_events.sort(); diff --git a/necsim/impls/no-std/src/parallelisation/independent/monolithic/reporter/mod.rs b/necsim/impls/no-std/src/parallelisation/independent/monolithic/reporter/mod.rs index 7df56366e..03c6ec143 100644 --- a/necsim/impls/no-std/src/parallelisation/independent/monolithic/reporter/mod.rs +++ b/necsim/impls/no-std/src/parallelisation/independent/monolithic/reporter/mod.rs @@ -1,3 +1,5 @@ +use core::ops::ControlFlow; + use necsim_core_bond::NonNegativeF64; use necsim_core::reporter::{ @@ -21,10 +23,12 @@ pub trait WaterLevelReporterProxy<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> ReportProgress = False, > { - fn new(capacity: usize, local_partition: &'l mut P) -> Self; + fn new(capacity: usize, local_partition: &'l mut P, sort_batch_size: usize) -> Self; fn water_level(&self) -> NonNegativeF64; + fn partial_sort_step(&mut self) -> ControlFlow<()>; + #[debug_requires(water_level >= self.water_level(), "advances the water level")] #[debug_ensures(self.water_level() == old(water_level))] fn advance_water_level(&mut self, water_level: NonNegativeF64); diff --git a/necsim/impls/no-std/src/parallelisation/independent/monolithic/reporter/recorded.rs b/necsim/impls/no-std/src/parallelisation/independent/monolithic/reporter/recorded.rs index 65a4d746b..737d1c095 100644 --- a/necsim/impls/no-std/src/parallelisation/independent/monolithic/reporter/recorded.rs +++ b/necsim/impls/no-std/src/parallelisation/independent/monolithic/reporter/recorded.rs @@ -1,4 +1,4 @@ -use core::{fmt, marker::PhantomData}; +use core::{fmt, marker::PhantomData, ops::ControlFlow}; use necsim_core_bond::NonNegativeF64; use necsim_core::{impl_report, reporter::Reporter}; @@ -51,7 +51,7 @@ impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> Reporter impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> WaterLevelReporterProxy<'l, 'p, R, P> for RecordedWaterLevelReporterProxy<'l, 'p, R, P> { - fn new(_capacity: usize, local_partition: &'l mut P) -> Self { + fn new(_capacity: usize, local_partition: &'l mut P, _sort_batch_size: usize) -> Self { info!("Events will be reported using the recorded water-level algorithm ..."); Self { @@ -66,6 +66,10 @@ impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> WaterLevelReporterProxy<'l, self.water_level } + fn partial_sort_step(&mut self) -> ControlFlow<()> { + ControlFlow::Break(()) + } + fn advance_water_level(&mut self, water_level: NonNegativeF64) { self.water_level = water_level; } diff --git a/rustcoalescence/algorithms/cuda/src/arguments.rs b/rustcoalescence/algorithms/cuda/src/arguments.rs index 0aad7af77..73758b9cb 100644 --- a/rustcoalescence/algorithms/cuda/src/arguments.rs +++ b/rustcoalescence/algorithms/cuda/src/arguments.rs @@ -1,4 +1,4 @@ -use std::num::{NonZeroU32, NonZeroU64}; +use std::num::{NonZeroU32, NonZeroU64, NonZeroUsize}; use serde::{Deserialize, Serialize}; use serde_state::DeserializeState; @@ -70,6 +70,7 @@ pub struct CudaArguments { pub block_size: NonZeroU32, pub grid_size: NonZeroU32, pub sort_block_size: NonZeroU32, + pub sort_batch_size: NonZeroUsize, pub sort_mode: SortMode, pub step_slice: NonZeroU64, pub dedup_cache: DedupCache, @@ -104,6 +105,7 @@ impl<'de> DeserializeState<'de, Partition> for CudaArguments { block_size: raw.block_size, grid_size: raw.grid_size, sort_block_size: raw.sort_block_size, + sort_batch_size: raw.sort_batch_size, sort_mode: raw.sort_mode, step_slice: raw.step_slice, dedup_cache: raw.dedup_cache, @@ -122,6 +124,7 @@ pub struct CudaArgumentsRaw { pub block_size: NonZeroU32, pub grid_size: NonZeroU32, pub sort_block_size: NonZeroU32, + pub sort_batch_size: NonZeroUsize, pub sort_mode: SortMode, pub step_slice: NonZeroU64, pub dedup_cache: DedupCache, @@ -138,6 +141,7 @@ impl Default for CudaArgumentsRaw { block_size: NonZeroU32::new(64_u32).unwrap(), grid_size: NonZeroU32::new(64_u32).unwrap(), sort_block_size: NonZeroU32::new(512_u32).unwrap(), + sort_batch_size: NonZeroUsize::new(100_000_usize).unwrap(), sort_mode: SortMode::None, step_slice: NonZeroU64::new(150_u64).unwrap(), dedup_cache: DedupCache::Relative(RelativeCapacity { diff --git a/rustcoalescence/algorithms/cuda/src/launch.rs b/rustcoalescence/algorithms/cuda/src/launch.rs index d2e75cf6f..e36b7973d 100644 --- a/rustcoalescence/algorithms/cuda/src/launch.rs +++ b/rustcoalescence/algorithms/cuda/src/launch.rs @@ -284,6 +284,7 @@ where args.step_slice, args.sort_block_size.get() as usize, args.sort_mode, + args.sort_batch_size.get(), ), &stream, lineages, diff --git a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs index 117c1d6a5..a3191869a 100644 --- a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs +++ b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs @@ -2,7 +2,7 @@ use std::{ collections::VecDeque, convert::{TryFrom, TryInto}, num::NonZeroU64, - sync::atomic::AtomicU64, + sync::atomic::AtomicU64, ops::ControlFlow, }; use rust_cuda::{ @@ -122,7 +122,7 @@ pub fn simulate< <>::WaterLevelReporter as Reporter>::ReportDispersal, >, ), - config: (GridSize, BlockSize, DedupCache, NonZeroU64, usize, SortMode), + config: (GridSize, BlockSize, DedupCache, NonZeroU64, usize, SortMode, usize), stream: &'stream Stream, lineages: LI, event_slice: EventSlice, @@ -178,13 +178,13 @@ pub fn simulate< let event_slice = event_slice.capacity(slow_lineages.len()); + let (grid_size, block_size, dedup_cache, step_slice, sort_block_size, sort_mode, sort_batch_size) = config; + let mut proxy = >::WaterLevelReporter::new(event_slice.get(), local_partition); - - let (grid_size, block_size, dedup_cache, step_slice, sort_block_size, sort_mode) = config; + >>::WaterLevelReporter::new(event_slice.get(), local_partition, sort_batch_size); #[allow(clippy::or_fun_call)] let intial_max_time = slow_lineages @@ -236,6 +236,10 @@ pub fn simulate< let cpu_turnover_rate = simulation.turnover_rate().backup(); let cpu_speciation_probability = simulation.speciation_probability().backup(); + let kernel_event = rust_cuda::host::CudaDropWrapper::from(rust_cuda::rustacuda::event::Event::new( + rust_cuda::rustacuda::event::EventFlags::DISABLE_TIMING + )?); + HostAndDeviceMutRef::with_new(&mut total_time_max, |total_time_max| -> Result<()> { HostAndDeviceMutRef::with_new(&mut total_steps_sum, |total_steps_sum| -> Result<()> { simulation.lend_to_cuda_mut(|mut simulation_cuda_repr| -> Result<()> { @@ -464,6 +468,15 @@ pub fn simulate< let event_buffer_host = event_buffer_cuda.move_to_host_async(stream)?; + kernel_event.record(stream)?; + + while let rust_cuda::rustacuda::event::EventStatus::NotReady = kernel_event.query()? { + if let ControlFlow::Break(()) = proxy.partial_sort_step() { + kernel_event.synchronize()?; + break; + } + } + min_spec_sample_buffer = min_spec_sample_buffer_host.sync_to_host()?; next_event_time_buffer = next_event_time_buffer_host.sync_to_host()?; task_list = task_list_host.sync_to_host()?; From 8ccf8a3d2a0d6c6bd9a1647bb4233254585c9466 Mon Sep 17 00:00:00 2001 From: Juniper Tyree Date: Sun, 11 Dec 2022 05:02:52 -0800 Subject: [PATCH 34/42] More perf improvements for incremental sorting --- .../independent/monolithic/reporter/live.rs | 97 +++++++++++-------- .../cuda/src/parallelisation/monolithic.rs | 46 ++++++--- 2 files changed, 85 insertions(+), 58 deletions(-) diff --git a/necsim/impls/no-std/src/parallelisation/independent/monolithic/reporter/live.rs b/necsim/impls/no-std/src/parallelisation/independent/monolithic/reporter/live.rs index 13083b4cd..31b649599 100644 --- a/necsim/impls/no-std/src/parallelisation/independent/monolithic/reporter/live.rs +++ b/necsim/impls/no-std/src/parallelisation/independent/monolithic/reporter/live.rs @@ -1,4 +1,4 @@ -use alloc::{vec::Vec, collections::VecDeque}; +use alloc::{collections::VecDeque, vec::Vec}; use core::{fmt, marker::PhantomData, ops::ControlFlow}; use necsim_core_bond::NonNegativeF64; @@ -115,7 +115,11 @@ impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> LiveWaterLevelReporterProxy< || (n >= 3 && self.runs[n - 3].len <= self.runs[n - 2].len + self.runs[n - 1].len) || (n >= 4 && self.runs[n - 4].len <= self.runs[n - 3].len + self.runs[n - 2].len)) { - if n >= 3 && self.runs[n - 3].len < self.runs[n - 1].len { Some(n - 3) } else { Some(n - 2) } + if n >= 3 && self.runs[n - 3].len < self.runs[n - 1].len { + Some(n - 3) + } else { + Some(n - 2) + } } else { None } @@ -157,30 +161,36 @@ impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> LiveWaterLevelReporterProxy< let v = v.as_mut_ptr(); let (v_mid, v_end) = unsafe { (v.add(mid), v.add(len)) }; - // The merge process first copies the shorter run into `buf`. Then it traces the newly copied - // run and the longer run forwards (or backwards), comparing their next unconsumed elements and - // copying the lesser (or greater) one into `v`. + // The merge process first copies the shorter run into `buf`. Then it traces the + // newly copied run and the longer run forwards (or backwards), + // comparing their next unconsumed elements and copying the lesser (or + // greater) one into `v`. // - // As soon as the shorter run is fully consumed, the process is done. If the longer run gets - // consumed first, then we must copy whatever is left of the shorter run into the remaining - // hole in `v`. + // As soon as the shorter run is fully consumed, the process is done. If the + // longer run gets consumed first, then we must copy whatever is left of + // the shorter run into the remaining hole in `v`. // - // Intermediate state of the process is always tracked by `hole`, which serves two purposes: - // 1. Protects integrity of `v` from panics in `is_less`. + // Intermediate state of the process is always tracked by `hole`, which serves + // two purposes: 1. Protects integrity of `v` from panics in `is_less`. // 2. Fills the remaining hole in `v` if the longer run gets consumed first. // // Panic safety: // - // If `is_less` panics at any point during the process, `hole` will get dropped and fill the - // hole in `v` with the unconsumed range in `buf`, thus ensuring that `v` still holds every - // object it initially held exactly once. + // If `is_less` panics at any point during the process, `hole` will get dropped + // and fill the hole in `v` with the unconsumed range in `buf`, thus + // ensuring that `v` still holds every object it initially held exactly + // once. let mut hole; if mid <= len - mid { // The left run is shorter. unsafe { core::ptr::copy_nonoverlapping(v, buf, mid); - hole = MergeHole { start: buf, end: buf.add(mid), dest: v }; + hole = MergeHole { + start: buf, + end: buf.add(mid), + dest: v, + }; } // Initially, these pointers point to the beginnings of their arrays. @@ -204,7 +214,11 @@ impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> LiveWaterLevelReporterProxy< // The right run is shorter. unsafe { core::ptr::copy_nonoverlapping(v_mid, buf, len - mid); - hole = MergeHole { start: buf, end: buf.add(len - mid), dest: v_mid }; + hole = MergeHole { + start: buf, + end: buf.add(len - mid), + dest: v_mid, + }; } // Initially, these pointers point past the ends of their arrays. @@ -225,39 +239,24 @@ impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> LiveWaterLevelReporterProxy< } } } - // Finally, `hole` gets dropped. If the shorter run was not fully consumed, whatever remains of - // it will now be copied into the hole in `v`. + // Finally, `hole` gets dropped. If the shorter run was not fully + // consumed, whatever remains of it will now be copied into the + // hole in `v`. } fn sort_slow_events_step(&mut self, force_merge: bool) -> ControlFlow<()> { - let r = loop { - if let Some(r) = self.collapse(force_merge && self.overflow.is_empty()) { - break r; - } - + let Some(r) = self.collapse(force_merge && self.overflow.is_empty() && self.run.len == 0) else { let next_run = match self.overflow.pop_front() { Some(next_run) => next_run, None if self.run.len > 0 => core::mem::replace(&mut self.run, Run { start: self.slow_events.len(), len: 0 }), None => return ControlFlow::Break(()), }; - // let Some(mut next_run) = self.overflow.pop_front() else { - // return ControlFlow::Break(()); - // }; - - // if next_run.len < self.sort_batch_size { - // while next_run.len < self.sort_batch_size { - // let Some(extra_run) = self.overflow.pop_front() else { - // break; - // }; - // next_run.len += extra_run.len; - // } - // self.slow_events[next_run.start..next_run.start+next_run.len].sort_unstable(); - // } - self.slow_events[next_run.start..next_run.start+next_run.len].sort_unstable(); self.runs.push(next_run); + + return ControlFlow::Continue(()); }; let left = self.runs[r]; @@ -266,7 +265,8 @@ impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> LiveWaterLevelReporterProxy< let min_len = left.len.min(right.len); if min_len > self.tmp_events.capacity() { - self.tmp_events.reserve(min_len - self.tmp_events.capacity()); + self.tmp_events + .reserve(min_len - self.tmp_events.capacity()); } unsafe { @@ -278,7 +278,10 @@ impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> LiveWaterLevelReporterProxy< ); } - self.runs[r] = Run { start: left.start, len: left.len + right.len }; + self.runs[r] = Run { + start: left.start, + len: left.len + right.len, + }; self.runs.remove(r + 1); ControlFlow::Continue(()) @@ -319,6 +322,8 @@ impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> WaterLevelReporterProxy<'l, let mut i = 0; // Report all events below the water level in sorted order + // TODO: Should we detect if no partial sort steps were taken + // and revert to a full unstable sort in that case? while let ControlFlow::Continue(()) = self.sort_slow_events_step(true) { if (i % 100) == 0 { info!("{:?}", self); @@ -350,14 +355,20 @@ impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> WaterLevelReporterProxy<'l, self.water_level = water_level; // Move fast events below the new water level into slow events - for event in self.fast_events.drain_filter(|event| event.event_time() < water_level) { + for event in self + .fast_events + .drain_filter(|event| event.event_time() < water_level) + { let new_run = self.run.len > self.sort_batch_size; // self.slow_events.last().map_or(true, |prev| prev > &event); if new_run { - let old_run = core::mem::replace(&mut self.run, Run { - start: self.slow_events.len(), - len: 1, - }); + let old_run = core::mem::replace( + &mut self.run, + Run { + start: self.slow_events.len(), + len: 1, + }, + ); self.overflow.push_back(old_run); } else { self.run.len += 1; diff --git a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs index a3191869a..e1f8dffae 100644 --- a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs +++ b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs @@ -2,7 +2,8 @@ use std::{ collections::VecDeque, convert::{TryFrom, TryInto}, num::NonZeroU64, - sync::atomic::AtomicU64, ops::ControlFlow, + ops::ControlFlow, + sync::atomic::{AtomicU64, Ordering}, }; use rust_cuda::{ @@ -178,13 +179,23 @@ pub fn simulate< let event_slice = event_slice.capacity(slow_lineages.len()); - let (grid_size, block_size, dedup_cache, step_slice, sort_block_size, sort_mode, sort_batch_size) = config; + let ( + grid_size, + block_size, + dedup_cache, + step_slice, + sort_block_size, + sort_mode, + sort_batch_size, + ) = config; let mut proxy = >::WaterLevelReporter::new(event_slice.get(), local_partition, sort_batch_size); + >>::WaterLevelReporter::new( + event_slice.get(), local_partition, sort_batch_size + ); #[allow(clippy::or_fun_call)] let intial_max_time = slow_lineages @@ -236,9 +247,8 @@ pub fn simulate< let cpu_turnover_rate = simulation.turnover_rate().backup(); let cpu_speciation_probability = simulation.speciation_probability().backup(); - let kernel_event = rust_cuda::host::CudaDropWrapper::from(rust_cuda::rustacuda::event::Event::new( - rust_cuda::rustacuda::event::EventFlags::DISABLE_TIMING - )?); + let cuda_kernel_cycle = AtomicU64::new(0); + let mut host_kernel_cycle = 0_u64; HostAndDeviceMutRef::with_new(&mut total_time_max, |total_time_max| -> Result<()> { HostAndDeviceMutRef::with_new(&mut total_steps_sum, |total_steps_sum| -> Result<()> { @@ -295,7 +305,7 @@ pub fn simulate< proxy.advance_water_level(level_time); // Simulate all slow lineages until they have finished or exceeded the - // new water level + // new water level while !slow_lineages.is_empty() { let mut num_tasks = 0_usize; @@ -318,7 +328,7 @@ pub fn simulate< } // Move the task list, event buffer and min speciation sample buffer - // to CUDA + // to CUDA let mut task_list_cuda = task_list.move_to_device_async(stream)?; // TODO: Investigate distributing over several streams @@ -468,11 +478,18 @@ pub fn simulate< let event_buffer_host = event_buffer_cuda.move_to_host_async(stream)?; - kernel_event.record(stream)?; + host_kernel_cycle = host_kernel_cycle.wrapping_add(1); - while let rust_cuda::rustacuda::event::EventStatus::NotReady = kernel_event.query()? { - if let ControlFlow::Break(()) = proxy.partial_sort_step() { - kernel_event.synchronize()?; + // Note: The stream ensures that the stores from subsequent + // cycles are ordered, so no compare_exchange is needed. + stream.add_callback(Box::new(|_| { + cuda_kernel_cycle.store(host_kernel_cycle, Ordering::SeqCst); + }))?; + + // While CUDA runs the simulation kernel, do some incremental + // sorting of the events that have already been produced + while let ControlFlow::Continue(()) = proxy.partial_sort_step() { + if cuda_kernel_cycle.load(Ordering::SeqCst) == host_kernel_cycle { break; } } @@ -496,9 +513,8 @@ pub fn simulate< (task.take(), next_event_time.take()) { if !duplicate_individual { - // Reclassify lineages as either slow (still below - // water) or - // fast + // Reclassify lineages as either slow + // (still below water) or fast if next_event_time < level_time { slow_lineages.push_back((task, next_event_time.into())); } else { From 71fe3cec0fc482890b34741230a73cb0e396fa19 Mon Sep 17 00:00:00 2001 From: Juniper Tyree Date: Sun, 11 Dec 2022 09:11:55 -0800 Subject: [PATCH 35/42] Minor incremental sorting perf optimisations --- .../independent/monolithic/reporter/live.rs | 64 ++++++++++++++++--- .../parallelisation/monolithic/optimistic.rs | 2 +- necsim/impls/std/src/event_log/recorder.rs | 2 +- necsim/impls/std/src/event_log/replay/mod.rs | 2 +- .../src/event_skipping/initialiser/fixup.rs | 4 +- .../gillespie/classical/initialiser/fixup.rs | 4 +- .../gillespie/turnover/initialiser/fixup.rs | 4 +- simulate.ron | 10 +-- 8 files changed, 69 insertions(+), 23 deletions(-) diff --git a/necsim/impls/no-std/src/parallelisation/independent/monolithic/reporter/live.rs b/necsim/impls/no-std/src/parallelisation/independent/monolithic/reporter/live.rs index 31b649599..c9c456e51 100644 --- a/necsim/impls/no-std/src/parallelisation/independent/monolithic/reporter/live.rs +++ b/necsim/impls/no-std/src/parallelisation/independent/monolithic/reporter/live.rs @@ -12,7 +12,7 @@ use necsim_partitioning_core::LocalPartition; use super::WaterLevelReporterProxy; -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] struct Run { start: usize, len: usize, @@ -49,6 +49,7 @@ impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> fmt::Debug .field("water_level", &self.water_level) .field("runs", &self.runs.len()) .field("overflow", &self.overflow.len()) + .field("run", &self.run) .field("slow_events", &EventBufferLen(self.slow_events.len())) .field("fast_events", &EventBufferLen(self.fast_events.len())) .finish() @@ -319,17 +320,35 @@ impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> WaterLevelReporterProxy<'l, } fn advance_water_level(&mut self, water_level: NonNegativeF64) { - let mut i = 0; + info!("{:?}", self); + + if self.run.len > 0 { + let last_run = core::mem::replace( + &mut self.run, + Run { + start: self.slow_events.len(), + len: 0, + }, + ); + self.overflow.push_back(last_run); + } + + if let (Some(Run { start, .. }), Some(Run { start: middle, len })) = ( + self.overflow.front().copied(), + self.overflow.back().copied(), + ) { + self.slow_events[start..middle + len].sort_unstable(); + self.overflow.clear(); + self.runs.push(Run { + start, + len: middle + len - start, + }); + } // Report all events below the water level in sorted order // TODO: Should we detect if no partial sort steps were taken // and revert to a full unstable sort in that case? - while let ControlFlow::Continue(()) = self.sort_slow_events_step(true) { - if (i % 100) == 0 { - info!("{:?}", self); - } - i += 1; - } + while let ControlFlow::Continue(()) = self.sort_slow_events_step(true) {} debug_assert!(self.slow_events.is_sorted()); @@ -387,6 +406,31 @@ impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> Drop for LiveWaterLevelReporterProxy<'l, 'p, R, P> { fn drop(&mut self) { + info!("{:?}", self); + + if self.run.len > 0 { + let last_run = core::mem::replace( + &mut self.run, + Run { + start: self.slow_events.len(), + len: 0, + }, + ); + self.overflow.push_back(last_run); + } + + if let (Some(Run { start, .. }), Some(Run { start: middle, len })) = ( + self.overflow.front().copied(), + self.overflow.back().copied(), + ) { + self.slow_events[start..middle + len].sort_unstable(); + self.overflow.clear(); + self.runs.push(Run { + start, + len: middle + len - start, + }); + } + // Report all events below the water level in sorted order while let ControlFlow::Continue(()) = self.sort_slow_events_step(true) {} @@ -411,7 +455,7 @@ impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> Drop self.run = Run { start: 0, len: 0 }; // Report all events above the water level in sorted order - self.fast_events.sort(); + self.fast_events.sort_unstable(); for event in self.fast_events.drain(..) { match event.into() { @@ -427,5 +471,7 @@ impl<'l, 'p, R: Reporter, P: LocalPartition<'p, R>> Drop }, } } + + info!("{:?}", self); } } diff --git a/necsim/impls/no-std/src/parallelisation/monolithic/optimistic.rs b/necsim/impls/no-std/src/parallelisation/monolithic/optimistic.rs index 78c5e4105..8d6926902 100644 --- a/necsim/impls/no-std/src/parallelisation/monolithic/optimistic.rs +++ b/necsim/impls/no-std/src/parallelisation/monolithic/optimistic.rs @@ -135,7 +135,7 @@ pub fn simulate< )); } - immigrants.sort(); + immigrants.sort_unstable(); // A global rollback is required if at least one partition received unexpected // immigration diff --git a/necsim/impls/std/src/event_log/recorder.rs b/necsim/impls/std/src/event_log/recorder.rs index 2fab5d5e5..7cbf14b68 100644 --- a/necsim/impls/std/src/event_log/recorder.rs +++ b/necsim/impls/std/src/event_log/recorder.rs @@ -177,7 +177,7 @@ impl EventLogRecorder { } fn sort_and_write_segment(&mut self) -> Result<()> { - self.buffer.sort(); + self.buffer.sort_unstable(); let segment_path = self.directory.join(format!("{}", self.segment_index)); self.segment_index += 1; diff --git a/necsim/impls/std/src/event_log/replay/mod.rs b/necsim/impls/std/src/event_log/replay/mod.rs index 65ece1931..bc6a342a6 100644 --- a/necsim/impls/std/src/event_log/replay/mod.rs +++ b/necsim/impls/std/src/event_log/replay/mod.rs @@ -43,7 +43,7 @@ impl Serialize for EventLogReplay { } } - segments.sort(); + segments.sort_unstable(); EventLog { segments, capacity }.serialize(serializer) } diff --git a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/fixup.rs b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/fixup.rs index 0e361bd03..b679acc4c 100644 --- a/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/gillespie/src/event_skipping/initialiser/fixup.rs @@ -199,7 +199,7 @@ where ); }, CoalescenceStrategy::Coalescence => { - coalescence.sort(); + coalescence.sort_unstable(); for (coalescing_lineage, parent) in coalescence { local_partition.get_reporter().report_dispersal( @@ -244,7 +244,7 @@ where return Err(ResumeError::Sample(exceptional_lineages)); } - fixable_lineages.sort(); + fixable_lineages.sort_unstable(); let active_lineage_sampler = RestartFixUpActiveLineageSampler::new( active_lineage_sampler, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs index e0b90e2f4..ce6886252 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/classical/initialiser/fixup.rs @@ -151,7 +151,7 @@ impl< ); }, CoalescenceStrategy::Coalescence => { - coalescence.sort(); + coalescence.sort_unstable(); for (coalescing_lineage, parent) in coalescence { local_partition.get_reporter().report_dispersal( @@ -196,7 +196,7 @@ impl< return Err(ResumeError::Sample(exceptional_lineages)); } - fixable_lineages.sort(); + fixable_lineages.sort_unstable(); let dispersal_sampler = TrespassingDispersalSampler::new( dispersal_sampler, diff --git a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/fixup.rs b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/fixup.rs index efffb65ff..3b307ed40 100644 --- a/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/gillespie/src/gillespie/turnover/initialiser/fixup.rs @@ -173,7 +173,7 @@ impl< ); }, CoalescenceStrategy::Coalescence => { - coalescence.sort(); + coalescence.sort_unstable(); for (coalescing_lineage, parent) in coalescence { local_partition.get_reporter().report_dispersal( @@ -218,7 +218,7 @@ impl< return Err(ResumeError::Sample(exceptional_lineages)); } - fixable_lineages.sort(); + fixable_lineages.sort_unstable(); let dispersal_sampler = TrespassingDispersalSampler::new( dispersal_sampler, diff --git a/simulate.ron b/simulate.ron index eba985740..1a7aa8b9a 100644 --- a/simulate.ron +++ b/simulate.ron @@ -1,19 +1,19 @@ ( - speciation: 0.1, + speciation: 0.0001, sample: Sample(percentage: 1.0), - rng: Entropy, + rng: Seed(42), - algorithm: EventSkipping(), + algorithm: CUDA(step_slice: 150, block_size: 64, grid_size: 128, sort_block_size: 512, sort_mode: None, sort_batch_size: 3500), scenario: NonSpatial( area: (100, 100), - deme: 100, + deme: 1000, ), reporters: [ Plugin( library: "target/release/deps/libnecsim_plugins_common.so", - reporters: [Biodiversity(), Execution(), Progress()], + reporters: [Biodiversity(), Execution(), Progress(), Counter()], ), ], ) From 1b33e567db7c0bb5705e5eee49e6721c1e51978d Mon Sep 17 00:00:00 2001 From: Juniper Langenstein Date: Thu, 29 Dec 2022 09:49:48 +0000 Subject: [PATCH 36/42] Cleaned up CUDA EventBuffer --- necsim/impls/cuda/src/event_buffer.rs | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/necsim/impls/cuda/src/event_buffer.rs b/necsim/impls/cuda/src/event_buffer.rs index 4f50719a1..545dc36bd 100644 --- a/necsim/impls/cuda/src/event_buffer.rs +++ b/necsim/impls/cuda/src/event_buffer.rs @@ -195,26 +195,13 @@ impl }) } - #[allow(clippy::missing_panics_doc)] // TODO: remove pub fn report_events_unordered

(&mut self, reporter: &mut P) where P: Reporter, { - // let mut last_time = 0.0_f64; - - // let mut times = alloc::vec::Vec::new(); - for (mask, event) in self.event_mask.iter_mut().zip(self.event_buffer.iter()) { if *mask.read() { let event: TypedEvent = unsafe { event.read().assume_some_read() }.into(); - // let new_time: f64 = match &event { - // TypedEvent::Speciation(speciation) => speciation.event_time, - // TypedEvent::Dispersal(dispersal) => dispersal.event_time, - // } - // .get(); - // times.push(Some(new_time)); - // assert!(new_time >= last_time, "{new_time} {last_time}"); - // last_time = new_time; match event { TypedEvent::Speciation(ref speciation) => { @@ -224,14 +211,10 @@ impl reporter.report_dispersal(dispersal.into()); }, } - } /*else { - times.push(None); - }*/ + } mask.write(false); } - - // panic!("{:?}", times); } pub fn max_events_per_individual(&self) -> usize { From 04540c6d3258a0392b3014bfe8b813b45395405f Mon Sep 17 00:00:00 2001 From: Juniper Tyree Date: Mon, 16 Jan 2023 06:25:59 +0000 Subject: [PATCH 37/42] Update to latest const-type-layout and rust-cuda --- Cargo.lock | 49 ++++++------------- necsim/core/Cargo.toml | 6 +-- necsim/core/bond/Cargo.toml | 2 +- necsim/impls/cuda/Cargo.toml | 6 +-- necsim/impls/no-std/Cargo.toml | 6 +-- rustcoalescence/algorithms/cuda/Cargo.toml | 2 +- .../algorithms/cuda/cpu-kernel/Cargo.toml | 2 +- .../algorithms/cuda/gpu-kernel/Cargo.toml | 2 +- 8 files changed, 28 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b994f415a..dd20e1ef1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -409,34 +409,15 @@ dependencies = [ [[package]] name = "const-type-layout" version = "0.1.0" -source = "git+https://github.com/juntyr/const-type-layout?rev=8c7d721#8c7d721643c9013bba0a8b01020a37d8352b5808" +source = "git+https://github.com/juntyr/const-type-layout?rev=e163b36#e163b364827a8402a6f55a9ac64414c849051ffd" dependencies = [ - "const-type-layout-derive 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=8c7d721)", -] - -[[package]] -name = "const-type-layout" -version = "0.1.0" -source = "git+https://github.com/MomoLangenstein/const-type-layout?rev=8c7d721#8c7d721643c9013bba0a8b01020a37d8352b5808" -dependencies = [ - "const-type-layout-derive 0.1.0 (git+https://github.com/MomoLangenstein/const-type-layout?rev=8c7d721)", -] - -[[package]] -name = "const-type-layout-derive" -version = "0.1.0" -source = "git+https://github.com/juntyr/const-type-layout?rev=8c7d721#8c7d721643c9013bba0a8b01020a37d8352b5808" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn", + "const-type-layout-derive", ] [[package]] name = "const-type-layout-derive" version = "0.1.0" -source = "git+https://github.com/MomoLangenstein/const-type-layout?rev=8c7d721#8c7d721643c9013bba0a8b01020a37d8352b5808" +source = "git+https://github.com/juntyr/const-type-layout?rev=e163b36#e163b364827a8402a6f55a9ac64414c849051ffd" dependencies = [ "proc-macro-error", "proc-macro2", @@ -1022,7 +1003,7 @@ dependencies = [ name = "necsim-core" version = "0.1.0" dependencies = [ - "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=8c7d721)", + "const-type-layout", "contracts", "necsim-core-bond", "necsim-core-maths", @@ -1034,7 +1015,7 @@ dependencies = [ name = "necsim-core-bond" version = "0.1.0" dependencies = [ - "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=8c7d721)", + "const-type-layout", "necsim-core-maths", "serde", ] @@ -1047,7 +1028,7 @@ version = "0.1.0" name = "necsim-impls-cuda" version = "0.1.0" dependencies = [ - "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=8c7d721)", + "const-type-layout", "contracts", "necsim-core", "rust-cuda", @@ -1058,7 +1039,7 @@ dependencies = [ name = "necsim-impls-no-std" version = "0.1.0" dependencies = [ - "const-type-layout 0.1.0 (git+https://github.com/juntyr/const-type-layout?rev=8c7d721)", + "const-type-layout", "contracts", "displaydoc", "final", @@ -1368,7 +1349,7 @@ dependencies = [ [[package]] name = "ptx-builder" version = "0.5.3" -source = "git+https://github.com/MomoLangenstein/rust-ptx-builder?rev=1f1f49d#1f1f49df761e919f721ef234722ee7b2cfcf9104" +source = "git+https://github.com/juntyr/rust-ptx-builder?rev=1f1f49d#1f1f49df761e919f721ef234722ee7b2cfcf9104" dependencies = [ "anyhow", "colored", @@ -1487,9 +1468,9 @@ dependencies = [ [[package]] name = "rust-cuda" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=6739fd0b#6739fd0bcbb212ed0c24c0cd5f3bfa8fc66af47d" +source = "git+https://github.com/juntyr/rust-cuda?rev=7a41652#7a4165277831ebe6178b1f17e50dd9bdcef3dd06" dependencies = [ - "const-type-layout 0.1.0 (git+https://github.com/MomoLangenstein/const-type-layout?rev=8c7d721)", + "const-type-layout", "final", "rust-cuda-derive", "rust-cuda-ptx-jit", @@ -1501,7 +1482,7 @@ dependencies = [ [[package]] name = "rust-cuda-derive" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=6739fd0b#6739fd0bcbb212ed0c24c0cd5f3bfa8fc66af47d" +source = "git+https://github.com/juntyr/rust-cuda?rev=7a41652#7a4165277831ebe6178b1f17e50dd9bdcef3dd06" dependencies = [ "cargo_metadata", "colored", @@ -1520,7 +1501,7 @@ dependencies = [ [[package]] name = "rust-cuda-ptx-jit" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=6739fd0b#6739fd0bcbb212ed0c24c0cd5f3bfa8fc66af47d" +source = "git+https://github.com/juntyr/rust-cuda?rev=7a41652#7a4165277831ebe6178b1f17e50dd9bdcef3dd06" dependencies = [ "lazy_static", "regex", @@ -1530,7 +1511,7 @@ dependencies = [ [[package]] name = "rustacuda" version = "0.1.3" -source = "git+https://github.com/MomoLangenstein/RustaCUDA?rev=c6ea7cc#c6ea7ccf24b15c4edbd5576852a8dcdc7df272b0" +source = "git+https://github.com/juntyr/RustaCUDA?rev=c6ea7cc#c6ea7ccf24b15c4edbd5576852a8dcdc7df272b0" dependencies = [ "bitflags 1.3.2", "cuda-driver-sys", @@ -1541,12 +1522,12 @@ dependencies = [ [[package]] name = "rustacuda_core" version = "0.1.2" -source = "git+https://github.com/MomoLangenstein/RustaCUDA?rev=c6ea7cc#c6ea7ccf24b15c4edbd5576852a8dcdc7df272b0" +source = "git+https://github.com/juntyr/RustaCUDA?rev=c6ea7cc#c6ea7ccf24b15c4edbd5576852a8dcdc7df272b0" [[package]] name = "rustacuda_derive" version = "0.1.2" -source = "git+https://github.com/MomoLangenstein/RustaCUDA?rev=c6ea7cc#c6ea7ccf24b15c4edbd5576852a8dcdc7df272b0" +source = "git+https://github.com/juntyr/RustaCUDA?rev=c6ea7cc#c6ea7ccf24b15c4edbd5576852a8dcdc7df272b0" dependencies = [ "proc-macro2", "quote", diff --git a/necsim/core/Cargo.toml b/necsim/core/Cargo.toml index ca822fb09..dd7a24ee4 100644 --- a/necsim/core/Cargo.toml +++ b/necsim/core/Cargo.toml @@ -15,12 +15,12 @@ cuda = ["rust-cuda"] necsim-core-maths = { path = "maths" } necsim-core-bond = { path = "bond" } -const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "8c7d721" } +const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "e163b36" } contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6739fd0b", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "7a41652", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6739fd0b", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "7a41652", features = ["derive", "host"], optional = true } diff --git a/necsim/core/bond/Cargo.toml b/necsim/core/bond/Cargo.toml index 927e37b4e..f21fe2937 100644 --- a/necsim/core/bond/Cargo.toml +++ b/necsim/core/bond/Cargo.toml @@ -13,5 +13,5 @@ default = [] [dependencies] necsim-core-maths = { path = "../maths" } -const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "8c7d721" } +const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "e163b36" } serde = { version = "1.0", default-features = false, features = ["derive"] } diff --git a/necsim/impls/cuda/Cargo.toml b/necsim/impls/cuda/Cargo.toml index 293954a88..85a77d3df 100644 --- a/necsim/impls/cuda/Cargo.toml +++ b/necsim/impls/cuda/Cargo.toml @@ -10,12 +10,12 @@ edition = "2021" [dependencies] necsim-core = { path = "../../core", features = ["cuda"] } -const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "8c7d721" } +const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "e163b36" } contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6739fd0b", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "7a41652", features = ["derive"] } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6739fd0b", features = ["derive", "host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "7a41652", features = ["derive", "host"] } diff --git a/necsim/impls/no-std/Cargo.toml b/necsim/impls/no-std/Cargo.toml index 02b026ec6..8ea09fc49 100644 --- a/necsim/impls/no-std/Cargo.toml +++ b/necsim/impls/no-std/Cargo.toml @@ -17,7 +17,7 @@ necsim-core-maths = { path = "../../core/maths" } necsim-core-bond = { path = "../../core/bond" } necsim-partitioning-core = { path = "../../partitioning/core" } -const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "8c7d721" } +const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "e163b36" } contracts = "0.6.3" libm = "0.2" hashbrown = "0.13" @@ -31,7 +31,7 @@ rand_core = "0.6" rand_distr = { version = "0.4", default-features = false, features = [] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6739fd0b", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "7a41652", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6739fd0b", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "7a41652", features = ["derive", "host"], optional = true } diff --git a/rustcoalescence/algorithms/cuda/Cargo.toml b/rustcoalescence/algorithms/cuda/Cargo.toml index d5ff316e4..8be9e11ab 100644 --- a/rustcoalescence/algorithms/cuda/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/Cargo.toml @@ -23,4 +23,4 @@ thiserror = "1.0" serde = { version = "1.0", features = ["derive"] } serde_state = "0.4" serde_derive_state = "0.4" -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6739fd0b", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "7a41652", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml index 798196e14..6017b448c 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml @@ -14,4 +14,4 @@ necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["c necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } rustcoalescence-algorithms-cuda-gpu-kernel = { path = "../gpu-kernel" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6739fd0b", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "7a41652", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml index a109a58b5..c504009fc 100644 --- a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml @@ -16,4 +16,4 @@ necsim-core-bond = { path = "../../../../necsim/core/bond" } necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["cuda"] } necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6739fd0b", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "7a41652", features = ["derive"] } From 81534a97fc88d6109a11153032094fceb9ebb407 Mon Sep 17 00:00:00 2001 From: Juniper Tyree Date: Tue, 9 May 2023 09:56:56 +0000 Subject: [PATCH 38/42] Progress upgrading to the latest rust-cuda, FitsIntoDeviceRegister still broken --- Cargo.lock | 17 ++++- necsim/core/Cargo.toml | 4 +- necsim/impls/cuda/Cargo.toml | 4 +- necsim/impls/cuda/src/event_buffer.rs | 54 +++++++++------- necsim/impls/no-std/Cargo.toml | 4 +- rustcoalescence/algorithms/cuda/Cargo.toml | 2 +- .../algorithms/cuda/cpu-kernel/Cargo.toml | 2 +- .../algorithms/cuda/cpu-kernel/src/link.rs | 10 +-- .../algorithms/cuda/gpu-kernel/Cargo.toml | 2 +- .../algorithms/cuda/gpu-kernel/src/lib.rs | 64 +++++++++++-------- 10 files changed, 100 insertions(+), 63 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dd20e1ef1..193c42b01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -658,6 +658,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1912868bad388722991f80323855d922e32b09ad00d76a13a98e465358765079" +[[package]] +name = "find_cuda_helper" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f9e65c593dd01ac77daad909ea4ad17f0d6d1776193fc8ea766356177abdad" +dependencies = [ + "glob", +] + [[package]] name = "findshlibs" version = "0.10.2" @@ -1468,7 +1477,7 @@ dependencies = [ [[package]] name = "rust-cuda" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=7a41652#7a4165277831ebe6178b1f17e50dd9bdcef3dd06" +source = "git+https://github.com/juntyr/rust-cuda?rev=626cd48#626cd48d9c040f1b9b51668e1716fdc6fa365362" dependencies = [ "const-type-layout", "final", @@ -1482,10 +1491,11 @@ dependencies = [ [[package]] name = "rust-cuda-derive" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=7a41652#7a4165277831ebe6178b1f17e50dd9bdcef3dd06" +source = "git+https://github.com/juntyr/rust-cuda?rev=626cd48#626cd48d9c040f1b9b51668e1716fdc6fa365362" dependencies = [ "cargo_metadata", "colored", + "find_cuda_helper", "lazy_static", "proc-macro-error", "proc-macro2", @@ -1496,12 +1506,13 @@ dependencies = [ "serde_json", "strip-ansi-escapes", "syn 1.0.109", + "thiserror", ] [[package]] name = "rust-cuda-ptx-jit" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=7a41652#7a4165277831ebe6178b1f17e50dd9bdcef3dd06" +source = "git+https://github.com/juntyr/rust-cuda?rev=626cd48#626cd48d9c040f1b9b51668e1716fdc6fa365362" dependencies = [ "lazy_static", "regex", diff --git a/necsim/core/Cargo.toml b/necsim/core/Cargo.toml index dd7a24ee4..5933c96c0 100644 --- a/necsim/core/Cargo.toml +++ b/necsim/core/Cargo.toml @@ -20,7 +20,7 @@ contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "7a41652", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "626cd48", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "7a41652", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "626cd48", features = ["derive", "host"], optional = true } diff --git a/necsim/impls/cuda/Cargo.toml b/necsim/impls/cuda/Cargo.toml index 85a77d3df..3b5ff16d6 100644 --- a/necsim/impls/cuda/Cargo.toml +++ b/necsim/impls/cuda/Cargo.toml @@ -15,7 +15,7 @@ contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "7a41652", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "626cd48", features = ["derive"] } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "7a41652", features = ["derive", "host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "626cd48", features = ["derive", "host"] } diff --git a/necsim/impls/cuda/src/event_buffer.rs b/necsim/impls/cuda/src/event_buffer.rs index 545dc36bd..2a538b092 100644 --- a/necsim/impls/cuda/src/event_buffer.rs +++ b/necsim/impls/cuda/src/event_buffer.rs @@ -271,27 +271,32 @@ impl let shared_buffer_len = ::SharedBuffer::<()>::len(); - let block_dim = rust_cuda::device::utils::block_dim(); + let thread = rust_cuda::device::thread::Thread::this(); + let thread_idx = thread.idx(); + let thread_block = thread.block(); + let block_dim = thread_block.dim(); + let block_idx = thread_block.idx(); + let block_grid = thread_block.grid(); + let grid_dim = block_grid.dim(); if shared_buffer_len != (block_dim.size() * 2) { core::arch::nvptx::trap(); } - let block_idx = - rust_cuda::device::utils::block_idx().as_id(&rust_cuda::device::utils::grid_dim()); - let thread_idx = rust_cuda::device::utils::thread_idx().as_id(&block_dim); + let block_idx = block_idx.as_id(&grid_dim); + let thread_idx = thread_idx.as_id(&block_dim); let idx = block_idx * shared_buffer_len + thread_idx; - let shared_mask: rust_cuda::device::ThreadBlockShared< + let shared_mask: rust_cuda::utils::shared::r#static::ThreadBlockShared< ::SharedBuffer, - > = rust_cuda::device::ThreadBlockShared::new_uninit(); - let shared_mask_array: *mut bool = shared_mask.get().as_mut_ptr(); - let shared_buffer: rust_cuda::device::ThreadBlockShared< + > = rust_cuda::utils::shared::r#static::ThreadBlockShared::new_uninit(); + let shared_mask_array: *mut bool = shared_mask.as_mut_ptr().cast(); + let shared_buffer: rust_cuda::utils::shared::r#static::ThreadBlockShared< ::SharedBuffer::Event>>, - > = rust_cuda::device::ThreadBlockShared::new_uninit(); + > = rust_cuda::utils::shared::r#static::ThreadBlockShared::new_uninit(); let shared_buffer_array: *mut MaybeSome<::Event> = - shared_buffer.get().as_mut_ptr(); + shared_buffer.as_mut_ptr().cast(); *shared_mask_array.add(thread_idx) = match self.event_mask.alias_unchecked().get(idx) { None => false, @@ -476,27 +481,32 @@ impl let shared_buffer_len = ::SharedBuffer::<()>::len(); - let block_dim = rust_cuda::device::utils::block_dim(); + let thread = rust_cuda::device::thread::Thread::this(); + let thread_idx = thread.idx(); + let thread_block = thread.block(); + let block_dim = thread_block.dim(); + let block_idx = thread_block.idx(); + let block_grid = thread_block.grid(); + let grid_dim = block_grid.dim(); if shared_buffer_len != (block_dim.size() * 2) { core::arch::nvptx::trap(); } - let block_idx = - rust_cuda::device::utils::block_idx().as_id(&rust_cuda::device::utils::grid_dim()); - let thread_idx = rust_cuda::device::utils::thread_idx().as_id(&block_dim); + let block_idx = block_idx.as_id(&grid_dim); + let thread_idx = thread_idx.as_id(&block_dim); let idx = block_idx * shared_buffer_len + thread_idx; - let shared_mask: rust_cuda::device::ThreadBlockShared< + let shared_mask: rust_cuda::utils::shared::r#static::ThreadBlockShared< ::SharedBuffer, - > = rust_cuda::device::ThreadBlockShared::new_uninit(); - let shared_mask_array: *mut bool = shared_mask.get().cast(); - let shared_buffer: rust_cuda::device::ThreadBlockShared< + > = rust_cuda::utils::shared::r#static::ThreadBlockShared::new_uninit(); + let shared_mask_array: *mut bool = shared_mask.as_mut_ptr().cast(); + let shared_buffer: rust_cuda::utils::shared::r#static::ThreadBlockShared< ::SharedBuffer::Event>>, - > = rust_cuda::device::ThreadBlockShared::new_uninit(); + > = rust_cuda::utils::shared::r#static::ThreadBlockShared::new_uninit(); let shared_buffer_array: *mut MaybeSome<::Event> = - shared_buffer.get().cast(); + shared_buffer.as_mut_ptr().cast(); *shared_mask_array.add(thread_idx) = match self.event_mask.alias_unchecked().get(idx) { None => false, @@ -618,7 +628,7 @@ impl pub unsafe fn bitonic_sort_events_step(&mut self, size: usize, stride: usize) { use core::cmp::Ordering; - let idx = rust_cuda::device::utils::index(); + let idx = rust_cuda::device::thread::Thread::this().index(); let pos = idx & ((self.event_mask.alias_unchecked().len().next_power_of_two() / 2) - 1); @@ -719,7 +729,7 @@ impl pub unsafe fn odd_even_sort_events_step(&mut self, size: usize, stride: usize) { use core::cmp::Ordering; - let idx = rust_cuda::device::utils::index(); + let idx = rust_cuda::device::thread::Thread::this().index(); let pos = 2 * idx - (idx & (stride - 1)); diff --git a/necsim/impls/no-std/Cargo.toml b/necsim/impls/no-std/Cargo.toml index 8ea09fc49..82401ccc7 100644 --- a/necsim/impls/no-std/Cargo.toml +++ b/necsim/impls/no-std/Cargo.toml @@ -31,7 +31,7 @@ rand_core = "0.6" rand_distr = { version = "0.4", default-features = false, features = [] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "7a41652", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "626cd48", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "7a41652", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "626cd48", features = ["derive", "host"], optional = true } diff --git a/rustcoalescence/algorithms/cuda/Cargo.toml b/rustcoalescence/algorithms/cuda/Cargo.toml index 8be9e11ab..55b44e234 100644 --- a/rustcoalescence/algorithms/cuda/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/Cargo.toml @@ -23,4 +23,4 @@ thiserror = "1.0" serde = { version = "1.0", features = ["derive"] } serde_state = "0.4" serde_derive_state = "0.4" -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "7a41652", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "626cd48", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml index 6017b448c..7136f2919 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml @@ -14,4 +14,4 @@ necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["c necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } rustcoalescence-algorithms-cuda-gpu-kernel = { path = "../gpu-kernel" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "7a41652", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "626cd48", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs b/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs index 436b74443..24947daa8 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/src/link.rs @@ -1,8 +1,10 @@ use rustcoalescence_algorithms_cuda_gpu_kernel::{ - BitonicGlobalSortStepKernelArgs, BitonicGlobalSortSteppableKernel, - BitonicSharedSortPrepKernelArgs, BitonicSharedSortPreparableKernel, - BitonicSharedSortStepKernelArgs, BitonicSharedSortSteppableKernel, EvenOddSortKernelArgs, - EvenOddSortableKernel, SimulatableKernel, SimulationKernelArgs, + BitonicGlobalSortStepKernelArgs, BitonicGlobalSortStepKernelPtx, + BitonicGlobalSortSteppableKernel, BitonicSharedSortPrepKernelArgs, + BitonicSharedSortPrepKernelPtx, BitonicSharedSortPreparableKernel, + BitonicSharedSortStepKernelArgs, BitonicSharedSortStepKernelPtx, + BitonicSharedSortSteppableKernel, EvenOddSortKernelArgs, EvenOddSortKernelPtx, + EvenOddSortableKernel, SimulatableKernel, SimulationKernelArgs, SimulationKernelPtx, }; use crate::{ diff --git a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml index c504009fc..5be731ac0 100644 --- a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml @@ -16,4 +16,4 @@ necsim-core-bond = { path = "../../../../necsim/core/bond" } necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["cuda"] } necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "7a41652", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "626cd48", features = ["derive"] } diff --git a/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs b/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs index 6ae7e7bb3..15ffae0b9 100644 --- a/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs +++ b/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs @@ -31,26 +31,28 @@ use necsim_impls_no_std::cogs::{ event_sampler::tracking::{MinSpeciationTrackingEventSampler, SpeciationSample}, }; -use rust_cuda::common::RustToCuda; +use rust_cuda::{common::RustToCuda, safety::NoAliasing}; #[rust_cuda::common::kernel( - pub use link_kernel! as impl SimulatableKernel for SimulationKernel + pub use link_kernel! as impl SimulatableKernel< + SimulationKernelArgs, SimulationKernelPtx, + > for SimulationKernel )] #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] pub fn simulate< M: MathsCore, - H: Habitat + RustToCuda, - G: Rng + RustToCuda, - S: LineageStore + RustToCuda, - X: EmigrationExit + RustToCuda, - D: DispersalSampler + RustToCuda, - C: CoalescenceSampler + RustToCuda, - T: TurnoverRate + RustToCuda, - N: SpeciationProbability + RustToCuda, - E: MinSpeciationTrackingEventSampler + RustToCuda, - I: ImmigrationEntry + RustToCuda, - A: SingularActiveLineageSampler + RustToCuda, + H: Habitat + RustToCuda + NoAliasing, + G: Rng + RustToCuda + NoAliasing, + S: LineageStore + RustToCuda + NoAliasing, + X: EmigrationExit + RustToCuda + NoAliasing, + D: DispersalSampler + RustToCuda + NoAliasing, + C: CoalescenceSampler + RustToCuda + NoAliasing, + T: TurnoverRate + RustToCuda + NoAliasing, + N: SpeciationProbability + RustToCuda + NoAliasing, + E: MinSpeciationTrackingEventSampler + RustToCuda + NoAliasing, + I: ImmigrationEntry + RustToCuda + NoAliasing, + A: SingularActiveLineageSampler + RustToCuda + NoAliasing, ReportSpeciation: Boolean, ReportDispersal: Boolean, >( @@ -135,13 +137,17 @@ pub fn simulate< } // #[rust_cuda::common::kernel( -// pub use link_sort_kernel! as impl SortableKernel for -// SortKernel )] +// pub use link_sort_kernel! as impl SortableKernel< +// SortKernelArgs, SortKernelPtx, +// > for SortKernel +// )] // pub fn sort_events_step( -// #[kernel(pass = LendRustToCuda, jit)] event_buffer_reporter: &mut -// ShallowCopy< -// necsim_impls_cuda::event_buffer::EventBuffer, >, +// #[kernel(pass = LendRustToCuda, jit)] +// event_buffer_reporter: &mut ShallowCopy< +// necsim_impls_cuda::event_buffer::EventBuffer< +// ReportSpeciation, ReportDispersal, +// >, +// >, // #[kernel(pass = SafeDeviceCopy)] size: usize, // #[kernel(pass = SafeDeviceCopy)] stride: usize, // ) { @@ -152,7 +158,9 @@ pub fn simulate< // } #[rust_cuda::common::kernel( - pub use link_even_odd_sort_kernel! as impl EvenOddSortableKernel for EvenOddSortKernel + pub use link_even_odd_sort_kernel! as impl EvenOddSortableKernel< + EvenOddSortKernelArgs, EvenOddSortKernelPtx, + > for EvenOddSortKernel )] pub fn even_odd_sort_events_step( #[kernel(pass = LendRustToCuda, jit)] event_buffer_reporter: &mut ShallowCopy< @@ -168,7 +176,9 @@ pub fn even_odd_sort_events_step for BitonicGlobalSortStepKernel + pub use link_bitonic_global_sort_step_kernel! as impl BitonicGlobalSortSteppableKernel< + BitonicGlobalSortStepKernelArgs, BitonicGlobalSortStepKernelPtx, + > for BitonicGlobalSortStepKernel )] pub fn bitonic_global_sort_events_step( #[kernel(pass = LendRustToCuda, jit)] event_buffer_reporter: &mut ShallowCopy< @@ -184,7 +194,9 @@ pub fn bitonic_global_sort_events_step for BitonicSharedSortStepKernel + pub use link_bitonic_shared_sort_step_kernel! as impl BitonicSharedSortSteppableKernel< + BitonicSharedSortStepKernelArgs, BitonicSharedSortStepKernelPtx, + > for BitonicSharedSortStepKernel )] pub fn bitonic_shared_sort_events_step( #[kernel(pass = LendRustToCuda, jit)] event_buffer_reporter: &mut ShallowCopy< @@ -199,7 +211,9 @@ pub fn bitonic_shared_sort_events_step for BitonicSharedSortPrepKernel + pub use link_bitonic_shared_sort_prep_kernel! as impl BitonicSharedSortPreparableKernel< + BitonicSharedSortPrepKernelArgs, BitonicSharedSortPrepKernelPtx, + > for BitonicSharedSortPrepKernel )] pub fn bitonic_shared_sort_events_prep( #[kernel(pass = LendRustToCuda, jit)] event_buffer_reporter: &mut ShallowCopy< @@ -215,10 +229,10 @@ pub fn bitonic_shared_sort_events_prep Date: Tue, 9 May 2023 12:59:32 +0000 Subject: [PATCH 39/42] Added compile-time-checked lints against local mem and register spills in CUDA kernels --- Cargo.lock | 6 +- necsim/core/Cargo.toml | 4 +- necsim/impls/cuda/Cargo.toml | 4 +- necsim/impls/no-std/Cargo.toml | 4 +- rustcoalescence/algorithms/cuda/Cargo.toml | 2 +- .../algorithms/cuda/cpu-kernel/Cargo.toml | 2 +- .../algorithms/cuda/cpu-kernel/src/lib.rs | 29 ++- .../algorithms/cuda/cpu-kernel/src/patch.rs | 231 ++++-------------- .../algorithms/cuda/gpu-kernel/Cargo.toml | 2 +- .../algorithms/cuda/gpu-kernel/src/lib.rs | 24 ++ .../algorithms/cuda/src/initialiser/fixup.rs | 26 +- .../cuda/src/initialiser/genesis.rs | 26 +- .../algorithms/cuda/src/initialiser/mod.rs | 28 ++- .../algorithms/cuda/src/initialiser/resume.rs | 26 +- rustcoalescence/algorithms/cuda/src/launch.rs | 9 +- rustcoalescence/algorithms/cuda/src/lib.rs | 10 +- .../cuda/src/parallelisation/monolithic.rs | 23 +- 17 files changed, 180 insertions(+), 276 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 193c42b01..418b89491 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1477,7 +1477,7 @@ dependencies = [ [[package]] name = "rust-cuda" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=626cd48#626cd48d9c040f1b9b51668e1716fdc6fa365362" +source = "git+https://github.com/juntyr/rust-cuda?rev=6b7c773#6b7c77372db56a078c842236acad62c249c7878c" dependencies = [ "const-type-layout", "final", @@ -1491,7 +1491,7 @@ dependencies = [ [[package]] name = "rust-cuda-derive" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=626cd48#626cd48d9c040f1b9b51668e1716fdc6fa365362" +source = "git+https://github.com/juntyr/rust-cuda?rev=6b7c773#6b7c77372db56a078c842236acad62c249c7878c" dependencies = [ "cargo_metadata", "colored", @@ -1512,7 +1512,7 @@ dependencies = [ [[package]] name = "rust-cuda-ptx-jit" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=626cd48#626cd48d9c040f1b9b51668e1716fdc6fa365362" +source = "git+https://github.com/juntyr/rust-cuda?rev=6b7c773#6b7c77372db56a078c842236acad62c249c7878c" dependencies = [ "lazy_static", "regex", diff --git a/necsim/core/Cargo.toml b/necsim/core/Cargo.toml index 5933c96c0..ce5574422 100644 --- a/necsim/core/Cargo.toml +++ b/necsim/core/Cargo.toml @@ -20,7 +20,7 @@ contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "626cd48", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6b7c773", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "626cd48", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6b7c773", features = ["derive", "host"], optional = true } diff --git a/necsim/impls/cuda/Cargo.toml b/necsim/impls/cuda/Cargo.toml index 3b5ff16d6..85ac45730 100644 --- a/necsim/impls/cuda/Cargo.toml +++ b/necsim/impls/cuda/Cargo.toml @@ -15,7 +15,7 @@ contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "626cd48", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6b7c773", features = ["derive"] } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "626cd48", features = ["derive", "host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6b7c773", features = ["derive", "host"] } diff --git a/necsim/impls/no-std/Cargo.toml b/necsim/impls/no-std/Cargo.toml index 82401ccc7..a7d980052 100644 --- a/necsim/impls/no-std/Cargo.toml +++ b/necsim/impls/no-std/Cargo.toml @@ -31,7 +31,7 @@ rand_core = "0.6" rand_distr = { version = "0.4", default-features = false, features = [] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "626cd48", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6b7c773", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "626cd48", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6b7c773", features = ["derive", "host"], optional = true } diff --git a/rustcoalescence/algorithms/cuda/Cargo.toml b/rustcoalescence/algorithms/cuda/Cargo.toml index 55b44e234..967d66238 100644 --- a/rustcoalescence/algorithms/cuda/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/Cargo.toml @@ -23,4 +23,4 @@ thiserror = "1.0" serde = { version = "1.0", features = ["derive"] } serde_state = "0.4" serde_derive_state = "0.4" -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "626cd48", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6b7c773", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml index 7136f2919..542fb3f2e 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml @@ -14,4 +14,4 @@ necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["c necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } rustcoalescence-algorithms-cuda-gpu-kernel = { path = "../gpu-kernel" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "626cd48", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6b7c773", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs b/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs index 28d080561..7ad21b0d7 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/src/lib.rs @@ -27,11 +27,14 @@ use rust_cuda::{ error::{CudaError, CudaResult}, function::{BlockSize, Function, GridSize}, }, + safety::NoAliasing, }; use rustcoalescence_algorithms_cuda_gpu_kernel::{ - BitonicGlobalSortSteppableKernel, BitonicSharedSortPreparableKernel, - BitonicSharedSortSteppableKernel, EvenOddSortableKernel, SimulatableKernel, + BitonicGlobalSortStepKernelPtx, BitonicGlobalSortSteppableKernel, + BitonicSharedSortPrepKernelPtx, BitonicSharedSortPreparableKernel, + BitonicSharedSortStepKernelPtx, BitonicSharedSortSteppableKernel, EvenOddSortKernelPtx, + EvenOddSortableKernel, SimulatableKernel, SimulationKernelPtx, }; mod link; @@ -83,17 +86,17 @@ pub struct SimulationKernel< impl< M: MathsCore, - H: Habitat + RustToCuda, - G: Rng + RustToCuda, - S: LineageStore + RustToCuda, - X: EmigrationExit + RustToCuda, - D: DispersalSampler + RustToCuda, - C: CoalescenceSampler + RustToCuda, - T: TurnoverRate + RustToCuda, - N: SpeciationProbability + RustToCuda, - E: MinSpeciationTrackingEventSampler + RustToCuda, - I: ImmigrationEntry + RustToCuda, - A: SingularActiveLineageSampler + RustToCuda, + H: Habitat + RustToCuda + NoAliasing, + G: Rng + RustToCuda + NoAliasing, + S: LineageStore + RustToCuda + NoAliasing, + X: EmigrationExit + RustToCuda + NoAliasing, + D: DispersalSampler + RustToCuda + NoAliasing, + C: CoalescenceSampler + RustToCuda + NoAliasing, + T: TurnoverRate + RustToCuda + NoAliasing, + N: SpeciationProbability + RustToCuda + NoAliasing, + E: MinSpeciationTrackingEventSampler + RustToCuda + NoAliasing, + I: ImmigrationEntry + RustToCuda + NoAliasing, + A: SingularActiveLineageSampler + RustToCuda + NoAliasing, ReportSpeciation: Boolean, ReportDispersal: Boolean, > SimulationKernel diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs b/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs index 52a5a0629..5c734e598 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/src/patch.rs @@ -1,31 +1,24 @@ -use std::sync::atomic::AtomicU64; - use necsim_core::{ cogs::{ CoalescenceSampler, DispersalSampler, EmigrationExit, Habitat, ImmigrationEntry, LineageStore, MathsCore, PrimeableRng, Rng, SpeciationProbability, TurnoverRate, }, - lineage::Lineage, reporter::boolean::{Boolean, False, True}, - simulation::Simulation, }; -use necsim_core_bond::{NonNegativeF64, PositiveF64}; -use necsim_impls_cuda::{event_buffer::EventBuffer, value_buffer::ValueBuffer}; use necsim_impls_no_std::cogs::{ active_lineage_sampler::singular::SingularActiveLineageSampler, - event_sampler::tracking::{MinSpeciationTrackingEventSampler, SpeciationSample}, + event_sampler::tracking::MinSpeciationTrackingEventSampler, }; use rust_cuda::{ - common::{DeviceAccessible, RustToCuda}, - host::{HostAndDeviceConstRefAsync, HostAndDeviceMutRefAsync, TypedKernel}, - rustacuda::{error::CudaResult, stream::Stream}, - utils::device_copy::SafeDeviceCopyWrapper, + common::RustToCuda, host::TypedKernel, rustacuda::error::CudaResult, safety::NoAliasing, }; use rustcoalescence_algorithms_cuda_gpu_kernel::{ - BitonicGlobalSortSteppableKernel, BitonicSharedSortPreparableKernel, - BitonicSharedSortSteppableKernel, EvenOddSortableKernel, SimulatableKernel, + BitonicGlobalSortStepKernelPtx, BitonicGlobalSortSteppableKernel, + BitonicSharedSortPrepKernelPtx, BitonicSharedSortPreparableKernel, + BitonicSharedSortStepKernelPtx, BitonicSharedSortSteppableKernel, EvenOddSortKernelPtx, + EvenOddSortableKernel, SimulatableKernel, SimulationKernelPtx, }; use crate::{ @@ -45,30 +38,30 @@ extern "C" { #[allow(clippy::trait_duplication_in_bounds)] unsafe impl< M: MathsCore, - H: Habitat + RustToCuda, - G: Rng + RustToCuda, - S: LineageStore + RustToCuda, - X: EmigrationExit + RustToCuda, - D: DispersalSampler + RustToCuda, - C: CoalescenceSampler + RustToCuda, - T: TurnoverRate + RustToCuda, - N: SpeciationProbability + RustToCuda, - E: MinSpeciationTrackingEventSampler + RustToCuda, - I: ImmigrationEntry + RustToCuda, - A: SingularActiveLineageSampler + RustToCuda, + H: Habitat + RustToCuda + NoAliasing, + G: Rng + RustToCuda + NoAliasing, + S: LineageStore + RustToCuda + NoAliasing, + X: EmigrationExit + RustToCuda + NoAliasing, + D: DispersalSampler + RustToCuda + NoAliasing, + C: CoalescenceSampler + RustToCuda + NoAliasing, + T: TurnoverRate + RustToCuda + NoAliasing, + N: SpeciationProbability + RustToCuda + NoAliasing, + E: MinSpeciationTrackingEventSampler + RustToCuda + NoAliasing, + I: ImmigrationEntry + RustToCuda + NoAliasing, + A: SingularActiveLineageSampler + RustToCuda + NoAliasing, ReportSpeciation: Boolean, ReportDispersal: Boolean, - > SimulatableKernel + > SimulationKernelPtx for SimulationKernel where SimulationKernel: - SimulatableKernel, + SimulationKernelPtx, SimulationKernel: - SimulatableKernel, + SimulationKernelPtx, SimulationKernel: - SimulatableKernel, + SimulationKernelPtx, SimulationKernel: - SimulatableKernel, + SimulationKernelPtx, { default fn get_ptx_str() -> &'static str { unsafe { unreachable_cuda_simulation_linking_reporter() } @@ -96,67 +89,17 @@ where > { unsafe { unreachable_cuda_simulation_linking_reporter() } } - - default fn simulate<'stream>( - &mut self, - _stream: &'stream Stream, - _simulation: &mut Simulation, - _task_list: &mut ValueBuffer, - _event_buffer_reporter: &mut EventBuffer, - _min_spec_sample_buffer: &mut ValueBuffer, - _next_event_time_buffer: &mut ValueBuffer, - _total_time_max: &AtomicU64, - _total_steps_sum: &AtomicU64, - _max_steps: u64, - _max_next_event_time: NonNegativeF64, - ) -> CudaResult<()> { - unsafe { unreachable_cuda_simulation_linking_reporter() } - } - - default fn simulate_async<'stream>( - &mut self, - _stream: &'stream Stream, - _simulation: HostAndDeviceMutRefAsync< - DeviceAccessible< - as RustToCuda>::CudaRepresentation, - >, - >, - _task_list: HostAndDeviceMutRefAsync< - DeviceAccessible< as RustToCuda>::CudaRepresentation>, - >, - _event_buffer_reporter: HostAndDeviceMutRefAsync< - DeviceAccessible< - as RustToCuda>::CudaRepresentation, - >, - >, - _min_spec_sample_buffer: HostAndDeviceMutRefAsync< - DeviceAccessible< - as RustToCuda>::CudaRepresentation, - >, - >, - _next_event_time_buffer: HostAndDeviceMutRefAsync< - DeviceAccessible< - as RustToCuda>::CudaRepresentation, - >, - >, - _total_time_max: HostAndDeviceConstRefAsync>, - _total_steps_sum: HostAndDeviceConstRefAsync>, - _max_steps: SafeDeviceCopyWrapper, - _max_next_event_time: SafeDeviceCopyWrapper, - ) -> CudaResult<()> { - unsafe { unreachable_cuda_simulation_linking_reporter() } - } } #[allow(clippy::trait_duplication_in_bounds)] unsafe impl - EvenOddSortableKernel + EvenOddSortKernelPtx for EvenOddSortKernel where - EvenOddSortKernel: EvenOddSortableKernel, - EvenOddSortKernel: EvenOddSortableKernel, - EvenOddSortKernel: EvenOddSortableKernel, - EvenOddSortKernel: EvenOddSortableKernel, + EvenOddSortKernel: EvenOddSortKernelPtx, + EvenOddSortKernel: EvenOddSortKernelPtx, + EvenOddSortKernel: EvenOddSortKernelPtx, + EvenOddSortKernel: EvenOddSortKernelPtx, { default fn get_ptx_str() -> &'static str { unsafe { unreachable_cuda_simulation_linking_reporter() } @@ -166,41 +109,17 @@ where ) -> CudaResult>> { unsafe { unreachable_cuda_simulation_linking_reporter() } } - - default fn even_odd_sort_events_step<'stream>( - &mut self, - _stream: &'stream Stream, - _event_buffer_reporter: &mut EventBuffer, - _size: usize, - _stride: usize, - ) -> CudaResult<()> { - unsafe { unreachable_cuda_simulation_linking_reporter() } - } - - default fn even_odd_sort_events_step_async<'stream>( - &mut self, - _stream: &'stream Stream, - _event_buffer_reporter: HostAndDeviceMutRefAsync< - DeviceAccessible< - as RustToCuda>::CudaRepresentation, - >, - >, - _size: SafeDeviceCopyWrapper, - _stride: SafeDeviceCopyWrapper, - ) -> CudaResult<()> { - unsafe { unreachable_cuda_simulation_linking_reporter() } - } } #[allow(clippy::trait_duplication_in_bounds)] unsafe impl - BitonicGlobalSortSteppableKernel + BitonicGlobalSortStepKernelPtx for BitonicGlobalSortStepKernel where - BitonicGlobalSortStepKernel: BitonicGlobalSortSteppableKernel, - BitonicGlobalSortStepKernel: BitonicGlobalSortSteppableKernel, - BitonicGlobalSortStepKernel: BitonicGlobalSortSteppableKernel, - BitonicGlobalSortStepKernel: BitonicGlobalSortSteppableKernel, + BitonicGlobalSortStepKernel: BitonicGlobalSortStepKernelPtx, + BitonicGlobalSortStepKernel: BitonicGlobalSortStepKernelPtx, + BitonicGlobalSortStepKernel: BitonicGlobalSortStepKernelPtx, + BitonicGlobalSortStepKernel: BitonicGlobalSortStepKernelPtx, { default fn get_ptx_str() -> &'static str { unsafe { unreachable_cuda_simulation_linking_reporter() } @@ -211,41 +130,17 @@ where > { unsafe { unreachable_cuda_simulation_linking_reporter() } } - - default fn bitonic_global_sort_events_step<'stream>( - &mut self, - _stream: &'stream Stream, - _event_buffer_reporter: &mut EventBuffer, - _size: usize, - _stride: usize, - ) -> CudaResult<()> { - unsafe { unreachable_cuda_simulation_linking_reporter() } - } - - default fn bitonic_global_sort_events_step_async<'stream>( - &mut self, - _stream: &'stream Stream, - _event_buffer_reporter: HostAndDeviceMutRefAsync< - DeviceAccessible< - as RustToCuda>::CudaRepresentation, - >, - >, - _size: SafeDeviceCopyWrapper, - _stride: SafeDeviceCopyWrapper, - ) -> CudaResult<()> { - unsafe { unreachable_cuda_simulation_linking_reporter() } - } } #[allow(clippy::trait_duplication_in_bounds)] unsafe impl - BitonicSharedSortSteppableKernel + BitonicSharedSortStepKernelPtx for BitonicSharedSortStepKernel where - BitonicSharedSortStepKernel: BitonicSharedSortSteppableKernel, - BitonicSharedSortStepKernel: BitonicSharedSortSteppableKernel, - BitonicSharedSortStepKernel: BitonicSharedSortSteppableKernel, - BitonicSharedSortStepKernel: BitonicSharedSortSteppableKernel, + BitonicSharedSortStepKernel: BitonicSharedSortStepKernelPtx, + BitonicSharedSortStepKernel: BitonicSharedSortStepKernelPtx, + BitonicSharedSortStepKernel: BitonicSharedSortStepKernelPtx, + BitonicSharedSortStepKernel: BitonicSharedSortStepKernelPtx, { default fn get_ptx_str() -> &'static str { unsafe { unreachable_cuda_simulation_linking_reporter() } @@ -256,39 +151,17 @@ where > { unsafe { unreachable_cuda_simulation_linking_reporter() } } - - default fn bitonic_shared_sort_events_step<'stream>( - &mut self, - _stream: &'stream Stream, - _event_buffer_reporter: &mut EventBuffer, - _size: usize, - ) -> CudaResult<()> { - unsafe { unreachable_cuda_simulation_linking_reporter() } - } - - default fn bitonic_shared_sort_events_step_async<'stream>( - &mut self, - _stream: &'stream Stream, - _event_buffer_reporter: HostAndDeviceMutRefAsync< - DeviceAccessible< - as RustToCuda>::CudaRepresentation, - >, - >, - _size: SafeDeviceCopyWrapper, - ) -> CudaResult<()> { - unsafe { unreachable_cuda_simulation_linking_reporter() } - } } #[allow(clippy::trait_duplication_in_bounds)] unsafe impl - BitonicSharedSortPreparableKernel + BitonicSharedSortPrepKernelPtx for BitonicSharedSortPrepKernel where - BitonicSharedSortPrepKernel: BitonicSharedSortPreparableKernel, - BitonicSharedSortPrepKernel: BitonicSharedSortPreparableKernel, - BitonicSharedSortPrepKernel: BitonicSharedSortPreparableKernel, - BitonicSharedSortPrepKernel: BitonicSharedSortPreparableKernel, + BitonicSharedSortPrepKernel: BitonicSharedSortPrepKernelPtx, + BitonicSharedSortPrepKernel: BitonicSharedSortPrepKernelPtx, + BitonicSharedSortPrepKernel: BitonicSharedSortPrepKernelPtx, + BitonicSharedSortPrepKernel: BitonicSharedSortPrepKernelPtx, { default fn get_ptx_str() -> &'static str { unsafe { unreachable_cuda_simulation_linking_reporter() } @@ -299,24 +172,4 @@ where > { unsafe { unreachable_cuda_simulation_linking_reporter() } } - - default fn bitonic_shared_sort_events_prep<'stream>( - &mut self, - _stream: &'stream Stream, - _event_buffer_reporter: &mut EventBuffer, - ) -> CudaResult<()> { - unsafe { unreachable_cuda_simulation_linking_reporter() } - } - - default fn bitonic_shared_sort_events_prep_async<'stream>( - &mut self, - _stream: &'stream Stream, - _event_buffer_reporter: HostAndDeviceMutRefAsync< - DeviceAccessible< - as RustToCuda>::CudaRepresentation, - >, - >, - ) -> CudaResult<()> { - unsafe { unreachable_cuda_simulation_linking_reporter() } - } } diff --git a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml index 5be731ac0..954f5112c 100644 --- a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml @@ -16,4 +16,4 @@ necsim-core-bond = { path = "../../../../necsim/core/bond" } necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["cuda"] } necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "626cd48", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6b7c773", features = ["derive"] } diff --git a/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs b/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs index 15ffae0b9..a4fb0c699 100644 --- a/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs +++ b/rustcoalescence/algorithms/cuda/gpu-kernel/src/lib.rs @@ -38,6 +38,10 @@ use rust_cuda::{common::RustToCuda, safety::NoAliasing}; SimulationKernelArgs, SimulationKernelPtx, > for SimulationKernel )] +#[kernel( + allow(ptx::double_precision_use), + forbid(ptx::local_memory_usage, ptx::register_spills) +)] #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] pub fn simulate< @@ -141,6 +145,10 @@ pub fn simulate< // SortKernelArgs, SortKernelPtx, // > for SortKernel // )] +// #[kernel( +// allow(ptx::double_precision_use), +// forbid(ptx::local_memory_usage, ptx::register_spills) +// )] // pub fn sort_events_step( // #[kernel(pass = LendRustToCuda, jit)] // event_buffer_reporter: &mut ShallowCopy< @@ -162,6 +170,10 @@ pub fn simulate< EvenOddSortKernelArgs, EvenOddSortKernelPtx, > for EvenOddSortKernel )] +#[kernel( + allow(ptx::double_precision_use), + forbid(ptx::local_memory_usage, ptx::register_spills) +)] pub fn even_odd_sort_events_step( #[kernel(pass = LendRustToCuda, jit)] event_buffer_reporter: &mut ShallowCopy< necsim_impls_cuda::event_buffer::EventBuffer, @@ -180,6 +192,10 @@ pub fn even_odd_sort_events_step for BitonicGlobalSortStepKernel )] +#[kernel( + allow(ptx::double_precision_use), + forbid(ptx::local_memory_usage, ptx::register_spills) +)] pub fn bitonic_global_sort_events_step( #[kernel(pass = LendRustToCuda, jit)] event_buffer_reporter: &mut ShallowCopy< necsim_impls_cuda::event_buffer::EventBuffer, @@ -198,6 +214,10 @@ pub fn bitonic_global_sort_events_step for BitonicSharedSortStepKernel )] +#[kernel( + allow(ptx::double_precision_use), + forbid(ptx::local_memory_usage, ptx::register_spills) +)] pub fn bitonic_shared_sort_events_step( #[kernel(pass = LendRustToCuda, jit)] event_buffer_reporter: &mut ShallowCopy< necsim_impls_cuda::event_buffer::EventBuffer, @@ -215,6 +235,10 @@ pub fn bitonic_shared_sort_events_step for BitonicSharedSortPrepKernel )] +#[kernel( + allow(ptx::double_precision_use), + forbid(ptx::local_memory_usage, ptx::register_spills) +)] pub fn bitonic_shared_sort_events_prep( #[kernel(pass = LendRustToCuda, jit)] event_buffer_reporter: &mut ShallowCopy< necsim_impls_cuda::event_buffer::EventBuffer, diff --git a/rustcoalescence/algorithms/cuda/src/initialiser/fixup.rs b/rustcoalescence/algorithms/cuda/src/initialiser/fixup.rs index e609816bd..042645d2e 100644 --- a/rustcoalescence/algorithms/cuda/src/initialiser/fixup.rs +++ b/rustcoalescence/algorithms/cuda/src/initialiser/fixup.rs @@ -31,7 +31,7 @@ use rustcoalescence_algorithms::{ }; use rustcoalescence_scenarios::Scenario; -use rust_cuda::common::RustToCuda; +use rust_cuda::{common::RustToCuda, safety::NoAliasing}; use crate::CudaError; @@ -51,18 +51,22 @@ impl< + Samples + Samples + Samples - + RustToCuda, + + RustToCuda + + NoAliasing, O: Scenario, > CudaLineageStoreSampleInitialiser> for FixUpInitialiser where - O::Habitat: RustToCuda, - O::DispersalSampler>: RustToCuda, - O::TurnoverRate: RustToCuda, - O::SpeciationProbability: RustToCuda, + O::Habitat: RustToCuda + NoAliasing, + O::DispersalSampler>: + RustToCuda + NoAliasing, + O::TurnoverRate: RustToCuda + NoAliasing, + O::SpeciationProbability: RustToCuda + NoAliasing, { type ActiveLineageSampler< - X: EmigrationExit> + RustToCuda, - J: EventTimeSampler + RustToCuda, + X: EmigrationExit> + + RustToCuda + + NoAliasing, + J: EventTimeSampler + RustToCuda + NoAliasing, > = IndependentActiveLineageSampler< M, O::Habitat, @@ -84,8 +88,10 @@ where fn init< 'h, T: TrustedOriginSampler<'h, M, Habitat = O::Habitat>, - J: EventTimeSampler + RustToCuda, - X: EmigrationExit> + RustToCuda, + J: EventTimeSampler + RustToCuda + NoAliasing, + X: EmigrationExit> + + RustToCuda + + NoAliasing, >( self, origin_sampler: T, diff --git a/rustcoalescence/algorithms/cuda/src/initialiser/genesis.rs b/rustcoalescence/algorithms/cuda/src/initialiser/genesis.rs index d932f189d..a4fb7a05e 100644 --- a/rustcoalescence/algorithms/cuda/src/initialiser/genesis.rs +++ b/rustcoalescence/algorithms/cuda/src/initialiser/genesis.rs @@ -17,7 +17,7 @@ use necsim_impls_no_std::cogs::{ use rustcoalescence_scenarios::Scenario; -use rust_cuda::common::RustToCuda; +use rust_cuda::{common::RustToCuda, safety::NoAliasing}; use crate::CudaError; @@ -33,18 +33,22 @@ impl< + Samples + Samples + Samples - + RustToCuda, + + RustToCuda + + NoAliasing, O: Scenario, > CudaLineageStoreSampleInitialiser for GenesisInitialiser where - O::Habitat: RustToCuda, - O::DispersalSampler>: RustToCuda, - O::TurnoverRate: RustToCuda, - O::SpeciationProbability: RustToCuda, + O::Habitat: RustToCuda + NoAliasing, + O::DispersalSampler>: + RustToCuda + NoAliasing, + O::TurnoverRate: RustToCuda + NoAliasing, + O::SpeciationProbability: RustToCuda + NoAliasing, { type ActiveLineageSampler< - X: EmigrationExit> + RustToCuda, - J: EventTimeSampler + RustToCuda, + X: EmigrationExit> + + RustToCuda + + NoAliasing, + J: EventTimeSampler + RustToCuda + NoAliasing, > = IndependentActiveLineageSampler< M, O::Habitat, @@ -61,8 +65,10 @@ where fn init< 'h, T: TrustedOriginSampler<'h, M, Habitat = O::Habitat>, - J: EventTimeSampler + RustToCuda, - X: EmigrationExit> + RustToCuda, + J: EventTimeSampler + RustToCuda + NoAliasing, + X: EmigrationExit> + + RustToCuda + + NoAliasing, >( self, origin_sampler: T, diff --git a/rustcoalescence/algorithms/cuda/src/initialiser/mod.rs b/rustcoalescence/algorithms/cuda/src/initialiser/mod.rs index bd624a7b0..f2ed53833 100644 --- a/rustcoalescence/algorithms/cuda/src/initialiser/mod.rs +++ b/rustcoalescence/algorithms/cuda/src/initialiser/mod.rs @@ -20,7 +20,7 @@ use necsim_impls_no_std::cogs::{ use rustcoalescence_scenarios::Scenario; -use rust_cuda::common::RustToCuda; +use rust_cuda::{common::RustToCuda, safety::NoAliasing}; use crate::CudaError; @@ -36,38 +36,42 @@ pub trait CudaLineageStoreSampleInitialiser< + Samples + Samples + Samples - + RustToCuda, + + RustToCuda + + NoAliasing, O: Scenario, Error: From, > where - O::Habitat: RustToCuda, - O::DispersalSampler>: RustToCuda, - O::TurnoverRate: RustToCuda, - O::SpeciationProbability: RustToCuda, + O::Habitat: RustToCuda + NoAliasing, + O::DispersalSampler>: + RustToCuda + NoAliasing, + O::TurnoverRate: RustToCuda + NoAliasing, + O::SpeciationProbability: RustToCuda + NoAliasing, { - type DispersalSampler: DispersalSampler + RustToCuda; + type DispersalSampler: DispersalSampler + RustToCuda + NoAliasing; type ActiveLineageSampler< X: EmigrationExit< M, O::Habitat, G, IndependentLineageStore, - > + RustToCuda, - J: EventTimeSampler + RustToCuda, + > + RustToCuda + NoAliasing, + J: EventTimeSampler + RustToCuda + NoAliasing, >: SingularActiveLineageSampler< M, O::Habitat, G, IndependentLineageStore, X, Self::DispersalSampler, IndependentCoalescenceSampler, O::TurnoverRate, O::SpeciationProbability, IndependentEventSampler< M, O::Habitat, G, X, Self::DispersalSampler, O::TurnoverRate, O::SpeciationProbability >, NeverImmigrationEntry, - > + RustToCuda; + > + RustToCuda + NoAliasing; #[allow(clippy::type_complexity)] fn init< 'h, T: TrustedOriginSampler<'h, M, Habitat = O::Habitat>, - J: EventTimeSampler + RustToCuda, - X: EmigrationExit> + RustToCuda, + J: EventTimeSampler + RustToCuda + NoAliasing, + X: EmigrationExit> + + RustToCuda + + NoAliasing, >( self, origin_sampler: T, diff --git a/rustcoalescence/algorithms/cuda/src/initialiser/resume.rs b/rustcoalescence/algorithms/cuda/src/initialiser/resume.rs index 649e1687e..9629d4415 100644 --- a/rustcoalescence/algorithms/cuda/src/initialiser/resume.rs +++ b/rustcoalescence/algorithms/cuda/src/initialiser/resume.rs @@ -20,7 +20,7 @@ use necsim_impls_no_std::cogs::{ use rustcoalescence_algorithms::result::ResumeError; use rustcoalescence_scenarios::Scenario; -use rust_cuda::common::RustToCuda; +use rust_cuda::{common::RustToCuda, safety::NoAliasing}; use crate::CudaError; @@ -40,18 +40,22 @@ impl< + Samples + Samples + Samples - + RustToCuda, + + RustToCuda + + NoAliasing, O: Scenario, > CudaLineageStoreSampleInitialiser> for ResumeInitialiser where - O::Habitat: RustToCuda, - O::DispersalSampler>: RustToCuda, - O::TurnoverRate: RustToCuda, - O::SpeciationProbability: RustToCuda, + O::Habitat: RustToCuda + NoAliasing, + O::DispersalSampler>: + RustToCuda + NoAliasing, + O::TurnoverRate: RustToCuda + NoAliasing, + O::SpeciationProbability: RustToCuda + NoAliasing, { type ActiveLineageSampler< - X: EmigrationExit> + RustToCuda, - J: EventTimeSampler + RustToCuda, + X: EmigrationExit> + + RustToCuda + + NoAliasing, + J: EventTimeSampler + RustToCuda + NoAliasing, > = IndependentActiveLineageSampler< M, O::Habitat, @@ -68,8 +72,10 @@ where fn init< 'h, T: TrustedOriginSampler<'h, M, Habitat = O::Habitat>, - J: EventTimeSampler + RustToCuda, - X: EmigrationExit> + RustToCuda, + J: EventTimeSampler + RustToCuda + NoAliasing, + X: EmigrationExit> + + RustToCuda + + NoAliasing, >( self, origin_sampler: T, diff --git a/rustcoalescence/algorithms/cuda/src/launch.rs b/rustcoalescence/algorithms/cuda/src/launch.rs index e36b7973d..d17f11463 100644 --- a/rustcoalescence/algorithms/cuda/src/launch.rs +++ b/rustcoalescence/algorithms/cuda/src/launch.rs @@ -38,6 +38,7 @@ use rust_cuda::{ function::{BlockSize, GridSize}, prelude::{Stream, StreamFlags}, }, + safety::NoAliasing, }; use crate::{ @@ -70,12 +71,12 @@ pub fn initialise_and_simulate< lineage_store_sampler_initialiser: L, ) -> Result, Error> where - O::Habitat: RustToCuda, + O::Habitat: RustToCuda + NoAliasing, O::DispersalSampler< InMemoryPackedAliasDispersalSampler>>, - >: RustToCuda, - O::TurnoverRate: RustToCuda, - O::SpeciationProbability: RustToCuda, + >: RustToCuda + NoAliasing, + O::TurnoverRate: RustToCuda + NoAliasing, + O::SpeciationProbability: RustToCuda + NoAliasing, SimulationKernel< M, O::Habitat, diff --git a/rustcoalescence/algorithms/cuda/src/lib.rs b/rustcoalescence/algorithms/cuda/src/lib.rs index 1b25d2543..fca116b46 100644 --- a/rustcoalescence/algorithms/cuda/src/lib.rs +++ b/rustcoalescence/algorithms/cuda/src/lib.rs @@ -45,7 +45,7 @@ use rustcoalescence_scenarios::Scenario; use rustcoalescence_algorithms_cuda_cpu_kernel::SimulationKernel; use rustcoalescence_algorithms_cuda_gpu_kernel::SimulatableKernel; -use rust_cuda::common::RustToCuda; +use rust_cuda::{common::RustToCuda, safety::NoAliasing}; mod arguments; mod cuda; @@ -84,12 +84,12 @@ impl< P: LocalPartition<'p, R>, > Algorithm<'p, M, O, R, P> for CudaAlgorithm where - O::Habitat: RustToCuda, + O::Habitat: RustToCuda + NoAliasing, O::DispersalSampler< InMemoryPackedAliasDispersalSampler>>, - >: RustToCuda, - O::TurnoverRate: RustToCuda, - O::SpeciationProbability: RustToCuda, + >: RustToCuda + NoAliasing, + O::TurnoverRate: RustToCuda + NoAliasing, + O::SpeciationProbability: RustToCuda + NoAliasing, SimulationKernel< M, O::Habitat, diff --git a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs index e1f8dffae..e21a7fe02 100644 --- a/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs +++ b/rustcoalescence/algorithms/cuda/src/parallelisation/monolithic.rs @@ -13,6 +13,7 @@ use rust_cuda::{ function::{BlockSize, GridSize}, stream::Stream, }, + safety::NoAliasing, utils::exchange::wrapper::ExchangeWrapperOnHost, }; @@ -72,18 +73,18 @@ pub fn simulate< 'p, 'stream, M: MathsCore, - H: Habitat + RustToCuda, - G: Rng + RustToCuda, - S: LineageStore + RustToCuda, - X: EmigrationExit + RustToCuda, - D: DispersalSampler + RustToCuda, - C: CoalescenceSampler + RustToCuda, - T: TurnoverRate + RustToCuda, - N: SpeciationProbability + RustToCuda, - E: MinSpeciationTrackingEventSampler + RustToCuda, - I: ImmigrationEntry + RustToCuda, + H: Habitat + RustToCuda + NoAliasing, + G: Rng + RustToCuda + NoAliasing, + S: LineageStore + RustToCuda + NoAliasing, + X: EmigrationExit + RustToCuda + NoAliasing, + D: DispersalSampler + RustToCuda + NoAliasing, + C: CoalescenceSampler + RustToCuda + NoAliasing, + T: TurnoverRate + RustToCuda + NoAliasing, + N: SpeciationProbability + RustToCuda + NoAliasing, + E: MinSpeciationTrackingEventSampler + RustToCuda + NoAliasing, + I: ImmigrationEntry + RustToCuda + NoAliasing, A: SingularActiveLineageSampler - + RustToCuda, + + RustToCuda + NoAliasing, P: Reporter, L: LocalPartition<'p, P>, LI: IntoIterator, From d97cf4fbf953c0a23391b0e8659524c970b66275 Mon Sep 17 00:00:00 2001 From: Juniper Tyree Date: Tue, 9 May 2023 13:11:41 +0000 Subject: [PATCH 40/42] Fix inlining for event comparison on CUDA --- necsim/core/src/event.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/necsim/core/src/event.rs b/necsim/core/src/event.rs index e484fc158..c4f14fab4 100644 --- a/necsim/core/src/event.rs +++ b/necsim/core/src/event.rs @@ -309,6 +309,7 @@ impl PartialEq for SpeciationEvent { } impl Ord for SpeciationEvent { + #[cfg_attr(target_os = "cuda", inline)] fn cmp(&self, other: &Self) -> Ordering { // Order `Event`s in lexicographical order: // (1) event_time different events @@ -385,6 +386,7 @@ mod tests { } impl Ord for DispersalEvent { + #[cfg_attr(target_os = "cuda", inline)] fn cmp(&self, other: &Self) -> Ordering { // Order `Event`s in lexicographical order: // (1) event_time /=\ From b3de59e496dd63bcd3005032a94f8975972f979d Mon Sep 17 00:00:00 2001 From: Juniper Tyree Date: Tue, 9 May 2023 13:16:43 +0000 Subject: [PATCH 41/42] Install CUDA in more CI runs --- .github/workflows/ci.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4cbb070b0..f0ff7643b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,16 @@ jobs: - name: Checkout the Repository uses: actions/checkout@v2 + - name: Install CUDA + run: | + wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-ubuntu1804.pin + sudo mv cuda-ubuntu1804.pin /etc/apt/preferences.d/cuda-repository-pin-600 + curl -L -O https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-keyring_1.0-1_all.deb + sudo dpkg -i cuda-keyring_1.0-1_all.deb + sudo add-apt-repository "deb https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/ /" + sudo apt-get update -q + sudo apt-get install cuda -y --no-install-recommends + - name: Install OpenMPI run: | sudo apt-get update -q @@ -79,6 +89,16 @@ jobs: steps: - name: Checkout the Repository uses: actions/checkout@v2 + + - name: Install CUDA + run: | + wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-ubuntu1804.pin + sudo mv cuda-ubuntu1804.pin /etc/apt/preferences.d/cuda-repository-pin-600 + curl -L -O https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-keyring_1.0-1_all.deb + sudo dpkg -i cuda-keyring_1.0-1_all.deb + sudo add-apt-repository "deb https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/ /" + sudo apt-get update -q + sudo apt-get install cuda -y --no-install-recommends - name: Install OpenMPI run: | From 5a758dba0e7e4158bdb621a91cbfe977b98a09b2 Mon Sep 17 00:00:00 2001 From: Juniper Tyree Date: Sat, 13 May 2023 17:31:04 +0000 Subject: [PATCH 42/42] Update to latest const-type-layout and rust-cuda --- Cargo.lock | 10 +++++----- necsim/core/Cargo.toml | 6 +++--- necsim/core/bond/Cargo.toml | 2 +- necsim/impls/cuda/Cargo.toml | 6 +++--- necsim/impls/no-std/Cargo.toml | 6 +++--- .../opensimplex_noise/open_simplex_noise_2d.rs | 1 + rustcoalescence/algorithms/cuda/Cargo.toml | 2 +- rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml | 2 +- rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml | 2 +- 9 files changed, 19 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 418b89491..35db041e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -409,7 +409,7 @@ dependencies = [ [[package]] name = "const-type-layout" version = "0.1.0" -source = "git+https://github.com/juntyr/const-type-layout?rev=e163b36#e163b364827a8402a6f55a9ac64414c849051ffd" +source = "git+https://github.com/juntyr/const-type-layout?rev=645de0e#645de0e2116cfb9fa263e10b1e3c8500451f5d0a" dependencies = [ "const-type-layout-derive", ] @@ -417,7 +417,7 @@ dependencies = [ [[package]] name = "const-type-layout-derive" version = "0.1.0" -source = "git+https://github.com/juntyr/const-type-layout?rev=e163b36#e163b364827a8402a6f55a9ac64414c849051ffd" +source = "git+https://github.com/juntyr/const-type-layout?rev=645de0e#645de0e2116cfb9fa263e10b1e3c8500451f5d0a" dependencies = [ "proc-macro-error", "proc-macro2", @@ -1477,7 +1477,7 @@ dependencies = [ [[package]] name = "rust-cuda" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=6b7c773#6b7c77372db56a078c842236acad62c249c7878c" +source = "git+https://github.com/juntyr/rust-cuda?rev=575bc27#575bc270881eb6fa91fc9be96d2096f35a12578a" dependencies = [ "const-type-layout", "final", @@ -1491,7 +1491,7 @@ dependencies = [ [[package]] name = "rust-cuda-derive" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=6b7c773#6b7c77372db56a078c842236acad62c249c7878c" +source = "git+https://github.com/juntyr/rust-cuda?rev=575bc27#575bc270881eb6fa91fc9be96d2096f35a12578a" dependencies = [ "cargo_metadata", "colored", @@ -1512,7 +1512,7 @@ dependencies = [ [[package]] name = "rust-cuda-ptx-jit" version = "0.1.0" -source = "git+https://github.com/juntyr/rust-cuda?rev=6b7c773#6b7c77372db56a078c842236acad62c249c7878c" +source = "git+https://github.com/juntyr/rust-cuda?rev=575bc27#575bc270881eb6fa91fc9be96d2096f35a12578a" dependencies = [ "lazy_static", "regex", diff --git a/necsim/core/Cargo.toml b/necsim/core/Cargo.toml index ce5574422..d4ee8f5b5 100644 --- a/necsim/core/Cargo.toml +++ b/necsim/core/Cargo.toml @@ -15,12 +15,12 @@ cuda = ["rust-cuda"] necsim-core-maths = { path = "maths" } necsim-core-bond = { path = "bond" } -const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "e163b36" } +const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "645de0e" } contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6b7c773", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "575bc27", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6b7c773", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "575bc27", features = ["derive", "host"], optional = true } diff --git a/necsim/core/bond/Cargo.toml b/necsim/core/bond/Cargo.toml index f21fe2937..748663395 100644 --- a/necsim/core/bond/Cargo.toml +++ b/necsim/core/bond/Cargo.toml @@ -13,5 +13,5 @@ default = [] [dependencies] necsim-core-maths = { path = "../maths" } -const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "e163b36" } +const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "645de0e" } serde = { version = "1.0", default-features = false, features = ["derive"] } diff --git a/necsim/impls/cuda/Cargo.toml b/necsim/impls/cuda/Cargo.toml index 85ac45730..d414a036e 100644 --- a/necsim/impls/cuda/Cargo.toml +++ b/necsim/impls/cuda/Cargo.toml @@ -10,12 +10,12 @@ edition = "2021" [dependencies] necsim-core = { path = "../../core", features = ["cuda"] } -const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "e163b36" } +const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "645de0e" } contracts = "0.6.3" serde = { version = "1.0", default-features = false, features = ["derive"] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6b7c773", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "575bc27", features = ["derive"] } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6b7c773", features = ["derive", "host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "575bc27", features = ["derive", "host"] } diff --git a/necsim/impls/no-std/Cargo.toml b/necsim/impls/no-std/Cargo.toml index a7d980052..96a6213ba 100644 --- a/necsim/impls/no-std/Cargo.toml +++ b/necsim/impls/no-std/Cargo.toml @@ -17,7 +17,7 @@ necsim-core-maths = { path = "../../core/maths" } necsim-core-bond = { path = "../../core/bond" } necsim-partitioning-core = { path = "../../partitioning/core" } -const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "e163b36" } +const-type-layout = { git = "https://github.com/juntyr/const-type-layout", rev = "645de0e" } contracts = "0.6.3" libm = "0.2" hashbrown = "0.13" @@ -31,7 +31,7 @@ rand_core = "0.6" rand_distr = { version = "0.4", default-features = false, features = [] } [target.'cfg(target_os = "cuda")'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6b7c773", features = ["derive"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "575bc27", features = ["derive"], optional = true } [target.'cfg(not(target_os = "cuda"))'.dependencies] -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6b7c773", features = ["derive", "host"], optional = true } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "575bc27", features = ["derive", "host"], optional = true } diff --git a/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/opensimplex_noise/open_simplex_noise_2d.rs b/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/opensimplex_noise/open_simplex_noise_2d.rs index b2b0b9363..69aaaf5c9 100644 --- a/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/opensimplex_noise/open_simplex_noise_2d.rs +++ b/necsim/impls/no-std/src/cogs/habitat/wrapping_noise/opensimplex_noise/open_simplex_noise_2d.rs @@ -55,6 +55,7 @@ impl NoiseEvaluator> for OpenSimplexNoise2D { point.x * delta.x + point.y * delta.y } + #[cfg_attr(target_os = "cuda", inline)] fn eval(input: Vec2, perm: &PermTable, wrap: f64) -> f64 { // Pre-squish the input to allow wrapping in extrapolate let input = input + (Self::SQUISH_POINT * input.sum()); diff --git a/rustcoalescence/algorithms/cuda/Cargo.toml b/rustcoalescence/algorithms/cuda/Cargo.toml index 967d66238..ef08b2f9e 100644 --- a/rustcoalescence/algorithms/cuda/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/Cargo.toml @@ -23,4 +23,4 @@ thiserror = "1.0" serde = { version = "1.0", features = ["derive"] } serde_state = "0.4" serde_derive_state = "0.4" -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6b7c773", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "575bc27", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml index 542fb3f2e..e7a5ad0f9 100644 --- a/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/cpu-kernel/Cargo.toml @@ -14,4 +14,4 @@ necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["c necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } rustcoalescence-algorithms-cuda-gpu-kernel = { path = "../gpu-kernel" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6b7c773", features = ["host"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "575bc27", features = ["host"] } diff --git a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml index 954f5112c..81a8eab05 100644 --- a/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml +++ b/rustcoalescence/algorithms/cuda/gpu-kernel/Cargo.toml @@ -16,4 +16,4 @@ necsim-core-bond = { path = "../../../../necsim/core/bond" } necsim-impls-no-std = { path = "../../../../necsim/impls/no-std", features = ["cuda"] } necsim-impls-cuda = { path = "../../../../necsim/impls/cuda" } -rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "6b7c773", features = ["derive"] } +rust-cuda = { git = "https://github.com/juntyr/rust-cuda", rev = "575bc27", features = ["derive"] }