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.
- passagemath_graphs-10.6.1rc1.dist-info/METADATA +292 -0
- passagemath_graphs-10.6.1rc1.dist-info/RECORD +260 -0
- passagemath_graphs-10.6.1rc1.dist-info/WHEEL +5 -0
- passagemath_graphs-10.6.1rc1.dist-info/top_level.txt +2 -0
- passagemath_graphs.libs/libgcc_s-69c45f16.so.1 +0 -0
- passagemath_graphs.libs/libgmp-8e78bd9b.so.10.5.0 +0 -0
- passagemath_graphs.libs/libstdc++-1f1a71be.so.6.0.33 +0 -0
- sage/all__sagemath_graphs.py +39 -0
- sage/combinat/abstract_tree.py +2723 -0
- sage/combinat/all__sagemath_graphs.py +34 -0
- sage/combinat/binary_tree.py +5306 -0
- sage/combinat/cluster_algebra_quiver/all.py +22 -0
- sage/combinat/cluster_algebra_quiver/cluster_seed.py +5208 -0
- sage/combinat/cluster_algebra_quiver/interact.py +124 -0
- sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
- sage/combinat/cluster_algebra_quiver/mutation_type.py +1555 -0
- sage/combinat/cluster_algebra_quiver/quiver.py +2290 -0
- sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +2468 -0
- sage/combinat/designs/MOLS_handbook_data.py +570 -0
- sage/combinat/designs/all.py +58 -0
- sage/combinat/designs/bibd.py +1655 -0
- sage/combinat/designs/block_design.py +1071 -0
- sage/combinat/designs/covering_array.py +269 -0
- sage/combinat/designs/covering_design.py +530 -0
- sage/combinat/designs/database.py +5615 -0
- sage/combinat/designs/design_catalog.py +122 -0
- sage/combinat/designs/designs_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/designs_pyx.pxd +21 -0
- sage/combinat/designs/designs_pyx.pyx +993 -0
- sage/combinat/designs/difference_family.py +3951 -0
- sage/combinat/designs/difference_matrices.py +279 -0
- sage/combinat/designs/evenly_distributed_sets.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/evenly_distributed_sets.pyx +661 -0
- sage/combinat/designs/ext_rep.py +1064 -0
- sage/combinat/designs/gen_quadrangles_with_spread.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/gen_quadrangles_with_spread.pyx +339 -0
- sage/combinat/designs/group_divisible_designs.py +361 -0
- sage/combinat/designs/incidence_structures.py +2357 -0
- sage/combinat/designs/latin_squares.py +581 -0
- sage/combinat/designs/orthogonal_arrays.py +2244 -0
- sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
- sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +967 -0
- sage/combinat/designs/resolvable_bibd.py +815 -0
- sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
- sage/combinat/designs/subhypergraph_search.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/subhypergraph_search.pyx +530 -0
- sage/combinat/designs/twographs.py +306 -0
- sage/combinat/finite_state_machine.py +14874 -0
- sage/combinat/finite_state_machine_generators.py +2006 -0
- sage/combinat/graph_path.py +448 -0
- sage/combinat/interval_posets.py +3908 -0
- sage/combinat/nu_tamari_lattice.py +269 -0
- sage/combinat/ordered_tree.py +1446 -0
- sage/combinat/posets/all.py +46 -0
- sage/combinat/posets/bubble_shuffle.py +247 -0
- sage/combinat/posets/cartesian_product.py +493 -0
- sage/combinat/posets/d_complete.py +182 -0
- sage/combinat/posets/elements.py +273 -0
- sage/combinat/posets/forest.py +30 -0
- sage/combinat/posets/hasse_cython.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/posets/hasse_cython.pyx +174 -0
- sage/combinat/posets/hasse_diagram.py +3672 -0
- sage/combinat/posets/hochschild_lattice.py +158 -0
- sage/combinat/posets/incidence_algebras.py +794 -0
- sage/combinat/posets/lattices.py +5117 -0
- sage/combinat/posets/linear_extension_iterator.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/posets/linear_extension_iterator.pyx +292 -0
- sage/combinat/posets/linear_extensions.py +1037 -0
- sage/combinat/posets/mobile.py +275 -0
- sage/combinat/posets/moebius_algebra.py +776 -0
- sage/combinat/posets/poset_examples.py +2178 -0
- sage/combinat/posets/posets.py +9360 -0
- sage/combinat/rooted_tree.py +1070 -0
- sage/combinat/shard_order.py +239 -0
- sage/combinat/tamari_lattices.py +384 -0
- sage/combinat/yang_baxter_graph.py +923 -0
- sage/databases/all__sagemath_graphs.py +1 -0
- sage/databases/knotinfo_db.py +1231 -0
- sage/ext_data/all__sagemath_graphs.py +1 -0
- sage/ext_data/graphs/graph_plot_js.html +330 -0
- sage/ext_data/kenzo/CP2.txt +45 -0
- sage/ext_data/kenzo/CP3.txt +349 -0
- sage/ext_data/kenzo/CP4.txt +4774 -0
- sage/ext_data/kenzo/README.txt +49 -0
- sage/ext_data/kenzo/S4.txt +20 -0
- sage/graphs/all.py +42 -0
- sage/graphs/asteroidal_triples.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/asteroidal_triples.pyx +320 -0
- sage/graphs/base/all.py +1 -0
- sage/graphs/base/boost_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/boost_graph.pxd +106 -0
- sage/graphs/base/boost_graph.pyx +3045 -0
- sage/graphs/base/c_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/c_graph.pxd +106 -0
- sage/graphs/base/c_graph.pyx +5096 -0
- sage/graphs/base/dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/dense_graph.pxd +28 -0
- sage/graphs/base/dense_graph.pyx +801 -0
- sage/graphs/base/graph_backends.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/graph_backends.pxd +5 -0
- sage/graphs/base/graph_backends.pyx +797 -0
- sage/graphs/base/overview.py +85 -0
- sage/graphs/base/sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/sparse_graph.pxd +90 -0
- sage/graphs/base/sparse_graph.pyx +1653 -0
- sage/graphs/base/static_dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_dense_graph.pxd +5 -0
- sage/graphs/base/static_dense_graph.pyx +1032 -0
- sage/graphs/base/static_sparse_backend.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_sparse_backend.pxd +27 -0
- sage/graphs/base/static_sparse_backend.pyx +1583 -0
- sage/graphs/base/static_sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_sparse_graph.pxd +37 -0
- sage/graphs/base/static_sparse_graph.pyx +1375 -0
- sage/graphs/bipartite_graph.py +2732 -0
- sage/graphs/centrality.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/centrality.pyx +1038 -0
- sage/graphs/cographs.py +519 -0
- sage/graphs/comparability.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/comparability.pyx +851 -0
- sage/graphs/connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/connectivity.pxd +157 -0
- sage/graphs/connectivity.pyx +4813 -0
- sage/graphs/convexity_properties.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/convexity_properties.pxd +16 -0
- sage/graphs/convexity_properties.pyx +870 -0
- sage/graphs/digraph.py +4754 -0
- sage/graphs/digraph_generators.py +1993 -0
- sage/graphs/distances_all_pairs.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/distances_all_pairs.pxd +12 -0
- sage/graphs/distances_all_pairs.pyx +2938 -0
- sage/graphs/domination.py +1363 -0
- sage/graphs/dot2tex_utils.py +100 -0
- sage/graphs/edge_connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/edge_connectivity.pyx +1215 -0
- sage/graphs/generators/all.py +1 -0
- sage/graphs/generators/basic.py +1769 -0
- sage/graphs/generators/chessboard.py +538 -0
- sage/graphs/generators/classical_geometries.py +1611 -0
- sage/graphs/generators/degree_sequence.py +235 -0
- sage/graphs/generators/distance_regular.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/generators/distance_regular.pyx +2846 -0
- sage/graphs/generators/families.py +4759 -0
- sage/graphs/generators/intersection.py +565 -0
- sage/graphs/generators/platonic_solids.py +262 -0
- sage/graphs/generators/random.py +2623 -0
- sage/graphs/generators/smallgraphs.py +5741 -0
- sage/graphs/generators/world_map.py +724 -0
- sage/graphs/generic_graph.py +26867 -0
- sage/graphs/generic_graph_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/generic_graph_pyx.pxd +34 -0
- sage/graphs/generic_graph_pyx.pyx +1673 -0
- sage/graphs/genus.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/genus.pyx +622 -0
- sage/graphs/graph.py +9645 -0
- sage/graphs/graph_coloring.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_coloring.pyx +2284 -0
- sage/graphs/graph_database.py +1177 -0
- sage/graphs/graph_decompositions/all.py +1 -0
- sage/graphs/graph_decompositions/bandwidth.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
- sage/graphs/graph_decompositions/clique_separators.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/clique_separators.pyx +616 -0
- sage/graphs/graph_decompositions/cutwidth.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
- sage/graphs/graph_decompositions/fast_digraph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
- sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
- sage/graphs/graph_decompositions/graph_products.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/graph_products.pyx +508 -0
- sage/graphs/graph_decompositions/modular_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
- sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
- sage/graphs/graph_decompositions/slice_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
- sage/graphs/graph_decompositions/slice_decomposition.pyx +1106 -0
- sage/graphs/graph_decompositions/tree_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
- sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
- sage/graphs/graph_decompositions/vertex_separation.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
- sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
- sage/graphs/graph_editor.py +82 -0
- sage/graphs/graph_generators.py +3314 -0
- sage/graphs/graph_generators_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_generators_pyx.pyx +95 -0
- sage/graphs/graph_input.py +812 -0
- sage/graphs/graph_latex.py +2064 -0
- sage/graphs/graph_list.py +410 -0
- sage/graphs/graph_plot.py +1756 -0
- sage/graphs/graph_plot_js.py +338 -0
- sage/graphs/hyperbolicity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/hyperbolicity.pyx +1704 -0
- sage/graphs/hypergraph_generators.py +364 -0
- sage/graphs/independent_sets.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/independent_sets.pxd +13 -0
- sage/graphs/independent_sets.pyx +402 -0
- sage/graphs/isgci.py +1033 -0
- sage/graphs/isoperimetric_inequalities.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/isoperimetric_inequalities.pyx +489 -0
- sage/graphs/line_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/line_graph.pyx +743 -0
- sage/graphs/lovasz_theta.py +77 -0
- sage/graphs/matching.py +1633 -0
- sage/graphs/matching_covered_graph.py +3590 -0
- sage/graphs/orientations.py +1489 -0
- sage/graphs/partial_cube.py +459 -0
- sage/graphs/path_enumeration.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/path_enumeration.pyx +2040 -0
- sage/graphs/pq_trees.py +1129 -0
- sage/graphs/print_graphs.py +201 -0
- sage/graphs/schnyder.py +865 -0
- sage/graphs/spanning_tree.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/spanning_tree.pyx +1457 -0
- sage/graphs/strongly_regular_db.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/strongly_regular_db.pyx +3340 -0
- sage/graphs/traversals.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/traversals.pxd +9 -0
- sage/graphs/traversals.pyx +1872 -0
- sage/graphs/trees.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/trees.pxd +15 -0
- sage/graphs/trees.pyx +310 -0
- sage/graphs/tutte_polynomial.py +713 -0
- sage/graphs/views.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/views.pyx +794 -0
- sage/graphs/weakly_chordal.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/weakly_chordal.pyx +604 -0
- sage/groups/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
- sage/knots/all.py +6 -0
- sage/knots/free_knotinfo_monoid.py +507 -0
- sage/knots/gauss_code.py +291 -0
- sage/knots/knot.py +682 -0
- sage/knots/knot_table.py +284 -0
- sage/knots/knotinfo.py +2900 -0
- sage/knots/link.py +4715 -0
- sage/sandpiles/all.py +13 -0
- sage/sandpiles/examples.py +225 -0
- sage/sandpiles/sandpile.py +6365 -0
- sage/topology/all.py +22 -0
- sage/topology/cell_complex.py +1214 -0
- sage/topology/cubical_complex.py +1976 -0
- sage/topology/delta_complex.py +1806 -0
- sage/topology/filtered_simplicial_complex.py +744 -0
- sage/topology/moment_angle_complex.py +823 -0
- sage/topology/simplicial_complex.py +5160 -0
- sage/topology/simplicial_complex_catalog.py +92 -0
- sage/topology/simplicial_complex_examples.py +1680 -0
- sage/topology/simplicial_complex_homset.py +205 -0
- sage/topology/simplicial_complex_morphism.py +836 -0
- sage/topology/simplicial_set.py +4102 -0
- sage/topology/simplicial_set_catalog.py +55 -0
- sage/topology/simplicial_set_constructions.py +2954 -0
- sage/topology/simplicial_set_examples.py +865 -0
- 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()
|