Skip to content

Commit a1ad6b7

Browse files
committed
(ml5717) Refactored to make dispersal more explicit
1 parent af18f9b commit a1ad6b7

File tree

28 files changed

+317
-328
lines changed

28 files changed

+317
-328
lines changed

TODO

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1-
x check refactored Gillespie implementation
2-
x check + add contract for alias method dispersal
3-
x add Gillespie without self-dispersal
1+
- implement event transform from GPU to CPU
2+
- implement event deduplication (global vs local? - needs to be global for speciation)
3+
- implement simple stop condition for time sliced kernel launching
4+
- implement declarative event filtering which can be put onto the GPU as well
5+
- implement declarative kernel generic substitution
6+
- refactor cfg feature cuda and os cudas
7+
- implement verification
8+
49
- describe Gillespie in report
510
- describe data parallelism idea
611
- describe exponential sampling idea

necsim-core/src/cogs/active_lineage_sampler.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use super::{
33
RngCore,
44
};
55

6-
use crate::landscape::Location;
6+
use crate::landscape::IndexedLocation;
77
use crate::simulation::partial::active_lineager_sampler::PartialSimulation;
88

99
#[allow(clippy::inline_always, clippy::inline_fn_without_body)]
@@ -41,22 +41,22 @@ pub trait ActiveLineageSampler<
4141
simulation.lineage_store[reference.clone()].time_of_last_event() == event_time
4242
},
4343
}, "updates the time of the last event of the returned lineage to the time of the event")]
44-
fn pop_active_lineage_location_event_time(
44+
fn pop_active_lineage_indexed_location_event_time(
4545
&mut self,
4646
time: f64,
4747
simulation: &mut PartialSimulation<H, G, D, R, S, C, E>,
4848
rng: &mut G,
49-
) -> Option<(R, Location, f64)>;
49+
) -> Option<(R, IndexedLocation, f64)>;
5050

5151
#[debug_requires(time >= 0.0_f64, "time is non-negative")]
5252
/*#[debug_requires(( TODO: How can we assert this only for coherent lineage stores?
5353
simulation.lineage_store.get_active_lineages_at_location(&location).len() <
5454
(simulation.habitat.get_habitat_at_location(&location) as usize)
5555
), "location has habitat capacity for the lineage")]*/
56-
fn push_active_lineage_to_location(
56+
fn push_active_lineage_to_indexed_location(
5757
&mut self,
5858
lineage_reference: R,
59-
location: Location,
59+
indexed_location: IndexedLocation,
6060
time: f64,
6161
simulation: &mut PartialSimulation<H, G, D, R, S, C, E>,
6262
rng: &mut G,
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::cogs::RngCore;
2-
use crate::landscape::Location;
2+
use crate::landscape::{IndexedLocation, Location};
33

44
use super::{Habitat, LineageReference, LineageStore};
55

@@ -9,12 +9,12 @@ pub trait CoalescenceSampler<H: Habitat, G: RngCore, R: LineageReference<H>, S:
99
core::fmt::Debug
1010
{
1111
#[must_use]
12-
#[debug_requires(habitat.get_habitat_at_location(location) > 0, "location is habitable")]
12+
#[debug_requires(habitat.get_habitat_at_location(&location) > 0, "location is habitable")]
1313
fn sample_optional_coalescence_at_location(
1414
&self,
15-
location: &Location,
15+
location: Location,
1616
habitat: &H,
1717
lineage_store: &S,
1818
rng: &mut G,
19-
) -> Option<R>;
19+
) -> (IndexedLocation, Option<R>);
2020
}

necsim-core/src/cogs/event_sampler.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use super::{
44
CoalescenceSampler, DispersalSampler, Habitat, LineageReference, LineageStore, RngCore,
55
};
66
use crate::event::{Event, EventType};
7-
use crate::landscape::Location;
7+
use crate::landscape::IndexedLocation;
88
use crate::simulation::partial::event_sampler::PartialSimulation;
99

1010
#[allow(clippy::inline_always, clippy::inline_fn_without_body)]
@@ -31,10 +31,10 @@ pub trait EventSampler<
3131
"event occurs for lineage_reference"
3232
)]
3333
#[debug_ensures(ret.time() == event_time, "event occurs at event_time")]
34-
fn sample_event_for_lineage_at_location_time(
34+
fn sample_event_for_lineage_at_indexed_location_time(
3535
&self,
3636
lineage_reference: R,
37-
location: Location,
37+
indexed_location: IndexedLocation,
3838
event_time: f64,
3939
simulation: &PartialSimulation<H, G, D, R, S, C>,
4040
rng: &mut G,

necsim-core/src/cogs/habitat.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::landscape::LandscapeExtent;
2-
use crate::landscape::Location;
2+
use crate::landscape::{IndexedLocation, Location};
33

44
#[allow(clippy::inline_always, clippy::inline_fn_without_body)]
55
#[contract_trait]
@@ -33,11 +33,13 @@ pub trait Habitat: core::fmt::Debug {
3333
#[contract_trait]
3434
pub trait HabitatToU64Injection: Habitat {
3535
#[must_use]
36-
#[debug_requires(self.get_extent().contains(location), "location is inside habitat extent")]
37-
#[debug_requires(index_at_location < self.get_habitat_at_location(location) as usize)]
38-
fn map_indexed_location_to_u64_injective(
39-
&self,
40-
location: &Location,
41-
index_at_location: usize,
42-
) -> u64;
36+
#[debug_requires(
37+
self.get_extent().contains(indexed_location.location()),
38+
"location is inside habitat extent"
39+
)]
40+
#[debug_requires(
41+
indexed_location.index() < self.get_habitat_at_location(indexed_location.location()),
42+
"index is within the location's habitat capacity"
43+
)]
44+
fn map_indexed_location_to_u64_injective(&self, indexed_location: &IndexedLocation) -> u64;
4345
}

necsim-core/src/cogs/lineage_store/contract.rs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use core::convert::TryFrom;
2+
13
use crate::cogs::{CoherentLineageStore, Habitat, LineageReference};
24
use crate::landscape::Location;
35

@@ -18,19 +20,14 @@ pub fn explicit_lineage_store_lineage_at_location_contract<
1820
None => return false,
1921
};
2022

21-
let location = match lineage.location() {
22-
Some(location) => location,
23+
let indexed_location = match lineage.indexed_location() {
24+
Some(indexed_location) => indexed_location,
2325
None => return false,
2426
};
2527

26-
let lineages_at_location = &store.get_active_lineages_at_location(location);
27-
28-
let index_at_location = match lineage.index_at_location() {
29-
Some(index_at_location) => index_at_location,
30-
None => return false,
31-
};
28+
let lineages_at_location = &store.get_active_lineages_at_location(indexed_location.location());
3229

33-
match lineages_at_location.get(index_at_location) {
30+
match lineages_at_location.get(indexed_location.index() as usize) {
3431
Some(reference_at_location) => reference_at_location == &input_reference,
3532
None => false,
3633
}
@@ -50,8 +47,15 @@ pub(super) fn explicit_lineage_store_invariant_contract<
5047
lineages_at_location
5148
.iter()
5249
.enumerate()
53-
.all(|(i, reference)| {
54-
store[reference.clone()].location() == Some(location)
55-
&& store[reference.clone()].index_at_location() == Some(i)
50+
.all(|(index, reference)| {
51+
match (
52+
u32::try_from(index),
53+
store[reference.clone()].indexed_location(),
54+
) {
55+
(Ok(index), Some(indexed_location)) => {
56+
indexed_location.location() == location && indexed_location.index() == index
57+
}
58+
_ => false,
59+
}
5660
})
5761
}

necsim-core/src/cogs/lineage_store/mod.rs

Lines changed: 17 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use core::ops::Index;
22

33
use super::{Habitat, LineageReference};
4-
use crate::landscape::Location;
4+
use crate::landscape::{IndexedLocation, Location};
55
use crate::lineage::Lineage;
66

77
mod contract;
@@ -58,8 +58,9 @@ pub trait CoherentLineageStore<H: Habitat, R: LineageReference<H>>: LineageStore
5858
contract::explicit_lineage_store_invariant_contract(self, &location),
5959
"invariant of lineage-location bijection holds"
6060
)]
61+
#[debug_ensures(self[old(reference.clone())].is_active(), "lineage was activated")]
6162
#[debug_ensures(
62-
self[old(reference.clone())].location() == Some(&old(location.clone())),
63+
self[old(reference.clone())].indexed_location().map(IndexedLocation::location) == Some(&old(location.clone())),
6364
"lineage was added to location"
6465
)]
6566
#[debug_ensures(
@@ -82,24 +83,25 @@ pub trait CoherentLineageStore<H: Habitat, R: LineageReference<H>>: LineageStore
8283
)]
8384
#[debug_requires(
8485
contract::explicit_lineage_store_invariant_contract(
85-
self, self[reference.clone()].location().unwrap()
86+
self, self[reference.clone()].indexed_location().unwrap().location()
8687
), "invariant of lineage-location bijection holds"
8788
)]
89+
#[debug_ensures(!self[old(reference.clone())].is_active(), "lineage was deactivated")]
8890
#[debug_ensures(
8991
!contract::explicit_lineage_store_lineage_at_location_contract(
9092
self, old(reference.clone())
9193
), "lineage was removed from the location and index it references"
9294
)]
9395
#[debug_ensures(
9496
contract::explicit_lineage_store_invariant_contract(
95-
self, &old(self[reference.clone()].location().unwrap().clone())
97+
self, &old(self[reference.clone()].indexed_location().unwrap().location().clone())
9698
), "maintains invariant of lineage-location bijection"
9799
)]
98100
#[debug_ensures(
99-
ret == old(self[reference.clone()].location().unwrap().clone()),
100-
"returns the individual's prior location"
101+
ret == old(self[reference.clone()].indexed_location().unwrap().clone()),
102+
"returns the individual's prior indexed_location"
101103
)]
102-
fn pop_lineage_from_its_location(&mut self, reference: R) -> Location;
104+
fn pop_lineage_from_its_location(&mut self, reference: R) -> IndexedLocation;
103105
}
104106

105107
#[allow(clippy::inline_always, clippy::inline_fn_without_body)]
@@ -108,59 +110,24 @@ pub trait CoherentLineageStore<H: Habitat, R: LineageReference<H>>: LineageStore
108110
pub trait IncoherentLineageStore<H: Habitat, R: LineageReference<H>>: LineageStore<H, R> {
109111
#[debug_requires(self.get(reference.clone()).is_some(), "lineage reference is valid")]
110112
#[debug_requires(!self[reference.clone()].is_active(), "lineage is inactive")]
111-
/*#[debug_requires(
112-
!contract::explicit_lineage_store_lineage_at_location_contract(self, reference.clone()),
113-
"lineage is not at the location and index it references"
114-
)]
115-
#[debug_requires(
116-
contract::explicit_lineage_store_invariant_contract(self, &location),
117-
"invariant of lineage-location bijection holds"
118-
)]
113+
#[debug_ensures(self[old(reference.clone())].is_active(), "lineage was activated")]
119114
#[debug_ensures(
120-
self[old(reference.clone())].location() == Some(&old(location.clone())),
121-
"lineage was added to location"
122-
)]
123-
#[debug_ensures(
124-
contract::explicit_lineage_store_lineage_at_location_contract(
125-
self, old(reference.clone())
126-
), "lineage is at the location and index it references"
115+
self[old(reference.clone())].indexed_location() == Some(&old(indexed_location.clone())),
116+
"lineage was added to indexed_location"
127117
)]
128-
#[debug_ensures(
129-
contract::explicit_lineage_store_invariant_contract(self, &old(location.clone())),
130-
"maintains invariant of lineage-location bijection"
131-
)]*/
132-
fn insert_lineage_to_location_at_index(
118+
fn insert_lineage_to_indexed_location(
133119
&mut self,
134120
reference: R,
135-
location: Location,
136-
index_at_location: usize,
121+
indexed_location: IndexedLocation,
137122
);
138123

139124
#[must_use]
140125
#[debug_requires(self.get(reference.clone()).is_some(), "lineage reference is valid")]
141126
#[debug_requires(self[reference.clone()].is_active(), "lineage is active")]
142-
/*#[debug_requires(
143-
contract::explicit_lineage_store_lineage_at_location_contract(self, reference.clone()),
144-
"lineage is at the location and index it references"
145-
)]
146-
#[debug_requires(
147-
contract::explicit_lineage_store_invariant_contract(
148-
self, self[reference.clone()].location().unwrap()
149-
), "invariant of lineage-location bijection holds"
150-
)]
151-
#[debug_ensures(
152-
!contract::explicit_lineage_store_lineage_at_location_contract(
153-
self, old(reference.clone())
154-
), "lineage was removed from the location and index it references"
155-
)]
156-
#[debug_ensures(
157-
contract::explicit_lineage_store_invariant_contract(
158-
self, &old(self[reference.clone()].location().unwrap().clone())
159-
), "maintains invariant of lineage-location bijection"
160-
)]*/
127+
#[debug_ensures(!self[old(reference.clone())].is_active(), "lineage was deactivated")]
161128
#[debug_ensures(
162-
ret == old(self[reference.clone()].location().unwrap().clone()),
129+
ret == old(self[reference.clone()].indexed_location().unwrap().clone()),
163130
"returns the individual's prior location"
164131
)]
165-
fn extract_lineage_from_its_location(&mut self, reference: R) -> Location;
132+
fn extract_lineage_from_its_location(&mut self, reference: R) -> IndexedLocation;
166133
}

necsim-core/src/event.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use core::marker::PhantomData;
22

33
use crate::cogs::{Habitat, LineageReference};
4-
use crate::landscape::Location;
4+
use crate::landscape::IndexedLocation;
55

66
pub struct Event<H: Habitat, R: LineageReference<H>> {
77
time: f64,
@@ -46,8 +46,8 @@ impl<H: Habitat, R: LineageReference<H>> Event<H, R> {
4646
pub enum EventType<H: Habitat, R: LineageReference<H>> {
4747
Speciation,
4848
Dispersal {
49-
origin: Location,
50-
target: Location,
49+
origin: IndexedLocation,
50+
target: IndexedLocation,
5151
coalescence: Option<R>,
5252
_marker: PhantomData<H>,
5353
},

necsim-core/src/landscape/location.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,39 @@ impl Location {
2323
self.y
2424
}
2525
}
26+
27+
impl From<IndexedLocation> for Location {
28+
fn from(indexed_location: IndexedLocation) -> Location {
29+
indexed_location.location
30+
}
31+
}
32+
33+
#[derive(Eq, PartialEq, Clone, Hash, Debug)]
34+
#[cfg_attr(feature = "cuda", derive(DeviceCopy))]
35+
#[allow(clippy::module_name_repetitions)]
36+
pub struct IndexedLocation {
37+
location: Location,
38+
pub(crate) index: u32,
39+
}
40+
41+
impl IndexedLocation {
42+
#[must_use]
43+
#[debug_ensures(
44+
ret.location.x() == old(location.x()) && ret.location.y() == old(location.y()),
45+
"stores location"
46+
)]
47+
#[debug_ensures(ret.index() == index, "stores index")]
48+
pub fn new(location: Location, index: u32) -> Self {
49+
Self { location, index }
50+
}
51+
52+
#[must_use]
53+
pub fn location(&self) -> &Location {
54+
&self.location
55+
}
56+
57+
#[must_use]
58+
pub fn index(&self) -> u32 {
59+
self.index
60+
}
61+
}

necsim-core/src/landscape/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ mod extent;
22
mod location;
33

44
pub use extent::LandscapeExtent;
5-
pub use location::Location;
5+
pub use location::{IndexedLocation, Location};

0 commit comments

Comments
 (0)