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,1769 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-graphs
|
2
|
+
r"""
|
3
|
+
Basic graphs
|
4
|
+
|
5
|
+
The methods defined here appear in :mod:`sage.graphs.graph_generators`.
|
6
|
+
"""
|
7
|
+
# ****************************************************************************
|
8
|
+
# Copyright (C) 2006 Robert L. Miller <rlmillster@gmail.com>
|
9
|
+
# and Emily A. Kirkman
|
10
|
+
# 2009 Michael C. Yurko <myurko@gmail.com>
|
11
|
+
#
|
12
|
+
# This program is free software: you can redistribute it and/or modify
|
13
|
+
# it under the terms of the GNU General Public License as published by
|
14
|
+
# the Free Software Foundation, either version 2 of the License, or
|
15
|
+
# (at your option) any later version.
|
16
|
+
# https://www.gnu.org/licenses/
|
17
|
+
# ****************************************************************************
|
18
|
+
|
19
|
+
# import from Sage library
|
20
|
+
from sage.graphs.graph import Graph
|
21
|
+
from math import sin, cos, pi
|
22
|
+
|
23
|
+
|
24
|
+
def BullGraph(immutable=False):
|
25
|
+
r"""
|
26
|
+
Return a bull graph with 5 nodes.
|
27
|
+
|
28
|
+
A bull graph is named for its shape. It's a triangle with horns.
|
29
|
+
See the :wikipedia:`Bull_graph` for more information.
|
30
|
+
|
31
|
+
INPUT:
|
32
|
+
|
33
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
34
|
+
immutable or a mutable graph
|
35
|
+
|
36
|
+
PLOTTING:
|
37
|
+
|
38
|
+
Upon construction, the position dictionary is filled to override the
|
39
|
+
spring-layout algorithm. By convention, the bull graph is drawn as a
|
40
|
+
triangle with the first node (0) on the bottom. The second and third nodes
|
41
|
+
(1 and 2) complete the triangle. Node 3 is the horn connected to 1 and node
|
42
|
+
4 is the horn connected to node 2.
|
43
|
+
|
44
|
+
EXAMPLES:
|
45
|
+
|
46
|
+
Construct and show a bull graph::
|
47
|
+
|
48
|
+
sage: g = graphs.BullGraph(); g
|
49
|
+
Bull graph: Graph on 5 vertices
|
50
|
+
sage: g.show() # long time # needs sage.plot
|
51
|
+
|
52
|
+
The bull graph has 5 vertices and 5 edges. Its radius is 2, its
|
53
|
+
diameter 3, and its girth 3. The bull graph is planar with chromatic
|
54
|
+
number 3 and chromatic index also 3::
|
55
|
+
|
56
|
+
sage: g.order(); g.size()
|
57
|
+
5
|
58
|
+
5
|
59
|
+
sage: g.radius(); g.diameter(); g.girth()
|
60
|
+
2
|
61
|
+
3
|
62
|
+
3
|
63
|
+
sage: g.chromatic_number() # needs cliquer
|
64
|
+
3
|
65
|
+
|
66
|
+
The bull graph has chromatic polynomial `x(x - 2)(x - 1)^3` and
|
67
|
+
Tutte polynomial `x^4 + x^3 + x^2 y`. Its characteristic polynomial
|
68
|
+
is `x(x^2 - x - 3)(x^2 + x - 1)`, which follows from the definition of
|
69
|
+
characteristic polynomials for graphs, i.e. `\det(xI - A)`, where
|
70
|
+
`x` is a variable, `A` the adjacency matrix of the graph, and `I`
|
71
|
+
the identity matrix of the same dimensions as `A`::
|
72
|
+
|
73
|
+
sage: # needs sage.libs.flint
|
74
|
+
sage: chrompoly = g.chromatic_polynomial()
|
75
|
+
sage: x = chrompoly.parent()('x')
|
76
|
+
sage: x * (x - 2) * (x - 1)^3 == chrompoly
|
77
|
+
True
|
78
|
+
|
79
|
+
sage: # needs sage.libs.flint sage.modules
|
80
|
+
sage: charpoly = g.characteristic_polynomial()
|
81
|
+
sage: M = g.adjacency_matrix(); M
|
82
|
+
[0 1 1 0 0]
|
83
|
+
[1 0 1 1 0]
|
84
|
+
[1 1 0 0 1]
|
85
|
+
[0 1 0 0 0]
|
86
|
+
[0 0 1 0 0]
|
87
|
+
sage: Id = identity_matrix(ZZ, M.nrows())
|
88
|
+
sage: D = x*Id - M
|
89
|
+
sage: D.determinant() == charpoly # needs sage.symbolic
|
90
|
+
True
|
91
|
+
sage: x * (x^2 - x - 3) * (x^2 + x - 1) == charpoly
|
92
|
+
True
|
93
|
+
|
94
|
+
TESTS:
|
95
|
+
|
96
|
+
Check the behavior of parameter ``immutable``::
|
97
|
+
|
98
|
+
sage: graphs.BullGraph(immutable=True).is_immutable()
|
99
|
+
True
|
100
|
+
"""
|
101
|
+
edge_list = [(0, 1), (0, 2), (1, 2), (1, 3), (2, 4)]
|
102
|
+
pos_dict = {0: (0, 0), 1: (-1, 1), 2: (1, 1), 3: (-2, 2), 4: (2, 2)}
|
103
|
+
return Graph([range(5), edge_list], format='vertices_and_edges',
|
104
|
+
immutable=immutable, pos=pos_dict, name="Bull graph")
|
105
|
+
|
106
|
+
|
107
|
+
def ButterflyGraph(immutable=False):
|
108
|
+
r"""
|
109
|
+
Return the butterfly graph.
|
110
|
+
|
111
|
+
Let `C_3` be the cycle graph on 3 vertices. The butterfly or bowtie
|
112
|
+
graph is obtained by joining two copies of `C_3` at a common vertex,
|
113
|
+
resulting in a graph that is isomorphic to the friendship graph `F_2`.
|
114
|
+
See the :wikipedia:`Butterfly_graph` for more information.
|
115
|
+
|
116
|
+
.. SEEALSO::
|
117
|
+
|
118
|
+
- :meth:`~sage.graphs.graph_generators.GraphGenerators.FriendshipGraph`
|
119
|
+
|
120
|
+
INPUT:
|
121
|
+
|
122
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
123
|
+
immutable or a mutable graph
|
124
|
+
|
125
|
+
EXAMPLES:
|
126
|
+
|
127
|
+
The butterfly graph is a planar graph on 5 vertices and having 6 edges::
|
128
|
+
|
129
|
+
sage: G = graphs.ButterflyGraph(); G
|
130
|
+
Butterfly graph: Graph on 5 vertices
|
131
|
+
sage: G.show() # long time # needs sage.plot
|
132
|
+
sage: G.is_planar() # needs planarity
|
133
|
+
True
|
134
|
+
sage: G.order()
|
135
|
+
5
|
136
|
+
sage: G.size()
|
137
|
+
6
|
138
|
+
|
139
|
+
It has diameter 2, girth 3, and radius 1::
|
140
|
+
|
141
|
+
sage: G.diameter()
|
142
|
+
2
|
143
|
+
sage: G.girth()
|
144
|
+
3
|
145
|
+
sage: G.radius()
|
146
|
+
1
|
147
|
+
|
148
|
+
The butterfly graph is Eulerian, with chromatic number 3::
|
149
|
+
|
150
|
+
sage: G.is_eulerian()
|
151
|
+
True
|
152
|
+
sage: G.chromatic_number() # needs cliquer
|
153
|
+
3
|
154
|
+
|
155
|
+
TESTS:
|
156
|
+
|
157
|
+
Check the behavior of parameter ``immutable``::
|
158
|
+
|
159
|
+
sage: graphs.ButterflyGraph(immutable=True).is_immutable()
|
160
|
+
True
|
161
|
+
"""
|
162
|
+
edge_dict = {
|
163
|
+
0: [3, 4],
|
164
|
+
1: [2, 4],
|
165
|
+
2: [4],
|
166
|
+
3: [4]}
|
167
|
+
pos_dict = {
|
168
|
+
0: [-1, 1],
|
169
|
+
1: [1, 1],
|
170
|
+
2: [1, -1],
|
171
|
+
3: [-1, -1],
|
172
|
+
4: [0, 0]}
|
173
|
+
return Graph(edge_dict, format='dict_of_lists',
|
174
|
+
immutable=immutable, pos=pos_dict, name="Butterfly graph")
|
175
|
+
|
176
|
+
|
177
|
+
def CircularLadderGraph(n, immutable=False):
|
178
|
+
r"""
|
179
|
+
Return a circular ladder graph with `2 * n` nodes.
|
180
|
+
|
181
|
+
A Circular ladder graph is a ladder graph that is connected at the ends,
|
182
|
+
i.e.: a ladder bent around so that top meets bottom. Thus it can be
|
183
|
+
described as two parallel cycle graphs connected at each corresponding node
|
184
|
+
pair.
|
185
|
+
|
186
|
+
PLOTTING: Upon construction, the position dictionary is filled to override
|
187
|
+
the spring-layout algorithm. By convention, the circular ladder graph is
|
188
|
+
displayed as an inner and outer cycle pair, with the first `n` nodes drawn
|
189
|
+
on the inner circle. The first (0) node is drawn at the top of the
|
190
|
+
inner-circle, moving clockwise after that. The outer circle is drawn with
|
191
|
+
the `(n+1)`-th node at the top, then counterclockwise as well.
|
192
|
+
When `n == 2`, we rotate the outer circle by an angle of `\pi/8` to ensure
|
193
|
+
that all edges are visible (otherwise the 4 vertices of the graph would be
|
194
|
+
placed on a single line).
|
195
|
+
|
196
|
+
INPUT:
|
197
|
+
|
198
|
+
- ``n`` -- nonnegative integer
|
199
|
+
|
200
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
201
|
+
immutable or a mutable graph
|
202
|
+
|
203
|
+
EXAMPLES:
|
204
|
+
|
205
|
+
Construct and show a circular ladder graph with 26 nodes::
|
206
|
+
|
207
|
+
sage: g = graphs.CircularLadderGraph(13)
|
208
|
+
sage: g.show() # long time # needs sage.plot
|
209
|
+
|
210
|
+
Create several circular ladder graphs in a Sage graphics array::
|
211
|
+
|
212
|
+
sage: g = []
|
213
|
+
sage: j = []
|
214
|
+
sage: for i in range(9):
|
215
|
+
....: k = graphs.CircularLadderGraph(i+3)
|
216
|
+
....: g.append(k)
|
217
|
+
sage: for i in range(3): # needs sage.plot
|
218
|
+
....: n = []
|
219
|
+
....: for m in range(3):
|
220
|
+
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
|
221
|
+
....: j.append(n)
|
222
|
+
sage: G = graphics_array(j) # needs sage.plot
|
223
|
+
sage: G.show() # long time # needs sage.plot
|
224
|
+
|
225
|
+
TESTS::
|
226
|
+
|
227
|
+
sage: G = graphs.CircularLadderGraph(4, immutable=True)
|
228
|
+
sage: G.is_immutable()
|
229
|
+
True
|
230
|
+
"""
|
231
|
+
from itertools import chain
|
232
|
+
edges_1 = zip(range(n), chain(range(1, n), (0,)))
|
233
|
+
edges_2 = zip(range(n, 2 * n), chain(range(n + 1, 2 * n), (n,)))
|
234
|
+
edges_3 = ((i, i + n) for i in range(n))
|
235
|
+
G = Graph([range(2 * n), chain(edges_1, edges_2, edges_3)],
|
236
|
+
format='vertices_and_edges', immutable=immutable,
|
237
|
+
name="Circular Ladder graph")
|
238
|
+
G._circle_embedding(list(range(n)), radius=1, angle=pi/2)
|
239
|
+
if n == 2:
|
240
|
+
G._circle_embedding(list(range(4)), radius=1, angle=pi/2 + pi/8)
|
241
|
+
else:
|
242
|
+
G._circle_embedding(list(range(n, 2*n)), radius=2, angle=pi/2)
|
243
|
+
return G
|
244
|
+
|
245
|
+
|
246
|
+
def ClawGraph(immutable=False):
|
247
|
+
"""
|
248
|
+
Return a claw graph.
|
249
|
+
|
250
|
+
A claw graph is named for its shape. It is actually a complete
|
251
|
+
bipartite graph with ``(n1, n2) = (1, 3)``.
|
252
|
+
|
253
|
+
PLOTTING: See :meth:`CompleteBipartiteGraph`.
|
254
|
+
|
255
|
+
INPUT:
|
256
|
+
|
257
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
258
|
+
immutable or a mutable graph
|
259
|
+
|
260
|
+
EXAMPLES:
|
261
|
+
|
262
|
+
Show a Claw graph::
|
263
|
+
|
264
|
+
sage: (graphs.ClawGraph()).show() # long time # needs sage.plot
|
265
|
+
|
266
|
+
Inspect a Claw graph::
|
267
|
+
|
268
|
+
sage: G = graphs.ClawGraph()
|
269
|
+
sage: G
|
270
|
+
Claw graph: Graph on 4 vertices
|
271
|
+
|
272
|
+
TESTS:
|
273
|
+
|
274
|
+
Check the behavior of parameter ``immutable``::
|
275
|
+
|
276
|
+
sage: graphs.ClawGraph(immutable=True).is_immutable()
|
277
|
+
True
|
278
|
+
"""
|
279
|
+
edge_list = [(0, 1), (0, 2), (0, 3)]
|
280
|
+
pos_dict = {0: (0, 1), 1: (-1, 0), 2: (0, 0), 3: (1, 0)}
|
281
|
+
return Graph([range(4), edge_list], format='vertices_and_edges',
|
282
|
+
immutable=immutable, pos=pos_dict, name="Claw graph")
|
283
|
+
|
284
|
+
|
285
|
+
def CycleGraph(n, immutable=False):
|
286
|
+
r"""
|
287
|
+
Return a cycle graph with `n` nodes.
|
288
|
+
|
289
|
+
A cycle graph is a basic structure which is also typically called an
|
290
|
+
`n`-gon.
|
291
|
+
|
292
|
+
INPUT:
|
293
|
+
|
294
|
+
- ``n`` -- nonnegative integer; the number of vertices of the cycle graph
|
295
|
+
|
296
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
297
|
+
immutable or a mutable graph
|
298
|
+
|
299
|
+
PLOTTING: Upon construction, the position dictionary is filled to override
|
300
|
+
the spring-layout algorithm. By convention, each cycle graph will be
|
301
|
+
displayed with the first (0) node at the top, with the rest following in a
|
302
|
+
counterclockwise manner.
|
303
|
+
|
304
|
+
The cycle graph is a good opportunity to compare efficiency of filling a
|
305
|
+
position dictionary vs. using the spring-layout algorithm for
|
306
|
+
plotting. Because the cycle graph is very symmetric, the resulting plots
|
307
|
+
should be similar (in cases of small `n`).
|
308
|
+
|
309
|
+
Filling the position dictionary in advance adds `O(n)` to the constructor.
|
310
|
+
|
311
|
+
EXAMPLES:
|
312
|
+
|
313
|
+
Compare plotting using the predefined layout and networkx::
|
314
|
+
|
315
|
+
sage: # needs networkx sage.plot
|
316
|
+
sage: import networkx
|
317
|
+
sage: n = networkx.cycle_graph(23)
|
318
|
+
sage: spring23 = Graph(n)
|
319
|
+
sage: posdict23 = graphs.CycleGraph(23)
|
320
|
+
sage: spring23.show() # long time
|
321
|
+
sage: posdict23.show() # long time
|
322
|
+
|
323
|
+
We next view many cycle graphs as a Sage graphics array. First we use the
|
324
|
+
``CycleGraph`` constructor, which fills in the position dictionary::
|
325
|
+
|
326
|
+
sage: # needs networkx sage.plot
|
327
|
+
sage: g = []
|
328
|
+
sage: j = []
|
329
|
+
sage: for i in range(9):
|
330
|
+
....: k = graphs.CycleGraph(i+3)
|
331
|
+
....: g.append(k)
|
332
|
+
sage: for i in range(3):
|
333
|
+
....: n = []
|
334
|
+
....: for m in range(3):
|
335
|
+
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
|
336
|
+
....: j.append(n)
|
337
|
+
sage: G = graphics_array(j)
|
338
|
+
sage: G.show() # long time
|
339
|
+
|
340
|
+
Compare to plotting with the spring-layout algorithm::
|
341
|
+
|
342
|
+
sage: # needs networkx sage.plot
|
343
|
+
sage: g = []
|
344
|
+
sage: j = []
|
345
|
+
sage: for i in range(9):
|
346
|
+
....: spr = networkx.cycle_graph(i+3)
|
347
|
+
....: k = Graph(spr)
|
348
|
+
....: g.append(k)
|
349
|
+
sage: for i in range(3):
|
350
|
+
....: n = []
|
351
|
+
....: for m in range(3):
|
352
|
+
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
|
353
|
+
....: j.append(n)
|
354
|
+
sage: G = graphics_array(j)
|
355
|
+
sage: G.show() # long time
|
356
|
+
|
357
|
+
TESTS:
|
358
|
+
|
359
|
+
The input parameter must be a positive integer::
|
360
|
+
|
361
|
+
sage: G = graphs.CycleGraph(-1)
|
362
|
+
Traceback (most recent call last):
|
363
|
+
...
|
364
|
+
ValueError: parameter n must be a positive integer
|
365
|
+
|
366
|
+
Check the behavior of parameter ``immutable``::
|
367
|
+
|
368
|
+
sage: graphs.CycleGraph(4, immutable=True).is_immutable()
|
369
|
+
True
|
370
|
+
"""
|
371
|
+
if n < 0:
|
372
|
+
raise ValueError("parameter n must be a positive integer")
|
373
|
+
|
374
|
+
from itertools import chain
|
375
|
+
edges = zip(range(n), chain(range(1, n), (0,))) if n > 1 else []
|
376
|
+
G = Graph([range(n), edges], format='vertices_and_edges',
|
377
|
+
immutable=immutable, name="Cycle graph")
|
378
|
+
if n == 1:
|
379
|
+
G.set_pos({0: (0, 0)})
|
380
|
+
else:
|
381
|
+
G._circle_embedding(list(range(n)), angle=pi/2)
|
382
|
+
return G
|
383
|
+
|
384
|
+
|
385
|
+
def CompleteGraph(n, immutable=False):
|
386
|
+
r"""
|
387
|
+
Return a complete graph on `n` nodes.
|
388
|
+
|
389
|
+
A Complete Graph is a graph in which all nodes are connected to all
|
390
|
+
other nodes.
|
391
|
+
|
392
|
+
INPUT:
|
393
|
+
|
394
|
+
- ``n`` -- nonnegative integer; the number of vertices of the complete graph
|
395
|
+
|
396
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
397
|
+
immutable or a mutable graph
|
398
|
+
|
399
|
+
PLOTTING: Upon construction, the position dictionary is filled to
|
400
|
+
override the spring-layout algorithm. By convention, each complete
|
401
|
+
graph will be displayed with the first (0) node at the top, with
|
402
|
+
the rest following in a counterclockwise manner.
|
403
|
+
|
404
|
+
In the complete graph, there is a big difference visually in using
|
405
|
+
the spring-layout algorithm vs. the position dictionary used in
|
406
|
+
this constructor. The position dictionary flattens the graph,
|
407
|
+
making it clear which nodes an edge is connected to. But the
|
408
|
+
complete graph offers a good example of how the spring-layout
|
409
|
+
works. The edges push outward (everything is connected), causing
|
410
|
+
the graph to appear as a 3-dimensional pointy ball. (See examples
|
411
|
+
below).
|
412
|
+
|
413
|
+
EXAMPLES:
|
414
|
+
|
415
|
+
We view many Complete graphs with a Sage Graphics Array, first with this
|
416
|
+
constructor (i.e., the position dictionary filled)::
|
417
|
+
|
418
|
+
sage: # needs sage.plot
|
419
|
+
sage: g = []
|
420
|
+
sage: j = []
|
421
|
+
sage: for i in range(9):
|
422
|
+
....: k = graphs.CompleteGraph(i+3)
|
423
|
+
....: g.append(k)
|
424
|
+
sage: for i in range(3):
|
425
|
+
....: n = []
|
426
|
+
....: for m in range(3):
|
427
|
+
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
|
428
|
+
....: j.append(n)
|
429
|
+
sage: G = graphics_array(j)
|
430
|
+
sage: G.show() # long time
|
431
|
+
|
432
|
+
We compare to plotting with the spring-layout algorithm::
|
433
|
+
|
434
|
+
sage: # needs networkx sage.plot
|
435
|
+
sage: import networkx
|
436
|
+
sage: g = []
|
437
|
+
sage: j = []
|
438
|
+
sage: for i in range(9):
|
439
|
+
....: spr = networkx.complete_graph(i+3)
|
440
|
+
....: k = Graph(spr)
|
441
|
+
....: g.append(k)
|
442
|
+
sage: for i in range(3):
|
443
|
+
....: n = []
|
444
|
+
....: for m in range(3):
|
445
|
+
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
|
446
|
+
....: j.append(n)
|
447
|
+
sage: G = graphics_array(j)
|
448
|
+
sage: G.show() # long time
|
449
|
+
|
450
|
+
Compare the constructors (results will vary)::
|
451
|
+
|
452
|
+
sage: # needs networkx
|
453
|
+
sage: import networkx
|
454
|
+
sage: t = cputime()
|
455
|
+
sage: n = networkx.complete_graph(389); spring389 = Graph(n)
|
456
|
+
sage: cputime(t) # random
|
457
|
+
0.59203700000000126
|
458
|
+
sage: t = cputime()
|
459
|
+
sage: posdict389 = graphs.CompleteGraph(389)
|
460
|
+
sage: cputime(t) # random
|
461
|
+
0.6680419999999998
|
462
|
+
|
463
|
+
We compare plotting::
|
464
|
+
|
465
|
+
sage: # needs networkx
|
466
|
+
sage: import networkx
|
467
|
+
sage: n = networkx.complete_graph(23)
|
468
|
+
sage: spring23 = Graph(n)
|
469
|
+
sage: posdict23 = graphs.CompleteGraph(23)
|
470
|
+
sage: spring23.show() # long time # needs sage.plot
|
471
|
+
sage: posdict23.show() # long time # needs sage.plot
|
472
|
+
|
473
|
+
TESTS:
|
474
|
+
|
475
|
+
Check the behavior of parameter ``immutable``::
|
476
|
+
|
477
|
+
sage: graphs.CompleteGraph(4, immutable=True).is_immutable()
|
478
|
+
True
|
479
|
+
"""
|
480
|
+
from itertools import combinations
|
481
|
+
G = Graph([range(n), combinations(range(n), 2)],
|
482
|
+
format='vertices_and_edges', immutable=immutable,
|
483
|
+
name="Complete graph")
|
484
|
+
if n == 1:
|
485
|
+
G.set_pos({0: (0, 0)})
|
486
|
+
else:
|
487
|
+
G._circle_embedding(list(range(n)), angle=pi/2)
|
488
|
+
return G
|
489
|
+
|
490
|
+
|
491
|
+
def CorrelationGraph(seqs, alpha, include_anticorrelation, immutable=False):
|
492
|
+
r"""
|
493
|
+
Return a correlation graph with a node per sequence in ``seqs``.
|
494
|
+
|
495
|
+
Edges are added between nodes where the corresponding sequences have a
|
496
|
+
correlation coefficient greater than alpha.
|
497
|
+
|
498
|
+
If ``include_anticorrelation`` is ``True``, then edges are also added
|
499
|
+
between nodes with correlation coefficient less than ``-alpha``.
|
500
|
+
|
501
|
+
INPUT:
|
502
|
+
|
503
|
+
- ``seqs`` -- list of sequences, that is a list of lists
|
504
|
+
|
505
|
+
- ``alpha`` -- float; threshold on the correlation coefficient between two
|
506
|
+
sequences for adding an edge
|
507
|
+
|
508
|
+
- ``include_anticorrelation`` -- boolean; whether to add edges between nodes
|
509
|
+
with correlation coefficient less than ``-alpha`` or not
|
510
|
+
|
511
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
512
|
+
immutable or a mutable graph
|
513
|
+
|
514
|
+
EXAMPLES::
|
515
|
+
|
516
|
+
sage: # needs numpy
|
517
|
+
sage: from sage.graphs.generators.basic import CorrelationGraph
|
518
|
+
sage: data = [[1,2,3], [4,5,6], [7,8,9999]]
|
519
|
+
sage: CG1 = CorrelationGraph(data, 0.9, False)
|
520
|
+
sage: CG2 = CorrelationGraph(data, 0.9, True)
|
521
|
+
sage: CG3 = CorrelationGraph(data, 0.1, True)
|
522
|
+
sage: CG1.edges(sort=False)
|
523
|
+
[(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)]
|
524
|
+
sage: CG2.edges(sort=False)
|
525
|
+
[(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)]
|
526
|
+
sage: CG3.edges(sort=False)
|
527
|
+
[(0, 0, None), (0, 1, None), (0, 2, None), (1, 1, None), (1, 2, None), (2, 2, None)]
|
528
|
+
|
529
|
+
TESTS:
|
530
|
+
|
531
|
+
Check the behavior of parameter ``immutable``::
|
532
|
+
|
533
|
+
sage: # needs numpy
|
534
|
+
sage: from sage.graphs.generators.basic import CorrelationGraph
|
535
|
+
sage: CorrelationGraph(data, 0.9, False, immutable=True).is_immutable()
|
536
|
+
True
|
537
|
+
sage: CorrelationGraph(data, 0.9, True, immutable=True).is_immutable()
|
538
|
+
True
|
539
|
+
"""
|
540
|
+
from numpy import corrcoef
|
541
|
+
from sage.matrix.constructor import Matrix
|
542
|
+
|
543
|
+
# compute pairwise correlation coefficients
|
544
|
+
corrs = corrcoef(seqs)
|
545
|
+
|
546
|
+
# compare against alpha to get adjacency matrix
|
547
|
+
if include_anticorrelation:
|
548
|
+
boolean_adjacency_matrix = abs(corrs) >= alpha
|
549
|
+
else:
|
550
|
+
boolean_adjacency_matrix = corrs >= alpha
|
551
|
+
|
552
|
+
adjacency_matrix = Matrix(boolean_adjacency_matrix.astype(int))
|
553
|
+
|
554
|
+
# call graph constructor
|
555
|
+
return Graph(adjacency_matrix, format='adjacency_matrix',
|
556
|
+
immutable=immutable, name="Correlation Graph")
|
557
|
+
|
558
|
+
|
559
|
+
def CompleteBipartiteGraph(p, q, set_position=True, immutable=False, name=None):
|
560
|
+
r"""
|
561
|
+
Return a Complete Bipartite Graph on `p + q` vertices.
|
562
|
+
|
563
|
+
A Complete Bipartite Graph is a graph with its vertices partitioned into two
|
564
|
+
groups, `V_1 = \{0,...,p-1\}` and `V_2 = \{p,...,p+q-1\}`. Each `u \in
|
565
|
+
V_1` is connected to every `v \in V_2`.
|
566
|
+
|
567
|
+
INPUT:
|
568
|
+
|
569
|
+
- ``p``, ``q`` -- number of vertices in each side
|
570
|
+
|
571
|
+
- ``set_position`` -- boolean (default: ``True``); if set to ``True``, we
|
572
|
+
assign positions to the vertices so that the set of cardinality `p` is
|
573
|
+
on the line `y=1` and the set of cardinality `q` is on the line `y=0`.
|
574
|
+
|
575
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
576
|
+
immutable or a mutable graph
|
577
|
+
|
578
|
+
- ``name`` -- string (default: ``None``); used as the name of the returned
|
579
|
+
graph when set
|
580
|
+
|
581
|
+
PLOTTING: Upon construction, the position dictionary is filled to override
|
582
|
+
the spring-layout algorithm. By convention, each complete bipartite graph
|
583
|
+
will be displayed with the first `p` nodes on the top row (at `y=1`) from
|
584
|
+
left to right. The remaining `q` nodes appear at `y=0`, also from left to
|
585
|
+
right. The shorter row (partition with fewer nodes) is stretched to the same
|
586
|
+
length as the longer row, unless the shorter row has 1 node; in which case
|
587
|
+
it is centered. The `x` values in the plot are in domain `[0, \max(p, q)]`.
|
588
|
+
|
589
|
+
In the Complete Bipartite graph, there is a visual difference in using the
|
590
|
+
spring-layout algorithm vs. the position dictionary used in this
|
591
|
+
constructor. The position dictionary flattens the graph and separates the
|
592
|
+
partitioned nodes, making it clear which nodes an edge is connected to. The
|
593
|
+
Complete Bipartite graph plotted with the spring-layout algorithm tends to
|
594
|
+
center the nodes in `p` (see ``spring_med`` in examples below), thus
|
595
|
+
overlapping its nodes and edges, making it typically hard to decipher.
|
596
|
+
|
597
|
+
Filling the position dictionary in advance adds `O(n)` to the constructor.
|
598
|
+
Feel free to race the constructors below in the examples section. The much
|
599
|
+
larger difference is the time added by the spring-layout algorithm when
|
600
|
+
plotting. (Also shown in the example below). The spring model is typically
|
601
|
+
described as `O(n^3)`, as appears to be the case in the NetworkX source
|
602
|
+
code.
|
603
|
+
|
604
|
+
EXAMPLES:
|
605
|
+
|
606
|
+
Two ways of constructing the complete bipartite graph, using different
|
607
|
+
layout algorithms::
|
608
|
+
|
609
|
+
sage: # needs networkx
|
610
|
+
sage: import networkx
|
611
|
+
sage: n = networkx.complete_bipartite_graph(389, 157) # long time
|
612
|
+
sage: spring_big = Graph(n) # long time
|
613
|
+
sage: posdict_big = graphs.CompleteBipartiteGraph(389, 157) # long time
|
614
|
+
|
615
|
+
Compare the plotting::
|
616
|
+
|
617
|
+
sage: n = networkx.complete_bipartite_graph(11, 17) # needs networkx
|
618
|
+
sage: spring_med = Graph(n) # needs networkx
|
619
|
+
sage: posdict_med = graphs.CompleteBipartiteGraph(11, 17)
|
620
|
+
|
621
|
+
Notice here how the spring-layout tends to center the nodes of `n1`::
|
622
|
+
|
623
|
+
sage: spring_med.show() # long time # needs networkx
|
624
|
+
sage: posdict_med.show() # long time # needs sage.plot
|
625
|
+
|
626
|
+
View many complete bipartite graphs with a Sage Graphics Array, with this
|
627
|
+
constructor (i.e., the position dictionary filled)::
|
628
|
+
|
629
|
+
sage: g = []
|
630
|
+
sage: j = []
|
631
|
+
sage: for i in range(9):
|
632
|
+
....: k = graphs.CompleteBipartiteGraph(i+1,4)
|
633
|
+
....: g.append(k)
|
634
|
+
sage: for i in range(3): # needs sage.plot
|
635
|
+
....: n = []
|
636
|
+
....: for m in range(3):
|
637
|
+
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
|
638
|
+
....: j.append(n)
|
639
|
+
sage: G = graphics_array(j) # needs sage.plot
|
640
|
+
sage: G.show() # long time # needs sage.plot
|
641
|
+
|
642
|
+
We compare to plotting with the spring-layout algorithm::
|
643
|
+
|
644
|
+
sage: # needs networkx sage.plot
|
645
|
+
sage: g = []
|
646
|
+
sage: j = []
|
647
|
+
sage: for i in range(9):
|
648
|
+
....: spr = networkx.complete_bipartite_graph(i+1,4)
|
649
|
+
....: k = Graph(spr)
|
650
|
+
....: g.append(k)
|
651
|
+
sage: for i in range(3):
|
652
|
+
....: n = []
|
653
|
+
....: for m in range(3):
|
654
|
+
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
|
655
|
+
....: j.append(n)
|
656
|
+
sage: G = graphics_array(j)
|
657
|
+
sage: G.show() # long time
|
658
|
+
|
659
|
+
:issue:`12155`::
|
660
|
+
|
661
|
+
sage: graphs.CompleteBipartiteGraph(5,6).complement()
|
662
|
+
complement(Complete bipartite graph of order 5+6): Graph on 11 vertices
|
663
|
+
|
664
|
+
TESTS:
|
665
|
+
|
666
|
+
Prevent negative dimensions (:issue:`18530`)::
|
667
|
+
|
668
|
+
sage: graphs.CompleteBipartiteGraph(-1,1)
|
669
|
+
Traceback (most recent call last):
|
670
|
+
...
|
671
|
+
ValueError: the arguments p(=-1) and q(=1) must be positive integers
|
672
|
+
sage: graphs.CompleteBipartiteGraph(1,-1)
|
673
|
+
Traceback (most recent call last):
|
674
|
+
...
|
675
|
+
ValueError: the arguments p(=1) and q(=-1) must be positive integers
|
676
|
+
|
677
|
+
Check the behavior of parameter ``immutable``::
|
678
|
+
|
679
|
+
sage: graphs.CompleteBipartiteGraph(1, 2, immutable=True).is_immutable()
|
680
|
+
True
|
681
|
+
|
682
|
+
Check the behavior of parameter ``name``::
|
683
|
+
|
684
|
+
sage: graphs.CompleteBipartiteGraph(1, 2, name='foo')
|
685
|
+
foo: Graph on 3 vertices
|
686
|
+
"""
|
687
|
+
if p < 0 or q < 0:
|
688
|
+
raise ValueError('the arguments p(={}) and q(={}) must be positive integers'.format(p, q))
|
689
|
+
|
690
|
+
name = f"Complete bipartite graph of order {p}+{q}" if name is None else name
|
691
|
+
edges = ((i, j) for i in range(p) for j in range(p, p + q))
|
692
|
+
G = Graph([range(p + q), edges], format='vertices_and_edges',
|
693
|
+
immutable=immutable, name=name)
|
694
|
+
|
695
|
+
# We now assign positions to vertices:
|
696
|
+
# - vertices 0,..,p-1 are placed on the line (0, 1) to (max(p, q), 1)
|
697
|
+
# - vertices p,..,p+q-1 are placed on the line (0, 0) to (max(p, q), 0)
|
698
|
+
# If p (or q) is 1, the vertex is centered in the line.
|
699
|
+
if set_position:
|
700
|
+
nmax = max(p, q)
|
701
|
+
G._line_embedding(list(range(p)), first=(0, 1), last=(nmax, 1))
|
702
|
+
G._line_embedding(list(range(p, p + q)), first=(0, 0), last=(nmax, 0))
|
703
|
+
|
704
|
+
return G
|
705
|
+
|
706
|
+
|
707
|
+
def CompleteMultipartiteGraph(L, immutable=False):
|
708
|
+
r"""
|
709
|
+
Return a complete multipartite graph.
|
710
|
+
|
711
|
+
INPUT:
|
712
|
+
|
713
|
+
- ``L`` -- list of integers; the respective sizes of the components
|
714
|
+
|
715
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
716
|
+
immutable or a mutable graph
|
717
|
+
|
718
|
+
PLOTTING: Produce a layout of the vertices so that vertices in the same
|
719
|
+
vertex set are adjacent and clearly separated from vertices in other vertex
|
720
|
+
sets.
|
721
|
+
|
722
|
+
This is done by calculating the vertices of an `r`-gon then calculating the
|
723
|
+
slope between adjacent vertices. We then 'walk' around the `r`-gon placing
|
724
|
+
graph vertices in regular intervals between adjacent vertices of the
|
725
|
+
`r`-gon.
|
726
|
+
|
727
|
+
Makes a nicely organized graph like in this picture:
|
728
|
+
https://commons.wikimedia.org/wiki/File:Turan_13-4.svg
|
729
|
+
|
730
|
+
EXAMPLES:
|
731
|
+
|
732
|
+
A complete tripartite graph with sets of sizes `5, 6, 8`::
|
733
|
+
|
734
|
+
sage: g = graphs.CompleteMultipartiteGraph([5, 6, 8]); g
|
735
|
+
Multipartite Graph with set sizes [5, 6, 8]: Graph on 19 vertices
|
736
|
+
|
737
|
+
It clearly has a chromatic number of 3::
|
738
|
+
|
739
|
+
sage: g.chromatic_number() # needs cliquer
|
740
|
+
3
|
741
|
+
|
742
|
+
TESTS:
|
743
|
+
|
744
|
+
Prevent negative dimensions::
|
745
|
+
|
746
|
+
sage: graphs.CompleteMultipartiteGraph([1, -1, 2])
|
747
|
+
Traceback (most recent call last):
|
748
|
+
...
|
749
|
+
ValueError: the sizes of the components must be positive integers
|
750
|
+
|
751
|
+
Check the behaviour of parameter ``immutable``::
|
752
|
+
|
753
|
+
sage: graphs.CompleteMultipartiteGraph([1], immutable=True).is_immutable()
|
754
|
+
True
|
755
|
+
sage: graphs.CompleteMultipartiteGraph([1, 2], immutable=True).is_immutable()
|
756
|
+
True
|
757
|
+
sage: graphs.CompleteMultipartiteGraph([1, 2, 3], immutable=True).is_immutable()
|
758
|
+
True
|
759
|
+
"""
|
760
|
+
if any(p < 0 for p in L):
|
761
|
+
raise ValueError("the sizes of the components must be positive integers")
|
762
|
+
|
763
|
+
r = len(L) # getting the number of partitions
|
764
|
+
name = "Multipartite Graph with set sizes {}".format(L)
|
765
|
+
|
766
|
+
if not r:
|
767
|
+
return Graph(name=name, immutable=immutable)
|
768
|
+
if r == 1:
|
769
|
+
g = Graph(L[0], immutable=immutable, name=name)
|
770
|
+
g._line_embedding(range(L[0]), first=(0, 0), last=(L[0], 0))
|
771
|
+
return g
|
772
|
+
if r == 2:
|
773
|
+
return CompleteBipartiteGraph(L[0], L[1], immutable=immutable, name=name)
|
774
|
+
|
775
|
+
# This position code gives bad results on bipartite or isolated graphs
|
776
|
+
points = [(cos(2 * pi * i / r), sin(2 * pi * i / r)) for i in range(r)]
|
777
|
+
slopes = [(points[(i + 1) % r][0] - points[i % r][0],
|
778
|
+
points[(i + 1) % r][1] - points[i % r][1]) for i in range(r)]
|
779
|
+
|
780
|
+
counter = 0
|
781
|
+
parts = []
|
782
|
+
positions = {}
|
783
|
+
for i, size in enumerate(L):
|
784
|
+
parts.append(list(range(counter, counter + size)))
|
785
|
+
vertex_set_size = size + 1
|
786
|
+
for j in range(1, vertex_set_size):
|
787
|
+
x = points[i][0] + slopes[i][0] * j / vertex_set_size
|
788
|
+
y = points[i][1] + slopes[i][1] * j / vertex_set_size
|
789
|
+
positions[counter] = (x, y)
|
790
|
+
counter += 1
|
791
|
+
|
792
|
+
from itertools import combinations
|
793
|
+
edges = ((a, b) for A, B in combinations(parts, 2) for a in A for b in B)
|
794
|
+
return Graph([range(counter), edges], format='vertices_and_edges',
|
795
|
+
immutable=immutable, pos=positions, name=name)
|
796
|
+
|
797
|
+
|
798
|
+
def DiamondGraph(immutable=False):
|
799
|
+
"""
|
800
|
+
Return a diamond graph with 4 nodes.
|
801
|
+
|
802
|
+
A diamond graph is a square with one pair of diagonal nodes connected.
|
803
|
+
|
804
|
+
INPUT:
|
805
|
+
|
806
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
807
|
+
immutable or a mutable graph
|
808
|
+
|
809
|
+
PLOTTING: Upon construction, the position dictionary is filled to override
|
810
|
+
the spring-layout algorithm. By convention, the diamond graph is drawn as a
|
811
|
+
diamond, with the first node on top, second on the left, third on the right,
|
812
|
+
and fourth on the bottom; with the second and third node connected.
|
813
|
+
|
814
|
+
EXAMPLES:
|
815
|
+
|
816
|
+
Construct and show a diamond graph::
|
817
|
+
|
818
|
+
sage: g = graphs.DiamondGraph()
|
819
|
+
sage: g.show() # long time # needs sage.plot
|
820
|
+
|
821
|
+
TESTS:
|
822
|
+
|
823
|
+
Check the behavior of parameter ``immutable``::
|
824
|
+
|
825
|
+
sage: graphs.DiamondGraph(immutable=True).is_immutable()
|
826
|
+
True
|
827
|
+
"""
|
828
|
+
pos_dict = {0: (0, 1), 1: (-1, 0), 2: (1, 0), 3: (0, -1)}
|
829
|
+
edges = [(0, 1), (0, 2), (1, 2), (1, 3), (2, 3)]
|
830
|
+
return Graph([range(4), edges], format='vertices_and_edges',
|
831
|
+
immutable=immutable, pos=pos_dict, name="Diamond Graph")
|
832
|
+
|
833
|
+
|
834
|
+
def GemGraph(immutable=False):
|
835
|
+
"""
|
836
|
+
Return a gem graph with 5 nodes.
|
837
|
+
|
838
|
+
A gem graph is a fan graph (4,1).
|
839
|
+
|
840
|
+
INPUT:
|
841
|
+
|
842
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
843
|
+
immutable or a mutable graph
|
844
|
+
|
845
|
+
PLOTTING: Upon construction, the position dictionary is filled to override
|
846
|
+
the spring-layout algorithm. By convention, the gem graph is drawn as a gem,
|
847
|
+
with the sharp part on the bottom.
|
848
|
+
|
849
|
+
EXAMPLES:
|
850
|
+
|
851
|
+
Construct and show a gem graph::
|
852
|
+
|
853
|
+
sage: g = graphs.GemGraph()
|
854
|
+
sage: g.show() # long time # needs sage.plot
|
855
|
+
|
856
|
+
TESTS:
|
857
|
+
|
858
|
+
Check the behavior of parameter ``immutable``::
|
859
|
+
|
860
|
+
sage: graphs.GemGraph(immutable=True).is_immutable()
|
861
|
+
True
|
862
|
+
"""
|
863
|
+
pos_dict = {0: (0.5, 0), 1: (0, 0.75), 2: (0.25, 1), 3: (0.75, 1), 4: (1, 0.75)}
|
864
|
+
edges = [(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (2, 3), (3, 4)]
|
865
|
+
return Graph([range(5), edges], format='vertices_and_edges',
|
866
|
+
immutable=immutable, pos=pos_dict, name="Gem Graph")
|
867
|
+
|
868
|
+
|
869
|
+
def ForkGraph(immutable=False):
|
870
|
+
"""
|
871
|
+
Return a fork graph with 5 nodes.
|
872
|
+
|
873
|
+
A fork graph, sometimes also called chair graph, is 5 vertex tree.
|
874
|
+
|
875
|
+
INPUT:
|
876
|
+
|
877
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
878
|
+
immutable or a mutable graph
|
879
|
+
|
880
|
+
PLOTTING: Upon construction, the position dictionary is filled to override
|
881
|
+
the spring-layout algorithm. By convention, the fork graph is drawn as a
|
882
|
+
fork, with the sharp part on the bottom.
|
883
|
+
|
884
|
+
EXAMPLES:
|
885
|
+
|
886
|
+
Construct and show a fork graph::
|
887
|
+
|
888
|
+
sage: g = graphs.ForkGraph()
|
889
|
+
sage: g.show() # long time # needs sage.plot
|
890
|
+
|
891
|
+
TESTS:
|
892
|
+
|
893
|
+
Check the behavior of parameter ``immutable``::
|
894
|
+
|
895
|
+
sage: graphs.ForkGraph(immutable=True).is_immutable()
|
896
|
+
True
|
897
|
+
"""
|
898
|
+
pos_dict = {0: (0, 0), 1: (1, 0), 2: (0, 1), 3: (1, 1), 4: (0, 2)}
|
899
|
+
edges = [(0, 2), (2, 3), (3, 1), (2, 4)]
|
900
|
+
return Graph([range(5), edges], format='vertices_and_edges',
|
901
|
+
immutable=immutable, pos=pos_dict, name="Fork Graph")
|
902
|
+
|
903
|
+
|
904
|
+
def DartGraph(immutable=False):
|
905
|
+
"""
|
906
|
+
Return a dart graph with 5 nodes.
|
907
|
+
|
908
|
+
INPUT:
|
909
|
+
|
910
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
911
|
+
immutable or a mutable graph
|
912
|
+
|
913
|
+
PLOTTING: Upon construction, the position dictionary is filled to override
|
914
|
+
the spring-layout algorithm. By convention, the dart graph is drawn as a
|
915
|
+
dart, with the sharp part on the bottom.
|
916
|
+
|
917
|
+
EXAMPLES:
|
918
|
+
|
919
|
+
Construct and show a dart graph::
|
920
|
+
|
921
|
+
sage: g = graphs.DartGraph()
|
922
|
+
sage: g.show() # long time # needs sage.plot
|
923
|
+
|
924
|
+
TESTS:
|
925
|
+
|
926
|
+
Check the behavior of parameter ``immutable``::
|
927
|
+
|
928
|
+
sage: graphs.DartGraph(immutable=True).is_immutable()
|
929
|
+
True
|
930
|
+
"""
|
931
|
+
pos_dict = {0: (0, 1), 1: (-1, 0), 2: (1, 0), 3: (0, -1), 4: (0, 0)}
|
932
|
+
edges = [(0, 1), (0, 2), (1, 4), (2, 4), (0, 4), (3, 4)]
|
933
|
+
return Graph([range(5), edges], format='vertices_and_edges',
|
934
|
+
immutable=immutable, pos=pos_dict, name="Dart Graph")
|
935
|
+
|
936
|
+
|
937
|
+
def EmptyGraph(immutable=False):
|
938
|
+
"""
|
939
|
+
Return an empty graph (0 nodes and 0 edges).
|
940
|
+
|
941
|
+
This is useful for constructing graphs by adding edges and vertices
|
942
|
+
individually or in a loop.
|
943
|
+
|
944
|
+
INPUT:
|
945
|
+
|
946
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
947
|
+
immutable or a mutable graph
|
948
|
+
|
949
|
+
PLOTTING: When plotting, this graph will use the default
|
950
|
+
spring-layout algorithm, unless a position dictionary is
|
951
|
+
specified.
|
952
|
+
|
953
|
+
EXAMPLES:
|
954
|
+
|
955
|
+
Add one vertex to an empty graph and then show::
|
956
|
+
|
957
|
+
sage: empty1 = graphs.EmptyGraph()
|
958
|
+
sage: empty1.add_vertex()
|
959
|
+
0
|
960
|
+
sage: empty1.show() # long time # needs sage.plot
|
961
|
+
|
962
|
+
Use for loops to build a graph from an empty graph::
|
963
|
+
|
964
|
+
sage: empty2 = graphs.EmptyGraph()
|
965
|
+
sage: for i in range(5):
|
966
|
+
....: empty2.add_vertex() # add 5 nodes, labeled 0-4
|
967
|
+
0
|
968
|
+
1
|
969
|
+
2
|
970
|
+
3
|
971
|
+
4
|
972
|
+
sage: for i in range(3):
|
973
|
+
....: empty2.add_edge(i,i+1) # add edges {[0:1],[1:2],[2:3]}
|
974
|
+
sage: for i in range(1, 4):
|
975
|
+
....: empty2.add_edge(4,i) # add edges {[1:4],[2:4],[3:4]}
|
976
|
+
sage: empty2.show() # long time # needs sage.plot
|
977
|
+
|
978
|
+
TESTS:
|
979
|
+
|
980
|
+
Check the behavior of parameter ``immutable``::
|
981
|
+
|
982
|
+
sage: graphs.EmptyGraph(immutable=True).is_immutable()
|
983
|
+
True
|
984
|
+
"""
|
985
|
+
return Graph(sparse=True, immutable=immutable)
|
986
|
+
|
987
|
+
|
988
|
+
def ToroidalGrid2dGraph(p, q, immutable=False):
|
989
|
+
r"""
|
990
|
+
Return a toroidal 2-dimensional grid graph with `p \times q` nodes (`p` rows
|
991
|
+
and `q` columns).
|
992
|
+
|
993
|
+
The toroidal 2-dimensional grid with parameters `p,q` is the 2-dimensional
|
994
|
+
grid graph with identical parameters to which are added the edges
|
995
|
+
`((i, 0), (i, q - 1))` and `((0, i), (p - 1, i))`.
|
996
|
+
|
997
|
+
INPUT:
|
998
|
+
|
999
|
+
- ``p, q`` -- nonnegative integers; the sides of the toroidal grid
|
1000
|
+
|
1001
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
1002
|
+
immutable or a mutable graph
|
1003
|
+
|
1004
|
+
EXAMPLES:
|
1005
|
+
|
1006
|
+
The toroidal 2-dimensional grid is a regular graph, while the usual
|
1007
|
+
2-dimensional grid is not ::
|
1008
|
+
|
1009
|
+
sage: tgrid = graphs.ToroidalGrid2dGraph(8,9)
|
1010
|
+
sage: print(tgrid)
|
1011
|
+
Toroidal 2D Grid Graph with parameters 8,9
|
1012
|
+
sage: grid = graphs.Grid2dGraph(8,9)
|
1013
|
+
sage: grid.is_regular()
|
1014
|
+
False
|
1015
|
+
sage: tgrid.is_regular()
|
1016
|
+
True
|
1017
|
+
|
1018
|
+
TESTS:
|
1019
|
+
|
1020
|
+
Check the behavior of parameter ``immutable``::
|
1021
|
+
|
1022
|
+
sage: graphs.ToroidalGrid2dGraph(2, 3, immutable=True).is_immutable()
|
1023
|
+
True
|
1024
|
+
"""
|
1025
|
+
name = f"Toroidal 2D Grid Graph with parameters {p},{q}"
|
1026
|
+
g = Grid2dGraph(p, q, set_positions=True, immutable=False)
|
1027
|
+
g.name(name)
|
1028
|
+
|
1029
|
+
g.add_edges([((i, 0), (i, q - 1)) for i in range(p)])
|
1030
|
+
g.add_edges([((0, i), (p - 1, i)) for i in range(q)])
|
1031
|
+
|
1032
|
+
pos = g._pos
|
1033
|
+
p += 0.
|
1034
|
+
q += 0.
|
1035
|
+
uf = (p / 2) * (p / 2)
|
1036
|
+
vf = (q / 2) * (q / 2)
|
1037
|
+
for u, v in g:
|
1038
|
+
x, y = pos[u, v]
|
1039
|
+
x += 0.25 * (1.0 + u * (u - p + 1) / uf)
|
1040
|
+
y += 0.25 * (1.0 + v * (v - q + 1) / vf)
|
1041
|
+
pos[u, v] = (x, y)
|
1042
|
+
|
1043
|
+
if immutable:
|
1044
|
+
return Graph(g, immutable=True, pos=g.get_pos(), name=name)
|
1045
|
+
return g
|
1046
|
+
|
1047
|
+
|
1048
|
+
def Toroidal6RegularGrid2dGraph(p, q, immutable=False):
|
1049
|
+
r"""
|
1050
|
+
Return a toroidal 6-regular grid.
|
1051
|
+
|
1052
|
+
The toroidal 6-regular grid is a 6-regular graph on `p \times q` vertices
|
1053
|
+
and its elements have coordinates `(i, j)` for `i \in \{0...p-1\}` and
|
1054
|
+
`j \in \{0...q-1\}`.
|
1055
|
+
|
1056
|
+
Its edges are those of the :meth:`ToroidalGrid2dGraph`, to which are added
|
1057
|
+
the edges between `(i, j)` and `((i + 1) \% p, (j + 1) \% q)`.
|
1058
|
+
|
1059
|
+
INPUT:
|
1060
|
+
|
1061
|
+
- ``p``, ``q`` -- integers
|
1062
|
+
|
1063
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
1064
|
+
immutable or a mutable graph
|
1065
|
+
|
1066
|
+
EXAMPLES:
|
1067
|
+
|
1068
|
+
The toroidal 6-regular grid on `25` elements::
|
1069
|
+
|
1070
|
+
sage: g = graphs.Toroidal6RegularGrid2dGraph(5,5)
|
1071
|
+
sage: g.is_regular(k=6)
|
1072
|
+
True
|
1073
|
+
sage: g.is_vertex_transitive() # needs sage.groups
|
1074
|
+
True
|
1075
|
+
sage: g.line_graph().is_vertex_transitive() # needs sage.groups
|
1076
|
+
True
|
1077
|
+
sage: g.automorphism_group().cardinality() # needs sage.groups
|
1078
|
+
300
|
1079
|
+
sage: g.is_hamiltonian() # needs sage.numerical.mip
|
1080
|
+
True
|
1081
|
+
|
1082
|
+
TESTS:
|
1083
|
+
|
1084
|
+
Senseless input::
|
1085
|
+
|
1086
|
+
sage: graphs.Toroidal6RegularGrid2dGraph(5,2)
|
1087
|
+
Traceback (most recent call last):
|
1088
|
+
...
|
1089
|
+
ValueError: parameters p and q must be integers larger than 3
|
1090
|
+
sage: graphs.Toroidal6RegularGrid2dGraph(2,0)
|
1091
|
+
Traceback (most recent call last):
|
1092
|
+
...
|
1093
|
+
ValueError: parameters p and q must be integers larger than 3
|
1094
|
+
|
1095
|
+
Check the behavior of parameter ``immutable``::
|
1096
|
+
|
1097
|
+
sage: graphs.Toroidal6RegularGrid2dGraph(4, 4, immutable=True).is_immutable()
|
1098
|
+
True
|
1099
|
+
"""
|
1100
|
+
if p <= 3 or q <= 3:
|
1101
|
+
raise ValueError("parameters p and q must be integers larger than 3")
|
1102
|
+
|
1103
|
+
g = ToroidalGrid2dGraph(p, q, immutable=False)
|
1104
|
+
for u, v in g:
|
1105
|
+
g.add_edge((u, v), ((u + 1) % p, (v + 1) % q))
|
1106
|
+
|
1107
|
+
name = f"Toroidal Hexagonal Grid graph on {p}x{q} elements"
|
1108
|
+
if immutable:
|
1109
|
+
return Graph(g, immutable=True, pos=g.get_pos(), name=name)
|
1110
|
+
g.name(name)
|
1111
|
+
return g
|
1112
|
+
|
1113
|
+
|
1114
|
+
def Grid2dGraph(p, q, set_positions=True, immutable=False, name=None):
|
1115
|
+
r"""
|
1116
|
+
Return a `2`-dimensional grid graph with `p \times q` nodes (`p` rows and
|
1117
|
+
`q` columns).
|
1118
|
+
|
1119
|
+
A 2d grid graph resembles a `2` dimensional grid. All inner nodes are
|
1120
|
+
connected to their `4` neighbors. Outer (non-corner) nodes are connected to
|
1121
|
+
their `3` neighbors. Corner nodes are connected to their 2 neighbors.
|
1122
|
+
|
1123
|
+
INPUT:
|
1124
|
+
|
1125
|
+
- ``p``, ``q`` -- two positive integers
|
1126
|
+
|
1127
|
+
- ``set_positions`` -- boolean (default: ``True``); whether to set the
|
1128
|
+
position of the nodes
|
1129
|
+
|
1130
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
1131
|
+
immutable or a mutable graph
|
1132
|
+
|
1133
|
+
- ``name`` -- string (default: ``None``); used as the name of the returned
|
1134
|
+
graph when set
|
1135
|
+
|
1136
|
+
PLOTTING: Upon construction, the position dictionary is filled to override
|
1137
|
+
the spring-layout algorithm. By convention, nodes are labelled in (row,
|
1138
|
+
column) pairs with `(0, 0)` in the top left corner. Edges will always be
|
1139
|
+
horizontal and vertical - another advantage of filling the position
|
1140
|
+
dictionary.
|
1141
|
+
|
1142
|
+
EXAMPLES:
|
1143
|
+
|
1144
|
+
Construct and show a grid 2d graph Rows = `5`, Columns = `7`::
|
1145
|
+
|
1146
|
+
sage: g = graphs.Grid2dGraph(5,7)
|
1147
|
+
sage: g.show() # long time # needs sage.plot
|
1148
|
+
|
1149
|
+
TESTS:
|
1150
|
+
|
1151
|
+
Senseless input::
|
1152
|
+
|
1153
|
+
sage: graphs.Grid2dGraph(5,0)
|
1154
|
+
Traceback (most recent call last):
|
1155
|
+
...
|
1156
|
+
ValueError: parameters p and q must be positive integers
|
1157
|
+
sage: graphs.Grid2dGraph(-1,0)
|
1158
|
+
Traceback (most recent call last):
|
1159
|
+
...
|
1160
|
+
ValueError: parameters p and q must be positive integers
|
1161
|
+
|
1162
|
+
The graph name contains the dimension::
|
1163
|
+
|
1164
|
+
sage: g = graphs.Grid2dGraph(5,7)
|
1165
|
+
sage: g.name()
|
1166
|
+
'2D Grid Graph for [5, 7]'
|
1167
|
+
|
1168
|
+
Check the behavior of parameter ``ìmmutable``::
|
1169
|
+
|
1170
|
+
sage: graphs.Grid2dGraph(2, 3, immutable=True).is_immutable()
|
1171
|
+
True
|
1172
|
+
|
1173
|
+
Check the behavior of parameter ``name``::
|
1174
|
+
|
1175
|
+
sage: graphs.Grid2dGraph(2, 3, name='foo')
|
1176
|
+
foo: Graph on 6 vertices
|
1177
|
+
"""
|
1178
|
+
if p <= 0 or q <= 0:
|
1179
|
+
raise ValueError("parameters p and q must be positive integers")
|
1180
|
+
|
1181
|
+
vertices = ((i, j) for i in range(p) for j in range(q))
|
1182
|
+
from itertools import chain
|
1183
|
+
edges = chain((((i, j), (i + 1, j)) for i in range(p - 1) for j in range(q)),
|
1184
|
+
(((i, j), (i, j + 1)) for i in range(p) for j in range(q - 1)))
|
1185
|
+
pos_dict = None
|
1186
|
+
if set_positions:
|
1187
|
+
pos_dict = {(i, j): (j, -i) for i in range(p) for j in range(q)}
|
1188
|
+
return Graph([vertices, edges], format='vertices_and_edges',
|
1189
|
+
immutable=immutable, pos=pos_dict,
|
1190
|
+
name=f"2D Grid Graph for [{p}, {q}]" if name is None else name)
|
1191
|
+
|
1192
|
+
|
1193
|
+
def GridGraph(dim_list, immutable=False):
|
1194
|
+
r"""
|
1195
|
+
Return an `n`-dimensional grid graph.
|
1196
|
+
|
1197
|
+
INPUT:
|
1198
|
+
|
1199
|
+
- ``dim_list`` -- list of integers representing the number of nodes to
|
1200
|
+
extend in each dimension
|
1201
|
+
|
1202
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
1203
|
+
immutable or a mutable graph
|
1204
|
+
|
1205
|
+
PLOTTING: When plotting, this graph will use the default spring-layout
|
1206
|
+
algorithm, unless a position dictionary is specified.
|
1207
|
+
|
1208
|
+
EXAMPLES::
|
1209
|
+
|
1210
|
+
sage: G = graphs.GridGraph([2,3,4])
|
1211
|
+
sage: G.show() # long time # needs sage.plot
|
1212
|
+
|
1213
|
+
::
|
1214
|
+
|
1215
|
+
sage: C = graphs.CubeGraph(4)
|
1216
|
+
sage: G = graphs.GridGraph([2,2,2,2])
|
1217
|
+
sage: C.show() # long time # needs sage.plot
|
1218
|
+
sage: G.show() # long time # needs sage.plot
|
1219
|
+
|
1220
|
+
TESTS:
|
1221
|
+
|
1222
|
+
The graph name contains the dimension::
|
1223
|
+
|
1224
|
+
sage: g = graphs.GridGraph([5, 7])
|
1225
|
+
sage: g.name()
|
1226
|
+
'Grid Graph for [5, 7]'
|
1227
|
+
sage: g = graphs.GridGraph([2, 3, 4])
|
1228
|
+
sage: g.name()
|
1229
|
+
'Grid Graph for [2, 3, 4]'
|
1230
|
+
sage: g = graphs.GridGraph([2, 4, 3])
|
1231
|
+
sage: g.name()
|
1232
|
+
'Grid Graph for [2, 4, 3]'
|
1233
|
+
|
1234
|
+
One dimensional grids (i.e., path) have simple vertex labels::
|
1235
|
+
|
1236
|
+
sage: g = graphs.GridGraph([5])
|
1237
|
+
sage: g.vertices(sort=True)
|
1238
|
+
[0, 1, 2, 3, 4]
|
1239
|
+
|
1240
|
+
The graph is correct::
|
1241
|
+
|
1242
|
+
sage: dim = [randint(1,4) for i in range(4)]
|
1243
|
+
sage: g = graphs.GridGraph(dim)
|
1244
|
+
sage: import networkx # needs networkx
|
1245
|
+
sage: h = Graph(networkx.grid_graph(list(dim))) # needs networkx
|
1246
|
+
sage: g.is_isomorphic(h) # needs networkx
|
1247
|
+
True
|
1248
|
+
|
1249
|
+
Trivial cases::
|
1250
|
+
|
1251
|
+
sage: g = graphs.GridGraph([]); g; g.vertices(sort=False)
|
1252
|
+
Grid Graph for []: Graph on 0 vertices
|
1253
|
+
[]
|
1254
|
+
sage: g = graphs.GridGraph([1]); g; g.vertices(sort=False)
|
1255
|
+
Grid Graph for [1]: Graph on 1 vertex
|
1256
|
+
[0]
|
1257
|
+
sage: g = graphs.GridGraph([2]); g; g.vertices(sort=True)
|
1258
|
+
Grid Graph for [2]: Graph on 2 vertices
|
1259
|
+
[0, 1]
|
1260
|
+
sage: g = graphs.GridGraph([1,1]); g; g.vertices(sort=False)
|
1261
|
+
Grid Graph for [1, 1]: Graph on 1 vertex
|
1262
|
+
[(0, 0)]
|
1263
|
+
sage: g = graphs.GridGraph([1, 1, 1]); g; g.vertices(sort=False)
|
1264
|
+
Grid Graph for [1, 1, 1]: Graph on 1 vertex
|
1265
|
+
[(0, 0, 0)]
|
1266
|
+
sage: g = graphs.GridGraph([1,1,2]); g; g.vertices(sort=True)
|
1267
|
+
Grid Graph for [1, 1, 2]: Graph on 2 vertices
|
1268
|
+
[(0, 0, 0), (0, 0, 1)]
|
1269
|
+
|
1270
|
+
All dimensions must be positive integers::
|
1271
|
+
|
1272
|
+
sage: g = graphs.GridGraph([2,-1,3])
|
1273
|
+
Traceback (most recent call last):
|
1274
|
+
...
|
1275
|
+
ValueError: all dimensions must be positive integers
|
1276
|
+
|
1277
|
+
Check the behavior of parameter ``ìmmutable``::
|
1278
|
+
|
1279
|
+
sage: graphs.GridGraph([], immutable=True).is_immutable()
|
1280
|
+
True
|
1281
|
+
sage: graphs.GridGraph([2], immutable=True).is_immutable()
|
1282
|
+
True
|
1283
|
+
sage: graphs.GridGraph([2, 2], immutable=True).is_immutable()
|
1284
|
+
True
|
1285
|
+
sage: graphs.GridGraph([2, 2, 2], immutable=True).is_immutable()
|
1286
|
+
True
|
1287
|
+
"""
|
1288
|
+
dim = [int(a) for a in dim_list]
|
1289
|
+
if any(a <= 0 for a in dim):
|
1290
|
+
raise ValueError("all dimensions must be positive integers")
|
1291
|
+
|
1292
|
+
name = "Grid Graph for {}".format(dim)
|
1293
|
+
n_dim = len(dim)
|
1294
|
+
if not n_dim:
|
1295
|
+
return Graph(name=name, immutable=immutable)
|
1296
|
+
if n_dim == 1:
|
1297
|
+
# Vertices are labeled from 0 to dim[0]-1
|
1298
|
+
return PathGraph(dim[0], immutable=immutable, name=name)
|
1299
|
+
if n_dim == 2:
|
1300
|
+
# We use the Grid2dGraph generator to also get the positions
|
1301
|
+
return Grid2dGraph(*dim, immutable=immutable, name=name)
|
1302
|
+
|
1303
|
+
# Now, n_dim > 2 and we don't set positions
|
1304
|
+
# Vertices are tuples of dimension n_dim, and the graph contains at
|
1305
|
+
# least vertex (0, 0, ..., 0)
|
1306
|
+
V = [tuple([0] * n_dim)]
|
1307
|
+
|
1308
|
+
def edges():
|
1309
|
+
from itertools import product
|
1310
|
+
for u in product(*[range(d) for d in dim]):
|
1311
|
+
for i in range(n_dim):
|
1312
|
+
if u[i] + 1 < dim[i]:
|
1313
|
+
v = list(u)
|
1314
|
+
v[i] = u[i] + 1
|
1315
|
+
yield (u, tuple(v))
|
1316
|
+
|
1317
|
+
return Graph([V, edges()], format='vertices_and_edges',
|
1318
|
+
immutable=immutable, name=name)
|
1319
|
+
|
1320
|
+
|
1321
|
+
def HouseGraph(immutable=False):
|
1322
|
+
"""
|
1323
|
+
Return a house graph with 5 nodes.
|
1324
|
+
|
1325
|
+
A house graph is named for its shape. It is a triangle (roof) over a
|
1326
|
+
square (walls).
|
1327
|
+
|
1328
|
+
PLOTTING: Upon construction, the position dictionary is filled to override
|
1329
|
+
the spring-layout algorithm. By convention, the house graph is drawn with
|
1330
|
+
the first node in the lower-left corner of the house, the second in the
|
1331
|
+
lower-right corner of the house. The third node is in the upper-left corner
|
1332
|
+
connecting the roof to the wall, and the fourth is in the upper-right corner
|
1333
|
+
connecting the roof to the wall. The fifth node is the top of the roof,
|
1334
|
+
connected only to the third and fourth.
|
1335
|
+
|
1336
|
+
INPUT:
|
1337
|
+
|
1338
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
1339
|
+
immutable or a mutable graph
|
1340
|
+
|
1341
|
+
EXAMPLES:
|
1342
|
+
|
1343
|
+
Construct and show a house graph::
|
1344
|
+
|
1345
|
+
sage: g = graphs.HouseGraph()
|
1346
|
+
sage: g.show() # long time # needs sage.plot
|
1347
|
+
|
1348
|
+
TESTS:
|
1349
|
+
|
1350
|
+
Check the behavior of parameter ``immutable``::
|
1351
|
+
|
1352
|
+
sage: graphs.HouseGraph(immutable=True).is_immutable()
|
1353
|
+
True
|
1354
|
+
"""
|
1355
|
+
pos_dict = {0: (-1, 0), 1: (1, 0), 2: (-1, 1), 3: (1, 1), 4: (0, 2)}
|
1356
|
+
edges = [(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)]
|
1357
|
+
return Graph([range(5), edges], format='vertices_and_edges',
|
1358
|
+
immutable=immutable, pos=pos_dict, name="House Graph")
|
1359
|
+
|
1360
|
+
|
1361
|
+
def HouseXGraph(immutable=False):
|
1362
|
+
"""
|
1363
|
+
Return a house X graph with 5 nodes.
|
1364
|
+
|
1365
|
+
A house X graph is a house graph with two additional edges. The upper-right
|
1366
|
+
corner is connected to the lower-left. And the upper-left corner is
|
1367
|
+
connected to the lower-right.
|
1368
|
+
|
1369
|
+
PLOTTING: Upon construction, the position dictionary is filled to override
|
1370
|
+
the spring-layout algorithm. By convention, the house X graph is drawn with
|
1371
|
+
the first node in the lower-left corner of the house, the second in the
|
1372
|
+
lower-right corner of the house. The third node is in the upper-left corner
|
1373
|
+
connecting the roof to the wall, and the fourth is in the upper-right corner
|
1374
|
+
connecting the roof to the wall. The fifth node is the top of the roof,
|
1375
|
+
connected only to the third and fourth.
|
1376
|
+
|
1377
|
+
INPUT:
|
1378
|
+
|
1379
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
1380
|
+
immutable or a mutable graph
|
1381
|
+
|
1382
|
+
EXAMPLES:
|
1383
|
+
|
1384
|
+
Construct and show a house X graph::
|
1385
|
+
|
1386
|
+
sage: g = graphs.HouseXGraph()
|
1387
|
+
sage: g.show() # long time # needs sage.plot
|
1388
|
+
|
1389
|
+
TESTS:
|
1390
|
+
|
1391
|
+
Check the behavior of parameter ``immutable``::
|
1392
|
+
|
1393
|
+
sage: graphs.HouseXGraph(immutable=True).is_immutable()
|
1394
|
+
True
|
1395
|
+
"""
|
1396
|
+
pos_dict = {0: (-1, 0), 1: (1, 0), 2: (-1, 1), 3: (1, 1), 4: (0, 2)}
|
1397
|
+
edges = [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3), (2, 4), (3, 4)]
|
1398
|
+
return Graph([range(5), edges], format='vertices_and_edges',
|
1399
|
+
immutable=immutable, pos=pos_dict, name="House Graph")
|
1400
|
+
|
1401
|
+
|
1402
|
+
def LadderGraph(n, immutable=False):
|
1403
|
+
r"""
|
1404
|
+
Return a ladder graph with `2 * n` nodes.
|
1405
|
+
|
1406
|
+
A ladder graph is a basic structure that is typically displayed as a ladder,
|
1407
|
+
i.e.: two parallel path graphs connected at each corresponding node pair.
|
1408
|
+
|
1409
|
+
PLOTTING: Upon construction, the position dictionary is filled to override
|
1410
|
+
the spring-layout algorithm. By convention, each ladder graph will be
|
1411
|
+
displayed horizontally, with the first n nodes displayed left to right on
|
1412
|
+
the top horizontal line.
|
1413
|
+
|
1414
|
+
INPUT:
|
1415
|
+
|
1416
|
+
- ``n`` -- a nonnegative integer; number of nodes is `2n`
|
1417
|
+
|
1418
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
1419
|
+
immutable or a mutable graph
|
1420
|
+
|
1421
|
+
EXAMPLES:
|
1422
|
+
|
1423
|
+
Construct and show a ladder graph with 14 nodes::
|
1424
|
+
|
1425
|
+
sage: g = graphs.LadderGraph(7)
|
1426
|
+
sage: g.show() # long time # needs sage.plot
|
1427
|
+
|
1428
|
+
Create several ladder graphs in a Sage graphics array::
|
1429
|
+
|
1430
|
+
sage: # needs sage.plot
|
1431
|
+
sage: g = []
|
1432
|
+
sage: j = []
|
1433
|
+
sage: for i in range(9):
|
1434
|
+
....: k = graphs.LadderGraph(i+2)
|
1435
|
+
....: g.append(k)
|
1436
|
+
sage: for i in range(3):
|
1437
|
+
....: n = []
|
1438
|
+
....: for m in range(3):
|
1439
|
+
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
|
1440
|
+
....: j.append(n)
|
1441
|
+
sage: G = graphics_array(j)
|
1442
|
+
sage: G.show() # long time
|
1443
|
+
|
1444
|
+
TESTS:
|
1445
|
+
|
1446
|
+
Check the behavior of parameter ``immutable``::
|
1447
|
+
|
1448
|
+
sage: graphs.LadderGraph(4, immutable=True).is_immutable()
|
1449
|
+
True
|
1450
|
+
"""
|
1451
|
+
pos_dict = {i: (i, 1) for i in range(n)}
|
1452
|
+
for i in range(n, 2 * n):
|
1453
|
+
x = i - n
|
1454
|
+
pos_dict[i] = (x, 0)
|
1455
|
+
from itertools import chain
|
1456
|
+
edges_1 = zip(range(n), range(1, n))
|
1457
|
+
edges_2 = zip(range(n, 2 * n), range(n + 1, 2 * n))
|
1458
|
+
edges_3 = ((i, i + n) for i in range(n))
|
1459
|
+
return Graph([range(2 * n), chain(edges_1, edges_2, edges_3)],
|
1460
|
+
format='vertices_and_edges', immutable=immutable,
|
1461
|
+
pos=pos_dict, name="Ladder graph")
|
1462
|
+
|
1463
|
+
|
1464
|
+
def MoebiusLadderGraph(n, immutable=False):
|
1465
|
+
r"""
|
1466
|
+
Return a Möbius ladder graph with `2n` nodes
|
1467
|
+
|
1468
|
+
A Möbius ladder graph of order `2n` is a ladder graph of the same order
|
1469
|
+
that is connected at the ends with a single twist, i.e., a ladder graph
|
1470
|
+
bent around so that top meets bottom with a single twist. Alternatively,
|
1471
|
+
it can be described as a single cycle graph (of order `2n`) with the
|
1472
|
+
addition of edges (called `rungs`) joining the antipodal pairs of nodes.
|
1473
|
+
Also, note that the Möbius ladder graph ``graphs.MoebiusLadderGraph(n)`` is
|
1474
|
+
precisely the same graph as the circulant graph
|
1475
|
+
``graphs.CirculantGraph(2 * n, [1, n])``.
|
1476
|
+
|
1477
|
+
PLOTTING:
|
1478
|
+
|
1479
|
+
Upon construction, the position dictionary is filled to override the
|
1480
|
+
spring-layout algorithm. By convention, each Möbius ladder graph will be
|
1481
|
+
displayed with the first (0) node at the top, with the rest following in a
|
1482
|
+
counterclockwise manner.
|
1483
|
+
|
1484
|
+
INPUT:
|
1485
|
+
|
1486
|
+
- ``n`` -- a nonnegative integer; number of nodes is `2n`
|
1487
|
+
|
1488
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
1489
|
+
immutable or a mutable graph
|
1490
|
+
|
1491
|
+
OUTPUT:
|
1492
|
+
|
1493
|
+
- ``G`` -- a Möbius ladder graph of order `2n`; note that a
|
1494
|
+
:exc:`ValueError` is returned if `n < 0`
|
1495
|
+
|
1496
|
+
EXAMPLES:
|
1497
|
+
|
1498
|
+
Construct and show a Möbius ladder graph with 26 nodes::
|
1499
|
+
|
1500
|
+
sage: g = graphs.MoebiusLadderGraph(13)
|
1501
|
+
sage: g.show() # long time # needs sage.plot
|
1502
|
+
|
1503
|
+
Create several Möbius ladder graphs in a Sage graphics array::
|
1504
|
+
|
1505
|
+
sage: # needs sage.plots
|
1506
|
+
sage: g = []
|
1507
|
+
sage: j = []
|
1508
|
+
sage: for i in range(9):
|
1509
|
+
....: k = graphs.MoebiusLadderGraph(i+3)
|
1510
|
+
....: g.append(k)
|
1511
|
+
sage: for i in range(3):
|
1512
|
+
....: n = []
|
1513
|
+
....: for m in range(3):
|
1514
|
+
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
|
1515
|
+
....: j.append(n)
|
1516
|
+
sage: G = graphics_array(j)
|
1517
|
+
sage: G.show() # long time
|
1518
|
+
|
1519
|
+
TESTS:
|
1520
|
+
|
1521
|
+
The input parameter must be a nonnegative integer::
|
1522
|
+
|
1523
|
+
sage: G = graphs.MoebiusLadderGraph(-1)
|
1524
|
+
Traceback (most recent call last):
|
1525
|
+
...
|
1526
|
+
ValueError: parameter n must be a nonnegative integer
|
1527
|
+
|
1528
|
+
Check the behavior of parameter ``immutable``::
|
1529
|
+
|
1530
|
+
sage: graphs.MoebiusLadderGraph(4, immutable=True).is_immutable()
|
1531
|
+
True
|
1532
|
+
|
1533
|
+
REFERENCES:
|
1534
|
+
|
1535
|
+
- :wikipedia:`Möbius_ladder`
|
1536
|
+
|
1537
|
+
.. SEEALSO::
|
1538
|
+
:meth:`~sage.graphs.graph_generators.GraphGenerators.LadderGraph`,
|
1539
|
+
:meth:`~sage.graphs.graph_generators.GraphGenerators.CircularLadderGraph`,
|
1540
|
+
:meth:`~sage.graphs.graph_generators.GraphGenerators.CirculantGraph`
|
1541
|
+
|
1542
|
+
AUTHORS:
|
1543
|
+
|
1544
|
+
- Janmenjaya Panda (2024-05-26)
|
1545
|
+
"""
|
1546
|
+
if n < 0:
|
1547
|
+
raise ValueError("parameter n must be a nonnegative integer")
|
1548
|
+
|
1549
|
+
from itertools import chain
|
1550
|
+
edges_1 = zip(range(2 * n), chain(range(1, 2 * n), (0,)))
|
1551
|
+
edges_2 = ((i, i + n) for i in range(n))
|
1552
|
+
G = Graph([range(2 * n), chain(edges_1, edges_2)],
|
1553
|
+
format='vertices_and_edges', immutable=immutable,
|
1554
|
+
name="Moebius ladder graph")
|
1555
|
+
G._circle_embedding(list(range(2 * n)), angle=pi/2)
|
1556
|
+
return G
|
1557
|
+
|
1558
|
+
|
1559
|
+
def PathGraph(n, pos=None, immutable=False, name=None):
|
1560
|
+
r"""
|
1561
|
+
Return a path graph with `n` nodes.
|
1562
|
+
|
1563
|
+
A path graph is a graph where all inner nodes are connected to their two
|
1564
|
+
neighbors and the two end-nodes are connected to their one inner neighbors
|
1565
|
+
(i.e.: a cycle graph without the first and last node connected).
|
1566
|
+
|
1567
|
+
INPUT:
|
1568
|
+
|
1569
|
+
- ``n`` -- nonnegative integer; number of nodes of the path graph
|
1570
|
+
|
1571
|
+
- ``pos`` -- string (default: ``None``); indicates the embedding to use
|
1572
|
+
between 'circle', 'line' or the default algorithm. See the plotting
|
1573
|
+
section below for more detail.
|
1574
|
+
|
1575
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
1576
|
+
immutable or a mutable graph
|
1577
|
+
|
1578
|
+
- ``name`` -- string (default: ``None``); used as the name of the returned
|
1579
|
+
graph when set
|
1580
|
+
|
1581
|
+
PLOTTING: Upon construction, the position dictionary is filled to override
|
1582
|
+
the spring-layout algorithm. By convention, the graph may be drawn in one of
|
1583
|
+
two ways: The 'line' argument will draw the graph in a horizontal line (left
|
1584
|
+
to right) if there are less than 11 nodes. Otherwise the 'line' argument
|
1585
|
+
will append horizontal lines of length 10 nodes below, alternating left to
|
1586
|
+
right and right to left. The 'circle' argument will cause the graph to be
|
1587
|
+
drawn in a cycle-shape, with the first node at the top and then about the
|
1588
|
+
circle in a clockwise manner. By default (without an appropriate string
|
1589
|
+
argument) the graph will be drawn as a 'circle' if `10 < n < 41` and as a
|
1590
|
+
'line' for all other `n`.
|
1591
|
+
|
1592
|
+
EXAMPLES:
|
1593
|
+
|
1594
|
+
Show default drawing by size: 'line': `n \leq 10`::
|
1595
|
+
|
1596
|
+
sage: p = graphs.PathGraph(10)
|
1597
|
+
sage: p.show() # long time # needs sage.plot
|
1598
|
+
|
1599
|
+
'circle': `10 < n < 41`::
|
1600
|
+
|
1601
|
+
sage: q = graphs.PathGraph(25)
|
1602
|
+
sage: q.show() # long time # needs sage.plot
|
1603
|
+
|
1604
|
+
'line': `n \geq 41`::
|
1605
|
+
|
1606
|
+
sage: r = graphs.PathGraph(55)
|
1607
|
+
sage: r.show() # long time # needs sage.plot
|
1608
|
+
|
1609
|
+
Override the default drawing::
|
1610
|
+
|
1611
|
+
sage: s = graphs.PathGraph(5,'circle')
|
1612
|
+
sage: s.show() # long time # needs sage.plot
|
1613
|
+
|
1614
|
+
TESTS:
|
1615
|
+
|
1616
|
+
Check the behavior of parameter ``immutable``::
|
1617
|
+
|
1618
|
+
sage: graphs.PathGraph(4, immutable=True).is_immutable()
|
1619
|
+
True
|
1620
|
+
|
1621
|
+
Check the behavior of parameter ``name``::
|
1622
|
+
|
1623
|
+
sage: graphs.PathGraph(4, name='foo')
|
1624
|
+
foo: Graph on 4 vertices
|
1625
|
+
"""
|
1626
|
+
edges = ((i, i + 1) for i in range(n - 1))
|
1627
|
+
G = Graph([range(n), edges], format='vertices_and_edges',
|
1628
|
+
immutable=immutable, name="Path graph" if name is None else name)
|
1629
|
+
|
1630
|
+
pos_dict = {}
|
1631
|
+
|
1632
|
+
# Choose appropriate drawing pattern
|
1633
|
+
circle = False
|
1634
|
+
if pos == "circle":
|
1635
|
+
circle = True
|
1636
|
+
elif pos == "line":
|
1637
|
+
circle = False
|
1638
|
+
# Otherwise use default by size of n
|
1639
|
+
elif 10 < n < 41:
|
1640
|
+
circle = True
|
1641
|
+
|
1642
|
+
# Draw 'circle'
|
1643
|
+
if circle:
|
1644
|
+
if n == 1:
|
1645
|
+
G.set_pos({0: (0, 0)})
|
1646
|
+
else:
|
1647
|
+
G._circle_embedding(list(range(n)), angle=pi/2)
|
1648
|
+
# Draw 'line'
|
1649
|
+
else:
|
1650
|
+
counter = 0 # node index
|
1651
|
+
rem = n % 10 # remainder to appear on last row
|
1652
|
+
rows = n // 10 # number of rows (not counting last row)
|
1653
|
+
lr = True # left to right
|
1654
|
+
|
1655
|
+
for i in range(rows): # note that rows doesn't include last row
|
1656
|
+
y = -i
|
1657
|
+
for j in range(10):
|
1658
|
+
if lr:
|
1659
|
+
x = j
|
1660
|
+
else:
|
1661
|
+
x = 9 - j
|
1662
|
+
pos_dict[counter] = (x, y)
|
1663
|
+
counter += 1
|
1664
|
+
if lr:
|
1665
|
+
lr = False
|
1666
|
+
else:
|
1667
|
+
lr = True
|
1668
|
+
y = -rows
|
1669
|
+
for j in range(rem): # last row
|
1670
|
+
if lr:
|
1671
|
+
x = j
|
1672
|
+
else:
|
1673
|
+
x = 9 - j
|
1674
|
+
pos_dict[counter] = (x, y)
|
1675
|
+
counter += 1
|
1676
|
+
G.set_pos(pos_dict)
|
1677
|
+
|
1678
|
+
return G
|
1679
|
+
|
1680
|
+
|
1681
|
+
def StarGraph(n, immutable=False):
|
1682
|
+
r"""
|
1683
|
+
Return a star graph with `n + 1` nodes.
|
1684
|
+
|
1685
|
+
A Star graph is a basic structure where one node is connected to all other
|
1686
|
+
nodes.
|
1687
|
+
|
1688
|
+
INPUT:
|
1689
|
+
|
1690
|
+
- ``n`` -- a nonnegative integer; number of nodes is `n + 1`
|
1691
|
+
|
1692
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return an
|
1693
|
+
immutable or a mutable graph
|
1694
|
+
|
1695
|
+
PLOTTING: Upon construction, the position dictionary is filled to override
|
1696
|
+
the spring-layout algorithm. By convention, each star graph will be
|
1697
|
+
displayed with the first (0) node in the center, the second node (1) at the
|
1698
|
+
top, with the rest following in a counterclockwise manner. (0) is the node
|
1699
|
+
connected to all other nodes.
|
1700
|
+
|
1701
|
+
The star graph is a good opportunity to compare efficiency of filling a
|
1702
|
+
position dictionary vs. using the spring-layout algorithm for plotting. As
|
1703
|
+
far as display, the spring-layout should push all other nodes away from the
|
1704
|
+
(0) node, and thus look very similar to this constructor's positioning.
|
1705
|
+
|
1706
|
+
EXAMPLES::
|
1707
|
+
|
1708
|
+
sage: import networkx # needs networkx
|
1709
|
+
|
1710
|
+
Compare the plots::
|
1711
|
+
|
1712
|
+
sage: # needs networkx sage.plot
|
1713
|
+
sage: n = networkx.star_graph(23)
|
1714
|
+
sage: spring23 = Graph(n)
|
1715
|
+
sage: posdict23 = graphs.StarGraph(23)
|
1716
|
+
sage: spring23.show() # long time
|
1717
|
+
sage: posdict23.show() # long time
|
1718
|
+
|
1719
|
+
View many star graphs as a Sage Graphics Array
|
1720
|
+
|
1721
|
+
With this constructor (i.e., the position dictionary filled)
|
1722
|
+
|
1723
|
+
::
|
1724
|
+
|
1725
|
+
sage: # needs sage.plot
|
1726
|
+
sage: g = []
|
1727
|
+
sage: j = []
|
1728
|
+
sage: for i in range(9):
|
1729
|
+
....: k = graphs.StarGraph(i+3)
|
1730
|
+
....: g.append(k)
|
1731
|
+
sage: for i in range(3):
|
1732
|
+
....: n = []
|
1733
|
+
....: for m in range(3):
|
1734
|
+
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
|
1735
|
+
....: j.append(n)
|
1736
|
+
sage: G = graphics_array(j)
|
1737
|
+
sage: G.show() # long time
|
1738
|
+
|
1739
|
+
Compared to plotting with the spring-layout algorithm
|
1740
|
+
|
1741
|
+
::
|
1742
|
+
|
1743
|
+
sage: # needs networkx sage.plot
|
1744
|
+
sage: g = []
|
1745
|
+
sage: j = []
|
1746
|
+
sage: for i in range(9):
|
1747
|
+
....: spr = networkx.star_graph(i+3)
|
1748
|
+
....: k = Graph(spr)
|
1749
|
+
....: g.append(k)
|
1750
|
+
sage: for i in range(3):
|
1751
|
+
....: n = []
|
1752
|
+
....: for m in range(3):
|
1753
|
+
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
|
1754
|
+
....: j.append(n)
|
1755
|
+
sage: G = graphics_array(j)
|
1756
|
+
sage: G.show() # long time
|
1757
|
+
|
1758
|
+
TESTS:
|
1759
|
+
|
1760
|
+
Check the behavior of parameter ``immutable``::
|
1761
|
+
|
1762
|
+
sage: graphs.StarGraph(4, immutable=True).is_immutable()
|
1763
|
+
True
|
1764
|
+
"""
|
1765
|
+
G = Graph({0: list(range(1, n + 1))}, format='dict_of_lists',
|
1766
|
+
immutable=immutable, name="Star graph")
|
1767
|
+
G.set_pos({0: (0, 0)})
|
1768
|
+
G._circle_embedding(list(range(1, n + 1)), angle=pi/2)
|
1769
|
+
return G
|