passagemath-graphs 10.6.1rc1__cp310-cp310-musllinux_1_2_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. passagemath_graphs-10.6.1rc1.dist-info/METADATA +292 -0
  2. passagemath_graphs-10.6.1rc1.dist-info/RECORD +260 -0
  3. passagemath_graphs-10.6.1rc1.dist-info/WHEEL +5 -0
  4. passagemath_graphs-10.6.1rc1.dist-info/top_level.txt +2 -0
  5. passagemath_graphs.libs/libgcc_s-69c45f16.so.1 +0 -0
  6. passagemath_graphs.libs/libgmp-8e78bd9b.so.10.5.0 +0 -0
  7. passagemath_graphs.libs/libstdc++-1f1a71be.so.6.0.33 +0 -0
  8. sage/all__sagemath_graphs.py +39 -0
  9. sage/combinat/abstract_tree.py +2723 -0
  10. sage/combinat/all__sagemath_graphs.py +34 -0
  11. sage/combinat/binary_tree.py +5306 -0
  12. sage/combinat/cluster_algebra_quiver/all.py +22 -0
  13. sage/combinat/cluster_algebra_quiver/cluster_seed.py +5208 -0
  14. sage/combinat/cluster_algebra_quiver/interact.py +124 -0
  15. sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
  16. sage/combinat/cluster_algebra_quiver/mutation_type.py +1555 -0
  17. sage/combinat/cluster_algebra_quiver/quiver.py +2290 -0
  18. sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +2468 -0
  19. sage/combinat/designs/MOLS_handbook_data.py +570 -0
  20. sage/combinat/designs/all.py +58 -0
  21. sage/combinat/designs/bibd.py +1655 -0
  22. sage/combinat/designs/block_design.py +1071 -0
  23. sage/combinat/designs/covering_array.py +269 -0
  24. sage/combinat/designs/covering_design.py +530 -0
  25. sage/combinat/designs/database.py +5615 -0
  26. sage/combinat/designs/design_catalog.py +122 -0
  27. sage/combinat/designs/designs_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  28. sage/combinat/designs/designs_pyx.pxd +21 -0
  29. sage/combinat/designs/designs_pyx.pyx +993 -0
  30. sage/combinat/designs/difference_family.py +3951 -0
  31. sage/combinat/designs/difference_matrices.py +279 -0
  32. sage/combinat/designs/evenly_distributed_sets.cpython-310-aarch64-linux-gnu.so +0 -0
  33. sage/combinat/designs/evenly_distributed_sets.pyx +661 -0
  34. sage/combinat/designs/ext_rep.py +1064 -0
  35. sage/combinat/designs/gen_quadrangles_with_spread.cpython-310-aarch64-linux-gnu.so +0 -0
  36. sage/combinat/designs/gen_quadrangles_with_spread.pyx +339 -0
  37. sage/combinat/designs/group_divisible_designs.py +361 -0
  38. sage/combinat/designs/incidence_structures.py +2357 -0
  39. sage/combinat/designs/latin_squares.py +581 -0
  40. sage/combinat/designs/orthogonal_arrays.py +2244 -0
  41. sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
  42. sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-310-aarch64-linux-gnu.so +0 -0
  43. sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +967 -0
  44. sage/combinat/designs/resolvable_bibd.py +815 -0
  45. sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
  46. sage/combinat/designs/subhypergraph_search.cpython-310-aarch64-linux-gnu.so +0 -0
  47. sage/combinat/designs/subhypergraph_search.pyx +530 -0
  48. sage/combinat/designs/twographs.py +306 -0
  49. sage/combinat/finite_state_machine.py +14874 -0
  50. sage/combinat/finite_state_machine_generators.py +2006 -0
  51. sage/combinat/graph_path.py +448 -0
  52. sage/combinat/interval_posets.py +3908 -0
  53. sage/combinat/nu_tamari_lattice.py +269 -0
  54. sage/combinat/ordered_tree.py +1446 -0
  55. sage/combinat/posets/all.py +46 -0
  56. sage/combinat/posets/bubble_shuffle.py +247 -0
  57. sage/combinat/posets/cartesian_product.py +493 -0
  58. sage/combinat/posets/d_complete.py +182 -0
  59. sage/combinat/posets/elements.py +273 -0
  60. sage/combinat/posets/forest.py +30 -0
  61. sage/combinat/posets/hasse_cython.cpython-310-aarch64-linux-gnu.so +0 -0
  62. sage/combinat/posets/hasse_cython.pyx +174 -0
  63. sage/combinat/posets/hasse_diagram.py +3672 -0
  64. sage/combinat/posets/hochschild_lattice.py +158 -0
  65. sage/combinat/posets/incidence_algebras.py +794 -0
  66. sage/combinat/posets/lattices.py +5117 -0
  67. sage/combinat/posets/linear_extension_iterator.cpython-310-aarch64-linux-gnu.so +0 -0
  68. sage/combinat/posets/linear_extension_iterator.pyx +292 -0
  69. sage/combinat/posets/linear_extensions.py +1037 -0
  70. sage/combinat/posets/mobile.py +275 -0
  71. sage/combinat/posets/moebius_algebra.py +776 -0
  72. sage/combinat/posets/poset_examples.py +2178 -0
  73. sage/combinat/posets/posets.py +9360 -0
  74. sage/combinat/rooted_tree.py +1070 -0
  75. sage/combinat/shard_order.py +239 -0
  76. sage/combinat/tamari_lattices.py +384 -0
  77. sage/combinat/yang_baxter_graph.py +923 -0
  78. sage/databases/all__sagemath_graphs.py +1 -0
  79. sage/databases/knotinfo_db.py +1231 -0
  80. sage/ext_data/all__sagemath_graphs.py +1 -0
  81. sage/ext_data/graphs/graph_plot_js.html +330 -0
  82. sage/ext_data/kenzo/CP2.txt +45 -0
  83. sage/ext_data/kenzo/CP3.txt +349 -0
  84. sage/ext_data/kenzo/CP4.txt +4774 -0
  85. sage/ext_data/kenzo/README.txt +49 -0
  86. sage/ext_data/kenzo/S4.txt +20 -0
  87. sage/graphs/all.py +42 -0
  88. sage/graphs/asteroidal_triples.cpython-310-aarch64-linux-gnu.so +0 -0
  89. sage/graphs/asteroidal_triples.pyx +320 -0
  90. sage/graphs/base/all.py +1 -0
  91. sage/graphs/base/boost_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  92. sage/graphs/base/boost_graph.pxd +106 -0
  93. sage/graphs/base/boost_graph.pyx +3045 -0
  94. sage/graphs/base/c_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  95. sage/graphs/base/c_graph.pxd +106 -0
  96. sage/graphs/base/c_graph.pyx +5096 -0
  97. sage/graphs/base/dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  98. sage/graphs/base/dense_graph.pxd +28 -0
  99. sage/graphs/base/dense_graph.pyx +801 -0
  100. sage/graphs/base/graph_backends.cpython-310-aarch64-linux-gnu.so +0 -0
  101. sage/graphs/base/graph_backends.pxd +5 -0
  102. sage/graphs/base/graph_backends.pyx +797 -0
  103. sage/graphs/base/overview.py +85 -0
  104. sage/graphs/base/sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  105. sage/graphs/base/sparse_graph.pxd +90 -0
  106. sage/graphs/base/sparse_graph.pyx +1653 -0
  107. sage/graphs/base/static_dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  108. sage/graphs/base/static_dense_graph.pxd +5 -0
  109. sage/graphs/base/static_dense_graph.pyx +1032 -0
  110. sage/graphs/base/static_sparse_backend.cpython-310-aarch64-linux-gnu.so +0 -0
  111. sage/graphs/base/static_sparse_backend.pxd +27 -0
  112. sage/graphs/base/static_sparse_backend.pyx +1583 -0
  113. sage/graphs/base/static_sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  114. sage/graphs/base/static_sparse_graph.pxd +37 -0
  115. sage/graphs/base/static_sparse_graph.pyx +1375 -0
  116. sage/graphs/bipartite_graph.py +2732 -0
  117. sage/graphs/centrality.cpython-310-aarch64-linux-gnu.so +0 -0
  118. sage/graphs/centrality.pyx +1038 -0
  119. sage/graphs/cographs.py +519 -0
  120. sage/graphs/comparability.cpython-310-aarch64-linux-gnu.so +0 -0
  121. sage/graphs/comparability.pyx +851 -0
  122. sage/graphs/connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
  123. sage/graphs/connectivity.pxd +157 -0
  124. sage/graphs/connectivity.pyx +4813 -0
  125. sage/graphs/convexity_properties.cpython-310-aarch64-linux-gnu.so +0 -0
  126. sage/graphs/convexity_properties.pxd +16 -0
  127. sage/graphs/convexity_properties.pyx +870 -0
  128. sage/graphs/digraph.py +4754 -0
  129. sage/graphs/digraph_generators.py +1993 -0
  130. sage/graphs/distances_all_pairs.cpython-310-aarch64-linux-gnu.so +0 -0
  131. sage/graphs/distances_all_pairs.pxd +12 -0
  132. sage/graphs/distances_all_pairs.pyx +2938 -0
  133. sage/graphs/domination.py +1363 -0
  134. sage/graphs/dot2tex_utils.py +100 -0
  135. sage/graphs/edge_connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
  136. sage/graphs/edge_connectivity.pyx +1215 -0
  137. sage/graphs/generators/all.py +1 -0
  138. sage/graphs/generators/basic.py +1769 -0
  139. sage/graphs/generators/chessboard.py +538 -0
  140. sage/graphs/generators/classical_geometries.py +1611 -0
  141. sage/graphs/generators/degree_sequence.py +235 -0
  142. sage/graphs/generators/distance_regular.cpython-310-aarch64-linux-gnu.so +0 -0
  143. sage/graphs/generators/distance_regular.pyx +2846 -0
  144. sage/graphs/generators/families.py +4759 -0
  145. sage/graphs/generators/intersection.py +565 -0
  146. sage/graphs/generators/platonic_solids.py +262 -0
  147. sage/graphs/generators/random.py +2623 -0
  148. sage/graphs/generators/smallgraphs.py +5741 -0
  149. sage/graphs/generators/world_map.py +724 -0
  150. sage/graphs/generic_graph.py +26867 -0
  151. sage/graphs/generic_graph_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  152. sage/graphs/generic_graph_pyx.pxd +34 -0
  153. sage/graphs/generic_graph_pyx.pyx +1673 -0
  154. sage/graphs/genus.cpython-310-aarch64-linux-gnu.so +0 -0
  155. sage/graphs/genus.pyx +622 -0
  156. sage/graphs/graph.py +9645 -0
  157. sage/graphs/graph_coloring.cpython-310-aarch64-linux-gnu.so +0 -0
  158. sage/graphs/graph_coloring.pyx +2284 -0
  159. sage/graphs/graph_database.py +1177 -0
  160. sage/graphs/graph_decompositions/all.py +1 -0
  161. sage/graphs/graph_decompositions/bandwidth.cpython-310-aarch64-linux-gnu.so +0 -0
  162. sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
  163. sage/graphs/graph_decompositions/clique_separators.cpython-310-aarch64-linux-gnu.so +0 -0
  164. sage/graphs/graph_decompositions/clique_separators.pyx +616 -0
  165. sage/graphs/graph_decompositions/cutwidth.cpython-310-aarch64-linux-gnu.so +0 -0
  166. sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
  167. sage/graphs/graph_decompositions/fast_digraph.cpython-310-aarch64-linux-gnu.so +0 -0
  168. sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
  169. sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
  170. sage/graphs/graph_decompositions/graph_products.cpython-310-aarch64-linux-gnu.so +0 -0
  171. sage/graphs/graph_decompositions/graph_products.pyx +508 -0
  172. sage/graphs/graph_decompositions/modular_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  173. sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
  174. sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
  175. sage/graphs/graph_decompositions/slice_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  176. sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
  177. sage/graphs/graph_decompositions/slice_decomposition.pyx +1106 -0
  178. sage/graphs/graph_decompositions/tree_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  179. sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
  180. sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
  181. sage/graphs/graph_decompositions/vertex_separation.cpython-310-aarch64-linux-gnu.so +0 -0
  182. sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
  183. sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
  184. sage/graphs/graph_editor.py +82 -0
  185. sage/graphs/graph_generators.py +3314 -0
  186. sage/graphs/graph_generators_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  187. sage/graphs/graph_generators_pyx.pyx +95 -0
  188. sage/graphs/graph_input.py +812 -0
  189. sage/graphs/graph_latex.py +2064 -0
  190. sage/graphs/graph_list.py +410 -0
  191. sage/graphs/graph_plot.py +1756 -0
  192. sage/graphs/graph_plot_js.py +338 -0
  193. sage/graphs/hyperbolicity.cpython-310-aarch64-linux-gnu.so +0 -0
  194. sage/graphs/hyperbolicity.pyx +1704 -0
  195. sage/graphs/hypergraph_generators.py +364 -0
  196. sage/graphs/independent_sets.cpython-310-aarch64-linux-gnu.so +0 -0
  197. sage/graphs/independent_sets.pxd +13 -0
  198. sage/graphs/independent_sets.pyx +402 -0
  199. sage/graphs/isgci.py +1033 -0
  200. sage/graphs/isoperimetric_inequalities.cpython-310-aarch64-linux-gnu.so +0 -0
  201. sage/graphs/isoperimetric_inequalities.pyx +489 -0
  202. sage/graphs/line_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  203. sage/graphs/line_graph.pyx +743 -0
  204. sage/graphs/lovasz_theta.py +77 -0
  205. sage/graphs/matching.py +1633 -0
  206. sage/graphs/matching_covered_graph.py +3590 -0
  207. sage/graphs/orientations.py +1489 -0
  208. sage/graphs/partial_cube.py +459 -0
  209. sage/graphs/path_enumeration.cpython-310-aarch64-linux-gnu.so +0 -0
  210. sage/graphs/path_enumeration.pyx +2040 -0
  211. sage/graphs/pq_trees.py +1129 -0
  212. sage/graphs/print_graphs.py +201 -0
  213. sage/graphs/schnyder.py +865 -0
  214. sage/graphs/spanning_tree.cpython-310-aarch64-linux-gnu.so +0 -0
  215. sage/graphs/spanning_tree.pyx +1457 -0
  216. sage/graphs/strongly_regular_db.cpython-310-aarch64-linux-gnu.so +0 -0
  217. sage/graphs/strongly_regular_db.pyx +3340 -0
  218. sage/graphs/traversals.cpython-310-aarch64-linux-gnu.so +0 -0
  219. sage/graphs/traversals.pxd +9 -0
  220. sage/graphs/traversals.pyx +1872 -0
  221. sage/graphs/trees.cpython-310-aarch64-linux-gnu.so +0 -0
  222. sage/graphs/trees.pxd +15 -0
  223. sage/graphs/trees.pyx +310 -0
  224. sage/graphs/tutte_polynomial.py +713 -0
  225. sage/graphs/views.cpython-310-aarch64-linux-gnu.so +0 -0
  226. sage/graphs/views.pyx +794 -0
  227. sage/graphs/weakly_chordal.cpython-310-aarch64-linux-gnu.so +0 -0
  228. sage/graphs/weakly_chordal.pyx +604 -0
  229. sage/groups/all__sagemath_graphs.py +1 -0
  230. sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
  231. sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
  232. sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-310-aarch64-linux-gnu.so +0 -0
  233. sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
  234. sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
  235. sage/knots/all.py +6 -0
  236. sage/knots/free_knotinfo_monoid.py +507 -0
  237. sage/knots/gauss_code.py +291 -0
  238. sage/knots/knot.py +682 -0
  239. sage/knots/knot_table.py +284 -0
  240. sage/knots/knotinfo.py +2900 -0
  241. sage/knots/link.py +4715 -0
  242. sage/sandpiles/all.py +13 -0
  243. sage/sandpiles/examples.py +225 -0
  244. sage/sandpiles/sandpile.py +6365 -0
  245. sage/topology/all.py +22 -0
  246. sage/topology/cell_complex.py +1214 -0
  247. sage/topology/cubical_complex.py +1976 -0
  248. sage/topology/delta_complex.py +1806 -0
  249. sage/topology/filtered_simplicial_complex.py +744 -0
  250. sage/topology/moment_angle_complex.py +823 -0
  251. sage/topology/simplicial_complex.py +5160 -0
  252. sage/topology/simplicial_complex_catalog.py +92 -0
  253. sage/topology/simplicial_complex_examples.py +1680 -0
  254. sage/topology/simplicial_complex_homset.py +205 -0
  255. sage/topology/simplicial_complex_morphism.py +836 -0
  256. sage/topology/simplicial_set.py +4102 -0
  257. sage/topology/simplicial_set_catalog.py +55 -0
  258. sage/topology/simplicial_set_constructions.py +2954 -0
  259. sage/topology/simplicial_set_examples.py +865 -0
  260. sage/topology/simplicial_set_morphism.py +1464 -0
@@ -0,0 +1,1032 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ # cython: binding=True
3
+ r"""
4
+ Static dense graphs
5
+
6
+ This module gathers everything which is related to static dense graphs, i.e. :
7
+
8
+ - The vertices are integer from `0` to `n-1`
9
+ - No labels on vertices/edges
10
+ - No multiple edges
11
+ - No addition/removal of vertices
12
+
13
+ This being said, it is technically possible to add/remove edges. The data
14
+ structure does not mind at all.
15
+
16
+ It is all based on the binary matrix data structure described in
17
+ ``data_structures/binary_matrix.pxd``, which is almost a copy of the bitset data
18
+ structure. The only difference is that it differentiates the rows (the vertices)
19
+ instead of storing the whole data in a long bitset, and we can use that.
20
+
21
+ For an overview of graph data structures in sage, see
22
+ :mod:`~sage.graphs.base.overview`.
23
+
24
+ Index
25
+ -----
26
+
27
+ **Cython functions**
28
+
29
+ .. csv-table::
30
+ :class: contentstable
31
+ :widths: 30, 70
32
+ :delim: |
33
+
34
+ ``dense_graph_init`` | Fill a binary matrix with the information from a Sage (di)graph.
35
+
36
+ **Python functions**
37
+
38
+ .. csv-table::
39
+ :class: contentstable
40
+ :widths: 30, 70
41
+ :delim: |
42
+
43
+ :meth:`is_strongly_regular` | Check whether the graph is strongly regular
44
+ :meth:`is_triangle_free` | Check whether `G` is triangle free
45
+ :meth:`triangles_count` | Return the number of triangles containing `v`, for every `v`
46
+ :meth:`connected_subgraph_iterator` | Iterator over the induced connected subgraphs of order at most `k`
47
+
48
+ Functions
49
+ ---------
50
+ """
51
+ from sage.data_structures.binary_matrix cimport *
52
+ from cysignals.signals cimport sig_on, sig_off, sig_check
53
+ from memory_allocator cimport MemoryAllocator
54
+ from itertools import product
55
+ from sage.misc.flatten import flatten
56
+
57
+
58
+ cdef dict dense_graph_init(binary_matrix_t m, g, translation=None, force_undirected=False):
59
+ r"""
60
+ Fill a binary matrix with the information from a Sage (di)graph.
61
+
62
+ INPUT:
63
+
64
+ - ``binary_matrix_t m`` -- the binary matrix to be filled
65
+
66
+ - ``g`` -- a graph or digraph
67
+
68
+ - ``translation`` -- (default: ``None``) several options for this parameter
69
+ used to specify the mapping from vertices to integers:
70
+
71
+ - ``True``, ``False``, ``None`` -- the `i`-th vertex in the binary matrix
72
+ corresponds to vertex ``g.vertices(sort=True)[i]``.
73
+ When set to ``True``, a dictionary encoding the mapping from the
74
+ vertices of `g` to integers in `(0, \dots, n-1)` is returned.
75
+
76
+ - a ``list`` -- defines a mapping from integers in `(0, \dots, n-1)` to
77
+ the vertices in the graph `g`. So the `i`-th vertex in the binary matrix
78
+ corresponds to vertex ``translation[i]``.
79
+ **Beware that no checks are made that this input is correct**.
80
+
81
+ - a ``dict`` -- defines a mapping from the vertices of the graph to
82
+ integers in `(0, \dots, n-1)`. So the `i`-th vertex in the binary matrix
83
+ corresponds to ``translation[v]`` for some vertex `v \in g`.
84
+ **Beware that no checks are made that this input is correct**.
85
+
86
+ - ``force_undirected`` -- boolean (default: ``False``); whether to consider
87
+ the graph as undirected or not
88
+ """
89
+ cdef dict d_translation = {}
90
+ from sage.graphs.graph import Graph
91
+ cdef bint is_undirected = isinstance(g, Graph) or force_undirected
92
+ cdef int n = g.order()
93
+ cdef int i, j
94
+
95
+ binary_matrix_init(m, n, n)
96
+
97
+ if translation and translation is not True:
98
+ if isinstance(translation, list):
99
+ # We are given a mapping from integers to vertices
100
+ d_translation = {v: i for i, v in enumerate(translation)}
101
+ elif isinstance(translation, dict):
102
+ # We are given a mapping vertices to integers
103
+ d_translation = translation
104
+
105
+ # If the vertices are 0...n-1, let's avoid an unnecessary dictionary
106
+ if not d_translation and set(g.vertex_iterator()) == set(range(n)):
107
+ if translation is True:
108
+ d_translation = {i: i for i in range(n)}
109
+
110
+ for i, j in g.edge_iterator(labels=False):
111
+ binary_matrix_set1(m, i, j)
112
+ if is_undirected:
113
+ binary_matrix_set1(m, j, i)
114
+ else:
115
+ if not d_translation:
116
+ d_translation = {v: i for i, v in enumerate(g.vertices(sort=True))}
117
+
118
+ for u, v in g.edge_iterator(labels=False):
119
+ binary_matrix_set1(m, d_translation[u], d_translation[v])
120
+ if is_undirected:
121
+ binary_matrix_set1(m, d_translation[v], d_translation[u])
122
+
123
+ if translation is True:
124
+ return d_translation
125
+
126
+
127
+ def is_strongly_regular(g, parameters=False):
128
+ r"""
129
+ Check whether the graph is strongly regular.
130
+
131
+ A simple graph `G` is said to be strongly regular with parameters
132
+ `(n, k, \lambda, \mu)` if and only if:
133
+
134
+ * `G` has `n` vertices
135
+
136
+ * `G` is `k`-regular
137
+
138
+ * Any two adjacent vertices of `G` have `\lambda` common neighbors
139
+
140
+ * Any two non-adjacent vertices of `G` have `\mu` common neighbors
141
+
142
+ By convention, the complete graphs, the graphs with no edges and the empty
143
+ graph are not strongly regular.
144
+
145
+ See the :wikipedia:`Strongly regular graph`.
146
+
147
+ INPUT:
148
+
149
+ - ``parameters`` -- boolean (default: ``False``); whether to return the
150
+ quadruple `(n, k, \lambda, \mu)`. If ``parameters = False`` (default),
151
+ this method only returns ``True`` and ``False`` answers.
152
+ If ``parameters = True``, the ``True`` answers are replaced by quadruples
153
+ `(n, k, \lambda, \mu)`. See definition above.
154
+
155
+ EXAMPLES:
156
+
157
+ Petersen's graph is strongly regular::
158
+
159
+ sage: g = graphs.PetersenGraph()
160
+ sage: g.is_strongly_regular()
161
+ True
162
+ sage: g.is_strongly_regular(parameters=True)
163
+ (10, 3, 0, 1)
164
+
165
+ And Clebsch's graph is too::
166
+
167
+ sage: g = graphs.ClebschGraph()
168
+ sage: g.is_strongly_regular()
169
+ True
170
+ sage: g.is_strongly_regular(parameters=True)
171
+ (16, 5, 0, 2)
172
+
173
+ But Chvatal's graph is not::
174
+
175
+ sage: g = graphs.ChvatalGraph()
176
+ sage: g.is_strongly_regular()
177
+ False
178
+
179
+ Complete graphs are not strongly regular. (:issue:`14297`) ::
180
+
181
+ sage: g = graphs.CompleteGraph(5)
182
+ sage: g.is_strongly_regular()
183
+ False
184
+
185
+ Completements of complete graphs are not strongly regular::
186
+
187
+ sage: g = graphs.CompleteGraph(5).complement()
188
+ sage: g.is_strongly_regular()
189
+ False
190
+
191
+ The empty graph is not strongly regular::
192
+
193
+ sage: g = graphs.EmptyGraph()
194
+ sage: g.is_strongly_regular()
195
+ False
196
+
197
+ If the input graph has loops or multiedges an exception is raised::
198
+
199
+ sage: Graph([(1,1),(2,2)],loops=True).is_strongly_regular()
200
+ Traceback (most recent call last):
201
+ ...
202
+ ValueError: This method is not known to work on graphs with
203
+ loops. Perhaps this method can be updated to handle them, but in the
204
+ meantime if you want to use it please disallow loops using
205
+ allow_loops().
206
+
207
+ sage: Graph([(1,2),(1,2)],multiedges=True).is_strongly_regular()
208
+ Traceback (most recent call last):
209
+ ...
210
+ ValueError: This method is not known to work on graphs with
211
+ multiedges. Perhaps this method can be updated to handle them, but in
212
+ the meantime if you want to use it please disallow multiedges using
213
+ allow_multiple_edges().
214
+ """
215
+ g._scream_if_not_simple()
216
+ cdef binary_matrix_t m
217
+ cdef bitset_t b_tmp
218
+ cdef int n = g.order()
219
+ cdef int inter
220
+ cdef int i, j, k
221
+
222
+ if not g.order() or not g.size(): # no vertices or no edges
223
+ return False
224
+
225
+ if g.is_clique():
226
+ return False
227
+
228
+ cdef list degree = g.degree()
229
+ k = degree[0]
230
+ if any(d != k for d in degree):
231
+ return False
232
+
233
+ bitset_init(b_tmp, n)
234
+
235
+ # m is now our copy of the graph
236
+ dense_graph_init(m, g, translation={v: i for i, v in enumerate(g)})
237
+
238
+ cdef int llambda = -1
239
+ cdef int mu = -1
240
+
241
+ for i in range(n):
242
+ for j in range(i + 1, n):
243
+
244
+ # The intersection of the common neighbors of i and j is a AND of
245
+ # their respective rows. A popcount then returns its cardinality.
246
+ bitset_and(b_tmp, m.rows[i], m.rows[j])
247
+ inter = bitset_len(b_tmp)
248
+
249
+ # Check that this cardinality is correct according to the values of lambda and mu
250
+ if binary_matrix_get(m, i, j):
251
+ if llambda == -1:
252
+ llambda = inter
253
+ elif llambda != inter:
254
+ binary_matrix_free(m)
255
+ bitset_free(b_tmp)
256
+ return False
257
+ else:
258
+ if mu == -1:
259
+ mu = inter
260
+ elif mu != inter:
261
+ binary_matrix_free(m)
262
+ bitset_free(b_tmp)
263
+ return False
264
+
265
+ binary_matrix_free(m)
266
+ bitset_free(b_tmp)
267
+
268
+ if parameters:
269
+ return (n, k, llambda, mu)
270
+ else:
271
+ return True
272
+
273
+
274
+ def is_triangle_free(G, certificate=False):
275
+ r"""
276
+ Check whether `G` is triangle free.
277
+
278
+ INPUT:
279
+
280
+ - ``G`` -- a Sage graph
281
+
282
+ - ``certificate`` -- boolean (default: ``False``); whether to return a
283
+ triangle if one is found
284
+
285
+ EXAMPLES::
286
+
287
+ sage: from sage.graphs.base.static_dense_graph import is_triangle_free
288
+ sage: is_triangle_free(graphs.PetersenGraph())
289
+ True
290
+ sage: K4 = graphs.CompleteGraph(4)
291
+ sage: is_triangle_free(K4)
292
+ False
293
+ sage: b, certif = is_triangle_free(K4, certificate=True)
294
+ sage: K4.subgraph(certif).is_clique()
295
+ True
296
+
297
+ TESTS::
298
+
299
+ sage: from sage.graphs.base.static_dense_graph import is_triangle_free
300
+ sage: is_triangle_free(Graph())
301
+ True
302
+ sage: is_triangle_free(Graph(), certificate=True)
303
+ (True, [])
304
+ """
305
+ G._scream_if_not_simple()
306
+ cdef int n = G.order()
307
+ if n < 3:
308
+ return (True, []) if certificate else True
309
+
310
+ cdef binary_matrix_t g
311
+ cdef list int_to_vertex = list(G)
312
+ dense_graph_init(g, G, translation=int_to_vertex)
313
+
314
+ cdef mp_size_t i, j, k
315
+ for i in range(n):
316
+ j = bitset_next(g.rows[i], i + 1)
317
+ while j != -1:
318
+ if bitset_are_disjoint(g.rows[i], g.rows[j]):
319
+ j = bitset_next(g.rows[i], j + 1)
320
+ else:
321
+ if certificate:
322
+ # Search for a common neighbor
323
+ k = bitset_first(g.rows[i])
324
+ while bitset_not_in(g.rows[j], k):
325
+ k = bitset_next(g.rows[j], k + 1)
326
+ certif = [int_to_vertex[i], int_to_vertex[j], int_to_vertex[k]]
327
+
328
+ binary_matrix_free(g)
329
+ return (False, certif) if certificate else False
330
+
331
+ binary_matrix_free(g)
332
+ return (True, []) if certificate else True
333
+
334
+
335
+ def triangles_count(G):
336
+ r"""
337
+ Return the number of triangles containing `v`, for every `v`.
338
+
339
+ INPUT:
340
+
341
+ - ``G`` -- a simple Sage graph
342
+
343
+ EXAMPLES::
344
+
345
+ sage: from sage.graphs.base.static_dense_graph import triangles_count
346
+ sage: triangles_count(graphs.PetersenGraph())
347
+ {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0}
348
+ sage: sum(triangles_count(graphs.CompleteGraph(15)).values()) == 3 * binomial(15, 3) # needs sage.symbolic
349
+ True
350
+ """
351
+ from sage.rings.integer import Integer
352
+ G._scream_if_not_simple()
353
+ cdef int n = G.order()
354
+
355
+ cdef uint64_t * count = <uint64_t *> check_calloc(n, sizeof(uint64_t))
356
+
357
+ cdef binary_matrix_t g
358
+ cdef list int_to_vertex = list(G)
359
+ dense_graph_init(g, G, translation=int_to_vertex)
360
+
361
+ cdef bitset_t b_tmp
362
+ bitset_init(b_tmp, n)
363
+
364
+ cdef int i, j
365
+ cdef uint64_t tmp_count = 0
366
+
367
+ for i in range(n):
368
+ for j in range(i + 1, n):
369
+ if not bitset_in(g.rows[i], j):
370
+ continue
371
+ bitset_and(b_tmp, g.rows[i], g.rows[j])
372
+ tmp_count = bitset_len(b_tmp)
373
+ count[i] += tmp_count
374
+ count[j] += tmp_count
375
+
376
+ ans = {v: Integer(count[i] // 2) for i, v in enumerate(int_to_vertex)}
377
+
378
+ bitset_free(b_tmp)
379
+ binary_matrix_free(g)
380
+ sig_free(count)
381
+
382
+ return ans
383
+
384
+
385
+ def _format_result(G, edges, edges_only, labels):
386
+ r"""
387
+ Helper method for ``connected_full_subgraphs`` to return a result.
388
+
389
+ INPUT:
390
+
391
+ - ``G`` -- a :class:`DiGraph`
392
+
393
+ - ``edges`` -- list of edges ignoring the orientation
394
+
395
+ - ``edges_only`` -- boolean; whether to return DiGraph or list of vertices
396
+
397
+ - ``labels`` -- boolean; whether to return labeled edges or not. This
398
+ parameter is used only when ``edges_only`` is ``True``.
399
+
400
+ EXAMPLES:
401
+
402
+ The complete graph of order 3 has 4 connected subgraphs::
403
+
404
+ sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs
405
+ sage: G = graphs.CompleteGraph(3)
406
+ sage: len(list(connected_full_subgraphs(G)))
407
+ 4
408
+ """
409
+ if edges_only:
410
+ if labels:
411
+ return [(u, v, G.edge_label(u, v)) for u, v in edges]
412
+ else:
413
+ return edges
414
+ else:
415
+ return G.subgraph(vertices=G, edges=edges)
416
+
417
+
418
+ def _yield_results_for_digraph(G, edges, edges_only, labels, min_edges, max_edges):
419
+ r"""
420
+ Helper method for ``connected_full_subgraphs`` to yield all subdigraphs.
421
+
422
+ INPUT:
423
+
424
+ - ``G`` -- a :class:`DiGraph`
425
+
426
+ - ``edges`` -- list of edges ignoring the orientation
427
+
428
+ - ``edges_only`` -- boolean; whether to return DiGraph or list of vertices
429
+
430
+ - ``labels`` -- boolean; whether to return labeled edges or not. This
431
+ parameter is used only when ``edges_only`` is ``True``.
432
+
433
+ - ``min_edges`` -- integer; minimum number of edges of reported subgraphs
434
+
435
+ - ``max_edges`` -- integer; maximum number of edges of reported subgraphs
436
+
437
+ EXAMPLES::
438
+
439
+ sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs
440
+ sage: G = digraphs.Complete(3)
441
+ sage: len(list(connected_full_subgraphs(G)))
442
+ 54
443
+ """
444
+ if not edges:
445
+ return
446
+ L = []
447
+ for u, v in edges:
448
+ tmp = []
449
+ if G.has_edge(u, v):
450
+ tmp.append([(u, v)])
451
+ if G.has_edge(v, u):
452
+ tmp.append([(v, u)])
453
+ if G.has_edge(u, v):
454
+ tmp.append([(u, v), (v, u)])
455
+ L.append(tmp)
456
+
457
+ if len(L) == 1:
458
+ for F in L[0]:
459
+ if min_edges <= len(F) and len(F) <= max_edges:
460
+ yield _format_result(G, F, edges_only, labels)
461
+ else:
462
+ for E in product(*L):
463
+ F = [e for le in E for e in le]
464
+ if min_edges <= len(F) and len(F) <= max_edges:
465
+ yield _format_result(G, F, edges_only, labels)
466
+ return
467
+
468
+
469
+ def connected_full_subgraphs(G, edges_only=False, labels=False,
470
+ min_edges=None, max_edges=None):
471
+ r"""
472
+ Return an iterator over the connected subgraphs of `G` with same vertex set.
473
+
474
+ This method implements a iterator over the connected subgraphs of the input
475
+ (di)graph with the same ground set of vertices. That is, it iterates over
476
+ every subgraph `H = (V_H, E_H)` of `G = (V, E)` such that `V_H = V`,
477
+ `E_H \subseteq E` and `H` is connected. Hence, this method may yield a huge
478
+ number of graphs.
479
+
480
+ When the input (di)graph `G` is not connected, this method returns nothing.
481
+
482
+ As for method :meth:`sage.graphs.generic_graph.connected_components`, edge
483
+ orientation is ignored. Hence, the directed graph with a single arc `0 \to
484
+ 1` is considered connected.
485
+
486
+ INPUT:
487
+
488
+ - ``G`` -- a :class:`Graph` or a :class:`DiGraph`; loops and multiple edges
489
+ are *not* allowed
490
+
491
+ - ``edges_only`` -- boolean (default: ``False``); whether to return
492
+ (Di)Graph or list of vertices
493
+
494
+ - ``labels`` -- boolean (default: ``False``); whether to return labeled
495
+ edges or not. This parameter is used only when ``edges_only`` is ``True``.
496
+
497
+ - ``min_edges`` -- integer (default: ``None``); minimum number of edges of
498
+ reported subgraphs. By default (``None``), this lower bound will be set to
499
+ `n - 1`.
500
+
501
+ - ``max_edges`` -- integer (default: ``None``); maximum number of edges of
502
+ reported subgraphs. By default (``None``), this lower bound will be set to
503
+ the number of edges of the input (di)graph.
504
+
505
+ .. NOTE::
506
+
507
+ Roughly, this method explores all possible subsets of neighbors of each
508
+ vertex, which represents a huge number of subsets. We have thus chosen
509
+ to limit the degree of the vertices of the graphs that can be
510
+ considered, even if the graph has a single connected subgraph (e.g., a
511
+ tree). It is therefore recommended to call this method on biconnected
512
+ components, as done in :meth:`connected_subgraph_iterator`.
513
+
514
+ EXAMPLES:
515
+
516
+ The complete graph of order 3 has 4 connected subgraphs::
517
+
518
+ sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs
519
+ sage: G = graphs.CompleteGraph(3)
520
+ sage: len(list(connected_full_subgraphs(G)))
521
+ 4
522
+
523
+ A cycle of order 5 has 6 connected subgraphs::
524
+
525
+ sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs
526
+ sage: G = graphs.CycleGraph(5)
527
+ sage: len(list(connected_full_subgraphs(G)))
528
+ 6
529
+
530
+ The House graph has 18 connected subgraphs of order 5::
531
+
532
+ sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs
533
+ sage: G = graphs.HouseGraph()
534
+ sage: L = list(connected_full_subgraphs(G))
535
+ sage: len(L)
536
+ 18
537
+ sage: all(g.order() == 5 for g in L)
538
+ True
539
+ sage: all(g.is_connected() for g in L)
540
+ True
541
+ sage: F = frozenset(frozenset(g.edges(sort=False, labels=False)) for g in L)
542
+ sage: len(F)
543
+ 18
544
+
545
+ Specifying bounds on the number of edges::
546
+
547
+ sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs
548
+ sage: G = graphs.HouseGraph()
549
+ sage: [g.size() for g in connected_full_subgraphs(G)]
550
+ [6, 5, 5, 5, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4]
551
+ sage: [g.size() for g in connected_full_subgraphs(G, max_edges=4)]
552
+ [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]
553
+ sage: [g.size() for g in connected_full_subgraphs(G, min_edges=6)]
554
+ [6]
555
+ sage: [g.size() for g in connected_full_subgraphs(G, min_edges=5, max_edges=5)]
556
+ [5, 5, 5, 5, 5, 5]
557
+
558
+ Asking for edges only::
559
+
560
+ sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs
561
+ sage: G = Graph([(0, 1, "01"), (0, 2, "02"), (1, 2, "12")])
562
+ sage: it = connected_full_subgraphs(G, edges_only=True)
563
+ sage: next(it)
564
+ [(0, 1), (0, 2), (1, 2)]
565
+ sage: next(it)
566
+ [(0, 1), (0, 2)]
567
+ sage: it = connected_full_subgraphs(G, edges_only=True, labels=True)
568
+ sage: next(it)
569
+ [(0, 1, '01'), (0, 2, '02'), (1, 2, '12')]
570
+ sage: next(it)
571
+ [(0, 1, '01'), (0, 2, '02')]
572
+
573
+ Subgraphs of a digraph::
574
+
575
+ sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs
576
+ sage: G = digraphs.Complete(2)
577
+ sage: list(connected_full_subgraphs(G, edges_only=True))
578
+ [[(0, 1)], [(1, 0)], [(0, 1), (1, 0)]]
579
+
580
+ TESTS:
581
+
582
+ Non connected input graph::
583
+
584
+ sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs
585
+ sage: list(connected_full_subgraphs(Graph(2)))
586
+ Traceback (most recent call last):
587
+ ...
588
+ ValueError: the input (di)graph is not connected
589
+
590
+ Too large degree::
591
+
592
+ sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs
593
+ sage: G = graphs.StarGraph(100)
594
+ sage: list(connected_full_subgraphs(G))
595
+ Traceback (most recent call last):
596
+ ...
597
+ ValueError: the degree of the graph is too large for this method
598
+
599
+ Wrong bounds on the number of edges::
600
+
601
+ sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs
602
+ sage: G = graphs.HouseGraph()
603
+ sage: [g.size() for g in connected_full_subgraphs(G, min_edges=G.size() + 1)]
604
+ Traceback (most recent call last):
605
+ ...
606
+ ValueError: we must have 4 <= min_edges <= max_edges <= 6
607
+ sage: [g.size() for g in connected_full_subgraphs(G, max_edges=G.order() - 2)]
608
+ Traceback (most recent call last):
609
+ ...
610
+ ValueError: we must have 4 <= min_edges <= max_edges <= 6
611
+ """
612
+ G._scream_if_not_simple()
613
+ if not G.is_connected():
614
+ raise ValueError("the input (di)graph is not connected")
615
+
616
+ for d in G.degree():
617
+ if d >= 8 * sizeof(unsigned long) - 1:
618
+ raise ValueError("the degree of the graph is too large for this method")
619
+
620
+ cdef Py_ssize_t n = G.order()
621
+ cdef Py_ssize_t m = G.size()
622
+ if min_edges is None or min_edges < n - 1:
623
+ min_edges = n - 1
624
+ if max_edges is None or max_edges > m:
625
+ max_edges = m
626
+ if min_edges > max_edges:
627
+ raise ValueError("we must have {} <= min_edges <= max_edges <= {}".format(n -1, m))
628
+
629
+ if n <= 1 or (not G.is_directed() and n == 2) or min_edges == m:
630
+ if edges_only:
631
+ yield list(G.edges(sort=False, labels=labels))
632
+ else:
633
+ yield G.copy()
634
+ return
635
+
636
+ # We map vertices to integers. We sort them by degree as a heuristic to
637
+ # reduce the number of operations.
638
+ cdef list int_to_vertex = sorted(G, key=G.degree)
639
+ cdef binary_matrix_t DG
640
+ sig_on()
641
+ dense_graph_init(DG, G, translation=int_to_vertex, force_undirected=True)
642
+
643
+ cdef MemoryAllocator mem = MemoryAllocator()
644
+ cdef int * order = <int *> mem.calloc(n, sizeof(int))
645
+ cdef mp_bitcnt_t * n_cpt = <mp_bitcnt_t *> mem.calloc(n, sizeof(mp_bitcnt_t))
646
+
647
+ # We use several bitsets to store the current boundary and active neighbors.
648
+ # We also need another bitset that we create at the same time
649
+ cdef binary_matrix_t boundaries
650
+ binary_matrix_init(boundaries, n + 1, n)
651
+ cdef binary_matrix_t neighborhoods
652
+ binary_matrix_init(neighborhoods, n, n)
653
+ sig_off()
654
+
655
+ cdef bitset_t active = boundaries.rows[n] # remaining vertices to consider
656
+ cdef bitset_t boundary # neighbors of the current subset
657
+
658
+ # Initialize the process
659
+ cdef Py_ssize_t i = 0
660
+ order[0] = 0
661
+ bitset_complement(active, active)
662
+ bitset_discard(active, 0)
663
+ bitset_copy(neighborhoods.rows[0], DG.rows[0])
664
+ n_cpt[0] = 1 << bitset_len(DG.rows[0])
665
+
666
+ cdef long u, v, j
667
+ cdef mp_bitcnt_t c
668
+ cdef Py_ssize_t num_edges = 0
669
+ cdef list E = []
670
+ cdef list edges
671
+
672
+ while i >= 0:
673
+ sig_check()
674
+ if i == n - 1 and num_edges >= min_edges:
675
+ # yield the current solution
676
+ edges = [(int_to_vertex[u], int_to_vertex[v]) for le in E for u, v in le]
677
+ if G.is_directed():
678
+ yield from _yield_results_for_digraph(G, edges, edges_only, labels, min_edges, max_edges)
679
+ else:
680
+ yield _format_result(G, edges, edges_only, labels)
681
+
682
+ if n_cpt[i] > 1:
683
+ # Consider the next neighborhood of the current vertex.
684
+ # If vertex u has k active neighbors, we have 2^k possibilities. We
685
+ # use the binary representation of n_cpt[i] to indicate which of the
686
+ # k neighbors are selected. We omit the empty neighborhood which is
687
+ # considered elsewhere.
688
+ n_cpt[i] -= 1
689
+ c = n_cpt[i]
690
+ if num_edges + _bitset_len(&c, 1) > max_edges:
691
+ # Too many edges
692
+ continue
693
+
694
+ boundary = boundaries.rows[i + 1]
695
+ bitset_copy(boundary, boundaries.rows[i])
696
+ edges = []
697
+ j = bitset_first(neighborhoods.rows[i])
698
+ while c and j != -1:
699
+ if c & 1:
700
+ bitset_add(boundary, j)
701
+ edges.append((order[i], j))
702
+ c >>= 1
703
+ j = bitset_next(neighborhoods.rows[i], j + 1)
704
+
705
+ if not bitset_len(boundary):
706
+ # We cannot extend
707
+ continue
708
+
709
+ E.append(edges)
710
+ num_edges += len(edges)
711
+ # otherwise, we select a vertex from the boundary and extend the order
712
+
713
+ elif bitset_len(boundaries.rows[i]):
714
+ # We prepare the boundary for the selection of the next vertex.
715
+ # This is equivalent to consider an empty neighborhood.
716
+ bitset_copy(boundaries.rows[i + 1], boundaries.rows[i])
717
+ bitset_clear(boundaries.rows[i]) # to prevent doing twice this operation
718
+ E.append([])
719
+
720
+ else:
721
+ # We have considered all possible extensions
722
+ bitset_add(active, order[i])
723
+ i -= 1
724
+ if E:
725
+ num_edges -= len(E[-1])
726
+ E.pop()
727
+ continue
728
+
729
+ # We select a vertex from the boundary to add to the order
730
+ i += 1
731
+ boundary = boundaries.rows[i]
732
+ u = bitset_first(boundary)
733
+ order[i] = u
734
+ bitset_discard(boundary, u)
735
+ bitset_discard(active, u)
736
+ # prepare neighborhood of u
737
+ bitset_and(neighborhoods.rows[i], active, DG.rows[u])
738
+ j = bitset_len(neighborhoods.rows[i])
739
+ n_cpt[i] = bool(j) << j # 0 if not j else 2^j
740
+
741
+ sig_on()
742
+ binary_matrix_free(boundaries)
743
+ binary_matrix_free(neighborhoods)
744
+ binary_matrix_free(DG)
745
+ sig_off()
746
+
747
+
748
+ def connected_subgraph_iterator(G, k=None, bint vertices_only=False,
749
+ edges_only=False, labels=False, induced=True,
750
+ exactly_k=False):
751
+ r"""
752
+ Return an terator over the induced connected subgraphs of order at most `k`.
753
+
754
+ This method implements a iterator over the induced connected subgraphs of
755
+ the input (di)graph. An induced subgraph of a graph is another graph, formed
756
+ from a subset of the vertices of the graph and all of the edges connecting
757
+ pairs of vertices in that subset (:wikipedia:`Induced_subgraph`).
758
+
759
+ As for method :meth:`sage.graphs.generic_graph.connected_components`, edge
760
+ orientation is ignored. Hence, the directed graph with a single arc `0 \to
761
+ 1` is considered connected.
762
+
763
+ INPUT:
764
+
765
+ - ``G`` -- a :class:`Graph` or a :class:`DiGraph`; loops and multiple edges
766
+ are allowed
767
+
768
+ - ``k`` -- (optional) integer; maximum order of the connected subgraphs to
769
+ report; by default, the method iterates over all connected subgraphs
770
+ (equivalent to ``k == n``)
771
+
772
+ - ``vertices_only`` -- boolean (default: ``False``); whether to return
773
+ (Di)Graph or list of vertices. This parameter is ignored when ``induced``
774
+ is ``True``.
775
+
776
+ - ``edges_only`` -- boolean (default: ``False``); whether to
777
+ return (Di)Graph or list of edges. When ``vertices_only`` is
778
+ ``True``, this parameter is ignored.
779
+
780
+ - ``labels`` -- boolean (default: ``False``); whether to return labeled
781
+ edges or not. This parameter is used only when ``vertices_only`` is
782
+ ``False`` and ``edges_only`` is ``True``.
783
+
784
+ - ``induced`` -- boolean (default: ``True``); whether to return induced
785
+ connected sub(di)graph only or also non-induced sub(di)graphs.
786
+ This parameter can be set to ``False`` for simple (di)graphs only.
787
+
788
+ - ``exactly_k`` -- boolean (default: ``False``); ``True`` if we only
789
+ return graphs of order `k`, ``False`` if we return graphs of order
790
+ at most `k`.
791
+
792
+ EXAMPLES::
793
+
794
+ sage: G = DiGraph([(1, 2), (2, 3), (3, 4), (4, 2)])
795
+ sage: list(G.connected_subgraph_iterator())
796
+ [Subgraph of (): Digraph on 1 vertex,
797
+ Subgraph of (): Digraph on 2 vertices,
798
+ Subgraph of (): Digraph on 3 vertices,
799
+ Subgraph of (): Digraph on 4 vertices,
800
+ Subgraph of (): Digraph on 3 vertices,
801
+ Subgraph of (): Digraph on 1 vertex,
802
+ Subgraph of (): Digraph on 2 vertices,
803
+ Subgraph of (): Digraph on 3 vertices,
804
+ Subgraph of (): Digraph on 2 vertices,
805
+ Subgraph of (): Digraph on 1 vertex,
806
+ Subgraph of (): Digraph on 2 vertices,
807
+ Subgraph of (): Digraph on 1 vertex]
808
+ sage: list(G.connected_subgraph_iterator(vertices_only=True))
809
+ [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 4],
810
+ [2], [2, 3], [2, 3, 4], [2, 4], [3], [3, 4], [4]]
811
+ sage: list(G.connected_subgraph_iterator(k=2))
812
+ [Subgraph of (): Digraph on 1 vertex,
813
+ Subgraph of (): Digraph on 2 vertices,
814
+ Subgraph of (): Digraph on 1 vertex,
815
+ Subgraph of (): Digraph on 2 vertices,
816
+ Subgraph of (): Digraph on 2 vertices,
817
+ Subgraph of (): Digraph on 1 vertex,
818
+ Subgraph of (): Digraph on 2 vertices,
819
+ Subgraph of (): Digraph on 1 vertex]
820
+ sage: list(G.connected_subgraph_iterator(k=3, vertices_only=True, exactly_k=True))
821
+ [[1, 2, 3], [1, 2, 4], [2, 3, 4]]
822
+ sage: list(G.connected_subgraph_iterator(k=2, vertices_only=True))
823
+ [[1], [1, 2], [2], [2, 3], [2, 4], [3], [3, 4], [4]]
824
+
825
+ sage: G = DiGraph([(1, 2), (2, 1)])
826
+ sage: list(G.connected_subgraph_iterator())
827
+ [Subgraph of (): Digraph on 1 vertex,
828
+ Subgraph of (): Digraph on 2 vertices,
829
+ Subgraph of (): Digraph on 1 vertex]
830
+ sage: list(G.connected_subgraph_iterator(vertices_only=True))
831
+ [[1], [1, 2], [2]]
832
+
833
+ sage: G = graphs.CompleteGraph(3)
834
+ sage: len(list(G.connected_subgraph_iterator()))
835
+ 7
836
+ sage: len(list(G.connected_subgraph_iterator(vertices_only=True)))
837
+ 7
838
+ sage: len(list(G.connected_subgraph_iterator(edges_only=True)))
839
+ 7
840
+ sage: len(list(G.connected_subgraph_iterator(induced=False)))
841
+ 10
842
+
843
+ sage: G = DiGraph([(0, 1), (1, 0), (1, 2), (2, 1)])
844
+ sage: len(list(G.connected_subgraph_iterator()))
845
+ 6
846
+ sage: len(list(G.connected_subgraph_iterator(vertices_only=True)))
847
+ 6
848
+ sage: len(list(G.connected_subgraph_iterator(edges_only=True)))
849
+ 6
850
+ sage: len(list(G.connected_subgraph_iterator(induced=False)))
851
+ 18
852
+
853
+ TESTS:
854
+
855
+ The Path Graph of order `n` has `n (n + 1) / 2` connected subgraphs::
856
+
857
+ sage: G = graphs.PathGraph(10)
858
+ sage: len(list(G.connected_subgraph_iterator(vertices_only=True)))
859
+ 55
860
+ sage: len(list(G.connected_subgraph_iterator(vertices_only=False)))
861
+ 55
862
+
863
+ The Complete Graph of order `n` has `2^n - 1` connected subgraphs::
864
+
865
+ sage: G = graphs.CompleteGraph(5)
866
+ sage: len(list(G.connected_subgraph_iterator(vertices_only=False))) == 2**G.order() - 1
867
+ True
868
+ sage: G = graphs.CompleteGraph(6)
869
+ sage: len(list(G.connected_subgraph_iterator(vertices_only=True))) == 2**G.order() - 1
870
+ True
871
+
872
+ Checks that it works with general graphs and corner cases::
873
+
874
+ sage: G = DiGraph([(1, 2), (1, 2)], multiedges=True)
875
+ sage: len(list(G.connected_subgraph_iterator()))
876
+ 3
877
+ sage: len(list(G.connected_subgraph_iterator(k=0)))
878
+ 0
879
+ sage: len(list(G.connected_subgraph_iterator(vertices_only=True)))
880
+ 3
881
+
882
+ sage: G = Graph([(1, 2), (1, 1)], loops=True)
883
+ sage: len(list(G.connected_subgraph_iterator(vertices_only=False)))
884
+ 3
885
+ sage: G = Graph([(1, 2), (1, 2), (1, 1)], loops=True, multiedges=True)
886
+ sage: len(list(G.connected_subgraph_iterator()))
887
+ 3
888
+ sage: len(list(G.connected_subgraph_iterator(k=1)))
889
+ 2
890
+ sage: len(list(G.connected_subgraph_iterator(vertices_only=True)))
891
+ 3
892
+ """
893
+ if not induced:
894
+ G._scream_if_not_simple()
895
+ vertices_only = False
896
+
897
+ cdef Py_ssize_t mk = G.order() if k is None else k
898
+ cdef Py_ssize_t n = G.order()
899
+ if not n or mk < 1:
900
+ return
901
+
902
+ cdef list int_to_vertex = list(G)
903
+ cdef binary_matrix_t DG
904
+ sig_on()
905
+ dense_graph_init(DG, G, translation=int_to_vertex, force_undirected=True)
906
+
907
+ # We use a stack of bitsets. We need 3 bitsets per level with at most n + 1
908
+ # levels, so 3 * n + 3 bitsets. We also need 1 bitset that we create at the
909
+ # same time, so we need overall 3 * n + 4 bitsets
910
+ cdef binary_matrix_t stack
911
+ binary_matrix_init(stack, 3 * n + 4, n)
912
+ sig_off()
913
+
914
+ cdef bitset_t current # current subset of vertices
915
+ cdef bitset_t left # remaining vertices to consider
916
+ cdef bitset_t boundary # neighbors of the current subset
917
+ # candidate vertices for extending the current subset, i.e., vertices that
918
+ # are both in left and in boundary
919
+ cdef bitset_t candidates = stack.rows[3 * n + 3]
920
+
921
+ cdef Py_ssize_t level
922
+ cdef Py_ssize_t u, v, a
923
+ cdef list vertices
924
+
925
+ # We first generate subsets containing vertex 0, then the subsets containing
926
+ # vertex 1 but not vertex 0 since we have already generated all subsets
927
+ # containing 0, then subsets containing 2 but not 0 or 1, etc.
928
+ for u in range(n):
929
+ sig_check()
930
+
931
+ vertices = [int_to_vertex[u]]
932
+ if not exactly_k or mk == 1:
933
+ if vertices_only:
934
+ yield vertices
935
+ else:
936
+ H = G.subgraph(vertices)
937
+ if edges_only:
938
+ yield H.edges(sort=False, labels=labels)
939
+ else:
940
+ yield H
941
+
942
+ # We initialize the loop with vertices u in current, {u+1, ..., n-1}
943
+ # in left, and N(u) in boundary
944
+ bitset_clear(stack.rows[0])
945
+ bitset_add(stack.rows[0], u)
946
+ bitset_set_first_n(stack.rows[1], u + 1)
947
+ bitset_complement(stack.rows[1], stack.rows[1])
948
+ bitset_copy(stack.rows[2], DG.rows[u])
949
+ level = 0
950
+
951
+ while level >= 0:
952
+ sig_check()
953
+
954
+ # We take the values at the top of the stack
955
+ current = stack.rows[level]
956
+ left = stack.rows[level + 1]
957
+ boundary = stack.rows[level + 2]
958
+
959
+ bitset_and(candidates, left, boundary)
960
+
961
+ # Search for a candidate vertex v
962
+ v = bitset_next(candidates, u + 1)
963
+ if v >= 0 and bitset_len(current) < mk:
964
+ # We select vertex v
965
+ bitset_discard(left, v)
966
+
967
+ # Since we have not modified 'level', the bitsets for iterating
968
+ # without v are already at the top of the stack, with correct
969
+ # values
970
+
971
+ # We also build the subset with v and so we add values at the
972
+ # top of the stack
973
+ level += 3
974
+ bitset_copy(stack.rows[level], current)
975
+ bitset_add(stack.rows[level], v)
976
+ bitset_copy(stack.rows[level + 1], left)
977
+ bitset_union(stack.rows[level + 2], boundary, DG.rows[v])
978
+
979
+ # We yield that new subset
980
+ vertices = [int_to_vertex[a] for a in range(u, n)
981
+ if bitset_in(stack.rows[level], a)]
982
+ if not exactly_k or bitset_len(current) == mk - 1:
983
+ if vertices_only:
984
+ yield vertices
985
+ else:
986
+ H = G.subgraph(vertices)
987
+ if induced:
988
+ if edges_only:
989
+ yield H.edges(sort=False, labels=labels)
990
+ else:
991
+ yield H
992
+ else:
993
+ # We use a decomposition into biconnected components to
994
+ # work on smaller graphs.
995
+ if H.is_directed():
996
+ blocks = H.to_undirected().blocks_and_cut_vertices()[0]
997
+ else:
998
+ blocks = H.blocks_and_cut_vertices()[0]
999
+ if len(blocks) == 1:
1000
+ # H is strongly connected or biconnected
1001
+ yield from connected_full_subgraphs(H, edges_only=edges_only,
1002
+ labels=labels)
1003
+ else:
1004
+ L = []
1005
+ for bloc in blocks:
1006
+ if len(bloc) == 2:
1007
+ bb = [[e] for e in H.edge_boundary(bloc, bloc, labels=labels)]
1008
+ if len(bb) == 2:
1009
+ # H is directed with edges (u, v) and (v, u)
1010
+ bb.append(H.edge_boundary(bloc, bloc, labels=labels))
1011
+ L.append(bb)
1012
+ else:
1013
+ L.append(connected_full_subgraphs(H.subgraph(vertices=bloc),
1014
+ edges_only=True, labels=labels))
1015
+
1016
+ for edges in product(*L):
1017
+ good_edges = flatten(edges, ltypes=list)
1018
+ if edges_only:
1019
+ yield list(good_edges)
1020
+ else:
1021
+ yield H.subgraph(vertices=H, edges=good_edges)
1022
+
1023
+ else:
1024
+ # We cannot extend the current subset, either due to a lack of
1025
+ # candidate (v == -1), or because the current subset has maximum
1026
+ # size. We pop
1027
+ level -= 3
1028
+
1029
+ sig_on()
1030
+ binary_matrix_free(stack)
1031
+ binary_matrix_free(DG)
1032
+ sig_off()