Skip to content

Commit d64c456

Browse files
committed
Fixed bafna_fvs
1 parent 5b8c6e0 commit d64c456

1 file changed

Lines changed: 38 additions & 19 deletions

File tree

bafna_fvs.py

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,48 +2,66 @@
22

33

44
def cleanup(G):
5-
new_G = G.copy()
65
while True:
7-
to_remove = [node for node in new_G.nodes if new_G.degree(node) <= 1]
6+
to_remove = [node for node in G.nodes if G.degree(node) <= 1]
87
if len(to_remove) == 0:
98
break
10-
new_G.remove_nodes_from(to_remove)
9+
G.remove_nodes_from(to_remove)
1110

12-
return new_G
11+
return G
1312

1413

1514
def find_semidisjoint_cycle(G):
16-
for cycle in nx.cycle_basis(G):
17-
cnt = 0
18-
for node in cycle:
19-
if G.degree(node) != 2:
20-
cnt += 1
21-
if cnt > 1:
22-
break
23-
if cnt <= 1:
24-
return cycle
15+
degree_2 = {n for n, d in G.degree() if d == 2}
16+
if len(degree_2) == 0:
17+
return None
18+
19+
sg_d2 = nx.subgraph(G, degree_2)
20+
visited = set()
21+
22+
for node in degree_2:
23+
if node in visited:
24+
continue
25+
26+
component = list(nx.node_connected_component(sg_d2, node))
27+
visited.update(component)
28+
sg_comp = nx.subgraph(G, component)
29+
30+
# If in the component the number of edges equals the number of nodes, then it's a cycle
31+
if 0 < len(component) == sg_comp.number_of_edges():
32+
return component
33+
34+
# Else, we need to check if it's a path with endpoints connected to a common junction node
35+
endpoints = [n for n in component if sg_comp.degree(n) <= 1]
36+
if len(endpoints) == 2:
37+
ep1, ep2 = endpoints
38+
nb_1 = {n for n in G.neighbors(ep1) if n not in component}
39+
nb_2 = {n for n in G.neighbors(ep2) if n not in component}
40+
common_junctions = {n for n in nb_1 & nb_2 if G.degree(n) > 2}
41+
42+
if len(common_junctions) > 0:
43+
return component + [list(common_junctions)[0]]
44+
2545
return None
2646

2747

2848
def get_fvs(og_G):
2949
F = set()
30-
i = 0
3150
stack = []
3251
G = og_G.copy()
3352

3453
while len(G.nodes) > 0:
35-
i += 1
3654
sd_cycle = find_semidisjoint_cycle(G)
3755
if sd_cycle is not None:
3856
for node in sd_cycle:
39-
G.node[node]["weight"] = 0.0
57+
G.nodes[node]["weight"] = 0.0
4058

4159
else:
4260
gamma = min(1 / (G.degree(node) - 1) for node in G.nodes)
4361
for node in G.nodes:
4462
G.nodes[node]["weight"] -= gamma * (G.degree(node) - 1)
4563

46-
to_remove = [node for node in G.nodes if G.nodes[node]["weight"] == 0.0]
64+
to_remove = [node for node in G.nodes if G.nodes[node]["weight"] <= 0.0]
4765
F.update(to_remove)
4866
G.remove_nodes_from(to_remove)
4967
stack.extend(to_remove)
@@ -52,14 +70,15 @@ def get_fvs(og_G):
5270
while len(stack) > 0:
5371
node = stack.pop()
5472
sg = nx.subgraph(og_G, og_G.nodes - (F - {node}))
55-
if nx.is_forest(sg):
73+
# With this check, it should ensure that each call for nx.is_forest is in O(|V|) time since |E| < |V|
74+
if G.number_of_edges() <= G.number_of_nodes() - 1 and nx.is_forest(sg):
5675
F.remove(node)
5776

5877
return F
5978

6079

6180
def get_decycling_number_2_approx(G):
62-
clean_G = cleanup(G)
81+
clean_G = cleanup(G.copy())
6382
for node in clean_G.nodes:
6483
clean_G.nodes[node]["weight"] = 1.0
6584

0 commit comments

Comments
 (0)