passagemath-graphs 10.5.43__cp39-cp39-musllinux_1_2_aarch64.whl

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