diff --git a/src/hugr/validate.rs b/src/hugr/validate.rs index 5e4438fee..a5a3b33b9 100644 --- a/src/hugr/validate.rs +++ b/src/hugr/validate.rs @@ -22,6 +22,7 @@ use crate::ops::{OpTag, OpTrait, OpType, ValidateOp}; use crate::types::{EdgeKind, Type}; use crate::{Direction, Hugr, Node, Port}; +use super::views::petgraph::PetgraphWrapper; use super::views::{HierarchyView, HugrView, SiblingGraph}; use super::NodeType; @@ -99,7 +100,8 @@ impl<'a, 'b> ValidationContext<'a, 'b> { /// The results of this computation should be cached in `self.dominators`. /// We don't do it here to avoid mutable borrows. fn compute_dominator(&self, parent: Node) -> Dominators { - let region: SiblingGraph = SiblingGraph::new(self.hugr, parent); + let region: PetgraphWrapper = + PetgraphWrapper::new(SiblingGraph::new(self.hugr, parent)); let entry_node = self.hugr.children(parent).next().unwrap(); dominators::simple_fast(®ion, entry_node) } @@ -364,7 +366,8 @@ impl<'a, 'b> ValidationContext<'a, 'b> { return Ok(()); }; - let region: SiblingGraph = SiblingGraph::new(self.hugr, parent); + let region: PetgraphWrapper = + PetgraphWrapper::new(SiblingGraph::new(self.hugr, parent)); let postorder = Topo::new(®ion); let nodes_visited = postorder.iter(®ion).filter(|n| *n != parent).count(); let node_count = self.hugr.children(parent).count(); diff --git a/src/hugr/views.rs b/src/hugr/views.rs index c05313569..b146316aa 100644 --- a/src/hugr/views.rs +++ b/src/hugr/views.rs @@ -8,6 +8,7 @@ pub mod sibling_subgraph; #[cfg(test)] mod tests; +pub use self::petgraph::PetgraphWrapper; pub use descendants::DescendantsGraph; pub use sibling::SiblingGraph; pub use sibling_subgraph::SiblingSubgraph; @@ -22,7 +23,6 @@ use crate::ops::handle::NodeHandle; use crate::ops::{FuncDecl, FuncDefn, OpName, OpTag, OpType, DFG}; use crate::types::{EdgeKind, FunctionType}; use crate::{Direction, Node, Port}; -use ::petgraph::visit as pv; /// A trait for inspecting HUGRs. /// For end users we intend this to be superseded by region-specific APIs. @@ -232,19 +232,7 @@ pub trait HugrView: sealed::HugrInternals { } /// A common trait for views of a HUGR hierarchical subgraph. -pub trait HierarchyView<'a>: - HugrView - + pv::GraphBase - + pv::GraphProp - + pv::NodeCount - + pv::NodeIndexable - + pv::EdgeCount - + pv::Visitable - + pv::GetAdjacencyMatrix - + pv::Visitable -where - for<'g> &'g Self: pv::IntoNeighborsDirected + pv::IntoNodeIdentifiers, -{ +pub trait HierarchyView<'a>: HugrView { /// The base from which the subgraph is derived. type Base; diff --git a/src/hugr/views/descendants.rs b/src/hugr/views/descendants.rs index cf0262be3..508517f40 100644 --- a/src/hugr/views/descendants.rs +++ b/src/hugr/views/descendants.rs @@ -21,8 +21,8 @@ type RegionGraph<'g> = portgraph::view::Region<'g, &'g MultiPortGraph>; /// its immediate children. Prefer using [`SiblingGraph`] when possible, /// as it is more efficient. /// -/// Implements the [`HierarchyView`] trait, as well as [`HugrView`] and petgraph's -/// _visit_ traits, so can be used interchangeably with [`SiblingGraph`]. +/// Implements the [`HierarchyView`] trait, as well as [`HugrView`], it can be +/// used interchangeably with [`SiblingGraph`]. /// /// [`SiblingGraph`]: super::SiblingGraph pub struct DescendantsGraph<'g, Root = Node, Base = Hugr> diff --git a/src/hugr/views/petgraph.rs b/src/hugr/views/petgraph.rs index 85eddb2ca..59b152f8e 100644 --- a/src/hugr/views/petgraph.rs +++ b/src/hugr/views/petgraph.rs @@ -1,201 +1,251 @@ //! Implementations of petgraph's traits for Hugr Region views. -use super::{DescendantsGraph, SiblingGraph}; -use crate::hugr::views::sealed::HugrInternals; use crate::hugr::HugrView; -use crate::ops::handle::NodeHandle; use crate::ops::OpType; use crate::types::EdgeKind; -use crate::{Hugr, Node, Port}; +use crate::{Node, Port}; use context_iterators::{ContextIterator, IntoContextIterator, MapWithCtx}; +use delegate::delegate; use petgraph::visit as pv; use portgraph::NodeIndex; -/// A trait grouping the multiple petgraph traits implemented on Hugrs -// -// TODO: We could just require these in `HugrView`. -pub trait PetgraphHugr: - HugrView - + pv::GraphBase - + pv::GraphProp - + pv::NodeCount - + pv::NodeIndexable - + pv::EdgeCount - + pv::Visitable - + pv::GetAdjacencyMatrix - + pv::Visitable +use super::sealed::HugrInternals; + +/// Wrapper for a HugrView that implements petgraph's traits. +/// +/// It can be used to apply petgraph's algorithms to a Hugr. +#[derive(Debug, Clone, Copy)] +pub struct PetgraphWrapper { + hugr: T, +} + +impl PetgraphWrapper where - for<'g> &'g Self: pv::IntoNeighborsDirected + pv::IntoNodeIdentifiers, + T: HugrView, { + /// Wrap a HugrView in a PetgraphWrapper. + pub fn new(hugr: T) -> Self { + Self { hugr } + } } -impl<'g> pv::IntoNodeReferences for &'g Hugr { - type NodeRef = HugrNodeRef<'g>; - type NodeReferences = MapWithCtx<::Nodes<'g>, Self, HugrNodeRef<'g>>; +impl pv::GraphBase for PetgraphWrapper +where + T: HugrView, +{ + type NodeId = Node; + type EdgeId = ((Node, Port), (Node, Port)); +} - fn node_references(self) -> Self::NodeReferences { - self.nodes() - .with_context(self) - .map_with_context(|n, &hugr| HugrNodeRef::from_node(n, hugr)) - } +impl pv::GraphProp for PetgraphWrapper +where + T: HugrView, +{ + type EdgeType = petgraph::Directed; } -macro_rules! impl_petgraph_into_noderefs { - ($hugr:ident) => { - impl<'g, 'a, Root, Base> pv::IntoNodeReferences for &'g $hugr<'a, Root, Base> - where - Root: NodeHandle, - 'g: 'a, - Base: HugrInternals + HugrView, - { - type NodeRef = HugrNodeRef<'a>; - type NodeReferences = - MapWithCtx<<$hugr<'a, Root, Base> as HugrView>::Nodes<'a>, Self, HugrNodeRef<'a>>; +impl pv::NodeCount for PetgraphWrapper +where + T: HugrView, +{ + fn node_count(&self) -> usize { + HugrView::node_count(self) + } +} - fn node_references(self) -> Self::NodeReferences { - self.nodes() - .with_context(self) - .map_with_context(|n, &hugr| HugrNodeRef::from_node(n, hugr)) - } - } - }; -} - -macro_rules! impl_region_petgraph_traits { - ($hugr:ident) => { - impl_region_petgraph_traits!($hugr<>); - }; - ($hugr:ident < $($l:lifetime,)? $($v:ident $(:$b:tt $(+ $b2:tt)*)?),* > ) => { - impl <$($l,)? $($v $(:$b $(+ $b2)*)?),*> pv::GraphBase for $hugr<$($l,)? $($v),*> - { - type NodeId = Node; - type EdgeId = ((Node, Port), (Node, Port)); - } +impl pv::NodeIndexable for PetgraphWrapper +where + T: HugrView, +{ + fn node_bound(&self) -> usize { + HugrView::node_count(self) + } - impl <$($l,)? $($v $(:$b $(+ $b2)*)?),*> pv::GraphProp for $hugr<$($l,)? $($v),*> - { - type EdgeType = petgraph::Directed; - } + fn to_index(&self, ix: Self::NodeId) -> usize { + ix.index.into() + } - impl <$($l,)? $($v $(:$b $(+ $b2)*)?),*> pv::NodeCount for $hugr<$($l,)? $($v),*> - { - fn node_count(&self) -> usize { - HugrView::node_count(self) - } - } + fn from_index(&self, ix: usize) -> Self::NodeId { + NodeIndex::new(ix).into() + } +} - impl <$($l,)? $($v $(:$b $(+ $b2)*)?),*> pv::NodeIndexable for $hugr<$($l,)? $($v),*> - { - fn node_bound(&self) -> usize { - HugrView::node_count(self) - } +impl pv::EdgeCount for PetgraphWrapper +where + T: HugrView, +{ + fn edge_count(&self) -> usize { + HugrView::edge_count(self) + } +} - fn to_index(&self, ix: Self::NodeId) -> usize { - ix.index.into() - } +impl pv::Data for PetgraphWrapper +where + T: HugrView, +{ + type NodeWeight = OpType; + type EdgeWeight = EdgeKind; +} - fn from_index(&self, ix: usize) -> Self::NodeId { - NodeIndex::new(ix).into() - } - } +impl<'g, T> pv::IntoNodeReferences for &'g PetgraphWrapper +where + T: HugrView, +{ + type NodeRef = HugrNodeRef<'g>; + type NodeReferences = MapWithCtx<::Nodes<'g>, Self, HugrNodeRef<'g>>; - impl <$($l,)? $($v $(:$b $(+ $b2)*)?),*> pv::EdgeCount for $hugr<$($l,)? $($v),*> - { - fn edge_count(&self) -> usize { - HugrView::edge_count(self) - } - } + fn node_references(self) -> Self::NodeReferences { + self.nodes() + .with_context(self) + .map_with_context(|n, &hugr| HugrNodeRef::from_node(n, hugr)) + } +} - impl <$($l,)? $($v $(:$b $(+ $b2)*)?),*> pv::Data for $hugr<$($l,)? $($v),*> - { - type NodeWeight = OpType; - type EdgeWeight = EdgeKind; - } +impl<'g, T> pv::IntoNodeIdentifiers for &'g PetgraphWrapper +where + T: HugrView, +{ + type NodeIdentifiers = ::Nodes<'g>; - impl <'g, $($l,)? $($v $(:$b $(+ $b2)*)?),*> pv::IntoNodeIdentifiers for &'g $hugr<$($l,)? $($v),*> - { - type NodeIdentifiers = <$hugr<$($l,)? $($v),*> as HugrView>::Nodes<'g>; + fn node_identifiers(self) -> Self::NodeIdentifiers { + self.nodes() + } +} - fn node_identifiers(self) -> Self::NodeIdentifiers { - self.nodes() - } - } +impl<'g, T> pv::IntoNeighbors for &'g PetgraphWrapper +where + T: HugrView, +{ + type Neighbors = ::Neighbours<'g>; - impl <'g, $($l,)? $($v $(:$b $(+ $b2)*)?),*> pv::IntoNeighbors for &'g $hugr<$($l,)? $($v),*> - { - type Neighbors = <$hugr<$($l,)? $($v),*> as HugrView>::Neighbours<'g>; + fn neighbors(self, n: Self::NodeId) -> Self::Neighbors { + self.output_neighbours(n) + } +} - fn neighbors(self, n: Self::NodeId) -> Self::Neighbors { - self.output_neighbours(n) - } - } +impl<'g, T> pv::IntoNeighborsDirected for &'g PetgraphWrapper +where + T: HugrView, +{ + type NeighborsDirected = ::Neighbours<'g>; + + fn neighbors_directed( + self, + n: Self::NodeId, + d: petgraph::Direction, + ) -> Self::NeighborsDirected { + self.neighbours(n, d.into()) + } +} - impl <'g, $($l,)? $($v $(:$b $(+ $b2)*)?),*> pv::IntoNeighborsDirected for &'g $hugr<$($l,)? $($v),*> - { - type NeighborsDirected = <$hugr<$($l,)? $($v),*> as HugrView>::Neighbours<'g>; +impl pv::Visitable for PetgraphWrapper +where + T: HugrView, +{ + type Map = std::collections::HashSet; - fn neighbors_directed( - self, - n: Self::NodeId, - d: petgraph::Direction, - ) -> Self::NeighborsDirected { - self.neighbours(n, d.into()) - } - } + fn visit_map(&self) -> Self::Map { + std::collections::HashSet::new() + } - impl <$($l,)? $($v $(:$b $(+ $b2)*)?),*> pv::Visitable for $hugr<$($l,)? $($v),*> - { - type Map = std::collections::HashSet; + fn reset_map(&self, map: &mut Self::Map) { + map.clear(); + } +} - fn visit_map(&self) -> Self::Map { - std::collections::HashSet::new() - } +impl pv::GetAdjacencyMatrix for PetgraphWrapper +where + T: HugrView, +{ + type AdjMatrix = std::collections::HashSet<(Self::NodeId, Self::NodeId)>; - fn reset_map(&self, map: &mut Self::Map) { - map.clear(); + fn adjacency_matrix(&self) -> Self::AdjMatrix { + let mut matrix = std::collections::HashSet::new(); + for node in self.nodes() { + for neighbour in self.output_neighbours(node) { + matrix.insert((node, neighbour)); } } + matrix + } - impl <$($l,)? $($v $(:$b $(+ $b2)*)?),*> pv::GetAdjacencyMatrix for $hugr<$($l,)? $($v),*> - { - type AdjMatrix = std::collections::HashSet<(Self::NodeId, Self::NodeId)>; - - fn adjacency_matrix(&self) -> Self::AdjMatrix { - let mut matrix = std::collections::HashSet::new(); - for node in self.nodes() { - for neighbour in self.output_neighbours(node) { - matrix.insert((node, neighbour)); - } - } - matrix - } + fn is_adjacent(&self, matrix: &Self::AdjMatrix, a: Self::NodeId, b: Self::NodeId) -> bool { + matrix.contains(&(a, b)) + } +} - fn is_adjacent( - &self, - matrix: &Self::AdjMatrix, - a: Self::NodeId, - b: Self::NodeId, - ) -> bool { - matrix.contains(&(a, b)) - } +impl HugrInternals for PetgraphWrapper +where + T: HugrView, +{ + type Portgraph<'p> = ::Portgraph<'p> + where + Self: 'p; + + delegate! { + to self.hugr { + fn portgraph(&self) -> Self::Portgraph<'_>; + fn base_hugr(&self) -> &crate::Hugr; + fn root_node(&self) -> Node; } + } +} - impl <$($l,)? $($v $(:$b $(+ $b2)*)?),*> PetgraphHugr for $hugr<$($l,)? $($v),*> - { +impl HugrView for PetgraphWrapper +where + T: HugrView, +{ + type RootHandle = T::RootHandle; + + type Nodes<'a> = T::Nodes<'a> + where + Self: 'a; + + type NodePorts<'a> = T::NodePorts<'a> + where + Self: 'a; + + type Children<'a> = T::Children<'a> + where + Self: 'a; + + type Neighbours<'a> = T::Neighbours<'a> + where + Self: 'a; + + type PortLinks<'a> = T::PortLinks<'a> + where + Self: 'a; + + type NodeConnections<'a> = T::NodeConnections<'a> + where + Self: 'a; + + delegate! { + to self.hugr { + fn contains_node(&self, node: Node) -> bool; + fn get_parent(&self, node: Node) -> Option; + fn get_optype(&self, node: Node) -> &OpType; + fn get_nodetype(&self, node: Node) -> &crate::hugr::NodeType; + fn get_metadata(&self, node: Node) -> &crate::hugr::NodeMetadata; + fn node_count(&self) -> usize; + fn edge_count(&self) -> usize; + fn nodes(&self) -> Self::Nodes<'_>; + fn node_ports(&self, node: Node, dir: crate::Direction) -> Self::NodePorts<'_>; + fn all_node_ports(&self, node: Node) -> Self::NodePorts<'_>; + fn linked_ports(&self, node: Node, port: Port) -> Self::PortLinks<'_>; + fn node_connections(&self, node: Node, other: Node) -> Self::NodeConnections<'_>; + fn num_ports(&self, node: Node, dir: crate::Direction) -> usize; + fn children(&self, node: Node) -> Self::Children<'_>; + fn neighbours(&self, node: Node, dir: crate::Direction) -> Self::Neighbours<'_>; + fn all_neighbours(&self, node: Node) -> Self::Neighbours<'_>; + fn get_io(&self, node: Node) -> Option<[Node; 2]>; + fn get_function_type(&self) -> Option<&crate::types::FunctionType>; } - }; + } } -impl_region_petgraph_traits!(Hugr); - -impl_petgraph_into_noderefs!(SiblingGraph); -impl_petgraph_into_noderefs!(DescendantsGraph); -impl_region_petgraph_traits!(SiblingGraph<'a, Root: NodeHandle, Base: HugrInternals + HugrView>); -impl_region_petgraph_traits!( - DescendantsGraph<'a, Root: NodeHandle, Base: HugrInternals + HugrView> -); - /// Reference to a Hugr node and its associated OpType. #[derive(Debug, Clone, Copy)] pub struct HugrNodeRef<'a> { diff --git a/src/hugr/views/sibling.rs b/src/hugr/views/sibling.rs index 84532831a..86bc142d3 100644 --- a/src/hugr/views/sibling.rs +++ b/src/hugr/views/sibling.rs @@ -21,8 +21,8 @@ type FlatRegionGraph<'g> = portgraph::view::FlatRegion<'g, &'g MultiPortGraph>; /// /// See [`DescendantsGraph`] for a view that includes all descendants of the root. /// -/// Implements the [`HierarchyView`] trait, as well as [`HugrView`] and petgraph's -/// _visit_ traits, so can be used interchangeably with [`DescendantsGraph`]. +/// Implements the [`HierarchyView`] trait, as well as [`HugrView`], it can be +/// used interchangeably with [`DescendantsGraph`]. /// /// [`DescendantsGraph`]: super::DescendantsGraph pub struct SiblingGraph<'g, Root = Node, Base = Hugr>