diff --git a/README.md b/README.md index db03861a9..51daae95a 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ necsim-rust consists of the following crates: - core/: `necsim-partitioning-core` declares the core partitioning traits - monolithic/: `necsim-partitioning-monolithic` implements monolithic, i.e. non-parallel partitioning - mpi/: `necsim-partitioning-mpi` implements the MPI-based partitioning backend - - threads/: `necsim-partitioning-threads` implements the multithreading partitioning backend + - threads/: `necsim-partitioning-threads` implements the multithreading-based partitioning backend - rustcoalescence/: `rustcoalescence` provides the command-line interface. - scenarios/: `rustcoalescence-scenarios` contains the glue code to put together the cogs for the built-in scenarios. It is specifically built only for reducing code duplication in rustcoalescence, not for giving a minimal example of how to construct a simulation. - algorithms/: diff --git a/docs/simulate.ron b/docs/simulate.ron index e3f19cfe5..a8cbf5e79 100644 --- a/docs/simulate.ron +++ b/docs/simulate.ron @@ -676,7 +676,8 @@ * optional, default = "100ms" */ progress: (DurationString), ) - /* the simulation is divided up across multiple threads + /* the simulation is divided up across multiple threads, which + communicate using message passing and may share immutable data * multi-threaded, single-process * requires the `threads-partitioning` feature */ | Threads( diff --git a/necsim/core/src/landscape/location.rs b/necsim/core/src/landscape/location.rs index 6bcc520a6..7d8b2cf26 100644 --- a/necsim/core/src/landscape/location.rs +++ b/necsim/core/src/landscape/location.rs @@ -1,7 +1,5 @@ use serde::{Deserialize, Serialize}; -use crate::cogs::Backup; - #[allow(clippy::module_name_repetitions)] #[derive( Eq, PartialEq, PartialOrd, Ord, Clone, Hash, Debug, Serialize, Deserialize, TypeLayout, @@ -15,13 +13,6 @@ pub struct Location { y: u32, } -#[contract_trait] -impl Backup for Location { - unsafe fn backup_unchecked(&self) -> Self { - self.clone() - } -} - impl Location { #[must_use] pub const fn new(x: u32, y: u32) -> Self { diff --git a/necsim/core/src/lineage.rs b/necsim/core/src/lineage.rs index 398973fd0..57e85b9c3 100644 --- a/necsim/core/src/lineage.rs +++ b/necsim/core/src/lineage.rs @@ -54,13 +54,6 @@ impl<'de> Deserialize<'de> for GlobalLineageReference { } } -#[contract_trait] -impl Backup for GlobalLineageReference { - unsafe fn backup_unchecked(&self) -> Self { - GlobalLineageReference(self.0) - } -} - impl> LineageReference for GlobalLineageReference {} #[allow(clippy::module_name_repetitions)] diff --git a/necsim/impls/no-std/src/alias/packed.rs b/necsim/impls/no-std/src/alias/packed.rs index 9f0e20259..7548d7529 100644 --- a/necsim/impls/no-std/src/alias/packed.rs +++ b/necsim/impls/no-std/src/alias/packed.rs @@ -119,22 +119,29 @@ impl AliasMethodSamplerAtom { } } + pub fn sample_event>( + alias_samplers: &[AliasMethodSamplerAtom], + rng: &mut G, + ) -> E { + Self::sample_event_with_cdf_limit(alias_samplers, rng, ClosedUnitF64::one()) + } + #[allow(clippy::no_effect_underscore_binding)] #[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), "returns one of the weighted events" )] - pub fn sample_event>( + pub fn sample_event_with_cdf_limit>( alias_samplers: &[AliasMethodSamplerAtom], rng: &mut G, - factor: ClosedUnitF64, + limit: ClosedUnitF64, ) -> E { use necsim_core::cogs::RngSampler; #[allow(clippy::cast_precision_loss)] let f = - rng.sample_uniform_closed_open().get() * factor.get() * (alias_samplers.len() as f64); + rng.sample_uniform_closed_open().get() * limit.get() * (alias_samplers.len() as f64); #[allow( clippy::cast_precision_loss, diff --git a/necsim/impls/no-std/src/array2d.rs b/necsim/impls/no-std/src/array2d.rs index 48a820fb0..f55364d98 100644 --- a/necsim/impls/no-std/src/array2d.rs +++ b/necsim/impls/no-std/src/array2d.rs @@ -464,7 +464,7 @@ impl> Array2D { /// # fn main() -> Result<(), Error> { /// let rows = vec![vec![1, 2, 3], vec![4, 5, 6]]; /// let array = VecArray2D::from_rows(&rows)?; - /// assert_eq!(array.into_row_major_inner(), vec![1, 2, 3, 4, 5, 6]); + /// assert_eq!(array.into_row_major_backend(), vec![1, 2, 3, 4, 5, 6]); /// # Ok(()) /// # } /// ``` @@ -472,7 +472,7 @@ impl> Array2D { /// [`Array2D`]: struct.Array2D.html /// [row major order]: https://en.wikipedia.org/wiki/Row-_and_column-major_order #[must_use] - pub fn into_row_major_inner(self) -> B { + pub fn into_row_major_backend(self) -> B { self.array } 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 04d554d8e..da31ab406 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/tests.rs b/necsim/impls/no-std/src/cogs/active_lineage_sampler/alias/sampler/stack/tests.rs index 505bf295c..9bc1b6017 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 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 f15e3f672..3c417d07f 100644 --- a/necsim/impls/no-std/src/cogs/coalescence_sampler/independent.rs +++ b/necsim/impls/no-std/src/cogs/coalescence_sampler/independent.rs @@ -1,9 +1,7 @@ use core::marker::PhantomData; use necsim_core::{ - cogs::{ - coalescence_sampler::CoalescenceRngSample, Backup, CoalescenceSampler, Habitat, MathsCore, - }, + cogs::{coalescence_sampler::CoalescenceRngSample, CoalescenceSampler, Habitat, MathsCore}, landscape::{IndexedLocation, Location}, lineage::LineageInteraction, }; @@ -25,9 +23,8 @@ impl> Default for IndependentCoalescenceSampler> Backup for IndependentCoalescenceSampler { - unsafe fn backup_unchecked(&self) -> Self { +impl> Clone for IndependentCoalescenceSampler { + fn clone(&self) -> Self { Self(PhantomData::<(M, H)>) } } diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_clark2dt.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_clark2dt.rs index 10b553abd..7858b7a1a 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_clark2dt.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/almost_infinite_clark2dt.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; use necsim_core::{ - cogs::{Backup, DispersalSampler, MathsCore, RngCore, RngSampler, SeparableDispersalSampler}, + cogs::{DispersalSampler, MathsCore, RngCore, RngSampler, SeparableDispersalSampler}, landscape::Location, }; use necsim_core_bond::{ClosedUnitF64, NonNegativeF64, PositiveF64}; @@ -9,7 +9,7 @@ use necsim_core_bond::{ClosedUnitF64, NonNegativeF64, PositiveF64}; use crate::cogs::habitat::almost_infinite::AlmostInfiniteHabitat; #[allow(clippy::module_name_repetitions)] -#[derive(Clone, Debug)] +#[derive(Debug)] #[cfg_attr(feature = "cuda", derive(rust_cuda::lend::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M", free = "G"))] pub struct AlmostInfiniteClark2DtDispersalSampler> { @@ -68,9 +68,8 @@ impl> AlmostInfiniteClark2DtDispersalSampler { } } -#[contract_trait] -impl> Backup for AlmostInfiniteClark2DtDispersalSampler { - unsafe fn backup_unchecked(&self) -> Self { +impl> Clone for AlmostInfiniteClark2DtDispersalSampler { + fn clone(&self) -> Self { Self { shape_u: self.shape_u, tail_p: self.tail_p, 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 41ba5f478..ecd9fb2d0 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::{DispersalSampler, MathsCore, RngCore, SeparableDispersalSampler}, landscape::Location, }; use necsim_core_bond::{ClosedUnitF64, NonNegativeF64}; @@ -9,7 +9,7 @@ use necsim_core_bond::{ClosedUnitF64, NonNegativeF64}; use crate::cogs::habitat::almost_infinite::AlmostInfiniteHabitat; #[allow(clippy::module_name_repetitions)] -#[derive(Clone, Debug)] +#[derive(Debug)] #[cfg_attr(feature = "cuda", derive(rust_cuda::lend::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M", free = "G"))] pub struct AlmostInfiniteNormalDispersalSampler> { @@ -39,9 +39,8 @@ impl> AlmostInfiniteNormalDispersalSampler { } } -#[contract_trait] -impl> Backup for AlmostInfiniteNormalDispersalSampler { - unsafe fn backup_unchecked(&self) -> Self { +impl> Clone for AlmostInfiniteNormalDispersalSampler { + fn clone(&self) -> Self { Self { sigma: self.sigma, self_dispersal: self.self_dispersal, 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 b90e95bba..f8c3e0697 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 @@ -4,7 +4,6 @@ use necsim_core::{ cogs::{DispersalSampler, Habitat, MathsCore, RngCore}, landscape::Location, }; -use necsim_core_bond::ClosedUnitF64; use crate::alias::packed::AliasMethodSamplerAtom; @@ -38,11 +37,8 @@ impl, G: RngCore> DispersalSampler let alias_dispersals_at_location = unsafe { &self.alias_dispersal_buffer.get_unchecked(alias_range) }; - let dispersal_target_index: usize = AliasMethodSamplerAtom::sample_event( - alias_dispersals_at_location, - rng, - ClosedUnitF64::one(), - ); + let dispersal_target_index: usize = + AliasMethodSamplerAtom::sample_event(alias_dispersals_at_location, rng); #[allow(clippy::cast_possible_truncation)] Location::new( diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_separable_alias/dispersal.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_separable_alias/dispersal.rs index ae848585d..09b9de4e8 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_separable_alias/dispersal.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_separable_alias/dispersal.rs @@ -29,18 +29,15 @@ impl, G: RngCore> DispersalSampler .unwrap_unchecked() }; - // Safe by the construction of `InMemoryPackedAliasDispersalSampler` + // Safe by the construction of `InMemoryPackedSeparableAliasDispersalSampler` let alias_dispersals_at_location = unsafe { &self .alias_dispersal_buffer .get_unchecked(alias_range.start..alias_range.end) }; - let dispersal_target_index: usize = AliasMethodSamplerAtom::sample_event( - alias_dispersals_at_location, - rng, - ClosedUnitF64::one(), - ); + let dispersal_target_index: usize = + AliasMethodSamplerAtom::sample_event(alias_dispersals_at_location, rng); #[allow(clippy::cast_possible_truncation)] Location::new( @@ -82,7 +79,7 @@ impl, G: RngCore> SeparableDispersalSampler, G: RngCore> SeparableDispersalSampler, G: RngCore> SeparableDispersalSampler ClosedUnitF64 { - self.self_dispersal[( - location.y().wrapping_sub(habitat.get_extent().origin().y()) as usize, - location.x().wrapping_sub(habitat.get_extent().origin().x()) as usize, - )] - .self_dispersal + // Only safe as trait precondition that `location` is inside `habitat` + unsafe { + self.self_dispersal + .get( + location.y().wrapping_sub(habitat.get_extent().origin().y()) as usize, + location.x().wrapping_sub(habitat.get_extent().origin().x()) as usize, + ) + .unwrap_unchecked() + } + .self_dispersal } } diff --git a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_separable_alias/mod.rs b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_separable_alias/mod.rs index a9dcb071f..47f9b5d9c 100644 --- a/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_separable_alias/mod.rs +++ b/necsim/impls/no-std/src/cogs/dispersal_sampler/in_memory/packed_separable_alias/mod.rs @@ -120,11 +120,11 @@ impl, G: RngCore> InMemoryDispersalSampler() - + self_dispersal_at_location; + .sum::(); // Safety: Normalisation limits the result to [0.0; 1.0] let self_dispersal_probability = unsafe { ClosedUnitF64::new_unchecked( 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 e0493dd5b..a2228149a 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 @@ -78,6 +78,8 @@ impl, G: RngCore> InMemoryDispersalSampler> { @@ -25,9 +25,8 @@ impl> Default for NonSpatialDispersalSampler { } } -#[contract_trait] -impl> Backup for NonSpatialDispersalSampler { - unsafe fn backup_unchecked(&self) -> Self { +impl> Clone for NonSpatialDispersalSampler { + fn clone(&self) -> Self { Self { marker: PhantomData::<(M, G)>, } 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 6aec8c14b..b2024f427 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::{DispersalSampler, Habitat, MathsCore, RngCore, SeparableDispersalSampler}, landscape::Location, }; use necsim_core_bond::{ClosedUnitF64, OpenClosedUnitF64 as PositiveUnitF64}; @@ -10,7 +10,7 @@ use crate::cogs::{ }; #[allow(clippy::module_name_repetitions)] -#[derive(Clone, Debug)] +#[derive(Debug)] #[cfg_attr(feature = "cuda", derive(rust_cuda::lend::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M"))] pub struct SpatiallyImplicitDispersalSampler> { @@ -32,12 +32,11 @@ impl> SpatiallyImplicitDispersalSampler { } } -#[contract_trait] -impl> Backup for SpatiallyImplicitDispersalSampler { - unsafe fn backup_unchecked(&self) -> Self { +impl> Clone for SpatiallyImplicitDispersalSampler { + fn clone(&self) -> Self { Self { - local: self.local.backup_unchecked(), - meta: self.meta.backup_unchecked(), + local: self.local.clone(), + meta: self.meta.clone(), local_migration_probability_per_generation: self .local_migration_probability_per_generation, } 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 85aef9d41..54f83c872 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,5 @@ use necsim_core::{ - cogs::{ - Backup, DispersalSampler, Habitat, MathsCore, RngCore, RngSampler, - SeparableDispersalSampler, - }, + cogs::{DispersalSampler, Habitat, MathsCore, RngCore, RngSampler, SeparableDispersalSampler}, landscape::Location, }; use necsim_core_bond::{ClosedUnitF64, NonNegativeF64}; @@ -13,7 +10,7 @@ use crate::cogs::{ }; #[allow(clippy::module_name_repetitions)] -#[derive(Clone, Debug)] +#[derive(Debug)] #[cfg_attr(feature = "cuda", derive(rust_cuda::lend::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M"))] pub struct WrappingNoiseApproximateNormalDispersalSampler> { @@ -30,11 +27,10 @@ impl> WrappingNoiseApproximateNormalDispersalSampler } } -#[contract_trait] -impl> Backup for WrappingNoiseApproximateNormalDispersalSampler { - unsafe fn backup_unchecked(&self) -> Self { +impl> Clone for WrappingNoiseApproximateNormalDispersalSampler { + fn clone(&self) -> Self { Self { - inner: self.inner.backup_unchecked(), + inner: self.inner.clone(), } } } 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 abd31221e..f3d97311b 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::{Habitat, MathsCore, RngCore, UniformlySampleableHabitat}, landscape::{IndexedLocation, LandscapeExtent, Location}, }; use necsim_core_bond::{OffByOneU32, OffByOneU64}; @@ -12,7 +12,6 @@ const ALMOST_INFINITE_EXTENT: LandscapeExtent = LandscapeExtent::new(Location::new(0, 0), OffByOneU32::max(), OffByOneU32::max()); #[allow(clippy::module_name_repetitions)] -#[derive(Clone)] #[cfg_attr(feature = "cuda", derive(rust_cuda::lend::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M"))] pub struct AlmostInfiniteHabitat { @@ -33,9 +32,8 @@ impl Default for AlmostInfiniteHabitat { } } -#[contract_trait] -impl Backup for AlmostInfiniteHabitat { - unsafe fn backup_unchecked(&self) -> Self { +impl Clone for AlmostInfiniteHabitat { + fn clone(&self) -> Self { Self { marker: PhantomData::, } 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 031a4ff08..a5464654a 100644 --- a/necsim/impls/no-std/src/cogs/habitat/in_memory.rs +++ b/necsim/impls/no-std/src/cogs/habitat/in_memory.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use alloc::{sync::Arc, vec::Vec}; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, RngCore, UniformlySampleableHabitat}, + cogs::{Habitat, MathsCore, RngCore, UniformlySampleableHabitat}, landscape::{IndexedLocation, LandscapeExtent, Location}, }; use necsim_core_bond::{OffByOneU32, OffByOneU64}; @@ -11,7 +11,7 @@ use necsim_core_bond::{OffByOneU32, OffByOneU64}; use crate::array2d::Array2D; #[allow(clippy::module_name_repetitions)] -#[derive(Clone, Debug)] +#[derive(Debug)] #[cfg_attr(feature = "cuda", derive(rust_cuda::lend::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M"))] pub struct InMemoryHabitat { @@ -24,9 +24,8 @@ pub struct InMemoryHabitat { marker: PhantomData, } -#[contract_trait] -impl Backup for InMemoryHabitat { - unsafe fn backup_unchecked(&self) -> Self { +impl Clone for InMemoryHabitat { + fn clone(&self) -> Self { Self { habitat: self.habitat.clone(), u64_injection: self.u64_injection.clone(), 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 720e064a8..f210cba81 100644 --- a/necsim/impls/no-std/src/cogs/habitat/non_spatial.rs +++ b/necsim/impls/no-std/src/cogs/habitat/non_spatial.rs @@ -4,13 +4,13 @@ use core::{ }; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, RngCore, UniformlySampleableHabitat}, + cogs::{Habitat, MathsCore, RngCore, UniformlySampleableHabitat}, landscape::{IndexedLocation, LandscapeExtent, Location}, }; use necsim_core_bond::{OffByOneU32, OffByOneU64}; #[allow(clippy::module_name_repetitions)] -#[derive(Clone, Debug)] +#[derive(Debug)] #[cfg_attr(feature = "cuda", derive(rust_cuda::lend::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M"))] pub struct NonSpatialHabitat { @@ -54,9 +54,8 @@ impl NonSpatialHabitat { } } -#[contract_trait] -impl Backup for NonSpatialHabitat { - unsafe fn backup_unchecked(&self) -> Self { +impl Clone for NonSpatialHabitat { + fn clone(&self) -> Self { Self { extent: self.extent.clone(), deme: self.deme, 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 eed0596b1..390176c2d 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::{Habitat, MathsCore, RngCore, UniformlySampleableHabitat}, landscape::{IndexedLocation, LandscapeExtent, Location}, }; use necsim_core_bond::{OffByOneU32, OffByOneU64}; @@ -12,7 +12,7 @@ const SPATIALLY_IMPLICIT_EXTENT: LandscapeExtent = LandscapeExtent::new(Location::new(0, 0), OffByOneU32::max(), OffByOneU32::max()); #[allow(clippy::module_name_repetitions)] -#[derive(Clone, Debug)] +#[derive(Debug)] #[cfg_attr(feature = "cuda", derive(rust_cuda::lend::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M"))] pub struct SpatiallyImplicitHabitat { @@ -62,12 +62,11 @@ impl SpatiallyImplicitHabitat { } } -#[contract_trait] -impl Backup for SpatiallyImplicitHabitat { - unsafe fn backup_unchecked(&self) -> Self { +impl Clone for SpatiallyImplicitHabitat { + fn clone(&self) -> Self { Self { - local: self.local.backup_unchecked(), - meta: self.meta.backup_unchecked(), + local: self.local.clone(), + meta: self.meta.clone(), } } } 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 47a74c080..5e4f1bd3f 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 @@ -7,7 +7,7 @@ mod opensimplex_noise; use opensimplex_noise::OpenSimplexNoise; use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, RngCore, UniformlySampleableHabitat}, + cogs::{Habitat, MathsCore, RngCore, UniformlySampleableHabitat}, landscape::{IndexedLocation, LandscapeExtent, Location}, }; @@ -17,7 +17,6 @@ use crate::cogs::{ }; #[allow(clippy::module_name_repetitions)] -#[derive(Clone)] #[cfg_attr(feature = "cuda", derive(rust_cuda::lend::LendRustToCuda))] #[cfg_attr(feature = "cuda", cuda(free = "M"))] pub struct WrappingNoiseHabitat { @@ -118,11 +117,10 @@ impl Default for WrappingNoiseHabitat { } } -#[contract_trait] -impl Backup for WrappingNoiseHabitat { - unsafe fn backup_unchecked(&self) -> Self { +impl Clone for WrappingNoiseHabitat { + fn clone(&self) -> Self { Self { - inner: self.inner.backup_unchecked(), + inner: self.inner.clone(), coverage: self.coverage, threshold: self.threshold, scale: self.scale, diff --git a/necsim/impls/no-std/src/cogs/rng/seahash.rs b/necsim/impls/no-std/src/cogs/rng/seahash.rs index bbfc0df7b..d13be722f 100644 --- a/necsim/impls/no-std/src/cogs/rng/seahash.rs +++ b/necsim/impls/no-std/src/cogs/rng/seahash.rs @@ -1,11 +1,11 @@ use core::marker::PhantomData; -use necsim_core::cogs::{Backup, MathsCore, PrimeableRng, RngCore}; +use necsim_core::cogs::{MathsCore, PrimeableRng, RngCore}; use serde::{Deserialize, Serialize}; #[allow(clippy::module_name_repetitions)] -#[derive(Clone, Debug, Serialize, Deserialize, TypeLayout)] +#[derive(Debug, Serialize, Deserialize, TypeLayout)] #[serde(deny_unknown_fields)] #[layout(free = "M")] pub struct SeaHash { @@ -17,10 +17,15 @@ pub struct SeaHash { marker: PhantomData, } -#[contract_trait] -impl Backup for SeaHash { - unsafe fn backup_unchecked(&self) -> Self { - self.clone() +impl Clone for SeaHash { + fn clone(&self) -> Self { + Self { + seed: self.seed, + location: self.location, + time: self.time, + offset: self.offset, + marker: PhantomData::, + } } } diff --git a/necsim/impls/no-std/src/cogs/rng/wyhash.rs b/necsim/impls/no-std/src/cogs/rng/wyhash.rs index dfa2d4d3e..2697546d5 100644 --- a/necsim/impls/no-std/src/cogs/rng/wyhash.rs +++ b/necsim/impls/no-std/src/cogs/rng/wyhash.rs @@ -1,6 +1,6 @@ use core::marker::PhantomData; -use necsim_core::cogs::{Backup, MathsCore, PrimeableRng, RngCore}; +use necsim_core::cogs::{MathsCore, PrimeableRng, RngCore}; use serde::{Deserialize, Serialize}; @@ -12,7 +12,7 @@ const P2: u64 = 0x8ebc_6af0_9c88_c6e3; const P5: u64 = 0xeb44_acca_b455_d165; #[allow(clippy::module_name_repetitions)] -#[derive(Clone, Debug, Serialize, Deserialize, TypeLayout)] +#[derive(Debug, Serialize, Deserialize, TypeLayout)] #[layout(free = "M")] #[serde(deny_unknown_fields)] #[repr(C)] @@ -23,10 +23,13 @@ pub struct WyHash { marker: PhantomData, } -#[contract_trait] -impl Backup for WyHash { - unsafe fn backup_unchecked(&self) -> Self { - self.clone() +impl Clone for WyHash { + fn clone(&self) -> Self { + Self { + seed: self.seed, + state: self.state, + marker: PhantomData::, + } } } diff --git a/necsim/impls/no-std/src/cogs/speciation_probability/spatially_implicit.rs b/necsim/impls/no-std/src/cogs/speciation_probability/spatially_implicit.rs index 90c064bb7..2321250b9 100644 --- a/necsim/impls/no-std/src/cogs/speciation_probability/spatially_implicit.rs +++ b/necsim/impls/no-std/src/cogs/speciation_probability/spatially_implicit.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, SpeciationProbability}, + cogs::{Habitat, MathsCore, SpeciationProbability}, landscape::Location, }; use necsim_core_bond::{ClosedUnitF64, OpenClosedUnitF64 as PositiveUnitF64}; @@ -22,15 +22,6 @@ impl SpatiallyImplicitSpeciationProbability { } } -#[contract_trait] -impl Backup for SpatiallyImplicitSpeciationProbability { - unsafe fn backup_unchecked(&self) -> Self { - Self { - meta_speciation_probability: self.meta_speciation_probability, - } - } -} - #[contract_trait] impl SpeciationProbability> for SpatiallyImplicitSpeciationProbability diff --git a/necsim/impls/no-std/src/cogs/speciation_probability/uniform.rs b/necsim/impls/no-std/src/cogs/speciation_probability/uniform.rs index 6e071ce3f..9c119db94 100644 --- a/necsim/impls/no-std/src/cogs/speciation_probability/uniform.rs +++ b/necsim/impls/no-std/src/cogs/speciation_probability/uniform.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, SpeciationProbability}, + cogs::{Habitat, MathsCore, SpeciationProbability}, landscape::Location, }; use necsim_core_bond::ClosedUnitF64; @@ -20,15 +20,6 @@ impl UniformSpeciationProbability { } } -#[contract_trait] -impl Backup for UniformSpeciationProbability { - unsafe fn backup_unchecked(&self) -> Self { - Self { - speciation_probability: self.speciation_probability, - } - } -} - #[contract_trait] impl> SpeciationProbability for UniformSpeciationProbability { #[must_use] diff --git a/necsim/impls/no-std/src/cogs/turnover_rate/uniform.rs b/necsim/impls/no-std/src/cogs/turnover_rate/uniform.rs index 671111023..c2465befc 100644 --- a/necsim/impls/no-std/src/cogs/turnover_rate/uniform.rs +++ b/necsim/impls/no-std/src/cogs/turnover_rate/uniform.rs @@ -1,5 +1,5 @@ use necsim_core::{ - cogs::{Backup, Habitat, MathsCore, TurnoverRate}, + cogs::{Habitat, MathsCore, TurnoverRate}, landscape::Location, }; use necsim_core_bond::{NonNegativeF64, PositiveF64}; @@ -19,15 +19,6 @@ impl Default for UniformTurnoverRate { } } -#[contract_trait] -impl Backup for UniformTurnoverRate { - unsafe fn backup_unchecked(&self) -> Self { - Self { - turnover_rate: self.turnover_rate, - } - } -} - #[contract_trait] impl> TurnoverRate for UniformTurnoverRate { #[must_use] diff --git a/necsim/partitioning/core/src/lib.rs b/necsim/partitioning/core/src/lib.rs index ccf8d5746..f4a719a14 100644 --- a/necsim/partitioning/core/src/lib.rs +++ b/necsim/partitioning/core/src/lib.rs @@ -66,8 +66,6 @@ pub trait LocalPartition<'p, R: Reporter>: Sized { fn get_reporter(&mut self) -> &mut Self::Reporter; - fn is_root(&self) -> bool; - fn get_partition(&self) -> Partition; fn migrate_individuals<'a, E: Iterator>( diff --git a/necsim/partitioning/monolithic/src/lib.rs b/necsim/partitioning/monolithic/src/lib.rs index 6975454b6..b1e255670 100644 --- a/necsim/partitioning/monolithic/src/lib.rs +++ b/necsim/partitioning/monolithic/src/lib.rs @@ -107,13 +107,6 @@ impl<'p, R: Reporter> LocalPartition<'p, R> for MonolithicLocalPartition { self } - fn is_root(&self) -> bool { - match self { - Self::Live(partition) => partition.is_root(), - Self::Recorded(partition) => partition.is_root(), - } - } - fn get_partition(&self) -> Partition { match self { Self::Live(partition) => partition.get_partition(), diff --git a/necsim/partitioning/monolithic/src/live.rs b/necsim/partitioning/monolithic/src/live.rs index 023087357..8b839e690 100644 --- a/necsim/partitioning/monolithic/src/live.rs +++ b/necsim/partitioning/monolithic/src/live.rs @@ -44,10 +44,6 @@ impl<'p, R: Reporter> LocalPartition<'p, R> for LiveMonolithicLocalPartition &mut self.reporter } - fn is_root(&self) -> bool { - true - } - fn get_partition(&self) -> Partition { Partition::monolithic() } diff --git a/necsim/partitioning/monolithic/src/recorded.rs b/necsim/partitioning/monolithic/src/recorded.rs index dfd0c2ded..fae4c9d6c 100644 --- a/necsim/partitioning/monolithic/src/recorded.rs +++ b/necsim/partitioning/monolithic/src/recorded.rs @@ -54,10 +54,6 @@ impl<'p, R: Reporter> LocalPartition<'p, R> for RecordedMonolithicLocalPartition self } - fn is_root(&self) -> bool { - true - } - fn get_partition(&self) -> Partition { Partition::monolithic() } diff --git a/necsim/partitioning/mpi/src/lib.rs b/necsim/partitioning/mpi/src/lib.rs index dba2c1980..0ba058d3c 100644 --- a/necsim/partitioning/mpi/src/lib.rs +++ b/necsim/partitioning/mpi/src/lib.rs @@ -294,21 +294,30 @@ fn reduce_partitioning_data( data: T, fold: fn(T, T) -> T, ) -> anyhow::Result { - let local_ser = postcard::to_stdvec(&data).context("MPI data failed to serialize")?; + let local_ser = + postcard::to_stdvec(&data).context("MPI local partition result failed to serialize")?; std::mem::drop(data); + let local_ser_len = Count::try_from(local_ser.len()) + .context("MPI local partition result is too big to share")?; #[allow(clippy::cast_sign_loss)] let mut counts = vec![0 as Count; world.size() as usize]; - world.all_gather_into(&(Count::try_from(local_ser.len()).unwrap()), &mut counts); + world.all_gather_into(&local_ser_len, &mut counts); let offsets = counts .iter() .scan(0 as Count, |acc, &x| { let tmp = *acc; - *acc = (*acc).checked_add(x).unwrap(); - Some(tmp) + if let Some(a) = (*acc).checked_add(x) { + *acc = a; + } else { + return Some(Err(anyhow::anyhow!( + "MPI all local partition results combined are too big to share" + ))); + } + Some(Ok(tmp)) }) - .collect::>(); + .collect::, _>>()?; #[allow(clippy::cast_sign_loss)] let mut all_sers = vec![0_u8; counts.iter().copied().sum::() as usize]; diff --git a/necsim/partitioning/mpi/src/partition/common.rs b/necsim/partitioning/mpi/src/partition/common.rs index 6c274d73e..de67dc7b2 100644 --- a/necsim/partitioning/mpi/src/partition/common.rs +++ b/necsim/partitioning/mpi/src/partition/common.rs @@ -208,7 +208,7 @@ impl<'p> MpiCommonPartition<'p> { } } - ImmigrantPopIterator::new(&mut self.migration_buffers[self.get_partition().rank() as usize]) + ImmigrantPopIterator::new(&mut self.migration_buffers[self_rank_index]) } #[must_use] diff --git a/necsim/partitioning/mpi/src/partition/mod.rs b/necsim/partitioning/mpi/src/partition/mod.rs index 6d584f236..d77255107 100644 --- a/necsim/partitioning/mpi/src/partition/mod.rs +++ b/necsim/partitioning/mpi/src/partition/mod.rs @@ -38,13 +38,6 @@ impl<'p, R: Reporter> LocalPartition<'p, R> for MpiLocalPartition<'p, R> { self } - fn is_root(&self) -> bool { - match self { - Self::Root(partition) => partition.is_root(), - Self::Parallel(partition) => partition.is_root(), - } - } - fn get_partition(&self) -> Partition { match self { Self::Root(partition) => partition.get_partition(), diff --git a/necsim/partitioning/mpi/src/partition/parallel.rs b/necsim/partitioning/mpi/src/partition/parallel.rs index dfb5775d2..85b41d576 100644 --- a/necsim/partitioning/mpi/src/partition/parallel.rs +++ b/necsim/partitioning/mpi/src/partition/parallel.rs @@ -91,10 +91,6 @@ impl<'p, R: Reporter> LocalPartition<'p, R> for MpiParallelPartition<'p, R> { self } - fn is_root(&self) -> bool { - false - } - fn get_partition(&self) -> Partition { self.common.get_partition() } diff --git a/necsim/partitioning/mpi/src/partition/root.rs b/necsim/partitioning/mpi/src/partition/root.rs index ca6dd68e2..2cdd8c467 100644 --- a/necsim/partitioning/mpi/src/partition/root.rs +++ b/necsim/partitioning/mpi/src/partition/root.rs @@ -108,10 +108,6 @@ impl<'p, R: Reporter> LocalPartition<'p, R> for MpiRootPartition<'p, R> { self } - fn is_root(&self) -> bool { - true - } - fn get_partition(&self) -> Partition { self.common.get_partition() } diff --git a/necsim/partitioning/threads/src/lib.rs b/necsim/partitioning/threads/src/lib.rs index 54ac2b7c5..540b1f9bb 100644 --- a/necsim/partitioning/threads/src/lib.rs +++ b/necsim/partitioning/threads/src/lib.rs @@ -50,7 +50,7 @@ pub enum ThreadsLocalPartitionError { } pub struct ThreadsPartitioning { - size: PartitionSize, + num_threads: PartitionSize, migration_interval: Duration, progress_interval: Duration, } @@ -66,7 +66,7 @@ impl fmt::Debug for ThreadsPartitioning { } fmt.debug_struct(stringify!(ThreadsPartitioning)) - .field("size", &self.get_size().get()) + .field("num_threads", &self.num_threads.get()) .field( "migration_interval", &FormattedDuration(self.migration_interval), @@ -82,7 +82,7 @@ impl fmt::Debug for ThreadsPartitioning { impl Serialize for ThreadsPartitioning { fn serialize(&self, serializer: S) -> Result { let mut args = serializer.serialize_struct(stringify!(ThreadsPartitioning), 3)?; - args.serialize_field("size", &self.get_size())?; + args.serialize_field("threads", &self.num_threads)?; args.serialize_field( "migration", &format_duration(self.migration_interval).to_string(), @@ -100,7 +100,7 @@ impl<'de> Deserialize<'de> for ThreadsPartitioning { let raw = ThreadsPartitioningRaw::deserialize(deserializer)?; Ok(Self { - size: raw.num_threads, + num_threads: raw.num_threads, migration_interval: raw.migration_interval, progress_interval: raw.progress_interval, }) @@ -126,9 +126,10 @@ impl Partitioning for ThreadsPartitioning { type LocalPartition<'p, R: Reporter> = ThreadsLocalPartition<'p, R>; fn get_size(&self) -> PartitionSize { - self.size + self.num_threads } + #[allow(clippy::too_many_lines)] /// # Errors /// /// Returns `MissingEventLog` if the local partition is non-monolithic and @@ -154,27 +155,28 @@ impl Partitioning for ThreadsPartitioning { let mut progress_reporter: FilteredReporter = reporter_context.try_build()?; - let (progress_sender, progress_receiver) = sync_channel(self.size.get() as usize); + let (progress_sender, progress_receiver) = sync_channel(self.num_threads.get() as usize); let progress_channels = self - .size + .num_threads .partitions() .map(|_| progress_sender.clone()) .collect::>(); std::mem::drop(progress_sender); - let vote_any = Vote::new(self.size.get() as usize); - let vote_min_time = Vote::new_with_dummy(self.size.get() as usize, (PositiveF64::one(), 0)); + let vote_any = Vote::new(self.num_threads.get() as usize); + let vote_min_time = + Vote::new_with_dummy(self.num_threads.get() as usize, (PositiveF64::one(), 0)); let vote_termination = - AsyncVote::new_with_dummy(self.size.get() as usize, ControlFlow::Continue(())); + AsyncVote::new_with_dummy(self.num_threads.get() as usize, ControlFlow::Continue(())); let (emigration_channels, immigration_channels): (Vec<_>, Vec<_>) = self - .size + .num_threads .partitions() - .map(|_| sync_channel(self.size.get() as usize)) + .map(|_| sync_channel(self.num_threads.get() as usize)) .unzip(); let event_logs = self - .size + .num_threads .partitions() .map(|partition| { let mut directory = event_log.directory().to_owned(); @@ -187,9 +189,9 @@ impl Partitioning for ThreadsPartitioning { }) .collect::, _>>()?; - let sync_barrier = Arc::new(Barrier::new(self.size.get() as usize)); + let sync_barrier = Arc::new(Barrier::new(self.num_threads.get() as usize)); let args = self - .size + .num_threads .partitions() .map(|_| args.clone()) .collect::>(); @@ -202,7 +204,7 @@ impl Partitioning for ThreadsPartitioning { let sync_barrier = &sync_barrier; let thread_handles = self - .size + .num_threads .partitions() .zip(immigration_channels) .zip(event_logs) @@ -231,7 +233,8 @@ impl Partitioning for ThreadsPartitioning { ) .collect::>(); - let mut progress_remaining = vec![0; self.size.get() as usize].into_boxed_slice(); + let mut progress_remaining = + vec![0; self.num_threads.get() as usize].into_boxed_slice(); for (remaining, rank) in progress_receiver { progress_remaining[rank as usize] = remaining; progress_reporter.report_progress( diff --git a/necsim/partitioning/threads/src/partition.rs b/necsim/partitioning/threads/src/partition.rs index 7b0221b94..bf511a1ba 100644 --- a/necsim/partitioning/threads/src/partition.rs +++ b/necsim/partitioning/threads/src/partition.rs @@ -115,10 +115,6 @@ impl<'p, R: Reporter> LocalPartition<'p, R> for ThreadsLocalPartition<'p, R> { self } - fn is_root(&self) -> bool { - true - } - fn get_partition(&self) -> Partition { self.partition } @@ -255,7 +251,13 @@ impl<'p, R: Reporter> LocalPartition<'p, R> for ThreadsLocalPartition<'p, R> { ); match async_vote { - Poll::Pending => ControlFlow::Continue(()), + Poll::Pending => { + // This partition doesn't have any work right now but we have + // to do another round of voting, so let's yield to not busy + // wait - we'll be woken up if more work comes in + std::thread::yield_now(); + ControlFlow::Continue(()) + }, Poll::Ready(result) => result, } } diff --git a/rustcoalescence/src/cli/simulate/dispatch/valid/info.rs b/rustcoalescence/src/cli/simulate/dispatch/valid/info.rs index a815fe02d..759a3bf09 100644 --- a/rustcoalescence/src/cli/simulate/dispatch/valid/info.rs +++ b/rustcoalescence/src/cli/simulate/dispatch/valid/info.rs @@ -120,12 +120,12 @@ where } let result = launch::simulate::( - algorithm_args, + &mut local_partition, + sample, rng, scenario, - sample, + algorithm_args, pause_before, - &mut local_partition, )?; if log::log_enabled!(log::Level::Info) { diff --git a/rustcoalescence/src/cli/simulate/dispatch/valid/launch.rs b/rustcoalescence/src/cli/simulate/dispatch/valid/launch.rs index a3982a0db..8b1978ee3 100644 --- a/rustcoalescence/src/cli/simulate/dispatch/valid/launch.rs +++ b/rustcoalescence/src/cli/simulate/dispatch/valid/launch.rs @@ -23,12 +23,13 @@ pub(super) fn simulate< R: Reporter, P: LocalPartition<'p, R>, >( - algorithm_args: A::Arguments, + local_partition: &mut P, + + sample: Sample, rng: G, scenario: ScenarioCogs, - sample: Sample, + algorithm_args: A::Arguments, pause_before: Option, - local_partition: &mut P, ) -> anyhow::Result> { let lineages = match sample.origin { SampleOrigin::Habitat => {