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,1666 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ """
3
+ Graph-theoretic partition backtrack functions
4
+
5
+ EXAMPLES::
6
+
7
+ sage: import sage.groups.perm_gps.partn_ref.refinement_graphs
8
+
9
+ REFERENCE:
10
+
11
+ - [1] McKay, Brendan D. *Practical Graph Isomorphism*. Congressus Numerantium,
12
+ Vol. 30 (1981), pp. 45-87.
13
+ """
14
+ # ****************************************************************************
15
+ # Copyright (C) 2006 - 2011 Robert L. Miller <rlmillster@gmail.com>
16
+ #
17
+ # This program is free software: you can redistribute it and/or modify
18
+ # it under the terms of the GNU General Public License as published by
19
+ # the Free Software Foundation, either version 2 of the License, or
20
+ # (at your option) any later version.
21
+ # https://www.gnu.org/licenses/
22
+ # ****************************************************************************
23
+
24
+ from sage.groups.perm_gps.partn_ref.data_structures cimport *
25
+ from sage.data_structures.bitset_base cimport *
26
+ from sage.rings.integer cimport Integer
27
+ from sage.graphs.base.sparse_graph cimport SparseGraph
28
+ from sage.graphs.base.dense_graph cimport DenseGraph, copy_dense_graph
29
+ from sage.groups.perm_gps.partn_ref.double_coset cimport double_coset
30
+
31
+
32
+ def isomorphic(G1, G2, partn, ordering2, dig, use_indicator_function, sparse=False):
33
+ """
34
+ Test whether two graphs are isomorphic.
35
+
36
+ EXAMPLES::
37
+
38
+ sage: from sage.groups.perm_gps.partn_ref.refinement_graphs import isomorphic
39
+
40
+ sage: G = Graph(2)
41
+ sage: H = Graph(2)
42
+ sage: isomorphic(G, H, [[0,1]], [0,1], 0, 1)
43
+ {0: 0, 1: 1}
44
+ sage: isomorphic(G, H, [[0,1]], [0,1], 0, 1)
45
+ {0: 0, 1: 1}
46
+ sage: isomorphic(G, H, [[0],[1]], [0,1], 0, 1)
47
+ {0: 0, 1: 1}
48
+ sage: isomorphic(G, H, [[0],[1]], [1,0], 0, 1)
49
+ {0: 1, 1: 0}
50
+
51
+ sage: G = Graph(3)
52
+ sage: H = Graph(3)
53
+ sage: isomorphic(G, H, [[0,1,2]], [0,1,2], 0, 1)
54
+ {0: 0, 1: 1, 2: 2}
55
+ sage: G.add_edge(0,1)
56
+ sage: isomorphic(G, H, [[0,1,2]], [0,1,2], 0, 1)
57
+ False
58
+ sage: H.add_edge(1,2)
59
+ sage: isomorphic(G, H, [[0,1,2]], [0,1,2], 0, 1)
60
+ {0: 1, 1: 2, 2: 0}
61
+ """
62
+ cdef PartitionStack *part
63
+ cdef int *output
64
+ cdef int *ordering
65
+ cdef CGraph G
66
+ cdef GraphStruct GS1 = GraphStruct()
67
+ cdef GraphStruct GS2 = GraphStruct()
68
+ cdef GraphStruct GS
69
+ cdef int i, j, n = -1
70
+ cdef list partition, cell
71
+ cdef bint loops = 0
72
+
73
+ from sage.graphs.graph import Graph
74
+ from sage.graphs.generic_graph import GenericGraph
75
+ from copy import copy
76
+ which_G = 1
77
+ for G_in in [G1, G2]:
78
+ if which_G == 1:
79
+ GS = GS1
80
+ first = True
81
+ else:
82
+ GS = GS2
83
+ first = False
84
+ if isinstance(G_in, GenericGraph):
85
+ if G_in.has_loops():
86
+ loops = 1
87
+ if n == -1:
88
+ n = G_in.num_verts()
89
+ elif n != G_in.num_verts():
90
+ return False
91
+ if G_in.vertices(sort=True) != list(range(n)):
92
+ G_in = copy(G_in)
93
+ to = G_in.relabel(return_map=True)
94
+ frm = {}
95
+ for v in to:
96
+ frm[to[v]] = v
97
+ if first:
98
+ partition = [[to[v] for v in cell] for cell in partn]
99
+ else:
100
+ if first:
101
+ partition = partn
102
+ to = list(range(n))
103
+ frm = to
104
+ if sparse:
105
+ G = SparseGraph(n)
106
+ else:
107
+ G = DenseGraph(n)
108
+ if G_in.is_directed():
109
+ for i, j in G_in.edge_iterator(labels=False):
110
+ G.add_arc(i, j)
111
+ else:
112
+ for i, j in G_in.edge_iterator(labels=False):
113
+ G.add_arc(i, j)
114
+ G.add_arc(j, i)
115
+ elif isinstance(G_in, CGraph):
116
+ G = <CGraph> G_in
117
+ if n == -1:
118
+ n = G.num_verts
119
+ elif n != <int>G.num_verts:
120
+ return False
121
+ if not loops:
122
+ for i in range(n):
123
+ if G.has_arc_unsafe(i,i):
124
+ loops = 1
125
+ to = {}
126
+ for a in G.verts():
127
+ to[a] = a
128
+ frm = to
129
+ if first:
130
+ partition = partn
131
+ else:
132
+ raise TypeError("G must be a Sage graph")
133
+ if first:
134
+ frm1 = frm
135
+ else:
136
+ frm2 = frm
137
+ to2 = to
138
+ GS.G = G
139
+ GS.directed = 1 if dig else 0
140
+ GS.loops = 1
141
+ GS.use_indicator = 1 if use_indicator_function else 0
142
+ which_G += 1
143
+
144
+ if n == 0:
145
+ return {}
146
+
147
+ part = PS_from_list(partition)
148
+ ordering = <int *> sig_malloc(n * sizeof(int))
149
+ output = <int *> sig_malloc(n * sizeof(int))
150
+ if part is NULL or ordering is NULL or output is NULL:
151
+ PS_dealloc(part)
152
+ sig_free(ordering)
153
+ sig_free(output)
154
+ raise MemoryError
155
+ for i from 0 <= i < n:
156
+ ordering[i] = to2[ordering2[i]]
157
+
158
+ GS1.scratch = <int *> sig_malloc((3*n+1) * sizeof(int))
159
+ GS2.scratch = <int *> sig_malloc((3*n+1) * sizeof(int))
160
+ if GS1.scratch is NULL or GS2.scratch is NULL:
161
+ sig_free(GS1.scratch)
162
+ sig_free(GS2.scratch)
163
+ PS_dealloc(part)
164
+ sig_free(ordering)
165
+ raise MemoryError
166
+
167
+ cdef bint isomorphic = double_coset(<void *>GS1, <void *>GS2, part, ordering, n, &all_children_are_equivalent, &refine_by_degree, &compare_graphs, NULL, NULL, output)
168
+
169
+ PS_dealloc(part)
170
+ sig_free(ordering)
171
+ sig_free(GS1.scratch)
172
+ sig_free(GS2.scratch)
173
+ if isomorphic:
174
+ output_py = dict([[frm1[i], frm2[output[i]]] for i from 0 <= i < n])
175
+ else:
176
+ output_py = False
177
+ sig_free(output)
178
+ return output_py
179
+
180
+
181
+ def search_tree(G_in, partition, lab=True, dig=False, dict_rep=False, certificate=False,
182
+ verbosity=0, use_indicator_function=True, sparse=True,
183
+ base=False, order=False):
184
+ """
185
+ Compute canonical labels and automorphism groups of graphs.
186
+
187
+ INPUT:
188
+
189
+ - ``G_in`` -- a Sage graph
190
+ - ``partition`` -- list of lists representing a partition of the vertices
191
+ - ``lab`` -- if ``True``, compute and return the canonical label in addition to the
192
+ automorphism group
193
+ - ``dig`` -- set to ``True`` for digraphs and graphs with loops; if ``True``, does not
194
+ use optimizations based on Lemma 2.25 in [1] that are valid only for
195
+ simple graphs
196
+ - ``dict_rep`` -- if ``True``, return a dictionary with keys the vertices of the
197
+ input graph G_in and values elements of the set the permutation group
198
+ acts on. (The point is that graphs are arbitrarily labelled, often
199
+ 0..n-1, and permutation groups always act on 1..n. This dictionary
200
+ maps vertex labels (such as 0..n-1) to the domain of the permutations.)
201
+ - ``certificate`` -- if ``True``, return the permutation from G to its canonical label
202
+ - ``verbosity`` -- currently ignored
203
+ - ``use_indicator_function`` -- option to turn off indicator function
204
+ (``True`` is generally faster)
205
+ - ``sparse`` -- whether to use sparse or dense representation of the graph
206
+ (ignored if G is already a CGraph - see sage.graphs.base)
207
+ - ``base`` -- whether to return the first sequence of split vertices (used in
208
+ computing the order of the group)
209
+ - ``order`` -- whether to return the order of the automorphism group
210
+
211
+ OUTPUT:
212
+
213
+ Depends on the options. If more than one thing is returned, they are in a
214
+ tuple in the following order:
215
+
216
+ - list of generators in list-permutation format -- always
217
+ - dict -- if dict_rep
218
+ - graph -- if lab
219
+ - dict -- if certificate
220
+ - list -- if base
221
+ - integer -- if order
222
+
223
+ EXAMPLES::
224
+
225
+ sage: st = sage.groups.perm_gps.partn_ref.refinement_graphs.search_tree
226
+ sage: from sage.graphs.base.dense_graph import DenseGraph
227
+ sage: from sage.graphs.base.sparse_graph import SparseGraph
228
+
229
+ Graphs on zero vertices::
230
+
231
+ sage: G = Graph()
232
+ sage: st(G, [[]], order=True)
233
+ ([], Graph on 0 vertices, 1)
234
+
235
+ Graphs on one vertex::
236
+
237
+ sage: G = Graph(1)
238
+ sage: st(G, [[0]], order=True)
239
+ ([], Graph on 1 vertex, 1)
240
+
241
+ Graphs on two vertices::
242
+
243
+ sage: G = Graph(2)
244
+ sage: st(G, [[0,1]], order=True)
245
+ ([[1, 0]], Graph on 2 vertices, 2)
246
+ sage: st(G, [[0],[1]], order=True)
247
+ ([], Graph on 2 vertices, 1)
248
+ sage: G.add_edge(0,1)
249
+ sage: st(G, [[0,1]], order=True)
250
+ ([[1, 0]], Graph on 2 vertices, 2)
251
+ sage: st(G, [[0],[1]], order=True)
252
+ ([], Graph on 2 vertices, 1)
253
+
254
+ Graphs on three vertices::
255
+
256
+ sage: G = Graph(3)
257
+ sage: st(G, [[0,1,2]], order=True)
258
+ ([[0, 2, 1], [1, 0, 2]], Graph on 3 vertices, 6)
259
+ sage: st(G, [[0],[1,2]], order=True)
260
+ ([[0, 2, 1]], Graph on 3 vertices, 2)
261
+ sage: st(G, [[0],[1],[2]], order=True)
262
+ ([], Graph on 3 vertices, 1)
263
+ sage: G.add_edge(0,1)
264
+ sage: st(G, [range(3)], order=True)
265
+ ([[1, 0, 2]], Graph on 3 vertices, 2)
266
+ sage: st(G, [[0],[1,2]], order=True)
267
+ ([], Graph on 3 vertices, 1)
268
+ sage: st(G, [[0,1],[2]], order=True)
269
+ ([[1, 0, 2]], Graph on 3 vertices, 2)
270
+
271
+ The Dodecahedron has automorphism group of size 120::
272
+
273
+ sage: G = graphs.DodecahedralGraph()
274
+ sage: Pi = [range(20)]
275
+ sage: st(G, Pi, order=True)[2]
276
+ 120
277
+
278
+ The three-cube has automorphism group of size 48::
279
+
280
+ sage: G = graphs.CubeGraph(3)
281
+ sage: G.relabel()
282
+ sage: Pi = [G.vertices(sort=False)]
283
+ sage: st(G, Pi, order=True)[2]
284
+ 48
285
+
286
+ We obtain the same output using different types of Sage graphs::
287
+
288
+ sage: G = graphs.DodecahedralGraph()
289
+ sage: GD = DenseGraph(20)
290
+ sage: GS = SparseGraph(20)
291
+ sage: for i,j,_ in G.edge_iterator():
292
+ ....: GD.add_arc(i,j); GD.add_arc(j,i)
293
+ ....: GS.add_arc(i,j); GS.add_arc(j,i)
294
+ sage: Pi = [range(20)]
295
+ sage: a,b = st(G, Pi)
296
+ sage: asp,bsp = st(GS, Pi)
297
+ sage: ade,bde = st(GD, Pi)
298
+ sage: bsg = Graph()
299
+ sage: bdg = Graph()
300
+ sage: for i in range(20):
301
+ ....: for j in range(20):
302
+ ....: if bsp.has_arc(i,j):
303
+ ....: bsg.add_edge(i,j)
304
+ ....: if bde.has_arc(i,j):
305
+ ....: bdg.add_edge(i,j)
306
+ sage: a, b.graph6_string()
307
+ ([[0, 19, 3, 2, 6, 5, 4, 17, 18, 11, 10, 9, 13, 12, 16, 15, 14, 7, 8, 1],
308
+ [0, 1, 8, 9, 13, 14, 7, 6, 2, 3, 19, 18, 17, 4, 5, 15, 16, 12, 11, 10],
309
+ [1, 8, 9, 10, 11, 12, 13, 14, 7, 6, 2, 3, 4, 5, 15, 16, 17, 18, 19, 0]],
310
+ 'S?[PG__OQ@?_?_?P?CO?_?AE?EC?Ac?@O')
311
+ sage: a == asp
312
+ True
313
+ sage: a == ade
314
+ True
315
+ sage: b == bsg
316
+ True
317
+ sage: b == bdg
318
+ True
319
+
320
+ Cubes!::
321
+
322
+ sage: C = graphs.CubeGraph(1)
323
+ sage: gens, order = st(C, [C.vertices(sort=False)], lab=False, order=True); order
324
+ 2
325
+ sage: C = graphs.CubeGraph(2)
326
+ sage: gens, order = st(C, [C.vertices(sort=False)], lab=False, order=True); order
327
+ 8
328
+ sage: C = graphs.CubeGraph(3)
329
+ sage: gens, order = st(C, [C.vertices(sort=False)], lab=False, order=True); order
330
+ 48
331
+ sage: C = graphs.CubeGraph(4)
332
+ sage: gens, order = st(C, [C.vertices(sort=False)], lab=False, order=True); order
333
+ 384
334
+ sage: C = graphs.CubeGraph(5)
335
+ sage: gens, order = st(C, [C.vertices(sort=False)], lab=False, order=True); order
336
+ 3840
337
+ sage: C = graphs.CubeGraph(6)
338
+ sage: gens, order = st(C, [C.vertices(sort=False)], lab=False, order=True); order
339
+ 46080
340
+
341
+ One can also turn off the indicator function (note: this will take longer)::
342
+
343
+ sage: D1 = DiGraph({0:[2],2:[0],1:[1]}, loops=True)
344
+ sage: D2 = DiGraph({1:[2],2:[1],0:[0]}, loops=True)
345
+ sage: a,b = st(D1, [D1.vertices(sort=False)], dig=True, use_indicator_function=False)
346
+ sage: c,d = st(D2, [D2.vertices(sort=False)], dig=True, use_indicator_function=False)
347
+ sage: b==d
348
+ True
349
+
350
+ This example is due to Chris Godsil::
351
+
352
+ sage: # needs cliquer
353
+ sage: HS = graphs.HoffmanSingletonGraph()
354
+ sage: alqs = [Set(c) for c in (HS.complement()).cliques_maximum()]
355
+ sage: Y = Graph([alqs, lambda s,t: len(s.intersection(t))==0])
356
+ sage: Y0,Y1 = Y.connected_components_subgraphs()
357
+ sage: st(Y0, [Y0.vertices(sort=False)])[1] == st(Y1, [Y1.vertices(sort=False)])[1]
358
+ True
359
+ sage: st(Y0, [Y0.vertices(sort=False)])[1] == st(HS, [HS.vertices(sort=False)])[1]
360
+ True
361
+ sage: st(HS, [HS.vertices(sort=False)])[1] == st(Y1, [Y1.vertices(sort=False)])[1]
362
+ True
363
+
364
+ Certain border cases need to be tested as well::
365
+
366
+ sage: G = Graph('Fll^G')
367
+ sage: a,b,c = st(G, [range(G.num_verts())], order=True); b
368
+ Graph on 7 vertices
369
+ sage: c
370
+ 48
371
+ sage: G = Graph(21)
372
+ sage: st(G, [range(G.num_verts())], order=True)[2] == factorial(21)
373
+ True
374
+
375
+ sage: G = Graph('^????????????????????{??N??@w??FaGa?PCO@CP?AGa?_QO?Q@G?CcA??cc????Bo????{????F_')
376
+ sage: perm = {3:15, 15:3}
377
+ sage: H = G.relabel(perm, inplace=False)
378
+ sage: st(G, [range(G.num_verts())])[1] == st(H, [range(H.num_verts())])[1]
379
+ True
380
+
381
+ sage: st(Graph(':Dkw'), [range(5)], lab=False, dig=True)
382
+ [[4, 1, 2, 3, 0], [0, 2, 1, 3, 4]]
383
+ """
384
+ cdef CGraph G
385
+ cdef int i, j, n
386
+ cdef Integer I
387
+ cdef bint loops
388
+ cdef aut_gp_and_can_lab *output
389
+ cdef PartitionStack *part
390
+ from sage.graphs.graph import Graph
391
+ from sage.graphs.generic_graph import GenericGraph
392
+ from copy import copy
393
+ if isinstance(G_in, GenericGraph):
394
+ loops = G_in.has_loops()
395
+ n = G_in.num_verts()
396
+ if G_in.vertices(sort=False) != list(range(n)):
397
+ G_in = copy(G_in)
398
+ to = G_in.relabel(return_map=True)
399
+ frm = {}
400
+ for v in to:
401
+ frm[to[v]] = v
402
+ partition = [[to[v] for v in cell] for cell in partition]
403
+ else:
404
+ to = dict(enumerate(range(n)))
405
+ frm = to
406
+ if sparse:
407
+ G = SparseGraph(n)
408
+ else:
409
+ G = DenseGraph(n)
410
+ if G_in.is_directed():
411
+ for i, j in G_in.edge_iterator(labels=False):
412
+ G.add_arc(i, j)
413
+ else:
414
+ for i, j in G_in.edge_iterator(labels=False):
415
+ G.add_arc(i, j)
416
+ G.add_arc(j, i)
417
+ elif isinstance(G_in, CGraph):
418
+ G = <CGraph> G_in
419
+ n = G.num_verts
420
+ loops = 0
421
+ for i in range(n):
422
+ if G.has_arc_unsafe(i, i):
423
+ loops = 1
424
+ to = {}
425
+ for a in G.verts():
426
+ to[a] = a
427
+ frm = to
428
+ else:
429
+ raise TypeError("G must be a Sage graph")
430
+
431
+ cdef GraphStruct GS = GraphStruct()
432
+ GS.G = G
433
+ GS.directed = 1 if dig else 0
434
+ GS.loops = loops
435
+ GS.use_indicator = 1 if use_indicator_function else 0
436
+
437
+ if n == 0:
438
+ return_tuple = [[]]
439
+ if dict_rep:
440
+ return_tuple.append({})
441
+ if lab:
442
+ if isinstance(G_in, GenericGraph):
443
+ G_C = copy(G_in)
444
+ else:
445
+ if isinstance(G, SparseGraph):
446
+ G_C = SparseGraph(n)
447
+ else:
448
+ G_C = DenseGraph(n)
449
+ return_tuple.append(G_C)
450
+ if certificate:
451
+ return_tuple.append({})
452
+ if base:
453
+ return_tuple.append([])
454
+ if order:
455
+ return_tuple.append(Integer(1))
456
+ if len(return_tuple) == 1:
457
+ return return_tuple[0]
458
+ else:
459
+ return tuple(return_tuple)
460
+
461
+ GS.scratch = <int *> sig_malloc( (3*G.num_verts + 1) * sizeof(int) )
462
+ part = PS_from_list(partition)
463
+ if GS.scratch is NULL or part is NULL:
464
+ PS_dealloc(part)
465
+ sig_free(GS.scratch)
466
+ raise MemoryError
467
+
468
+ output = get_aut_gp_and_can_lab(<void *>GS, part, G.num_verts, &all_children_are_equivalent, &refine_by_degree, &compare_graphs, lab, NULL, NULL, NULL)
469
+ sig_free( GS.scratch )
470
+ # prepare output
471
+ list_of_gens = []
472
+ for i from 0 <= i < output.num_gens:
473
+ list_of_gens.append([output.generators[j+i*G.num_verts] for j from 0 <= j < <int>G.num_verts])
474
+ return_tuple = [list_of_gens]
475
+ if dict_rep:
476
+ ddd = {}
477
+ for v in frm:
478
+ ddd[frm[v]] = v if v != 0 else n
479
+ return_tuple.append(ddd)
480
+ if lab:
481
+ if isinstance(G_in, GenericGraph):
482
+ G_C = copy(G_in)
483
+ G_C.relabel([output.relabeling[i] for i from 0 <= i < n])
484
+ else:
485
+ if isinstance(G, SparseGraph):
486
+ G_C = SparseGraph(n)
487
+ else:
488
+ G_C = DenseGraph(n)
489
+ for i from 0 <= i < n:
490
+ for j in G.out_neighbors(i):
491
+ G_C.add_arc(output.relabeling[i],output.relabeling[j])
492
+ return_tuple.append(G_C)
493
+ if certificate:
494
+ dd = {}
495
+ for i from 0 <= i < <int>G.num_verts:
496
+ dd[frm[i]] = output.relabeling[i]
497
+ return_tuple.append(dd)
498
+ if base:
499
+ return_tuple.append([output.group.base_orbits[i][0] for i from 0 <= i < output.group.base_size])
500
+ if order:
501
+ I = Integer()
502
+ SC_order(output.group, 0, I.value)
503
+ return_tuple.append(I)
504
+ PS_dealloc(part)
505
+ deallocate_agcl_output(output)
506
+ if len(return_tuple) == 1:
507
+ return return_tuple[0]
508
+ else:
509
+ return tuple(return_tuple)
510
+
511
+
512
+ cdef int refine_by_degree(PartitionStack *PS, void *S, int *cells_to_refine_by, int ctrb_len) noexcept:
513
+ r"""
514
+ Refine the input partition by checking degrees of vertices to the given
515
+ cells.
516
+
517
+ INPUT:
518
+
519
+ - ``PS`` -- a partition stack, whose finest partition is the partition to be
520
+ refined
521
+ - ``S`` -- a graph struct object, which contains scratch space, the graph in
522
+ question, and some flags
523
+ - ``cells_to_refine_by`` -- list of pointers to cells to check degrees against
524
+ in refining the other cells (updated in place). Must be allocated to
525
+ length at least the degree of PS, since the array may grow
526
+ - ``ctrb_len`` -- how many cells in cells_to_refine_by
527
+
528
+ OUTPUT:
529
+
530
+ An integer invariant under the orbits of $S_n$. That is, if $\gamma$ is a
531
+ permutation of the vertices, then
532
+ $$ I(G, PS, cells_to_refine_by) = I( \gamma(G), \gamma(PS), \gamma(cells_to_refine_by) ) .$$
533
+ """
534
+ cdef GraphStruct GS = <GraphStruct> S
535
+ cdef CGraph G = GS.G
536
+ cdef int current_cell_against = 0
537
+ cdef int current_cell, i, r
538
+ cdef int first_largest_subcell
539
+ cdef int invariant = 1
540
+ cdef int max_degree
541
+ cdef int *degrees = GS.scratch # length 3n+1
542
+ cdef bint necessary_to_split_cell
543
+ cdef int against_index
544
+ if <int>G.num_verts != PS.degree and PS.depth == 0:
545
+ # should be less verts, then, so place the "nonverts" in separate cell at the end
546
+ current_cell = 0
547
+ while current_cell < PS.degree:
548
+ i = current_cell
549
+ r = 0
550
+ while True:
551
+ if G.has_vertex(PS.entries[i]):
552
+ degrees[i-current_cell] = 0
553
+ else:
554
+ r = 1
555
+ degrees[i-current_cell] = 1
556
+ i += 1
557
+ if PS.levels[i-1] <= PS.depth:
558
+ break
559
+ if r != 0:
560
+ sort_by_function(PS, current_cell, degrees)
561
+ current_cell = i
562
+ while not PS_is_discrete(PS) and current_cell_against < ctrb_len:
563
+ invariant += 1
564
+ current_cell = 0
565
+ while current_cell < PS.degree:
566
+ invariant += 50
567
+ i = current_cell
568
+ necessary_to_split_cell = 0
569
+ max_degree = 0
570
+ while True:
571
+ degrees[i-current_cell] = degree(PS, G, i, cells_to_refine_by[current_cell_against], 0)
572
+ if degrees[i-current_cell] != degrees[0]:
573
+ necessary_to_split_cell = 1
574
+ if degrees[i-current_cell] > max_degree:
575
+ max_degree = degrees[i-current_cell]
576
+ i += 1
577
+ if PS.levels[i-1] <= PS.depth:
578
+ break
579
+ # now, i points to the next cell (before refinement)
580
+ if necessary_to_split_cell:
581
+ invariant += 10
582
+ first_largest_subcell = sort_by_function(PS, current_cell, degrees)
583
+ invariant += first_largest_subcell + max_degree
584
+ against_index = current_cell_against
585
+ while against_index < ctrb_len:
586
+ if cells_to_refine_by[against_index] == current_cell:
587
+ cells_to_refine_by[against_index] = first_largest_subcell
588
+ break
589
+ against_index += 1
590
+ r = current_cell
591
+ while True:
592
+ if r == current_cell or PS.levels[r-1] == PS.depth:
593
+ if r != first_largest_subcell:
594
+ cells_to_refine_by[ctrb_len] = r
595
+ ctrb_len += 1
596
+ r += 1
597
+ if r >= i:
598
+ break
599
+ invariant += (i - current_cell)
600
+ current_cell = i
601
+ if GS.directed:
602
+ # if we are looking at a digraph, also compute
603
+ # the reverse degrees and sort by them
604
+ current_cell = 0
605
+ while current_cell < PS.degree: # current_cell is still a valid cell
606
+ invariant += 20
607
+ i = current_cell
608
+ necessary_to_split_cell = 0
609
+ max_degree = 0
610
+ while True:
611
+ degrees[i-current_cell] = degree(PS, G, i, cells_to_refine_by[current_cell_against], 1)
612
+ if degrees[i-current_cell] != degrees[0]:
613
+ necessary_to_split_cell = 1
614
+ if degrees[i-current_cell] > max_degree:
615
+ max_degree = degrees[i-current_cell]
616
+ i += 1
617
+ if PS.levels[i-1] <= PS.depth:
618
+ break
619
+ # now, i points to the next cell (before refinement)
620
+ if necessary_to_split_cell:
621
+ invariant += 7
622
+ first_largest_subcell = sort_by_function(PS, current_cell, degrees)
623
+ invariant += first_largest_subcell + max_degree
624
+ against_index = current_cell_against
625
+ while against_index < ctrb_len:
626
+ if cells_to_refine_by[against_index] == current_cell:
627
+ cells_to_refine_by[against_index] = first_largest_subcell
628
+ break
629
+ against_index += 1
630
+ against_index = ctrb_len
631
+ r = current_cell
632
+ while True:
633
+ if r == current_cell or PS.levels[r-1] == PS.depth:
634
+ if r != first_largest_subcell:
635
+ cells_to_refine_by[against_index] = r
636
+ against_index += 1
637
+ ctrb_len += 1
638
+ r += 1
639
+ if r >= i:
640
+ break
641
+ invariant += (i - current_cell)
642
+ current_cell = i
643
+ current_cell_against += 1
644
+ if GS.use_indicator:
645
+ return invariant
646
+ else:
647
+ return 0
648
+
649
+ cdef int compare_graphs(int *gamma_1, int *gamma_2, void *S1, void *S2, int degree) noexcept:
650
+ r"""
651
+ Compare gamma_1(S1) and gamma_2(S2).
652
+
653
+ Return -1 if gamma_1(S1) < gamma_2(S2), 0 if gamma_1(S1) ==
654
+ gamma_2(S2), 1 if gamma_1(S1) > gamma_2(S2).
655
+
656
+ INPUT:
657
+
658
+ - ``gamma_1``, ``gamma_2`` -- list permutations (inverse)
659
+ - ``S1``, ``S2`` -- graph struct objects
660
+ """
661
+ cdef size_t i, j
662
+ cdef GraphStruct GS1 = <GraphStruct> S1
663
+ cdef GraphStruct GS2 = <GraphStruct> S2
664
+ cdef CGraph G1 = GS1.G
665
+ cdef CGraph G2 = GS2.G
666
+ if G1.active_vertices.size != G2.active_vertices.size or \
667
+ not bitset_cmp(G1.active_vertices, G2.active_vertices):
668
+ for i from 0 <= i < <size_t>degree:
669
+ if G1.has_vertex(gamma_1[i]) != G2.has_vertex(gamma_2[i]):
670
+ return G1.has_vertex(gamma_1[i]) - G2.has_vertex(gamma_2[i])
671
+ for i from 0 <= i < G1.num_verts:
672
+ for j from 0 <= j < G1.num_verts:
673
+ if G1.has_arc_unsafe(gamma_1[i], gamma_1[j]):
674
+ if not G2.has_arc_unsafe(gamma_2[i], gamma_2[j]):
675
+ return 1
676
+ elif G2.has_arc_unsafe(gamma_2[i], gamma_2[j]):
677
+ return -1
678
+ return 0
679
+
680
+ cdef bint all_children_are_equivalent(PartitionStack *PS, void *S) noexcept:
681
+ """
682
+ Return ``True`` if every refinement of the current partition results in the
683
+ same structure.
684
+
685
+ .. WARNING::
686
+
687
+ Converse does not hold in general! See Lemma 2.25 of [1] for details.
688
+
689
+ INPUT:
690
+
691
+ - ``PS`` -- the partition stack to be checked
692
+ - ``S`` -- a graph struct object
693
+ """
694
+ cdef GraphStruct GS = <GraphStruct> S
695
+ if GS.directed or GS.loops:
696
+ return 0
697
+ cdef int i, n = PS.degree
698
+ cdef bint in_cell = 0
699
+ cdef int nontrivial_cells = 0
700
+ cdef int total_cells = PS_num_cells(PS)
701
+ if n <= total_cells + 4:
702
+ return 1
703
+ for i from 0 <= i < n-1:
704
+ if PS.levels[i] <= PS.depth:
705
+ if in_cell:
706
+ nontrivial_cells += 1
707
+ in_cell = 0
708
+ else:
709
+ in_cell = 1
710
+ if in_cell:
711
+ nontrivial_cells += 1
712
+ if n == total_cells + nontrivial_cells:
713
+ return 1
714
+ if n == total_cells + nontrivial_cells + 1:
715
+ return 1
716
+ return 0
717
+
718
+ cdef inline int degree(PartitionStack *PS, CGraph G, int entry, int cell_index, bint reverse) noexcept:
719
+ """
720
+ Return the number of edges from the vertex corresponding to entry to
721
+ vertices in the cell corresponding to cell_index.
722
+
723
+ INPUT:
724
+
725
+ - ``PS`` -- the partition stack to be checked
726
+ - ``S`` -- a graph struct object
727
+ - ``entry`` -- the position of the vertex in question in the entries of PS
728
+ - ``cell_index`` -- the starting position of the cell in question in the entries
729
+ of PS
730
+ - ``reverse`` -- whether to check for arcs in the other direction
731
+ """
732
+ cdef int num_arcs = 0
733
+ entry = PS.entries[entry]
734
+ if not reverse:
735
+ while True:
736
+ if G.has_arc_unsafe(PS.entries[cell_index], entry):
737
+ num_arcs += 1
738
+ if PS.levels[cell_index] > PS.depth:
739
+ cell_index += 1
740
+ else:
741
+ break
742
+ else:
743
+ while True:
744
+ if G.has_arc_unsafe(entry, PS.entries[cell_index]):
745
+ num_arcs += 1
746
+ if PS.levels[cell_index] > PS.depth:
747
+ cell_index += 1
748
+ else:
749
+ break
750
+ return num_arcs
751
+
752
+
753
+ def all_labeled_graphs(n):
754
+ """
755
+ Return all labeled graphs on n vertices {0,1,...,n-1}.
756
+
757
+ Used in classifying isomorphism types (naive approach), and more
758
+ importantly in benchmarking the search algorithm.
759
+
760
+ EXAMPLES::
761
+
762
+ sage: from sage.groups.perm_gps.partn_ref.refinement_graphs import all_labeled_graphs
763
+ sage: st = sage.groups.perm_gps.partn_ref.refinement_graphs.search_tree
764
+ sage: Glist = {}
765
+ sage: Giso = {}
766
+ sage: for n in [1..5]: # long time (4s on sage.math, 2011)
767
+ ....: Glist[n] = all_labeled_graphs(n)
768
+ ....: Giso[n] = []
769
+ ....: for g in Glist[n]:
770
+ ....: a, b = st(g, [range(n)])
771
+ ....: inn = False
772
+ ....: for gi in Giso[n]:
773
+ ....: if b == gi:
774
+ ....: inn = True
775
+ ....: if not inn:
776
+ ....: Giso[n].append(b)
777
+ sage: for n in Giso: # long time
778
+ ....: print("{} {}".format(n, len(Giso[n])))
779
+ 1 1
780
+ 2 2
781
+ 3 4
782
+ 4 11
783
+ 5 34
784
+ """
785
+ from sage.graphs.graph import Graph
786
+ TE = []
787
+ for i in range(n):
788
+ for j in range(i):
789
+ TE.append((i, j))
790
+ m = len(TE)
791
+ Glist= []
792
+ for i in range(2**m):
793
+ G = Graph(n)
794
+ b = Integer(i).binary()
795
+ b = '0'*(m-len(b)) + b
796
+ for i in range(m):
797
+ if int(b[i]):
798
+ G.add_edge(TE[i])
799
+ Glist.append(G)
800
+ return Glist
801
+
802
+
803
+ def random_tests(num=10, n_max=60, perms_per_graph=5):
804
+ """
805
+ Test to make sure that C(gamma(G)) == C(G) for random permutations gamma
806
+ and random graphs G, and that isomorphic returns an isomorphism.
807
+
808
+ INPUT:
809
+
810
+ - ``num`` -- run tests for this many graphs
811
+ - ``n_max`` -- test graphs with at most this many vertices
812
+ - ``perms_per_graph`` -- test each graph with this many random permutations
813
+
814
+ DISCUSSION:
815
+
816
+ This code generates num random graphs G on at most n_max vertices. The
817
+ density of edges is chosen randomly between 0 and 1.
818
+
819
+ For each graph G generated, we uniformly generate perms_per_graph random
820
+ permutations and verify that the canonical labels of G and the image of G
821
+ under the generated permutation are equal, and that the isomorphic function
822
+ returns an isomorphism.
823
+
824
+ TESTS::
825
+
826
+ sage: import sage.groups.perm_gps.partn_ref.refinement_graphs
827
+ sage: sage.groups.perm_gps.partn_ref.refinement_graphs.random_tests() # long time
828
+ All passed: 200 random tests on 20 graphs.
829
+ """
830
+ from sage.misc.prandom import random, randint
831
+ from sage.graphs.graph_generators import GraphGenerators
832
+ from sage.graphs.digraph_generators import DiGraphGenerators
833
+ from sage.combinat.permutation import Permutations
834
+ from copy import copy
835
+ cdef int i, j, num_tests = 0, num_graphs = 0
836
+ GG = GraphGenerators()
837
+ DGG = DiGraphGenerators()
838
+ for mmm in range(num):
839
+ p = random()
840
+ n = randint(1, n_max)
841
+ S = Permutations(n)
842
+
843
+ G = GG.RandomGNP(n, p)
844
+ H = copy(G)
845
+ for i from 0 <= i < perms_per_graph:
846
+ G = copy(H)
847
+ G1 = search_tree(G, [G.vertices(sort=False)])[1]
848
+ perm = list(S.random_element())
849
+ perm = [perm[j]-1 for j from 0 <= j < n]
850
+ G.relabel(perm)
851
+ G2 = search_tree(G, [G.vertices(sort=False)])[1]
852
+ if G1 != G2:
853
+ print("search_tree FAILURE: graph6-")
854
+ print(H.graph6_string())
855
+ print(perm)
856
+ return
857
+ isom = isomorphic(G, H, [list(range(n))], list(range(n)), 0, 1)
858
+ if not isom or G.relabel(isom, inplace=False) != H:
859
+ print("isom FAILURE: graph6-")
860
+ print(H.graph6_string())
861
+ print(perm)
862
+ return
863
+
864
+ D = DGG.RandomDirectedGNP(n, p)
865
+ D.allow_loops(True)
866
+ for i from 0 <= i < n:
867
+ if random() < p:
868
+ D.add_edge(i,i)
869
+ E = copy(D)
870
+ for i from 0 <= i < perms_per_graph:
871
+ D = copy(E)
872
+ D1 = search_tree(D, [D.vertices(sort=False)], dig=True)[1]
873
+ perm = list(S.random_element())
874
+ perm = [perm[j]-1 for j from 0 <= j < n]
875
+ D.relabel(perm)
876
+ D2 = search_tree(D, [D.vertices(sort=False)], dig=True)[1]
877
+ if D1 != D2:
878
+ print("search_tree FAILURE: dig6-")
879
+ print(E.dig6_string())
880
+ print(perm)
881
+ return
882
+ isom = isomorphic(D, E, [list(range(n))], list(range(n)), 1, 1)
883
+ if not isom or D.relabel(isom, inplace=False) != E:
884
+ print("isom FAILURE: dig6-")
885
+ print(E.dig6_string())
886
+ print(perm)
887
+ print(isom)
888
+ return
889
+ num_tests += 4*perms_per_graph
890
+ num_graphs += 2
891
+ print("All passed: %d random tests on %d graphs." % (num_tests, num_graphs))
892
+
893
+
894
+ def orbit_partition(gamma, list_perm=False):
895
+ r"""
896
+ Assuming that G is a graph on vertices 0,1,...,n-1, and gamma is an
897
+ element of SymmetricGroup(n), returns the partition of the vertex
898
+ set determined by the orbits of gamma, considered as action on the
899
+ set 1,2,...,n where we take 0 = n. In other words, returns the
900
+ partition determined by a cyclic representation of gamma.
901
+
902
+ INPUT:
903
+
904
+ - ``list_perm`` -- if ``True``, assumes
905
+ ``gamma`` is a list representing the map
906
+ `i \mapsto ``gamma``[i]`
907
+
908
+ EXAMPLES::
909
+
910
+ sage: # needs sage.groups
911
+ sage: from sage.groups.perm_gps.partn_ref.refinement_graphs import orbit_partition
912
+ sage: G = graphs.PetersenGraph()
913
+ sage: S = SymmetricGroup(10)
914
+ sage: gamma = S('(10,1,2,3,4)(5,6,7)(8,9)')
915
+ sage: orbit_partition(gamma)
916
+ [[1, 2, 3, 4, 0], [5, 6, 7], [8, 9]]
917
+ sage: gamma = S('(10,5)(1,6)(2,7)(3,8)(4,9)')
918
+ sage: orbit_partition(gamma)
919
+ [[1, 6], [2, 7], [3, 8], [4, 9], [5, 0]]
920
+ """
921
+ if list_perm:
922
+ n = len(gamma)
923
+ seen = [1] + [0]*(n-1)
924
+ i = 0
925
+ p = 0
926
+ partition = [[0]]
927
+ while sum(seen) < n:
928
+ if gamma[i] != partition[p][0]:
929
+ partition[p].append(gamma[i])
930
+ i = gamma[i]
931
+ seen[i] = 1
932
+ else:
933
+ for j in range(n):
934
+ if seen[j] == 0:
935
+ i = j
936
+ break
937
+ partition.append([i])
938
+ p += 1
939
+ seen[i] = 1
940
+ return partition
941
+ else:
942
+ n = len(gamma.domain())
943
+ l = []
944
+ for i in range(1,n+1):
945
+ orb = gamma.orbit(i)
946
+ if orb not in l:
947
+ l.append(orb)
948
+ for i in l:
949
+ for j in range(len(i)):
950
+ if i[j] == n:
951
+ i[j] = 0
952
+ return l
953
+
954
+
955
+ def coarsest_equitable_refinement(CGraph G, list partition, bint directed):
956
+ """
957
+ Return the coarsest equitable refinement of ``partition`` for ``G``.
958
+
959
+ This is a helper function for the graph function of the same name.
960
+
961
+ DOCTEST (More thorough testing in ``sage/graphs/graph.py``)::
962
+
963
+ sage: from sage.groups.perm_gps.partn_ref.refinement_graphs import coarsest_equitable_refinement
964
+ sage: from sage.graphs.base.sparse_graph import SparseGraph
965
+ sage: coarsest_equitable_refinement(SparseGraph(7), [[0], [1,2,3,4], [5,6]], 0)
966
+ [[0], [1, 2, 3, 4], [5, 6]]
967
+ """
968
+ cdef int i, j = 0, k = 0, n = G.num_verts
969
+
970
+ # set up partition stack and graph struct
971
+ cdef PartitionStack *nu = PS_new(n, 0)
972
+ for cell in partition:
973
+ for i in cell:
974
+ nu.entries[j] = i
975
+ nu.levels[j] = n
976
+ j += 1
977
+ nu.levels[j-1] = 0
978
+ PS_move_min_to_front(nu, k, j-1)
979
+ k = j
980
+
981
+ cdef GraphStruct GS = GraphStruct()
982
+ GS.G = G
983
+ GS.scratch = <int *> sig_malloc((3*n+1) * sizeof(int))
984
+ if GS.scratch is NULL:
985
+ PS_dealloc(nu)
986
+ raise MemoryError
987
+ GS.directed = directed
988
+ GS.use_indicator = 0
989
+
990
+ # set up cells to refine by
991
+ cdef int num_cells = len(partition)
992
+ cdef int *alpha = <int *>sig_malloc(n * sizeof(int))
993
+ if alpha is NULL:
994
+ PS_dealloc(nu)
995
+ sig_free(GS.scratch)
996
+ raise MemoryError
997
+ j = 0
998
+ for i from 0 <= i < num_cells:
999
+ alpha[i] = j
1000
+ j += len(partition[i])
1001
+
1002
+ # refine, and get the result
1003
+ refine_by_degree(nu, <void *>GS, alpha, num_cells)
1004
+
1005
+ eq_part = []
1006
+ cell = []
1007
+ for i from 0 <= i < n:
1008
+ cell.append(nu.entries[i])
1009
+ if nu.levels[i] <= 0:
1010
+ eq_part.append(cell)
1011
+ cell = []
1012
+
1013
+ PS_dealloc(nu)
1014
+ sig_free(GS.scratch)
1015
+ sig_free(alpha)
1016
+
1017
+ return eq_part
1018
+
1019
+
1020
+ def get_orbits(list gens, int n):
1021
+ """
1022
+ Compute orbits given a list of generators of a permutation group, in list
1023
+ format.
1024
+
1025
+ This is a helper function for automorphism groups of graphs.
1026
+
1027
+ DOCTEST (More thorough testing in ``sage/graphs/graph.py``)::
1028
+
1029
+ sage: from sage.groups.perm_gps.partn_ref.refinement_graphs import get_orbits
1030
+ sage: get_orbits([[1,2,3,0,4,5], [0,1,2,3,5,4]], 6)
1031
+ [[0, 1, 2, 3], [4, 5]]
1032
+ """
1033
+ cdef int i, j
1034
+ if len(gens) == 0:
1035
+ return [[i] for i from 0 <= i < n]
1036
+
1037
+ cdef OrbitPartition *OP = OP_new(n)
1038
+ cdef int *perm_ints = <int *> sig_malloc(n * sizeof(int))
1039
+ if perm_ints is NULL:
1040
+ OP_dealloc(OP)
1041
+ raise MemoryError
1042
+
1043
+ for gen in gens:
1044
+ for i from 0 <= i < n:
1045
+ perm_ints[i] = gen[i]
1046
+ OP_merge_list_perm(OP, perm_ints)
1047
+
1048
+ orbit_dict = {}
1049
+ for i from 0 <= i < n:
1050
+ j = OP_find(OP, i)
1051
+ if j in orbit_dict:
1052
+ orbit_dict[j].append(i)
1053
+ else:
1054
+ orbit_dict[j] = [i]
1055
+
1056
+ OP_dealloc(OP)
1057
+ sig_free(perm_ints)
1058
+
1059
+ return list(orbit_dict.itervalues())
1060
+
1061
+
1062
+ # Canonical augmentation
1063
+ from cpython.ref cimport *
1064
+
1065
+ # Dense graphs: adding edges
1066
+
1067
+ # This implements an augmentation scheme as follows:
1068
+ # * Seed objects are graphs with n vertices and no edges.
1069
+ # * Augmentations consist of adding a single edge, or a loop.
1070
+
1071
+ cdef void *dg_edge_gen_next(void *data, int *degree, bint *mem_err) noexcept:
1072
+ r"""
1073
+ The ``next`` function in an edge iterator. The iterator generates unique
1074
+ representatives under the action of the automorphism group of the parent
1075
+ graph on edges not in the graph, which are to considered for adding to the
1076
+ graph.
1077
+ """
1078
+ cdef dg_edge_gen_data *degd = <dg_edge_gen_data *> data
1079
+ cdef GraphStruct graph = <GraphStruct> degd.graph
1080
+ cdef subset *edge_candidate
1081
+ cdef int u, v, reject
1082
+ cdef bint mem_err_sub = 0
1083
+ if mem_err[0]:
1084
+ (<canonical_generator_data *> degd.edge_iterator.data).mem_err = 1
1085
+ while True:
1086
+ edge_candidate = <subset *> degd.edge_iterator.next(degd.edge_iterator.data, NULL, &mem_err_sub)
1087
+ if edge_candidate is NULL:
1088
+ break
1089
+ reject = 0
1090
+ if bitset_len(&edge_candidate.bits) < (1 if graph.loops else 2):
1091
+ reject = 1
1092
+ else:
1093
+ u = bitset_first(&edge_candidate.bits)
1094
+ v = bitset_next(&edge_candidate.bits, u+1)
1095
+ if v == -1:
1096
+ v = u
1097
+ if graph.G.has_arc_unsafe(u, v):
1098
+ reject = 1
1099
+ if not reject:
1100
+ break
1101
+ if mem_err_sub:
1102
+ mem_err[0] = 1
1103
+ return edge_candidate
1104
+
1105
+ cdef void *allocate_degd(int degree) noexcept:
1106
+ r"""
1107
+ Allocate the data part of the iterator over edges to add to the graph.
1108
+ """
1109
+ cdef dg_edge_gen_data *degd = <dg_edge_gen_data *> sig_malloc(sizeof(dg_edge_gen_data))
1110
+ cdef iterator *edge_iterator = allocate_subset_gen(degree, 2)
1111
+ if degd is NULL or edge_iterator is NULL:
1112
+ sig_free(degd)
1113
+ free_subset_gen(edge_iterator)
1114
+ return NULL
1115
+ edge_iterator = setup_set_gen(edge_iterator, degree, 2)
1116
+ if edge_iterator is NULL:
1117
+ sig_free(degd)
1118
+ return NULL
1119
+ degd.edge_iterator = edge_iterator
1120
+ return degd
1121
+
1122
+ cdef void deallocate_degd(void *data) noexcept:
1123
+ r"""
1124
+ Deallocate the data part of the iterator over edges to add to the graph.
1125
+ """
1126
+ cdef dg_edge_gen_data *degd = <dg_edge_gen_data *> data
1127
+ free_subset_gen(degd.edge_iterator)
1128
+ sig_free(degd)
1129
+
1130
+ cdef int gen_children_dg_edge(void *S, aut_gp_and_can_lab *group, iterator *it) noexcept:
1131
+ r"""
1132
+ Setup an iterator over edges to be added.
1133
+ """
1134
+ cdef GraphStruct GS = <GraphStruct> S
1135
+ cdef int n = GS.G.num_verts
1136
+ (<dg_edge_gen_data *> it.data).graph = <void *> GS
1137
+ cdef iterator *edge_iterator = setup_set_gen((<dg_edge_gen_data *> it.data).edge_iterator, n, 2)
1138
+ if edge_iterator is not NULL:
1139
+ start_canonical_generator(group.group, NULL, n, edge_iterator)
1140
+ return (edge_iterator is NULL)
1141
+
1142
+ cdef void *apply_dg_edge_aug(void *parent, void *aug, void *child, int *degree, bint *mem_err) noexcept:
1143
+ r"""
1144
+ Apply the augmentation to ``parent`` storing the result in ``child``. Here
1145
+ ``aug`` represents an edge to be added.
1146
+ """
1147
+ cdef GraphStruct GS_child = <GraphStruct> child, GS_par = <GraphStruct> parent
1148
+ cdef DenseGraph DG = <DenseGraph> GS_child.G, DG_par = <DenseGraph> GS_par.G
1149
+ cdef subset *edge = <subset *> aug
1150
+ cdef int u, v
1151
+
1152
+ # copy DG_par edges to DG
1153
+ copy_dense_graph(DG, DG_par)
1154
+
1155
+ # add the edge
1156
+ u = bitset_first(&edge.bits)
1157
+ v = bitset_next(&edge.bits, u+1)
1158
+ if v == -1:
1159
+ DG.add_arc_unsafe(u, u)
1160
+ else:
1161
+ DG.add_arc_unsafe(u, v)
1162
+ DG.add_arc_unsafe(v, u)
1163
+
1164
+ degree[0] = DG.num_verts
1165
+ return <void *> GS_child
1166
+
1167
+ cdef void *allocate_dg_edge(int n, bint loops) noexcept:
1168
+ r"""
1169
+ Allocate an object for this augmentation scheme.
1170
+ """
1171
+ cdef GraphStruct GS
1172
+ cdef DenseGraph G
1173
+ cdef int *scratch
1174
+ try:
1175
+ GS = GraphStruct()
1176
+ G = DenseGraph(n)
1177
+ scratch = <int *> sig_malloc((3*n+1) * sizeof(int))
1178
+ if scratch is NULL:
1179
+ raise MemoryError
1180
+ except MemoryError:
1181
+ return NULL
1182
+ Py_INCREF(GS)
1183
+ Py_INCREF(G)
1184
+ GS.G = G
1185
+ GS.directed = 0
1186
+ GS.loops = loops
1187
+ GS.use_indicator = 1
1188
+ GS.scratch = scratch
1189
+ return <void *> GS
1190
+
1191
+ cdef void free_dg_edge(void *child) noexcept:
1192
+ r"""
1193
+ Deallocate an object for this augmentation scheme.
1194
+ """
1195
+ cdef GraphStruct GS = <GraphStruct> child
1196
+ sig_free(GS.scratch)
1197
+ Py_DECREF(GS.G)
1198
+ Py_DECREF(GS)
1199
+
1200
+ cdef void *canonical_dg_edge_parent(void *child, void *parent, int *permutation, int *degree, bint *mem_err) noexcept:
1201
+ r"""
1202
+ Apply ``permutation`` to ``child``, determine an arbitrary parent by
1203
+ deleting the lexicographically largest edge, apply the inverse of
1204
+ ``permutation`` to the result and store the result in ``parent``.
1205
+ """
1206
+ cdef GraphStruct GS_par = <GraphStruct> parent, GS = <GraphStruct> child
1207
+ cdef DenseGraph DG_par = <DenseGraph> GS_par.G, DG = <DenseGraph> GS.G
1208
+ cdef int u, v, n = DG.num_verts
1209
+ cdef int *scratch = GS_par.scratch
1210
+
1211
+ # copy DG edges to DG_par
1212
+ copy_dense_graph(DG_par, DG)
1213
+
1214
+ # remove the right edge
1215
+ for u from 0 <= u < n:
1216
+ scratch[permutation[u]] = u
1217
+ for u from n > u >= 0:
1218
+ if DG.in_degrees[scratch[u]] != 0:
1219
+ break
1220
+ for v from u >= v >= 0:
1221
+ if DG.has_arc_unsafe(scratch[u], scratch[v]):
1222
+ break
1223
+ DG_par.del_arc_unsafe(scratch[u], scratch[v])
1224
+ if u != v:
1225
+ DG_par.del_arc_unsafe(scratch[v], scratch[u])
1226
+
1227
+ degree[0] = n
1228
+ return <void *> GS_par
1229
+
1230
+ cdef iterator *allocate_dg_edge_gen(int degree, int depth, bint loops) noexcept:
1231
+ r"""
1232
+ Allocate the iterator for generating graphs.
1233
+ """
1234
+ cdef iterator *dg_edge_gen = <iterator *> sig_malloc(sizeof(iterator))
1235
+ cdef canonical_generator_data *cgd = allocate_cgd(depth, degree)
1236
+ if dg_edge_gen is NULL or cgd is NULL:
1237
+ sig_free(dg_edge_gen)
1238
+ deallocate_cgd(cgd)
1239
+ return NULL
1240
+ cdef int i, j
1241
+ for i from 0 <= i < depth:
1242
+ cgd.object_stack[i] = allocate_dg_edge(degree, loops)
1243
+ cgd.parent_stack[i] = allocate_dg_edge(degree, loops)
1244
+ cgd.iterator_stack[i].data = allocate_degd(degree)
1245
+ cgd.iterator_stack[i].next = &dg_edge_gen_next
1246
+ if cgd.iterator_stack[i].data is NULL or \
1247
+ cgd.object_stack[i] is NULL or \
1248
+ cgd.parent_stack[i] is NULL:
1249
+ for j from 0 <= j <= i:
1250
+ deallocate_degd(cgd.iterator_stack[j].data)
1251
+ free_dg_edge(cgd.object_stack[j])
1252
+ free_dg_edge(cgd.parent_stack[j])
1253
+ sig_free(dg_edge_gen)
1254
+ deallocate_cgd(cgd)
1255
+ return NULL
1256
+ dg_edge_gen.data = <void *> cgd
1257
+ dg_edge_gen.next = canonical_generator_next
1258
+ return dg_edge_gen
1259
+
1260
+ cdef void free_dg_edge_gen(iterator *dg_edge_gen) noexcept:
1261
+ r"""
1262
+ Deallocate the iterator for generating graphs.
1263
+ """
1264
+ cdef canonical_generator_data *cgd = <canonical_generator_data *> dg_edge_gen.data
1265
+ deallocate_cgd(cgd)
1266
+ sig_free(dg_edge_gen)
1267
+
1268
+
1269
+ def generate_dense_graphs_edge_addition(int n, bint loops, G=None, depth=None,
1270
+ bint construct=False,
1271
+ bint indicate_mem_err=True):
1272
+ r"""
1273
+
1274
+ EXAMPLES::
1275
+
1276
+ sage: from sage.groups.perm_gps.partn_ref.refinement_graphs import generate_dense_graphs_edge_addition
1277
+
1278
+ ::
1279
+
1280
+ sage: for n in [0..6]:
1281
+ ....: print(generate_dense_graphs_edge_addition(n,1))
1282
+ 1
1283
+ 2
1284
+ 6
1285
+ 20
1286
+ 90
1287
+ 544
1288
+ 5096
1289
+
1290
+ ::
1291
+
1292
+ sage: for n in [0..7]:
1293
+ ....: print(generate_dense_graphs_edge_addition(n,0))
1294
+ 1
1295
+ 1
1296
+ 2
1297
+ 4
1298
+ 11
1299
+ 34
1300
+ 156
1301
+ 1044
1302
+ sage: generate_dense_graphs_edge_addition(8,0) # long time (about 14 seconds at 2.4 GHz)
1303
+ 12346
1304
+ """
1305
+ from sage.graphs.graph import Graph
1306
+ cdef iterator *graph_iterator
1307
+ cdef DenseGraph DG, ODG
1308
+ cdef GraphStruct GS
1309
+ if n < 0:
1310
+ return [] if construct else Integer(0)
1311
+ if n == 0:
1312
+ return [Graph(0, implementation='c_graph', sparse=False, loops=loops)] if construct else Integer(1)
1313
+ if n == 1:
1314
+ if not loops:
1315
+ return [Graph(1, implementation='c_graph', sparse=False, loops=loops)] if construct else Integer(1)
1316
+ else:
1317
+ if construct:
1318
+ G = Graph(1, implementation='c_graph', sparse=False, loops=loops)
1319
+ (<CGraph>G._backend._cg).add_arc_unsafe(0,0)
1320
+ return [G, Graph(1, implementation='c_graph', sparse=False, loops=loops)]
1321
+ else:
1322
+ return Integer(2)
1323
+
1324
+ if depth is None:
1325
+ depth = n*n
1326
+
1327
+ graph_iterator = allocate_dg_edge_gen(n, depth, loops)
1328
+ if graph_iterator is NULL:
1329
+ raise MemoryError
1330
+
1331
+ GS = (<GraphStruct> (<canonical_generator_data *> graph_iterator.data).object_stack[0])
1332
+ if G is not None:
1333
+ DG = GS.G
1334
+ for u,v in G.edges(sort=False, labels=False):
1335
+ DG.add_arc(u,v)
1336
+ if u != v:
1337
+ DG.add_arc(v,u)
1338
+
1339
+ graph_iterator = setup_canonical_generator(n,
1340
+ all_children_are_equivalent,
1341
+ refine_by_degree,
1342
+ compare_graphs,
1343
+ gen_children_dg_edge,
1344
+ apply_dg_edge_aug,
1345
+ free_dg_edge,
1346
+ deallocate_degd,
1347
+ free_subset,
1348
+ canonical_dg_edge_parent,
1349
+ depth, 0, graph_iterator)
1350
+
1351
+ start_canonical_generator(NULL, <void *> GS, n, graph_iterator)
1352
+
1353
+ cdef list out_list
1354
+ cdef void *thing
1355
+ cdef Integer number
1356
+ cdef bint mem_err = 0
1357
+ if construct:
1358
+ out_list = []
1359
+ else:
1360
+ number = Integer(0)
1361
+ if construct:
1362
+ while True:
1363
+ thing = graph_iterator.next(graph_iterator.data, NULL, &mem_err)
1364
+ if thing is NULL:
1365
+ break
1366
+ ODG = (<GraphStruct>thing).G
1367
+ G = Graph(0, implementation='c_graph', sparse=False)
1368
+ DG = DenseGraph(ODG.active_vertices.size, extra_vertices=0)
1369
+ copy_dense_graph(DG, ODG)
1370
+ G._backend._cg = DG
1371
+ out_list.append(G)
1372
+ else:
1373
+ while True:
1374
+ thing = graph_iterator.next(graph_iterator.data, NULL, &mem_err)
1375
+ if thing is NULL:
1376
+ break
1377
+ number += 1
1378
+
1379
+ free_dg_edge_gen(graph_iterator)
1380
+ if mem_err:
1381
+ if indicate_mem_err:
1382
+ raise MemoryError
1383
+ else:
1384
+ out_list.append(MemoryError())
1385
+ if construct:
1386
+ return out_list
1387
+ else:
1388
+ return number
1389
+
1390
+
1391
+ # Dense graphs: adding vertices
1392
+
1393
+ # This implements an augmentation scheme as follows:
1394
+ # * Seed objects are graphs with one vertex and no edges.
1395
+ # * Augmentations consist of adding a single vertex connected to some subset of
1396
+ # the previous vertices.
1397
+
1398
+ cdef int gen_children_dg_vert(void *S, aut_gp_and_can_lab *group, iterator *it) noexcept:
1399
+ r"""
1400
+ Setup an iterator over subsets to join a new vertex to.
1401
+ """
1402
+ cdef GraphStruct GS = <GraphStruct> S
1403
+ cdef int n = GS.G.num_verts
1404
+ cdef iterator *subset_iterator = setup_set_gen(it, n, n)
1405
+ if subset_iterator is not NULL:
1406
+ start_canonical_generator(group.group, NULL, n, subset_iterator)
1407
+ return (subset_iterator is NULL)
1408
+
1409
+ cdef void *apply_dg_vert_aug(void *parent, void *aug, void *child, int *degree, bint *mem_err) noexcept:
1410
+ r"""
1411
+ Apply the augmentation to ``parent`` storing the result in ``child``. Here
1412
+ ``aug`` represents a subset to join to a new vertex.
1413
+ """
1414
+ cdef GraphStruct GS_child = <GraphStruct> child, GS_par = <GraphStruct> parent
1415
+ cdef DenseGraph DG = <DenseGraph> GS_child.G, DG_par = <DenseGraph> GS_par.G
1416
+ cdef subset *set1 = <subset *> aug
1417
+ cdef int u, n = DG_par.num_verts
1418
+
1419
+ # copy DG_par edges to DG
1420
+ copy_dense_graph(DG, DG_par)
1421
+ DG.add_vertex_unsafe(n)
1422
+
1423
+ # add the edges
1424
+ u = bitset_first(&set1.bits)
1425
+ while u != -1:
1426
+ DG.add_arc_unsafe(u, n)
1427
+ DG.add_arc_unsafe(n, u)
1428
+ u = bitset_next(&set1.bits, u+1)
1429
+
1430
+ degree[0] = n+1
1431
+ return <void *> GS_child
1432
+
1433
+ cdef void *allocate_dg_vert(int n, int depth) noexcept:
1434
+ r"""
1435
+ Allocate an object for this augmentation scheme.
1436
+ """
1437
+ cdef GraphStruct GS
1438
+ cdef DenseGraph G
1439
+ cdef int *scratch
1440
+ try:
1441
+ GS = GraphStruct()
1442
+ G = DenseGraph(0, extra_vertices=depth)
1443
+ bitset_set_first_n(G.active_vertices, n)
1444
+ G.num_verts = n
1445
+ scratch = <int *> sig_malloc((3*depth+1) * sizeof(int))
1446
+ if scratch is NULL:
1447
+ raise MemoryError
1448
+ except MemoryError:
1449
+ return NULL
1450
+ Py_INCREF(GS)
1451
+ Py_INCREF(G)
1452
+ GS.G = G
1453
+ GS.directed = 0
1454
+ GS.loops = 0
1455
+ GS.use_indicator = 1
1456
+ GS.scratch = scratch
1457
+ return <void *> GS
1458
+
1459
+ cdef void free_dg_vert(void *child) noexcept:
1460
+ r"""
1461
+ Deallocate an object for this augmentation scheme.
1462
+ """
1463
+ cdef GraphStruct GS = <GraphStruct> child
1464
+ sig_free(GS.scratch)
1465
+ Py_DECREF(GS.G)
1466
+ Py_DECREF(GS)
1467
+
1468
+ cdef void *canonical_dg_vert_parent(void *child, void *parent, int *permutation, int *degree, bint *mem_err) noexcept:
1469
+ r"""
1470
+ Apply ``permutation`` to ``child``, determines an arbitrary parent by
1471
+ deleting the lexicographically largest vertex, apply the inverse of
1472
+ ``permutation`` to the result and store the result in ``parent``.
1473
+ """
1474
+ cdef GraphStruct GS_par = <GraphStruct> parent, GS = <GraphStruct> child
1475
+ cdef DenseGraph DG_par = <DenseGraph> GS_par.G, DG = <DenseGraph> GS.G
1476
+ cdef int u, n = DG_par.num_verts
1477
+ cdef int *scratch = GS.scratch
1478
+
1479
+ # copy DG edges to DG_par
1480
+ copy_dense_graph(DG_par, DG)
1481
+
1482
+ # remove the right vertex
1483
+ for u from 0 <= u <= n:
1484
+ scratch[permutation[u]] = u
1485
+ DG_par.del_vertex_unsafe(scratch[n])
1486
+
1487
+ degree[0] = n
1488
+ return <void *> GS_par
1489
+
1490
+ cdef iterator *allocate_dg_vert_gen(int degree, int depth) noexcept:
1491
+ r"""
1492
+ Allocate the iterator for generating graphs.
1493
+ """
1494
+ cdef iterator *dg_vert_gen = <iterator *> sig_malloc(sizeof(iterator))
1495
+ cdef canonical_generator_data *cgd = allocate_cgd(depth, degree)
1496
+ cdef canonical_generator_data *cgd2
1497
+ if dg_vert_gen is NULL or cgd is NULL:
1498
+ sig_free(dg_vert_gen)
1499
+ deallocate_cgd(cgd)
1500
+ return NULL
1501
+ cdef int i, j
1502
+ for i from 0 <= i < depth:
1503
+ cgd.object_stack[i] = allocate_dg_vert(i+degree,depth+degree-1)
1504
+ cgd.parent_stack[i] = allocate_dg_vert(i+degree,depth+degree-1)
1505
+ if cgd.object_stack[i] is NULL or \
1506
+ cgd.parent_stack[i] is NULL:
1507
+ for j from 0 <= j <= i:
1508
+ free_dg_vert(cgd.object_stack[j])
1509
+ free_dg_vert(cgd.parent_stack[j])
1510
+ sig_free(dg_vert_gen)
1511
+ deallocate_cgd(cgd)
1512
+ return NULL
1513
+ for i from 0 <= i < depth-1:
1514
+ # TODO: in fact, should this not happen in
1515
+ # dg_vert_gen_children!? otherwise iterator[i].data will be NULL
1516
+ # and no problems.....
1517
+ if allocate_subset_gen_2(i+degree, i+degree, cgd.iterator_stack+i):
1518
+ for j from 0 <= j < depth:
1519
+ free_dg_vert(cgd.object_stack[j])
1520
+ free_dg_vert(cgd.parent_stack[j])
1521
+ for j from 0 <= j < i:
1522
+ cgd2 = <canonical_generator_data *> cgd.iterator_stack[j].data
1523
+ deallocate_cgd(cgd2)
1524
+ sig_free(dg_vert_gen)
1525
+ deallocate_cgd(cgd)
1526
+ return NULL
1527
+ dg_vert_gen.data = <void *> cgd
1528
+ dg_vert_gen.next = canonical_generator_next
1529
+ return dg_vert_gen
1530
+
1531
+ cdef void free_dg_vert_gen(iterator *dg_vert_gen) noexcept:
1532
+ r"""
1533
+ Deallocate the iterator for generating graphs.
1534
+ """
1535
+ cdef canonical_generator_data *cgd = <canonical_generator_data *> dg_vert_gen.data
1536
+ deallocate_cgd(cgd)
1537
+ sig_free(dg_vert_gen)
1538
+
1539
+ cdef void free_cgd_2(void *data) noexcept:
1540
+ r"""
1541
+ A simpler alternative to ``free_cgd``.
1542
+ """
1543
+ cdef canonical_generator_data *cgd = <canonical_generator_data *> data
1544
+ deallocate_cgd(cgd)
1545
+
1546
+
1547
+ def generate_dense_graphs_vert_addition(int n, base_G=None,
1548
+ bint construct=False,
1549
+ bint indicate_mem_err=True):
1550
+ r"""
1551
+
1552
+ EXAMPLES::
1553
+
1554
+ sage: from sage.groups.perm_gps.partn_ref.refinement_graphs import generate_dense_graphs_vert_addition
1555
+
1556
+ ::
1557
+
1558
+ sage: for n in [0..7]:
1559
+ ....: generate_dense_graphs_vert_addition(n)
1560
+ 1
1561
+ 2
1562
+ 4
1563
+ 8
1564
+ 19
1565
+ 53
1566
+ 209
1567
+ 1253
1568
+ sage: generate_dense_graphs_vert_addition(8) # long time
1569
+ 13599
1570
+
1571
+ TESTS::
1572
+
1573
+ sage: from sage.groups.perm_gps.partn_ref.refinement_graphs import generate_dense_graphs_vert_addition
1574
+ sage: generate_dense_graphs_vert_addition(10, base_G=Graph('HEhf^rs'))
1575
+ 11
1576
+ """
1577
+ from sage.graphs.graph import Graph
1578
+ cdef iterator *graph_iterator
1579
+ cdef DenseGraph DG, ODG
1580
+ cdef GraphStruct GS
1581
+ if n < 2:
1582
+ if construct:
1583
+ L = []
1584
+ if n < 0:
1585
+ return L
1586
+ L.append(Graph(0, implementation='c_graph', sparse=False))
1587
+ if n == 0:
1588
+ return L
1589
+ L.append(Graph(0, implementation='c_graph', sparse=False))
1590
+ L.reverse()
1591
+ return L
1592
+ else:
1593
+ if n < 0:
1594
+ return Integer(0)
1595
+ if n == 0:
1596
+ return Integer(1)
1597
+ return Integer(2)
1598
+
1599
+ cdef int start_deg = 1 if base_G is None else base_G.num_verts()
1600
+ graph_iterator = allocate_dg_vert_gen(start_deg, n+1-start_deg)
1601
+ if graph_iterator is NULL:
1602
+ raise MemoryError
1603
+
1604
+ GS = (<GraphStruct> (<canonical_generator_data *> graph_iterator.data).object_stack[0])
1605
+ DG = GS.G
1606
+ if base_G is not None:
1607
+ for v in base_G.vertices(sort=False):
1608
+ DG.add_vertex(v)
1609
+ for u,v in base_G.edges(sort=False, labels=False):
1610
+ DG.add_arc(u,v)
1611
+ DG.add_arc(v,u)
1612
+
1613
+ graph_iterator = setup_canonical_generator(start_deg,
1614
+ all_children_are_equivalent,
1615
+ refine_by_degree,
1616
+ compare_graphs,
1617
+ gen_children_dg_vert,
1618
+ apply_dg_vert_aug,
1619
+ free_dg_vert,
1620
+ free_cgd_2,
1621
+ free_subset,
1622
+ canonical_dg_vert_parent,
1623
+ n+1-start_deg, 0, graph_iterator)
1624
+
1625
+ start_canonical_generator(NULL, <void *> GS, DG.num_verts, graph_iterator)
1626
+
1627
+ cdef list out_list
1628
+ cdef void *thing
1629
+ cdef Integer number
1630
+ cdef bint mem_err = 0
1631
+ if construct:
1632
+ out_list = []
1633
+ else:
1634
+ number = Integer(0)
1635
+ if construct:
1636
+ while True:
1637
+ thing = graph_iterator.next(graph_iterator.data, NULL, &mem_err)
1638
+ if thing is NULL:
1639
+ break
1640
+ ODG = (<GraphStruct>thing).G
1641
+ G = Graph(0, implementation='c_graph', sparse=False)
1642
+ DG = DenseGraph(ODG.active_vertices.size, extra_vertices=0)
1643
+ copy_dense_graph(DG, ODG)
1644
+ G._backend._cg = DG
1645
+ out_list.append(G)
1646
+ else:
1647
+ while True:
1648
+ thing = graph_iterator.next(graph_iterator.data, NULL, &mem_err)
1649
+ if thing is NULL:
1650
+ break
1651
+ number += 1
1652
+
1653
+ free_dg_vert_gen(graph_iterator)
1654
+ if mem_err:
1655
+ if indicate_mem_err:
1656
+ raise MemoryError
1657
+ else:
1658
+ out_list.append(MemoryError())
1659
+ if construct:
1660
+ if base_G is None:
1661
+ out_list = [Graph(0, implementation='c_graph', sparse=False)] + out_list
1662
+ return out_list
1663
+ else:
1664
+ if base_G is None:
1665
+ number += 1
1666
+ return number