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,870 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ # cython: binding=True
3
+ r"""
4
+ Convexity properties of graphs
5
+
6
+ This class gathers the algorithms related to convexity in a graph. It implements
7
+ the following methods:
8
+
9
+ .. csv-table::
10
+ :class: contentstable
11
+ :widths: 30, 70
12
+ :delim: |
13
+
14
+ :meth:`ConvexityProperties.hull` | Return the convex hull of a set of vertices
15
+ :meth:`ConvexityProperties.hull_number` | Compute the hull number of a graph and a corresponding generating set
16
+ :meth:`geodetic_closure`| Return the geodetic closure of a set of vertices
17
+ :meth:`is_geodetic` | Check whether the input (di)graph is geodetic
18
+
19
+ Some of these methods can be used through the :class:`ConvexityProperties`
20
+ object returned by :meth:`Graph.convexity_properties`.
21
+
22
+ Methods
23
+ -------
24
+ """
25
+
26
+ # ****************************************************************************
27
+ # Copyright (C) 2011 Nathann Cohen <nathann.cohen@gmail.com>
28
+ # 2021 David Coudert <david.coudert@inria.fr>
29
+ #
30
+ # This program is free software: you can redistribute it and/or modify
31
+ # it under the terms of the GNU General Public License as published by
32
+ # the Free Software Foundation, either version 2 of the License, or
33
+ # (at your option) any later version.
34
+ # https://www.gnu.org/licenses/
35
+ # ****************************************************************************
36
+
37
+ from sage.data_structures.binary_matrix cimport *
38
+ from sage.numerical.backends.generic_backend cimport GenericBackend
39
+ from sage.numerical.backends.generic_backend import get_solver
40
+ from sage.graphs.distances_all_pairs cimport c_distances_all_pairs
41
+ from cysignals.memory cimport sig_free
42
+ from memory_allocator cimport MemoryAllocator
43
+ from libc.stdint cimport uint32_t
44
+ from sage.graphs.base.static_sparse_backend cimport StaticSparseCGraph
45
+ from sage.graphs.base.static_sparse_backend cimport StaticSparseBackend
46
+ from sage.graphs.base.static_sparse_graph cimport (short_digraph,
47
+ init_short_digraph,
48
+ free_short_digraph,
49
+ out_degree,
50
+ simple_BFS)
51
+
52
+
53
+ cdef class ConvexityProperties:
54
+ r"""
55
+ This class gathers the algorithms related to convexity in a graph.
56
+
57
+ **Definitions**
58
+
59
+ A set `S \subseteq V(G)` of vertices is said to be convex if for all `u,v\in
60
+ S` the set `S` contains all the vertices located on a shortest path between
61
+ `u` and `v`. Alternatively, a set `S` is said to be convex if the distances
62
+ satisfy `\forall u,v\in S, \forall w\in V\backslash S : d_{G}(u,w) +
63
+ d_{G}(w,v) > d_{G}(u,v)`.
64
+
65
+ The convex hull `h(S)` of a set `S` of vertices is defined as the smallest
66
+ convex set containing `S`.
67
+
68
+ It is a closure operator, as trivially `S\subseteq h(S)` and `h(h(S)) =
69
+ h(S)`.
70
+
71
+ **What this class contains**
72
+
73
+ As operations on convex sets generally involve the computation of distances
74
+ between vertices, this class' purpose is to cache that information so that
75
+ computing the convex hulls of several different sets of vertices does not
76
+ imply recomputing several times the distances between the vertices.
77
+
78
+ In order to compute the convex hull of a set `S` it is possible to write the
79
+ following algorithm:
80
+
81
+ For any pair `u,v` of elements in the set `S`, and for any vertex `w`
82
+ outside of it, add `w` to `S` if `d_{G}(u,w) + d_{G}(w,v) =
83
+ d_{G}(u,v)`. When no vertex can be added anymore, the set `S` is convex
84
+
85
+ The distances are not actually that relevant. The same algorithm can be
86
+ implemented by remembering for each pair `u, v` of vertices the list of
87
+ elements `w` satisfying the condition, and this is precisely what this class
88
+ remembers, encoded as bitsets to make storage and union operations more
89
+ efficient.
90
+
91
+ .. NOTE::
92
+
93
+ * This class is useful if you compute the convex hulls of many sets in
94
+ the same graph, or if you want to compute the hull number itself as it
95
+ involves many calls to :meth:`hull`
96
+
97
+ * Using this class on non-connected graphs is a waste of space and
98
+ efficiency ! If your graph is disconnected, the best for you is to
99
+ deal independently with each connected component, whatever you are
100
+ doing.
101
+
102
+ **Possible improvements**
103
+
104
+ When computing a convex set, all the pairs of elements belonging to the set
105
+ `S` are enumerated several times.
106
+
107
+ * There should be a smart way to avoid enumerating pairs of vertices which
108
+ have already been tested. The cost of each of them is not very high, so
109
+ keeping track of those which have been tested already may be too expensive
110
+ to gain any efficiency.
111
+
112
+ * The ordering in which they are visited is currently purely lexicographic,
113
+ while there is a Poset structure to exploit. In particular, when two
114
+ vertices `u, v` are far apart and generate a set `h(\{u,v\})` of vertices,
115
+ all the pairs of vertices `u', v'\in h(\{u,v\})` satisfy `h(\{u',v'\})
116
+ \subseteq h(\{u,v\})`, and so it is useless to test the pair `u', v'` when
117
+ both `u` and `v` where present.
118
+
119
+ * The information cached is for any pair `u,v` of vertices the list of
120
+ elements `z` with `d_{G}(u,w) + d_{G}(w,v) = d_{G}(u,v)`. This is not in
121
+ general equal to `h(\{u,v\})` !
122
+
123
+ Nothing says these recommendations will actually lead to any actual
124
+ improvements. There are just some ideas remembered while writing this
125
+ code. Trying to optimize may well lead to lost in efficiency on many
126
+ instances.
127
+
128
+ EXAMPLES::
129
+
130
+ sage: from sage.graphs.convexity_properties import ConvexityProperties
131
+ sage: g = graphs.PetersenGraph()
132
+ sage: CP = ConvexityProperties(g)
133
+ sage: CP.hull([1, 3])
134
+ [1, 2, 3]
135
+ sage: CP.hull_number() # needs sage.numerical.mip
136
+ 3
137
+
138
+ TESTS::
139
+
140
+ sage: ConvexityProperties(digraphs.Circuit(5))
141
+ Traceback (most recent call last):
142
+ ...
143
+ NotImplementedError: this is currently implemented for Graphs only, but only minor updates are needed if you want to make it support DiGraphs too
144
+ """
145
+
146
+ def __init__(self, G):
147
+ r"""
148
+ Constructor.
149
+
150
+ EXAMPLES::
151
+
152
+ sage: from sage.graphs.convexity_properties import ConvexityProperties
153
+ sage: g = graphs.PetersenGraph()
154
+ sage: ConvexityProperties(g)
155
+ <sage.graphs.convexity_properties.ConvexityProperties object at ...>
156
+ """
157
+ from sage.graphs.digraph import DiGraph
158
+ if isinstance(G, DiGraph):
159
+ raise NotImplementedError("this is currently implemented for Graphs only, "
160
+ "but only minor updates are needed if you want "
161
+ "to make it support DiGraphs too")
162
+
163
+ # Cached number of vertices
164
+ cdef int n = G.order()
165
+ self._n = n
166
+
167
+ cdef int i = 0
168
+ cdef int j, k
169
+
170
+ # Build mappings integer <-> vertices.
171
+ # Must be consistent with the mappings used in c_distances_all_pairs
172
+ self._list_integers_to_vertices = list(G)
173
+ self._dict_vertices_to_integers = {v: i for i, v in enumerate(self._list_integers_to_vertices)}
174
+
175
+ # Computation of distances between all pairs. Costly.
176
+ cdef unsigned short* c_distances = c_distances_all_pairs(G, vertex_list=self._list_integers_to_vertices)
177
+ # Temporary variables
178
+ cdef unsigned short* d_i
179
+ cdef unsigned short* d_j
180
+ cdef int d_ij
181
+
182
+ # We use a binary matrix with one row per pair of vertices,
183
+ # so n * (n - 1) / 2 rows. Row u * n + v is a bitset whose 1 bits are
184
+ # the vertices located on a shortest path from vertex u to v
185
+ #
186
+ # Note that u < v
187
+ binary_matrix_init(self._cache_hull_pairs, n * (n - 1) / 2, n)
188
+ binary_matrix_fill(self._cache_hull_pairs, 0)
189
+ cdef bitset_t * p_bitset = self._cache_hull_pairs.rows
190
+
191
+ # Filling the cache
192
+ #
193
+ # The p_bitset variable iterates over the successive elements of the cache
194
+ #
195
+ # For any pair i, j of vertices (i < j), we built the bitset of all the
196
+ # elements k which are on a shortest path from i to j
197
+
198
+ for i in range(n):
199
+ # Caching the distances from i to the other vertices
200
+ d_i = c_distances + n * i
201
+
202
+ for j in range(i + 1, n):
203
+ # Caching the distances from j to the other vertices
204
+ d_j = c_distances + n * j
205
+
206
+ # Caching the distance between i and j
207
+ d_ij = d_i[j]
208
+
209
+ # Filling it
210
+ for k in range(n):
211
+ if d_i[k] + d_j[k] == d_ij:
212
+ bitset_add(p_bitset[0], k)
213
+
214
+ # Next bitset !
215
+ p_bitset = p_bitset + 1
216
+
217
+ sig_free(c_distances)
218
+
219
+ def __dealloc__(self):
220
+ r"""
221
+ Destructor.
222
+
223
+ EXAMPLES::
224
+
225
+ sage: from sage.graphs.convexity_properties import ConvexityProperties
226
+ sage: g = graphs.PetersenGraph()
227
+ sage: ConvexityProperties(g)
228
+ <sage.graphs.convexity_properties.ConvexityProperties object at ...>
229
+ """
230
+ binary_matrix_free(self._cache_hull_pairs)
231
+
232
+ cdef list _vertices_to_integers(self, vertices):
233
+ r"""
234
+ Convert a list of vertices to a list of integers with the cached data.
235
+ """
236
+ return [self._dict_vertices_to_integers[v] for v in vertices]
237
+
238
+ cdef list _integers_to_vertices(self, list integers):
239
+ r"""
240
+ Convert a list of integers to a list of vertices with the cached data.
241
+ """
242
+ cdef int i
243
+ return [self._list_integers_to_vertices[i] for i in integers]
244
+
245
+ cdef _bitset_convex_hull(self, bitset_t hull):
246
+ r"""
247
+ Compute the convex hull of a list of vertices given as a bitset.
248
+
249
+ (this method returns nothing and modifies the input)
250
+ """
251
+ cdef int count
252
+ cdef int tmp_count
253
+ cdef int i, j
254
+
255
+ cdef bitset_t * p_bitset
256
+
257
+ # Current size of the set
258
+ count = bitset_len(hull)
259
+
260
+ while True:
261
+
262
+ # Iterating over all the elements in the cache
263
+ p_bitset = self._cache_hull_pairs.rows
264
+
265
+ # For any vertex i
266
+ for i in range(self._n - 1):
267
+
268
+ # If i is not in the current set, we skip it !
269
+ if not bitset_in(hull, i):
270
+ p_bitset = p_bitset + (self._n - 1 - i)
271
+ continue
272
+
273
+ # If it is, we iterate over all the elements j
274
+ for j in range(i + 1, self._n):
275
+
276
+ # If both i and j are inside, we add all the (cached)
277
+ # vertices on a shortest ij-path
278
+
279
+ if bitset_in(hull, j):
280
+ bitset_union(hull, hull, p_bitset[0])
281
+
282
+ # Next bitset !
283
+ p_bitset = p_bitset + 1
284
+
285
+ tmp_count = bitset_len(hull)
286
+
287
+ # If we added nothing new during the previous loop, our set is
288
+ # convex !
289
+ if tmp_count == count:
290
+ return
291
+
292
+ # Otherwise, update and back to the loop
293
+ count = tmp_count
294
+
295
+ cpdef hull(self, list vertices):
296
+ r"""
297
+ Return the convex hull of a set of vertices.
298
+
299
+ INPUT:
300
+
301
+ - ``vertices`` -- list of vertices
302
+
303
+ EXAMPLES::
304
+
305
+ sage: from sage.graphs.convexity_properties import ConvexityProperties
306
+ sage: g = graphs.PetersenGraph()
307
+ sage: CP = ConvexityProperties(g)
308
+ sage: CP.hull([1, 3])
309
+ [1, 2, 3]
310
+ """
311
+ cdef bitset_t bs
312
+ bitset_init(bs, self._n)
313
+ bitset_set_first_n(bs, 0)
314
+
315
+ for v in vertices:
316
+ bitset_add(bs, <mp_bitcnt_t> self._dict_vertices_to_integers[v])
317
+
318
+ self._bitset_convex_hull(bs)
319
+
320
+ cdef list answer = self._integers_to_vertices(bitset_list(bs))
321
+
322
+ bitset_free(bs)
323
+
324
+ return answer
325
+
326
+ cdef _greedy_increase(self, bitset_t bs):
327
+ r"""
328
+ Given a bitset whose hull is not the whole set, greedily add vertices
329
+ and stop before its hull is the whole set.
330
+
331
+ .. NOTE::
332
+
333
+ * Counting the bits at each turn is not the best way...
334
+ """
335
+ cdef bitset_t tmp
336
+ bitset_init(tmp, self._n)
337
+
338
+ for i in range(self._n):
339
+ if not bitset_in(bs, i):
340
+ bitset_copy(tmp, bs)
341
+ bitset_add(tmp, i)
342
+ self._bitset_convex_hull(tmp)
343
+ if bitset_len(tmp) < self._n:
344
+ bitset_add(bs, i)
345
+
346
+ bitset_free(tmp)
347
+
348
+ cpdef hull_number(self, value_only=True, verbose=False):
349
+ r"""
350
+ Compute the hull number and a corresponding generating set.
351
+
352
+ The hull number `hn(G)` of a graph `G` is the cardinality of a smallest
353
+ set of vertices `S` such that `h(S)=V(G)`.
354
+
355
+ INPUT:
356
+
357
+ - ``value_only`` -- boolean (default: ``True``); whether to return only
358
+ the hull number (default) or a minimum set whose convex hull is the
359
+ whole graph
360
+
361
+ - ``verbose`` -- boolean (default: ``False``); whether to display
362
+ information on the LP
363
+
364
+ **COMPLEXITY:**
365
+
366
+ This problem is NP-Hard [HLT1993]_, but seems to be of the "nice" kind.
367
+ Update this comment if you fall on hard instances `:-)`
368
+
369
+ **ALGORITHM:**
370
+
371
+ This is solved by linear programming.
372
+
373
+ As the function `h(S)` associating to each set `S` its convex hull is a
374
+ closure operator, it is clear that any set `S_G` of vertices such that
375
+ `h(S_G)=V(G)` must satisfy `S_G \not \subseteq C` for any *proper*
376
+ convex set `C \subsetneq V(G)`. The following formulation is hence
377
+ correct
378
+
379
+ .. MATH::
380
+
381
+ \text{Minimize :}& \sum_{v\in G}b_v\\
382
+ \text{Such that :}&\\
383
+ &\forall C\subsetneq V(G)\text{ a proper convex set }\\
384
+ &\sum_{v\in V(G)\backslash C} b_v \geq 1
385
+
386
+ Of course, the number of convex sets -- and so the number of constraints
387
+ -- can be huge, and hard to enumerate, so at first an incomplete
388
+ formulation is solved (it is missing some constraints). If the answer
389
+ returned by the LP solver is a set `S` generating the whole graph, then
390
+ it is optimal and so is returned. Otherwise, the constraint
391
+ corresponding to the set `h(S)` can be added to the LP, which makes the
392
+ answer `S` infeasible, and another solution computed.
393
+
394
+ This being said, simply adding the constraint corresponding to `h(S)` is
395
+ a bit slow, as these sets can be large (and the corresponding constraint
396
+ a bit weak). To improve it a bit, before being added, the set `h(S)` is
397
+ "greedily enriched" to a set `S'` with vertices for as long as
398
+ `h(S')\neq V(G)`. This way, we obtain a set `S'` with `h(S)\subseteq
399
+ h(S')\subsetneq V(G)`, and the constraint corresponding to `h(S')` --
400
+ which is stronger than the one corresponding to `h(S)` -- is added.
401
+
402
+ This can actually be seen as a hitting set problem on the complement of
403
+ convex sets.
404
+
405
+ EXAMPLES:
406
+
407
+ The Hull number of Petersen's graph::
408
+
409
+ sage: from sage.graphs.convexity_properties import ConvexityProperties
410
+ sage: g = graphs.PetersenGraph()
411
+ sage: CP = ConvexityProperties(g)
412
+ sage: CP.hull_number() # needs sage.numerical.mip
413
+ 3
414
+ sage: generating_set = CP.hull_number(value_only=False) # needs sage.numerical.mip
415
+ sage: CP.hull(generating_set) # needs sage.numerical.mip
416
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
417
+ """
418
+ cdef int i
419
+ cdef list constraint # temporary variable to add constraints to the LP
420
+
421
+ if self._n <= 2:
422
+ if value_only:
423
+ return self._n
424
+ else:
425
+ return self._list_integers_to_vertices
426
+
427
+ cdef GenericBackend p = <GenericBackend> get_solver(constraint_generation=True)
428
+
429
+ # Minimization
430
+ p.set_sense(False)
431
+
432
+ # We have exactly n binary variables, all of them with a coefficient of
433
+ # 1 in the objective function
434
+ p.add_variables(self._n, 0, None, True, False, False, 1, None)
435
+
436
+ # We know that at least 2 vertices are required to cover the whole graph
437
+ p.add_linear_constraint([(i, 1) for i in range(self._n)], 2, None)
438
+
439
+ # The set of vertices generated by the current LP solution
440
+ cdef bitset_t current_hull
441
+ bitset_init(current_hull, self._n)
442
+
443
+ # Which is at first empty
444
+ bitset_set_first_n(current_hull, 1)
445
+
446
+ while True:
447
+
448
+ # Greedily increase it to obtain a better constraint
449
+ self._greedy_increase(current_hull)
450
+
451
+ if verbose:
452
+ print("Adding a constraint corresponding to convex set ",
453
+ end="")
454
+ print(bitset_list(current_hull))
455
+
456
+ # Building the corresponding constraint
457
+ constraint = []
458
+ for i in range(self._n):
459
+ if not bitset_in(current_hull, i):
460
+ constraint.append((i, 1))
461
+
462
+ p.add_linear_constraint(constraint, 1, None)
463
+
464
+ p.solve()
465
+
466
+ # Computing the current solution's convex hull
467
+ bitset_set_first_n(current_hull, 0)
468
+
469
+ for i in range(self._n):
470
+ if p.get_variable_value(i) > .5:
471
+ bitset_add(current_hull, i)
472
+
473
+ self._bitset_convex_hull(current_hull)
474
+
475
+ # Are we done ?
476
+ if bitset_len(current_hull) == self._n:
477
+ break
478
+
479
+ bitset_free(current_hull)
480
+
481
+ if value_only:
482
+ return <int> p.get_objective_value()
483
+
484
+ constraint = []
485
+ for i in range(self._n):
486
+ if p.get_variable_value(i) > .5:
487
+ constraint.append(i)
488
+
489
+ return self._integers_to_vertices(constraint)
490
+
491
+
492
+ def geodetic_closure(G, S):
493
+ r"""
494
+ Return the geodetic closure of the set of vertices `S` in `G`.
495
+
496
+ The geodetic closure `g(S)` of a subset of vertices `S` of a graph `G` is in
497
+ [HLT1993]_ as the set of all vertices that lie on a shortest `u-v` path for
498
+ any pair of vertices `u,v \in S`. We assume that `g(\emptyset) = \emptyset`
499
+ and that `g(\{u\}) = \{u\}` for any `u` in `G`.
500
+
501
+ .. WARNING::
502
+
503
+ This operation is **not** a closure function. Indeed, a closure function
504
+ must satisfy the property that `f(f(X))` should be equal to `f(X)`,
505
+ which is not always the case here. The term ``closure`` is used here to
506
+ follow the terminology of the domain. See for instance [HLT1993]_.
507
+
508
+ Here, we implement a simple algorithm to determine this set. Roughly, for
509
+ each vertex `u \in S`, the algorithm first performs a breadth first search
510
+ from `u` to get distances, and then identifies the vertices of `G` lying on
511
+ a shortest path from `u` to any `v\in S` using a reversal traversal from
512
+ vertices in `S`. This algorithm has time complexity in `O(|S|(n + m))` for
513
+ ``SparseGraph``, `O(|S|(n + m) + n^2)` for ``DenseGraph`` and
514
+ space complexity in `O(n + m)`.
515
+
516
+ INPUT:
517
+
518
+ - ``G`` -- a Sage graph
519
+
520
+ - ``S`` -- a subset of vertices of `G`
521
+
522
+ EXAMPLES:
523
+
524
+ The vertices of the Petersen graph can be obtained by a geodetic closure of
525
+ four of its vertices::
526
+
527
+ sage: from sage.graphs.convexity_properties import geodetic_closure
528
+ sage: G = graphs.PetersenGraph()
529
+ sage: geodetic_closure(G, [0, 2, 8, 9])
530
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
531
+
532
+ The vertices of a 2D grid can be obtained by a geodetic closure of
533
+ two vertices::
534
+
535
+ sage: G = graphs.Grid2dGraph(4, 4)
536
+ sage: c = G.geodetic_closure([(0, 0), (3, 3)])
537
+ sage: len(c) == G.order()
538
+ True
539
+
540
+ If two vertices belong to different connected components of a graph, their
541
+ geodetic closure is trivial::
542
+
543
+ sage: G = Graph([(0, 1), (2, 3)])
544
+ sage: geodetic_closure(G, [0, 2])
545
+ [0, 2]
546
+
547
+ The geodetic closure does not satisfy the closure function property that
548
+ `f(f(X))` should be equal to `f(X)`::
549
+
550
+ sage: G = graphs.DiamondGraph()
551
+ sage: G.subdivide_edge((1, 2), 1)
552
+ sage: geodetic_closure(G, [0, 3])
553
+ [0, 1, 2, 3]
554
+ sage: geodetic_closure(G, geodetic_closure(G, [0, 3]))
555
+ [0, 1, 2, 3, 4]
556
+
557
+ TESTS::
558
+
559
+ sage: G = graphs.DiamondGraph()
560
+ sage: geodetic_closure(G, [])
561
+ []
562
+ sage: geodetic_closure(G, [1])
563
+ [1]
564
+ sage: S = geodetic_closure(G, list(G))
565
+ sage: all(u in G for u in S) and len(S) == G.order()
566
+ True
567
+ sage: S = geodetic_closure(G, G)
568
+ sage: all(u in G for u in S) and len(S) == G.order()
569
+ True
570
+ sage: geodetic_closure(G, [1, 'foo'])
571
+ Traceback (most recent call last):
572
+ ...
573
+ ValueError: S is not a subset of vertices of the graph
574
+ sage: geodetic_closure(digraphs.Path(3), [0, 1])
575
+ Traceback (most recent call last):
576
+ ...
577
+ NotImplementedError: the geodetic closure of digraphs has not been implemented yet
578
+
579
+ The method is valid for immutable graphs::
580
+
581
+ sage: G = graphs.RandomGNP(10, .7)
582
+ sage: G._backend
583
+ <sage.graphs.base.sparse_graph.SparseGraphBackend ...>
584
+ sage: H = Graph(G, immutable=True)
585
+ sage: H._backend
586
+ <sage.graphs.base.static_sparse_backend.StaticSparseBackend ...>
587
+ sage: geodetic_closure(G, [0, 3]) == geodetic_closure(H, [0, 3])
588
+ True
589
+ """
590
+ if G.is_directed():
591
+ raise NotImplementedError("the geodetic closure of digraphs has not been implemented yet")
592
+ S = list(S)
593
+ if not S:
594
+ return []
595
+ elif any(v not in G for v in S):
596
+ raise ValueError("S is not a subset of vertices of the graph")
597
+ elif len(S) == 1 or len(S) == G.order():
598
+ return S
599
+ elif not G.is_connected():
600
+ L = []
601
+ for g in G.connected_components_subgraphs():
602
+ Sg = [u for u in S if u in g]
603
+ L.extend(geodetic_closure(g, Sg))
604
+ return L
605
+
606
+ cdef int n = G.order()
607
+ cdef int nS = len(S)
608
+ cdef list int_to_vertex
609
+ cdef dict vertex_to_int
610
+
611
+ # Copy the graph as a short digraph
612
+ cdef StaticSparseCGraph cg
613
+ cdef short_digraph sd
614
+ if isinstance(G, StaticSparseBackend):
615
+ cg = <StaticSparseCGraph> G._cg
616
+ sd = <short_digraph> cg.g
617
+ int_to_vertex = cg._vertex_to_labels
618
+ vertex_to_int = cg._vertex_to_int
619
+ else:
620
+ int_to_vertex = list(G)
621
+ vertex_to_int = {u: i for i, u in enumerate(int_to_vertex)}
622
+ init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex)
623
+
624
+ cdef list S_int = [vertex_to_int[u] for u in S]
625
+
626
+ # Allocate some data structures
627
+ cdef MemoryAllocator mem = MemoryAllocator()
628
+ cdef uint32_t * distances = <uint32_t *> mem.malloc(n * sizeof(uint32_t))
629
+ cdef uint32_t * waiting_list = <uint32_t *> mem.malloc(n * sizeof(uint32_t))
630
+ if not distances or not waiting_list:
631
+ free_short_digraph(sd)
632
+ raise MemoryError()
633
+ cdef bitset_t seen
634
+ cdef bitset_t visited
635
+ cdef bitset_t closure
636
+ bitset_init(seen, n)
637
+ bitset_init(visited, n)
638
+ bitset_init(closure, n)
639
+
640
+ cdef int ui, vi, xi, yi, i_begin, i_end, i, j, k
641
+
642
+ # Vertices in S are in the closure
643
+ bitset_clear(closure)
644
+ for ui in S_int:
645
+ bitset_add(closure, ui)
646
+
647
+ # We now explore geodesics between vertices in S, and we avoid visiting
648
+ # twice the geodesics between u and v
649
+ for i in range(nS - 1):
650
+ ui = S_int[i]
651
+
652
+ # Compute distances from ui using BFS
653
+ _ = simple_BFS(sd, ui, distances, NULL, waiting_list, seen)
654
+
655
+ # Perform a reverse BFS from vertices in S, following only vertices
656
+ # along a shortest path from ui to identify vertices of the geodetic
657
+ # closure.
658
+ bitset_clear(visited)
659
+ i_begin = 0
660
+ i_end = 0
661
+ for j in range(i + 1, nS):
662
+ vi = S_int[j]
663
+ if not bitset_in(seen, vi) or bitset_in(visited, vi):
664
+ # vi is not reachable from ui using BFS or has already been
665
+ # considered for the geodetic closure from ui
666
+ continue
667
+
668
+ # We explore all vertices on a shortest path from ui to vi
669
+ waiting_list[i_end] = vi
670
+ i_end += 1
671
+ bitset_add(visited, vi)
672
+
673
+ while i_begin < i_end:
674
+ xi = waiting_list[i_begin]
675
+ i_begin += 1
676
+
677
+ for k in range(out_degree(sd, xi)):
678
+ yi = sd.neighbors[xi][k]
679
+ if distances[xi] == distances[yi] + 1:
680
+ # yi in on a shortest path to ui
681
+ if not bitset_in(visited, yi):
682
+ waiting_list[i_end] = yi
683
+ i_end += 1
684
+ bitset_add(visited, yi)
685
+
686
+ # Now, visited contains all vertices on geodesics from ui to any other
687
+ # vertex in S
688
+ bitset_union(closure, closure, visited)
689
+
690
+ cdef list ret = [int_to_vertex[ui] for ui in range(n) if bitset_in(closure, ui)]
691
+
692
+ bitset_free(seen)
693
+ bitset_free(visited)
694
+ bitset_free(closure)
695
+ if not isinstance(G, StaticSparseBackend):
696
+ free_short_digraph(sd)
697
+
698
+ return ret
699
+
700
+
701
+ def is_geodetic(G):
702
+ r"""
703
+ Check whether the input (di)graph is geodetic.
704
+
705
+ A graph `G` is *geodetic* if there exists only one shortest path between
706
+ every pair of its vertices. This can be checked in time `O(nm)` for
707
+ ``SparseGraph`` and `O(nm+n^2)` for ``DenseGraph`` in unweighted (di)graphs
708
+ with `n` nodes and `m` edges. Examples of geodetic graphs are trees, cliques
709
+ and odd cycles. See the :wikipedia:`Geodetic_graph` for more details.
710
+
711
+ (Di)graphs with multiple edges are not considered geodetic.
712
+
713
+ INPUT:
714
+
715
+ - ``G`` -- a graph or a digraph
716
+
717
+ EXAMPLES:
718
+
719
+ Trees, cliques and odd cycles are geodetic::
720
+
721
+ sage: T = graphs.RandomTree(20)
722
+ sage: T.is_geodetic()
723
+ True
724
+ sage: all(graphs.CompleteGraph(n).is_geodetic() for n in range(8))
725
+ True
726
+ sage: all(graphs.CycleGraph(n).is_geodetic() for n in range(3, 16, 2))
727
+ True
728
+
729
+ Even cycles of order at least 4 are not geodetic::
730
+
731
+ sage: all(graphs.CycleGraph(n).is_geodetic() for n in range(4, 17, 2))
732
+ False
733
+
734
+ The Petersen graph is geodetic::
735
+
736
+ sage: P = graphs.PetersenGraph()
737
+ sage: P.is_geodetic()
738
+ True
739
+
740
+ Grid graphs are not geodetic::
741
+
742
+ sage: G = graphs.Grid2dGraph(2, 3)
743
+ sage: G.is_geodetic()
744
+ False
745
+
746
+ This method is also valid for digraphs::
747
+
748
+ sage: G = DiGraph(graphs.PetersenGraph())
749
+ sage: G.is_geodetic()
750
+ True
751
+ sage: G = digraphs.Path(5)
752
+ sage: G.add_path([0, 'a', 'b', 'c', 4])
753
+ sage: G.is_geodetic()
754
+ False
755
+
756
+ TESTS::
757
+
758
+ sage: all(g.is_geodetic() for g in graphs(3)) # needs nauty
759
+ True
760
+ sage: all((2*g).is_geodetic() for g in graphs(3)) # needs nauty
761
+ True
762
+ sage: G = graphs.CycleGraph(5)
763
+ sage: G.allow_loops(True)
764
+ sage: G.add_edges([(u, u) for u in G])
765
+ sage: G.is_geodetic()
766
+ True
767
+ sage: G.allow_multiple_edges(True)
768
+ sage: G.is_geodetic()
769
+ True
770
+ sage: G.add_edge(G.random_edge())
771
+ sage: G.is_geodetic()
772
+ False
773
+
774
+ The method is valid for immutable graphs::
775
+
776
+ sage: G = graphs.RandomGNP(10, .7)
777
+ sage: G._backend
778
+ <sage.graphs.base.sparse_graph.SparseGraphBackend ...>
779
+ sage: H = Graph(G, immutable=True)
780
+ sage: H._backend
781
+ <sage.graphs.base.static_sparse_backend.StaticSparseBackend ...>
782
+ sage: G.is_geodetic() == H.is_geodetic()
783
+ True
784
+ """
785
+ if G.has_multiple_edges():
786
+ return False
787
+
788
+ if G.order() < 4:
789
+ return True
790
+
791
+ # Copy the graph as a short digraph
792
+ cdef int n = G.order()
793
+ cdef StaticSparseCGraph cg
794
+ cdef short_digraph sd
795
+ if isinstance(G, StaticSparseBackend):
796
+ cg = <StaticSparseCGraph> G._cg
797
+ sd = <short_digraph> cg.g
798
+ else:
799
+ init_short_digraph(sd, G, edge_labelled=False, vertex_list=list(G))
800
+
801
+ # Allocate some data structures
802
+ cdef MemoryAllocator mem = MemoryAllocator()
803
+ cdef uint32_t * distances = <uint32_t *> mem.malloc(n * sizeof(uint32_t))
804
+ cdef uint32_t * waiting_list = <uint32_t *> mem.malloc(n * sizeof(uint32_t))
805
+ if not distances or not waiting_list:
806
+ if not isinstance(G, StaticSparseBackend):
807
+ free_short_digraph(sd)
808
+ raise MemoryError()
809
+ cdef bitset_t seen
810
+ bitset_init(seen, n)
811
+
812
+ # We now explore geodesics between vertices in S, and we avoid visiting
813
+ # twice the geodesics between u and v
814
+
815
+ cdef uint32_t source, u, v
816
+ cdef uint32_t waiting_beginning
817
+ cdef uint32_t waiting_end
818
+ cdef uint32_t * p_tmp
819
+ cdef uint32_t * end
820
+ cdef uint32_t ** p_vertices = sd.neighbors
821
+
822
+ for source in range(n):
823
+
824
+ # Compute distances from source using BFS
825
+ bitset_clear(seen)
826
+ bitset_add(seen, source)
827
+ distances[source] = 0
828
+ waiting_beginning = 0
829
+ waiting_end = 0
830
+ waiting_list[waiting_beginning] = source
831
+
832
+ # For as long as there are vertices left to explore
833
+ while waiting_beginning <= waiting_end:
834
+
835
+ # We pick the first one
836
+ v = waiting_list[waiting_beginning]
837
+ p_tmp = p_vertices[v]
838
+ end = p_vertices[v + 1]
839
+
840
+ # and we iterate over all the outneighbors u of v
841
+ while p_tmp < end:
842
+ u = p_tmp[0]
843
+
844
+ # If we notice one of these neighbors is not seen yet, we set
845
+ # its parameters and add it to the queue to be explored later.
846
+ # Otherwise, we check whether we have detected a second shortest
847
+ # path between source and v.
848
+ if not bitset_in(seen, u):
849
+ distances[u] = distances[v] + 1
850
+ bitset_add(seen, u)
851
+ waiting_end += 1
852
+ waiting_list[waiting_end] = u
853
+ elif distances[u] == distances[v] + 1:
854
+ # G is not geodetic
855
+ bitset_free(seen)
856
+ if not isinstance(G, StaticSparseBackend):
857
+ free_short_digraph(sd)
858
+ return False
859
+
860
+ p_tmp += 1
861
+
862
+ # We go to the next vertex in the queue
863
+ waiting_beginning += 1
864
+
865
+ bitset_free(seen)
866
+ if not isinstance(G, StaticSparseBackend):
867
+ free_short_digraph(sd)
868
+
869
+ # The graph is geodetic
870
+ return True