Haploid Wright-Fisher simulation
The following code simulates a haploid Wright-Fisher model.
The code is a reimplementation of an example program distributed with tskit-c
.
In addition to tskit
, the example uses:
fn simulate(
seed: u64,
popsize: usize,
num_generations: i32,
simplify_interval: i32,
update_bookmark: bool,
) -> Result<tskit::TreeSequence> {
if popsize == 0 {
return Err(anyhow::Error::msg("popsize must be > 0"));
}
if num_generations == 0 {
return Err(anyhow::Error::msg("num_generations must be > 0"));
}
if simplify_interval == 0 {
return Err(anyhow::Error::msg("simplify_interval must be > 0"));
}
let mut tables = tskit::TableCollection::new(1.0)?;
// create parental nodes
let mut parents_and_children = {
let mut temp = vec![];
let parental_time = f64::from(num_generations);
for _ in 0..popsize {
let node = tables.add_node(0, parental_time, -1, -1)?;
temp.push(node);
}
temp
};
// allocate space for offspring nodes
parents_and_children.resize(2 * parents_and_children.len(), tskit::NodeId::NULL);
// Construct non-overlapping mutable slices into our vector.
let (mut parents, mut children) = parents_and_children.split_at_mut(popsize);
let parent_picker = rand::distributions::Uniform::new(0, popsize);
let breakpoint_generator = rand::distributions::Uniform::new(0.0, 1.0);
let mut rng = rand::rngs::StdRng::seed_from_u64(seed);
let mut bookmark = tskit::types::Bookmark::default();
for birth_time in (0..num_generations).rev() {
for c in children.iter_mut() {
let bt = f64::from(birth_time);
let child = tables.add_node(0, bt, -1, -1)?;
let left_parent = parents
.get(parent_picker.sample(&mut rng))
.ok_or_else(|| anyhow::Error::msg("invalid left_parent index"))?;
let right_parent = parents
.get(parent_picker.sample(&mut rng))
.ok_or_else(|| anyhow::Error::msg("invalid right_parent index"))?;
let breakpoint = breakpoint_generator.sample(&mut rng);
tables.add_edge(0., breakpoint, *left_parent, child)?;
tables.add_edge(breakpoint, 1.0, *right_parent, child)?;
*c = child;
}
if birth_time % simplify_interval == 0 {
tables.sort(&bookmark, tskit::TableSortOptions::default())?;
if update_bookmark {
rotate_edges(&bookmark, &mut tables);
}
if let Some(idmap) =
tables.simplify(children, tskit::SimplificationOptions::default(), true)?
{
// remap child nodes
for o in children.iter_mut() {
*o = idmap[usize::try_from(*o)?];
}
}
if update_bookmark {
bookmark.set_edges(tables.edges().num_rows());
}
}
std::mem::swap(&mut parents, &mut children);
}
tables.build_index()?;
let treeseq = tables.tree_sequence(tskit::TreeSequenceFlags::default())?;
Ok(treeseq)
}