pub mod simulate;
pub mod space;
pub mod state;
mod tests;
pub use self::simulate::*;
pub use self::space::*;
pub use self::state::*;
use error::*;
use id::*;
use petgraph::algo::astar;
use petgraph::graphmap::UnGraphMap;
use rayon::prelude::*;
use std::collections::hash_set::Iter;
use std::collections::{HashMap, HashSet};
pub type SpaceGraph = UnGraphMap<ID, ()>;
pub type SpaceMap<S> = HashMap<ID, Space<S>>;
#[derive(Debug)]
pub struct QDF<S>
where
S: State,
{
id: ID,
graph: SpaceGraph,
spaces: SpaceMap<S>,
space_ids: HashSet<ID>,
dimensions: usize,
}
impl<S> QDF<S>
where
S: State,
{
pub fn new(dimensions: usize, state: S) -> (Self, ID) {
let mut graph = UnGraphMap::new();
let mut spaces = HashMap::new();
let mut space_ids = HashSet::new();
let id = ID::new();
graph.add_node(id);
spaces.insert(id, Space::new(id, state));
space_ids.insert(id);
let qdf = Self {
id: ID::new(),
graph,
spaces,
space_ids,
dimensions,
};
(qdf, id)
}
pub fn with_levels(dimensions: usize, state: S, levels: usize) -> (Self, Vec<ID>) {
let (mut qdf, _) = Self::new(dimensions, state);
for _ in 0..levels {
let spaces = qdf.spaces().cloned().collect::<Vec<ID>>();
for id in spaces {
qdf.increase_space_density(id).unwrap();
}
}
let spaces = qdf.spaces().cloned().collect();
(qdf, spaces)
}
#[inline]
pub fn with_levels_and_minimum_state(
dimensions: usize,
state: S,
levels: usize,
) -> (Self, Vec<ID>) {
Self::with_levels(dimensions, state.super_state_at_level(dimensions, levels), levels)
}
#[inline]
pub fn id(&self) -> ID {
self.id
}
#[inline]
pub fn dimensions(&self) -> usize {
self.dimensions
}
#[inline]
pub fn space_exists(&self, id: ID) -> bool {
self.spaces.contains_key(&id)
}
#[inline]
pub fn spaces(&self) -> Iter<ID> {
self.space_ids.iter()
}
#[inline]
pub fn try_get_space(&self, id: ID) -> Option<&Space<S>> {
self.spaces.get(&id)
}
#[inline]
pub fn get_space(&self, id: ID) -> Result<&Space<S>> {
if let Some(space) = self.spaces.get(&id) {
Ok(space)
} else {
Err(QDFError::SpaceDoesNotExists(id))
}
}
#[inline]
pub fn space(&self, id: ID) -> &Space<S> {
&self.spaces[&id]
}
#[inline]
pub fn try_set_space_state(&mut self, id: ID, state: S) -> bool {
self.set_space_state(id, state).is_ok()
}
#[inline]
pub fn set_space_state(&mut self, id: ID, state: S) -> Result<()> {
if self.space_exists(id) {
self.spaces.get_mut(&id).unwrap().apply_state(state);
Ok(())
} else {
Err(QDFError::SpaceDoesNotExists(id))
}
}
#[inline]
pub fn find_space_neighbors(&self, id: ID) -> Result<Vec<ID>> {
if self.graph.contains_node(id) {
Ok(self.graph.neighbors(id).collect())
} else {
Err(QDFError::SpaceDoesNotExists(id))
}
}
pub fn find_path(&self, from: ID, to: ID) -> Result<Vec<ID>> {
if !self.space_exists(from) {
return Err(QDFError::SpaceDoesNotExists(from));
}
if !self.space_exists(to) {
return Err(QDFError::SpaceDoesNotExists(to));
}
if let Some((_, spaces)) = astar(&self.graph, from, |f| f == to, |_| 0, |_| 0) {
Ok(spaces)
} else {
Ok(vec![])
}
}
pub fn increase_space_density(&mut self, id: ID) -> Result<(ID, Vec<ID>, Vec<(ID, ID)>)> {
if self.space_exists(id) {
let space = self.spaces[&id].clone();
let subs = self.dimensions + 1;
let substates = space.state().subdivide(subs);
let spaces = substates
.iter()
.map(|substate| Space::new(ID::new(), substate.clone()))
.collect::<Vec<Space<S>>>();
for s in &spaces {
let id = s.id();
self.spaces.insert(id, s.clone());
self.graph.add_node(id);
self.space_ids.insert(id);
}
for a in &spaces {
let aid = a.id();
for b in &spaces {
let bid = b.id();
if aid != bid {
self.graph.add_edge(aid, bid, ());
}
}
}
let neighbors = self.graph.neighbors(id).collect::<Vec<ID>>();
let pairs = neighbors
.iter()
.enumerate()
.map(|(i, n)| {
let t = spaces[i].id();
self.graph.remove_edge(*n, id);
self.graph.add_edge(*n, t, ());
(*n, t)
})
.collect::<Vec<(ID, ID)>>();
self.space_ids.remove(&id);
self.spaces.remove(&id);
let space_ids = spaces.iter().map(|s| s.id()).collect::<Vec<ID>>();
Ok((id, space_ids, pairs))
} else {
Err(QDFError::SpaceDoesNotExists(id))
}
}
pub fn decrease_space_density(&mut self, id: ID) -> Result<Option<(Vec<ID>, ID)>> {
if self.space_exists(id) {
let neighbor = self.graph.neighbors(id).collect::<Vec<ID>>();
let mut connected = neighbor
.iter()
.filter(|a| {
neighbor
.iter()
.any(|b| **a != *b && self.graph.edge_weight(**a, *b).is_some())
}).cloned()
.collect::<Vec<ID>>();
if connected.len() != self.dimensions {
Ok(None)
} else {
connected.push(id);
let states = connected
.iter()
.map(|i| self.spaces[&i].state())
.cloned()
.collect::<Vec<S>>();
let id = ID::new();
self.graph.add_node(id);
self.space_ids.insert(id);
self.spaces
.insert(id, Space::new(id, State::merge(&states)));
for i in &connected {
let outsiders = self
.graph
.neighbors(*i)
.filter(|n| !connected.contains(n))
.collect::<Vec<ID>>();
for n in outsiders {
self.graph.add_edge(id, n, ());
}
}
let space_ids = connected
.iter()
.map(|i| {
self.graph.remove_node(*i);
self.spaces.remove(i);
self.space_ids.remove(i);
*i
})
.collect::<Vec<ID>>();
Ok(Some((space_ids, id)))
}
} else {
Err(QDFError::SpaceDoesNotExists(id))
}
}
pub fn simulation_step<M>(&mut self)
where
M: Simulate<S>,
{
let states = self.simulate_states::<M>();
for (id, state) in states {
self.spaces.get_mut(&id).unwrap().apply_state(state);
}
}
pub fn simulation_step_parallel<M>(&mut self)
where
M: Simulate<S>,
{
let states = self.simulate_states_parallel::<M>();
for (id, state) in states {
self.spaces.get_mut(&id).unwrap().apply_state(state);
}
}
pub fn simulate_states<M>(&self) -> Vec<(ID, S)>
where
M: Simulate<S>,
{
self.space_ids
.iter()
.map(|id| {
let neighbor_states = self
.graph
.neighbors(*id)
.map(|i| self.spaces[&i].state())
.collect::<Vec<&S>>();
(*id, M::simulate(self.spaces[id].state(), &neighbor_states))
}).collect()
}
pub fn simulate_states_parallel<M>(&self) -> Vec<(ID, S)>
where
M: Simulate<S>,
{
let spaces = &self.spaces;
let space_ids = &self.space_ids;
let graph = &self.graph;
space_ids
.par_iter()
.map(|id| {
let neighbor_states = graph
.neighbors(*id)
.map(|i| spaces[&i].state())
.collect::<Vec<&S>>();
(*id, M::simulate(spaces[id].state(), &neighbor_states))
}).collect()
}
}