use super::{GraphStatistic, GraphStorage};
use annis::db::annostorage::AnnoStorage;
use annis::db::graphstorage::EdgeContainer;
use annis::db::AnnotationStorage;
use annis::db::Graph;
use annis::db::Match;
use annis::dfs::{CycleSafeDFS, DFSStep};
use annis::errors::*;
use annis::types::{AnnoKey, Edge, NodeID, NumValue};
use bincode;
use rustc_hash::FxHashMap;
use rustc_hash::FxHashSet;
use serde::{Deserialize, Serialize};
use std;
use std::clone::Clone;
#[derive(Serialize, Deserialize, Clone, MallocSizeOf)]
struct RelativePosition<PosT> {
pub root: NodeID,
pub pos: PosT,
}
#[derive(Serialize, Deserialize, Clone, MallocSizeOf)]
pub struct LinearGraphStorage<PosT: NumValue> {
node_to_pos: FxHashMap<NodeID, RelativePosition<PosT>>,
node_chains: FxHashMap<NodeID, Vec<NodeID>>,
annos: AnnoStorage<Edge>,
stats: Option<GraphStatistic>,
}
impl<PosT> LinearGraphStorage<PosT>
where
PosT: NumValue,
{
pub fn new() -> LinearGraphStorage<PosT> {
LinearGraphStorage {
node_to_pos: FxHashMap::default(),
node_chains: FxHashMap::default(),
annos: AnnoStorage::new(),
stats: None,
}
}
pub fn clear(&mut self) {
self.node_to_pos.clear();
self.node_chains.clear();
self.annos.clear();
self.stats = None;
}
}
impl<PosT> Default for LinearGraphStorage<PosT>
where
PosT: NumValue,
{
fn default() -> Self {
LinearGraphStorage::new()
}
}
impl<PosT: 'static> EdgeContainer for LinearGraphStorage<PosT>
where
PosT: NumValue,
{
fn get_outgoing_edges<'a>(&'a self, node: &NodeID) -> Box<Iterator<Item = NodeID> + 'a> {
if let Some(pos) = self.node_to_pos.get(node) {
if let Some(chain) = self.node_chains.get(&pos.root) {
let next_pos = pos.pos.clone() + PosT::one();
if let Some(next_pos) = next_pos.to_usize() {
if next_pos < chain.len() {
return Box::from(std::iter::once(chain[next_pos]));
}
}
}
}
return Box::from(std::iter::empty());
}
fn get_ingoing_edges<'a>(&'a self, node: &NodeID) -> Box<Iterator<Item = NodeID> + 'a> {
if let Some(pos) = self.node_to_pos.get(node) {
if let Some(chain) = self.node_chains.get(&pos.root) {
if let Some(pos) = pos.pos.to_usize() {
if let Some(previous_pos) = pos.checked_sub(1) {
return Box::from(std::iter::once(chain[previous_pos]));
}
}
}
}
return Box::from(std::iter::empty());
}
fn get_anno_storage(&self) -> &AnnotationStorage<Edge> {
&self.annos
}
fn source_nodes<'a>(&'a self) -> Box<Iterator<Item = NodeID> + 'a> {
let it = self
.node_chains
.iter()
.flat_map(|(_root, chain)| chain.iter().rev().skip(1))
.cloned();
return Box::new(it);
}
fn get_statistics(&self) -> Option<&GraphStatistic> {
self.stats.as_ref()
}
}
impl<PosT: 'static> GraphStorage for LinearGraphStorage<PosT>
where
for<'de> PosT: NumValue + Deserialize<'de> + Serialize,
{
fn serialization_id(&self) -> String {
format!("LinearO{}V1", std::mem::size_of::<PosT>() * 8)
}
fn serialize_gs(&self, writer: &mut std::io::Write) -> Result<()> {
bincode::serialize_into(writer, self)?;
Ok(())
}
fn find_connected<'a>(
&'a self,
source: &NodeID,
min_distance: usize,
max_distance: usize,
) -> Box<Iterator<Item = NodeID> + 'a> {
if let Some(start_pos) = self.node_to_pos.get(source) {
if let Some(chain) = self.node_chains.get(&start_pos.root) {
if let Some(offset) = start_pos.pos.to_usize() {
let max_distance = offset + max_distance;
let min_distance = offset + min_distance;
let max_distance = std::cmp::min(chain.len(), max_distance + 1);
if min_distance < chain.len() {
return Box::new(chain[min_distance..max_distance].iter().cloned());
}
}
}
}
return Box::new(std::iter::empty());
}
fn find_connected_inverse<'a>(
&'a self,
source: &NodeID,
min_distance: usize,
max_distance: usize,
) -> Box<Iterator<Item = NodeID> + 'a> {
if let Some(start_pos) = self.node_to_pos.get(source) {
if let Some(chain) = self.node_chains.get(&start_pos.root) {
if let Some(offset) = start_pos.pos.to_usize() {
let max_distance = offset.checked_sub(max_distance).unwrap_or(0);
if let Some(min_distance) = offset.checked_sub(min_distance) {
if min_distance < chain.len() {
return Box::new(
chain[max_distance..(min_distance + 1)].iter().cloned(),
);
} else {
return Box::new(chain[max_distance..chain.len()].iter().cloned());
}
}
}
}
}
return Box::new(std::iter::empty());
}
fn distance(&self, source: &NodeID, target: &NodeID) -> Option<usize> {
if source == target {
return Some(0);
}
if let (Some(source_pos), Some(target_pos)) =
(self.node_to_pos.get(source), self.node_to_pos.get(target))
{
if source_pos.root == target_pos.root && source_pos.pos <= target_pos.pos {
let diff = target_pos.pos.clone() - source_pos.pos.clone();
if let Some(diff) = diff.to_usize() {
return Some(diff);
}
}
}
return None;
}
fn is_connected(
&self,
source: &NodeID,
target: &NodeID,
min_distance: usize,
max_distance: usize,
) -> bool {
if let (Some(source_pos), Some(target_pos)) =
(self.node_to_pos.get(source), self.node_to_pos.get(target))
{
if source_pos.root == target_pos.root && source_pos.pos <= target_pos.pos {
let diff = target_pos.pos.clone() - source_pos.pos.clone();
if let Some(diff) = diff.to_usize() {
if diff >= min_distance && diff <= max_distance {
return true;
}
}
}
}
return false;
}
fn copy(&mut self, db: &Graph, orig: &EdgeContainer) {
self.clear();
let mut roots: FxHashSet<NodeID> = FxHashSet::default();
let node_name_key: AnnoKey = db.get_node_name_key();
let nodes: Box<Iterator<Item = Match>> = db.node_annos.exact_anno_search(
Some(node_name_key.ns.clone()),
node_name_key.name.clone(),
None,
);
for m in nodes {
let m: Match = m;
let n = m.node;
if orig.get_outgoing_edges(&n).next().is_some() {
roots.insert(n);
}
}
let nodes: Box<Iterator<Item = Match>> =
db.node_annos
.exact_anno_search(Some(node_name_key.ns), node_name_key.name, None);
for m in nodes {
let m: Match = m;
let source = m.node;
let out_edges = orig.get_outgoing_edges(&source);
for target in out_edges {
roots.remove(&target);
let e = Edge { source, target };
let edge_annos = orig.get_anno_storage().get_annotations_for_item(&e);
for a in edge_annos.into_iter() {
self.annos.insert(e.clone(), a);
}
}
}
for root_node in roots.iter() {
let mut chain: Vec<NodeID> = vec![root_node.clone()];
let pos: RelativePosition<PosT> = RelativePosition {
root: root_node.clone(),
pos: PosT::zero(),
};
self.node_to_pos.insert(root_node.clone(), pos);
let dfs = CycleSafeDFS::new(orig, &root_node, 1, usize::max_value());
for step in dfs {
let step: DFSStep = step;
if let Some(pos) = PosT::from_usize(chain.len()) {
let pos: RelativePosition<PosT> = RelativePosition {
root: root_node.clone(),
pos: pos,
};
self.node_to_pos.insert(step.node.clone(), pos);
}
chain.push(step.node);
}
chain.shrink_to_fit();
self.node_chains.insert(root_node.clone(), chain);
}
self.node_chains.shrink_to_fit();
self.node_to_pos.shrink_to_fit();
self.stats = orig.get_statistics().cloned();
self.annos.calculate_statistics();
}
fn inverse_has_same_cost(&self) -> bool {
true
}
fn as_edgecontainer(&self) -> &EdgeContainer {
self
}
}