1- use crate :: index:: make_index;
1+ use std:: fmt:: { Debug , Display , Formatter } ;
2+
23use petgraph:: graph:: DiGraph ;
34use petgraph:: { Incoming , Outgoing } ;
4- use std:: fmt:: { Debug , Display , Formatter } ;
55
6- make_index ! ( pub NodeIndex ) ;
6+ use crate :: index:: make_index;
7+
8+ make_index ! ( pub ( crate ) NodeIndex ) ;
79
810/// Module kinds of nodes in a [MDTree].
911///
@@ -13,18 +15,18 @@ make_index!(pub NodeIndex);
1315/// The module kinds are determined by the quotient graph of a module that is obtained by taking a
1416/// single node from each child module.
1517#[ derive( Copy , Clone , Hash , Eq , PartialEq , Ord , PartialOrd ) ]
16- pub enum ModuleKind {
18+ pub enum ModuleKind < NodeId : Copy + PartialEq > {
1719 /// A prime module. Its quotient graph has only trivial modules.
1820 Prime ,
1921 /// A series module. Its quotient graph is a complete graph.
2022 Series ,
2123 /// A parallel module. Its quotient graph is an empty graph.
2224 Parallel ,
2325 /// A trivial module with a single vertex. This is leaf node in the [MDTree].
24- Node ( NodeIndex ) ,
26+ Node ( NodeId ) ,
2527}
2628
27- impl Debug for ModuleKind {
29+ impl < NodeId : Debug + Copy + PartialEq > Debug for ModuleKind < NodeId > {
2830 fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
2931 match self {
3032 ModuleKind :: Prime => {
@@ -37,24 +39,42 @@ impl Debug for ModuleKind {
3739 write ! ( f, "Parallel" )
3840 }
3941 ModuleKind :: Node ( v) => {
40- write ! ( f, "{v}" )
42+ write ! ( f, "{v:? }" )
4143 }
4244 }
4345 }
4446}
4547
4648/// A modular decomposition tree. The tree contains at least one node.
4749#[ derive( Clone , Debug ) ]
48- pub struct MDTree {
49- tree : DiGraph < ModuleKind , ( ) > ,
50- root : petgraph :: graph :: NodeIndex ,
50+ pub struct MDTree < NodeId : Copy + PartialEq > {
51+ tree : DiGraph < ModuleKind < NodeId > , ( ) > ,
52+ root : ModuleIndex ,
5153}
5254
5355/// Module identifier.
54- #[ derive( Copy , Clone , Eq , PartialEq , Hash , Debug ) ]
55- pub struct ModuleIndex ( petgraph:: graph:: NodeIndex ) ;
56+ #[ derive( Copy , Clone , Eq , PartialEq , Hash , Ord , PartialOrd ) ]
57+ pub struct ModuleIndex ( pub ( crate ) petgraph:: graph:: NodeIndex ) ;
5658
57- impl MDTree {
59+ impl Debug for ModuleIndex {
60+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
61+ f. debug_tuple ( "ModuleIndex" ) . field ( & self . 0 . index ( ) ) . finish ( )
62+ }
63+ }
64+
65+ impl ModuleIndex {
66+ /// Create new index from `usize`.
67+ pub fn new ( x : usize ) -> Self {
68+ Self ( petgraph:: graph:: NodeIndex :: new ( x) )
69+ }
70+
71+ /// Returns the index as `usize`.
72+ pub fn index ( & self ) -> usize {
73+ self . 0 . index ( )
74+ }
75+ }
76+
77+ impl < NodeId : Copy + PartialEq > MDTree < NodeId > {
5878 /// Create a new modular decomposition tree.
5979 ///
6080 /// Assumes that the input `DiGraph` is rooted tree with node weights
@@ -64,11 +84,12 @@ impl MDTree {
6484 /// Return `NullGraph` if the input graph does not have any nodes.
6585 ///
6686 /// Panics if all nodes have a non-zero in-degree.
67- pub ( crate ) fn from_digraph ( tree : DiGraph < ModuleKind , ( ) > ) -> Result < Self , NullGraphError > {
87+ pub ( crate ) fn from_digraph ( tree : DiGraph < ModuleKind < NodeId > , ( ) > ) -> Result < Self , NullGraphError > {
6888 if tree. node_count ( ) == 0 {
6989 return Err ( NullGraphError ) ;
7090 }
7191 let root = tree. externals ( Incoming ) . next ( ) . expect ( "non-null trees must have a root" ) ;
92+ let root = ModuleIndex ( root) ;
7293 Ok ( Self { tree, root } )
7394 }
7495
@@ -81,18 +102,18 @@ impl MDTree {
81102 /// Return the root node index.
82103 #[ inline( always) ]
83104 pub fn root ( & self ) -> ModuleIndex {
84- ModuleIndex ( self . root )
105+ self . root
85106 }
86107
87108 /// Access the [ModuleKind] of a module.
88109 ///
89110 /// If the module does not exist, return None.
90- pub fn module_kind ( & self , module : ModuleIndex ) -> Option < & ModuleKind > {
111+ pub fn module_kind ( & self , module : ModuleIndex ) -> Option < & ModuleKind < NodeId > > {
91112 self . tree . node_weight ( module. 0 )
92113 }
93114
94115 /// Return an iterator yielding references to [ModuleKind]s for all nodes.
95- pub fn module_kinds ( & self ) -> impl Iterator < Item = & ModuleKind > {
116+ pub fn module_kinds ( & self ) -> impl Iterator < Item = & ModuleKind < NodeId > > {
96117 self . tree . node_weights ( )
97118 }
98119
@@ -102,13 +123,50 @@ impl MDTree {
102123 }
103124
104125 /// Convert to [DiGraph].
105- pub fn into_digraph ( self ) -> DiGraph < ModuleKind , ( ) > {
126+ ///
127+ /// This allows the use of [petgraph] algorithms. Use [ModuleIndex::index] and
128+ /// [petgraph::graph::NodeIndex::new] to convert the root index.
129+ ///
130+ /// ```rust
131+ /// # use std::error::Error;
132+ /// #
133+ /// # fn main() -> Result<(), Box<dyn Error>> {
134+ /// use petgraph::graph::{NodeIndex, UnGraph};
135+ /// use petgraph::visit::Dfs;
136+ /// use modular_decomposition::{modular_decomposition, ModuleKind};
137+ ///
138+ /// let graph = UnGraph::<(), ()>::from_edges([(0, 2), (1, 2), (2, 3), (3, 4), (3, 5)]);
139+ /// let md = modular_decomposition(&graph)?;
140+ ///
141+ /// let root = NodeIndex::new(md.root().index());
142+ /// let digraph = md.into_digraph();
143+ ///
144+ /// let mut dfs = Dfs::new(&digraph, root);
145+ /// let mut node_order = vec![];
146+ /// while let Some(node) = dfs.next(&digraph) { node_order.push(*digraph.node_weight(node).unwrap()); }
147+ ///
148+ /// let expected_node_order = [
149+ /// ModuleKind::Prime,
150+ /// ModuleKind::Node(NodeIndex::new(2)),
151+ /// ModuleKind::Parallel,
152+ /// ModuleKind::Node(NodeIndex::new(0)),
153+ /// ModuleKind::Node(NodeIndex::new(1)),
154+ /// ModuleKind::Node(NodeIndex::new(3)),
155+ /// ModuleKind::Parallel,
156+ /// ModuleKind::Node(NodeIndex::new(4)),
157+ /// ModuleKind::Node(NodeIndex::new(5)),
158+ /// ];
159+ /// assert_eq!(node_order, expected_node_order);
160+ /// # Ok(())
161+ /// # }
162+ /// ```
163+ pub fn into_digraph ( self ) -> DiGraph < ModuleKind < NodeId > , ( ) > {
106164 self . tree
107165 }
108166}
109167
110168/// A graph does not contain any nodes or edges.
111- #[ derive( Copy , Clone , Debug ) ]
169+ #[ derive( Copy , Clone , Debug , Eq , PartialEq , Hash , Ord , PartialOrd ) ]
112170pub struct NullGraphError ;
113171
114172impl Display for NullGraphError {
@@ -118,3 +176,46 @@ impl Display for NullGraphError {
118176}
119177
120178impl std:: error:: Error for NullGraphError { }
179+
180+ #[ cfg( test) ]
181+ mod test {
182+ use petgraph:: graph:: { DiGraph , NodeIndex } ;
183+ use petgraph:: Outgoing ;
184+
185+ use crate :: md_tree:: NullGraphError ;
186+ use crate :: tests:: complete_graph;
187+ use crate :: { modular_decomposition, MDTree , ModuleIndex , ModuleKind } ;
188+
189+ #[ test]
190+ fn mdtree_and_digraph_are_equivalent ( ) {
191+ let graph = complete_graph ( 5 ) ;
192+ let md = modular_decomposition ( & graph) . unwrap ( ) ;
193+ let root = md. root ( ) ;
194+
195+ assert_eq ! ( md. module_kind( root) , Some ( & ModuleKind :: Series ) ) ;
196+
197+ let children: Vec < _ > = md. children ( root) . collect ( ) ;
198+ assert_eq ! ( md. module_kind( children[ 0 ] ) , Some ( & ModuleKind :: Node ( NodeIndex :: new( 0 ) ) ) ) ;
199+
200+ let md = md. into_digraph ( ) ;
201+ let root = NodeIndex :: new ( root. index ( ) ) ;
202+
203+ let children: Vec < _ > = md. neighbors_directed ( root, Outgoing ) . collect ( ) ;
204+ assert_eq ! ( md. node_weight( root) , Some ( & ModuleKind :: Series ) ) ;
205+ assert_eq ! ( md. node_weight( children[ 0 ] ) , Some ( & ModuleKind :: Node ( NodeIndex :: new( 0 ) ) ) ) ;
206+ }
207+
208+ #[ test]
209+ fn null_graph_error ( ) {
210+ let digraph: DiGraph < ModuleKind < NodeIndex > , ( ) > = Default :: default ( ) ;
211+ let err = MDTree :: from_digraph ( digraph) . unwrap_err ( ) ;
212+ assert_eq ! ( err, NullGraphError ) ;
213+ assert_eq ! ( format!( "{}" , err) , "graph does not contain any nodes or edges" . to_string( ) ) ;
214+ }
215+
216+ #[ test]
217+ fn module_index_fmt ( ) {
218+ let idx = ModuleIndex :: new ( 42 ) ;
219+ assert_eq ! ( format!( "{:?}" , idx) , "ModuleIndex(42)" . to_string( ) )
220+ }
221+ }
0 commit comments