use ojo_graph::Graph;
use ojo_multimap::MMap;
use ojo_partition::Partition;
use std::collections::BTreeSet as Set;
use std::collections::HashSet;
use crate::{NodeId, PatchId};
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub enum EdgeKind {
Live,
Pseudo,
Deleted,
}
impl EdgeKind {
fn from_deleted(deleted: bool) -> EdgeKind {
if deleted {
EdgeKind::Deleted
} else {
EdgeKind::Live
}
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Edge {
pub kind: EdgeKind,
pub dest: NodeId,
pub patch: PatchId,
}
impl Edge {
fn not_deleted(&self) -> bool {
self.kind != EdgeKind::Deleted
}
fn new_pseudo(dest: NodeId) -> Edge {
Edge {
dest: dest,
kind: EdgeKind::Pseudo,
patch: PatchId::cur(),
}
}
fn new_live(dest: NodeId, patch: PatchId) -> Edge {
Edge {
dest,
kind: EdgeKind::Live,
patch,
}
}
fn new_deleted(dest: NodeId, patch: PatchId) -> Edge {
Edge {
dest,
kind: EdgeKind::Deleted,
patch,
}
}
fn new_real(dest: NodeId, deleted: bool, patch: PatchId) -> Edge {
Edge {
dest,
kind: EdgeKind::from_deleted(deleted),
patch,
}
}
}
impl ojo_graph::Edge<NodeId> for Edge {
fn target(&self) -> NodeId {
self.dest
}
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[serde(rename = "Graggle")]
pub(crate) struct GraggleData {
nodes: Set<NodeId>,
deleted_nodes: Set<NodeId>,
edges: MMap<NodeId, Edge>,
back_edges: MMap<NodeId, Edge>,
deleted_partition: Partition<NodeId>,
pseudo_edge_reasons: MMap<(NodeId, NodeId), NodeId>,
reason_pseudo_edges: MMap<NodeId, (NodeId, NodeId)>,
dirty_reps: Set<NodeId>,
}
impl PartialEq<GraggleData> for GraggleData {
fn eq(&self, other: &GraggleData) -> bool {
self.nodes.eq(&other.nodes)
&& self.deleted_nodes.eq(&other.deleted_nodes)
&& self.edges.eq(&other.edges)
&& self.back_edges.eq(&other.back_edges)
}
}
impl GraggleData {
pub fn new() -> GraggleData {
Default::default()
}
pub fn as_graggle(&'_ self) -> Graggle<'_> {
Graggle { data: self }
}
pub fn all_out_edges<'b>(&'b self, node: &NodeId) -> impl Iterator<Item = &'b Edge> + 'b {
self.edges.get(node)
}
pub fn all_in_edges<'b>(&'b self, node: &NodeId) -> impl Iterator<Item = &'b Edge> + 'b {
self.back_edges.get(node)
}
pub fn add_node(&mut self, id: NodeId) {
self.nodes.insert(id);
}
fn has_live_edge(&self, src: &NodeId, dest: &NodeId) -> bool {
let e = Edge::new_live(*dest, PatchId::cur());
if let Some(actual_e) = self.edges.get_from(src, &e).next() {
actual_e.dest == *dest && actual_e.kind == EdgeKind::Live
} else {
false
}
}
fn remove_pseudo_edge_reasons(&mut self, src: &NodeId, dest: &NodeId) {
let reasons = self
.pseudo_edge_reasons
.get(&(*src, *dest))
.cloned()
.collect::<Vec<_>>();
self.pseudo_edge_reasons.remove_all(&(*src, *dest));
for r in reasons {
self.reason_pseudo_edges.remove(&r, &(*src, *dest));
}
}
fn internal_delete_edge(&mut self, src: &NodeId, edge: &Edge) {
self.edges.remove(src, edge);
let back_edge = Edge {
dest: *src,
kind: edge.kind,
patch: edge.patch,
};
self.back_edges.remove(&edge.dest, &back_edge);
}
fn internal_delete_back_edge(&mut self, dest: &NodeId, back_edge: &Edge) {
self.back_edges.remove(dest, back_edge);
let edge = Edge {
dest: *dest,
kind: back_edge.kind,
patch: back_edge.patch,
};
self.edges.remove(&back_edge.dest, &edge);
}
pub fn unadd_node(&mut self, id: &NodeId) {
assert!(self.nodes.contains(id));
self.nodes.remove(id);
let out_edges = self.all_out_edges(id).cloned().collect::<Vec<_>>();
let in_edges = self.all_in_edges(id).cloned().collect::<Vec<_>>();
for e in out_edges {
self.internal_delete_edge(id, &e);
if e.kind == EdgeKind::Pseudo {
self.remove_pseudo_edge_reasons(id, &e.dest);
}
}
for e in in_edges {
self.internal_delete_back_edge(id, &e);
if e.kind == EdgeKind::Pseudo {
self.remove_pseudo_edge_reasons(&e.dest, id);
}
}
}
pub fn delete_node(&mut self, id: &NodeId) {
assert!(self.nodes.contains(id));
self.nodes.remove(id);
self.deleted_nodes.insert(id.clone());
if !self.deleted_partition.contains(id.clone()) {
self.deleted_partition.insert(id.clone());
}
let out_neighbors = self.all_out_edges(id).cloned().collect::<Vec<_>>();
let in_neighbors = self.all_in_edges(id).cloned().collect::<Vec<_>>();
for e in out_neighbors {
self.delete_opposite_edge(id, &e, true);
}
for e in in_neighbors {
self.delete_opposite_edge(id, &e, false);
}
self.mark_dirty(id);
}
pub fn undelete_node(&mut self, id: &NodeId) {
assert!(self.deleted_nodes.contains(id));
self.deleted_nodes.remove(id);
self.nodes.insert(id.clone());
let out_neighbors = self.all_out_edges(id).cloned().collect::<Vec<_>>();
let in_neighbors = self.all_in_edges(id).cloned().collect::<Vec<_>>();
for e in out_neighbors {
self.undelete_opposite_edge(id, &e, true);
}
for e in in_neighbors {
self.undelete_opposite_edge(id, &e, false);
}
self.mark_dirty(id);
}
fn delete_opposite_edge(&mut self, src: &NodeId, edge: &Edge, edge_points_forwards: bool) {
let opposite_edges = if edge_points_forwards {
&mut self.back_edges
} else {
&mut self.edges
};
if edge.kind == EdgeKind::Pseudo {
let opposite_edge = Edge::new_pseudo(*src);
opposite_edges.remove(&edge.dest, &opposite_edge);
} else {
let mut opposite_edge = Edge::new_live(*src, edge.patch);
opposite_edges.remove(&edge.dest, &opposite_edge);
opposite_edge.kind = EdgeKind::Deleted;
opposite_edges.insert(edge.dest, opposite_edge);
}
if edge.kind == EdgeKind::Deleted {
self.merge_components(src, &edge.dest);
}
}
fn undelete_opposite_edge(&mut self, src: &NodeId, edge: &Edge, edge_points_forwards: bool) {
let opposite_edges = if edge_points_forwards {
&mut self.back_edges
} else {
&mut self.edges
};
let mut opposite_edge = Edge::new_deleted(*src, edge.patch);
opposite_edges.remove(&edge.dest, &opposite_edge);
opposite_edge.kind = EdgeKind::Live;
opposite_edges.insert(edge.dest, opposite_edge);
}
fn merge_components(&mut self, id1: &NodeId, id2: &NodeId) {
let rep1 = self.deleted_partition.representative(*id1);
let rep2 = self.deleted_partition.representative(*id2);
self.deleted_partition.merge(rep1, rep2);
let new_rep = self.deleted_partition.representative(rep1);
self.delete_obsolete_reason(&rep1);
self.delete_obsolete_reason(&rep2);
self.dirty_reps.remove(&rep1);
self.dirty_reps.remove(&rep2);
self.dirty_reps.insert(new_rep);
}
fn delete_obsolete_reason(&mut self, reason: &NodeId) {
let obsolete_pairs = self
.reason_pseudo_edges
.get(reason)
.cloned()
.collect::<Vec<_>>();
for (src, dest) in obsolete_pairs {
let e = Edge::new_pseudo(dest);
self.pseudo_edge_reasons.remove(&(src, dest), reason);
if self.pseudo_edge_reasons.get(&(src, dest)).next().is_none() {
self.internal_delete_edge(&src, &e);
}
}
self.reason_pseudo_edges.remove_all(reason);
}
fn mark_dirty(&mut self, id: &NodeId) {
let rep = self.deleted_partition.representative(*id);
self.delete_obsolete_reason(&rep);
self.dirty_reps.insert(rep);
}
pub fn add_edge(&mut self, from: NodeId, to: NodeId, patch: PatchId) {
let from_deleted = !self.nodes.contains(&from);
let to_deleted = !self.nodes.contains(&to);
assert!(!from_deleted || self.deleted_nodes.contains(&from));
assert!(!to_deleted || self.deleted_nodes.contains(&to));
self.edges
.insert(from, Edge::new_real(to, to_deleted, patch));
self.back_edges
.insert(to, Edge::new_real(from, from_deleted, patch));
if from_deleted && to_deleted {
self.merge_components(&from, &to);
} else if from_deleted {
self.mark_dirty(&from);
} else if to_deleted {
self.mark_dirty(&to);
}
}
pub fn resolve_pseudo_edges(&mut self) {
let mut dirty_reps = Set::new();
std::mem::swap(&mut dirty_reps, &mut self.dirty_reps);
let graggle = self.as_graggle();
let graph = graggle.as_full_graph();
let sub_graph = graph.node_filtered(|u| {
!graggle.is_live(u) && dirty_reps.contains(&self.deleted_partition.representative(*u))
});
let components = sub_graph.weak_components().into_parts();
for rep in dirty_reps {
self.deleted_partition.remove_part(rep);
}
for component in &components {
let mut iter = component.iter();
let rep = iter.next().unwrap();
self.deleted_partition.insert(*rep);
for u in iter {
self.deleted_partition.insert(*u);
self.deleted_partition.merge(*rep, *u);
}
}
for component in components {
self.add_component_pseudo_edges(&component);
}
}
pub fn unadd_edge(&mut self, from: &NodeId, to: &NodeId, patch: PatchId) {
let from_deleted = self.deleted_nodes.contains(&from);
let to_deleted = self.deleted_nodes.contains(&to);
assert!(from_deleted || self.nodes.contains(&from));
assert!(to_deleted || self.nodes.contains(&to));
let forward_edge = Edge::new_real(*to, to_deleted, patch);
let back_edge = Edge::new_real(*from, from_deleted, patch);
self.edges.remove(&from, &forward_edge);
self.back_edges.remove(&to, &back_edge);
if from_deleted {
self.mark_dirty(from);
}
if to_deleted {
self.mark_dirty(to);
}
}
fn add_component_pseudo_edges(&mut self, component: &HashSet<NodeId>) {
let graggle = self.as_graggle();
let graph = graggle.as_full_graph();
let mut neighborhood = graph.neighbor_set(component.iter());
neighborhood.extend(component.iter().cloned());
let rep = self
.deleted_partition
.representative(*component.iter().next().unwrap());
let boundary = neighborhood.iter().filter(|u| graggle.is_live(u));
let mut pairs = Vec::new();
for u in boundary {
let sub_graph = graph.edge_filtered(|src, edge| {
(src == u && component.contains(&edge.dest)) || component.contains(src)
});
for visit in sub_graph.dfs_from(u) {
if let ojo_graph::dfs::Visit::Edge { dst, status, .. } = visit {
if status == ojo_graph::dfs::Status::New && graggle.is_live(&dst) {
pairs.push((*u, dst));
}
}
}
}
for (src, dest) in pairs {
if !self.has_live_edge(&src, &dest) {
self.edges.insert(src, Edge::new_pseudo(dest));
self.back_edges.insert(dest, Edge::new_pseudo(src));
self.pseudo_edge_reasons.insert((src, dest), rep);
self.reason_pseudo_edges.insert(rep, (src, dest));
}
}
}
fn is_live(&self, node: &NodeId) -> bool {
self.nodes.contains(node)
}
fn pseudo_edges(&self, u: &NodeId) -> HashSet<NodeId> {
use ojo_graph::dfs::{Status, Visit};
let mut ret = HashSet::new();
let graph = self.as_graggle().as_full_graph();
let u_graph = graph.edge_filtered(|src, edge| {
edge.kind != EdgeKind::Pseudo
&& ((src == u && !self.is_live(&edge.dest)) || !self.is_live(src))
});
for visit in u_graph.dfs_from(u) {
if let Visit::Edge { dst, status, .. } = visit {
if status == Status::New
&& dst != *u
&& self.is_live(&dst)
&& !self.has_live_edge(u, &dst)
{
ret.insert(dst);
}
}
}
ret
}
pub fn assert_consistent(&self) {
assert!(self.nodes.is_disjoint(&self.deleted_nodes));
let node_exists = |id| self.nodes.contains(id) || self.deleted_nodes.contains(id);
let mut seen_back_edges = HashSet::new();
for (src, edge) in self.edges.iter() {
assert!(node_exists(src));
assert!(node_exists(&edge.dest));
assert!(src != &edge.dest);
assert_eq!(
self.deleted_nodes.contains(&edge.dest),
edge.kind == EdgeKind::Deleted
);
let back_edge = Edge {
dest: *src,
kind: if edge.kind == EdgeKind::Pseudo {
EdgeKind::Pseudo
} else {
EdgeKind::from_deleted(self.deleted_nodes.contains(src))
},
patch: edge.patch,
};
assert!(self.back_edges.contains(&edge.dest, &back_edge));
seen_back_edges.insert((edge.dest, back_edge));
}
for (src, back_edge) in self.back_edges.iter() {
assert!(seen_back_edges.contains(&(*src, *back_edge)));
}
for u in &self.deleted_nodes {
assert!(self.deleted_partition.contains(*u));
}
if self.dirty_reps.is_empty() {
for u in self.deleted_partition.iter_parts().flat_map(|p| p) {
assert!(self.deleted_nodes.contains(&u));
}
for (src, edge) in self.edges.iter() {
if edge.kind == EdgeKind::Pseudo {
assert!(self
.pseudo_edge_reasons
.get(&(*src, edge.dest))
.next()
.is_some());
}
}
for (&(src, dest), _) in self.pseudo_edge_reasons.iter() {
assert!(self.edges.contains(&src, &Edge::new_pseudo(dest)));
}
for (reason, _) in self.reason_pseudo_edges.iter() {
assert!(self.deleted_partition.is_rep(reason));
}
for u in &self.nodes {
let correct_pseudo_edges = self.pseudo_edges(u);
let actual_pseudo_edges = self
.all_out_edges(u)
.filter(|e| e.kind == EdgeKind::Pseudo)
.map(|e| e.dest)
.collect::<HashSet<_>>();
assert_eq!(correct_pseudo_edges, actual_pseudo_edges);
}
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct Graggle<'a> {
data: &'a GraggleData,
}
impl<'a> Graggle<'a> {
pub fn nodes(self) -> impl Iterator<Item = NodeId> + 'a {
self.data.nodes.iter().cloned()
}
pub fn out_edges(self, node: &NodeId) -> impl Iterator<Item = &'a Edge> + 'a {
self.data.edges.get(node).take_while(|e| e.not_deleted())
}
pub fn out_neighbors(self, node: &NodeId) -> impl Iterator<Item = &'a NodeId> + 'a {
self.out_edges(node).map(|e| &e.dest)
}
pub fn in_neighbors(self, node: &NodeId) -> impl Iterator<Item = &'a NodeId> + 'a {
self.in_edges(node).map(|e| &e.dest)
}
pub fn all_out_edges(self, node: &NodeId) -> impl Iterator<Item = &'a Edge> + 'a {
self.data.edges.get(node)
}
pub fn in_edges(self, node: &NodeId) -> impl Iterator<Item = &'a Edge> + 'a {
self.data
.back_edges
.get(node)
.take_while(|e| e.not_deleted())
}
pub fn all_in_edges(self, node: &NodeId) -> impl Iterator<Item = &'a Edge> + 'a {
self.data.back_edges.get(node)
}
pub fn has_node(self, node: &NodeId) -> bool {
self.data.nodes.contains(node) || self.data.deleted_nodes.contains(node)
}
pub fn is_live(self, node: &NodeId) -> bool {
assert!(self.has_node(node));
self.data.nodes.contains(node)
}
pub fn as_live_graph(self) -> LiveGraph<'a> {
LiveGraph(self)
}
pub fn as_full_graph(self) -> FullGraph<'a> {
FullGraph(self)
}
}
impl<'a> From<&'a GraggleData> for Graggle<'a> {
fn from(d: &'a GraggleData) -> Graggle<'a> {
Graggle { data: d }
}
}
pub struct LiveGraph<'a>(Graggle<'a>);
impl<'a> ojo_graph::Graph for LiveGraph<'a> {
type Node = NodeId;
type Edge = Edge;
fn nodes<'b>(&'b self) -> Box<dyn Iterator<Item = Self::Node> + 'b> {
Box::new(self.0.data.nodes.iter().cloned())
}
fn out_edges<'b>(&'b self, u: &NodeId) -> Box<dyn Iterator<Item = Self::Edge> + 'b> {
Box::new(self.0.out_edges(u).cloned())
}
fn in_edges<'b>(&'b self, u: &NodeId) -> Box<dyn Iterator<Item = Self::Edge> + 'b> {
Box::new(self.0.in_edges(u).cloned())
}
}
pub struct FullGraph<'a>(Graggle<'a>);
impl<'a> ojo_graph::Graph for FullGraph<'a> {
type Node = NodeId;
type Edge = Edge;
fn nodes<'b>(&'b self) -> Box<dyn Iterator<Item = Self::Node> + 'b> {
Box::new(
self.0
.data
.nodes
.iter()
.chain(self.0.data.deleted_nodes.iter())
.cloned(),
)
}
fn out_edges<'b>(&'b self, u: &NodeId) -> Box<dyn Iterator<Item = Self::Edge> + 'b> {
Box::new(self.0.all_out_edges(u).cloned())
}
fn in_edges<'b>(&'b self, u: &NodeId) -> Box<dyn Iterator<Item = Self::Edge> + 'b> {
Box::new(self.0.all_in_edges(u).cloned())
}
}
#[cfg(test)]
#[macro_use]
pub mod tests;