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,459 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ r"""
3
+ Partial cubes
4
+
5
+ The code in this module that recognizes partial cubes is originally
6
+ from the PADS library by David Eppstein, which is available at
7
+ http://www.ics.uci.edu/~eppstein/PADS/ under the MIT license. It has a
8
+ quadratic runtime and has been described in [Epp2008]_.
9
+
10
+ For more information on partial cubes, see the :wikipedia:`Partial cube`.
11
+
12
+ Recognition algorithm
13
+ ---------------------
14
+
15
+ Definitions
16
+ ^^^^^^^^^^^
17
+
18
+ A **partial cube** is an isometric subgraph `G` of a
19
+ :meth:`~sage.graphs.graph_generators.GraphGenerators.CubeGraph` (of
20
+ possibly high dimension). Consequently, the vertices of `G` can be
21
+ labelled with binary sequences in such a way that the distance between
22
+ two vertices `u,v\in G` is the Hamming distance between their labels.
23
+
24
+ **Tokens** and their **action**: in the terminology of
25
+ [Epp2008]_, a token represents a transition of the form:
26
+
27
+ *switch the `k`-th bit of the binary string from 0 to 1*
28
+
29
+ Each token can be matched with a 'reversed' token that performs the
30
+ same switch in the opposite direction. Alternatively, a token can be
31
+ seen as a set of disjoint (directed) edges of `G`, corresponding to
32
+ the transitions. When a vertex `v\in G` is the source of such an edge,
33
+ it is said that the token *acts* on `v`.
34
+
35
+ Observations
36
+ ^^^^^^^^^^^^
37
+
38
+ **Shortest paths**: in a hypercube, a shortest path between two
39
+ vertices uses each token at most once. Furthermore, it cannot use both
40
+ a token and it reverse.
41
+
42
+ **Cycles**: a cycle in a partial cube is necessarily even, as
43
+ hypercubes are bipartite. If an edge `e` of a cycle `C` belongs to a
44
+ token `T`, then the edge opposite to `e` in `C` belongs to the reverse
45
+ of `T`.
46
+
47
+ **Incident edges**: all `2d_G(v)` arcs incident to a given vertex
48
+ belong to as many different tokens.
49
+
50
+ Algorithm
51
+ ^^^^^^^^^
52
+
53
+ **Labeling**: Iteratively, the algorithm selects a vertex `v\in G`,
54
+ which is naturally associated to `2d(v)` tokens. It then performs a
55
+ breadth-first search from `v`, applying the previous observation on
56
+ cycles to attribute a token to some of the edges it meets. None of the
57
+ edges whose token remains undecided after this step can belong to one
58
+ of those `2d(v)` tokens, by virtue of the observation on shortest
59
+ paths.
60
+
61
+ The labeled edges can then be simplified (contracted) if the previous
62
+ step did not lead to a contradiction, and the procedure is applied
63
+ again until the graph is contracted to a single vertex and all edges
64
+ are labeled.
65
+
66
+ A partial cube is correctly labeled at this step, but some other
67
+ graphs can also satisfy the procedure.
68
+
69
+ **Checking the labeling**: once all tokens are defined and the
70
+ vertices are labeled with a binary string, we check that they define
71
+ an isometric subgraph of the hypercube. To ensure that the distance
72
+ `d(v_0,u)` is what we expect for any vertex `u`, it is sufficient to
73
+ find, for any vertex `u`, a neighbor `n_u` of `u` whose Hamming
74
+ distance with `v_0` is strictly less than the Hamming distance between
75
+ `u` and `v_0`. Here is the algorithm used to check the labeling:
76
+
77
+ * For an initial vertex `v`, run a BFS starting from `v`, and
78
+ associate to every other vertex `u` a token that brings `u` closer
79
+ to `v`. This yields shortest paths from every vertex to `v`.
80
+
81
+ * Assuming that the information is computed (and correct) for `v`, it
82
+ is easy to update it for a neighbor `v'` of `v`. Indeed, if we write
83
+ `T` the token that turns `v` into `v'`, only the vertices which were
84
+ associated with the reverse of `T` need to select a new neighbour. All
85
+ others can remain as they were previously.
86
+
87
+ With this second observation, one can efficiently check that the
88
+ distance between all pairs of vertices are what they should be. In
89
+ the implementation, the sequence of the sources `(v, v', ...)` is
90
+ given by a depth-first search.
91
+
92
+ Functions
93
+ ---------
94
+ """
95
+
96
+
97
+ def breadth_first_level_search(G, start):
98
+ r"""
99
+ Generate a sequence of dictionaries, each mapping the vertices at
100
+ distance ``i`` from ``start`` to the set of their neighbours at
101
+ distance ``i+1``.
102
+
103
+ Originally written by D. Eppstein for the PADS library
104
+ (http://www.ics.uci.edu/~eppstein/PADS/).
105
+
106
+ INPUT:
107
+
108
+ - ``G`` -- a graph to perform the search on
109
+
110
+ - ``start`` -- vertex or list of vertices from which to start the traversal
111
+
112
+ EXAMPLES::
113
+
114
+ sage: H = digraphs.DeBruijn(3,2) # needs sage.combinat
115
+ sage: list(sage.graphs.partial_cube.breadth_first_level_search(H, '00')) # needs sage.combinat
116
+ [{'00': {'01', '02'}},
117
+ {'01': {'10', '11', '12'}, '02': {'20', '21', '22'}},
118
+ {'10': set(),
119
+ '11': set(),
120
+ '12': set(),
121
+ '20': set(),
122
+ '21': set(),
123
+ '22': set()}]
124
+ """
125
+ neighbors = G.neighbor_out_iterator
126
+ visited = set()
127
+ if isinstance(start, list):
128
+ currentLevel = start
129
+ else:
130
+ currentLevel = [start]
131
+ while currentLevel:
132
+ visited.update(currentLevel)
133
+ nextLevel = set()
134
+ levelGraph = {v: set() for v in currentLevel}
135
+ for v in currentLevel:
136
+ for w in neighbors(v):
137
+ if w not in visited:
138
+ levelGraph[v].add(w)
139
+ nextLevel.add(w)
140
+ yield levelGraph
141
+ currentLevel = nextLevel
142
+
143
+
144
+ def depth_first_traversal(G, start):
145
+ r"""
146
+ Generate a sequence of triples (v,w,edgetype) for DFS of graph G.
147
+
148
+ Originally written by D. Eppstein for the PADS library
149
+ (http://www.ics.uci.edu/~eppstein/PADS/).
150
+
151
+ INPUT:
152
+
153
+ - ``G`` -- a graph to perform the search on
154
+
155
+ - ``start`` -- vertex or list of vertices from which to start the traversal
156
+
157
+ OUTPUT:
158
+
159
+ - a generator of triples ``(v,w,edgetype)``, where ``edgetype`` is ``True``
160
+ if the algorithm is progressing via the edge ``vw``, or ``False`` if the
161
+ algorithm is backtracking via the edge ``wv``.
162
+
163
+ EXAMPLES::
164
+
165
+ sage: H = digraphs.DeBruijn(3,2) # needs sage.combinat
166
+ sage: t = list(sage.graphs.partial_cube.depth_first_traversal(H, '00')) # needs sage.combinat
167
+ sage: len(t) # needs sage.combinat
168
+ 16
169
+ """
170
+ neighbors = G.neighbor_out_iterator
171
+ seen = set()
172
+ if not isinstance(start, list):
173
+ start = [start]
174
+
175
+ for v in start:
176
+ if v in seen:
177
+ continue
178
+ seen.add(v)
179
+ stack = [(v, neighbors(v))]
180
+ while stack:
181
+ parent, children = stack[-1]
182
+ try:
183
+ child = next(children)
184
+ if child not in seen:
185
+ yield (parent, child, True)
186
+ seen.add(child)
187
+ stack.append((child, neighbors(child)))
188
+ except StopIteration:
189
+ stack.pop()
190
+ if stack:
191
+ yield (stack[-1][0], parent, False)
192
+
193
+
194
+ def is_partial_cube(G, certificate=False):
195
+ r"""
196
+ Test whether the given graph is a partial cube.
197
+
198
+ A partial cube is a graph that can be isometrically embedded into a
199
+ hypercube, i.e., its vertices can be labelled with (0,1)-vectors of some
200
+ fixed length such that the distance between any two vertices in the graph
201
+ equals the Hamming distance of their labels.
202
+
203
+ Originally written by D. Eppstein for the PADS library
204
+ (http://www.ics.uci.edu/~eppstein/PADS/), see also
205
+ [Epp2008]_. The algorithm runs in `O(n^2)` time, where `n`
206
+ is the number of vertices. See the documentation of
207
+ :mod:`~sage.graphs.partial_cube` for an overview of the algorithm.
208
+
209
+ INPUT:
210
+
211
+ - ``certificate`` -- boolean (default: ``False``); this function returns
212
+ ``True`` or ``False`` according to the graph, when ``certificate =
213
+ False``. When ``certificate = True`` and the graph is a partial cube, the
214
+ function returns ``(True, mapping)``, where ``mapping`` is an isometric
215
+ mapping of the vertices of the graph to the vertices of a hypercube
216
+ ((0, 1)-strings of a fixed length). When ``certificate = True`` and the
217
+ graph is not a partial cube, ``(False, None)`` is returned.
218
+
219
+ EXAMPLES:
220
+
221
+ The Petersen graph is not a partial cube::
222
+
223
+ sage: g = graphs.PetersenGraph()
224
+ sage: g.is_partial_cube()
225
+ False
226
+
227
+ All prisms are partial cubes::
228
+
229
+ sage: g = graphs.CycleGraph(10).cartesian_product(graphs.CompleteGraph(2))
230
+ sage: g.is_partial_cube()
231
+ True
232
+
233
+ TESTS:
234
+
235
+ The returned mapping is an isometric embedding into a hypercube::
236
+
237
+ sage: g = graphs.DesarguesGraph()
238
+ sage: _, m = g.is_partial_cube(certificate=True)
239
+ sage: m # random
240
+ {0: '00000',
241
+ 1: '00001',
242
+ 2: '00011',
243
+ 3: '01011',
244
+ 4: '11011',
245
+ 5: '11111',
246
+ 6: '11110',
247
+ 7: '11100',
248
+ 8: '10100',
249
+ 9: '00100',
250
+ 10: '01000',
251
+ 11: '10001',
252
+ 12: '00111',
253
+ 13: '01010',
254
+ 14: '11001',
255
+ 15: '10111',
256
+ 16: '01110',
257
+ 17: '11000',
258
+ 18: '10101',
259
+ 19: '00110'}
260
+ sage: all(all(g.distance(u, v) == len([i for i in range(len(m[u])) if m[u][i] != m[v][i]]) for v in m) for u in m)
261
+ True
262
+
263
+ A graph without vertices is trivially a partial cube::
264
+
265
+ sage: Graph().is_partial_cube(certificate=True)
266
+ (True, {})
267
+ """
268
+ G._scream_if_not_simple()
269
+
270
+ if not G.order():
271
+ if certificate:
272
+ return (True, {})
273
+ else:
274
+ return True
275
+
276
+ if certificate:
277
+ fail = (False, None)
278
+ else:
279
+ fail = False
280
+
281
+ if not G.is_connected():
282
+ return fail
283
+ n = G.order()
284
+
285
+ # Initial sanity check: are there few enough edges?
286
+ # Needed so that we don't try to use union-find on a dense
287
+ # graph and incur superquadratic runtimes.
288
+ if 1 << (2 * G.size() // n) > n:
289
+ return fail
290
+
291
+ # Check for bipartiteness.
292
+ # This ensures also that each contraction will be bipartite.
293
+ if not G.is_bipartite():
294
+ return fail
295
+
296
+ # Set up data structures for algorithm:
297
+ # - contracted: contracted graph at current stage of algorithm
298
+ # - unionfind: union find data structure representing known edge equivalences
299
+ # - available: limit on number of remaining available labels
300
+ from sage.graphs.digraph import DiGraph
301
+ from sage.graphs.graph import Graph
302
+ from sage.sets.disjoint_set import DisjointSet
303
+ contracted = DiGraph({v: {w: (v, w) for w in G[v]} for v in G})
304
+ unionfind = DisjointSet(contracted.edges(sort=True, labels=False))
305
+ available = n - 1
306
+
307
+ # Main contraction loop in place of the original algorithm's recursion
308
+ while contracted.order() > 1:
309
+ # Find max degree vertex in contracted, and update label limit
310
+ deg, root = max([(contracted.out_degree(v), v) for v in contracted], key=lambda x: x[0])
311
+ if deg > available:
312
+ return fail
313
+ available -= deg
314
+
315
+ # Set up bitvectors on vertices
316
+ bitvec = {v: 0 for v in contracted}
317
+ neighbors = {}
318
+ for i, neighbor in enumerate(contracted[root]):
319
+ bitvec[neighbor] = 1 << i
320
+ neighbors[1 << i] = neighbor
321
+
322
+ # Breadth first search to propagate bitvectors to the rest of the graph
323
+ for level in breadth_first_level_search(contracted, root):
324
+ for v in level:
325
+ for w in level[v]:
326
+ bitvec[w] |= bitvec[v]
327
+
328
+ # Make graph of labeled edges and union them together
329
+ labeled = Graph([contracted.vertices(sort=False), []])
330
+ for v, w in contracted.edge_iterator(labels=False):
331
+ diff = bitvec[v] ^ bitvec[w]
332
+ if not diff or not bitvec[w] & ~bitvec[v]:
333
+ continue # zero edge or wrong direction
334
+ if diff not in neighbors:
335
+ return fail
336
+ neighbor = neighbors[diff]
337
+ unionfind.union(contracted.edge_label(v, w),
338
+ contracted.edge_label(root, neighbor))
339
+ unionfind.union(contracted.edge_label(w, v),
340
+ contracted.edge_label(neighbor, root))
341
+ labeled.add_edge(v, w)
342
+
343
+ # Map vertices to components of labeled-edge graph
344
+ component = {}
345
+ for i, SCC in enumerate(labeled.connected_components(sort=False)):
346
+ for v in SCC:
347
+ component[v] = i
348
+
349
+ # generate new compressed subgraph
350
+ newgraph = DiGraph()
351
+ for v, w, t in contracted.edge_iterator():
352
+ if bitvec[v] == bitvec[w]:
353
+ vi = component[v]
354
+ wi = component[w]
355
+ if vi == wi:
356
+ return fail
357
+ if newgraph.has_edge(vi, wi):
358
+ unionfind.union(newgraph.edge_label(vi, wi), t)
359
+ else:
360
+ newgraph.add_edge(vi, wi, t)
361
+ contracted = newgraph
362
+
363
+ # Make a digraph with edges labeled by the equivalence classes in unionfind
364
+ g = DiGraph({v: {w: unionfind.find((v, w)) for w in G[v]} for v in G})
365
+
366
+ # Associates to a vertex the token that acts on it, and check that
367
+ # no two edges on a single vertex have the same label
368
+ action = {}
369
+ for v in g:
370
+ action[v] = set(t for _, _, t in g.edge_iterator(v))
371
+ if len(action[v]) != g.out_degree(v):
372
+ return fail
373
+
374
+ # Associate every token to its reverse
375
+ reverse = {}
376
+ for v, w, t in g.edge_iterator():
377
+ rt = g.edge_label(w, v)
378
+ reverse[t] = rt
379
+ reverse[rt] = t
380
+
381
+ current = initialState = next(g.vertex_iterator())
382
+
383
+ # A token T is said to be 'active' for a vertex u if it takes u
384
+ # one step closer to the source in terms of distance. The 'source'
385
+ # is initially 'initialState'. See the module's documentation for
386
+ # more explanations.
387
+
388
+ # Find list of tokens that lead to the initial state
389
+ activeTokens = set()
390
+ for level in breadth_first_level_search(g, initialState):
391
+ for v in level:
392
+ for w in level[v]:
393
+ activeTokens.add(g.edge_label(w, v))
394
+ for t in activeTokens:
395
+ if reverse[t] in activeTokens:
396
+ return fail
397
+ activeTokens = list(activeTokens)
398
+
399
+ # Rest of data structure: point from states to list and list to states
400
+ state_to_active_token = {v: -1 for v in g}
401
+ token_to_states = [[] for _ in activeTokens] # (i.e. vertices on which each token acts)
402
+
403
+ def scan(v):
404
+ """
405
+ Find the next token that is effective for v.
406
+ """
407
+ a = next(i for i in range(state_to_active_token[v] + 1, len(activeTokens))
408
+ if activeTokens[i] is not None and activeTokens[i] in action[v])
409
+ state_to_active_token[v] = a
410
+ token_to_states[a].append(v)
411
+
412
+ # Initialize isometric embedding into a hypercube
413
+ if certificate:
414
+ dim = 0
415
+ tokmap = {}
416
+ for t in reverse:
417
+ if t not in tokmap:
418
+ tokmap[t] = tokmap[reverse[t]] = 1 << dim
419
+ dim += 1
420
+ embed = {initialState: 0}
421
+
422
+ # Set initial active states
423
+ for v in g:
424
+ if v != current:
425
+ try:
426
+ scan(v)
427
+ except StopIteration:
428
+ return fail
429
+
430
+ # Traverse the graph, maintaining active tokens
431
+ for prev, current, fwd in depth_first_traversal(g, initialState):
432
+ if not fwd:
433
+ prev, current = current, prev
434
+ elif certificate:
435
+ embed[current] = embed[prev] ^ tokmap[g.edge_label(prev, current)]
436
+
437
+ # Add token to end of list, point to it from old state
438
+ activeTokens.append(g.edge_label(prev, current))
439
+ state_to_active_token[prev] = len(activeTokens) - 1
440
+ token_to_states.append([prev])
441
+
442
+ # Deactivate reverse token, find new token for its states
443
+ #
444
+ # (the 'active' token of 'current' is necessarily the label of
445
+ # (current, previous))
446
+ activeTokens[state_to_active_token[current]] = None
447
+ for v in token_to_states[state_to_active_token[current]]:
448
+ if v != current:
449
+ try:
450
+ scan(v)
451
+ except StopIteration:
452
+ return fail
453
+
454
+ # All checks passed, return the result
455
+ if certificate:
456
+ format = "{0:0%db}" % dim
457
+ return (True, {v: format.format(l) for v, l in embed.items()})
458
+ else:
459
+ return True