Skip to content

Commit ed93eda

Browse files
committed
Return subgraphs with exactly k vertices
In response to issue #35857 modified connected_subgraph_iterator to just return the subgraphs of order k. - Added a parameter 'exactly_k
1 parent 3230f00 commit ed93eda

File tree

1 file changed

+54
-45
lines changed

1 file changed

+54
-45
lines changed

src/sage/graphs/base/static_dense_graph.pyx

Lines changed: 54 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,8 @@ def connected_full_subgraphs(G, edges_only=False, labels=False,
745745

746746

747747
def connected_subgraph_iterator(G, k=None, bint vertices_only=False,
748-
edges_only=False, labels=False, induced=True):
748+
edges_only=False, labels=False, induced=True,
749+
exactly_k=False):
749750
r"""
750751
Return an terator over the induced connected subgraphs of order at most `k`.
751752
@@ -783,6 +784,10 @@ def connected_subgraph_iterator(G, k=None, bint vertices_only=False,
783784
connected sub(di)graph only or also non-induced sub(di)graphs.
784785
This parameter can be set to ``False`` for simple (di)graphs only.
785786
787+
- ``exactly_k`` -- boolean (default: ``False``); ``True`` if we only
788+
return graphs of order ``k``, ``False`` if we return graphs of order
789+
at most ``k``.
790+
786791
EXAMPLES::
787792
788793
sage: G = DiGraph([(1, 2), (2, 3), (3, 4), (4, 2)])
@@ -811,6 +816,8 @@ def connected_subgraph_iterator(G, k=None, bint vertices_only=False,
811816
Subgraph of (): Digraph on 1 vertex,
812817
Subgraph of (): Digraph on 2 vertices,
813818
Subgraph of (): Digraph on 1 vertex]
819+
sage: list(G.connected_subgraph_iterator(k=3, vertices_only=True, exactly_k=True))
820+
[[1, 2, 3], [1, 2, 4], [2, 3, 4]]
814821
sage: list(G.connected_subgraph_iterator(k=2, vertices_only=True))
815822
[[1], [1, 2], [2], [2, 3], [2, 4], [3], [3, 4], [4]]
816823
@@ -921,14 +928,15 @@ def connected_subgraph_iterator(G, k=None, bint vertices_only=False,
921928
sig_check()
922929

923930
vertices = [int_to_vertex[u]]
924-
if vertices_only:
925-
yield vertices
926-
else:
927-
H = G.subgraph(vertices)
928-
if edges_only:
929-
yield H.edges(sort=False, labels=labels)
931+
if not exactly_k or mk == 1:
932+
if vertices_only:
933+
yield vertices
930934
else:
931-
yield H
935+
H = G.subgraph(vertices)
936+
if edges_only:
937+
yield H.edges(sort=False, labels=labels)
938+
else:
939+
yield H
932940

933941
# We initialize the loop with vertices u in current, {u+1, ..., n-1}
934942
# in left, and N(u) in boundary
@@ -970,45 +978,46 @@ def connected_subgraph_iterator(G, k=None, bint vertices_only=False,
970978
# We yield that new subset
971979
vertices = [int_to_vertex[a] for a in range(u, n)
972980
if bitset_in(stack.rows[level], a)]
973-
if vertices_only:
974-
yield vertices
975-
else:
976-
H = G.subgraph(vertices)
977-
if induced:
978-
if edges_only:
979-
yield H.edges(sort=False, labels=labels)
980-
else:
981-
yield H
981+
if not exactly_k or bitset_len(current) == mk - 1:
982+
if vertices_only:
983+
yield vertices
982984
else:
983-
# We use a decomposition into biconnected components to
984-
# work on smaller graphs.
985-
if H.is_directed():
986-
blocks = H.to_undirected().blocks_and_cut_vertices()[0]
987-
else:
988-
blocks = H.blocks_and_cut_vertices()[0]
989-
if len(blocks) == 1:
990-
# H is strongly connected or biconnected
991-
yield from connected_full_subgraphs(H, edges_only=edges_only,
992-
labels=labels)
985+
H = G.subgraph(vertices)
986+
if induced:
987+
if edges_only:
988+
yield H.edges(sort=False, labels=labels)
989+
else:
990+
yield H
993991
else:
994-
L = []
995-
for bloc in blocks:
996-
if len(bloc) == 2:
997-
bb = [[e] for e in H.edge_boundary(bloc, bloc, labels=labels)]
998-
if len(bb) == 2:
999-
# H is directed with edges (u, v) and (v, u)
1000-
bb.append(H.edge_boundary(bloc, bloc, labels=labels))
1001-
L.append(bb)
1002-
else:
1003-
L.append(connected_full_subgraphs(H.subgraph(vertices=bloc),
1004-
edges_only=True, labels=labels))
1005-
1006-
for edges in product(*L):
1007-
good_edges = flatten(edges, ltypes=list)
1008-
if edges_only:
1009-
yield list(good_edges)
1010-
else:
1011-
yield H.subgraph(vertices=H, edges=good_edges)
992+
# We use a decomposition into biconnected components to
993+
# work on smaller graphs.
994+
if H.is_directed():
995+
blocks = H.to_undirected().blocks_and_cut_vertices()[0]
996+
else:
997+
blocks = H.blocks_and_cut_vertices()[0]
998+
if len(blocks) == 1:
999+
# H is strongly connected or biconnected
1000+
yield from connected_full_subgraphs(H, edges_only=edges_only,
1001+
labels=labels)
1002+
else:
1003+
L = []
1004+
for bloc in blocks:
1005+
if len(bloc) == 2:
1006+
bb = [[e] for e in H.edge_boundary(bloc, bloc, labels=labels)]
1007+
if len(bb) == 2:
1008+
# H is directed with edges (u, v) and (v, u)
1009+
bb.append(H.edge_boundary(bloc, bloc, labels=labels))
1010+
L.append(bb)
1011+
else:
1012+
L.append(connected_full_subgraphs(H.subgraph(vertices=bloc),
1013+
edges_only=True, labels=labels))
1014+
1015+
for edges in product(*L):
1016+
good_edges = flatten(edges, ltypes=list)
1017+
if edges_only:
1018+
yield list(good_edges)
1019+
else:
1020+
yield H.subgraph(vertices=H, edges=good_edges)
10121021

10131022
else:
10141023
# We cannot extend the current subset, either due to a lack of

0 commit comments

Comments
 (0)