33
44
55def get_generalized_neighbors (G , F , active_v , v ):
6+ """
7+ Return the generalized neighbors of node v in graph G.
8+ The generalized neighborhood is defined as the neighbors of v that are
9+ not in set F, plus vertices that share a common neighbor (belonging to F excluding the active vertex) with v .
10+
11+ Args:
12+ G (networkx.Graph): A networkx graph.
13+ F: Set of vertices.
14+ active_v: Currently active vertex (may be None).
15+ v: Vertex for which generalized neighbors are computed.
16+
17+ Returns:
18+ set: Set of generalized neighbors of v.
19+ """
620 gen_nb = set (nx .neighbors (G , v )) - F
721 excl = {active_v } if active_v is not None else set ()
822 ens = set (nx .neighbors (G , v )) & (F - excl )
@@ -13,6 +27,15 @@ def get_generalized_neighbors(G, F, active_v, v):
1327
1428
1529def get_non_trivial_components (G ):
30+ """
31+ Return connected components of G that have size greater than 1.
32+
33+ Args:
34+ G (networkx.Graph): A networkx graph.
35+
36+ Returns:
37+ list: List of sets, each containing the vertices of a connected component of size > 1.
38+ """
1639 components = []
1740 for c in nx .connected_components (G ):
1841 if len (c ) > 1 :
@@ -22,10 +45,23 @@ def get_non_trivial_components(G):
2245
2346
2447def find_short_pair (G , F , active_v ):
48+ """
49+ Find a short-pair of vertices (u, v).
50+
51+ A cycle is a short-cycle if it contains exactly 2 vertices that do not belong to F.
52+ These two vertices form a short-pair if the active vertex is undefined or not adjacent to either of them.
53+
54+ Args:
55+ G (networkx.Graph): A networkx graph.
56+ F: Set of vertices.
57+ active_v: Currently active vertex (may be None).
58+
59+ Returns:
60+ tuple: (u, v) if found, otherwise (None, None).
61+ """
2562 for u , v in itertools .combinations (sorted (set (G .nodes ) - F ), 2 ):
2663 nb_u = set (nx .neighbors (G , u ))
2764 nb_v = set (nx .neighbors (G , v ))
28- # If parallel edges between u and v (so u,v is a short-cycle) or they have a common neighbor in F (also short-cycle)
2965 if (G .number_of_edges (u , v ) > 1 ) or (
3066 G .number_of_edges (u , v ) == 1 and any (w in F for w in nb_u & nb_v )
3167 ):
@@ -36,6 +72,18 @@ def find_short_pair(G, F, active_v):
3672
3773
3874def is_trigger_vertex (G , F , active_v , v ):
75+ """
76+ Checks if vertex v is a trigger-vertex according to the paper's definition.
77+
78+ Args:
79+ G (networkx.Graph): A networkx graph.
80+ F: Set of vertices.
81+ active_v: Currently active vertex.
82+ v: Candidate vertex to test.
83+
84+ Returns:
85+ bool: True if v is a trigger-vertex, False otherwise.
86+ """
3987 nb_active = set (nx .neighbors (G , active_v ))
4088 for u in sorted (nb_active - F ):
4189 gen_nb = get_generalized_neighbors (G , F , active_v , u )
@@ -60,6 +108,17 @@ def is_trigger_vertex(G, F, active_v, v):
60108
61109
62110def find_optimal_v (G , F , active_v ):
111+ """
112+ Select an optimal vertex to process next according to the paper's rules.
113+
114+ Args:
115+ G (networkx.Graph): A networkx graph.
116+ F: A set of vertices.
117+ active_v: Currently active vertex.
118+
119+ Returns:
120+ int: an optimal vertex.
121+ """
63122 nb_active = set (nx .neighbors (G , active_v ))
64123 G_not_F = set (G .nodes ) - F
65124 possible = set ()
@@ -92,6 +151,18 @@ def find_optimal_v(G, F, active_v):
92151
93152
94153def main_procedure (G , F , active_v ):
154+ """
155+ Main procedure described in the paper.
156+ This procedure is called on reduced graphs and computes the MIF length.
157+
158+ Args:
159+ G (networkx.Graph): A networkx graph.
160+ F: Set of vertices.
161+ active_v: Currently active vertex (may be None).
162+
163+ Returns:
164+ int: a MIF size for G given fixed set F.
165+ """
95166 a , b = find_short_pair (G , F , active_v )
96167 if a is not None and b is not None :
97168 return max (
@@ -215,12 +286,22 @@ def main_procedure(G, F, active_v):
215286
216287
217288def get_mif_len (G , F , active_v ):
289+ """
290+ Reduces the graph G according to the paper's rules and computes the size of a maximum induced forest (MIF).
291+
292+ Args:
293+ G (networkx.Graph): A networkx graph.
294+ F: Set of vertices fixed to be in the induced forest.
295+ active_v: Currently active vertex (may be None).
296+
297+ Returns:
298+ int: Size of a maximum induced forest in G given fixed set F.
299+ """
218300 if len (F ) > 1 and not nx .is_forest (nx .subgraph (G , F )):
219301 print ("Can't reduce cause F is not acyclic" )
220302 return Exception
221303
222304 new_G = nx .MultiGraph (G )
223- # Security measure but shouldn't be necessary, the code shouldn't provoque this case
224305 new_F = set (F ) - set ([n for n in F if n not in set (G .nodes )])
225306 S = set ()
226307
@@ -295,6 +376,15 @@ def get_mif_len(G, F, active_v):
295376
296377
297378def get_decycling_number_xiao (G ):
379+ """
380+ Computes the decycling number of a graph G using Xiao's algorithm.
381+
382+ Args:
383+ G (networkx.Graph): A networkx graph.
384+
385+ Returns:
386+ int: Decycling number of G (0 if G is already a forest).
387+ """
298388 if nx .is_forest (G ):
299389 return 0
300390
0 commit comments