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,1993 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ r"""
3
+ Common digraphs
4
+
5
+ All digraphs in Sage can be built through the ``digraphs`` object. In order to
6
+ build a circuit on 15 elements, one can do::
7
+
8
+ sage: g = digraphs.Circuit(15)
9
+
10
+ To get a circulant graph on 10 vertices in which a vertex `i` has `i+2` and
11
+ `i+3` as outneighbors::
12
+
13
+ sage: p = digraphs.Circulant(10,[2,3])
14
+
15
+ More interestingly, one can get the list of all digraphs that Sage knows how to
16
+ build by typing ``digraphs.`` in Sage and then hitting :kbd:`Tab`.
17
+
18
+ .. csv-table::
19
+ :class: contentstable
20
+ :widths: 30, 70
21
+ :delim: |
22
+
23
+ :meth:`~DiGraphGenerators.ButterflyGraph` | Return a `n`-dimensional butterfly graph.
24
+ :meth:`~DiGraphGenerators.Circuit` | Return the circuit on `n` vertices.
25
+ :meth:`~DiGraphGenerators.Circulant` | Return a circulant digraph on `n` vertices from a set of integers.
26
+ :meth:`~DiGraphGenerators.Complete` | Return a complete digraph on `n` vertices.
27
+ :meth:`~DiGraphGenerators.DeBruijn` | Return the De Bruijn digraph with parameters `k,n`.
28
+ :meth:`~DiGraphGenerators.GeneralizedDeBruijn` | Return the generalized de Bruijn digraph of order `n` and degree `d`.
29
+ :meth:`~DiGraphGenerators.ImaseItoh` | Return the digraph of Imase and Itoh of order `n` and degree `d`.
30
+ :meth:`~DiGraphGenerators.Kautz` | Return the Kautz digraph of degree `d` and diameter `D`.
31
+ :meth:`~DiGraphGenerators.nauty_directg` | Return an iterator yielding digraphs using nauty's ``directg`` program.
32
+ :meth:`~DiGraphGenerators.nauty_posetg` | Return an iterator yielding Hasse diagrams of posets using nauty's ``genposetg`` program.
33
+ :meth:`~DiGraphGenerators.Paley` | Return a Paley digraph on `q` vertices.
34
+ :meth:`~DiGraphGenerators.Path` | Return a directed path on `n` vertices.
35
+ :meth:`~DiGraphGenerators.RandomDirectedAcyclicGraph` | Return a random (weighted) directed acyclic graph of order `n`.
36
+ :meth:`~DiGraphGenerators.RandomDirectedGNC` | Return a random growing network with copying (GNC) digraph with `n` vertices.
37
+ :meth:`~DiGraphGenerators.RandomDirectedGNM` | Return a random labelled digraph on `n` nodes and `m` arcs.
38
+ :meth:`~DiGraphGenerators.RandomDirectedGNP` | Return a random digraph on `n` nodes.
39
+ :meth:`~DiGraphGenerators.RandomDirectedGN` | Return a random growing network (GN) digraph with `n` vertices.
40
+ :meth:`~DiGraphGenerators.RandomDirectedGNR` | Return a random growing network with redirection (GNR) digraph.
41
+ :meth:`~DiGraphGenerators.RandomSemiComplete` | Return a random semi-complete digraph of order `n`.
42
+ :meth:`~DiGraphGenerators.RandomTournament` | Return a random tournament on `n` vertices.
43
+ :meth:`~DiGraphGenerators.TransitiveTournament`| Return a transitive tournament on `n` vertices.
44
+ :meth:`~DiGraphGenerators.tournaments_nauty` | Iterator over all tournaments on `n` vertices using Nauty.
45
+
46
+
47
+ AUTHORS:
48
+
49
+ - Robert L. Miller (2006)
50
+ - Emily A. Kirkman (2006)
51
+ - Michael C. Yurko (2009)
52
+ - David Coudert (2012)
53
+ - Janmenjaya Panda (2024)
54
+
55
+ Functions and methods
56
+ ---------------------
57
+ """
58
+ # ****************************************************************************
59
+ # Copyright (C) 2006 Robert L. Miller <rlmillster@gmail.com>
60
+ # and Emily A. Kirkman
61
+ # Copyright (C) 2009 Michael C. Yurko <myurko@gmail.com>
62
+ # Copyright (C) 2012 David Coudert <david.coudert@inria.fr>
63
+ # Copyright (C) 2024 Janmenjaya Panda <janmenjaya.panda.22@gmail.com>
64
+ #
65
+ # This program is free software: you can redistribute it and/or modify
66
+ # it under the terms of the GNU General Public License as published by
67
+ # the Free Software Foundation, either version 2 of the License, or
68
+ # (at your option) any later version.
69
+ # https://www.gnu.org/licenses/
70
+ # ****************************************************************************
71
+ import sys
72
+ import subprocess
73
+
74
+ from sage.cpython.string import bytes_to_str
75
+ from sage.misc.randstate import current_randstate
76
+ from sage.graphs.digraph import DiGraph
77
+ from sage.graphs.graph import Graph
78
+
79
+
80
+ class DiGraphGenerators:
81
+ r"""
82
+ A class consisting of constructors for several common digraphs,
83
+ including orderly generation of isomorphism class representatives.
84
+
85
+ A list of all graphs and graph structures in this database is available via
86
+ tab completion. Type ``digraphs.`` and then hit :kbd:`Tab` to see which
87
+ digraphs are available.
88
+
89
+ The docstrings include educational information about each named
90
+ digraph with the hopes that this class can be used as a reference.
91
+
92
+ The constructors currently in this class include::
93
+
94
+ Random Directed Graphs:
95
+ - RandomDirectedAcyclicGraph
96
+ - RandomDirectedGN
97
+ - RandomDirectedGNC
98
+ - RandomDirectedGNP
99
+ - RandomDirectedGNM
100
+ - RandomDirectedGNR
101
+ - RandomTournament
102
+ - RandomSemiComplete
103
+
104
+ Families of Graphs:
105
+ - Complete
106
+ - DeBruijn
107
+ - GeneralizedDeBruijn
108
+ - Kautz
109
+ - Path
110
+ - ImaseItoh
111
+ - RandomTournament
112
+ - TransitiveTournament
113
+ - tournaments_nauty
114
+
115
+
116
+ ORDERLY GENERATION: digraphs(vertices, property=lambda x: True,
117
+ augment='edges', size=None)
118
+
119
+ Accesses the generator of isomorphism class representatives [McK1998]_.
120
+ Iterates over distinct, exhaustive representatives.
121
+
122
+ INPUT:
123
+
124
+ - ``vertices`` -- natural number or ``None`` to infinitely generate bigger
125
+ and bigger digraphs
126
+
127
+ - ``property`` -- any property to be tested on digraphs before generation
128
+
129
+ - ``augment`` -- choices:
130
+
131
+ - ``'vertices'`` -- augments by adding a vertex, and edges incident to
132
+ that vertex. In this case, all digraphs on *up to* n=vertices are
133
+ generated. If for any digraph G satisfying the property, every subgraph,
134
+ obtained from G by deleting one vertex and only edges incident to that
135
+ vertex, satisfies the property, then this will generate all digraphs
136
+ with that property. If this does not hold, then all the digraphs
137
+ generated will satisfy the property, but there will be some missing.
138
+
139
+ - ``'edges'`` -- augments a fixed number of vertices by adding one
140
+ edge. In this case, all digraphs on *exactly* n=vertices are
141
+ generated. If for any graph G satisfying the property, every subgraph,
142
+ obtained from G by deleting one edge but not the vertices incident to
143
+ that edge, satisfies the property, then this will generate all digraphs
144
+ with that property. If this does not hold, then all the digraphs
145
+ generated will satisfy the property, but there will be some missing.
146
+
147
+ - ``implementation`` -- which underlying implementation to use
148
+ (see DiGraph?)
149
+
150
+ - ``sparse`` -- boolean (default: ``True``); whether to use a sparse or
151
+ dense data structure. See the documentation of
152
+ :class:`~sage.graphs.graph.Graph`.
153
+
154
+ - ``copy`` -- boolean (default: ``True``); whether to make copies of the
155
+ digraphs before returning them. If set to ``False`` the method returns the
156
+ digraph it is working on. The second alternative is faster, but modifying
157
+ any of the digraph instances returned by the method may break the
158
+ function's behaviour, as it is using these digraphs to compute the next
159
+ ones: only use ``copy = False`` when you stick to *reading* the digraphs
160
+ returned.
161
+
162
+ This parameter is ignored when ``immutable`` is set to ``True``, in which
163
+ case returned graphs are always copies.
164
+
165
+ - ``immutable`` -- boolean (default: ``False``); whether to return immutable
166
+ or mutable digraphs. When set to ``True``, this parameter implies
167
+ ``copy=True``.
168
+
169
+ EXAMPLES:
170
+
171
+ Print digraphs on 2 or less vertices::
172
+
173
+ sage: for D in digraphs(2, augment='vertices'):
174
+ ....: print(D)
175
+ Digraph on 0 vertices
176
+ Digraph on 1 vertex
177
+ Digraph on 2 vertices
178
+ Digraph on 2 vertices
179
+ Digraph on 2 vertices
180
+
181
+ Print digraphs on 3 vertices::
182
+
183
+ sage: for D in digraphs(3):
184
+ ....: print(D)
185
+ Digraph on 3 vertices
186
+ Digraph on 3 vertices
187
+ ...
188
+ Digraph on 3 vertices
189
+ Digraph on 3 vertices
190
+
191
+ Generate all digraphs with 4 vertices and 3 edges::
192
+
193
+ sage: L = digraphs(4, size=3)
194
+ sage: len(list(L))
195
+ 13
196
+
197
+ Generate all digraphs with 4 vertices and up to 3 edges::
198
+
199
+ sage: L = list(digraphs(4, lambda G: G.size() <= 3))
200
+ sage: len(L)
201
+ 20
202
+ sage: graphs_list.show_graphs(L) # long time # needs sage.plot
203
+
204
+ Generate all digraphs with degree at most 2, up to 5 vertices::
205
+
206
+ sage: property = lambda G: (max([G.degree(v) for v in G] + [0]) <= 2)
207
+ sage: L = list(digraphs(5, property, augment='vertices'))
208
+ sage: len(L)
209
+ 75
210
+
211
+ Generate digraphs on the fly (see http://oeis.org/classic/A000273)::
212
+
213
+ sage: for i in range(5):
214
+ ....: print(len(list(digraphs(i))))
215
+ 1
216
+ 1
217
+ 3
218
+ 16
219
+ 218
220
+ """
221
+
222
+ def ButterflyGraph(self, n, vertices='strings', immutable=False):
223
+ r"""
224
+ Return a `n`-dimensional butterfly graph.
225
+
226
+ The vertices consist of pairs `(v, i)`, where `v` is an `n`-dimensional
227
+ tuple (vector) with binary entries (or a string representation of such)
228
+ and `i` is an integer in `[0..n]`. A directed edge goes from `(v, i)` to
229
+ `(w, i + 1)` if `v` and `w` are identical except for possibly when `v[i]
230
+ \neq w[i]`.
231
+
232
+ A butterfly graph has `(2^n)(n+1)` vertices and `n2^{n+1}` edges.
233
+
234
+ INPUT:
235
+
236
+ - ``n`` -- nonnegative integer; the dimension of the butterfly graph
237
+
238
+ - ``vertices`` -- string (default: ``'strings'``); specifies whether the
239
+ vertices are zero-one strings (default) or tuples over GF(2)
240
+ (``vertices='vectors'``)
241
+
242
+ - ``immutable`` -- boolean (default: ``False``); whether to return
243
+ an immutable or mutable digraph
244
+
245
+ EXAMPLES::
246
+
247
+ sage: digraphs.ButterflyGraph(2).edges(sort=True, labels=False)
248
+ [(('00', 0), ('00', 1)),
249
+ (('00', 0), ('10', 1)),
250
+ (('00', 1), ('00', 2)),
251
+ (('00', 1), ('01', 2)),
252
+ (('01', 0), ('01', 1)),
253
+ (('01', 0), ('11', 1)),
254
+ (('01', 1), ('00', 2)),
255
+ (('01', 1), ('01', 2)),
256
+ (('10', 0), ('00', 1)),
257
+ (('10', 0), ('10', 1)),
258
+ (('10', 1), ('10', 2)),
259
+ (('10', 1), ('11', 2)),
260
+ (('11', 0), ('01', 1)),
261
+ (('11', 0), ('11', 1)),
262
+ (('11', 1), ('10', 2)),
263
+ (('11', 1), ('11', 2))]
264
+ sage: digraphs.ButterflyGraph(2, vertices='vectors').edges(sort=True, # needs sage.modules sage.rings.finite_rings
265
+ ....: labels=False)
266
+ [(((0, 0), 0), ((0, 0), 1)),
267
+ (((0, 0), 0), ((1, 0), 1)),
268
+ (((0, 0), 1), ((0, 0), 2)),
269
+ (((0, 0), 1), ((0, 1), 2)),
270
+ (((0, 1), 0), ((0, 1), 1)),
271
+ (((0, 1), 0), ((1, 1), 1)),
272
+ (((0, 1), 1), ((0, 0), 2)),
273
+ (((0, 1), 1), ((0, 1), 2)),
274
+ (((1, 0), 0), ((0, 0), 1)),
275
+ (((1, 0), 0), ((1, 0), 1)),
276
+ (((1, 0), 1), ((1, 0), 2)),
277
+ (((1, 0), 1), ((1, 1), 2)),
278
+ (((1, 1), 0), ((0, 1), 1)),
279
+ (((1, 1), 0), ((1, 1), 1)),
280
+ (((1, 1), 1), ((1, 0), 2)),
281
+ (((1, 1), 1), ((1, 1), 2))]
282
+ sage: pos = digraphs.ButterflyGraph(2).get_pos()
283
+ sage: pos['11', 0]
284
+ (0, 0)
285
+
286
+ TESTS::
287
+
288
+ sage: digraphs.ButterflyGraph(0)
289
+ 0-dimensional Butterfly: Digraph on 0 vertices
290
+ sage: digraphs.ButterflyGraph(-1)
291
+ Traceback (most recent call last):
292
+ ...
293
+ ValueError: the number of dimensions must be positive
294
+ """
295
+ if n == 0:
296
+ return DiGraph(name="0-dimensional Butterfly")
297
+ if n < 0:
298
+ raise ValueError("the number of dimensions must be positive")
299
+
300
+ # We could switch to Sage integers to handle arbitrary n.
301
+ if vertices == 'strings':
302
+ if n >= 31:
303
+ raise NotImplementedError("vertices='strings' is only valid for n <= 30")
304
+ from sage.graphs.generic_graph_pyx import int_to_binary_string
305
+ V = []
306
+ E = []
307
+ for v in range(2 ** n):
308
+ bv = int_to_binary_string(v)
309
+ # pad and reverse the string
310
+ padded_bv = ('0' * (n - len(bv)) + bv)[::-1]
311
+ V.append(padded_bv)
312
+ for i in range(n):
313
+ w = v
314
+ w ^= (1 << i) # push 1 to the left by i and xor with w
315
+ bw = int_to_binary_string(w)
316
+ padded_bw = ('0' * (n - len(bw)) + bw)[::-1]
317
+ E.append(((padded_bv, i), (padded_bv, i + 1)))
318
+ E.append(((padded_bv, i), (padded_bw, i + 1)))
319
+ elif vertices == 'vectors':
320
+ from sage.modules.free_module import VectorSpace
321
+ from sage.rings.finite_rings.finite_field_constructor import FiniteField
322
+ from copy import copy
323
+ V = []
324
+ E = []
325
+ for v in VectorSpace(FiniteField(2), n):
326
+ # We must call tuple since vectors are mutable. To obtain a
327
+ # vector from the tuple tv, just call vector(tv).
328
+ tv = tuple(v)
329
+ V.append(tv)
330
+ w = copy(v)
331
+ for i in range(n):
332
+ w[i] += 1 # Flip the ith bit
333
+ E.append(((tv, i), (tv, i + 1)))
334
+ E.append(((tv, i), (tuple(w), i + 1)))
335
+ w[i] += 1 # Flip the ith bit back
336
+ else:
337
+ raise NotImplementedError("vertices must be 'strings' or 'vectors'")
338
+ # Set position of vertices
339
+ pos = dict()
340
+ dec = 2**n // n
341
+ for i, v in enumerate(sorted(V, reverse=True)):
342
+ for x in range(n + 1):
343
+ pos[v, x] = (dec * x, i)
344
+ return DiGraph([pos.keys(), E], format='vertices_and_edges', pos=pos,
345
+ name="{}-dimensional Butterfly".format(n),
346
+ immutable=immutable)
347
+
348
+ def Path(self, n, immutable=False):
349
+ r"""
350
+ Return a directed path on `n` vertices.
351
+
352
+ INPUT:
353
+
354
+ - ``n`` -- integer; number of vertices in the path
355
+
356
+ - ``immutable`` -- boolean (default: ``False``); whether to return
357
+ an immutable or mutable digraph
358
+
359
+ EXAMPLES::
360
+
361
+ sage: g = digraphs.Path(5)
362
+ sage: g.vertices(sort=True)
363
+ [0, 1, 2, 3, 4]
364
+ sage: g.size()
365
+ 4
366
+ sage: g.automorphism_group().cardinality() # needs sage.groups
367
+ 1
368
+ """
369
+ g = DiGraph([range(n), zip(range(n - 1), range(1, n))],
370
+ format='vertices_and_edges', name='Path',
371
+ immutable=immutable)
372
+ g.set_pos({i: (i, 0) for i in range(n)})
373
+ return g
374
+
375
+ def StronglyRegular(self, n, immutable=False):
376
+ r"""
377
+ Return a Strongly Regular digraph with `n` vertices.
378
+
379
+ The adjacency matrix of the graph is constructed from a skew Hadamard
380
+ matrix of order `n+1`. These graphs were first constructed in [Duv1988]_.
381
+
382
+ INPUT:
383
+
384
+ - ``n`` -- integer; the number of vertices of the digraph
385
+
386
+ - ``immutable`` -- boolean (default: ``False``); whether to return
387
+ an immutable or mutable digraph
388
+
389
+ .. SEEALSO::
390
+
391
+ - :func:`sage.combinat.matrices.hadamard_matrix.skew_hadamard_matrix`
392
+ - :meth:`Paley`
393
+
394
+ EXAMPLES:
395
+
396
+ A Strongly Regular digraph satisfies the condition `AJ = JA = kJ` where
397
+ `A` is the adjacency matrix::
398
+
399
+ sage: # needs sage.combinat sage.modules
400
+ sage: g = digraphs.StronglyRegular(7); g
401
+ Strongly regular digraph: Digraph on 7 vertices
402
+ sage: A = g.adjacency_matrix()*ones_matrix(7)
403
+ sage: B = ones_matrix(7)*g.adjacency_matrix()
404
+ sage: A == B == A[0, 0]*ones_matrix(7)
405
+ True
406
+
407
+ TESTS:
408
+
409
+ Wrong parameter::
410
+
411
+ sage: digraphs.StronglyRegular(73) # needs sage.combinat sage.modules
412
+ Traceback (most recent call last):
413
+ ...
414
+ ValueError: strongly regular digraph with 73 vertices not yet implemented
415
+ """
416
+ from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix
417
+ from sage.matrix.constructor import ones_matrix, identity_matrix
418
+ if skew_hadamard_matrix(n + 1, existence=True) is not True:
419
+ raise ValueError(f'strongly regular digraph with {n} vertices not yet implemented')
420
+
421
+ H = skew_hadamard_matrix(n + 1, skew_normalize=True)
422
+ M = H[1:, 1:]
423
+ M = (M + ones_matrix(n)) / 2 - identity_matrix(n)
424
+ return DiGraph(M, format='adjacency_matrix', immutable=immutable,
425
+ name='Strongly regular digraph')
426
+
427
+ def Paley(self, q, immutable=False):
428
+ r"""
429
+ Return a Paley digraph on `q` vertices.
430
+
431
+ Parameter `q` must be the power of a prime number and congruent to 3 mod
432
+ 4.
433
+
434
+ INPUT:
435
+
436
+ - ``q`` -- integer; the number of vertices of the digraph
437
+
438
+ - ``immutable`` -- boolean (default: ``False``); whether to return
439
+ an immutable or mutable digraph
440
+
441
+ .. SEEALSO::
442
+
443
+ - :wikipedia:`Paley_graph`
444
+ - :meth:`~sage.graphs.graph_generators.GraphGenerators.PaleyGraph`
445
+
446
+ EXAMPLES:
447
+
448
+ A Paley digraph has `n * (n-1) / 2` edges, its underlying graph is a
449
+ clique, and so it is a tournament::
450
+
451
+ sage: g = digraphs.Paley(7); g # needs sage.rings.finite_rings
452
+ Paley digraph with parameter 7: Digraph on 7 vertices
453
+ sage: g.size() == g.order() * (g.order() - 1) / 2 # needs sage.rings.finite_rings
454
+ True
455
+ sage: g.to_undirected().is_clique() # needs sage.rings.finite_rings
456
+ True
457
+
458
+ A Paley digraph is always self-complementary::
459
+
460
+ sage: g.complement().is_isomorphic(g) # needs sage.rings.finite_rings
461
+ True
462
+
463
+ TESTS:
464
+
465
+ Wrong parameter::
466
+
467
+ sage: digraphs.Paley(6)
468
+ Traceback (most recent call last):
469
+ ...
470
+ ValueError: parameter q must be a prime power
471
+ sage: digraphs.Paley(5)
472
+ Traceback (most recent call last):
473
+ ...
474
+ ValueError: parameter q must be congruent to 3 mod 4
475
+ """
476
+ from sage.rings.finite_rings.integer_mod import mod
477
+ from sage.rings.finite_rings.finite_field_constructor import FiniteField
478
+ from sage.arith.misc import is_prime_power
479
+ if not is_prime_power(q):
480
+ raise ValueError("parameter q must be a prime power")
481
+ if not mod(q, 4) == 3:
482
+ raise ValueError("parameter q must be congruent to 3 mod 4")
483
+ return DiGraph([FiniteField(q, 'a'),
484
+ lambda i, j: (i != j) and (j - i).is_square()],
485
+ format='rule', loops=False, immutable=immutable,
486
+ name="Paley digraph with parameter {}".format(q))
487
+
488
+ def TransitiveTournament(self, n, immutable=False):
489
+ r"""
490
+ Return a transitive tournament on `n` vertices.
491
+
492
+ In this tournament there is an edge from `i` to `j` if `i<j`.
493
+
494
+ See the :wikipedia:`Tournament_(graph_theory)` for more information.
495
+
496
+ INPUT:
497
+
498
+ - ``n`` -- integer; number of vertices in the tournament
499
+
500
+ - ``immutable`` -- boolean (default: ``False``); whether to return
501
+ an immutable or mutable digraph
502
+
503
+ EXAMPLES::
504
+
505
+ sage: g = digraphs.TransitiveTournament(5)
506
+ sage: g.vertices(sort=True)
507
+ [0, 1, 2, 3, 4]
508
+ sage: g.size()
509
+ 10
510
+ sage: g.automorphism_group().cardinality() # needs sage.groups
511
+ 1
512
+
513
+ .. SEEALSO::
514
+
515
+ - :wikipedia:`Tournament_(graph_theory)`
516
+ - :meth:`~sage.graphs.digraph.DiGraph.is_tournament`
517
+ - :meth:`~sage.graphs.digraph.DiGraph.is_transitive`
518
+ - :meth:`~sage.graphs.digraph_generators.DiGraphGenerators.RandomTournament`
519
+
520
+ TESTS::
521
+
522
+ sage: digraphs.TransitiveTournament(-1)
523
+ Traceback (most recent call last):
524
+ ...
525
+ ValueError: the number of vertices cannot be strictly negative
526
+ """
527
+ if n < 0:
528
+ raise ValueError('the number of vertices cannot be strictly negative')
529
+
530
+ from itertools import combinations
531
+ g = DiGraph([range(n), combinations(range(n), 2)],
532
+ format='vertices_and_edges', immutable=immutable,
533
+ name="Transitive Tournament")
534
+ g._circle_embedding(list(range(n)))
535
+ return g
536
+
537
+ def RandomTournament(self, n, immutable=False):
538
+ r"""
539
+ Return a random tournament on `n` vertices.
540
+
541
+ For every pair of vertices, the tournament has an edge from
542
+ `i` to `j` with probability `1/2`, otherwise it has an edge
543
+ from `j` to `i`.
544
+
545
+ INPUT:
546
+
547
+ - ``n`` -- integer; number of vertices
548
+
549
+ - ``immutable`` -- boolean (default: ``False``); whether to return
550
+ an immutable or mutable digraph
551
+
552
+ EXAMPLES::
553
+
554
+ sage: T = digraphs.RandomTournament(10); T
555
+ Random Tournament: Digraph on 10 vertices
556
+ sage: T.size() == binomial(10, 2) # needs sage.symbolic
557
+ True
558
+ sage: T.is_tournament()
559
+ True
560
+ sage: digraphs.RandomTournament(-1)
561
+ Traceback (most recent call last):
562
+ ...
563
+ ValueError: the number of vertices cannot be strictly negative
564
+
565
+ .. SEEALSO::
566
+
567
+ - :wikipedia:`Tournament_(graph_theory)`
568
+ - :meth:`~sage.graphs.digraph.DiGraph.is_tournament`
569
+ - :meth:`~sage.graphs.digraph_generators.DiGraphGenerators.TransitiveTournament`
570
+ - :meth:`~sage.graphs.digraph_generators.DiGraphGenerators.Complete`
571
+ - :meth:`~sage.graphs.digraph_generators.DiGraphGenerators.RandomSemiComplete`
572
+ """
573
+ if n < 0:
574
+ raise ValueError('the number of vertices cannot be strictly negative')
575
+
576
+ from itertools import combinations
577
+ from sage.misc.prandom import getrandbits
578
+
579
+ bits = getrandbits(n * (n - 1) // 2)
580
+ edges = ((i, j) if (bits >> k) & 1 else (j, i)
581
+ for k, (i, j) in enumerate(combinations(range(n), 2)))
582
+ g = DiGraph([range(n), edges], format='vertices_and_edges',
583
+ immutable=immutable, name="Random Tournament")
584
+
585
+ g._circle_embedding(list(range(n)))
586
+
587
+ return g
588
+
589
+ def tournaments_nauty(self, n,
590
+ min_out_degree=None, max_out_degree=None,
591
+ strongly_connected=False, debug=False, options="",
592
+ immutable=False):
593
+ r"""
594
+ Iterator over all tournaments on `n` vertices using Nauty.
595
+
596
+ INPUT:
597
+
598
+ - ``n`` -- integer; number of vertices
599
+
600
+ - ``min_out_degree``, ``max_out_degree`` -- integers; if set to
601
+ ``None`` (default), then the min/max out-degree is not constrained
602
+
603
+ - ``debug`` -- boolean (default: ``False``); if ``True`` the first line
604
+ of gentourng's output to standard error is captured and the first call
605
+ to the generator's ``next()`` function will return this line as a
606
+ string. A line leading with ">A" indicates a successful initiation of
607
+ the program with some information on the arguments, while a line
608
+ beginning with ">E" indicates an error with the input.
609
+
610
+ - ``options`` -- string; anything else that should be forwarded as input
611
+ to Nauty's gentourng. See its documentation for more information :
612
+ `<https://pallini.di.uniroma1.it>`_.
613
+
614
+ - ``immutable`` -- boolean (default: ``False``); whether to return
615
+ immutable or mutable digraphs
616
+
617
+ EXAMPLES::
618
+
619
+ sage: # needs nauty
620
+ sage: for g in digraphs.tournaments_nauty(4):
621
+ ....: print(g.edges(sort=True, labels = False))
622
+ [(1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2)]
623
+ [(1, 0), (1, 3), (2, 0), (2, 1), (3, 0), (3, 2)]
624
+ [(0, 2), (1, 0), (2, 1), (3, 0), (3, 1), (3, 2)]
625
+ [(0, 2), (0, 3), (1, 0), (2, 1), (3, 1), (3, 2)]
626
+ sage: tournaments = digraphs.tournaments_nauty
627
+ sage: [len(list(tournaments(x))) for x in range(1,8)]
628
+ [1, 1, 2, 4, 12, 56, 456]
629
+ sage: [len(list(tournaments(x, strongly_connected = True))) for x in range(1,9)]
630
+ [1, 0, 1, 1, 6, 35, 353, 6008]
631
+ """
632
+ nauty_input = options
633
+
634
+ if min_out_degree is None:
635
+ min_out_degree = 0
636
+ if max_out_degree is None:
637
+ max_out_degree = n - 1
638
+
639
+ nauty_input += " -d" + str(min_out_degree)
640
+ nauty_input += " -D" + str(max_out_degree)
641
+
642
+ if strongly_connected:
643
+ nauty_input += " -c"
644
+
645
+ nauty_input += " " + str(n) + " "
646
+
647
+ import shlex
648
+ from sage.features.nauty import NautyExecutable
649
+ gentourng_path = NautyExecutable("gentourng").absolute_filename()
650
+
651
+ sp = subprocess.Popen(shlex.quote(gentourng_path) + " {0}".format(nauty_input),
652
+ shell=True,
653
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
654
+ stderr=subprocess.PIPE, close_fds=True)
655
+
656
+ if debug:
657
+ yield sp.stderr.readline()
658
+
659
+ def edges(s):
660
+ i = 0
661
+ j = 1
662
+ for b in s[:-1]:
663
+ yield (i, j) if b == '0' else (j, i)
664
+
665
+ if j == n - 1:
666
+ i += 1
667
+ j = i + 1
668
+ else:
669
+ j += 1
670
+
671
+ gen = sp.stdout
672
+ while True:
673
+ try:
674
+ s = bytes_to_str(next(gen))
675
+ except StopIteration:
676
+ # Exhausted list of graphs from nauty geng
677
+ return
678
+
679
+ yield DiGraph([range(n), edges(s)], format='vertices_and_edges',
680
+ immutable=immutable)
681
+
682
+ def nauty_directg(self, graphs, options='', debug=False, immutable=False):
683
+ r"""
684
+ Return an iterator yielding digraphs using nauty's ``directg`` program.
685
+
686
+ Description from ``directg --help``:
687
+ Read undirected graphs and orient their edges in all possible ways.
688
+ Edges can be oriented in either or both directions (3 possibilities).
689
+ Isomorphic directed graphs derived from the same input are suppressed.
690
+ If the input graphs are non-isomorphic then the output graphs are also.
691
+
692
+ INPUT:
693
+
694
+ - ``graphs`` -- a :class:`Graph` or an iterable containing
695
+ :class:`Graph`. The graph6 string of these graphs is used as an input
696
+ for ``directg``.
697
+
698
+ - ``options`` -- string passed to ``directg`` as if it was run at
699
+ a system command line. Available options from ``directg --help``::
700
+
701
+ -e<int> | -e<int>:<int> specify a value or range of the total number of arcs
702
+ -o orient each edge in only one direction, never both
703
+ -a only make acyclic orientations (implies -o)
704
+ -f<int> Use only the subgroup that fixes the first <int> vertices setwise
705
+ -V only output graphs with nontrivial groups (including exchange of
706
+ isolated vertices). The -f option is respected.
707
+ -s<int>/<int> Make only a fraction of the orientations: The first integer is
708
+ the part number (first is 0) and the second is the number of
709
+ parts. Splitting is done per input graph independently.
710
+
711
+ - ``debug`` -- boolean (default: ``False``); if ``True`` ``directg``
712
+ standard error and standard output are displayed
713
+
714
+ - ``immutable`` -- boolean (default: ``False``); whether to return
715
+ immutable or mutable digraphs
716
+
717
+ EXAMPLES::
718
+
719
+ sage: # needs nauty
720
+ sage: gen = graphs.nauty_geng("-c 3")
721
+ sage: dgs = list(digraphs.nauty_directg(gen))
722
+ sage: len(dgs)
723
+ 13
724
+ sage: dgs[0]
725
+ Digraph on 3 vertices
726
+ sage: dgs[0]._bit_vector()
727
+ '001001000'
728
+ sage: len(list(digraphs.nauty_directg(graphs.PetersenGraph(), options='-o')))
729
+ 324
730
+
731
+ Generate non-isomorphic acyclic orientations::
732
+
733
+ sage: # needs nauty
734
+ sage: K = graphs.CompleteGraph(4)
735
+ sage: all(d.is_directed_acyclic() for d in digraphs.nauty_directg(K, options='-a'))
736
+ True
737
+ sage: sum(1 for _ in digraphs.nauty_directg(K, options='-a'))
738
+ 1
739
+ sage: S = graphs.StarGraph(4)
740
+ sage: all(d.is_directed_acyclic() for d in digraphs.nauty_directg(S, options='-a'))
741
+ True
742
+ sage: sum(1 for _ in digraphs.nauty_directg(S, options='-a'))
743
+ 5
744
+
745
+ TESTS::
746
+
747
+ sage: # needs nauty
748
+ sage: g = digraphs.nauty_directg(graphs.PetersenGraph(), options="-o -G")
749
+ sage: next(g)
750
+ Traceback (most recent call last):
751
+ ...
752
+ ValueError: directg output options [-u|-T|-G] are not allowed
753
+ sage: next(digraphs.nauty_directg(graphs.nauty_geng("-c 3"),
754
+ ....: options='-o', debug=True))
755
+ &BH?
756
+ &BGO
757
+ &B?o
758
+ &BX?
759
+ &BP_
760
+ <BLANKLINE>
761
+ Digraph on 3 vertices
762
+
763
+ .. SEEALSO::
764
+
765
+ - :meth:`~sage.graphs.graph.Graph.orientations`
766
+ - :meth:`~sage.graphs.graph.Graph.strong_orientation`
767
+ - :meth:`~sage.graphs.orientations.strong_orientations_iterator`
768
+ - :meth:`~sage.graphs.orientations.random_orientation`
769
+ """
770
+ if '-u' in options or '-T' in options or '-G' in options:
771
+ raise ValueError("directg output options [-u|-T|-G] are not allowed")
772
+
773
+ if isinstance(graphs, Graph):
774
+ graphs = [graphs]
775
+ elif not graphs:
776
+ return
777
+
778
+ if '-q' not in options:
779
+ options += ' -q'
780
+
781
+ # Build directg input (graphs6 format)
782
+ input = ''.join(g.graph6_string() + '\n' for g in graphs)
783
+
784
+ import shlex
785
+ from sage.features.nauty import NautyExecutable
786
+ directg_path = NautyExecutable("directg").absolute_filename()
787
+
788
+ sub = subprocess.Popen(shlex.quote(directg_path) + ' {0}'.format(options),
789
+ shell=True,
790
+ stdout=subprocess.PIPE,
791
+ stdin=subprocess.PIPE,
792
+ stderr=subprocess.STDOUT,
793
+ encoding='latin-1')
794
+ out, err = sub.communicate(input=input)
795
+
796
+ if debug:
797
+ if err:
798
+ print(err)
799
+
800
+ if out:
801
+ print(out)
802
+
803
+ for line in out.split('\n'):
804
+ # directg return graphs in the digraph6 format.
805
+ # digraph6 is very similar with the dig6 format used in sage :
806
+ # digraph6_string = '&' + dig6_string
807
+ # digraph6 specifications:
808
+ # http://users.cecs.anu.edu.au/~bdm/data/formats.txt
809
+ if line and line[0] == '&':
810
+ yield DiGraph(line[1:], format='dig6', immutable=immutable)
811
+
812
+ def nauty_posetg(self, options='', debug=False, immutable=False):
813
+ r"""
814
+ Return a generator which creates all posets using ``nauty``.
815
+
816
+ Here a poset is seen through its Hasse diagram, which is
817
+ an acyclic and transitively reduced digraph.
818
+
819
+ INPUT:
820
+
821
+ - ``options`` -- string (default: ``""``); a string passed to
822
+ ``genposetg`` as if it was run at a system command line.
823
+ At a minimum, you *must* pass the number of vertices you desire
824
+ and a choice between ``o`` and ``t`` for the output order.
825
+
826
+ - ``debug`` -- boolean (default: ``False``); if ``True`` the first line
827
+ of ``genposetg``'s output to standard error is captured and the first
828
+ call to the generator's ``next()`` function will return this line as a
829
+ string. A line leading with ">A" indicates a successful initiation of
830
+ the program with some information on the arguments, while a line
831
+ beginning with ">E" indicates an error with the input.
832
+
833
+ - ``immutable`` -- boolean (default: ``False``); whether to return
834
+ immutable or mutable posets
835
+
836
+ The possible options, obtained as output of ``genposetg --help``::
837
+
838
+ n: the number of vertices, between 0 and 16
839
+ o: digraph6 output in arbitrary order
840
+ t: digraph6 output in topological order
841
+
842
+ EXAMPLES::
843
+
844
+ sage: gen = digraphs.nauty_posetg("5 o") # needs nauty
845
+ sage: len(list(gen)) # needs nauty
846
+ 63
847
+
848
+ This coincides with :oeis:`A000112`.
849
+ """
850
+ import shlex
851
+ from sage.features.nauty import NautyExecutable
852
+ geng_path = NautyExecutable("genposetg").absolute_filename()
853
+ sp = subprocess.Popen(shlex.quote(geng_path) + f" {options}", shell=True,
854
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
855
+ stderr=subprocess.PIPE, close_fds=True,
856
+ encoding='latin-1')
857
+ msg = sp.stderr.readline()
858
+ if debug:
859
+ yield msg
860
+ elif msg.startswith('>E'):
861
+ raise ValueError('wrong format of parameter option')
862
+ gen = sp.stdout
863
+ while True:
864
+ try:
865
+ s = next(gen)
866
+ except StopIteration:
867
+ # Exhausted list of graphs from nauty genposetg
868
+ return
869
+ yield DiGraph(s[1:-1], format='dig6', immutable=immutable)
870
+
871
+ def Complete(self, n, loops=False, immutable=False):
872
+ r"""
873
+ Return the complete digraph on `n` vertices.
874
+
875
+ INPUT:
876
+
877
+ - ``n`` -- integer; number of vertices
878
+
879
+ - ``loops`` -- boolean (default: ``False``); whether to add loops or
880
+ not, i.e., edges from `u` to itself
881
+
882
+ - ``immutable`` -- boolean (default: ``False``); whether to return
883
+ an immutable or mutable digraph
884
+
885
+ .. SEEALSO::
886
+
887
+ - :meth:`~sage.graphs.digraph_generators.DiGraphGenerators.RandomSemiComplete`
888
+
889
+ - :meth:`~sage.graphs.digraph_generators.DiGraphGenerators.RandomTournament`
890
+
891
+ EXAMPLES::
892
+
893
+ sage: n = 10
894
+ sage: G = digraphs.Complete(n); G
895
+ Complete digraph: Digraph on 10 vertices
896
+ sage: G.size() == n*(n-1)
897
+ True
898
+ sage: G = digraphs.Complete(n, loops=True); G
899
+ Complete digraph with loops: Looped digraph on 10 vertices
900
+ sage: G.size() == n*n
901
+ True
902
+ sage: digraphs.Complete(-1)
903
+ Traceback (most recent call last):
904
+ ...
905
+ ValueError: the number of vertices cannot be strictly negative
906
+ """
907
+ if n < 0:
908
+ raise ValueError('the number of vertices cannot be strictly negative')
909
+
910
+ edges = ((u, v) for u in range(n) for v in range(n) if u != v or loops)
911
+ G = DiGraph([range(n), edges], format='vertices_and_edges',
912
+ loops=loops, immutable=immutable,
913
+ name="Complete digraph" + (" with loops" if loops else ''))
914
+
915
+ G._circle_embedding(list(range(n)))
916
+
917
+ return G
918
+
919
+ def Circuit(self, n, immutable=False):
920
+ r"""
921
+ Return the circuit on `n` vertices.
922
+
923
+ The circuit is an oriented
924
+ :meth:`~sage.graphs.graph_generators.GraphGenerators.CycleGraph`.
925
+
926
+ INPUT:
927
+
928
+ - ``n`` -- integer; number of vertices
929
+
930
+ - ``immutable`` -- boolean (default: ``False``); whether to return
931
+ an immutable or mutable digraph
932
+
933
+ EXAMPLES:
934
+
935
+ A circuit is the smallest strongly connected digraph::
936
+
937
+ sage: circuit = digraphs.Circuit(15)
938
+ sage: len(circuit.strongly_connected_components()) == 1
939
+ True
940
+ """
941
+ if n < 0:
942
+ raise ValueError('the number of vertices cannot be strictly negative')
943
+ if n == 1:
944
+ return DiGraph([(0, 0)], format='list_of_edges', loops=True,
945
+ immutable=immutable, name='Circuit')
946
+
947
+ from itertools import chain
948
+ edges = zip(range(n), chain(range(1, n), [0]))
949
+ g = DiGraph([range(n), edges], format='vertices_and_edges',
950
+ immutable=immutable, name='Circuit')
951
+ g._circle_embedding(list(range(n)))
952
+ return g
953
+
954
+ def Circulant(self, n, integers, immutable=False):
955
+ r"""
956
+ Return a circulant digraph on `n` vertices from a set of integers.
957
+
958
+ A circulant digraph of order `n` has an arc from vertex `i` to
959
+ vertex `i+j \pmod{n}`, for each `j` in ``integers``.
960
+
961
+ INPUT:
962
+
963
+ - ``n`` -- integer; number of vertices
964
+
965
+ - ``integers`` -- iterable container (list, set, etc.) of integers such
966
+ that there is an edge from `i` to `j` if and only if `(j-i) \pmod{n}`
967
+ is an integer
968
+
969
+ - ``immutable`` -- boolean (default: ``False``); whether to return
970
+ an immutable or mutable digraph
971
+
972
+ EXAMPLES:
973
+
974
+ Construct and show the circulant graph [3, 5, 7], a digraph on 13
975
+ vertices::
976
+
977
+ sage: g = digraphs.Circulant(13, [3, 5, 7])
978
+ sage: g.show() # long time # needs sage.plot
979
+
980
+ The Koh-Tindell digraph [LM2024]_ is the circulant digraph of order 7
981
+ with parameters `[1, 5]`. This `2`-diregular digraph is
982
+ vertex-transitive but not arc-transitive. The associated bipartite
983
+ digraph of the Koh-Tindell digraph is a Pfaffian orientation of the
984
+ Heawood graph. Construct and show the Koh-Tindell digraph::
985
+
986
+ sage: kohTindellDigraph = digraphs.Circulant(7, [1, 5])
987
+ sage: kohTindellDigraph.show() # long time # needs sage.plot
988
+
989
+ TESTS:
990
+
991
+ sage: digraphs.Circulant(13, [3, 5, 7, "hey"])
992
+ Traceback (most recent call last):
993
+ ...
994
+ ValueError: the list must contain only integers
995
+ sage: digraphs.Circulant(3, [3, 5, 7, 3.4])
996
+ Traceback (most recent call last):
997
+ ...
998
+ ValueError: the list must contain only integers
999
+ """
1000
+ from sage.rings.integer_ring import ZZ
1001
+
1002
+ # Bad input and loops
1003
+ loops = False
1004
+ for i in integers:
1005
+ if i not in ZZ:
1006
+ raise ValueError("the list must contain only integers")
1007
+ if not i % n:
1008
+ loops = True
1009
+
1010
+ edges = ((v, (v + j) % n) for j in integers for v in range(n))
1011
+ G = DiGraph([range(n), edges], format='vertices_and_edges',
1012
+ loops=loops, immutable=immutable,
1013
+ name="Circulant graph (" + str(integers) + ")")
1014
+ G._circle_embedding(list(range(n)))
1015
+ return G
1016
+
1017
+ def DeBruijn(self, k, n, vertices='strings', immutable=False):
1018
+ r"""
1019
+ Return the De Bruijn digraph with parameters `k,n`.
1020
+
1021
+ The De Bruijn digraph with parameters `k,n` is built upon a set of
1022
+ vertices equal to the set of words of length `n` from a dictionary of
1023
+ `k` letters.
1024
+
1025
+ In this digraph, there is an arc `w_1w_2` if `w_2` can be obtained from
1026
+ `w_1` by removing the leftmost letter and adding a new letter at its
1027
+ right end. For more information, see the :wikipedia:`De_Bruijn_graph`.
1028
+
1029
+ INPUT:
1030
+
1031
+ - ``k`` -- two possibilities for this parameter :
1032
+ - An integer equal to the cardinality of the alphabet to use, that
1033
+ is, the degree of the digraph to be produced.
1034
+ - An iterable object to be used as the set of letters. The degree
1035
+ of the resulting digraph is the cardinality of the set of letters.
1036
+
1037
+ - ``n`` -- integer; length of words in the De Bruijn digraph when
1038
+ ``vertices == 'strings'``, and also the diameter of the digraph
1039
+
1040
+ - ``vertices`` -- string (default: ``'strings'``); whether the vertices
1041
+ are words over an alphabet (default) or integers
1042
+ (``vertices='string'``)
1043
+
1044
+ - ``immutable`` -- boolean (default: ``False``); whether to return
1045
+ an immutable or mutable digraph
1046
+
1047
+ EXAMPLES:
1048
+
1049
+ de Bruijn digraph of degree 2 and diameter 2::
1050
+
1051
+ sage: db = digraphs.DeBruijn(2, 2); db # needs sage.combinat
1052
+ De Bruijn digraph (k=2, n=2): Looped digraph on 4 vertices
1053
+ sage: db.order(), db.size() # needs sage.combinat
1054
+ (4, 8)
1055
+ sage: db.diameter() # needs sage.combinat
1056
+ 2
1057
+
1058
+ Building a de Bruijn digraph on a different alphabet::
1059
+
1060
+ sage: # needs sage.combinat
1061
+ sage: g = digraphs.DeBruijn(['a', 'b'], 2)
1062
+ sage: g.vertices(sort=True)
1063
+ ['aa', 'ab', 'ba', 'bb']
1064
+ sage: g.is_isomorphic(db)
1065
+ True
1066
+ sage: g = digraphs.DeBruijn(['AA', 'BB'], 2)
1067
+ sage: g.vertices(sort=True)
1068
+ ['AA,AA', 'AA,BB', 'BB,AA', 'BB,BB']
1069
+ sage: g.is_isomorphic(db)
1070
+ True
1071
+
1072
+ TESTS:
1073
+
1074
+ Alphabet of null size or words of length zero::
1075
+
1076
+ sage: digraphs.DeBruijn(5, 0) # needs sage.combinat
1077
+ De Bruijn digraph (k=5, n=0): Looped multi-digraph on 1 vertex
1078
+ sage: digraphs.DeBruijn(0, 0) # needs sage.combinat
1079
+ De Bruijn digraph (k=0, n=0): Looped multi-digraph on 0 vertices
1080
+
1081
+ :issue:`22355`::
1082
+
1083
+ sage: db = digraphs.DeBruijn(2, 2, vertices='strings') # needs sage.combinat
1084
+ sage: db.vertices(sort=True) # needs sage.combinat
1085
+ ['00', '01', '10', '11']
1086
+ sage: h = digraphs.DeBruijn(2, 2, vertices='integers')
1087
+ sage: h.vertices(sort=True)
1088
+ [0, 1, 2, 3]
1089
+ sage: db.is_isomorphic(h) # needs sage.combinat
1090
+ True
1091
+ sage: digraphs.DeBruijn(0, 0, vertices='integers')
1092
+ De Bruijn digraph (k=0, n=0): Looped multi-digraph on 0 vertices
1093
+ sage: digraphs.DeBruijn(2, 2, vertices='circles')
1094
+ Traceback (most recent call last):
1095
+ ...
1096
+ ValueError: unknown type for vertices
1097
+ """
1098
+ from sage.rings.integer import Integer
1099
+
1100
+ name = f"De Bruijn digraph (k={k}, n={n})"
1101
+ if vertices == 'strings':
1102
+ from sage.combinat.words.words import Words
1103
+
1104
+ W = Words(list(range(k)) if isinstance(k, Integer) else k, n)
1105
+ A = Words(list(range(k)) if isinstance(k, Integer) else k, 1)
1106
+
1107
+ if not n:
1108
+ multiedges = True
1109
+
1110
+ def edges():
1111
+ v = W[0]
1112
+ vs = v.string_rep()
1113
+ return ((vs, vs, a.string_rep()) for a in A)
1114
+
1115
+ else:
1116
+ multiedges = False
1117
+
1118
+ def edges():
1119
+ for w in W:
1120
+ ww = w[1:]
1121
+ ws = w.string_rep()
1122
+ yield from ((ws, (ww * a).string_rep(), a.string_rep())
1123
+ for a in A)
1124
+
1125
+ return DiGraph(edges(), format='list_of_edges', name=name,
1126
+ loops=True, multiedges=multiedges,
1127
+ immutable=immutable)
1128
+
1129
+ elif vertices == 'integers':
1130
+ d = k if isinstance(k, Integer) else len(list(k))
1131
+ if not d:
1132
+ return DiGraph(loops=True, multiedges=True, name=name,
1133
+ immutable=immutable)
1134
+
1135
+ return digraphs.GeneralizedDeBruijn(d ** n, d, immutable=immutable,
1136
+ name=name)
1137
+
1138
+ else:
1139
+ raise ValueError('unknown type for vertices')
1140
+
1141
+ def GeneralizedDeBruijn(self, n, d, immutable=False, name=None):
1142
+ r"""
1143
+ Return the generalized de Bruijn digraph of order `n` and degree `d`.
1144
+
1145
+ The generalized de Bruijn digraph was defined in [RPK1980]_ [RPK1983]_.
1146
+ It has vertex set `V=\{0, 1,..., n-1\}` and there is an arc from vertex
1147
+ `u \in V` to all vertices `v \in V` such that `v \equiv (u*d + a)
1148
+ \mod{n}` with `0 \leq a < d`.
1149
+
1150
+ When `n = d^{D}`, the generalized de Bruijn digraph is isomorphic to
1151
+ the de Bruijn digraph of degree `d` and diameter `D`.
1152
+
1153
+ INPUT:
1154
+
1155
+ - ``n`` -- integer; number of vertices of the digraph (must be at least
1156
+ one)
1157
+
1158
+ - ``d`` -- integer; degree of the digraph (must be at least one)
1159
+
1160
+ - ``immutable`` -- boolean (default: ``False``); whether to return
1161
+ an immutable or mutable digraph
1162
+
1163
+ - ``name`` -- string (default: ``None``); when set, the specified name
1164
+ is used instead of the default one
1165
+
1166
+ .. SEEALSO::
1167
+
1168
+ * :meth:`sage.graphs.generic_graph.GenericGraph.is_circulant` --
1169
+ checks whether a (di)graph is circulant, and/or returns all
1170
+ possible sets of parameters.
1171
+
1172
+ EXAMPLES::
1173
+
1174
+ sage: GB = digraphs.GeneralizedDeBruijn(8, 2)
1175
+ sage: GB.is_isomorphic(digraphs.DeBruijn(2, 3), certificate=True) # needs sage.combinat
1176
+ (True, {0: '000', 1: '001', 2: '010', 3: '011',
1177
+ 4: '100', 5: '101', 6: '110', 7: '111'})
1178
+
1179
+ TESTS:
1180
+
1181
+ An exception is raised when the degree is less than one::
1182
+
1183
+ sage: G = digraphs.GeneralizedDeBruijn(2, 0)
1184
+ Traceback (most recent call last):
1185
+ ...
1186
+ ValueError: degree must be greater than or equal to one
1187
+
1188
+ An exception is raised when the order of the graph is less than one::
1189
+
1190
+ sage: G = digraphs.GeneralizedDeBruijn(0, 2)
1191
+ Traceback (most recent call last):
1192
+ ...
1193
+ ValueError: order must be greater than or equal to one
1194
+ """
1195
+ if n < 1:
1196
+ raise ValueError("order must be greater than or equal to one")
1197
+ if d < 1:
1198
+ raise ValueError("degree must be greater than or equal to one")
1199
+ if name is None:
1200
+ name = f"Generalized de Bruijn digraph (n={n}, d={d})"
1201
+
1202
+ edges = ((u, a % n) for u in range(n) for a in range(u * d, u * d + d))
1203
+ return DiGraph([range(n), edges], format='vertices_and_edges',
1204
+ loops=True, multiedges=True, immutable=immutable,
1205
+ name=name)
1206
+
1207
+ def ImaseItoh(self, n, d, immutable=False, name=None):
1208
+ r"""
1209
+ Return the Imase-Itoh digraph of order `n` and degree `d`.
1210
+
1211
+ The Imase-Itoh digraph was defined in [II1983]_. It has vertex set
1212
+ `V=\{0, 1,..., n-1\}` and there is an arc from vertex `u \in V` to all
1213
+ vertices `v \in V` such that `v \equiv (-u*d-a-1) \mod{n}` with `0 \leq
1214
+ a < d`.
1215
+
1216
+ When `n = d^{D}`, the Imase-Itoh digraph is isomorphic to the de Bruijn
1217
+ digraph of degree `d` and diameter `D`. When `n = d^{D-1}(d+1)`, the
1218
+ Imase-Itoh digraph is isomorphic to the Kautz digraph [Kau1968]_ of
1219
+ degree `d` and diameter `D`.
1220
+
1221
+ INPUT:
1222
+
1223
+ - ``n`` -- integer; number of vertices of the digraph (must be greater
1224
+ than or equal to two)
1225
+
1226
+ - ``d`` -- integer; degree of the digraph (must be greater than or
1227
+ equal to one)
1228
+
1229
+ - ``immutable`` -- boolean (default: ``False``); whether to return
1230
+ an immutable or mutable digraph
1231
+
1232
+ - ``name`` -- string (default: ``None``); when set, the specified name
1233
+ is used instead of the default one
1234
+
1235
+ EXAMPLES::
1236
+
1237
+ sage: II = digraphs.ImaseItoh(8, 2)
1238
+ sage: II.is_isomorphic(digraphs.DeBruijn(2, 3), certificate=True) # needs sage.combinat
1239
+ (True, {0: '010', 1: '011', 2: '000', 3: '001',
1240
+ 4: '110', 5: '111', 6: '100', 7: '101'})
1241
+
1242
+ sage: II = digraphs.ImaseItoh(12, 2)
1243
+ sage: b,D = II.is_isomorphic(digraphs.Kautz(2, 3), certificate=True) # needs sage.combinat
1244
+ sage: b # needs sage.combinat
1245
+ True
1246
+ sage: D # random isomorphism # needs sage.combinat
1247
+ {0: '202', 1: '201', 2: '210', 3: '212', 4: '121',
1248
+ 5: '120', 6: '102', 7: '101', 8: '010', 9: '012',
1249
+ 10: '021', 11: '020'}
1250
+
1251
+ TESTS:
1252
+
1253
+ An exception is raised when the degree is less than one::
1254
+
1255
+ sage: G = digraphs.ImaseItoh(2, 0)
1256
+ Traceback (most recent call last):
1257
+ ...
1258
+ ValueError: degree must be greater than or equal to one
1259
+
1260
+ An exception is raised when the order of the graph is less than two::
1261
+
1262
+ sage: G = digraphs.ImaseItoh(1, 2)
1263
+ Traceback (most recent call last):
1264
+ ...
1265
+ ValueError: order must be greater than or equal to two
1266
+ """
1267
+ if n < 2:
1268
+ raise ValueError("order must be greater than or equal to two")
1269
+ if d < 1:
1270
+ raise ValueError("degree must be greater than or equal to one")
1271
+ if name is None:
1272
+ name = f"Imase and Itoh digraph (n={n}, d={d})"
1273
+
1274
+ edges = ((u, a % n) for u in range(n) for a in range(-u * d - d, -u * d))
1275
+ return DiGraph([range(n), edges], format='vertices_and_edges',
1276
+ loops=True, multiedges=True, immutable=immutable,
1277
+ name=name)
1278
+
1279
+ def Kautz(self, k, D, vertices='strings', immutable=False):
1280
+ r"""
1281
+ Return the Kautz digraph of degree `d` and diameter `D`.
1282
+
1283
+ The Kautz digraph has been defined in [Kau1968]_. The Kautz digraph of
1284
+ degree `d` and diameter `D` has `d^{D-1}(d+1)` vertices. This digraph
1285
+ is built from a set of vertices equal to the set of words of length `D`
1286
+ over an alphabet of `d+1` letters such that consecutive letters are
1287
+ different. There is an arc from vertex `u` to vertex `v` if `v` can be
1288
+ obtained from `u` by removing the leftmost letter and adding a new
1289
+ letter, distinct from the rightmost letter of `u`, at the right end.
1290
+
1291
+ The Kautz digraph of degree `d` and diameter `D` is isomorphic to the
1292
+ Imase-Itoh digraph [II1983]_ of degree `d` and order `d^{D-1}(d+1)`.
1293
+
1294
+ See the :wikipedia:`Kautz_graph` for more information.
1295
+
1296
+ INPUT:
1297
+
1298
+ - ``k`` -- two possibilities for this parameter. In either case the
1299
+ degree must be at least one:
1300
+
1301
+ - An integer equal to the degree of the digraph to be produced,
1302
+ that is, the cardinality of the alphabet to be used minus one.
1303
+ - An iterable object to be used as the set of letters. The degree
1304
+ of the resulting digraph is the cardinality of the set of letters
1305
+ minus one.
1306
+
1307
+ - ``D`` -- integer; diameter of the digraph, and length of a vertex
1308
+ label when ``vertices == 'strings'`` (must be at least one)
1309
+
1310
+ - ``vertices`` -- string (default: ``'strings'``); whether the vertices
1311
+ are words over an alphabet (default) or integers
1312
+ (``vertices='strings'``)
1313
+
1314
+ - ``immutable`` -- boolean (default: ``False``); whether to return
1315
+ an immutable or mutable digraph
1316
+
1317
+ EXAMPLES::
1318
+
1319
+ sage: # needs sage.combinat
1320
+ sage: K = digraphs.Kautz(2, 3)
1321
+ sage: b, D = K.is_isomorphic(digraphs.ImaseItoh(12, 2), certificate=True)
1322
+ sage: b
1323
+ True
1324
+ sage: D # random isomorphism
1325
+ {'010': 8, '012': 9, '020': 11, '021': 10, '101': 7, '102': 6,
1326
+ '120': 5, '121': 4, '201': 1, '202': 0, '210': 2, '212': 3}
1327
+
1328
+ sage: K = digraphs.Kautz([1,'a','B'], 2) # needs sage.combinat
1329
+ sage: K.edges(sort=True) # needs sage.combinat
1330
+ [('1B', 'B1', '1'), ('1B', 'Ba', 'a'), ('1a', 'a1', '1'),
1331
+ ('1a', 'aB', 'B'), ('B1', '1B', 'B'), ('B1', '1a', 'a'),
1332
+ ('Ba', 'a1', '1'), ('Ba', 'aB', 'B'), ('a1', '1B', 'B'),
1333
+ ('a1', '1a', 'a'), ('aB', 'B1', '1'), ('aB', 'Ba', 'a')]
1334
+
1335
+ sage: K = digraphs.Kautz([1,'aA','BB'], 2) # needs sage.combinat
1336
+ sage: K.edges(sort=True) # needs sage.combinat
1337
+ [('1,BB', 'BB,1', '1'), ('1,BB', 'BB,aA', 'aA'),
1338
+ ('1,aA', 'aA,1', '1'), ('1,aA', 'aA,BB', 'BB'),
1339
+ ('BB,1', '1,BB', 'BB'), ('BB,1', '1,aA', 'aA'),
1340
+ ('BB,aA', 'aA,1', '1'), ('BB,aA', 'aA,BB', 'BB'),
1341
+ ('aA,1', '1,BB', 'BB'), ('aA,1', '1,aA', 'aA'),
1342
+ ('aA,BB', 'BB,1', '1'), ('aA,BB', 'BB,aA', 'aA')]
1343
+
1344
+ TESTS:
1345
+
1346
+ An exception is raised when the degree is less than one::
1347
+
1348
+ sage: G = digraphs.Kautz(0, 2) # needs sage.combinat
1349
+ Traceback (most recent call last):
1350
+ ...
1351
+ ValueError: degree must be greater than or equal to one
1352
+
1353
+ sage: G = digraphs.Kautz(['a'], 2) # needs sage.combinat
1354
+ Traceback (most recent call last):
1355
+ ...
1356
+ ValueError: degree must be greater than or equal to one
1357
+
1358
+ An exception is raised when the diameter of the graph is less than
1359
+ one::
1360
+
1361
+ sage: G = digraphs.Kautz(2, 0) # needs sage.combinat
1362
+ Traceback (most recent call last):
1363
+ ...
1364
+ ValueError: diameter must be greater than or equal to one
1365
+
1366
+ :issue:`22355`::
1367
+
1368
+ sage: K = digraphs.Kautz(2, 2, vertices='strings') # needs sage.combinat
1369
+ sage: K.vertices(sort=True) # needs sage.combinat
1370
+ ['01', '02', '10', '12', '20', '21']
1371
+ sage: h = digraphs.Kautz(2, 2, vertices='integers')
1372
+ sage: h.vertices(sort=True)
1373
+ [0, 1, 2, 3, 4, 5]
1374
+ sage: h.is_isomorphic(K) # needs sage.combinat
1375
+ True
1376
+ sage: h = digraphs.Kautz([1,'aA','BB'], 2, vertices='integers')
1377
+ sage: h.is_isomorphic(K) # needs sage.combinat
1378
+ True
1379
+ sage: h.vertices(sort=True)
1380
+ [0, 1, 2, 3, 4, 5]
1381
+ sage: digraphs.Kautz(2, 2, vertices='circles')
1382
+ Traceback (most recent call last):
1383
+ ...
1384
+ ValueError: unknown type for vertices
1385
+ """
1386
+ if D < 1:
1387
+ raise ValueError("diameter must be greater than or equal to one")
1388
+
1389
+ from sage.rings.integer import Integer
1390
+
1391
+ name = f"Kautz digraph (k={k}, D={D})"
1392
+
1393
+ if vertices == 'strings':
1394
+ from sage.combinat.words.words import Words
1395
+
1396
+ my_alphabet = Words([str(i) for i in range(k + 1)] if isinstance(k,
1397
+ Integer) else k, 1)
1398
+ if my_alphabet.alphabet().cardinality() < 2:
1399
+ raise ValueError("degree must be greater than or equal to one")
1400
+
1401
+ # We start building the set of vertices
1402
+ V = list(my_alphabet)
1403
+ for i in range(D - 1):
1404
+ VV = []
1405
+ for w in V:
1406
+ VV += [w * a for a in my_alphabet if not w.has_suffix(a)]
1407
+ V = VV
1408
+
1409
+ # We now build the set of arcs
1410
+ def edges():
1411
+ for u in V:
1412
+ us = u.string_rep()
1413
+ yield from ((us, (u[1:] * a).string_rep(), a.string_rep())
1414
+ for a in my_alphabet if not u.has_suffix(a))
1415
+
1416
+ return DiGraph(edges(), format='list_of_edges',
1417
+ name=name, immutable=immutable)
1418
+
1419
+ elif vertices == 'integers':
1420
+ d = k if isinstance(k, Integer) else (len(list(k)) - 1)
1421
+ if d < 1:
1422
+ raise ValueError("degree must be greater than or equal to one")
1423
+ return digraphs.ImaseItoh((d + 1) * (d ** (D - 1)), d,
1424
+ name=name, immutable=immutable)
1425
+
1426
+ else:
1427
+ raise ValueError('unknown type for vertices')
1428
+
1429
+ def RandomDirectedAcyclicGraph(self, n, p, weight_max=None, immutable=False):
1430
+ r"""
1431
+ Return a random (weighted) directed acyclic graph of order `n`.
1432
+
1433
+ The method starts with the sink vertex and adds vertices one at a time.
1434
+ A vertex is connected only to previously defined vertices, and the
1435
+ probability of each possible connection is given by the probability `p`.
1436
+ The weight of an edge is a random integer between ``1`` and
1437
+ ``weight_max``.
1438
+
1439
+ INPUT:
1440
+
1441
+ - ``n`` -- number of nodes of the graph
1442
+
1443
+ - ``p`` -- probability of an edge
1444
+
1445
+ - ``weight_max`` -- (default: ``None``) by default, the returned DAG is
1446
+ unweighted. When ``weight_max`` is set to a positive integer, edges
1447
+ are assigned a random integer weight between ``1`` and ``weight_max``.
1448
+
1449
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
1450
+ immutable or mutable digraph
1451
+
1452
+ EXAMPLES::
1453
+
1454
+ sage: D = digraphs.RandomDirectedAcyclicGraph(5, .5); D
1455
+ RandomDAG(5, 0.500000000000000): Digraph on 5 vertices
1456
+ sage: D.is_directed_acyclic()
1457
+ True
1458
+ sage: D = digraphs.RandomDirectedAcyclicGraph(5, .5, weight_max=3); D
1459
+ RandomWeightedDAG(5, 0.500000000000000, 3): Digraph on 5 vertices
1460
+ sage: D.is_directed_acyclic()
1461
+ True
1462
+
1463
+ TESTS:
1464
+
1465
+ Check special cases::
1466
+
1467
+ sage: digraphs.RandomDirectedAcyclicGraph(0, .5).order() == 0
1468
+ True
1469
+ sage: digraphs.RandomDirectedAcyclicGraph(4, 0).size() == 0
1470
+ True
1471
+ sage: digraphs.RandomDirectedAcyclicGraph(4, 1).size() == 6
1472
+ True
1473
+
1474
+ Check that bad inputs are rejected::
1475
+
1476
+ sage: digraphs.RandomDirectedAcyclicGraph(-1, .5)
1477
+ Traceback (most recent call last):
1478
+ ...
1479
+ ValueError: the number of nodes must be positive or null
1480
+ sage: digraphs.RandomDirectedAcyclicGraph(5, 1.1)
1481
+ Traceback (most recent call last):
1482
+ ...
1483
+ ValueError: the probability p must be in [0..1]
1484
+ sage: digraphs.RandomDirectedAcyclicGraph(5, .5, weight_max=-1)
1485
+ Traceback (most recent call last):
1486
+ ...
1487
+ ValueError: parameter weight_max must be a positive integer
1488
+ """
1489
+ if n < 0:
1490
+ raise ValueError("the number of nodes must be positive or null")
1491
+ if 0.0 > p or 1.0 < p:
1492
+ raise ValueError("the probability p must be in [0..1]")
1493
+
1494
+ # according the sage.misc.randstate.pyx documentation, random
1495
+ # integers are on 31 bits. We thus set the pivot value to p*2^31
1496
+ from sage.misc.prandom import randint
1497
+ from sage.misc.randstate import random
1498
+ RAND_MAX_f = float(1 << 31)
1499
+ pp = int(round(float(p * RAND_MAX_f)))
1500
+
1501
+ if weight_max is None:
1502
+ name = f"RandomDAG({n}, {p})"
1503
+ edges = ((i, j) for i in range(n) for j in range(i) if random() < pp)
1504
+
1505
+ else:
1506
+ from sage.rings.integer_ring import ZZ
1507
+ if weight_max in ZZ and weight_max < 1:
1508
+ raise ValueError("parameter weight_max must be a positive integer")
1509
+
1510
+ name = f"RandomWeightedDAG({n}, {p}, {weight_max})"
1511
+ edges = ((i, j, randint(1, weight_max))
1512
+ for i in range(n) for j in range(i) if random() < pp)
1513
+
1514
+ return DiGraph([range(n), edges], format='vertices_and_edges',
1515
+ name=name, immutable=immutable)
1516
+
1517
+ def RandomDirectedGN(self, n, kernel=None, seed=None, immutable=False):
1518
+ r"""
1519
+ Return a random growing network (GN) digraph with `n` vertices.
1520
+
1521
+ The digraph is constructed by adding vertices with a link to one
1522
+ previously added vertex. The vertex to link to is chosen with a
1523
+ preferential attachment model, i.e. probability is proportional to
1524
+ degree. The default attachment kernel is a linear function of
1525
+ degree. The digraph is always a tree, so in particular it is a
1526
+ directed acyclic graph. See [KR2001b]_ for more details.
1527
+
1528
+ INPUT:
1529
+
1530
+ - ``n`` -- integer; number of vertices
1531
+
1532
+ - ``kernel`` -- the attachment kernel (default: identity function)
1533
+
1534
+ - ``seed`` -- a ``random.Random`` seed or a Python ``int`` for the
1535
+ random number generator (default: ``None``)
1536
+
1537
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
1538
+ immutable or mutable digraph
1539
+
1540
+ EXAMPLES::
1541
+
1542
+ sage: # needs networkx
1543
+ sage: D = digraphs.RandomDirectedGN(25)
1544
+ sage: D.num_verts()
1545
+ 25
1546
+ sage: D.num_edges()
1547
+ 24
1548
+ sage: D.is_connected()
1549
+ True
1550
+ sage: D.parent() is DiGraph
1551
+ True
1552
+ sage: D.show() # long time
1553
+ """
1554
+ if kernel is None:
1555
+ kernel = lambda x: x
1556
+ if seed is None:
1557
+ seed = int(current_randstate().long_seed() % sys.maxsize)
1558
+ import networkx
1559
+ return DiGraph(networkx.gn_graph(n, kernel, seed=seed),
1560
+ immutable=immutable)
1561
+
1562
+ def RandomDirectedGNC(self, n, seed=None, immutable=False):
1563
+ r"""
1564
+ Return a random growing network with copying (GNC) digraph with `n`
1565
+ vertices.
1566
+
1567
+ The digraph is constructed by adding vertices with a link to one
1568
+ previously added vertex. The vertex to link to is chosen with a
1569
+ preferential attachment model, i.e. probability is proportional to
1570
+ degree. The new vertex is also linked to all of the previously
1571
+ added vertex's successors. See [KR2005]_ for more details.
1572
+
1573
+ INPUT:
1574
+
1575
+ - ``n`` -- integer; number of vertices
1576
+
1577
+ - ``seed`` -- a ``random.Random`` seed or a Python ``int`` for the
1578
+ random number generator (default: ``None``)
1579
+
1580
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
1581
+ immutable or mutable digraph
1582
+
1583
+ EXAMPLES::
1584
+
1585
+ sage: # needs networkx
1586
+ sage: D = digraphs.RandomDirectedGNC(25)
1587
+ sage: D.is_directed_acyclic()
1588
+ True
1589
+ sage: D.topological_sort()
1590
+ [24, 23, ..., 1, 0]
1591
+ sage: D.show() # long time
1592
+ """
1593
+ if seed is None:
1594
+ seed = int(current_randstate().long_seed() % sys.maxsize)
1595
+ import networkx
1596
+ return DiGraph(networkx.gnc_graph(n, seed=seed), immutable=immutable)
1597
+
1598
+ def RandomDirectedGNP(self, n, p, loops=False, seed=None, immutable=False):
1599
+ r"""
1600
+ Return a random digraph on `n` nodes.
1601
+
1602
+ Each edge is inserted independently with probability `p`.
1603
+ See [ER1959]_ and [Gil1959]_ for more details.
1604
+
1605
+ INPUT:
1606
+
1607
+ - ``n`` -- integer; number of nodes of the digraph
1608
+
1609
+ - ``p`` -- float; probability of an edge
1610
+
1611
+ - ``loops`` -- boolean (default: ``False``); whether the random digraph
1612
+ may have loops
1613
+
1614
+ - ``seed`` -- integer (default: ``None``); seed for random number
1615
+ generator
1616
+
1617
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
1618
+ immutable or mutable digraph
1619
+
1620
+ PLOTTING: When plotting, this graph will use the default spring-layout
1621
+ algorithm, unless a position dictionary is specified.
1622
+
1623
+ EXAMPLES::
1624
+
1625
+ sage: D = digraphs.RandomDirectedGNP(10, .2)
1626
+ sage: D.num_verts()
1627
+ 10
1628
+ sage: D.parent() is DiGraph
1629
+ True
1630
+ """
1631
+ from sage.graphs.graph_generators_pyx import RandomGNP
1632
+ if 0.0 > p or 1.0 < p:
1633
+ raise ValueError("the probability p must be in [0..1]")
1634
+
1635
+ if seed is None:
1636
+ seed = current_randstate().long_seed()
1637
+
1638
+ return RandomGNP(n, p, directed=True, loops=loops, seed=seed,
1639
+ immutable=immutable)
1640
+
1641
+ def RandomDirectedGNM(self, n, m, loops=False, immutable=False):
1642
+ r"""
1643
+ Return a random labelled digraph on `n` nodes and `m` arcs.
1644
+
1645
+ INPUT:
1646
+
1647
+ - ``n`` -- integer; number of vertices
1648
+
1649
+ - ``m`` -- integer; number of edges
1650
+
1651
+ - ``loops`` -- boolean (default: ``False``); whether to allow loops
1652
+
1653
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
1654
+ immutable or mutable digraph
1655
+
1656
+ PLOTTING: When plotting, this graph will use the default spring-layout
1657
+ algorithm, unless a position dictionary is specified.
1658
+
1659
+ EXAMPLES::
1660
+
1661
+ sage: D = digraphs.RandomDirectedGNM(10, 5)
1662
+ sage: D.num_verts()
1663
+ 10
1664
+ sage: D.num_edges()
1665
+ 5
1666
+
1667
+ With loops::
1668
+
1669
+ sage: D = digraphs.RandomDirectedGNM(10, 100, loops = True)
1670
+ sage: D.num_verts()
1671
+ 10
1672
+ sage: D.loops()
1673
+ [(0, 0, None), (1, 1, None), (2, 2, None), (3, 3, None),
1674
+ (4, 4, None), (5, 5, None), (6, 6, None), (7, 7, None),
1675
+ (8, 8, None), (9, 9, None)]
1676
+
1677
+ TESTS::
1678
+
1679
+ sage: digraphs.RandomDirectedGNM(10,-3)
1680
+ Traceback (most recent call last):
1681
+ ...
1682
+ ValueError: the number of edges must satisfy 0 <= m <= n(n-1) when no loops are allowed, and 0 <= m <= n^2 otherwise
1683
+
1684
+ sage: digraphs.RandomDirectedGNM(10,100)
1685
+ Traceback (most recent call last):
1686
+ ...
1687
+ ValueError: the number of edges must satisfy 0 <= m <= n(n-1) when no loops are allowed, and 0 <= m <= n^2 otherwise
1688
+ """
1689
+ n, m = int(n), int(m)
1690
+
1691
+ # The random graph is built by drawing randomly and uniformly two
1692
+ # integers u,v, and adding the corresponding edge if it does not exist,
1693
+ # as many times as necessary.
1694
+
1695
+ # When the graph is dense, we actually compute its complement. This will
1696
+ # prevent us from drawing the same pair u,v too many times.
1697
+
1698
+ # Ensuring the parameters n,m make sense.
1699
+ #
1700
+ # If the graph is dense, we actually want to build its complement. We
1701
+ # update m accordingly.
1702
+
1703
+ good_input = True
1704
+ is_dense = False
1705
+
1706
+ if m < 0:
1707
+ good_input = False
1708
+
1709
+ if loops:
1710
+ if m > n * n:
1711
+ good_input = False
1712
+ elif 2 * m > n * n:
1713
+ is_dense = True
1714
+ m = n * n - m
1715
+
1716
+ else:
1717
+ if m > n * (n - 1):
1718
+ good_input = False
1719
+ elif m > (n * (n - 1)) // 2:
1720
+ is_dense = True
1721
+ m = n * (n - 1) - m
1722
+
1723
+ if not good_input:
1724
+ raise ValueError("the number of edges must satisfy 0 <= m <= n(n-1) "
1725
+ "when no loops are allowed, and 0 <= m <= n^2 otherwise")
1726
+
1727
+ # When the given number of edges defines a density larger than 1/2, it
1728
+ # should be faster to compute the complement of the graph (less edges to
1729
+ # generate), then to return its complement. This being said, the
1730
+ # .complement() method for sparse graphs is very slow at the moment.
1731
+
1732
+ # Similarly, it is faster to test whether a pair belongs to a dictionary
1733
+ # than to test the adjacency of two vertices in a graph. For these
1734
+ # reasons, the following code mainly works on dictionaries.
1735
+
1736
+ adj = {i: dict() for i in range(n)}
1737
+
1738
+ # We fill the dictionary structure.
1739
+
1740
+ from sage.misc.prandom import _pyrand
1741
+ rand = _pyrand()
1742
+
1743
+ while m > 0:
1744
+
1745
+ # It is better to obtain random numbers this way than by calling the
1746
+ # randint or randrange method. This, because they are very expensive
1747
+ # when trying to compute MANY random integers, and because the
1748
+ # following lines is precisely what they do anyway, after checking
1749
+ # their parameters are correct.
1750
+
1751
+ u = int(rand.random() * n)
1752
+ v = int(rand.random() * n)
1753
+
1754
+ if (u != v or loops) and (v not in adj[u]):
1755
+ adj[u][v] = 1
1756
+ m -= 1
1757
+
1758
+ # If is_dense is True, we fill the digraph with the complement of the
1759
+ # edges stored in the adj dictionary
1760
+
1761
+ if is_dense:
1762
+ edges = ((u, v) for u in range(n) for v in range(n)
1763
+ if (u != v or loops) and v not in adj[u])
1764
+ return DiGraph([range(n), edges], format='vertices_and_edges',
1765
+ loops=loops, immutable=immutable)
1766
+
1767
+ return DiGraph(adj, format='dict_of_lists', loops=loops)
1768
+
1769
+ def RandomDirectedGNR(self, n, p, seed=None, immutable=False):
1770
+ r"""
1771
+ Return a random growing network with redirection (GNR) digraph
1772
+ with `n` vertices and redirection probability `p`.
1773
+
1774
+ The digraph is constructed by adding vertices with a link to one
1775
+ previously added vertex. The vertex to link to is chosen uniformly.
1776
+ With probability p, the arc is instead redirected to the successor
1777
+ vertex. The digraph is always a tree.
1778
+ See [KR2001b]_ for more details.
1779
+
1780
+ INPUT:
1781
+
1782
+ - ``n`` -- integer; number of vertices
1783
+
1784
+ - ``p`` -- redirection probability
1785
+
1786
+ - ``seed`` -- a ``random.Random`` seed or a Python ``int`` for the
1787
+ random number generator (default: ``None``)
1788
+
1789
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
1790
+ immutable or mutable digraph
1791
+
1792
+ EXAMPLES::
1793
+
1794
+ sage: # needs networkx
1795
+ sage: D = digraphs.RandomDirectedGNR(25, .2)
1796
+ sage: D.is_directed_acyclic()
1797
+ True
1798
+ sage: D.to_undirected().is_tree()
1799
+ True
1800
+ sage: D.show() # long time # needs sage.plot
1801
+ """
1802
+ if seed is None:
1803
+ seed = int(current_randstate().long_seed() % sys.maxsize)
1804
+ import networkx
1805
+ return DiGraph(networkx.gnr_graph(n, p, seed=seed), immutable=immutable)
1806
+
1807
+ def RandomSemiComplete(self, n, immutable=False):
1808
+ r"""
1809
+ Return a random semi-complete digraph on `n` vertices.
1810
+
1811
+ A directed graph `G=(V,E)` is *semi-complete* if for any pair of
1812
+ vertices `u` and `v`, there is *at least* one arc between them.
1813
+
1814
+ To generate randomly a semi-complete digraph, we have to ensure, for any
1815
+ pair of distinct vertices `u` and `v`, that with probability `1/3` we
1816
+ have only arc `uv`, with probability `1/3` we have only arc `vu`, and
1817
+ with probability `1/3` we have both arc `uv` and arc `vu`. We do so by
1818
+ selecting a random integer `coin` in `[1,3]`. When `coin==1` we select
1819
+ only arc `uv`, when `coin==3` we select only arc `vu`, and when
1820
+ `coin==2` we select both arcs. In other words, we select arc `uv` when
1821
+ `coin\leq 2` and arc `vu` when `coin\geq 2`.
1822
+
1823
+ INPUT:
1824
+
1825
+ - ``n`` -- integer; the number of nodes
1826
+
1827
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
1828
+ immutable or mutable digraph
1829
+
1830
+ .. SEEALSO::
1831
+
1832
+ - :meth:`~sage.graphs.digraph_generators.DiGraphGenerators.Complete`
1833
+
1834
+ - :meth:`~sage.graphs.digraph_generators.DiGraphGenerators.RandomTournament`
1835
+
1836
+ EXAMPLES::
1837
+
1838
+ sage: SC = digraphs.RandomSemiComplete(10); SC
1839
+ Random Semi-Complete digraph: Digraph on 10 vertices
1840
+ sage: SC.size() >= binomial(10, 2) # needs sage.symbolic
1841
+ True
1842
+ sage: digraphs.RandomSemiComplete(-1)
1843
+ Traceback (most recent call last):
1844
+ ...
1845
+ ValueError: the number of vertices cannot be strictly negative
1846
+ """
1847
+ if n < 0:
1848
+ raise ValueError('the number of vertices cannot be strictly negative')
1849
+
1850
+ # For each pair u,v we choose a random number ``coin`` in [1,3].
1851
+ # We select edge `(u,v)` if `coin==1` or `coin==2`.
1852
+ # We select edge `(v,u)` if `coin==2` or `coin==3`.
1853
+ import itertools
1854
+ from sage.misc.prandom import randint
1855
+
1856
+ def edges():
1857
+ for u, v in itertools.combinations(range(n), 2):
1858
+ coin = randint(1, 3)
1859
+ if coin <= 2:
1860
+ yield (u, v)
1861
+ if coin >= 2:
1862
+ yield (v, u)
1863
+
1864
+ G = DiGraph([range(n), edges()], format='vertices_and_edges',
1865
+ immutable=immutable, name="Random Semi-Complete digraph")
1866
+ G._circle_embedding(list(range(n)))
1867
+ return G
1868
+
1869
+ # ##############################################################################
1870
+ # DiGraph Iterators
1871
+ # ##############################################################################
1872
+
1873
+ def __call__(self, vertices=None, property=lambda x: True, augment='edges',
1874
+ size=None, sparse=True, copy=True, immutable=False):
1875
+ """
1876
+ Access the generator of isomorphism class representatives [McK1998]_.
1877
+ Iterates over distinct, exhaustive representatives.
1878
+
1879
+ INPUT:
1880
+
1881
+ - ``vertices`` -- natural number or ``None`` to generate all digraphs
1882
+
1883
+ - ``property`` -- any property to be tested on digraphs before
1884
+ generation
1885
+
1886
+ - ``augment`` -- choices:
1887
+
1888
+ - ``'vertices'`` -- augments by adding a vertex, and edges incident to
1889
+ that vertex. In this case, all digraphs on up to n=vertices are
1890
+ generated. If for any digraph G satisfying the property, every
1891
+ subgraph, obtained from G by deleting one vertex and only edges
1892
+ incident to that vertex, satisfies the property, then this will
1893
+ generate all digraphs with that property. If this does not hold,
1894
+ then all the digraphs generated will satisfy the property, but there
1895
+ will be some missing.
1896
+
1897
+ - ``'edges'`` -- augments a fixed number of vertices by adding one
1898
+ edge. In this case, all digraphs on exactly n=vertices are
1899
+ generated. If for any graph G satisfying the property, every
1900
+ subgraph, obtained from G by deleting one edge but not the vertices
1901
+ incident to that edge, satisfies the property, then this will
1902
+ generate all digraphs with that property. If this does not hold,
1903
+ then all the digraphs generated will satisfy the property, but there
1904
+ will be some missing.
1905
+
1906
+ - ``sparse`` -- boolean (default: ``True``); whether to use a sparse or
1907
+ dense data structure. See the documentation of
1908
+ :class:`~sage.graphs.graph.Graph`.
1909
+
1910
+ - ``copy`` -- boolean (default: ``True``); whether to make copies of the
1911
+ digraphs before returning them. If set to ``False`` the method returns
1912
+ the digraph it is working on. The second alternative is faster, but
1913
+ modifying any of the digraph instances returned by the method may
1914
+ break the function's behaviour, as it is using these digraphs to
1915
+ compute the next ones: only use ``copy = False`` when you stick to
1916
+ *reading* the digraphs returned.
1917
+
1918
+ This parameter is ignored when ``immutable`` is set to ``True``, in
1919
+ which case returned graphs are always copies.
1920
+
1921
+ - ``immutable`` -- boolean (default: ``False``); whether to return
1922
+ immutable or mutable digraphs. When set to ``True``, this parameter
1923
+ implies ``copy=True``.
1924
+
1925
+ EXAMPLES:
1926
+
1927
+ Print digraphs on 2 or less vertices::
1928
+
1929
+ sage: for D in digraphs(2, augment='vertices'):
1930
+ ....: print(D)
1931
+ Digraph on 0 vertices
1932
+ Digraph on 1 vertex
1933
+ Digraph on 2 vertices
1934
+ Digraph on 2 vertices
1935
+ Digraph on 2 vertices
1936
+
1937
+ Print digraphs on 3 vertices::
1938
+
1939
+ sage: for D in digraphs(3):
1940
+ ....: print(D)
1941
+ Digraph on 3 vertices
1942
+ Digraph on 3 vertices
1943
+ ...
1944
+ Digraph on 3 vertices
1945
+ Digraph on 3 vertices
1946
+
1947
+ For more examples, see the class level documentation, or type ::
1948
+
1949
+ sage: digraphs? # not tested
1950
+ """
1951
+ if size is not None:
1952
+ def extra_property(x):
1953
+ return x.size() == size
1954
+ else:
1955
+ def extra_property(x):
1956
+ return True
1957
+ if augment == 'vertices':
1958
+ if vertices is None:
1959
+ raise NotImplementedError
1960
+
1961
+ from sage.graphs.graph_generators import canaug_traverse_vert
1962
+ g = DiGraph(sparse=sparse)
1963
+ for gg in canaug_traverse_vert(g, [], vertices, property, dig=True, sparse=sparse):
1964
+ if extra_property(gg):
1965
+ yield gg.copy(immutable=immutable) if copy or immutable else gg
1966
+
1967
+ elif augment == 'edges':
1968
+
1969
+ if vertices is None:
1970
+ vertices = 0
1971
+ while True:
1972
+ yield from self(vertices, sparse=sparse, copy=copy,
1973
+ immutable=immutable)
1974
+ vertices += 1
1975
+
1976
+ from sage.graphs.graph_generators import canaug_traverse_edge
1977
+ g = DiGraph(vertices, sparse=sparse)
1978
+ gens = []
1979
+ for i in range(vertices - 1):
1980
+ gen = list(range(i))
1981
+ gen.append(i + 1)
1982
+ gen.append(i)
1983
+ gen += list(range(i + 2, vertices))
1984
+ gens.append(gen)
1985
+ for gg in canaug_traverse_edge(g, gens, property, dig=True, sparse=sparse):
1986
+ if extra_property(gg):
1987
+ yield gg.copy(immutable=immutable) if copy or immutable else gg
1988
+ else:
1989
+ raise NotImplementedError()
1990
+
1991
+
1992
+ # Easy access to the graph generators from the command line:
1993
+ digraphs = DiGraphGenerators()