@@ -745,7 +745,8 @@ def connected_full_subgraphs(G, edges_only=False, labels=False,
745
745
746
746
747
747
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 ):
749
750
r """
750
751
Return an terator over the induced connected subgraphs of order at most `k`.
751
752
@@ -783,6 +784,10 @@ def connected_subgraph_iterator(G, k=None, bint vertices_only=False,
783
784
connected sub( di) graph only or also non-induced sub( di) graphs.
784
785
This parameter can be set to ``False`` for simple ( di) graphs only.
785
786
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
+
786
791
EXAMPLES::
787
792
788
793
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,
811
816
Subgraph of (): Digraph on 1 vertex,
812
817
Subgraph of (): Digraph on 2 vertices,
813
818
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 ]]
814
821
sage: list( G. connected_subgraph_iterator( k=2, vertices_only=True))
815
822
[[1 ], [1, 2 ], [2 ], [2, 3 ], [2, 4 ], [3 ], [3, 4 ], [4 ]]
816
823
@@ -921,14 +928,15 @@ def connected_subgraph_iterator(G, k=None, bint vertices_only=False,
921
928
sig_check()
922
929
923
930
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
930
934
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
932
940
933
941
# We initialize the loop with vertices u in current, {u+1, ..., n-1}
934
942
# in left, and N(u) in boundary
@@ -970,45 +978,46 @@ def connected_subgraph_iterator(G, k=None, bint vertices_only=False,
970
978
# We yield that new subset
971
979
vertices = [int_to_vertex[a] for a in range (u, n)
972
980
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
982
984
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
993
991
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)
1012
1021
1013
1022
else :
1014
1023
# We cannot extend the current subset, either due to a lack of
0 commit comments