passagemath-graphs 10.5.43__cp39-cp39-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 (258) hide show
  1. passagemath_graphs-10.5.43.dist-info/METADATA +293 -0
  2. passagemath_graphs-10.5.43.dist-info/RECORD +258 -0
  3. passagemath_graphs-10.5.43.dist-info/WHEEL +5 -0
  4. passagemath_graphs-10.5.43.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 +2552 -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 +125 -0
  15. sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
  16. sage/combinat/cluster_algebra_quiver/mutation_type.py +1556 -0
  17. sage/combinat/cluster_algebra_quiver/quiver.py +2262 -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 +534 -0
  25. sage/combinat/designs/database.py +5614 -0
  26. sage/combinat/designs/design_catalog.py +122 -0
  27. sage/combinat/designs/designs_pyx.cpython-39-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-39-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-39-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 +548 -0
  40. sage/combinat/designs/orthogonal_arrays.py +2243 -0
  41. sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
  42. sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-39-aarch64-linux-gnu.so +0 -0
  43. sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +966 -0
  44. sage/combinat/designs/resolvable_bibd.py +781 -0
  45. sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
  46. sage/combinat/designs/subhypergraph_search.cpython-39-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/cartesian_product.py +493 -0
  57. sage/combinat/posets/d_complete.py +182 -0
  58. sage/combinat/posets/elements.py +273 -0
  59. sage/combinat/posets/forest.py +30 -0
  60. sage/combinat/posets/hasse_cython.cpython-39-aarch64-linux-gnu.so +0 -0
  61. sage/combinat/posets/hasse_cython.pyx +174 -0
  62. sage/combinat/posets/hasse_diagram.py +3678 -0
  63. sage/combinat/posets/incidence_algebras.py +796 -0
  64. sage/combinat/posets/lattices.py +5119 -0
  65. sage/combinat/posets/linear_extension_iterator.cpython-39-aarch64-linux-gnu.so +0 -0
  66. sage/combinat/posets/linear_extension_iterator.pyx +292 -0
  67. sage/combinat/posets/linear_extensions.py +1039 -0
  68. sage/combinat/posets/mobile.py +275 -0
  69. sage/combinat/posets/moebius_algebra.py +776 -0
  70. sage/combinat/posets/poset_examples.py +2131 -0
  71. sage/combinat/posets/posets.py +9169 -0
  72. sage/combinat/rooted_tree.py +1070 -0
  73. sage/combinat/shard_order.py +239 -0
  74. sage/combinat/tamari_lattices.py +384 -0
  75. sage/combinat/yang_baxter_graph.py +923 -0
  76. sage/databases/all__sagemath_graphs.py +1 -0
  77. sage/databases/knotinfo_db.py +1230 -0
  78. sage/ext_data/all__sagemath_graphs.py +1 -0
  79. sage/ext_data/graphs/graph_plot_js.html +330 -0
  80. sage/ext_data/kenzo/CP2.txt +45 -0
  81. sage/ext_data/kenzo/CP3.txt +349 -0
  82. sage/ext_data/kenzo/CP4.txt +4774 -0
  83. sage/ext_data/kenzo/README.txt +49 -0
  84. sage/ext_data/kenzo/S4.txt +20 -0
  85. sage/graphs/all.py +42 -0
  86. sage/graphs/asteroidal_triples.cpython-39-aarch64-linux-gnu.so +0 -0
  87. sage/graphs/asteroidal_triples.pyx +299 -0
  88. sage/graphs/base/all.py +1 -0
  89. sage/graphs/base/boost_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  90. sage/graphs/base/boost_graph.pxd +106 -0
  91. sage/graphs/base/boost_graph.pyx +3045 -0
  92. sage/graphs/base/c_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  93. sage/graphs/base/c_graph.pxd +106 -0
  94. sage/graphs/base/c_graph.pyx +5096 -0
  95. sage/graphs/base/dense_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  96. sage/graphs/base/dense_graph.pxd +26 -0
  97. sage/graphs/base/dense_graph.pyx +757 -0
  98. sage/graphs/base/graph_backends.cpython-39-aarch64-linux-gnu.so +0 -0
  99. sage/graphs/base/graph_backends.pxd +5 -0
  100. sage/graphs/base/graph_backends.pyx +797 -0
  101. sage/graphs/base/overview.py +85 -0
  102. sage/graphs/base/sparse_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  103. sage/graphs/base/sparse_graph.pxd +90 -0
  104. sage/graphs/base/sparse_graph.pyx +1653 -0
  105. sage/graphs/base/static_dense_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  106. sage/graphs/base/static_dense_graph.pxd +5 -0
  107. sage/graphs/base/static_dense_graph.pyx +1032 -0
  108. sage/graphs/base/static_sparse_backend.cpython-39-aarch64-linux-gnu.so +0 -0
  109. sage/graphs/base/static_sparse_backend.pxd +27 -0
  110. sage/graphs/base/static_sparse_backend.pyx +1580 -0
  111. sage/graphs/base/static_sparse_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  112. sage/graphs/base/static_sparse_graph.pxd +37 -0
  113. sage/graphs/base/static_sparse_graph.pyx +1304 -0
  114. sage/graphs/bipartite_graph.py +2709 -0
  115. sage/graphs/centrality.cpython-39-aarch64-linux-gnu.so +0 -0
  116. sage/graphs/centrality.pyx +965 -0
  117. sage/graphs/cographs.py +519 -0
  118. sage/graphs/comparability.cpython-39-aarch64-linux-gnu.so +0 -0
  119. sage/graphs/comparability.pyx +813 -0
  120. sage/graphs/connectivity.cpython-39-aarch64-linux-gnu.so +0 -0
  121. sage/graphs/connectivity.pxd +157 -0
  122. sage/graphs/connectivity.pyx +4813 -0
  123. sage/graphs/convexity_properties.cpython-39-aarch64-linux-gnu.so +0 -0
  124. sage/graphs/convexity_properties.pxd +16 -0
  125. sage/graphs/convexity_properties.pyx +827 -0
  126. sage/graphs/digraph.py +4410 -0
  127. sage/graphs/digraph_generators.py +1921 -0
  128. sage/graphs/distances_all_pairs.cpython-39-aarch64-linux-gnu.so +0 -0
  129. sage/graphs/distances_all_pairs.pxd +12 -0
  130. sage/graphs/distances_all_pairs.pyx +2938 -0
  131. sage/graphs/domination.py +1363 -0
  132. sage/graphs/dot2tex_utils.py +100 -0
  133. sage/graphs/edge_connectivity.cpython-39-aarch64-linux-gnu.so +0 -0
  134. sage/graphs/edge_connectivity.pyx +1215 -0
  135. sage/graphs/generators/all.py +1 -0
  136. sage/graphs/generators/basic.py +1769 -0
  137. sage/graphs/generators/chessboard.py +538 -0
  138. sage/graphs/generators/classical_geometries.py +1611 -0
  139. sage/graphs/generators/degree_sequence.py +235 -0
  140. sage/graphs/generators/distance_regular.cpython-39-aarch64-linux-gnu.so +0 -0
  141. sage/graphs/generators/distance_regular.pyx +2846 -0
  142. sage/graphs/generators/families.py +4749 -0
  143. sage/graphs/generators/intersection.py +565 -0
  144. sage/graphs/generators/platonic_solids.py +262 -0
  145. sage/graphs/generators/random.py +2623 -0
  146. sage/graphs/generators/smallgraphs.py +5741 -0
  147. sage/graphs/generators/world_map.py +724 -0
  148. sage/graphs/generic_graph.py +26395 -0
  149. sage/graphs/generic_graph_pyx.cpython-39-aarch64-linux-gnu.so +0 -0
  150. sage/graphs/generic_graph_pyx.pxd +34 -0
  151. sage/graphs/generic_graph_pyx.pyx +1626 -0
  152. sage/graphs/genus.cpython-39-aarch64-linux-gnu.so +0 -0
  153. sage/graphs/genus.pyx +623 -0
  154. sage/graphs/graph.py +9362 -0
  155. sage/graphs/graph_coloring.cpython-39-aarch64-linux-gnu.so +0 -0
  156. sage/graphs/graph_coloring.pyx +2284 -0
  157. sage/graphs/graph_database.py +1122 -0
  158. sage/graphs/graph_decompositions/all.py +1 -0
  159. sage/graphs/graph_decompositions/bandwidth.cpython-39-aarch64-linux-gnu.so +0 -0
  160. sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
  161. sage/graphs/graph_decompositions/clique_separators.cpython-39-aarch64-linux-gnu.so +0 -0
  162. sage/graphs/graph_decompositions/clique_separators.pyx +595 -0
  163. sage/graphs/graph_decompositions/cutwidth.cpython-39-aarch64-linux-gnu.so +0 -0
  164. sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
  165. sage/graphs/graph_decompositions/fast_digraph.cpython-39-aarch64-linux-gnu.so +0 -0
  166. sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
  167. sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
  168. sage/graphs/graph_decompositions/graph_products.cpython-39-aarch64-linux-gnu.so +0 -0
  169. sage/graphs/graph_decompositions/graph_products.pyx +462 -0
  170. sage/graphs/graph_decompositions/modular_decomposition.cpython-39-aarch64-linux-gnu.so +0 -0
  171. sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
  172. sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
  173. sage/graphs/graph_decompositions/slice_decomposition.cpython-39-aarch64-linux-gnu.so +0 -0
  174. sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
  175. sage/graphs/graph_decompositions/slice_decomposition.pyx +1080 -0
  176. sage/graphs/graph_decompositions/tree_decomposition.cpython-39-aarch64-linux-gnu.so +0 -0
  177. sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
  178. sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
  179. sage/graphs/graph_decompositions/vertex_separation.cpython-39-aarch64-linux-gnu.so +0 -0
  180. sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
  181. sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
  182. sage/graphs/graph_editor.py +82 -0
  183. sage/graphs/graph_generators.py +3301 -0
  184. sage/graphs/graph_generators_pyx.cpython-39-aarch64-linux-gnu.so +0 -0
  185. sage/graphs/graph_generators_pyx.pyx +95 -0
  186. sage/graphs/graph_input.py +812 -0
  187. sage/graphs/graph_latex.py +2064 -0
  188. sage/graphs/graph_list.py +367 -0
  189. sage/graphs/graph_plot.py +1749 -0
  190. sage/graphs/graph_plot_js.py +338 -0
  191. sage/graphs/hyperbolicity.cpython-39-aarch64-linux-gnu.so +0 -0
  192. sage/graphs/hyperbolicity.pyx +1702 -0
  193. sage/graphs/hypergraph_generators.py +364 -0
  194. sage/graphs/independent_sets.cpython-39-aarch64-linux-gnu.so +0 -0
  195. sage/graphs/independent_sets.pxd +13 -0
  196. sage/graphs/independent_sets.pyx +402 -0
  197. sage/graphs/isgci.py +1033 -0
  198. sage/graphs/isoperimetric_inequalities.cpython-39-aarch64-linux-gnu.so +0 -0
  199. sage/graphs/isoperimetric_inequalities.pyx +453 -0
  200. sage/graphs/line_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  201. sage/graphs/line_graph.pyx +627 -0
  202. sage/graphs/lovasz_theta.py +77 -0
  203. sage/graphs/matching.py +1633 -0
  204. sage/graphs/matching_covered_graph.py +3566 -0
  205. sage/graphs/orientations.py +1504 -0
  206. sage/graphs/partial_cube.py +459 -0
  207. sage/graphs/path_enumeration.cpython-39-aarch64-linux-gnu.so +0 -0
  208. sage/graphs/path_enumeration.pyx +2040 -0
  209. sage/graphs/pq_trees.py +1129 -0
  210. sage/graphs/print_graphs.py +201 -0
  211. sage/graphs/schnyder.py +865 -0
  212. sage/graphs/spanning_tree.cpython-39-aarch64-linux-gnu.so +0 -0
  213. sage/graphs/spanning_tree.pyx +1457 -0
  214. sage/graphs/strongly_regular_db.cpython-39-aarch64-linux-gnu.so +0 -0
  215. sage/graphs/strongly_regular_db.pyx +3340 -0
  216. sage/graphs/traversals.cpython-39-aarch64-linux-gnu.so +0 -0
  217. sage/graphs/traversals.pxd +9 -0
  218. sage/graphs/traversals.pyx +1871 -0
  219. sage/graphs/trees.cpython-39-aarch64-linux-gnu.so +0 -0
  220. sage/graphs/trees.pxd +15 -0
  221. sage/graphs/trees.pyx +310 -0
  222. sage/graphs/tutte_polynomial.py +713 -0
  223. sage/graphs/views.cpython-39-aarch64-linux-gnu.so +0 -0
  224. sage/graphs/views.pyx +794 -0
  225. sage/graphs/weakly_chordal.cpython-39-aarch64-linux-gnu.so +0 -0
  226. sage/graphs/weakly_chordal.pyx +562 -0
  227. sage/groups/all__sagemath_graphs.py +1 -0
  228. sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
  229. sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
  230. sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-39-aarch64-linux-gnu.so +0 -0
  231. sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
  232. sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
  233. sage/knots/all.py +6 -0
  234. sage/knots/free_knotinfo_monoid.py +507 -0
  235. sage/knots/gauss_code.py +291 -0
  236. sage/knots/knot.py +682 -0
  237. sage/knots/knot_table.py +284 -0
  238. sage/knots/knotinfo.py +2880 -0
  239. sage/knots/link.py +4682 -0
  240. sage/sandpiles/all.py +13 -0
  241. sage/sandpiles/examples.py +225 -0
  242. sage/sandpiles/sandpile.py +6365 -0
  243. sage/topology/all.py +22 -0
  244. sage/topology/cell_complex.py +1214 -0
  245. sage/topology/cubical_complex.py +1977 -0
  246. sage/topology/delta_complex.py +1806 -0
  247. sage/topology/filtered_simplicial_complex.py +744 -0
  248. sage/topology/moment_angle_complex.py +823 -0
  249. sage/topology/simplicial_complex.py +5161 -0
  250. sage/topology/simplicial_complex_catalog.py +86 -0
  251. sage/topology/simplicial_complex_examples.py +1692 -0
  252. sage/topology/simplicial_complex_homset.py +205 -0
  253. sage/topology/simplicial_complex_morphism.py +836 -0
  254. sage/topology/simplicial_set.py +4102 -0
  255. sage/topology/simplicial_set_catalog.py +55 -0
  256. sage/topology/simplicial_set_constructions.py +2954 -0
  257. sage/topology/simplicial_set_examples.py +865 -0
  258. sage/topology/simplicial_set_morphism.py +1464 -0
@@ -0,0 +1,13 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ from libc.stdint cimport uint8_t
3
+
4
+ cdef class FastDigraph:
5
+ cdef uint8_t n
6
+ cdef int * graph
7
+ cdef list int_to_vertices
8
+ cdef int * degree
9
+
10
+ cdef int compute_out_neighborhood_cardinality(FastDigraph, int) noexcept
11
+
12
+ cdef int popcount32(int) noexcept
13
+ cdef int slow_popcount32(int) noexcept
@@ -0,0 +1,212 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ r"""
3
+ Compact structure for fast operations on less than 32 vertices
4
+
5
+ This module implements a digraph structure meant to be used in Cython in
6
+ **highly enumerative** algorithms. It can store graphs on less than
7
+ ``sizeof(int)`` vertices and perform several basic operations **quickly**
8
+ (add/remove arcs, count the out-neighborhood of a set of vertices or return its
9
+ cardinality).
10
+
11
+ **Sets and integers :**
12
+
13
+ In the following code, sets are represented as integers, where the `i`-th bit is
14
+ set if element `i` belongs to the set.
15
+ """
16
+ from cysignals.memory cimport check_allocarray, check_calloc, sig_free
17
+
18
+
19
+ cdef class FastDigraph:
20
+
21
+ def __cinit__(self, D, vertex_list=None):
22
+ r"""
23
+ Constructor for ``FastDigraph``.
24
+
25
+ If the input parameter ``D`` is a Graph, it is handled as a symmetric
26
+ DiGraph.
27
+
28
+ INPUT:
29
+
30
+ - ``D`` -- a (Di)Graph
31
+
32
+ - ``vertex_list`` -- list (default: ``None``); specifies a mapping
33
+ between `[0..n-1]` and the set of vertices of the input (Di)Graph,
34
+ ``list(D)`` by default
35
+
36
+ EXAMPLES::
37
+
38
+ sage: cython_code = [
39
+ ....: 'from sage.graphs.graph import Graph',
40
+ ....: 'from sage.graphs.graph_decompositions.fast_digraph cimport FastDigraph',
41
+ ....: 'G = Graph([(0, 1), (1, 2)])',
42
+ ....: 'cdef FastDigraph F = FastDigraph(G)',
43
+ ....: 'cdef int i',
44
+ ....: 'print([F.degree[i] for i in range(F.n)])']
45
+ sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython
46
+ [1, 2, 1]
47
+ """
48
+ if D.order() > 8*sizeof(int):
49
+ raise OverflowError("Too many vertices. This structure can only "
50
+ "encode digraphs on at most "
51
+ "%i vertices" % (8 * sizeof(int)))
52
+
53
+ self.n = D.order()
54
+ self.graph = <int *>check_calloc(self.n, sizeof(int))
55
+
56
+ cdef int i
57
+ cdef int tmp
58
+
59
+ # When the vertices are not consecutive integers
60
+ if vertex_list is None:
61
+ self.int_to_vertices = list(D)
62
+ elif len(vertex_list) == self.n and not set(vertex_list).symmetric_difference(D):
63
+ self.int_to_vertices = list(vertex_list)
64
+ else:
65
+ raise ValueError("the input vertex_list is incorrect")
66
+ cdef dict vertices_to_int = {v: i for i, v in enumerate(self.int_to_vertices)}
67
+
68
+ if D.is_directed():
69
+ for u in D:
70
+ tmp = 0
71
+ for v in D.neighbors_out(u):
72
+ tmp |= 1 << vertices_to_int[v]
73
+ self.graph[vertices_to_int[u]] = tmp
74
+ else:
75
+ for u in D:
76
+ tmp = 0
77
+ for v in D.neighbors(u):
78
+ tmp |= 1 << vertices_to_int[v]
79
+ self.graph[vertices_to_int[u]] = tmp
80
+
81
+ self.degree = <int *>check_allocarray(self.n, sizeof(int))
82
+ for i in range(self.n):
83
+ self.degree[i] = popcount32(self.graph[i])
84
+
85
+ def __dealloc__(self):
86
+ r"""
87
+ Destructor.
88
+ """
89
+ sig_free(self.graph)
90
+ sig_free(self.degree)
91
+
92
+ def print_adjacency_matrix(self):
93
+ r"""
94
+ Displays the adjacency matrix of ``self``.
95
+
96
+ EXAMPLES::
97
+
98
+ sage: cython_code = [
99
+ ....: 'from sage.graphs.graph import Graph',
100
+ ....: 'from sage.graphs.graph_decompositions.fast_digraph cimport FastDigraph',
101
+ ....: 'FastDigraph(Graph([(0, 1), (1, 2)])).print_adjacency_matrix()']
102
+ sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython
103
+ 010
104
+ 101
105
+ 010
106
+ """
107
+ cdef int i, j
108
+ for i in range(self.n):
109
+ for j in range(self.n):
110
+ print(((self.graph[i] >> j) & 1), end="")
111
+ print("")
112
+
113
+ cdef inline int compute_out_neighborhood_cardinality(FastDigraph g, int S) noexcept:
114
+ r"""
115
+ Return the cardinality of `N^+(S)\S`.
116
+
117
+ INPUT:
118
+
119
+ - ``g`` -- a FastDigraph
120
+
121
+ - ``S`` -- integer describing the set
122
+
123
+ EXAMPLES::
124
+
125
+ sage: cython_code = [
126
+ ....: 'from sage.graphs.graph import Graph',
127
+ ....: 'from sage.graphs.graph_decompositions.fast_digraph cimport FastDigraph',
128
+ ....: 'from sage.graphs.graph_decompositions.fast_digraph cimport compute_out_neighborhood_cardinality',
129
+ ....: 'cdef FastDigraph F = FastDigraph(Graph([(0, 1), (1, 2)]))',
130
+ ....: 'cdef int i',
131
+ ....: 'print([compute_out_neighborhood_cardinality(F, 1<<i) for i in range(F.n)])']
132
+ sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython
133
+ [1, 2, 1]
134
+ """
135
+ cdef int i
136
+ cdef int tmp = 0
137
+ for i in range(g.n):
138
+ tmp |= g.graph[i] & (-((S >> i) & 1))
139
+
140
+ tmp &= (~S)
141
+ return popcount32(tmp)
142
+
143
+ cdef inline int popcount32(int i) noexcept:
144
+ r"""
145
+ Return the number of '1' bits in a 32-bits integer.
146
+
147
+ If ``sizeof(int) > 4``, this function only returns the number of '1'
148
+ bits in ``(i & ((1<<32) - 1))``.
149
+
150
+ EXAMPLES::
151
+
152
+ sage: cython_code = [
153
+ ....: 'from sage.graphs.graph_decompositions.fast_digraph cimport popcount32',
154
+ ....: 'cdef int i',
155
+ ....: 'print([popcount32(i) for i in range(16)])']
156
+ sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython
157
+ [0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4]
158
+ """
159
+ i = i - ((i >> 1) & 0x55555555)
160
+ i = (i & 0x33333333) + ((i >> 2) & 0x33333333)
161
+ return ((i + (i >> 4) & 0x0F0F0F0F) * 0x01010101) >> 24
162
+
163
+
164
+ # If you happened to be doubting the consistency of the popcount32 function
165
+ # above, you can give the following doctest a try. It is not tested
166
+ # automatically by Sage as it takes a *LONG* time to run (around 5 minutes), but
167
+ # it would report any problem if it finds one.
168
+
169
+ def test_popcount():
170
+ """
171
+ Correction test for popcount32.
172
+
173
+ EXAMPLES::
174
+
175
+ sage: from sage.graphs.graph_decompositions.fast_digraph import test_popcount
176
+ sage: test_popcount() # not tested
177
+ """
178
+ cdef int i = 1
179
+ # While the last 32 bits of i are not equal to 0
180
+ while (i & ((1 << 32) - 1)):
181
+ if popcount32(i) != slow_popcount32(i):
182
+ print("Error for i = ", str(i))
183
+ print("Result with popcount32 : " + str(popcount32(i)))
184
+ print("Result with slow_popcount32 : " + str(slow_popcount32(i)))
185
+ i += 1
186
+
187
+
188
+ cdef inline int slow_popcount32(int i) noexcept:
189
+ """
190
+ Return the number of '1' bits in a 32-bits integer.
191
+
192
+ If ``sizeof(int) > 4``, this function only returns the number of '1'
193
+ bits in ``(i & ((1<<32) - 1))``.
194
+
195
+ EXAMPLES::
196
+
197
+ sage: cython_code = [
198
+ ....: 'from sage.graphs.graph_decompositions.fast_digraph cimport popcount32',
199
+ ....: 'from sage.graphs.graph_decompositions.fast_digraph cimport slow_popcount32',
200
+ ....: 'cdef int i',
201
+ ....: 'print(all(popcount32(i) == slow_popcount32(i) for i in range(16)))']
202
+ sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython
203
+ True
204
+ """
205
+ # Slow popcount for 32bits integers
206
+ cdef int j = 0
207
+ cdef int k
208
+
209
+ for k in range(32):
210
+ j += (i >> k) & 1
211
+
212
+ return j
@@ -0,0 +1,462 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ # cython: binding=True
3
+ r"""
4
+ Products of graphs
5
+
6
+ This module gathers everything related to graph products. At the moment it
7
+ contains an implementation of a recognition algorithm for graphs that can be
8
+ written as a Cartesian product of smaller ones.
9
+
10
+ Author:
11
+
12
+ - Nathann Cohen (May 2012 -- coded while watching the election of Francois
13
+ Hollande on TV)
14
+
15
+ Cartesian product of graphs -- the recognition problem
16
+ ------------------------------------------------------
17
+
18
+ First, a definition:
19
+
20
+ **Definition** The Cartesian product of two graphs `G` and `H`, denoted
21
+ `G\square H`, is a graph defined on the pairs `(g, h)\in V(G)\times V(H)`.
22
+
23
+ Two elements `(g, h),(g', h')\in V(G\square H)` are adjacent in `G\square H`
24
+ if and only if :
25
+
26
+ - `g=g'` and `hh'\in H`; or
27
+ - `h=h'` and `gg'\in G`
28
+
29
+ Two remarks follow :
30
+
31
+ #. The Cartesian product is commutative
32
+
33
+ #. Any edge `uv` of a graph `G_1 \square \cdots \square G_k` can be given a
34
+ color `i` corresponding to the unique index `i` such that `u_i` and `v_i`
35
+ differ.
36
+
37
+ The problem that is of interest to us in the present module is the following:
38
+
39
+ **Recognition problem** Given a graph `G`, can we guess whether there exist
40
+ graphs `G_1, ..., G_k` such that `G=G_1\square \cdots \square G_k` ?
41
+
42
+ This problem can actually be solved, and the resulting factorization is
43
+ unique. What is explained below can be found in the book *Handbook of Product
44
+ Graphs* [HIK2011]_.
45
+
46
+ Everything is actually based on simple observations. Given a graph `G`, finding
47
+ out whether `G` can be written as the product of several graphs can be attempted
48
+ by trying to color its edges according to some rules. Indeed, if we are to color
49
+ the edges of `G` in such a way that each color class represents a factor of `G`,
50
+ we must ensure several things.
51
+
52
+ **Remark 1** In any cycle of `G` no color can appear exactly once.
53
+
54
+ Indeed, if only one edge `uv` of a cycle were labelled with color `i`, it
55
+ would mean that:
56
+
57
+ #. The only difference between `u` and `v` lies in their `i` th coordinate
58
+
59
+ #. It is possible to go from `u` to `v` by changing only coordinates
60
+ different from the `i` th
61
+
62
+ A contradiction indeed.
63
+
64
+ .. image:: ../../../media/cycle.png
65
+
66
+ That means that, for instance, the edges of a triangle necessarily have the
67
+ same color.
68
+
69
+ **Remark 2** If two consecutive edges `u_1u_2` and `u_2u_3` have different
70
+ colors, there necessarily exists a unique vertex `u_4` different from `u_2`
71
+ and incident to both `u_1` and `u_3`.
72
+
73
+ In this situation, opposed edges necessarily have the same colors because of
74
+ the previous remark.
75
+
76
+ .. image:: ../../../media/square.png
77
+
78
+ **1st criterion** : As a corollary, we know that:
79
+
80
+ #. If two vertices `u,v` have a *unique* common neighbor `x`, then `ux` and
81
+ `xv` have the same color.
82
+
83
+ #. If two vertices `u, v` have more that two common neighbors `x_1, ...,
84
+ x_k` then all edges between the `x_i` and the vertices of `u,v` have the
85
+ same color. This is also a consequence of the first remark.
86
+
87
+ **2nd criterion** : if two edges `uv` and `u'v'` of the product graph
88
+ `G\square H` are such that `d(u,u')+d(v,v')\neq d(u,v') + d(v,u')` then the
89
+ two edges `uv` and `u'v'` necessarily have the same color.
90
+
91
+ This is a consequence of the fact that for any two vertices `u,v` of
92
+ `G\square H` (where `u=(u_G,u_H)` and `v=(v_G,v_H)`), we have `d(u,v) =
93
+ d_G(u_G,v_G)+d_H(u_H,v_H)`. Indeed, a shortest path from `u` to `v` in
94
+ `G\square H` contains the information of a shortest path from `u_G` to `v_G`
95
+ in `G`, and a shortest path from `u_H` to `v_H` in `H`.
96
+
97
+ The algorithm
98
+ ^^^^^^^^^^^^^
99
+
100
+ The previous remarks tell us that some edges are in some way equivalent to some
101
+ others, i.e. that their colors are equal. In order to compute the coloring we
102
+ are looking for, we therefore build a graph on the *edges* of a graph `G`,
103
+ linking two edges whenever they are found to be equivalent according to the
104
+ previous remarks.
105
+
106
+ All that is left to do is to compute the connected components of this new graph,
107
+ as each of them representing the edges of a factor. Of course, only one
108
+ connected component indicates that the graph has no factorization.
109
+
110
+ Then again, please refer to [HIK2011]_ for any technical question.
111
+
112
+ To Do
113
+ ^^^^^
114
+
115
+ This implementation is made at Python level, and some parts of the algorithm
116
+ could be rewritten in Cython to save time. Especially when enumerating all pairs
117
+ of edges and computing their distances. This can easily be done in C with the
118
+ functions from the :mod:`sage.graphs.distances_all_pairs` module.
119
+
120
+ Methods
121
+ -------
122
+ """
123
+
124
+ # ****************************************************************************
125
+ # Copyright (C) 2012 Nathann Cohen <nathann.cohen@gmail.com>
126
+ #
127
+ # This program is free software: you can redistribute it and/or modify
128
+ # it under the terms of the GNU General Public License as published by
129
+ # the Free Software Foundation, either version 2 of the License, or
130
+ # (at your option) any later version.
131
+ # https://www.gnu.org/licenses/
132
+ # ****************************************************************************
133
+
134
+
135
+ def is_cartesian_product(g, certificate=False, relabeling=False):
136
+ r"""
137
+ Test whether the graph is a Cartesian product.
138
+
139
+ INPUT:
140
+
141
+ - ``certificate`` -- boolean (default: ``False``); if ``certificate =
142
+ False`` (default) the method only returns ``True`` or ``False``
143
+ answers. If ``certificate = True``, the ``True`` answers are replaced by
144
+ the list of the factors of the graph.
145
+
146
+ - ``relabeling`` -- boolean (default: ``False``); if ``relabeling = True``
147
+ (implies ``certificate = True``), the method also returns a dictionary
148
+ associating to each vertex its natural coordinates as a vertex of a
149
+ product graph. If `g` is not a Cartesian product, ``None`` is returned
150
+ instead.
151
+
152
+ .. SEEALSO::
153
+
154
+ - :meth:`sage.graphs.generic_graph.GenericGraph.cartesian_product`
155
+
156
+ - :mod:`~sage.graphs.graph_decompositions.graph_products` -- a module on
157
+ graph products
158
+
159
+ .. NOTE::
160
+
161
+ This algorithm may run faster whenever the graph's vertices are integers
162
+ (see :meth:`~sage.graphs.generic_graph.GenericGraph.relabel`). Give it a
163
+ try if it is too slow !
164
+
165
+ EXAMPLES:
166
+
167
+ The Petersen graph is prime::
168
+
169
+ sage: from sage.graphs.graph_decompositions.graph_products import is_cartesian_product
170
+ sage: g = graphs.PetersenGraph()
171
+ sage: is_cartesian_product(g)
172
+ False
173
+
174
+ A 2d grid is the product of paths::
175
+
176
+ sage: g = graphs.Grid2dGraph(5,5)
177
+ sage: p1, p2 = is_cartesian_product(g, certificate = True)
178
+ sage: p1.is_isomorphic(graphs.PathGraph(5))
179
+ True
180
+ sage: p2.is_isomorphic(graphs.PathGraph(5))
181
+ True
182
+
183
+ Forgetting the graph's labels, then finding them back::
184
+
185
+ sage: g.relabel()
186
+ sage: b,D = g.is_cartesian_product(g, relabeling=True)
187
+ sage: b
188
+ True
189
+ sage: D # random isomorphism
190
+ {0: (20, 0), 1: (20, 1), 2: (20, 2), 3: (20, 3), 4: (20, 4),
191
+ 5: (15, 0), 6: (15, 1), 7: (15, 2), 8: (15, 3), 9: (15, 4),
192
+ 10: (10, 0), 11: (10, 1), 12: (10, 2), 13: (10, 3), 14: (10, 4),
193
+ 15: (5, 0), 16: (5, 1), 17: (5, 2), 18: (5, 3), 19: (5, 4),
194
+ 20: (0, 0), 21: (0, 1), 22: (0, 2), 23: (0, 3), 24: (0, 4)}
195
+
196
+ And of course, we find the factors back when we build a graph from a
197
+ product::
198
+
199
+ sage: g = graphs.PetersenGraph().cartesian_product(graphs.CycleGraph(3))
200
+ sage: g1, g2 = is_cartesian_product(g, certificate = True)
201
+ sage: any( x.is_isomorphic(graphs.PetersenGraph()) for x in [g1,g2])
202
+ True
203
+ sage: any( x.is_isomorphic(graphs.CycleGraph(3)) for x in [g1,g2])
204
+ True
205
+
206
+ TESTS:
207
+
208
+ Wagner's Graph (:issue:`13599`)::
209
+
210
+ sage: g = graphs.WagnerGraph() # needs networkx
211
+ sage: g.is_cartesian_product() # needs networkx
212
+ False
213
+
214
+ Empty and one-element graph (:issue:`19546`)::
215
+
216
+ sage: Graph().is_cartesian_product()
217
+ False
218
+ sage: Graph({0:[]}).is_cartesian_product()
219
+ False
220
+ """
221
+ g._scream_if_not_simple()
222
+ if g.is_directed():
223
+ raise NotImplementedError("recognition of Cartesian product is not implemented for directed graphs")
224
+ if relabeling:
225
+ certificate = True
226
+
227
+ from sage.rings.integer import Integer
228
+
229
+ if not g.is_connected():
230
+ raise NotImplementedError("recognition of Cartesian product is not implemented for disconnected graphs")
231
+
232
+ # Of course the number of vertices of g cannot be prime !
233
+ if g.order() <= 3 or Integer(g.order()).is_prime():
234
+ return (False, None) if relabeling else False
235
+
236
+ from sage.graphs.graph import Graph
237
+
238
+ # As we need the vertices of g to be linearly ordered, we copy the graph and
239
+ # relabel it
240
+ cdef list int_to_vertex = list(g)
241
+ cdef dict vertex_to_int = {vert: i for i, vert in enumerate(int_to_vertex)}
242
+ g_int = g.relabel(perm=vertex_to_int, inplace=False)
243
+
244
+ # Reorder the vertices of an edge
245
+ def r(x, y):
246
+ return (x, y) if x < y else (y, x)
247
+
248
+ cdef int x, y, u, v
249
+ cdef set un, intersect
250
+
251
+ # The equivalence graph on the edges of g
252
+ h = Graph()
253
+ h.add_vertices(r(x, y) for x, y in g_int.edge_iterator(labels=False))
254
+
255
+ # For all pairs of vertices u,v of G, according to their number of common
256
+ # neighbors... See the module's documentation !
257
+ for u in g_int:
258
+ un = set(g_int.neighbor_iterator(u))
259
+ for v in g_int.breadth_first_search(u):
260
+
261
+ # u and v are different
262
+ if u == v:
263
+ continue
264
+
265
+ # List of common neighbors
266
+ intersect = un & set(g_int.neighbor_iterator(v))
267
+
268
+ # If u and v have no neighbors and uv is not an edge then their
269
+ # distance is at least 3. As we enumerate the vertices in a
270
+ # breadth-first search, it means that we already checked all the
271
+ # vertices at distance less than two from u, and we are done with
272
+ # this loop !
273
+ if not intersect:
274
+ if g_int.has_edge(u, v):
275
+ continue
276
+ else:
277
+ break
278
+
279
+ # If uv is an edge
280
+ if g_int.has_edge(u, v):
281
+ h.add_path([r(u, x) for x in intersect] + [r(v, x) for x in intersect])
282
+
283
+ # Only one common neighbor
284
+ elif len(intersect) == 1:
285
+ x = intersect.pop()
286
+ h.add_edge(r(u, x), r(v, x))
287
+
288
+ # Exactly 2 neighbors
289
+ elif len(intersect) == 2:
290
+ x, y = intersect
291
+ h.add_edge(r(u, x), r(v, y))
292
+ h.add_edge(r(v, x), r(u, y))
293
+ # More
294
+ else:
295
+ h.add_path([r(u, x) for x in intersect] + [r(v, x) for x in intersect])
296
+
297
+ # Edges uv and u'v' such that d(u,u')+d(v,v') != d(u,v')+d(v,u') are also
298
+ # equivalent
299
+
300
+ cdef list edges = list(g_int.edges(labels=False, sort=False))
301
+ cdef dict d = g_int.distance_all_pairs()
302
+ cdef int uu, vv
303
+ for i, (u, v) in enumerate(edges):
304
+ du = d[u]
305
+ dv = d[v]
306
+ for j in range(i + 1, g_int.size()):
307
+ uu, vv = edges[j]
308
+ if du[uu] + dv[vv] != du[vv] + dv[uu]:
309
+ h.add_edge(r(u, v), r(uu, vv))
310
+
311
+ # Gathering the connected components, relabeling the vertices on-the-fly
312
+ edges = [[(int_to_vertex[u], int_to_vertex[v]) for u, v in cc]
313
+ for cc in h.connected_components(sort=False)]
314
+
315
+ # Only one connected component ?
316
+ if len(edges) == 1:
317
+ return (False, None) if relabeling else False
318
+
319
+ # Building the list of factors
320
+ cdef list factors = []
321
+ for cc in edges:
322
+ tmp = Graph()
323
+ tmp.add_edges(cc)
324
+ factors.append(tmp.subgraph(vertices=tmp.connected_components(sort=False)[0]))
325
+
326
+ # Computing the product of these graphs
327
+ answer = factors[0]
328
+ for i in range(1, len(factors)):
329
+ answer = answer.cartesian_product(factors[i])
330
+
331
+ # Checking that the resulting graph is indeed isomorphic to what we have.
332
+ isiso, dictt = g.is_isomorphic(answer, certificate=True)
333
+ if not isiso:
334
+ raise ValueError("something weird happened during the algorithm... "
335
+ "Please report the bug and give us the graph instance"
336
+ " that made it fail !")
337
+ if relabeling:
338
+ return isiso, dictt
339
+ if certificate:
340
+ return factors
341
+ else:
342
+ return True
343
+
344
+
345
+ def rooted_product(G, H, root=None):
346
+ r"""
347
+ Return the rooted product of `G` and `H`.
348
+
349
+ The rooted product of two graphs `G` and `H` is the graph `R` defined as
350
+ follows: take a copy of `G` and `|V(G)|` copies of `H`, and for every vertex
351
+ `g_i` of `G`, identify `g_i` with the root of the `i`-th copy of `H`.
352
+ Mode formally, let `V(G) = \{g_1, g_2, \ldots, g_n\}`,
353
+ `V(H) = \{h_1, h_2, \ldots, h_m\}`, and let `h_1` be the root vertex of `H`.
354
+ The vertex set `V(R)` is equal to the cartesian product of the sets of
355
+ vertices `V(G)` and `V(H)`, that is
356
+ `V(R) = \{(g_i, h_j) : g_i \in V(G), h_j \in V(H)\}`. The edge set `E(R)`
357
+ is the union of the edges of a copy of `G`, that is
358
+ `\{((g_i, h_1), (g_j, h_1)) : (g_i, g_j) \in E(G)\}`, and the edges of the
359
+ copies of `H` for every `g_i \in V(G)`, that is
360
+ `\{((g_i, h_j), (g_i, h_k)) : (h_j, h_k) \in V(H)\}`.
361
+
362
+ See :wikipedia:`Rooted_product_of_graphs` for more details.
363
+
364
+ .. SEEALSO::
365
+
366
+ - :meth:`~sage.graphs.generic_graph.cartesian_product`
367
+ -- return the cartesian product of two graphs
368
+
369
+ - :mod:`~sage.graphs.graph_decompositions.graph_products`
370
+ -- a module on graph products
371
+
372
+ EXAMPLES:
373
+
374
+ The rooted product of two trees is a tree::
375
+
376
+ sage: T1 = graphs.RandomTree(7)
377
+ sage: T2 = graphs.RandomTree(8)
378
+ sage: T = T1.rooted_product(T2)
379
+ sage: T.is_tree()
380
+ True
381
+
382
+ The rooted product of `G` and `H` depends on the selected root in `H`::
383
+
384
+ sage: G = graphs.CycleGraph(4)
385
+ sage: H = graphs.PathGraph(3)
386
+ sage: R1 = G.rooted_product(H, root=0)
387
+ sage: R2 = G.rooted_product(H, root=1)
388
+ sage: R1.is_isomorphic(R2)
389
+ False
390
+ sage: sorted(R1.degree())
391
+ [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]
392
+ sage: sorted(R2.degree())
393
+ [1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4]
394
+
395
+ The domination number of the rooted product of any graph `G` and a path of
396
+ order 2 is the order of `G`::
397
+
398
+ sage: G = graphs.RandomGNP(20, .3)
399
+ sage: P = graphs.PathGraph(2)
400
+ sage: R = G.rooted_product(P)
401
+ sage: len(R.dominating_set()) == G.order() # needs sage.numerical.mip
402
+ True
403
+ sage: G = digraphs.RandomDirectedGNP(20, .3)
404
+ sage: P = digraphs.Path(2)
405
+ sage: R = G.rooted_product(P)
406
+ sage: len(R.dominating_set()) == G.order() # needs sage.numerical.mip
407
+ True
408
+
409
+ The rooted product of two graphs is a subgraph of the cartesian product of
410
+ the same two graphs::
411
+
412
+ sage: G = graphs.RandomGNP(6, .4)
413
+ sage: H = graphs.RandomGNP(7, .4)
414
+ sage: R = G.rooted_product(H)
415
+ sage: C = G.cartesian_product(H)
416
+ sage: R.is_subgraph(C, induced=False)
417
+ True
418
+
419
+ Corner cases::
420
+
421
+ sage: Graph().rooted_product(Graph())
422
+ Rooted product of Graph on 0 vertices and Graph on 0 vertices: Graph on 0 vertices
423
+ sage: Graph(1).rooted_product(Graph())
424
+ Rooted product of Graph on 1 vertex and Graph on 0 vertices: Graph on 0 vertices
425
+ sage: Graph().rooted_product(Graph(1))
426
+ Rooted product of Graph on 0 vertices and Graph on 1 vertex: Graph on 0 vertices
427
+ sage: Graph(1).rooted_product(Graph(1))
428
+ Rooted product of Graph on 1 vertex and Graph on 1 vertex: Graph on 1 vertex
429
+
430
+ TESTS::
431
+
432
+ sage: Graph().rooted_product(DiGraph())
433
+ Traceback (most recent call last):
434
+ ...
435
+ TypeError: the graphs should be both directed or both undirected
436
+ """
437
+ G._scream_if_not_simple(allow_loops=True)
438
+ if G._directed and H._directed:
439
+ from sage.graphs.digraph import DiGraph
440
+ R = DiGraph(loops=(G.has_loops() or H.has_loops()))
441
+ elif (not G._directed) and (not H._directed):
442
+ from sage.graphs.graph import Graph
443
+ R = Graph(loops=(G.has_loops() or H.has_loops()))
444
+ else:
445
+ raise TypeError('the graphs should be both directed or both undirected')
446
+
447
+ R.name(f'Rooted product of {G} and {H}')
448
+
449
+ if not G or not H:
450
+ return R
451
+ if root is None:
452
+ root = next(H.vertex_iterator())
453
+ elif root not in H:
454
+ raise ValueError("the specified root is not a vertex of H")
455
+
456
+ R.add_vertices((u, x) for u in G for x in H)
457
+ for u, v in G.edge_iterator(labels=False):
458
+ R.add_edge((u, root), (v, root))
459
+ for x, y in H.edge_iterator(labels=False):
460
+ R.add_edges(((u, x), (u, y)) for u in G)
461
+
462
+ return R