Skip to content

Commit 4f52a0e

Browse files
committed
Docs for Xiao
1 parent 96d45d7 commit 4f52a0e

2 files changed

Lines changed: 94 additions & 4 deletions

File tree

fomin.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ def construct_H(G, F, nb):
4545
4646
Args:
4747
G (networkx.Graph): A networkx graph.
48-
F (set): A set of nodes in G.
49-
nb (set): A set of neighbors in G.
48+
F: A set of nodes in G.
49+
nb: A set of neighbors in G.
5050
5151
Returns:
5252
networkx.Graph: The constructed subgraph H.

xiao.py

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,20 @@
33

44

55
def 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

1529
def 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

2447
def 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

3874
def 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

62110
def 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

94153
def 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

217288
def 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

297378
def 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

Comments
 (0)