use crate::walker;
use crate::{Dag, WouldCycle};
use petgraph as pg;
use petgraph::algo::{has_path_connecting, DfsSpace};
use petgraph::stable_graph::{DefaultIx, GraphIndex, IndexType, StableDiGraph};
use petgraph::visit::{
GetAdjacencyMatrix, GraphBase, GraphProp, IntoEdgeReferences, IntoEdges, IntoEdgesDirected,
IntoNeighbors, IntoNeighborsDirected, IntoNodeIdentifiers, IntoNodeReferences,
NodeCompactIndexable, NodeCount, NodeIndexable, Visitable,
};
use petgraph::IntoWeightedEdge;
use std::marker::PhantomData;
use std::ops::{Index, IndexMut};
pub use petgraph::graph::{EdgeIndex, EdgeWeightsMut, NodeIndex, NodeWeightsMut};
pub use petgraph::visit::Walker;
#[cfg(feature = "serde-1")]
mod serde;
pub type Edges<'a, E, Ix> = pg::stable_graph::Edges<'a, E, pg::Directed, Ix>;
#[derive(Clone, Debug)]
pub struct StableDag<N, E, Ix: IndexType = DefaultIx> {
graph: StableDiGraph<N, E, Ix>,
cycle_state: DfsSpace<NodeIndex<Ix>, <StableDiGraph<N, E, Ix> as Visitable>::Map>,
}
pub struct Children<N, E, Ix: IndexType> {
walk_edges: pg::stable_graph::WalkNeighbors<Ix>,
_node: PhantomData<N>,
_edge: PhantomData<E>,
}
pub struct Parents<N, E, Ix: IndexType> {
walk_edges: pg::stable_graph::WalkNeighbors<Ix>,
_node: PhantomData<N>,
_edge: PhantomData<E>,
}
pub struct EdgeIndices<Ix: IndexType> {
indices: ::std::ops::Range<usize>,
_phantom: PhantomData<Ix>,
}
pub type RecursiveWalk<N, E, Ix, F> = walker::Recursive<StableDag<N, E, Ix>, F>;
impl<N, E, Ix> StableDag<N, E, Ix>
where
Ix: IndexType,
{
pub fn new() -> Self {
Self::with_capacity(1, 1)
}
pub fn with_capacity(nodes: usize, edges: usize) -> Self {
StableDag {
graph: StableDiGraph::with_capacity(nodes, edges),
cycle_state: DfsSpace::default(),
}
}
pub fn from_edges<I>(edges: I) -> Result<Self, WouldCycle<E>>
where
I: IntoIterator,
I::Item: IntoWeightedEdge<E>,
<I::Item as IntoWeightedEdge<E>>::NodeId: Into<NodeIndex<Ix>>,
N: Default,
{
let mut dag = Self::default();
dag.extend_with_edges(edges)?;
Ok(dag)
}
pub fn extend_with_edges<I>(&mut self, edges: I) -> Result<(), WouldCycle<E>>
where
I: IntoIterator,
I::Item: IntoWeightedEdge<E>,
<I::Item as IntoWeightedEdge<E>>::NodeId: Into<NodeIndex<Ix>>,
N: Default,
{
for edge in edges {
let (source, target, weight) = edge.into_weighted_edge();
let (source, target) = (source.into(), target.into());
let nx = ::std::cmp::max(source, target);
while nx.index() >= self.node_count() {
self.add_node(N::default());
}
self.add_edge(source, target, weight)?;
}
Ok(())
}
pub fn from_elements<I>(elements: I) -> Result<Self, WouldCycle<E>>
where
Self: Sized,
I: IntoIterator<Item = pg::data::Element<N, E>>,
{
let mut dag = Self::default();
for elem in elements {
match elem {
pg::data::Element::Node { weight } => {
dag.add_node(weight);
}
pg::data::Element::Edge {
source,
target,
weight,
} => {
let n = NodeIndex::new(source);
let e = NodeIndex::new(target);
dag.update_edge(n, e, weight)?;
}
}
}
Ok(dag)
}
pub fn map<'a, F, G, N2, E2>(&'a self, node_map: F, edge_map: G) -> StableDag<N2, E2, Ix>
where
F: FnMut(NodeIndex<Ix>, &'a N) -> N2,
G: FnMut(EdgeIndex<Ix>, &'a E) -> E2,
{
let graph = self.graph.map(node_map, edge_map);
let cycle_state = self.cycle_state.clone();
StableDag { graph, cycle_state }
}
pub fn filter_map<'a, F, G, N2, E2>(&'a self, node_map: F, edge_map: G) -> StableDag<N2, E2, Ix>
where
F: FnMut(NodeIndex<Ix>, &'a N) -> Option<N2>,
G: FnMut(EdgeIndex<Ix>, &'a E) -> Option<E2>,
{
let graph = self.graph.filter_map(node_map, edge_map);
let cycle_state = DfsSpace::new(&graph);
StableDag { graph, cycle_state }
}
pub fn clear(&mut self) {
self.graph.clear();
}
pub fn node_count(&self) -> usize {
self.graph.node_count()
}
pub fn edge_count(&self) -> usize {
self.graph.edge_count()
}
pub fn graph(&self) -> &StableDiGraph<N, E, Ix> {
&self.graph
}
pub fn into_graph(self) -> StableDiGraph<N, E, Ix> {
let StableDag { graph, .. } = self;
graph
}
pub fn add_node(&mut self, weight: N) -> NodeIndex<Ix> {
self.graph.add_node(weight)
}
pub fn add_edge(
&mut self,
a: NodeIndex<Ix>,
b: NodeIndex<Ix>,
weight: E,
) -> Result<EdgeIndex<Ix>, WouldCycle<E>> {
let should_check_for_cycle = must_check_for_cycle(self, a, b);
let state = Some(&mut self.cycle_state);
if should_check_for_cycle && has_path_connecting(&self.graph, b, a, state) {
return Err(WouldCycle(weight));
}
Ok(self.graph.add_edge(a, b, weight))
}
pub fn add_edges<I>(&mut self, edges: I) -> Result<EdgeIndices<Ix>, WouldCycle<Vec<E>>>
where
I: IntoIterator<Item = (NodeIndex<Ix>, NodeIndex<Ix>, E)>,
{
let mut num_edges = 0;
let mut should_check_for_cycle = false;
for (a, b, weight) in edges {
if !should_check_for_cycle && must_check_for_cycle(self, a, b) {
should_check_for_cycle = true;
}
self.graph.add_edge(a, b, weight);
num_edges += 1;
}
let total_edges = self.edge_count();
let new_edges_range = total_edges - num_edges..total_edges;
if should_check_for_cycle && pg::algo::is_cyclic_directed(&self.graph) {
let removed_edges = new_edges_range.rev().filter_map(|i| {
let idx = EdgeIndex::new(i);
self.graph.remove_edge(idx)
});
Err(WouldCycle(removed_edges.collect()))
} else {
Ok(EdgeIndices {
indices: new_edges_range,
_phantom: ::std::marker::PhantomData,
})
}
}
pub fn update_edge(
&mut self,
a: NodeIndex<Ix>,
b: NodeIndex<Ix>,
weight: E,
) -> Result<EdgeIndex<Ix>, WouldCycle<E>> {
if let Some(edge_idx) = self.find_edge(a, b) {
if let Some(edge) = self.edge_weight_mut(edge_idx) {
*edge = weight;
return Ok(edge_idx);
}
}
self.add_edge(a, b, weight)
}
pub fn find_edge(&self, a: NodeIndex<Ix>, b: NodeIndex<Ix>) -> Option<EdgeIndex<Ix>> {
self.graph.find_edge(a, b)
}
pub fn edge_endpoints(&self, e: EdgeIndex<Ix>) -> Option<(NodeIndex<Ix>, NodeIndex<Ix>)> {
self.graph.edge_endpoints(e)
}
pub fn clear_edges(&mut self) {
self.graph.clear_edges()
}
pub fn add_parent(
&mut self,
child: NodeIndex<Ix>,
edge: E,
node: N,
) -> (EdgeIndex<Ix>, NodeIndex<Ix>) {
let parent_node = self.graph.add_node(node);
let parent_edge = self.graph.add_edge(parent_node, child, edge);
(parent_edge, parent_node)
}
pub fn add_child(
&mut self,
parent: NodeIndex<Ix>,
edge: E,
node: N,
) -> (EdgeIndex<Ix>, NodeIndex<Ix>) {
let child_node = self.graph.add_node(node);
let child_edge = self.graph.add_edge(parent, child_node, edge);
(child_edge, child_node)
}
pub fn node_weight(&self, node: NodeIndex<Ix>) -> Option<&N> {
self.graph.node_weight(node)
}
pub fn node_weight_mut(&mut self, node: NodeIndex<Ix>) -> Option<&mut N> {
self.graph.node_weight_mut(node)
}
pub fn edge_weight(&self, edge: EdgeIndex<Ix>) -> Option<&E> {
self.graph.edge_weight(edge)
}
pub fn edge_weight_mut(&mut self, edge: EdgeIndex<Ix>) -> Option<&mut E> {
self.graph.edge_weight_mut(edge)
}
#[allow(clippy::type_complexity)]
pub fn index_twice_mut<A, B>(
&mut self,
a: A,
b: B,
) -> (
&mut <StableDiGraph<N, E, Ix> as Index<A>>::Output,
&mut <StableDiGraph<N, E, Ix> as Index<B>>::Output,
)
where
StableDiGraph<N, E, Ix>: IndexMut<A> + IndexMut<B>,
A: GraphIndex,
B: GraphIndex,
{
self.graph.index_twice_mut(a, b)
}
pub fn remove_node(&mut self, node: NodeIndex<Ix>) -> Option<N> {
self.graph.remove_node(node)
}
pub fn contains_node(&self, a: NodeIndex<Ix>) -> bool {
self.graph.contains_node(a)
}
pub fn remove_edge(&mut self, e: EdgeIndex<Ix>) -> Option<E> {
self.graph.remove_edge(e)
}
pub fn parents(&self, child: NodeIndex<Ix>) -> Parents<N, E, Ix> {
let walk_edges = self.graph.neighbors_directed(child, pg::Incoming).detach();
Parents {
walk_edges,
_node: PhantomData,
_edge: PhantomData,
}
}
pub fn children(&self, parent: NodeIndex<Ix>) -> Children<N, E, Ix> {
let walk_edges = self.graph.neighbors_directed(parent, pg::Outgoing).detach();
Children {
walk_edges,
_node: PhantomData,
_edge: PhantomData,
}
}
pub fn recursive_walk<F>(
&self,
start: NodeIndex<Ix>,
recursive_fn: F,
) -> RecursiveWalk<N, E, Ix, F>
where
F: FnMut(&Self, NodeIndex<Ix>) -> Option<(EdgeIndex<Ix>, NodeIndex<Ix>)>,
{
walker::Recursive::new(start, recursive_fn)
}
}
fn must_check_for_cycle<N, E, Ix>(
dag: &StableDag<N, E, Ix>,
a: NodeIndex<Ix>,
b: NodeIndex<Ix>,
) -> bool
where
Ix: IndexType,
{
if a == b {
return true;
}
dag.parents(a).walk_next(dag).is_some()
&& dag.children(b).walk_next(dag).is_some()
&& dag.find_edge(a, b).is_none()
}
impl<N, E, Ix> From<StableDag<N, E, Ix>> for StableDiGraph<N, E, Ix>
where
Ix: IndexType,
{
fn from(val: StableDag<N, E, Ix>) -> Self {
val.into_graph()
}
}
impl<N, E, Ix> Default for StableDag<N, E, Ix>
where
Ix: IndexType,
{
fn default() -> Self {
StableDag::new()
}
}
impl<N, E, Ix> GraphBase for StableDag<N, E, Ix>
where
Ix: IndexType,
{
type NodeId = NodeIndex<Ix>;
type EdgeId = EdgeIndex<Ix>;
}
impl<N, E, Ix> NodeCount for StableDag<N, E, Ix>
where
Ix: IndexType,
{
fn node_count(&self) -> usize {
StableDag::node_count(self)
}
}
impl<N, E, Ix> GraphProp for StableDag<N, E, Ix>
where
Ix: IndexType,
{
type EdgeType = pg::Directed;
fn is_directed(&self) -> bool {
true
}
}
impl<N, E, Ix> pg::visit::Visitable for StableDag<N, E, Ix>
where
Ix: IndexType,
{
type Map = <StableDiGraph<N, E, Ix> as Visitable>::Map;
fn visit_map(&self) -> Self::Map {
self.graph.visit_map()
}
fn reset_map(&self, map: &mut Self::Map) {
self.graph.reset_map(map)
}
}
impl<N, E, Ix> pg::visit::Data for StableDag<N, E, Ix>
where
Ix: IndexType,
{
type NodeWeight = N;
type EdgeWeight = E;
}
impl<N, E, Ix> pg::data::DataMap for StableDag<N, E, Ix>
where
Ix: IndexType,
{
fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight> {
self.graph.node_weight(id)
}
fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight> {
self.graph.edge_weight(id)
}
}
impl<N, E, Ix> pg::data::DataMapMut for StableDag<N, E, Ix>
where
Ix: IndexType,
{
fn node_weight_mut(&mut self, id: Self::NodeId) -> Option<&mut Self::NodeWeight> {
self.graph.node_weight_mut(id)
}
fn edge_weight_mut(&mut self, id: Self::EdgeId) -> Option<&mut Self::EdgeWeight> {
self.graph.edge_weight_mut(id)
}
}
impl<'a, N, E, Ix> IntoNeighbors for &'a StableDag<N, E, Ix>
where
Ix: IndexType,
{
type Neighbors = pg::stable_graph::Neighbors<'a, E, Ix>;
fn neighbors(self, n: NodeIndex<Ix>) -> Self::Neighbors {
self.graph.neighbors(n)
}
}
impl<'a, N, E, Ix> IntoNeighborsDirected for &'a StableDag<N, E, Ix>
where
Ix: IndexType,
{
type NeighborsDirected = pg::stable_graph::Neighbors<'a, E, Ix>;
fn neighbors_directed(self, n: NodeIndex<Ix>, d: pg::Direction) -> Self::Neighbors {
self.graph.neighbors_directed(n, d)
}
}
impl<'a, N, E, Ix> IntoEdgeReferences for &'a StableDag<N, E, Ix>
where
Ix: IndexType,
{
type EdgeRef = pg::stable_graph::EdgeReference<'a, E, Ix>;
type EdgeReferences = pg::stable_graph::EdgeReferences<'a, E, Ix>;
fn edge_references(self) -> Self::EdgeReferences {
self.graph.edge_references()
}
}
impl<'a, N, E, Ix> IntoEdges for &'a StableDag<N, E, Ix>
where
Ix: IndexType,
{
type Edges = Edges<'a, E, Ix>;
fn edges(self, a: Self::NodeId) -> Self::Edges {
self.graph.edges(a)
}
}
impl<'a, N, E, Ix> IntoEdgesDirected for &'a StableDag<N, E, Ix>
where
Ix: IndexType,
{
type EdgesDirected = Edges<'a, E, Ix>;
fn edges_directed(self, a: Self::NodeId, dir: pg::Direction) -> Self::EdgesDirected {
self.graph.edges_directed(a, dir)
}
}
impl<'a, N, E, Ix> IntoNodeIdentifiers for &'a StableDag<N, E, Ix>
where
Ix: IndexType,
{
type NodeIdentifiers = pg::stable_graph::NodeIndices<'a, N, Ix>;
fn node_identifiers(self) -> Self::NodeIdentifiers {
self.graph.node_identifiers()
}
}
impl<'a, N, E, Ix> IntoNodeReferences for &'a StableDag<N, E, Ix>
where
Ix: IndexType,
{
type NodeRef = (NodeIndex<Ix>, &'a N);
type NodeReferences = pg::stable_graph::NodeReferences<'a, N, Ix>;
fn node_references(self) -> Self::NodeReferences {
self.graph.node_references()
}
}
impl<N, E, Ix> NodeIndexable for StableDag<N, E, Ix>
where
Ix: IndexType,
{
fn node_bound(&self) -> usize {
self.graph.node_bound()
}
fn to_index(&self, ix: NodeIndex<Ix>) -> usize {
self.graph.to_index(ix)
}
fn from_index(&self, ix: usize) -> Self::NodeId {
self.graph.from_index(ix)
}
}
impl<N, E, Ix> NodeCompactIndexable for StableDag<N, E, Ix> where Ix: IndexType {}
impl<N, E, Ix> Index<NodeIndex<Ix>> for StableDag<N, E, Ix>
where
Ix: IndexType,
{
type Output = N;
fn index(&self, index: NodeIndex<Ix>) -> &N {
&self.graph[index]
}
}
impl<N, E, Ix> IndexMut<NodeIndex<Ix>> for StableDag<N, E, Ix>
where
Ix: IndexType,
{
fn index_mut(&mut self, index: NodeIndex<Ix>) -> &mut N {
&mut self.graph[index]
}
}
impl<N, E, Ix> Index<EdgeIndex<Ix>> for StableDag<N, E, Ix>
where
Ix: IndexType,
{
type Output = E;
fn index(&self, index: EdgeIndex<Ix>) -> &E {
&self.graph[index]
}
}
impl<N, E, Ix> IndexMut<EdgeIndex<Ix>> for StableDag<N, E, Ix>
where
Ix: IndexType,
{
fn index_mut(&mut self, index: EdgeIndex<Ix>) -> &mut E {
&mut self.graph[index]
}
}
impl<N, E, Ix> GetAdjacencyMatrix for StableDag<N, E, Ix>
where
Ix: IndexType,
{
type AdjMatrix = <StableDiGraph<N, E, Ix> as GetAdjacencyMatrix>::AdjMatrix;
fn adjacency_matrix(&self) -> Self::AdjMatrix {
self.graph.adjacency_matrix()
}
fn is_adjacent(&self, matrix: &Self::AdjMatrix, a: NodeIndex<Ix>, b: NodeIndex<Ix>) -> bool {
self.graph.is_adjacent(matrix, a, b)
}
}
impl<'a, N, E, Ix> Walker<&'a StableDag<N, E, Ix>> for Children<N, E, Ix>
where
Ix: IndexType,
{
type Item = (EdgeIndex<Ix>, NodeIndex<Ix>);
#[inline]
fn walk_next(&mut self, dag: &'a StableDag<N, E, Ix>) -> Option<Self::Item> {
self.walk_edges.next(&dag.graph)
}
}
impl<'a, N, E, Ix> Walker<&'a StableDag<N, E, Ix>> for Parents<N, E, Ix>
where
Ix: IndexType,
{
type Item = (EdgeIndex<Ix>, NodeIndex<Ix>);
#[inline]
fn walk_next(&mut self, dag: &'a StableDag<N, E, Ix>) -> Option<Self::Item> {
self.walk_edges.next(&dag.graph)
}
}
impl<Ix> Iterator for EdgeIndices<Ix>
where
Ix: IndexType,
{
type Item = EdgeIndex<Ix>;
fn next(&mut self) -> Option<EdgeIndex<Ix>> {
self.indices.next().map(|i| EdgeIndex::new(i))
}
}
impl<N, E, Ix> From<Dag<N, E, Ix>> for StableDag<N, E, Ix>
where
Ix: IndexType,
{
fn from(g: Dag<N, E, Ix>) -> Self {
StableDag {
graph: StableDiGraph::from(g.graph),
cycle_state: DfsSpace::default(),
}
}
}