Graphs
Graphs
Release 9.7
4 Hypergraphs 921
Bibliography 1221
Index 1225
i
ii
CHAPTER
ONE
This module implements the base class for graphs and digraphs, and methods that can be applied on both. Here is what
it can do:
Basic Graph operations:
1
Graph Theory, Release 9.7
Graph products:
Linear algebra:
Some metrics:
cluster_triangles() Return the number of triangles for the set nbunch of vertices as a dictionary
keyed by vertex.
clustering_average() Return the average clustering coefficient.
clustering_coeff() Return the clustering coefficient for each vertex in nbunch
cluster_transitivity() Return the transitivity (fraction of transitive triangles) of the graph.
szeged_index() Return the Szeged index of the graph.
katz_centrality() Return the katz centrality of the vertex u of the graph.
katz_matrix() Return the katz matrix of the graph.
pagerank() Return the PageRank of the vertices of self.
Automorphism group:
Return the coarsest partition which is finer than the input partition, and equitable
coarsest_equitable_refinement()
with respect to self.
automorphism_group() Return the largest subgroup of the automorphism group of the (di)graph whose
orbit partition is finer than the partition given.
is_vertex_transitive() Return whether the automorphism group of self is transitive within the partition
provided
is_isomorphic() Test for isomorphism between self and other.
canonical_label() Return the canonical graph.
is_cayley() Check whether the graph is a Cayley graph.
Graph properties:
is_eulerian() Return True if the graph has a (closed) tour that visits each edge exactly once.
is_planar() Check whether the graph is planar.
is_circular_planar() Check whether the graph is circular planar (outerplanar)
is_regular() Return True if this graph is (𝑘-)regular.
is_chordal() Check whether the given graph is chordal.
is_bipartite() Test whether the given graph is bipartite.
is_circulant() Check whether the graph is a circulant graph.
is_interval() Check whether the graph is an interval graph.
is_gallai_tree() Return whether the current graph is a Gallai tree.
is_clique() Check whether a set of vertices is a clique
is_cycle() Check whether self is a (directed) cycle graph.
is_independent_set() Check whether vertices is an independent set of self
is_transitively_reduced() Test whether the digraph is transitively reduced.
is_equitable() Check whether the given partition is equitable with respect to self.
is_self_complementary() Check whether the graph is self-complementary.
Traversals:
Distances:
Plot/embedding-related methods:
steiner_tree() Return a tree of minimum weight connecting the given set of vertices.
Return the desired number of edge-disjoint spanning trees/arborescences.
edge_disjoint_spanning_trees()
feedback_vertex_set() Compute the minimum feedback vertex set of a (di)graph.
multiway_cut() Return a minimum edge multiway cut
max_cut() Return a maximum edge cut of the graph.
longest_path() Return a longest path of self.
Solve the traveling salesman problem (TSP)
traveling_salesman_problem()
is_hamiltonian() Test whether the current graph is Hamiltonian.
hamiltonian_cycle() Return a Hamiltonian cycle/circuit of the current graph/digraph
hamiltonian_path() Return a Hamiltonian path of the current graph/digraph
multicommodity_flow() Solve a multicommodity flow problem.
disjoint_routed_paths() Return a set of disjoint routed paths.
dominating_set() Return a minimum dominating set of the graph
greedy_dominating_set() Return a greedy distance-𝑘 dominating set of the graph.
subgraph_search() Return a copy of G in self.
subgraph_search_count() Return the number of labelled occurrences of G in self.
subgraph_search_iterator() Return an iterator over the labelled copies of G in self.
characteristic_polynomial()Return the characteristic polynomial of the adjacency matrix of the (di)graph.
genus() Return the minimal genus of the graph.
crossing_number() Return the crossing number of the graph.
Miscellaneous
1.1.1 Methods
class sage.graphs.generic_graph.GenericGraph
Bases: sage.graphs.generic_graph_pyx.GenericGraph_pyx
Base class for graphs and digraphs.
__eq__(other)
Compare self and other for equality.
Do not call this method directly. That is, for G.__eq__(H) write G == H.
Two graphs are considered equal if the following hold:
• they are either both directed, or both undirected;
• they have the same settings for loops, multiedges, and weightedness;
• they have the same set of vertices;
• they have the same (multi)set of arrows/edges, where labels of arrows/edges are taken into account
if and only if the graphs are considered weighted. See weighted().
Note that this is not an isomorphism test.
EXAMPLES:
sage: G = graphs.EmptyGraph()
sage: H = Graph()
sage: G == H
True
sage: G.to_directed() == H.to_directed()
True
sage: G = graphs.RandomGNP(8, .9999)
sage: H = graphs.CompleteGraph(8)
sage: G == H # random - most often true
True
sage: G = Graph({0: [1, 2, 3, 4, 5, 6, 7]} )
sage: H = Graph({1: [0], 2: [0], 3: [0], 4: [0], 5: [0], 6: [0], 7: [0]} )
sage: G == H
True
sage: G.allow_loops(True)
sage: G == H
False
sage: G = graphs.RandomGNP(9, .3).to_directed()
sage: H = graphs.RandomGNP(9, .3).to_directed()
sage: G == H # most often false
False
sage: G = Graph(multiedges=True, sparse=True)
sage: G.add_edge(0, 1)
sage: H = copy(G)
sage: H.add_edge(0, 1)
(continues on next page)
Note that graphs must be considered weighted, or Sage will not pay attention to edge label data in equality
testing:
add_clique(vertices, loops=False)
Add a clique to the graph with the given vertices.
If the vertices are already present, only the edges are added.
INPUT:
• vertices – an iterable container of vertices for the clique to be added, e.g. a list, set, graph, etc.
• loops – boolean (default: False); whether to add edges from every given vertex to itself. This is
allowed only if the (di)graph allows loops.
EXAMPLES:
sage: G = Graph()
sage: G.add_clique(range(4))
sage: G.is_isomorphic(graphs.CompleteGraph(4))
True
sage: D = DiGraph()
sage: D.add_clique(range(4))
sage: D.is_isomorphic(digraphs.Complete(4))
True
sage: D = DiGraph(loops=True)
sage: D.add_clique(range(4), loops=True)
sage: D.is_isomorphic(digraphs.Complete(4, loops=True))
True
sage: D = DiGraph(loops=False)
sage: D.add_clique(range(4), loops=True)
Traceback (most recent call last):
...
ValueError: cannot add edge from 0 to 0 in graph without loops
If the list of vertices contains repeated elements, a loop will be added at that vertex, even if loops=False:
sage: G = Graph(loops=True)
sage: G.add_clique([1, 1])
(continues on next page)
sage: G = Graph(loops=True)
sage: G.add_clique([1], loops=True)
sage: G.edges(sort=True)
[(1, 1, None)]
add_cycle(vertices)
Add a cycle to the graph with the given vertices.
If the vertices are already present, only the edges are added.
For digraphs, adds the directed cycle, whose orientation is determined by the list. Adds edges
(vertices[u], vertices[u+1]) and (vertices[-1], vertices[0]).
INPUT:
• vertices – an ordered list of the vertices of the cycle to be added
EXAMPLES:
sage: G = Graph()
sage: G.add_vertices(range(10)); G
Graph on 10 vertices
sage: show(G)
sage: G.add_cycle(list(range(10, 20)))
sage: show(G)
sage: G.add_cycle(list(range(10)))
sage: show(G)
sage: D = DiGraph()
sage: D.add_cycle(list(range(4)))
sage: D.edges(sort=True)
[(0, 1, None), (1, 2, None), (2, 3, None), (3, 0, None)]
sage: G = Graph()
sage: G.add_edge((1, 2), 'label')
sage: G.edges(sort=False)
[('label', (1, 2), None)]
sage: G = Graph()
sage: G.add_edge((1, 2), label="label")
sage: G.edges(sort=False)
[(1, 2, 'label')]
sage: G = Graph()
sage: G.add_edge(1, 2, 'label')
sage: G.edges(sort=False)
[(1, 2, 'label')]
sage: G = Graph()
sage: G.add_edge((1, 2, 'label'))
sage: G.edges(sort=False)
[(1, 2, 'label')]
sage: G = Graph()
sage: G.add_edge(None, 4)
sage: G.vertices(sort=True)
[0, 4]
add_edges(edges, loops=True)
Add edges from an iterable container.
INPUT:
• edges – an iterable of edges, given either as (u, v) or (u, v, label).
• loops – boolean (default: True); if False, remove all loops (v, v) from the input iterator. If None,
remove loops unless the graph allows loops.
EXAMPLES:
sage: G = graphs.DodecahedralGraph()
sage: H = Graph()
sage: H.add_edges(G.edge_iterator()); H
Graph on 20 vertices
sage: G = graphs.DodecahedralGraph().to_directed()
sage: H = DiGraph()
sage: H.add_edges(G.edge_iterator()); H
Digraph on 20 vertices
sage: H.add_edges(iter([]))
sage: H = Graph()
sage: H.add_edges([(0, 1), (0, 2, "label")])
sage: H.edges(sort=True)
[(0, 1, None), (0, 2, 'label')]
sage: H = Graph()
sage: H.add_edges([(0, 0)], loops=False); H.edges(sort=True)
[]
sage: H.add_edges([(0, 0)], loops=None); H.edges(sort=True)
[]
sage: H.add_edges([(0, 0)]); H.edges(sort=True)
Traceback (most recent call last):
...
ValueError: cannot add edge from 0 to 0 in graph without loops
sage: H = Graph(loops=True)
sage: H.add_edges([(0, 0)], loops=False); H.edges(sort=True)
[]
sage: H.add_edges([(0, 0)], loops=None); H.edges(sort=True)
[(0, 0, None)]
sage: H.add_edges([(0, 0)]); H.edges(sort=True)
[(0, 0, None)]
add_path(vertices)
Add a path to the graph with the given vertices.
If the vertices are already present, only the edges are added.
For digraphs, adds the directed path vertices[0], ..., vertices[-1].
INPUT:
• vertices – an ordered list of the vertices of the path to be added
EXAMPLES:
sage: G = Graph()
sage: G.add_vertices(range(10)); G
Graph on 10 vertices
sage: show(G)
sage: G.add_path(list(range(10, 20)))
sage: show(G)
sage: G.add_path(list(range(10)))
sage: show(G)
sage: D = DiGraph()
sage: D.add_path(list(range(4)))
sage: D.edges(sort=True)
[(0, 1, None), (1, 2, None), (2, 3, None)]
add_vertex(name=None)
Create an isolated vertex.
If the vertex already exists, then nothing is done.
INPUT:
• name – an immutable object (default: None); when no name is specified (default), then the new vertex
will be represented by the least integer not already representing a vertex. name must be an immutable
object (e.g., an integer, a tuple, etc.).
As it is implemented now, if a graph 𝐺 has a large number of vertices with numeric labels, then G.
add_vertex() could potentially be slow, if name=None.
OUTPUT:
If name=None, the new vertex name is returned. None otherwise.
EXAMPLES:
add_vertices(vertices)
Add vertices to the (di)graph from an iterable container of vertices.
Vertices that already exist in the graph will not be added again.
INPUT:
• vertices – iterator container of vertex labels. A new label is created, used and returned in the output
list for all None values in vertices.
OUTPUT:
Generated names of new vertices if there is at least one None value present in vertices. None otherwise.
EXAMPLES:
sage: G = Graph(d)
sage: G.add_vertices([10,11,12])
sage: G.vertices(sort=True)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
sage: G.add_vertices(graphs.CycleGraph(25).vertex_iterator())
sage: G.vertices(sort=True)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,␣
˓→22, 23, 24]
sage: G = Graph()
sage: G.add_vertices([1, 2, 3])
sage: G.add_vertices([4, None, None, 5])
[0, 6]
EXAMPLES:
sage: G = graphs.CubeGraph(4)
sage: G.adjacency_matrix()
[0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0]
[1 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0]
[1 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0]
[0 1 1 0 0 0 0 1 0 0 0 1 0 0 0 0]
[1 0 0 0 0 1 1 0 0 0 0 0 1 0 0 0]
[0 1 0 0 1 0 0 1 0 0 0 0 0 1 0 0]
[0 0 1 0 1 0 0 1 0 0 0 0 0 0 1 0]
[0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 1]
[1 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0]
[0 1 0 0 0 0 0 0 1 0 0 1 0 1 0 0]
[0 0 1 0 0 0 0 0 1 0 0 1 0 0 1 0]
[0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 1]
[0 0 0 0 1 0 0 0 1 0 0 0 0 1 1 0]
[0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 1]
[0 0 0 0 0 0 1 0 0 0 1 0 1 0 0 1]
[0 0 0 0 0 0 0 1 0 0 0 1 0 1 1 0]
sage: D = DiGraph({0: [1, 2, 3], 1: [0, 2], 2: [3], 3: [4], 4: [0, 5], 5: [1]})
sage: D.adjacency_matrix()
[0 1 1 1 0 0]
[1 0 1 0 0 0]
[0 0 0 1 0 0]
[0 0 0 0 1 0]
[1 0 0 0 0 1]
[0 1 0 0 0 0]
sage: graphs.PathGraph(5).adjacency_matrix(base_ring=RDF)
[0.0 1.0 0.0 0.0 0.0]
[1.0 0.0 1.0 0.0 0.0]
[0.0 1.0 0.0 1.0 0.0]
[0.0 0.0 1.0 0.0 1.0]
[0.0 0.0 0.0 1.0 0.0]
sage: type(_)
<class 'sage.matrix.matrix_real_double_dense.Matrix_real_double_dense'>
As an immutable matrix:
• use_multiedges – boolean (default: False); this parameter is used only if the graph has multiple
edges.
– If False, the graph is considered as simple and an edge label is arbitrarily selected for each edge as
in sage.graphs.generic_graph.GenericGraph.to_simple() if report_edges is True
– If True, a path will be reported as many times as the edges multiplicities along that path (when
report_edges = False or labels = False), or with all possible combinations of edge labels
(when report_edges = True and labels = True)
• report_edges – boolean (default: False); whether to report paths as list of vertices (default) or list
of edges, if False then labels parameter is ignored
• labels – boolean (default: False); if False, each edge is simply a pair (u, v) of vertices. Other-
wise a list of edges along with its edge labels are used to represent the path.
EXAMPLES:
sage: g = Graph([(0, 1), (0, 1), (1, 2), (1, 2)], multiedges=True)
sage: g.all_paths(0, 2, use_multiedges=True)
[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]
allow_loops(new, check=True)
Change whether loops are permitted in the (di)graph
INPUT:
• new – boolean
• check – boolean (default: True); whether to remove existing loops from the (di)graph when the new
status is False
EXAMPLES:
sage: G = Graph(loops=True); G
Looped graph on 0 vertices
sage: G.has_loops()
False
sage: G.allows_loops()
True
sage: G.add_edge((0, 0))
sage: G.has_loops()
True
(continues on next page)
sage: D = DiGraph(loops=True); D
Looped digraph on 0 vertices
sage: D.has_loops()
False
sage: D.allows_loops()
True
sage: D.add_edge((0, 0))
sage: D.has_loops()
True
sage: D.loops()
[(0, 0, None)]
sage: D.allow_loops(False); D
Digraph on 1 vertex
sage: D.has_loops()
False
sage: D.edges(sort=True)
[]
Warning: 'min' and 'max' only works if the labels can be compared. A TypeError might be raised
when working with non-comparable objects in Python 3.
EXAMPLES:
The standard behavior with undirected graphs:
sage: G = Graph(multiedges=True, sparse=True); G
Multi-graph on 0 vertices
(continues on next page)
allows_loops()
Return whether loops are permitted in the (di)graph
EXAMPLES:
sage: G = Graph(loops=True); G
Looped graph on 0 vertices
sage: G.has_loops()
False
sage: G.allows_loops()
True
sage: G.add_edge((0, 0))
sage: G.has_loops()
True
sage: G.loops()
[(0, 0, None)]
sage: G.allow_loops(False); G
Graph on 1 vertex
sage: G.has_loops()
False
sage: G.edges(sort=True)
[]
sage: D = DiGraph(loops=True); D
Looped digraph on 0 vertices
sage: D.has_loops()
False
sage: D.allows_loops()
True
sage: D.add_edge((0, 0))
sage: D.has_loops()
True
sage: D.loops()
[(0, 0, None)]
sage: D.allow_loops(False); D
Digraph on 1 vertex
sage: D.has_loops()
False
sage: D.edges(sort=True)
[]
allows_multiple_edges()
Return whether multiple edges are permitted in the (di)graph.
EXAMPLES:
sage: G = graphs.CubeGraph(4)
sage: G.adjacency_matrix()
[0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0]
[1 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0]
[1 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0]
[0 1 1 0 0 0 0 1 0 0 0 1 0 0 0 0]
[1 0 0 0 0 1 1 0 0 0 0 0 1 0 0 0]
[0 1 0 0 1 0 0 1 0 0 0 0 0 1 0 0]
[0 0 1 0 1 0 0 1 0 0 0 0 0 0 1 0]
[0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 1]
[1 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0]
[0 1 0 0 0 0 0 0 1 0 0 1 0 1 0 0]
[0 0 1 0 0 0 0 0 1 0 0 1 0 0 1 0]
[0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 1]
(continues on next page)
sage: D = DiGraph({0: [1, 2, 3], 1: [0, 2], 2: [3], 3: [4], 4: [0, 5], 5: [1]})
sage: D.adjacency_matrix()
[0 1 1 1 0 0]
[1 0 1 0 0 0]
[0 0 0 1 0 0]
[0 0 0 0 1 0]
[1 0 0 0 0 1]
[0 1 0 0 0 0]
sage: graphs.PathGraph(5).adjacency_matrix(base_ring=RDF)
[0.0 1.0 0.0 0.0 0.0]
[1.0 0.0 1.0 0.0 0.0]
[0.0 1.0 0.0 1.0 0.0]
[0.0 0.0 1.0 0.0 1.0]
[0.0 0.0 0.0 1.0 0.0]
sage: type(_)
<class 'sage.matrix.matrix_real_double_dense.Matrix_real_double_dense'>
As an immutable matrix:
antisymmetric()
Check whether the graph is antisymmetric.
A graph represents an antisymmetric relation if the existence of a path from a vertex 𝑥 to a vertex 𝑦 implies
that there is not a path from 𝑦 to 𝑥 unless 𝑥 = 𝑦.
EXAMPLES:
A directed acyclic graph is antisymmetric:
sage: G.allow_loops(True)
sage: G.add_edge(0, 0)
sage: G.antisymmetric()
True
An undirected graph is never antisymmetric unless it is just a union of isolated vertices (with possible
loops):
sage: D = graphs.DodecahedralGraph()
sage: G = D.automorphism_group()
sage: A5 = AlternatingGroup(5)
(continues on next page)
sage: G.is_isomorphic(H)
True
Multigraphs:
sage: G = Graph(multiedges=True,sparse=True)
sage: G.add_edge(('a', 'b'))
sage: G.add_edge(('a', 'b'))
sage: G.add_edge(('a', 'b'))
sage: G.automorphism_group()
Permutation Group with generators [('a','b')]
Digraphs:
sage: G = Graph(sparse=True)
sage: G.add_edges( [(0,1,'a'),(1,2,'b'),(2,3,'c'),(3,4,'b'),(4,0,'a')] )
sage: G.automorphism_group(edge_labels=True)
Permutation Group with generators [(1,4)(2,3)]
You can also ask for just the order of the group:
sage: G = graphs.PetersenGraph()
sage: G.automorphism_group(return_group=False, order=True)
120
Or, just the orbits (note that each graph here is vertex transitive)
sage: G = graphs.PetersenGraph()
sage: G.automorphism_group(return_group=False, orbits=True,algorithm='sage')
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]
sage: orb = G.automorphism_group(partition=[[0],list(range(1,10))],
....: return_group=False, orbits=True,algorithm='sage
˓→')
One can also use the faster algorithm for computing the automorphism group of the graph - bliss:
average_degree()
Return the average degree of the graph.
2|𝐸|
The average degree of a graph 𝐺 = (𝑉, 𝐸) is equal to |𝑉 | .
EXAMPLES:
The average degree of a regular graph is equal to the degree of any vertex:
sage: g = graphs.CompleteGraph(5)
sage: g.average_degree() == 4
True
2|𝐸|
For any graph, it is equal to |𝑉 | :
sage: g=graphs.PathGraph(10)
sage: w=lambda x: (x*(x*x -1)/6)/(x*(x-1)/2)
sage: g.average_distance()==w(10)
True
sage: g = digraphs.Circuit(6)
sage: g.average_distance()
3
• blocks_and_cuts_tree()
• sage.graphs.base.boost_graph.blocks_and_cut_vertices()
• is_biconnected()
• bridges()
EXAMPLES:
We construct a trivial example of a graph with one cut vertex:
sage: blocks_and_cut_vertices(graphs.PetersenGraph())
([[0, 1, 4, 5, 2, 6, 3, 7, 8, 9]], [])
A disconnected graph:
sage: g = Graph({1: {2: 28, 3: 10}, 2: {1: 10, 3: 16}, 4: {}, 5: {6: 3, 7: 10,␣
˓→8: 4}})
sage: blocks_and_cut_vertices(g)
([[1, 2, 3], [5, 6], [5, 7], [5, 8], [4]], [5])
blocks_and_cuts_tree(G)
Return the blocks-and-cuts tree of self.
This new graph has two different kinds of vertices, some representing the blocks (type B) and some other
the cut vertices of the graph (type C).
There is an edge between a vertex 𝑢 of type B and a vertex 𝑣 of type C if the cut-vertex corresponding to 𝑣
is in the block corresponding to 𝑢.
The resulting graph is a tree, with the additional characteristic property that the distance between two leaves
is even. When self is not connected, the resulting graph is a forest.
When self is biconnected, the tree is reduced to a single node of type 𝐵.
We referred to [HarPri] and [Gallai] for blocks and cuts tree.
See also:
• blocks_and_cut_vertices()
• is_biconnected()
EXAMPLES:
sage: T = blocks_and_cuts_tree(graphs.RandomTree(40))
sage: T.is_tree()
True
sage: leaves = [v for v in T if T.degree(v) == 1]
sage: all(T.distance(u,v) % 2 == 0 for u in leaves for v in leaves)
True
sage: T = blocks_and_cuts_tree(graphs.PetersenGraph())
sage: T.vertices(sort=True)
[('B', (0, 1, 4, 5, 2, 6, 3, 7, 8, 9))]
• report_distance – boolean (default: False); if True, reports pairs (vertex, distance) where
distance is the distance from the start nodes. If False only the vertices are reported.
• edges – boolean (default: False); whether to return the edges of the BFS tree in the order of visit or
the vertices (default). Edges are directed in root to leaf orientation of the tree.
Note that parameters edges and report_distance cannot be True simultaneously.
See also:
EXAMPLES:
By default, the edge direction of a digraph is respected, but this can be overridden by the
ignore_direction parameter:
sage: D = DiGraph({0: [1, 2, 3], 1: [4, 5], 2: [5], 3: [6], 5: [7], 6: [7], 7:␣
˓→[0]})
sage: list(D.breadth_first_search(0))
[0, 1, 2, 3, 4, 5, 6, 7]
sage: list(D.breadth_first_search(0, ignore_direction=True))
[0, 1, 2, 3, 7, 4, 5, 6]
You can specify a maximum distance in which to search. A distance of zero returns the start vertices:
sage: D = DiGraph({0: [1, 2, 3], 1: [4, 5], 2: [5], 3: [6], 5: [7], 6: [7], 7:␣
˓→[0]})
sage: D = DiGraph({0: [1, 2, 3], 1: [4, 5], 2: [5], 3: [6], 5: [7], 6: [7], 7:␣
˓→[0]})
sage: list(D.breadth_first_search([0]))
[0, 1, 2, 3, 4, 5, 6, 7]
sage: list(D.breadth_first_search([0, 6]))
[0, 6, 1, 2, 3, 7, 4, 5]
sage: list(D.breadth_first_search([0, 6], distance=0))
[0, 6]
sage: list(D.breadth_first_search([0, 6], distance=1))
[0, 6, 1, 2, 3, 7]
sage: list(D.breadth_first_search(6, ignore_direction=True, distance=2))
[6, 3, 7, 0, 5]
More generally, you can specify a neighbors function. For example, you can traverse the graph backwards
by setting neighbors to be the neighbors_in() function of the graph:
sage: D = DiGraph({0: [1, 2, 3], 1: [4, 5], 2: [5], 3: [6], 5: [7], 6: [7], 7:␣
˓→[0]})
It is possible (trac ticket #16470) using the keyword report_distance to get pairs (vertex, distance)
encoding the distance from the starting vertices:
sage: G = graphs.PetersenGraph()
sage: list(G.breadth_first_search(0, report_distance=True))
[(0, 0), (1, 1), (4, 1), (5, 1), (2, 2), (6, 2), (3, 2), (9, 2),
(7, 2), (8, 2)]
sage: list(G.breadth_first_search(0, report_distance=False))
[0, 1, 4, 5, 2, 6, 3, 9, 7, 8]
[(4, 0), (3, 1), (0, 2), (2, 2), (1, 3)]
sage: C = graphs.CycleGraph(4)
sage: list(C.breadth_first_search([0, 1], report_distance=True))
[(0, 0), (1, 0), (3, 1), (2, 1)]
You can get edges of the BFS tree instead of the vertices using the edges parameter:
sage: D = DiGraph({1:[2,3],2:[4],3:[4],4:[1],5:[2,6]})
sage: list(D.breadth_first_search(1, edges=True))
[(1, 2), (1, 3), (2, 4)]
Note: Make sure you always compare canonical forms obtained by the same algorithm.
• return_graph – boolean (default: True). When set to False, returns the list of edges of the canonical
graph instead of the canonical graph; only available when 'bliss' is explicitly set as algorithm.
EXAMPLES:
Canonization changes isomorphism to equality:
sage: g1 = graphs.GridGraph([2,3])
sage: g2 = Graph({1: [2, 4], 3: [2, 6], 5: [4, 2, 6]})
sage: g1 == g2
False
sage: g1.is_isomorphic(g2)
True
sage: g1.canonical_label() == g2.canonical_label()
True
sage: G = Graph(multiedges=True,sparse=True)
sage: G.add_edge((0,1))
sage: G.add_edge((0,1))
sage: G.add_edge((0,1))
sage: G.canonical_label()
Multi-graph on 2 vertices
sage: Graph('A?').canonical_label()
Graph on 2 vertices
sage: P = graphs.PetersenGraph()
sage: DP = P.to_directed()
sage: DP.canonical_label(algorithm='sage').adjacency_matrix()
[0 0 0 0 0 0 0 1 1 1]
[0 0 0 0 1 0 1 0 0 1]
[0 0 0 1 0 0 1 0 1 0]
[0 0 1 0 0 1 0 0 0 1]
[0 1 0 0 0 1 0 0 1 0]
[0 0 0 1 1 0 0 1 0 0]
[0 1 1 0 0 0 0 1 0 0]
(continues on next page)
sage: G = Graph(sparse=True)
sage: G.add_edges( [(0,1,'a'),(1,2,'b'),(2,3,'c'),(3,4,'b'),(4,0,'a')] )
sage: G.canonical_label(edge_labels=True)
Graph on 5 vertices
sage: G.canonical_label(edge_labels=True, algorithm="bliss", certificate=True)
˓→# optional - bliss
cartesian_product(other)
Return the Cartesian product of self and other.
The Cartesian product of 𝐺 and 𝐻 is the graph 𝐿 with vertex set 𝑉 (𝐿) equal to the Cartesian product of
the vertices 𝑉 (𝐺) and 𝑉 (𝐻), and ((𝑢, 𝑣), (𝑤, 𝑥)) is an edge iff either - (𝑢, 𝑤) is an edge of self and 𝑣 = 𝑥,
or - (𝑣, 𝑥) is an edge of other and 𝑢 = 𝑤.
See also:
categorical_product(other)
Return the tensor product of self and other.
The tensor product of 𝐺 and 𝐻 is the graph 𝐿 with vertex set 𝑉 (𝐿) equal to the Cartesian product of the
vertices 𝑉 (𝐺) and 𝑉 (𝐻), and ((𝑢, 𝑣), (𝑤, 𝑥)) is an edge iff - (𝑢, 𝑤) is an edge of self, and - (𝑣, 𝑥) is an
edge of other.
The tensor product is also known as the categorical product and the Kronecker product (referring to the
Kronecker matrix product). See the Wikipedia article Kronecker_product.
EXAMPLES:
sage: Z = graphs.CompleteGraph(2)
sage: C = graphs.CycleGraph(5)
sage: T = C.tensor_product(Z); T
(continues on next page)
sage: D = graphs.DodecahedralGraph()
sage: P = graphs.PetersenGraph()
sage: T = D.tensor_product(P); T
Graph on 200 vertices
sage: T.size()
900
sage: T.plot() # long time
Graphics object consisting of 1101 graphics primitives
• centrality_degree()
• centrality_closeness()
EXAMPLES:
sage: g = graphs.ChvatalGraph()
sage: g.centrality_betweenness() # abs tol 1e-10
{0: 0.06969696969696969, 1: 0.06969696969696969,
2: 0.0606060606060606, 3: 0.0606060606060606,
(continues on next page)
𝑟(𝑣) − 1 𝑟(𝑣) − 1
𝑐(𝑣) = ∑︀
𝑤∈𝑅(𝑣) 𝑑(𝑣, 𝑤) 𝑛−1
where 𝑅(𝑣) is the set of vertices reachable from 𝑣, and 𝑟(𝑣) is the cardinality of 𝑅(𝑣).
‘Closeness centrality may be defined as the total graph-theoretic distance of a given vertex from all other
vertices. . . Closeness is an inverse measure of centrality in that a larger value indicates a less central actor
while a smaller value indicates a more central actor,’ [Bor1995].
For more information, see the Wikipedia article Centrality.
INPUT:
• vert – the vertex or the list of vertices we want to analyze. If None (default), all vertices are considered.
• by_weight – boolean (default: False); if True, the edges in the graph are weighted, and otherwise
all edges have weight 1
• algorithm – string (default: None); one of the following algorithms:
– 'BFS': performs a BFS from each vertex that has to be analyzed. Does not work with edge weights.
– 'NetworkX': the NetworkX algorithm (works only with positive weights).
– 'Dijkstra_Boost': the Dijkstra algorithm, implemented in Boost (works only with positive
weights).
– 'Floyd-Warshall-Cython': the Cython implementation of the Floyd-Warshall algorithm.
Works only if by_weight==False and all centralities are needed.
– 'Floyd-Warshall-Python': the Python implementation of the Floyd-Warshall algorithm.
Works only if all centralities are needed, but it can deal with weighted graphs, even with neg-
ative weights (but no negative cycle is allowed).
– 'Johnson_Boost': the Johnson algorithm, implemented in Boost (works also with negative
weights, if there is no negative cycle).
– None (default): Sage chooses the best algorithm: 'BFS' if by_weight is False,
'Dijkstra_Boost' if all weights are positive, 'Johnson_Boost' otherwise.
• weight_function – function (default: None); a function that takes as input an edge (u, v, l) and
outputs its weight. If not None, by_weight is automatically set to True. If None and by_weight is
True, we use the edge label l as a weight, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs a
number for each edge.
OUTPUT:
If vert is a vertex, the closeness centrality of that vertex. Otherwise, a dictionary associating to each vertex
in vert its closeness centrality. If a vertex has (out)degree 0, its closeness centrality is not defined, and the
vertex is not included in the output.
See also:
• centrality_closeness_top_k()
• centrality_degree()
• centrality_betweenness()
EXAMPLES:
Standard examples:
sage: (graphs.ChvatalGraph()).centrality_closeness()
{0: 0.61111111111111..., 1: 0.61111111111111..., 2: 0.61111111111111..., 3: 0.
˓→61111111111111..., 4: 0.61111111111111..., 5: 0.61111111111111..., 6: 0.
In a (strongly) connected (di)graph, the closeness centrality of 𝑣 is inverse of the average distance between
𝑣 and all other vertices:
sage: g = graphs.PathGraph(5)
sage: g.centrality_closeness(0)
0.4
sage: dist = g.shortest_path_lengths(0).values()
sage: float(len(dist)-1) / sum(dist)
0.4
sage: d = g.to_directed()
sage: d.centrality_closeness(0)
0.4
sage: dist = d.shortest_path_lengths(0).values()
(continues on next page)
sage: g = Graph(5)
sage: g.centrality_closeness()
{}
sage: print(g.centrality_closeness(0))
None
Weighted graphs:
sage: D = graphs.GridGraph([2,2])
sage: weight_function = lambda e:10
sage: D.centrality_closeness([(0,0),(0,1)]) # tol abs␣
˓→1e-12
0.075
characteristic_polynomial(var='x', laplacian=False)
Return the characteristic polynomial of the adjacency matrix of the (di)graph.
Let 𝐺 be a (simple) graph with adjacency matrix 𝐴. Let 𝐼 be the identity matrix of dimensions the same
as 𝐴. The characteristic polynomial of 𝐺 is defined as the determinant det(𝑥𝐼 − 𝐴).
Note: characteristic_polynomial and charpoly are aliases and thus provide exactly the same
method.
INPUT:
• x – (default: 'x'); the variable of the characteristic polynomial
• laplacian – boolean (default: False); if True, use the Laplacian matrix
See also:
• kirchhoff_matrix()
• laplacian_matrix()
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.characteristic_polynomial()
x^10 - 15*x^8 + 75*x^6 - 24*x^5 - 165*x^4 + 120*x^3 + 120*x^2 - 160*x + 48
sage: P.charpoly()
x^10 - 15*x^8 + 75*x^6 - 24*x^5 - 165*x^4 + 120*x^3 + 120*x^2 - 160*x + 48
sage: P.characteristic_polynomial(laplacian=True)
x^10 - 30*x^9 + 390*x^8 - 2880*x^7 + 13305*x^6 -
39882*x^5 + 77640*x^4 - 94800*x^3 + 66000*x^2 - 20000*x
charpoly(var='x', laplacian=False)
Return the characteristic polynomial of the adjacency matrix of the (di)graph.
Let 𝐺 be a (simple) graph with adjacency matrix 𝐴. Let 𝐼 be the identity matrix of dimensions the same
as 𝐴. The characteristic polynomial of 𝐺 is defined as the determinant det(𝑥𝐼 − 𝐴).
Note: characteristic_polynomial and charpoly are aliases and thus provide exactly the same
method.
INPUT:
• x – (default: 'x'); the variable of the characteristic polynomial
• laplacian – boolean (default: False); if True, use the Laplacian matrix
See also:
• kirchhoff_matrix()
• laplacian_matrix()
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.characteristic_polynomial()
x^10 - 15*x^8 + 75*x^6 - 24*x^5 - 165*x^4 + 120*x^3 + 120*x^2 - 160*x + 48
sage: P.charpoly()
x^10 - 15*x^8 + 75*x^6 - 24*x^5 - 165*x^4 + 120*x^3 + 120*x^2 - 160*x + 48
sage: P.characteristic_polynomial(laplacian=True)
x^10 - 30*x^9 + 390*x^8 - 2880*x^7 + 13305*x^6 -
39882*x^5 + 77640*x^4 - 94800*x^3 + 66000*x^2 - 20000*x
clear()
Empties the graph of vertices and edges and removes name, associated objects, and position information.
EXAMPLES:
sage: G = graphs.CycleGraph(4)
sage: G.set_vertices({0:'vertex0'})
sage: print(G.order(), G.size())
4 4
sage: G.name()
'Cycle graph'
sage: G.get_vertex(0)
'vertex0'
sage: H = G.copy(sparse=True)
sage: H.clear()
sage: print(H.order(), H.size())
0 0
sage: H.name()
''
sage: H.get_vertex(0)
sage: H = G.copy(sparse=False)
sage: H.clear()
sage: print(H.order(), H.size())
(continues on next page)
cluster_transitivity()
Return the transitivity (fraction of transitive triangles) of the graph.
triangles
Transitivity is the fraction of all existing triangles over all connected triples (triads), 𝑇 = 3 × triads .
sage: graphs.FruchtGraph().cluster_transitivity()
0.25
cluster_triangles(nbunch=None, implementation=None)
Return the number of triangles for the set 𝑛𝑏𝑢𝑛𝑐ℎ of vertices as a dictionary keyed by vertex.
See also section “Clustering” in chapter “Algorithms” of [HSS].
INPUT:
• nbunch – a list of vertices (default: None); the vertices to inspect. If ``nbunch=None,
returns data for all vertices in the graph.
• implementation – string (default: None); one of 'sparse_copy', 'dense_copy', 'networkx'
or None (default). In the latter case, the best algorithm available is used. Note that 'networkx' does
not support directed graphs.
EXAMPLES:
sage: F = graphs.FruchtGraph()
sage: list(F.cluster_triangles().values())
[1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0]
sage: F.cluster_triangles()
{0: 1, 1: 1, 2: 0, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 0, 9: 1, 10: 1, 11: 0}
sage: F.cluster_triangles(nbunch=[0, 1, 2])
{0: 1, 1: 1, 2: 0}
clustering_average(implementation=None)
Return the average clustering coefficient.
The clustering coefficient of a node(︀ 𝑖 is
)︀ the fraction of existing triangles containing node 𝑖 over all possible
triangles containing 𝑖: 𝑐𝑖 = 𝑇 (𝑖)/ 𝑘2𝑖 where 𝑇 (𝑖) is the number of existing triangles through 𝑖, and 𝑘𝑖 is
the degree of vertex 𝑖.
A coefficient for the whole graph is the average of the 𝑐𝑖 .
See also section “Clustering” in chapter “Algorithms” of [HSS].
INPUT:
• implementation – string (default: None); one of 'boost', 'sparse_copy', 'dense_copy',
'networkx' or None (default). In the latter case, the best algorithm available is used. Note that
only 'networkx' supports directed graphs.
EXAMPLES:
sage: (graphs.FruchtGraph()).clustering_average()
1/4
sage: (graphs.FruchtGraph()).clustering_average(implementation='networkx')
0.25
sage: graphs.FruchtGraph().clustering_coeff()
{0: 1/3, 1: 1/3, 2: 0, 3: 1/3, 4: 1/3, 5: 1/3,
6: 1/3, 7: 1/3, 8: 0, 9: 1/3, 10: 1/3, 11: 0}
sage: (graphs.FruchtGraph()).clustering_coeff(weight=True)
{0: 0.3333333333333333, 1: 0.3333333333333333, 2: 0,
3: 0.3333333333333333, 4: 0.3333333333333333,
5: 0.3333333333333333, 6: 0.3333333333333333,
7: 0.3333333333333333, 8: 0, 9: 0.3333333333333333,
10: 0.3333333333333333, 11: 0}
sage: (graphs.FruchtGraph()).clustering_coeff(nodes=[0,1,2])
{0: 0.3333333333333333, 1: 0.3333333333333333, 2: 0.0}
sage: (graphs.FruchtGraph()).clustering_coeff(nodes=[0,1,2],
....: weight=True)
{0: 0.3333333333333333, 1: 0.3333333333333333, 2: 0}
(continues on next page)
sage: (graphs.GridGraph([5,5])).clustering_coeff(nodes=[(0,0),(0,1),(2,2)])
{(0, 0): 0.0, (0, 1): 0.0, (2, 2): 0.0}
coarsest_equitable_refinement(partition, sparse=True)
Return the coarsest partition which is finer than the input partition, and equitable with respect to self.
A partition is equitable with respect to a graph if for every pair of cells 𝐶1 , 𝐶2 of the partition, the number
of edges from a vertex of 𝐶1 to 𝐶2 is the same, over all vertices in 𝐶1 .
A partition 𝑃1 is finer than 𝑃2 (𝑃2 is coarser than 𝑃1 ) if every cell of 𝑃1 is a subset of a cell of 𝑃2 .
INPUT:
• partition – a list of lists
• sparse – boolean (default: False); whether to use sparse or dense representation - for small
graphs, use dense for speed
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.coarsest_equitable_refinement([[0],list(range(1,10))])
[[0], [2, 3, 6, 7, 8, 9], [1, 4, 5]]
sage: G = graphs.CubeGraph(3)
sage: verts = G.vertices(sort=True)
sage: Pi = [verts[:1], verts[1:]]
sage: Pi
[['000'], ['001', '010', '011', '100', '101', '110', '111']]
sage: [sorted(cell) for cell in G.coarsest_equitable_refinement(Pi)]
[['000'], ['011', '101', '110'], ['111'], ['001', '010', '100']]
Note that given an equitable partition, this function returns that partition:
sage: P = graphs.PetersenGraph()
sage: prt = [[0], [1, 4, 5], [2, 3, 6, 7, 8, 9]]
sage: P.coarsest_equitable_refinement(prt)
[[0], [1, 4, 5], [2, 3, 6, 7, 8, 9]]
sage: ss = (graphs.WheelGraph(6)).line_graph(labels=False)
sage: prt = [[(0, 1)], [(0, 2), (0, 3), (0, 4), (1, 2), (1, 4)], [(2, 3), (3,␣
˓→4)]]
sage: ss.coarsest_equitable_refinement(prt)
Traceback (most recent call last):
...
TypeError: partition ([[(0, 1)], [(0, 2), (0, 3), (0, 4), (1, 2), (1, 4)], [(2,␣
˓→3), (3, 4)]]) is not valid for this graph: vertices are incorrect
sage: ss = (graphs.WheelGraph(5)).line_graph(labels=False)
sage: ss.coarsest_equitable_refinement(prt)
[[(0, 1)], [(1, 2), (1, 4)], [(0, 3)], [(0, 4), (0, 2)], [(2, 3), (3, 4)]]
The complement of a graph has the same vertices, but exactly those edges that are not in the original graph.
This is not well defined for graphs with multiple edges.
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.plot() # long time
Graphics object consisting of 26 graphics primitives
sage: PC = P.complement()
sage: PC.plot() # long time
Graphics object consisting of 41 graphics primitives
sage: graphs.TetrahedralGraph().complement().size()
0
sage: graphs.CycleGraph(4).complement().edges(sort=True)
[(0, 2, None), (1, 3, None)]
sage: graphs.CycleGraph(4).complement()
complement(Cycle graph): Graph on 4 vertices
sage: G = Graph(multiedges=True, sparse=True)
sage: G.add_edges([(0, 1)] * 3)
sage: G.complement()
Traceback (most recent call last):
...
ValueError: This method is not known to work on graphs with
multiedges. Perhaps this method can be updated to handle them, but
in the meantime if you want to use it please disallow multiedges
using allow_multiple_edges().
connected_components(G, sort=True)
Return the list of connected components.
This returns a list of lists of vertices, each list representing a connected component. The list is ordered from
largest to smallest component.
INPUT:
connected_components_number(G)
Return the number of connected components.
INPUT:
• G – the input graph
EXAMPLES:
connected_components_sizes(G)
Return the sizes of the connected components as a list.
The list is sorted from largest to lower values.
EXAMPLES:
connected_components_subgraphs(G)
Return a list of connected components as graph objects.
EXAMPLES:
sage: G = graphs.CompleteGraph(4)
sage: G.contract_edge((0, 1)); G.edges(sort=True)
[(0, 2, None), (0, 3, None), (2, 3, None)]
sage: G = graphs.CompleteGraph(4)
sage: G.allow_loops(True); G.allow_multiple_edges(True)
sage: G.contract_edge((0, 1)); G.edges(sort=True)
[(0, 2, None), (0, 2, None), (0, 3, None), (0, 3, None), (2, 3, None)]
sage: G.contract_edge((0, 2)); G.edges(sort=True)
[(0, 0, None), (0, 3, None), (0, 3, None), (0, 3, None)]
sage: G = graphs.CompleteGraph(4).to_directed()
sage: G.allow_loops(True)
sage: G.contract_edge(0, 1); G.edges(sort=True)
[(0, 0, None),
(0, 2, None),
(0, 3, None),
(2, 0, None),
(2, 3, None),
(3, 0, None),
(3, 2, None)]
contract_edges(edges)
Contract edges from an iterable container.
If 𝑒 is an edge that is not contracted but the vertices of 𝑒 are merged by contraction of other edges, then 𝑒
will become a loop.
INPUT:
• edges – a list containing 2-tuples or 3-tuples that represent edges
EXAMPLES:
sage: G = graphs.CompleteGraph(4)
sage: G.allow_loops(True); G.allow_multiple_edges(True)
sage: G.contract_edges([(0, 1), (1, 2), (0, 2)]); G.edges(sort=True)
[(0, 3, None), (0, 3, None), (0, 3, None)]
sage: G.contract_edges([(1, 3), (2, 3)]); G.edges(sort=True)
[(0, 3, None), (0, 3, None), (0, 3, None)]
sage: G = graphs.CompleteGraph(4)
sage: G.allow_loops(True); G.allow_multiple_edges(True)
sage: G.contract_edges([(0, 1), (1, 2), (0, 2), (1, 3), (2, 3)]); G.
˓→edges(sort=True)
[(0, 0, None)]
sage: D = digraphs.Complete(4)
sage: D.allow_loops(True); D.allow_multiple_edges(True)
sage: D.contract_edges([(0, 1), (1, 0), (0, 2)]); D.edges(sort=True)
[(0, 0, None),
(0, 0, None),
(0, 0, None),
(0, 3, None),
(0, 3, None),
(0, 3, None),
(3, 0, None),
(3, 0, None),
(3, 0, None)]
Note: If the graph uses StaticSparseBackend and the _immutable flag, then self is returned rather
than a copy (unless one of the optional arguments is used).
OUTPUT:
A Graph object.
Warning: Please use this method only if you need to copy but change the underlying data structure or
weightedness. Otherwise simply do copy(g) instead of g.copy().
Warning: If weighted is passed and is not the weightedness of the original, then the copy will not
equal the original.
EXAMPLES:
sage: g == copy(g)
True
sage: T = graphs.TetrahedralGraph()
sage: T.set_vertices(d)
sage: T2 = copy(T)
sage: T2.get_vertex(0)
Dodecahedron: Graph on 20 vertices
sage: G = graphs.CompleteGraph(9)
sage: H = G.copy()
sage: H == G; H is G
True
False
sage: G1 = G.copy(sparse=True)
sage: G1 == G
True
sage: G1 is G
False
(continues on next page)
sage: G = graphs.CompleteGraph(5)
sage: H1 = G.copy(weighted=False)
sage: H2 = G.copy(weighted=True)
sage: [G.weighted(), H1.weighted(), H2.weighted()]
[False, False, True]
sage: [G == H1, G == H2, H1 == H2]
[True, False, False]
sage: G.weighted(True)
sage: [G == H1, G == H2, H1 == H2]
[False, True, False]
crossing_number()
Return the crossing number of the graph.
The crossing number of a graph is the minimum number of edge crossings needed to draw the graph on a
plane. It can be seen as a measure of non-planarity; a planar graph has crossing number zero.
See the Wikipedia article Crossing_number for more information.
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.crossing_number()
2
ALGORITHM:
This is slow brute force implementation: for every 𝑘 pairs of edges try adding a new vertex for a crossing
point for them. If the result is not planar in any of those, try 𝑘 + 1 pairs.
Computing the crossing number is NP-hard problem.
cycle_basis(output='vertex')
Return a list of cycles which form a basis of the cycle space of self.
A basis of cycles of a graph is a minimal collection of cycles (considered as sets of edges) such that the
edge set of any cycle in the graph can be written as a 𝑍/2𝑍 sum of the cycles in the basis.
See the Wikipedia article Cycle_basis for more information.
INPUT:
• output – string (default: 'vertex'); whether every cycle is given as a list of vertices (output ==
'vertex') or a list of edges (output == 'edge')
OUTPUT:
A list of lists, each of them representing the vertices (or the edges) of a cycle in a basis.
ALGORITHM:
Uses the NetworkX library for graphs without multiple edges.
Otherwise, by the standard algorithm using a spanning tree.
EXAMPLES:
A cycle basis in Petersen’s Graph
sage: g = graphs.PetersenGraph()
sage: g.cycle_basis()
[[1, 6, 8, 5, 0], [4, 9, 6, 8, 5, 0], [7, 9, 6, 8, 5], [4, 3, 8, 5, 0], [1, 2,␣
˓→3, 8, 5, 0], [7, 2, 3, 8, 5]]
sage: g.cycle_basis(output='edge')
[[(1, 6, None), (6, 8, None), (8, 5, None), (5, 0, None),
(0, 1, None)], [(4, 9, None), (9, 6, None), (6, 8, None),
(8, 5, None), (5, 0, None), (0, 4, None)], [(7, 9, None),
(9, 6, None), (6, 8, None), (8, 5, None), (5, 7, None)],
[(4, 3, None), (3, 8, None), (8, 5, None), (5, 0, None),
(0, 4, None)], [(1, 2, None), (2, 3, None), (3, 8, None),
(8, 5, None), (5, 0, None), (0, 1, None)], [(7, 2, None),
(2, 3, None), (3, 8, None), (8, 5, None), (5, 7, None)]]
Building the space of (directed) edges over 𝑍/2𝑍. On the way, building a dictionary associating a unique
vector to each undirected edge:
sage: m = g.size()
sage: edge_space = VectorSpace(FiniteField(2), m)
sage: edge_vector = dict(zip(g.edges(labels=False, sort=False), edge_space.
˓→basis()))
sage: G.cycle_basis()
[[0, 2], [2, 1, 0]]
sage: G.cycle_basis(output='edge')
(continues on next page)
sage: H.cycle_basis()
[[1, 4], [2, 3], [4, 3, 2, 1], [6, 5, 4]]
Disconnected graph:
Graph that allows multiple edges but does not contain any:
sage: G = graphs.CycleGraph(3)
sage: G.allow_multiple_edges(True)
sage: G.cycle_basis()
[[2, 1, 0]]
degree(vertices=None, labels=False)
Return the degree (in + out for digraphs) of a vertex or of vertices.
INPUT:
• vertices – a vertex or an iterable container of vertices (default: None); if vertices is a single vertex,
returns the number of neighbors of that vertex. If vertices is an iterable container of vertices, returns
a list of degrees. If vertices is None, same as listing all vertices.
• labels – boolean (default: False); when True, return a dictionary mapping each vertex in vertices
to its degree. Otherwise, return the degree of a single vertex or a list of the degrees of each vertex in
vertices
OUTPUT:
• When vertices is a single vertex and labels is False, returns the degree of that vertex as an integer
• When vertices is an iterable container of vertices (or None) and labels is False, returns a list of
integers. The 𝑖-th value is the degree of the 𝑖-th vertex in the list vertices. When vertices is None,
the 𝑖-th value is the degree of 𝑖-th vertex in the ordering list(self), which might be different from
the ordering of the vertices given by g.vertices(sort=True).
• When labels is True, returns a dictionary mapping each vertex in vertices to its degree
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.degree(5)
3
sage: K = graphs.CompleteGraph(9)
sage: K.degree()
[8, 8, 8, 8, 8, 8, 8, 8, 8]
sage: D = DiGraph({0: [1, 2, 3], 1: [0, 2], 2: [3], 3: [4], 4: [0,5], 5: [1]})
sage: D.degree(vertices=[0, 1, 2], labels=True)
{0: 5, 1: 4, 2: 3}
sage: D.degree()
[5, 4, 3, 3, 3, 2]
When vertices=None and labels=False, the 𝑖-th value of the returned list is the degree of the 𝑖-th
vertex in the list list(self):
sage: D = digraphs.DeBruijn(4, 2)
sage: D.delete_vertex('20')
sage: print(D.degree())
[7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8]
sage: print(D.degree(vertices=list(D)))
[7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8]
sage: print(D.degree(vertices=D.vertices(sort=False)))
[7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8]
degree_histogram()
Return a list, whose 𝑖-th entry is the frequency of degree 𝑖.
EXAMPLES:
degree_iterator(vertices=None, labels=False)
Return an iterator over the degrees of the (di)graph.
In the case of a digraph, the degree is defined as the sum of the in-degree and the out-degree, i.e. the total
number of edges incident to a given vertex.
INPUT:
• vertices – a vertex or an iterable container of vertices (default: None); if vertices is a single vertex,
the iterator will yield the number of neighbors of that vertex. If vertices is an iterable container of
vertices, return an iterator over the degrees of these vertices. If vertices is None, same as listing all
vertices.
• labels – boolean (default: False); whether to return an iterator over degrees (labels=False), or
over tuples (vertex, degree)
Note: The returned iterator yields values in order specified by list(vertices). When vertices is
None, it yields values in the same order as list(self), which might be different from the ordering of the
vertices given by g.vertices(sort=True).
EXAMPLES:
sage: G = graphs.Grid2dGraph(3, 4)
sage: for i in G.degree_iterator():
....: print(i)
2
3
3
...
3
2
sage: for i in G.degree_iterator(labels=True):
....: print(i)
((0, 0), 2)
((0, 1), 3)
((0, 2), 3)
...
((2, 2), 3)
((2, 3), 2)
sage: D = graphs.Grid2dGraph(2,4).to_directed()
sage: for i in D.degree_iterator():
....: print(i)
4
6
...
6
4
sage: for i in D.degree_iterator(labels=True):
....: print(i)
((0, 0), 4)
((0, 1), 6)
...
((1, 2), 6)
((1, 3), 4)
sage: V = list(D)
sage: D = digraphs.DeBruijn(4, 2)
sage: D.delete_vertex('20')
sage: print(list(D.degree_iterator()))
[7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8]
sage: print([D.degree(v) for v in D])
[7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8]
degree_sequence()
Return the degree sequence of this (di)graph.
EXAMPLES:
The degree sequence of an undirected graph:
sage: g = Graph({1: [2, 5], 2: [1, 5, 3, 4], 3: [2, 5], 4: [3], 5: [2, 3]})
sage: g.degree_sequence()
[4, 3, 3, 2, 2]
sage: g = DiGraph({1: [2, 5, 6], 2: [3, 6], 3: [4, 6], 4: [6], 5: [4, 6]})
sage: g.degree_sequence()
[5, 3, 3, 3, 3, 3]
sage: graphs.PetersenGraph().degree_sequence()
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
sage: graphs.HouseGraph().degree_sequence()
[3, 3, 2, 2, 2]
sage: graphs.FlowerSnark().degree_sequence()
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
degree_to_cell(vertex, cell)
Returns the number of edges from vertex to an edge in cell. In the case of a digraph, returns a tuple
(in_degree, out_degree).
EXAMPLES:
sage: G = graphs.CubeGraph(3)
sage: cell = G.vertices(sort=True)[:3]
sage: G.degree_to_cell('011', cell)
2
sage: G.degree_to_cell('111', cell)
0
sage: G = graphs.CompleteGraph(9)
sage: G.size()
36
sage: G.delete_edge( 1, 2 )
sage: G.delete_edge( (3, 4) )
sage: G.delete_edges( [ (5, 6), (7, 8) ] )
sage: G.size()
32
sage: C = digraphs.Complete(9)
sage: C.size()
72
sage: C.delete_edge( 1, 2 )
sage: C.delete_edge( (3, 4) )
sage: C.delete_edges( [ (5, 6), (7, 8) ] )
sage: C.size()
68
delete_edges(edges)
Delete edges from an iterable container.
EXAMPLES:
delete_multiedge(u, v)
Delete all edges from u to v.
EXAMPLES:
sage: D.edges(sort=True)
[(0, 1, 1), (0, 1, 2), (0, 1, 3), (1, 0, None), (1, 2, None), (2, 3, None)]
sage: D.delete_multiedge(0, 1)
sage: D.edges(sort=True)
[(1, 0, None), (1, 2, None), (2, 3, None)]
delete_vertex(vertex, in_order=False)
Delete vertex, removing all incident edges.
Deleting a non-existent vertex will raise an exception.
INPUT:
• in_order – boolean (default: False); if True, this deletes the 𝑖-th vertex in the sorted list of vertices,
i.e. G.vertices(sort=True)[i]
EXAMPLES:
sage: G = Graph(graphs.WheelGraph(9))
sage: G.delete_vertex(0); G.show()
sage: G = graphs.CompleteGraph(4).line_graph(labels=False)
sage: G.vertices(sort=True)
[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
sage: G.delete_vertex(0, in_order=True)
sage: G.vertices(sort=True)
[(0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
sage: G = graphs.PathGraph(5)
sage: G.set_vertices({0: 'no delete', 1: 'delete'})
sage: G.delete_vertex(1)
sage: G.get_vertices()
{0: 'no delete', 2: None, 3: None, 4: None}
sage: G.get_pos()
{0: (0, 0), 2: (2, 0), 3: (3, 0), 4: (4, 0)}
delete_vertices(vertices)
Delete vertices from the (di)graph taken from an iterable container of vertices.
Deleting a non-existent vertex will raise an exception, in which case none of the vertices in vertices is
deleted.
EXAMPLES:
density()
Return the density of the (di)graph.
The density of a (di)graph is defined as the number of edges divided by number of possible edges.
In the case of a multigraph, raises an error, since there is an infinite number of possible edges.
EXAMPLES:
sage: d = {0: [1,4,5], 1: [2,6], 2: [3,7], 3: [4,8], 4: [9], 5: [7, 8], 6: [8,
˓→9], 7: [9]}
sage: G = Graph(d); G.density()
1/3
sage: G = Graph({0: [1, 2], 1: [0]}); G.density()
2/3
sage: G = DiGraph({0: [1, 2], 1: [0]}); G.density()
1/2
sage: G.allow_loops(True)
sage: G.density()
1/3
• breadth_first_search()
• breadth_first_search – breadth-first search for fast compiled graphs.
• depth_first_search – depth-first search for fast compiled graphs.
EXAMPLES:
By default, the edge direction of a digraph is respected, but this can be overridden by the
ignore_direction parameter:
sage: D = DiGraph({0: [1, 2, 3], 1: [4, 5], 2: [5], 3: [6], 5: [7], 6: [7], 7:␣
˓→[0]})
sage: list(D.depth_first_search(0))
[0, 3, 6, 7, 2, 5, 1, 4]
sage: list(D.depth_first_search(0, ignore_direction=True))
[0, 7, 6, 3, 5, 2, 1, 4]
sage: D = DiGraph({0: [1, 2, 3], 1: [4, 5], 2: [5], 3: [6], 5: [7], 6: [7], 7:␣
˓→[0]})
sage: list(D.depth_first_search([0]))
[0, 3, 6, 7, 2, 5, 1, 4]
sage: list(D.depth_first_search([0, 6]))
[0, 3, 6, 7, 2, 5, 1, 4]
More generally, you can specify a neighbors function. For example, you can traverse the graph backwards
by setting neighbors to be the neighbors_in() function of the graph:
sage: D = digraphs.Path(10)
sage: D.add_path([22, 23, 24, 5])
sage: D.add_path([5, 33, 34, 35])
sage: list(D.depth_first_search(5, neighbors=D.neighbors_in))
[5, 4, 3, 2, 1, 0, 24, 23, 22]
sage: list(D.breadth_first_search(5, neighbors=D.neighbors_in))
[5, 24, 4, 23, 3, 22, 2, 1, 0]
sage: list(D.depth_first_search(5, neighbors=D.neighbors_out))
[5, 6, 7, 8, 9, 33, 34, 35]
sage: list(D.breadth_first_search(5, neighbors=D.neighbors_out))
[5, 33, 6, 34, 7, 35, 8, 9]
You can get edges of the DFS tree instead of the vertices using the edges parameter:
sage: D = digraphs.Path(5)
sage: list(D.depth_first_search(2, edges=True))
[(2, 3), (3, 4)]
sage: list(D.depth_first_search(2, edges=True, ignore_direction=True))
[(2, 3), (3, 4), (2, 1), (1, 0)]
sage: g = graphs.Grid2dGraph(5, 5)
sage: p1,p2 = g.disjoint_routed_paths([((0, 0), (0, 4)), ((4, 4), (4, 0))])
Though there is obviously no solution to the problem in which each corner is sending information to the
opposite one:
sage: g = graphs.Grid2dGraph(5, 5)
sage: p1,p2 = g.disjoint_routed_paths([((0, 0), (4, 4)), ((0, 4), (4, 0))])
Traceback (most recent call last):
...
EmptySetError: the disjoint routed paths do not exist
INPUT:
• labels – string (default: 'pairs'); if set to 'pairs', each element v in the first graph will be named
(0, v) and each element u in other will be named (1, u) in the result. If set to 'integers', the
elements of the result will be relabeled with consecutive integers.
• immutable – boolean (default: None); whether to create a mutable/immutable disjoint union.
immutable=None (default) means that the graphs and their disjoint union will behave the same way.
See also:
• union()
• join()
EXAMPLES:
sage: G = graphs.CycleGraph(3)
sage: H = graphs.CycleGraph(4)
sage: J = G.disjoint_union(H); J
Cycle graph disjoint_union Cycle graph: Graph on 7 vertices
sage: J.vertices(sort=True)
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (1, 3)]
sage: J = G.disjoint_union(H, labels='integers'); J
Cycle graph disjoint_union Cycle graph: Graph on 7 vertices
sage: J.vertices(sort=True)
[0, 1, 2, 3, 4, 5, 6]
sage: (G + H).vertices(sort=True) # '+'-operator is a shortcut
[0, 1, 2, 3, 4, 5, 6]
disjunctive_product(other)
Return the disjunctive product of self and other.
The disjunctive product of 𝐺 and 𝐻 is the graph 𝐿 with vertex set 𝑉 (𝐿) = 𝑉 (𝐺) × 𝑉 (𝐻), and
((𝑢, 𝑣), (𝑤, 𝑥)) is an edge iff either :
• (𝑢, 𝑤) is an edge of 𝐺, or
• (𝑣, 𝑥) is an edge of 𝐻.
EXAMPLES:
sage: Z = graphs.CompleteGraph(2)
sage: D = Z.disjunctive_product(Z); D
Graph on 4 vertices
sage: D.plot() # long time
Graphics object consisting of 11 graphics primitives
sage: C = graphs.CycleGraph(5)
sage: D = C.disjunctive_product(Z); D
Graph on 10 vertices
sage: D.plot() # long time
Graphics object consisting of 46 graphics primitives
sage: G = graphs.CycleGraph(9)
sage: G.distance(0,1)
1
sage: G.distance(0,4)
4
sage: G.distance(0,5)
4
sage: G = Graph({0:[], 1:[]})
sage: G.distance(0,1)
+Infinity
sage: G = Graph({ 0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2}},␣
˓→sparse = True)
Note: There is a Cython version of this method that is usually much faster for large graphs, as most of the
time is actually spent building the final double dictionary. Everything on the subject is to be found in the
distances_all_pairs module.
EXAMPLES:
The Petersen Graph:
sage: g = graphs.PetersenGraph()
sage: print(g.distance_all_pairs())
{0: {0: 0, 1: 1, 2: 2, 3: 2, 4: 1, 5: 1, 6: 2, 7: 2, 8: 2, 9: 2}, 1: {0: 1, 1:␣
˓→0, 2: 1, 3: 2, 4: 2, 5: 2, 6: 1, 7: 2, 8: 2, 9: 2}, 2: {0: 2, 1: 1, 2: 0, 3:␣
˓→5: 2, 6: 1, 7: 1, 8: 2, 9: 0}}
sage: g = graphs.RandomGNP(20,.3)
sage: distances = g.distance_all_pairs()
(continues on next page)
See also:
• distance_matrix()
• shortest_path_all_pairs()
sage: G = graphs.CubeGraph(3)
sage: G.distance_matrix()
[0 1 1 2 1 2 2 3]
[1 0 2 1 2 1 3 2]
[1 2 0 1 2 3 1 2]
[2 1 1 0 3 2 2 1]
[1 2 2 3 0 1 1 2]
[2 1 3 2 1 0 2 1]
(continues on next page)
The well known result of Graham and Pollak states that the determinant of the distance matrix of any tree
of order 𝑛 is (−1)𝑛−1 (𝑛 − 1)2𝑛−2 :
See also:
distances_distribution(G)
Return the distances distribution of the (di)graph in a dictionary.
This method ignores all edge labels, so that the distance considered is the topological distance.
OUTPUT:
A dictionary d such that the number of pairs of vertices at distance k (if any) is equal to 𝑑[𝑘] ·
|𝑉 (𝐺)| · (|𝑉 (𝐺)| − 1).
Note: We consider that two vertices that do not belong to the same connected component are at infinite
distance, and we do not take the trivial pairs of vertices (𝑣, 𝑣) at distance 0 into account. Empty (di)graphs
and (di)graphs of order 1 have no paths and so we return the empty dictionary {}.
EXAMPLES:
An empty Graph:
sage: g = Graph()
sage: g.distances_distribution()
{}
A Graph of order 1:
sage: g = Graph()
sage: g.add_vertex(1)
sage: g.distances_distribution()
{}
sage: g = Graph()
sage: g.add_vertices([1,2])
sage: g.distances_distribution()
{+Infinity: 1}
sage: g = graphs.PetersenGraph()
sage: g.distances_distribution()
{1: 1/3, 2: 2/3}
sage: g = graphs.PetersenGraph()
sage: g.add_edge('good','wine')
sage: g.distances_distribution()
{1: 8/33, 2: 5/11, +Infinity: 10/33}
sage: D = digraphs.DeBruijn(2,3)
sage: D.distances_distribution()
{1: 1/4, 2: 11/28, 3: 5/14}
∀𝑥 ∈ 𝐺, 𝑏𝑥 is a binary variable
INPUT:
• k – a non-negative integer (default: 1); the domination distance
• independent – boolean (default: False); when True, computes a minimum independent dominating
set, that is a minimum dominating set that is also an independent set (see also independent_set())
• total – boolean (default: False); when True, computes a total dominating set (see the See the
Wikipedia article Dominating_set)
• value_only – boolean (default: False); whether to only return the cardinality of the computed dom-
inating set, or to return its list of vertices (default)
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
EXAMPLES:
A basic illustration on a PappusGraph:
sage: g = graphs.PappusGraph()
sage: g.dominating_set(value_only=True)
5
If we build a graph from two disjoint stars, then link their centers we will find a difference between the
cardinality of an independent set and a stable independent set:
sage: g = 2 * graphs.StarGraph(5)
sage: g.add_edge(0, 6)
sage: len(g.dominating_set())
2
sage: len(g.dominating_set(independent=True))
6
sage: G = graphs.PetersenGraph()
sage: G.dominating_set(total=True, value_only=True)
4
The dominating set is calculated for both the directed and undirected graphs (modification introduced in
trac ticket #17905):
sage: g = digraphs.Path(3)
sage: g.dominating_set(value_only=True)
2
sage: g = graphs.PathGraph(3)
sage: g.dominating_set(value_only=True)
1
sage: G = graphs.PetersenGraph()
sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)]
[10, 3, 1]
sage: G = graphs.PathGraph(5)
sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)]
[5, 2, 1]
If the graph is directed, computing a dominator tree is more complicated, and it needs time 𝑂(𝑚 log 𝑚),
where 𝑚 is the number of edges. The implementation provided by Boost is the most general one, so it
needs time 𝑂(𝑚 log 𝑚) even for undirected graphs.
INPUT:
• g – the input Sage (Di)Graph
• root – the root of the dominator tree
• return_dict – boolean (default: False); if True, the function returns a dictionary associating to
each vertex its parent in the dominator tree. If False (default), it returns the whole tree, as a Graph
or a DiGraph.
• reverse – boolean (default: False); when set to True, computes the dominator tree in the reverse
graph
OUTPUT:
The dominator tree, as a graph or as a dictionary, depending on the value of return_dict. If the output
is a dictionary, it will contain None in correspondence of root and of vertices that are not reachable from
root. If the output is a graph, it will not contain vertices that are not reachable from root.
EXAMPLES:
An undirected grid is biconnected, and its dominator tree is a star (everyone’s parent is the root):
sage: g = graphs.GridGraph([2,2]).dominator_tree((0,0))
sage: g.to_dictionary()
{(0, 0): [(0, 1), (1, 0), (1, 1)], (0, 1): [(0, 0)], (1, 0): [(0, 0)], (1, 1):␣
˓→[(0, 0)]}
If the graph is made by two 3-cycles 𝐶1 , 𝐶2 connected by an edge (𝑣, 𝑤), with 𝑣 ∈ 𝐶1 , 𝑤 ∈ 𝐶2 , the cut
vertices are 𝑣 and 𝑤, the biconnected components are 𝐶1 , 𝐶2 , and the edge (𝑣, 𝑤). If the root is in 𝐶1 , the
parent of each vertex in 𝐶1 is the root, the parent of 𝑤 is 𝑣, and the parent of each vertex in 𝐶2 is 𝑤:
sage: G = 2 * graphs.CycleGraph(3)
sage: v = 0
sage: w = 3
sage: G.add_edge(v,w)
sage: G.dominator_tree(1, return_dict=True)
{0: 1, 1: None, 2: 1, 3: 0, 4: 3, 5: 3}
sage: g = digraphs.Circuit(10).dominator_tree(5)
sage: g.to_dictionary()
{0: [1], 1: [2], 2: [3], 3: [4], 4: [], 5: [6], 6: [7], 7: [8], 8: [9], 9: [0]}
sage: g = digraphs.Circuit(10).dominator_tree(5, reverse=True)
sage: g.to_dictionary()
{0: [9], 1: [0], 2: [1], 3: [2], 4: [3], 5: [4], 6: [], 7: [6], 8: [7], 9: [8]}
sage: K = graphs.CompleteBipartiteGraph(9, 3)
sage: len(K.edge_boundary([0, 1, 2, 3, 4, 5, 6, 7, 8], [9, 10, 11]))
27
sage: K.size()
27
Note: When the graph is a directed graph, this method actually computes the strong connectivity, (i.e. a
directed graph is strongly 𝑘-connected if there are 𝑘 disjoint paths between any two vertices 𝑢, 𝑣). If you do
not want to consider strong connectivity, the best is probably to convert your DiGraph object to a Graph
object, and compute the connectivity of this other graph.
INPUT:
• G – the input Sage (Di)Graph
• value_only – boolean (default: True)
– When set to True (default), only the value is returned.
– When set to False, both the value and a minimum vertex cut are returned.
• implementation – string (default: None); selects an implementation:
– None (default) – selects the best implementation available
– "boost" – use the Boost graph library (which is much more efficient). It is not available when
edge_labels=True, and it is unreliable for directed graphs (see trac ticket #18753).
The edge connectivity of a complete graph is its minimum degree, and one of the two parts of the bipartition
is reduced to only one vertex. The graph of the cut edges is isomorphic to a Star graph:
sage: g = graphs.CompleteGraph(5)
sage: [ value, edges, [ setA, setB ]] = edge_connectivity(g,vertices=True)
sage: value
4
sage: len(setA) == 1 or len(setB) == 1
True
sage: cut = Graph()
sage: cut.add_edges(edges)
sage: cut.is_isomorphic(graphs.StarGraph(4))
True
Even if obviously in any graph we know that the edge connectivity is less than the minimum degree of the
graph:
sage: g = graphs.RandomGNP(10,.3)
sage: min(g.degree()) >= edge_connectivity(g)
True
If we build a tree then assign to its edges a random value, the minimum cut will be the edge with minimum
value:
sage: l == minimum
True
When value_only=True and implementation="sage", this function is optimized for small connectiv-
ity values and does not need to build a linear program.
It is the case for graphs which are not connected
sage: g = 2 * graphs.PetersenGraph()
sage: edge_connectivity(g, implementation="sage")
0.0
For directed graphs, the strong connectivity is tested through the dedicated function:
sage: g = digraphs.ButterflyGraph(3)
sage: edge_connectivity(g, implementation="sage")
0.0
We check that the result with Boost is the same as the result without Boost:
True
However, the Boost algorithm is not reliable if the input is directed (see trac ticket #18753):
sage: g = digraphs.Path(3)
sage: edge_connectivity(g)
0.0
sage: edge_connectivity(g, implementation="boost")
1
sage: g.add_edge(1, 0)
sage: edge_connectivity(g)
0.0
sage: edge_connectivity(g, implementation="boost")
0
the graph obtained by removing 𝐴 from the graph is disconnected. For more information, see the Wikipedia
article Cut_(graph_theory).
INPUT:
• s – source vertex
• t – sink vertex
• value_only – boolean (default: True); whether to return only the weight of a minimum cut (True)
or a list of edges of a minimum cut (False)
• use_edge_labels – boolean (default: False); whether to compute a weighted minimum edge cut
where the weight of an edge is defined by its label (if an edge has no label, 1 is assumed), or to compute
a cut of minimum cardinality (i.e., edge weights are set to 1)
• vertices – boolean (default: False); whether set to True, return a list of edges in the edge cut and
the two sets of vertices that are disconnected by the cut
Note: vertices=True implies value_only=False.
• algorithm – string (default: 'FF'); algorithm to use:
– If algorithm = "FF", a Python implementation of the Ford-Fulkerson algorithm is used
– If algorithm = "LP", the problem is solved using Linear Programming.
– If algorithm = "igraph", the igraph implementation of the Goldberg-Tarjan algorithm is used
(only available when igraph is installed)
– If algorithm = None, the problem is solved using the default maximum flow algorithm (see
flow())
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
Note: The use of Linear Programming for non-integer problems may possibly mean the presence of a
(slight) numerical noise.
OUTPUT:
Real number or tuple, depending on the given arguments (examples are given below).
EXAMPLES:
A basic application in the Pappus graph:
sage: g = graphs.PappusGraph()
sage: g.edge_cut(1, 2, value_only=True)
3
sage: g = graphs.PathGraph(15)
sage: for u,v in g.edge_iterator(labels=None):
....: g.set_edge_label(u, v, random())
The edge cut between the two ends is the edge of minimum weight:
The two sides of the edge cut are obviously shorter paths:
sage: g.subgraph(set1).is_isomorphic(graphs.PathGraph(len(set1)))
True
sage: g.subgraph(set2).is_isomorphic(graphs.PathGraph(len(set2)))
True
sage: len(set1) + len(set2) == g.order()
True
Note: This function is topological: it does not take the eventual weights of the edges into account.
EXAMPLES:
In a complete bipartite graph
sage: g = graphs.CompleteBipartiteGraph(2, 3)
sage: g.edge_disjoint_paths(0, 1)
[[0, 2, 1], [0, 3, 1], [0, 4, 1]]
sage: g = graphs.PetersenGraph()
sage: [T] = g.edge_disjoint_spanning_trees(1)
sage: T.is_tree()
True
Though, it does not have 2 edge-disjoint trees (as it has less than 2(|𝑉 | − 1) edges):
sage: g.edge_disjoint_spanning_trees(2)
Traceback (most recent call last):
...
EmptySetError: this graph does not contain the required number of trees/
˓→arborescences
By Edmond’s theorem, a graph which is 𝑘-connected always has 𝑘 edge-disjoint arborescences, regardless
of the root we pick:
sage: k = Integer(g.edge_connectivity())
sage: while not k:
....: g = digraphs.RandomDirectedGNP(11, .3)
....: k = Integer(g.edge_connectivity())
sage: arborescences = g.edge_disjoint_spanning_trees(k) # long time (up to 15s␣
˓→on sage.math, 2011)
sage: d6 = r'[E_S?_hKIH@eos[BSg???Q@FShGC?hTHUGM?IPug?JOEYCdOzdkQGo'
sage: d6 += r'@ADA@AAg?GAQW?[aIaSwHYcD@qQb@Dd?\hJTI@OHlJ_?C_OEIKoeC'
sage: d6 += r'R@_BC?Q??YBFosqITEA?IvCU_'
sage: G = DiGraph(d6, format='dig6')
(continues on next page)
Small cases:
sage: Graph().edge_disjoint_spanning_trees(0)
[]
sage: Graph(1).edge_disjoint_spanning_trees(0)
[]
sage: Graph(2).edge_disjoint_spanning_trees(0)
[]
sage: Graph([(0, 1)]).edge_disjoint_spanning_trees(0)
[]
sage: Graph([(0, 1)]).edge_disjoint_spanning_trees(1)
[Graph on 2 vertices]
sage: Graph([(0, 1)]).edge_disjoint_spanning_trees(2)
Traceback (most recent call last):
...
EmptySetError: this graph does not contain the required number of trees/
˓→arborescences
EXAMPLES:
sage: G = graphs.TetrahedralGraph()
sage: list(G.edge_iterator(labels=False))
[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
sage: G = graphs.TetrahedralGraph()
sage: list(G.edge_iterator(labels=False, sort_vertices=False))
[(1, 0), (2, 0), (3, 0), (2, 1), (3, 1), (3, 2)]
edge_label(u, v)
Return the label of an edge.
If the graph allows multiple edges, then the list of labels on the edges is returned.
See also:
• set_edge_label()
EXAMPLES:
sage: G = Graph(multiedges=True)
sage: [G.add_edge(0, 1, i) for i in range(1, 6)]
[None, None, None, None, None]
sage: sorted(G.edge_label(0, 1))
[1, 2, 3, 4, 5]
edge_labels()
Return a list of the labels of all edges in self.
The output list is not sorted.
EXAMPLES:
edge_polytope(backend=None)
Return the edge polytope of self.
The edge polytope (EP) of a Graph on 𝑛 vertices is the polytope in Z𝑛 defined as the convex hull of 𝑒𝑖 + 𝑒𝑗
for each edge (𝑖, 𝑗). Here 𝑒1 , . . . , 𝑒𝑛 denotes the standard basis.
INPUT:
• backend – string or None (default); the backend to use; see sage.geometry.polyhedron.
constructor.Polyhedron()
EXAMPLES:
The EP of a 4-cycle is a square:
sage: G = graphs.CycleGraph(4)
sage: P = G.edge_polytope(); P
A 2-dimensional polyhedron in ZZ^4 defined as the convex hull of 4 vertices
sage: G = graphs.CompleteGraph(4)
sage: P = G.edge_polytope(); P
A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 6 vertices
sage: P.is_combinatorially_isomorphic(polytopes.cross_polytope(3))
True
The EP of a graph is isomorphic to the subdirect sum of its connected components EPs:
sage: n = randint(3, 6)
sage: G1 = graphs.RandomGNP(n, 0.2)
sage: n = randint(3, 6)
sage: G2 = graphs.RandomGNP(n, 0.2)
sage: G = G1.disjoint_union(G2)
sage: P = G.edge_polytope()
sage: P1 = G1.edge_polytope()
sage: P2 = G2.edge_polytope()
sage: P.is_combinatorially_isomorphic(P1.subdirect_sum(P2))
True
sage: len(list(graphs(5)))
34
sage: polys = []
sage: for G in graphs(5):
....: P = G.edge_polytope()
....: for P1 in polys:
....: if P.is_combinatorially_isomorphic(P1):
....: break
....: else:
....: polys.append(P)
sage: len(polys)
19
Warning: Since any object may be a vertex, there is no guarantee that any two vertices will be com-
parable, and thus no guarantee how two edges may compare. With default objects for vertices (all
integers), or when all the vertices are of the same simple type, then there should not be a problem with
how the vertices will be sorted. However, if you need to guarantee a total order for the sorting of the
edges, use the key argument, as illustrated in the examples below.
EXAMPLES:
sage: graphs.DodecahedralGraph().edges(sort=True)
[(0, 1, None), (0, 10, None), (0, 19, None), (1, 2, None), (1, 8, None), (2, 3,␣
˓→None), (2, 6, None), (3, 4, None), (3, 19, None), (4, 5, None), (4, 17, None),
˓→ (5, 6, None), (5, 15, None), (6, 7, None), (7, 8, None), (7, 14, None), (8,␣
˓→9, None), (9, 10, None), (9, 13, None), (10, 11, None), (11, 12, None), (11,␣
˓→18, None), (12, 13, None), (12, 16, None), (13, 14, None), (14, 15, None),␣
˓→(15, 16, None), (16, 17, None), (17, 18, None), (18, 19, None)]
˓→13), (10, 11), (11, 12), (11, 18), (12, 13), (12, 16), (13, 14), (14, 15),␣
sage: D = graphs.DodecahedralGraph().to_directed()
sage: D.edges(sort=True)
[(0, 1, None), (0, 10, None), (0, 19, None), (1, 0, None), (1, 2, None), (1, 8,␣
˓→None), (2, 1, None), (2, 3, None), (2, 6, None), (3, 2, None), (3, 4, None),␣
˓→(3, 19, None), (4, 3, None), (4, 5, None), (4, 17, None), (5, 4, None), (5, 6,
˓→ None), (5, 15, None), (6, 2, None), (6, 5, None), (6, 7, None), (7, 6, None),
˓→ (7, 8, None), (7, 14, None), (8, 1, None), (8, 7, None), (8, 9, None), (9, 8,
˓→ None), (9, 10, None), (9, 13, None), (10, 0, None), (10, 9, None), (10, 11,␣
˓→None), (11, 10, None), (11, 12, None), (11, 18, None), (12, 11, None), (12,␣
˓→13, None), (12, 16, None), (13, 9, None), (13, 12, None), (13, 14, None), (14,
˓→ 7, None), (14, 13, None), (14, 15, None), (15, 5, None), (15, 14, None), (15,
˓→ 16, None), (16, 12, None), (16, 15, None), (16, 17, None), (17, 4, None),␣
˓→(17, 16, None), (17, 18, None), (18, 11, None), (18, 17, None), (18, 19,␣
˓→ (6, 5), (6, 7), (7, 6), (7, 8), (7, 14), (8, 1), (8, 7), (8, 9), (9, 8), (9,␣
˓→10), (9, 13), (10, 0), (10, 9), (10, 11), (11, 10), (11, 12), (11, 18), (12,␣
˓→11), (12, 13), (12, 16), (13, 9), (13, 12), (13, 14), (14, 7), (14, 13), (14,␣
˓→15), (15, 5), (15, 14), (15, 16), (16, 12), (16, 15), (16, 17), (17, 4), (17,␣
˓→16), (17, 18), (18, 11), (18, 17), (18, 19), (19, 0), (19, 3), (19, 18)]
The default is to sort the returned list in the default fashion, as in the above examples. This can be overridden
by specifying a key function. This first example just ignores the labels in the third component of the triple:
sage: G = graphs.CycleGraph(5)
sage: G.edges(sort=True, key=lambda x: (x[1], -x[0]))
[(0, 1, None), (1, 2, None), (2, 3, None), (3, 4, None), (0, 4, None)]
We set the labels to characters and then perform a default sort followed by a sort according to the labels:
sage: G = graphs.CycleGraph(5)
sage: for e in G.edges(sort=False):
....: G.set_edge_label(e[0], e[1], chr(ord('A') + e[0] + 5 * e[1]))
sage: G.edges(sort=True)
[(0, 1, 'F'), (0, 4, 'U'), (1, 2, 'L'), (2, 3, 'R'), (3, 4, 'X')]
(continues on next page)
sage: G = Graph()
sage: G = Graph()
sage: G.add_edges([[1,2], [2,3], [0,3]])
sage: list(G.edge_iterator(sort_vertices=False))
[(3, 0, None), (2, 1, None), (3, 2, None)]
eigenspaces(laplacian=False)
Return the right eigenspaces of the adjacency matrix of the graph.
INPUT:
• laplacian – boolean (default: False); if True, use the Laplacian matrix (see
kirchhoff_matrix())
OUTPUT:
A list of pairs. Each pair is an eigenvalue of the adjacency matrix of the graph, followed by the vector space
that is the eigenspace for that eigenvalue, when the eigenvectors are placed on the right of the matrix.
For some graphs, some of the eigenspaces are described exactly by vector spaces over a NumberField().
For numerical eigenvectors use eigenvectors().
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.eigenspaces()
[
(3, Vector space of degree 10 and dimension 1 over Rational Field
User basis matrix:
[1 1 1 1 1 1 1 1 1 1]),
(-2, Vector space of degree 10 and dimension 4 over Rational Field
User basis matrix:
[ 1 0 0 0 -1 -1 -1 0 1 1]
[ 0 1 0 0 -1 0 -2 -1 1 2]
[ 0 0 1 0 -1 1 -1 -2 0 2]
[ 0 0 0 1 -1 1 0 -1 -1 1]),
(1, Vector space of degree 10 and dimension 5 over Rational Field
User basis matrix:
[ 1 0 0 0 0 1 -1 0 0 -1]
[ 0 1 0 0 0 -1 1 -1 0 0]
[ 0 0 1 0 0 0 -1 1 -1 0]
[ 0 0 0 1 0 0 0 -1 1 -1]
[ 0 0 0 0 1 -1 0 0 -1 1])
]
Eigenspaces for the Laplacian should be identical since the Petersen graph is regular. However, since the
output also contains the eigenvalues, the two outputs are slightly different:
sage: P.eigenspaces(laplacian=True)
[
(0, Vector space of degree 10 and dimension 1 over Rational Field
User basis matrix:
[1 1 1 1 1 1 1 1 1 1]),
(5, Vector space of degree 10 and dimension 4 over Rational Field
User basis matrix:
[ 1 0 0 0 -1 -1 -1 0 1 1]
[ 0 1 0 0 -1 0 -2 -1 1 2]
[ 0 0 1 0 -1 1 -1 -2 0 2]
(continues on next page)
Notice how one eigenspace below is described with a square root of 2. For the two possible values (positive
and negative) there is a corresponding eigenspace:
sage: C = graphs.CycleGraph(8)
sage: C.eigenspaces()
[
(2, Vector space of degree 8 and dimension 1 over Rational Field
User basis matrix:
[1 1 1 1 1 1 1 1]),
(-2, Vector space of degree 8 and dimension 1 over Rational Field
User basis matrix:
[ 1 -1 1 -1 1 -1 1 -1]),
(0, Vector space of degree 8 and dimension 2 over Rational Field
User basis matrix:
[ 1 0 -1 0 1 0 -1 0]
[ 0 1 0 -1 0 1 0 -1]),
(a3, Vector space of degree 8 and dimension 2 over Number Field in a3 with␣
˓→defining polynomial x^2 - 2
A digraph may have complex eigenvalues and eigenvectors. For a 3-cycle, we have:
eigenvectors(laplacian=False)
Return the right eigenvectors of the adjacency matrix of the graph.
INPUT:
• laplacian – boolean (default: False); if True, use the Laplacian matrix (see
kirchhoff_matrix())
OUTPUT:
A list of triples. Each triple begins with an eigenvalue of the adjacency matrix of the graph. This is
followed by a list of eigenvectors for the eigenvalue, when the eigenvectors are placed on the right side
of the matrix. Together, the eigenvectors form a basis for the eigenspace. The triple concludes with the
algebraic multiplicity of the eigenvalue.
For some graphs, the exact eigenspaces provided by eigenspaces() provide additional insight into the
structure of the eigenspaces.
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.eigenvectors()
[(3, [
(1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
], 1), (-2, [
(1, 0, 0, 0, -1, -1, -1, 0, 1, 1),
(0, 1, 0, 0, -1, 0, -2, -1, 1, 2),
(0, 0, 1, 0, -1, 1, -1, -2, 0, 2),
(0, 0, 0, 1, -1, 1, 0, -1, -1, 1)
], 4), (1, [
(1, 0, 0, 0, 0, 1, -1, 0, 0, -1),
(0, 1, 0, 0, 0, -1, 1, -1, 0, 0),
(0, 0, 1, 0, 0, 0, -1, 1, -1, 0),
(0, 0, 0, 1, 0, 0, 0, -1, 1, -1),
(0, 0, 0, 0, 1, -1, 0, 0, -1, 1)
], 5)]
Eigenspaces for the Laplacian should be identical since the Petersen graph is regular. However, since the
output also contains the eigenvalues, the two outputs are slightly different:
sage: P.eigenvectors(laplacian=True)
[(0, [
(1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
], 1), (5, [
(1, 0, 0, 0, -1, -1, -1, 0, 1, 1),
(0, 1, 0, 0, -1, 0, -2, -1, 1, 2),
(0, 0, 1, 0, -1, 1, -1, -2, 0, 2),
(0, 0, 0, 1, -1, 1, 0, -1, -1, 1)
], 4), (2, [
(1, 0, 0, 0, 0, 1, -1, 0, 0, -1),
(0, 1, 0, 0, 0, -1, 1, -1, 0, 0),
(0, 0, 1, 0, 0, 0, -1, 1, -1, 0),
(0, 0, 0, 1, 0, 0, 0, -1, 1, -1),
(0, 0, 0, 0, 1, -1, 0, 0, -1, 1)
], 5)]
sage: C = graphs.CycleGraph(8)
sage: C.eigenvectors()
[(2,
[
(1, 1, 1, 1, 1, 1, 1, 1)
],
1),
(continues on next page)
A digraph may have complex eigenvalues. Previously, the complex parts of graph eigenvalues were being
dropped. For a 3-cycle, we have:
1),
(-0.5000000000... + 0.8660254037...*I,
[(1, -0.5000000000... + 0.8660254037...*I, -0.5000000000... - 0.8660254037...
˓→*I)],
1)]
EXAMPLES:
sage: g = graphs.CycleGraph(5)
sage: g.eulerian_circuit()
[(0, 4, None), (4, 3, None), (3, 2, None), (2, 1, None), (1, 0, None)]
sage: g.eulerian_circuit(labels=False)
[(0, 4), (4, 3), (3, 2), (2, 1), (1, 0)]
sage: g = graphs.CompleteGraph(7)
sage: edges, vertices = g.eulerian_circuit(return_vertices=True)
sage: vertices
[0, 6, 5, 4, 6, 3, 5, 2, 4, 3, 2, 6, 1, 5, 0, 4, 1, 3, 0, 2, 1, 0]
sage: graphs.CompleteGraph(4).eulerian_circuit()
False
eulerian_orientation()
Return a DiGraph which is an Eulerian orientation of the current graph.
An Eulerian graph being a graph such that any vertex has an even degree, an Eulerian orientation of a graph
is an orientation of its edges such that each vertex 𝑣 verifies 𝑑+ (𝑣) = 𝑑− (𝑣) = 𝑑(𝑣)/2, where 𝑑+ and 𝑑−
respectively represent the out-degree and the in-degree of a vertex.
If the graph is not Eulerian, the orientation verifies for any vertex 𝑣 that |𝑑+ (𝑣) − 𝑑− (𝑣)| ≤ 1.
ALGORITHM:
This algorithm is a random walk through the edges of the graph, which orients the edges according to the
walk. When a vertex is reached which has no non-oriented edge (this vertex must have odd degree), the
walk resumes at another vertex of odd degree, if any.
This algorithm has complexity 𝑂(𝑚), where 𝑚 is the number of edges in the graph.
EXAMPLES:
The CubeGraph with parameter 4, which is regular of even degree, has an Eulerian orientation such that
𝑑+ = 𝑑− :
sage: g = graphs.CubeGraph(4)
sage: g.degree()
(continues on next page)
Secondly, the Petersen Graph, which is 3 regular has an orientation such that the difference between 𝑑+
and 𝑑− is at most 1:
sage: g = graphs.PetersenGraph()
sage: o = g.eulerian_orientation()
sage: o.in_degree()
[2, 2, 2, 2, 2, 1, 1, 1, 1, 1]
sage: o.out_degree()
[1, 1, 1, 1, 1, 2, 2, 2, 2, 2]
adjlist http://networkx.lanl.gov/reference/generated/networkx.readwrite.
adjlist.write_adjlist.html
dot https://networkx.github.io/documentation/latest/reference/
generated/networkx.drawing.nx_pydot.write_dot.html
edgelist http://networkx.lanl.gov/reference/generated/networkx.readwrite.
edgelist.write_edgelist.html
gexf http://networkx.lanl.gov/reference/generated/networkx.readwrite.
gexf.write_gexf.html
gml http://networkx.lanl.gov/reference/generated/networkx.readwrite.
gml.write_gml.html
graphml http://networkx.lanl.gov/reference/generated/networkx.readwrite.
graphml.write_graphml.html
multiline_adjlist http://networkx.lanl.gov/reference/generated/networkx.readwrite.
multiline_adjlist.write_multiline_adjlist.html
pajek http://networkx.lanl.gov/reference/generated/networkx.readwrite.
pajek.write_pajek.html
yaml http://networkx.lanl.gov/reference/generated/networkx.readwrite.
nx_yaml.write_yaml.html
See also:
• save() – save a Sage object to a ‘sobj’ file (preserves all its attributes)
Note: This functions uses the write_* functions defined in NetworkX (see http://networkx.lanl.gov/
reference/readwrite.html).
EXAMPLES:
sage: g = graphs.PetersenGraph()
sage: filename = tmp_filename(ext=".pajek")
sage: g.export_to_file(filename)
sage: import networkx
sage: G_networkx = networkx.read_pajek(filename)
sage: Graph(G_networkx).is_isomorphic(g)
True
sage: filename = tmp_filename(ext=".edgelist")
sage: g.export_to_file(filename, data=False)
sage: h = Graph(networkx.read_edgelist(filename))
sage: g.is_isomorphic(h)
True
faces(embedding=None)
Return the faces of an embedded graph.
A combinatorial embedding of a graph is a clockwise ordering of the neighbors of each vertex. From this
information one can define the faces of the embedding, which is what this method returns.
If no embedding is provided or stored as self._embedding, this method will compute the set of faces
from the embedding returned by is_planar() (if the graph is, of course, planar).
Warning: This method is not well defined when the graph is not connected. Indeed, the result may
contain several faces corresponding to the external face.
INPUT:
• embedding – dictionary (default: None); a combinatorial embedding dictionary. Format: {v1:
[v2,v3], v2: [v1], v3: [v1]} (clockwise ordering of neighbors at each vertex). If set to
None (default) the method will use the embedding stored as self._embedding. If none is stored, the
method will compute the set of faces from the embedding returned by is_planar() (if the graph is,
of course, planar).
Note: embedding is an ordered list based on the hash order of the vertices of graph. To avoid confusion,
it might be best to set the rot_sys based on a ‘nice_copy’ of the graph.
See also:
• set_embedding()
• get_embedding()
• is_planar()
• planar_dual()
EXAMPLES:
Providing an embedding:
sage: T = graphs.TetrahedralGraph()
sage: T.faces({0: [1, 3, 2], 1: [0, 2, 3], 2: [0, 3, 1], 3: [0, 1, 2]})
[[(0, 1), (1, 2), (2, 0)],
[(0, 2), (2, 3), (3, 0)],
[(0, 3), (3, 1), (1, 0)],
[(1, 3), (3, 2), (2, 1)]]
sage: graphs.TetrahedralGraph().faces()
[[(0, 1), (1, 2), (2, 0)],
[(0, 2), (2, 3), (3, 0)],
[(0, 3), (3, 1), (1, 0)],
[(1, 3), (3, 2), (2, 1)]]
sage: graphs.PetersenGraph().faces()
Traceback (most recent call last):
...
ValueError: no embedding is provided and the graph is not planar
As the number of circuits contained in a graph is exponential, this LP is solved through constraint genera-
tion. This means that the solver is sequentially asked to solve the problem, knowing only a portion of the
circuits contained in 𝐺, each time adding to the list of its constraints the circuit which its last answer had
left intact.
(Another formulation based on an ordering of the vertices)
When the graph is directed, a second (and very slow) formulation is available, which should only be used
to check the result of the first implementation in case of doubt.
∑︁
Minimize : 𝑏𝑣
𝑣∈𝐺
Such that :
∀(𝑢, 𝑣) ∈ 𝐺, 𝑑𝑢 − 𝑑𝑣 + 𝑛𝑏𝑢 + 𝑛𝑏𝑣 ≥ 0
∀𝑢 ∈ 𝐺, 0 ≤ 𝑑𝑢 ≤ |𝐺|
A brief explanation:
An acyclic digraph can be seen as a poset, and every poset has a linear extension. This means that in any
acyclic digraph the vertices can be ordered with a total order < in such a way that if (𝑢, 𝑣) ∈ 𝐺, then 𝑢 < 𝑣.
Thus, this linear program is built in order to assign to each vertex 𝑣 a number 𝑑𝑣 ∈ [0, . . . , 𝑛 − 1] such that
if there exists an edge (𝑢, 𝑣) ∈ 𝐺 then either 𝑑𝑣 < 𝑑𝑢 or one of 𝑢 or 𝑣 is removed. The number of vertices
removed is then minimized, which is the objective.
EXAMPLES:
The necessary example:
sage: g = graphs.PetersenGraph()
sage: fvs = g.feedback_vertex_set()
sage: len(fvs)
3
sage: g.delete_vertices(fvs)
sage: g.is_forest()
True
In a digraph built from a graph, any edge is replaced by arcs going in the two opposite directions, thus
creating a cycle of length two. Hence, to remove all the cycles from the graph, each edge must see one of
its neighbors removed: a feedback vertex set is in this situation a vertex cover:
∀𝑥 ∈ 𝐺, 𝑏𝑥 is a binary variable
Observe that the integrality of the flow variables is automatic for all available solvers when all capacities
are integers.
INPUT:
• x – source vertex
• y – sink vertex
• value_only – boolean (default: True); whether to return only the value of a maximal flow, or to also
return a flow graph (a copy of the current graph, such that each edge has the flow using it as a label,
the edges without flow being omitted)
• integer – boolean (default: True); whether to compute an optimal solution under the constraint that
the flow going through an edge has to be an integer, or without this constraint
• use_edge_labels – boolean (default: False); whether to compute a maximum flow where each
edge has a capacity defined by its label (if an edge has no label, capacity 1 is assumed), or to use
default edge capacity of 1
• vertex_bound – boolean (default: False); when set to True, sets the maximum flow leaving a vertex
different from 𝑥 to 1 (useful for vertex connectivity parameters)
• algorithm – string (default: None); the algorithm to use among:
– "FF", a Python implementation of the Ford-Fulkerson algorithm (only available when
vertex_bound = False)
– "LP", the flow problem is solved using Linear Programming
– "igraph", the igraph implementation of the Goldberg-Tarjan algorithm is used (only available
when igraph is installed and vertex_bound = False)
When algorithm = None (default), we use LP if vertex_bound = True, otherwise, we use
igraph if it is available, FF if it is not available.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
Only useful when algorithm "LP" is used to solve the flow problem.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
Only useful when algorithm "LP" is used to solve the flow problem.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
Note: Even though the three different implementations are meant to return the same Flow values, they
cannot be expected to return the same Flow graphs.
Besides, the use of Linear Programming may possibly mean a (slight) numerical noise.
EXAMPLES:
Two basic applications of the flow method for the PappusGraph and the ButterflyGraph with parameter
2
sage: g=graphs.PappusGraph()
sage: int(g.flow(1,2))
3
sage: b=digraphs.ButterflyGraph(2)
sage: int(b.flow(('00', 1), ('00', 2)))
1
The flow method can be used to compute a matching in a bipartite graph by linking a source 𝑠 to all the
vertices of the first set and linking a sink 𝑡 to all the vertices of the second set, then computing a maximum
𝑠 − 𝑡 flow
sage: g = DiGraph()
sage: g.add_edges(('s', i) for i in range(4))
sage: g.add_edges((i, 4 + j) for i in range(4) for j in range(4))
sage: g.add_edges((4 + i, 't') for i in range(4))
sage: [cardinal, flow_graph] = g.flow('s', 't', integer=True, value_only=False)
sage: flow_graph.delete_vertices(['s', 't'])
sage: flow_graph.size()
4
sage: g = Graph()
sage: g.add_edges(('s', i) for i in range(4))
sage: g.add_edges((i, 4 + j) for i in range(4) for j in range(4))
sage: g.add_edges((4 + i, 't') for i in range(4))
sage: [cardinal, flow_graph] = g.flow('s', 't', integer=True, value_only=False)
sage: flow_graph.delete_vertices(['s', 't'])
sage: flow_graph.size()
4
Note: This function uses Euler’s formula and thus it is necessary to consider only connected graphs.
INPUT:
• set_embedding – boolean (default: True); whether or not to store an embedding attribute of the
computed (minimal) genus of the graph
• on_embedding – two kinds of input are allowed (default: None):
• minimal – boolean (default: True); whether or not to compute the minimal genus of the graph (i.e.,
testing all embeddings). If minimal is False, then either maximal must be True or on_embedding
must not be None. If on_embedding is not None, it will take priority over minimal. Similarly, if
maximal is True, it will take priority over minimal.
• maximal – boolean (default: False); whether or not to compute the maximal genus of the graph (i.e.,
testing all embeddings). If maximal is False, then either minimal must be True or on_embedding
must not be None. If on_embedding is not None, it will take priority over maximal. However,
maximal takes priority over the default minimal.
• circular – list (default: None); if circular is a list of vertices, the method computes the genus
preserving a planar embedding of the this list. If circular is defined, on_embedding is not a valid
option.
• ordered – boolean (default: True); if circular is True, then whether or not the boundary order
may be permuted (default is True, which means the boundary order is preserved)
EXAMPLES:
sage: g = graphs.PetersenGraph()
sage: g.genus() # tests for minimal genus by default
1
sage: g.genus(on_embedding=True, maximal=True) # on_embedding overrides minimal␣
˓→and maximal arguments
1
sage: g.genus(maximal=True) # setting maximal to True overrides default␣
˓→minimal=True
3
sage: g.genus(on_embedding=g.get_embedding()) # can also send a valid␣
˓→combinatorial embedding dict
3
sage: (graphs.CubeGraph(3)).genus()
0
sage: K23 = graphs.CompleteBipartiteGraph(2,3)
sage: K23.genus()
0
sage: K33 = graphs.CompleteBipartiteGraph(3,3)
sage: K33.genus()
1
Using the circular argument, we can compute the minimal genus preserving a planar, ordered boundary:
Note: not everything works for multigraphs, looped graphs or digraphs. But the minimal genus is ultimately
computable for every connected graph – but the embedding we obtain for the simple graph can’t be easily
converted to an embedding of a non-simple graph. Also, the maximal genus of a multigraph does not
trivially correspond to that of its simple graph:
sage: G = DiGraph({0: [0, 1, 1, 1], 1: [2, 2, 3, 3], 2: [1, 3, 3], 3: [0, 3]})
sage: G.genus()
Traceback (most recent call last):
...
NotImplementedError: cannot work with embeddings of non-simple graphs
sage: G.to_simple().genus()
0
sage: G.genus(set_embedding=False)
0
sage: G.genus(maximal=True, set_embedding=False)
Traceback (most recent call last):
...
NotImplementedError: cannot compute the maximal genus of a graph with loops or␣
˓→multiple edges
We break graphs with cut vertices into their blocks, which greatly speeds up computation of minimal genus.
This is not implemented for maximal genus:
sage: G = graphs.RandomBlockGraph(10, 5)
sage: G.genus()
10
get_embedding()
Return the stored embedding or None.
If the stored embedding is no longer valid (because of vertex/edge additions) then the stored embedding
is discarded and None is returned. In case some vertex/edge has been deleted, the stored embedding is
updated accordingly.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.genus()
1
sage: G.get_embedding()
{0: [1, 4, 5], 1: [0, 2, 6], 2: [1, 3, 7], 3: [2, 4, 8], 4: [0, 3, 9], 5: [0, 7,
˓→ 8], 6: [1, 9, 8], 7: [2, 5, 9], 8: [3, 6, 5], 9: [4, 6, 7]}
Note that the embeddings gets properly modified on vertex or edge deletion:
sage: G.delete_edge(0, 1)
sage: G.delete_vertex(3)
sage: G.get_embedding()
{0: [4, 5],
1: [2, 6],
2: [1, 7],
4: [0, 9],
5: [0, 7, 8],
6: [1, 9, 8],
7: [2, 5, 9],
8: [6, 5],
9: [4, 6, 7]}
sage: G.add_edge(0, 7)
sage: G.get_embedding() is None
True
get_pos(dim=2)
Return the position dictionary.
The position dictionary specifies the coordinates of each vertex.
INPUT:
• dim – integer (default: 2); whether to return the position dictionary in the plane (dim == 2) or in the
3-dimensional space
EXAMPLES:
By default, the position of a graph is None:
sage: G = Graph()
sage: G.get_pos()
sage: G.get_pos() is None
True
sage: P = G.plot(save_pos=True)
sage: G.get_pos()
{}
sage: G = graphs.PetersenGraph()
sage: G.get_pos()
{0: (0.0, 1.0),
(continues on next page)
sage: G.delete_vertex(0)
sage: G.get_pos()
{1: (-0.951..., 0.309...),
...
9: (0.475..., 0.154...)}
sage: G.add_vertex(0)
sage: G.get_pos() is None
True
get_vertex(vertex)
Retrieve the object associated with a given vertex.
If no associated object is found, None is returned.
INPUT:
• vertex – the given vertex
EXAMPLES:
sage: d[2]
Moebius-Kantor Graph: Graph on 16 vertices
sage: T = graphs.TetrahedralGraph()
sage: T.vertices(sort=True)
[0, 1, 2, 3]
sage: T.set_vertices(d)
sage: T.get_vertex(1)
Flower Snark: Graph on 20 vertices
get_vertices(verts=None)
Return a dictionary of the objects associated to each vertex.
INPUT:
• verts – iterable container of vertices
EXAMPLES:
sage: T = graphs.TetrahedralGraph()
sage: T.set_vertices(d)
sage: T.get_vertices([1, 2])
{1: Flower Snark: Graph on 20 vertices,
2: Moebius-Kantor Graph: Graph on 16 vertices}
girth(certificate=False)
Return the girth of the graph.
The girth is the length of the shortest cycle in the graph (directed cycle if the graph is directed). Graphs
without (directed) cycles have infinite girth.
INPUT:
• certificate – boolean (default: False); whether to return (g, c), where g is the girth and c is a
list of vertices of a (directed) cycle of length g in the graph, thus providing a certificate that the girth
is at most g, or None if g infinite
EXAMPLES:
sage: graphs.TetrahedralGraph().girth()
3
sage: graphs.CubeGraph(3).girth()
4
sage: graphs.PetersenGraph().girth(certificate=True) # random
(5, [4, 3, 2, 1, 0])
sage: graphs.HeawoodGraph().girth()
6
sage: next(graphs.trees(9)).girth()
+Infinity
See also:
graphplot(**options)
Return a GraphPlot object.
See GraphPlot for more details.
INPUT:
• **options – parameters for the GraphPlot constructor
EXAMPLES:
Creating a GraphPlot object uses the same options as plot():
sage: GP.plot()
Graphics object consisting of 22 graphics primitives
We can modify the GraphPlot object. Notice that the changes are cumulative:
sage: GP.set_edges(edge_style='solid')
sage: GP.plot()
Graphics object consisting of 22 graphics primitives
sage: GP.set_vertices(talk=True)
sage: GP.plot()
Graphics object consisting of 22 graphics primitives
sage: G = Graph({0: {1: None, 2: None}, 1: {0: None, 2: None}, 2: {0: None, 1:␣
˓→None, 3: 'foo'}, 3: {2: 'foo'}}, sparse=True)
sage: print(G.graphviz_string(edge_labels=True))
graph {
node_0 [label="0"];
node_1 [label="1"];
node_2 [label="2"];
node_3 [label="3"];
node_0 -- node_1;
node_0 -- node_2;
(continues on next page)
node_0 -- node_1;
node_0 -- node_2;
node_1 -- node_2;
node_2 -- node_3 [label=" ", texlbl="$\text{\texttt{foo}}$"];
}
sage: G = DiGraph({0: {1: None, 2: None}, 1: {2: None}, 2: {3: 'foo'}, 3: {}},␣
˓→sparse=True)
sage: print(G.graphviz_string(edge_color="red"))
digraph {
node_0 [label="0"];
node_1 [label="1"];
node_2 [label="2"];
node_3 [label="3"];
edge [color="red"];
node_0 -> node_1;
node_0 -> node_2;
node_1 -> node_2;
node_2 -> node_3;
}
sage: g(x) = 1 / (x + 1)
˓→# optional - sage.symbolic
sage: G = DiGraph()
˓→# optional - sage.symbolic
digraph {
(continues on next page)
digraph {
node [shape="plaintext"];
node_10 [label=" ", texlbl="$1$"];
node_11 [label=" ", texlbl="$2$"];
node_3 [label=" ", texlbl="$-\frac{1}{2}$"];
node_6 [label=" ", texlbl="$\frac{1}{2}$"];
node_7 [label=" ", texlbl="$\frac{1}{2}$"];
node_5 [label=" ", texlbl="$\frac{1}{3}$"];
node_8 [label=" ", texlbl="$\frac{2}{3}$"];
node_4 [label=" ", texlbl="$\frac{1}{4}$"];
node_1 [label=" ", texlbl="$-2$"];
node_9 [label=" ", texlbl="$\frac{4}{5}$"];
node_0 [label=" ", texlbl="$-4$"];
node_2 [label=" ", texlbl="$-1$"];
By default graphviz renders digraphs using a hierarchical layout, ranking the vertices down from top to
bottom. Here we specify alternative ranking directions for this layout:
Edge-specific options can also be specified by providing a function (or tuple thereof) which maps each edge
to a dictionary of options. Valid options are
• "color"
• "dot" (a string containing a sequence of options in dot format)
• "label" (a string)
• "label_style" ("string" or "latex")
• "edge_string" ("--" or "->")
• "dir" ("forward", "back", "both" or "none")
• "backward" (boolean), instead of defining the edge in the graphviz string as u -> v it draws it as v
-> u [dir=back] and instead of u -> v [dir=back] it draws it as v -> u, this changes the way
it is drawn by Graphviz’s dot program: vertex v will be above vertex u instead of below.
Here we state that the graph should be laid out so that edges starting from 1 are going backward (e.g. going
up instead of down):
digraph {
node_0 [label="-1"];
node_1 [label="-1/2"];
node_2 [label="1/2"];
node_3 [label="-2"];
node_4 [label="1/4"];
node_5 [label="-4"];
node_6 [label="1/3"];
node_7 [label="2/3"];
node_8 [label="4/5"];
node_9 [label="1"];
node_10 [label="2"];
digraph {
node_0 [label="-1"];
node_1 [label="-1/2"];
node_2 [label="1/2"];
node_3 [label="-2"];
node_4 [label="1/4"];
node_5 [label="-4"];
node_6 [label="1/3"];
node_7 [label="2/3"];
node_8 [label="4/5"];
node_9 [label="1"];
node_10 [label="2"];
We test the same graph and 'dir' edge options but with backward=True, which reverses the natural
direction each edge wants to be pointing for the layout:
graphviz_to_file_named(filename, **options)
Write a representation in the dot language in a file.
The dot language is a plaintext format for graph structures. See the documentation of
graphviz_string() for available options.
INPUT:
• filename – the name of the file to write in
• **options – options for the graphviz string
EXAMPLES:
sage: G = Graph({0: {1: None, 2: None}, 1: {0: None, 2: None}, 2: {0: None, 1:␣
˓→None, 3: 'foo'}, 3: {2: 'foo'}}, sparse=True)
node_0 -- node_1;
node_0 -- node_2;
node_1 -- node_2;
node_2 -- node_3 [label="foo"];
}
ALGORITHM:
See traveling_salesman_problem() for ‘tsp’ algorithm and find_hamiltonian() from sage.
graphs.generic_graph_pyx for ‘backtrack’ algorithm.
INPUT:
• algorithm – string (default: 'tsp'); one of ‘tsp’ or ‘backtrack’
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• constraint_generation – boolean (default: None); whether to use constraint generation when
solving the Mixed Integer Linear Program.
When constraint_generation = None, constraint generation is used whenever the graph has a
density larger than 70%.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• verbose_constraints – boolean (default: False); whether to display which constraints are being
generated
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
OUTPUT:
If using the 'tsp' algorithm, returns a Hamiltonian cycle/circuit if it exists; otherwise, raises a
EmptySetError exception. If using the 'backtrack' algorithm, returns a pair (B, P). If B is True
then P is a Hamiltonian cycle and if B is False, P is a longest path found by the algorithm. Observe that
if B is False, the graph may still be Hamiltonian. The 'backtrack' algorithm is only implemented for
undirected graphs.
Warning: The 'backtrack' algorithm may loop endlessly on graphs with vertices of degree 1.
NOTE:
This function, as is_hamiltonian(), computes a Hamiltonian cycle if it exists: the user should NOT test
for Hamiltonicity using is_hamiltonian() before calling this function, as it would result in computing
it twice.
The backtrack algorithm is only implemented for undirected graphs.
EXAMPLES:
The Heawood Graph is known to be Hamiltonian
sage: g = graphs.HeawoodGraph()
sage: g.hamiltonian_cycle()
TSP from Heawood graph: Graph on 14 vertices
sage: g = graphs.PetersenGraph()
sage: g.hamiltonian_cycle()
Traceback (most recent call last):
...
EmptySetError: the given graph is not Hamiltonian
sage: G=graphs.HeawoodGraph()
sage: G.hamiltonian_cycle(algorithm='backtrack')
(True, [...])
sage: G=graphs.PetersenGraph()
sage: B, P = G.hamiltonian_cycle(algorithm='backtrack')
sage: B
False
sage: len(P)
10
sage: G.has_edge(P[0], P[-1])
False
sage: G=graphs.CubeGraph(3)
sage: G.hamiltonian_cycle(algorithm='backtrack')
(True, [...])
• longest_path()
• hamiltonian_cycle()
INPUT:
• s – vertex (default: None); if specified, then forces the source of the path (the method then returns a
Hamiltonian path starting at s)
• t – vertex (default: None); if specified, then forces the destination of the path (the method then returns
a Hamiltonian path ending at t)
• use_edge_labels – boolean (default: False); whether to compute a weighted hamiltonian path
where the weight of an edge is defined by its label (a label set to None or {} being considered as a
weight of 1), or a non-weighted hamiltonian path
• maximize – boolean (default: False); whether to compute a minimum (default) or a maxi-
mum (when maximize == True) weight hamiltonian path. This parameter is considered only if
use_edge_labels == True.
• algorithm – string (default: "MILP"); the algorithm the use among "MILP" and "backtrack"; two
remarks on this respect:
– While the MILP formulation returns an exact answer, the backtrack algorithm is a randomized
heuristic.
– The backtrack algorithm does not support edge weighting, so setting use_edge_labels=True
will force the use of the MILP algorithm.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
OUTPUT:
A subgraph of self corresponding to a (directed if self is directed) hamiltonian path. If no hamiltonian
path is found, return None. If use_edge_labels == True, a pair weight, path is returned.
EXAMPLES:
The 3×3-grid has an Hamiltonian path, an hamiltonian path starting from vertex (0, 0) and ending at vertex
(2, 2), but no Hamiltonian path starting from (0, 0) and ending at (0, 1):
sage: g = graphs.Grid2dGraph(3, 3)
sage: g.hamiltonian_path()
Hamiltonian path from 2D Grid Graph for [3, 3]: Graph on 9 vertices
sage: g.hamiltonian_path(s=(0, 0), t=(2, 2))
Hamiltonian path from 2D Grid Graph for [3, 3]: Graph on 9 vertices
sage: g.hamiltonian_path(s=(0, 0), t=(2, 2), use_edge_labels=True)
(8, Hamiltonian path from 2D Grid Graph for [3, 3]: Graph on 9 vertices)
sage: g.hamiltonian_path(s=(0, 0), t=(0, 1)) is None
True
sage: g.hamiltonian_path(s=(0, 0), t=(0, 1), use_edge_labels=True)
(0, None)
sage: graphs.EmptyGraph().has_edge(9, 2)
False
sage: DiGraph().has_edge(9, 2)
False
sage: G = Graph(sparse=True)
sage: G.add_edge(0, 1, "label")
sage: G.has_edge(0, 1, "different label")
False
sage: G.has_edge(0, 1, "label")
True
has_loops()
Return whether there are loops in the (di)graph
EXAMPLES:
sage: G = Graph(loops=True); G
Looped graph on 0 vertices
sage: G.has_loops()
False
sage: G.allows_loops()
True
sage: G.add_edge((0, 0))
sage: G.has_loops()
True
sage: G.loops()
[(0, 0, None)]
sage: G.allow_loops(False); G
Graph on 1 vertex
sage: G.has_loops()
False
sage: G.edges(sort=True)
[]
sage: D = DiGraph(loops=True); D
Looped digraph on 0 vertices
sage: D.has_loops()
False
sage: D.allows_loops()
True
sage: D.add_edge((0, 0))
sage: D.has_loops()
True
sage: D.loops()
[(0, 0, None)]
sage: D.allow_loops(False); D
Digraph on 1 vertex
sage: D.has_loops()
False
sage: D.edges(sort=True)
[]
has_multiple_edges(to_undirected=False)
Return whether there are multiple edges in the (di)graph.
INPUT:
• to_undirected – (default: False); if True, runs the test on the undirected version of a DiGraph.
Otherwise, treats DiGraph edges (u, v) and (v, u) as unique individual edges.
EXAMPLES:
sage: G = Graph(multiedges=True, sparse=True); G
Multi-graph on 0 vertices
sage: G.has_multiple_edges()
False
sage: G.allows_multiple_edges()
(continues on next page)
has_vertex(vertex)
Check if vertex is one of the vertices of this graph.
INPUT:
• vertex – the name of a vertex (see add_vertex())
EXAMPLES:
sage: g = Graph({0: [1, 2, 3], 2: [4]}); g
Graph on 5 vertices
sage: 2 in g
True
sage: 10 in g
False
sage: graphs.PetersenGraph().has_vertex(99)
False
Note: This routine needs the optional package igraph to be installed: to do so, it is enough to run sage -i
python_igraph. For more information on the Python version of igraph, see http://igraph.org/python/.
INPUT:
• vertex_list – list (default: None); defines a mapping from the vertices of the graph to consecutive
integers in (0, \ldots, n-1)`. Otherwise, the result of :meth:`vertices` will
be used instead. Because :meth:`vertices` only works if the vertices can be
sorted, using ``vertex_list is useful when working with possibly non-sortable objects in
Python 3.
• vertex_attrs – dictionary (default: {}); a dictionary where the key is a string (the attribute name),
and the value is an iterable containing in position 𝑖 the label of the 𝑖-th vertex in the list vertex_list if
it is given or in vertices() when vertex_list == None (see http://igraph.org/python/doc/igraph.
Graph-class.html#__init__ for more information)
• edge_attrs – dictionary (default: {}); a dictionary where the key is a string (the attribute name),
and the value is an iterable containing in position 𝑖 the label of the 𝑖-th edge in the list outputted
by edge_iterator() (see http://igraph.org/python/doc/igraph.Graph-class.html#__init__ for more
information)
Note: In igraph, a graph is weighted if the edge labels have attribute weight. Hence, to create a weighted
graph, it is enough to add this attribute.
Note: Often, Sage uses its own defined types for integer/floats. These types may not be igraph-compatible
(see example below).
EXAMPLES:
Standard conversion:
sage: G = graphs.TetrahedralGraph()
sage: H = G.igraph_graph() # optional - python_igraph
sage: H.summary() # optional - python_igraph
'IGRAPH U--- 4 6 -- '
sage: G = digraphs.Path(3)
sage: H = G.igraph_graph() # optional - python_igraph
(continues on next page)
['a', 'b']
sage: H.is_weighted() #␣
˓→optional - python_igraph
True
sage: H.es['weight'] #␣
˓→optional - python_igraph
[1, 2]
True
2.0
sage: G = graphs.PetersenGraph()
sage: G.incidence_matrix()
[1 1 1 0 0 0 0 0 0 0 0 0 0 0 0]
[1 0 0 1 1 0 0 0 0 0 0 0 0 0 0]
[0 0 0 1 0 1 1 0 0 0 0 0 0 0 0]
[0 0 0 0 0 1 0 1 1 0 0 0 0 0 0]
[0 1 0 0 0 0 0 1 0 1 0 0 0 0 0]
[0 0 1 0 0 0 0 0 0 0 1 1 0 0 0]
[0 0 0 0 1 0 0 0 0 0 0 0 1 1 0]
[0 0 0 0 0 0 1 0 0 0 1 0 0 0 1]
[0 0 0 0 0 0 0 0 1 0 0 1 1 0 0]
[0 0 0 0 0 0 0 0 0 1 0 0 0 1 1]
(continues on next page)
sage: graphs.CompleteGraph(3).incidence_matrix()
[1 1 0]
[1 0 1]
[0 1 1]
sage: G = Graph([(0, 0), (0, 1), (0, 1)], loops=True, multiedges=True)
sage: G.incidence_matrix(oriented=False)
[2 1 1]
[0 1 1]
A well known result states that the product of the (oriented) incidence matrix with its transpose of a (non-
oriented graph) is in fact the Kirchhoff matrix:
sage: G = graphs.PetersenGraph()
sage: m = G.incidence_matrix(oriented=True)
sage: m * m.transpose() == G.kirchhoff_matrix()
True
sage: K = graphs.CompleteGraph(3)
sage: m = K.incidence_matrix(oriented=True)
sage: m * m.transpose() == K.kirchhoff_matrix()
True
sage: P5 = graphs.PathGraph(5)
sage: P5.incidence_matrix()
[1 0 0 0]
[1 1 0 0]
(continues on next page)
sage: E = list(P5.edge_iterator(labels=False))
sage: P5.incidence_matrix(edges=E[::-1])
[0 0 0 1]
[0 0 1 1]
[0 1 1 0]
[1 1 0 0]
[1 0 0 0]
sage: P5.incidence_matrix(vertices=[2, 4, 1, 3, 0], edges=E[::-1])
[0 1 1 0]
[1 0 0 0]
[0 0 1 1]
[1 1 0 0]
[0 0 0 1]
sage: P5.incidence_matrix(base_ring=RDF)
[1.0 0.0 0.0 0.0]
[1.0 1.0 0.0 0.0]
[0.0 1.0 1.0 0.0]
[0.0 0.0 1.0 1.0]
[0.0 0.0 0.0 1.0]
sage: m = P5.incidence_matrix(immutable=True); m
[1 0 0 0]
[1 1 0 0]
[0 1 1 0]
[0 0 1 1]
[0 0 0 1]
sage: m[1,2] = 1
Traceback (most recent call last):
...
ValueError: matrix is immutable; please change a copy instead (i.e., use␣
˓→copy(M) to change a copy of M).
is_bipartite(certificate=False)
Check whether the graph is bipartite.
Traverse the graph 𝐺 with breadth-first-search and color nodes.
INPUT:
• certificate – boolean (default: False); whether to return a certificate. If set to True, the certificate
returned is a proper 2-coloring when 𝐺 is bipartite, and an odd cycle otherwise.
EXAMPLES:
sage: graphs.CycleGraph(4).is_bipartite()
True
sage: graphs.CycleGraph(5).is_bipartite()
False
sage: graphs.RandomBipartite(10, 10, 0.7).is_bipartite()
True
sage: g = graphs.PetersenGraph()
sage: g.is_bipartite()
False
sage: false, oddcycle = g.is_bipartite(certificate=True)
sage: len(oddcycle) % 2
1
sage: graphs.CycleGraph(4).random_orientation().is_bipartite()
True
sage: graphs.CycleGraph(5).random_orientation().is_bipartite()
False
Note: For this routine to work on all graphs, the optional package gap_packages needs to be installed:
to do so, it is enough to run sage -i gap_packages.
INPUT:
• return_group (boolean; False) – If True, return a group for which the graph is a Cayley graph.
• mapping (boolean; False) – If True, return a mapping from vertices to group elements.
• generators (boolean; False) – If True, return the generating set of the Cayley graph.
• allow_disconnected (boolean; False) – If True, disconnected graphs are considered Cayley if they
can be obtained from the Cayley construction with a generating set that does not generate the group.
ALGORITHM:
For connected graphs, find a regular subgroup of the automorphism group. For disconnected graphs, check
that the graph is vertex-transitive and perform the check on one of its connected components. If a simple
graph has density over 1/2, perform the check on its complement as its disconnectedness may increase
performance.
EXAMPLES:
A Petersen Graph is not a Cayley graph:
sage: g = graphs.PetersenGraph()
sage: g.is_cayley()
False
sage: C7 = groups.permutation.Cyclic(7)
sage: S = [(1,2,3,4,5,6,7), (1,3,5,7,2,4,6), (1,5,2,6,3,7,4)]
sage: d = C7.cayley_graph(generators=S)
sage: d.is_cayley()
True
Graphs with loops and multiedges will have identity and repeated elements, respectively, among the gen-
erators:
is_chordal(certificate=False, algorithm='B')
Check whether the given graph is chordal.
A Graph 𝐺 is said to be chordal if it contains no induced hole (a cycle of length at least 4).
Alternatively, chordality can be defined using a Perfect Elimination Order :
A Perfect Elimination Order of a graph 𝐺 is an ordering 𝑣1 , ..., 𝑣𝑛 of its vertex set such that for all 𝑖, the
neighbors of 𝑣𝑖 whose index is greater that 𝑖 induce a complete subgraph in 𝐺. Hence, the graph 𝐺 can
be totally erased by successively removing vertices whose neighborhood is a clique (also called simplicial
vertices) [FG1965].
(It can be seen that if 𝐺 contains an induced hole, then it cannot have a perfect elimination order. Indeed,
if we write ℎ1 , ..., ℎ𝑘 the 𝑘 vertices of such a hole, then the first of those vertices to be removed would have
two non-adjacent neighbors in the graph.)
A Graph is then chordal if and only if it has a Perfect Elimination Order.
INPUT:
• certificate – boolean (default: False); whether to return a certificate.
– If certificate = False (default), returns True or False accordingly.
– If certificate = True, returns :
∗ (True, peo) when the graph is chordal, where peo is a perfect elimination order of its vertices.
∗ (False, Hole) when the graph is not chordal, where Hole (a Graph object) is an induced
subgraph of self isomorphic to a hole.
• algorithm – string (default: "B"); the algorithm to choose among "A" or "B" (see next section).
While they will agree on whether the given graph is chordal, they cannot be expected to return the
same certificates.
ALGORITHM:
This algorithm works through computing a Lex BFS on the graph, then checking whether the order is a Per-
fect Elimination Order by computing for each vertex 𝑣 the subgraph induces by its non-deleted neighbors,
then testing whether this graph is complete.
This problem can be solved in 𝑂(𝑚) [RT1975] ( where 𝑚 is the number of edges in the graph ) but this
implementation is not linear because of the complexity of Lex BFS.
EXAMPLES:
The lexicographic product of a Path and a Complete Graph is chordal
sage: g = graphs.PathGraph(5).lexicographic_product(graphs.CompleteGraph(3))
sage: g.is_chordal()
True
The same goes with the product of a random lobster (which is a tree) and a Complete Graph
sage: g.is_chordal()
True
sage: (2 * g).is_chordal()
True
Let us check the certificate given by Sage is indeed a perfect elimination order:
sage: g = graphs.PetersenGraph()
sage: g.girth()
5
(continues on next page)
is_circulant(certificate=False)
Check whether the graph is circulant.
For more information, see Wikipedia article Circulant_graph.
INPUT:
• certificate – boolean (default: False); whether to return a certificate for yes-answers (see OUT-
PUT section)
OUTPUT:
When certificate is set to False (default) this method only returns True or False an-
swers. When certificate is set to True, the method either returns (False, None) or (True,
lists_of_parameters) each element of lists_of_parameters can be used to define the graph as
a circulant graph.
See the documentation of CirculantGraph() and Circulant() for more information, and the examples
below.
See also:
CirculantGraph() – a constructor for circulant graphs.
EXAMPLES:
The Petersen graph is not a circulant graph:
sage: g = graphs.PetersenGraph()
sage: g.is_circulant()
False
A cycle is obviously a circulant graph, but several sets of parameters can be used to define it:
sage: g = graphs.CycleGraph(5)
sage: g.is_circulant(certificate=True)
(True, [(5, [1, 4]), (5, [2, 3])])
sage: g = digraphs.Circuit(5)
sage: g.is_circulant(certificate=True)
(True, [(5, [1]), (5, [3]), (5, [2]), (5, [4])])
With this information, it is very easy to create (and plot) all possible drawings of a circulant graph:
REFERENCE:
[BM2004]
EXAMPLES:
sage: g439 = Graph({1: [5, 7], 2: [5, 6], 3: [6, 7], 4: [5, 6, 7]})
sage: g439.show()
sage: g439.is_circular_planar(boundary=[1, 2, 3, 4])
False
sage: g439.is_circular_planar(kuratowski=True, boundary=[1, 2, 3, 4])
(False, Graph on 8 vertices)
sage: g439.is_circular_planar(kuratowski=True, boundary=[1, 2, 3])
(True, None)
sage: g439.get_embedding()
{1: [5, 7],
2: [6, 5],
3: [7, 6],
4: [5, 6, 7],
5: [2, 4, 1],
6: [3, 4, 2],
7: [1, 4, 3]}
Order matters:
sage: g = graphs.CompleteGraph(4)
sage: g.is_clique([1, 2, 3])
True
sage: g.is_clique()
True
sage: h = graphs.CycleGraph(4)
sage: h.is_clique([1, 2])
True
sage: h.is_clique([1, 2, 3])
False
sage: h.is_clique()
False
sage: i = digraphs.Complete(4)
sage: i.delete_edge([0, 1])
sage: i.is_clique(directed_clique=False, induced=True)
False
sage: i.is_clique(directed_clique=False, induced=False)
True
sage: i.is_clique(directed_clique=True)
False
is_connected(G)
Check whether the (di)graph is connected.
Note that in a graph, path connected is equivalent to connected.
INPUT:
• G – the input graph
See also:
• is_biconnected()
EXAMPLES:
sage: G = graphs.CompleteGraph(4)
sage: G.add_edge((0,5,'silly'))
sage: is_cut_edge(G,(0,5,'silly'))
True
sage: G = Graph([[0,1],[0,2],[3,4],[4,5],[3,5]])
sage: is_cut_edge(G,(0,1))
True
sage: G = digraphs.Circuit(5)
sage: is_cut_edge(G,(0,1))
False
sage: G = graphs.CompleteGraph(6)
sage: is_cut_edge(G,(0,7))
Traceback (most recent call last):
...
ValueError: edge not in graph
is_cut_vertex(G, u, weak=False)
Check whether the input vertex is a cut-vertex.
A vertex is a cut-vertex if its removal from the (di)graph increases the number of (strongly) connected
components. Isolated vertices or leafs are not cut-vertices. This function works with simple graphs as well
as graphs with loops and multiple edges.
INPUT:
• G – a Sage (Di)Graph
• u – a vertex
• weak – boolean (default: False); whether the connectivity of directed graphs is to be taken in the
weak sense, that is ignoring edges orientations
OUTPUT:
Return True if u is a cut-vertex, and False otherwise.
EXAMPLES:
Giving a LollipopGraph(4,2), that is a complete graph with 4 vertices with a pending edge:
sage: G = graphs.CompleteGraph(4)
sage: is_cut_vertex(G, 7)
Traceback (most recent call last):
...
ValueError: vertex (7) is not a vertex of the graph
is_cycle(directed_cycle=True)
Check whether self is a (directed) cycle graph.
We follow the definition provided in [BM2008] for undirected graphs. A cycle on three or more vertices
is a simple graph whose vertices can be arranged in a cyclic order so that two vertices are adjacent if they
are consecutive in the order, and not adjacent otherwise. A cycle on a vertex consists of a single vertex
provided with a loop and a cycle with two vertices consists of two vertices connected by a pair of parallel
edges. In other words, an undirected graph is a cycle if it is 2-regular and connected. The empty graph is
not a cycle.
For directed graphs, a directed cycle, or circuit, on two or more vertices is a strongly connected directed
graph without loops nor multiple edges with has many arcs as vertices. A circuit on a vertex consists of a
single vertex provided with a loop.
INPUT:
• directed_cycle – boolean (default: True); if set to True and the graph is directed, only return True
if self is a directed cycle graph (i.e., a circuit). If set to False, we ignore the direction of edges and
so opposite arcs become multiple (parallel) edges. This parameter is ignored for undirected graphs.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.is_cycle()
False
sage: graphs.CycleGraph(5).is_cycle()
True
sage: Graph([(0,1 )]).is_cycle()
False
sage: Graph([(0, 1), (0, 1)], multiedges=True).is_cycle()
True
sage: Graph([(0, 1), (0, 1), (0, 1)], multiedges=True).is_cycle()
False
sage: Graph().is_cycle()
False
sage: G = Graph([(0, 0)], loops=True)
sage: G.is_cycle()
True
sage: digraphs.Circuit(3).is_cycle()
True
sage: digraphs.Circuit(2).is_cycle()
True
sage: digraphs.Circuit(2).is_cycle(directed_cycle=False)
True
sage: D = DiGraph(graphs.CycleGraph(3))
sage: D.is_cycle()
False
sage: D.is_cycle(directed_cycle=False)
False
sage: D.edges(sort=True, labels=False)
[(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
is_drawn_free_of_edge_crossings()
Check whether the position dictionary for this graph is set and that position dictionary gives a planar em-
bedding.
This simply checks all pairs of edges that don’t share a vertex to make sure that they don’t intersect.
Note: This function require that _pos attribute is set (Returns False otherwise)
EXAMPLES:
sage: D = graphs.DodecahedralGraph()
sage: pos = D.layout(layout='planar', save_pos=True)
sage: D.is_drawn_free_of_edge_crossings()
True
is_equitable(partition, quotient_matrix=False)
Checks whether the given partition is equitable with respect to self.
A partition is equitable with respect to a graph if for every pair of cells C1, C2 of the partition, the number
sage: G = graphs.PetersenGraph()
sage: G.is_equitable([[0,4],[1,3,5,9],[2,6,8],[7]])
False
sage: G.is_equitable([[0,4],[1,3,5,9],[2,6,8,7]])
True
sage: G.is_equitable([[0,4],[1,3,5,9],[2,6,8,7]], quotient_matrix=True)
[1 2 0]
[1 0 2]
[0 2 1]
sage: ss = (graphs.WheelGraph(6)).line_graph(labels=False)
sage: prt = [[(0, 1)], [(0, 2), (0, 3), (0, 4), (1, 2), (1, 4)], [(2, 3), (3,␣
˓→4)]]
sage: ss.is_equitable(prt)
Traceback (most recent call last):
...
TypeError: Partition ([[(0, 1)], [(0, 2), (0, 3), (0, 4), (1, 2), (1, 4)], [(2,␣
˓→3), (3, 4)]]) is not valid for this graph: vertices are incorrect.
sage: ss = (graphs.WheelGraph(5)).line_graph(labels=False)
sage: ss.is_equitable(prt)
False
is_eulerian(path=False)
Check whether the graph is Eulerian.
A graph is Eulerian if it has a (closed) tour that visits each edge exactly once.
INPUT:
• path – boolean (default: False); by default this function finds if the graph contains a closed tour
visiting each edge once, i.e. an Eulerian cycle. If you want to test the existence of an Eulerian path,
set this argument to True. Graphs with this property are sometimes called semi-Eulerian.
OUTPUT:
True or False for the closed tour case. For an open tour search (path``=``True) the function returns
False if the graph is not semi-Eulerian, or a tuple (u, v) in the other case. This tuple defines the edge
that would make the graph Eulerian, i.e. close an existing open tour. This edge may or may not be already
present in the graph.
EXAMPLES:
sage: graphs.CompleteGraph(4).is_eulerian()
False
(continues on next page)
is_gallai_tree()
Return whether the current graph is a Gallai tree.
A graph is a Gallai tree if and only if it is connected and its 2-connected components are all isomorphic to
complete graphs or odd cycles.
A connected graph is not degree-choosable if and only if it is a Gallai tree [ERT1979].
EXAMPLES:
A complete graph is, or course, a Gallai Tree:
sage: g = graphs.CompleteGraph(15)
sage: g.is_gallai_tree()
True
sage: g = graphs.PetersenGraph()
sage: g.is_gallai_tree()
False
A Graph built from vertex-disjoint complete graphs linked by one edge to a special vertex −1 is a ‘’star-
shaped” Gallai tree:
sage: g = 8 * graphs.CompleteGraph(6)
sage: g.add_edges([(-1, c[0]) for c in g.connected_components()])
sage: g.is_gallai_tree()
True
sage: g = graphs.HeawoodGraph()
sage: g.is_hamiltonian()
True
sage: g = graphs.PetersenGraph()
sage: g.is_hamiltonian()
False
is_immutable()
Check whether the graph is immutable.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.is_immutable()
False
sage: Graph(G, immutable=True).is_immutable()
True
is_independent_set(vertices=None)
Check whether vertices is an independent set of self.
An independent set is a set of vertices such that there is no edge between any two vertices.
INPUT:
• vertices – a single vertex or an iterable container of vertices (default: None); when set, check
whether the given set of vertices is an independent set, otherwise, check
whether the set of vertices of ``self is an independent set
EXAMPLES:
sage: graphs.CycleGraph(4).is_independent_set([1,3])
True
sage: graphs.CycleGraph(4).is_independent_set([1,2,3])
False
is_interval(certificate=False)
Check whether the graph is an interval graph.
An interval graph is one where every vertex can be seen as an interval on the real line so that there is an
edge in the graph iff the corresponding intervals intersects.
See the Wikipedia article Interval_graph for more information.
INPUT:
• certificate – boolean (default: False);
– When certificate=False, returns True is the graph is an interval graph and False otherwise
– When certificate=True, returns either (False, None) or (True, d) where d is a dictionary
whose keys are the vertices and values are pairs of integers. They correspond to an embedding
of the interval graph, each vertex being represented by an interval going from the first of the two
values to the second.
ALGORITHM:
Through the use of PQ-Trees.
AUTHOR:
Nathann Cohen (implementation)
EXAMPLES:
sage: g = graphs.PetersenGraph()
sage: g.is_interval()
False
See also:
sage: D = graphs.DodecahedralGraph()
sage: E = copy(D)
sage: gamma = SymmetricGroup(20).random_element() #␣
˓→optional - sage.groups
sage: E.relabel(gamma) #␣
˓→optional - sage.groups
sage: D.is_isomorphic(E)
True
sage: D = graphs.DodecahedralGraph()
sage: S = SymmetricGroup(20) #␣
˓→optional - sage.groups
sage: E = copy(D) #␣
˓→optional - sage.groups
sage: E.relabel(gamma) #␣
˓→optional - sage.groups
sage: g=graphs.HeawoodGraph()
sage: g.is_isomorphic(g)
True
Multigraphs:
sage: G = Graph(multiedges=True,sparse=True)
sage: G.add_edge((0,1,1))
sage: G.add_edge((0,1,2))
sage: G.add_edge((0,1,3))
sage: G.add_edge((0,1,4))
sage: H = Graph(multiedges=True,sparse=True)
sage: H.add_edge((3,4))
sage: H.add_edge((3,4))
sage: H.add_edge((3,4))
sage: H.add_edge((3,4))
sage: G.is_isomorphic(H)
True
Digraphs:
sage: G = Graph(sparse=True)
sage: G.add_edges( [(0,1,'a'),(1,2,'b'),(2,3,'c'),(3,4,'b'),(4,0,'a')] )
sage: H = G.relabel([1,2,3,4,0], inplace=False)
sage: G.is_isomorphic(H, edge_labels=True)
True
sage: G = DiGraph()
sage: G.add_edges( [(0,1,'a'),(1,2,'b'),(2,3,'c'),(3,4,'b'),(4,0,'a')] )
sage: H = G.relabel([1,2,3,4,0], inplace=False)
sage: G.is_isomorphic(H, edge_labels=True)
True
sage: G.is_isomorphic(H, edge_labels=True, certificate=True)
(True, {0: 1, 1: 2, 2: 3, 3: 4, 4: 0})
Note: The argument on_embedding takes precedence over set_embedding. This means that only the
on_embedding combinatorial embedding will be tested for planarity and no _embedding attribute will be
set as a result of this function call, unless on_embedding is None.
REFERENCE:
[BM2004]
See also:
INPUT:
• on_embedding – dictionary (default: None); the embedding dictionary to test planarity on (i.e.: will
return True or False only for the given embedding)
• kuratowski – boolean (default: False); whether to return a tuple with boolean as first entry. If the
graph is nonplanar, will return the Kuratowski subgraph (i.e. an edge subdivision of 𝐾5 or 𝐾3,3 ) as
the second tuple entry. If the graph is planar, returns None as the second entry. When set to False,
only a boolean answer is returned.
• set_embedding – boolean (default: False); whether to set the instance field variable that contains a
combinatorial embedding (clockwise ordering of neighbors at each vertex). This value will only be set
if a planar embedding is found. It is stored as a Python dict: v1: [n1,n2,n3] where v1 is a vertex
and n1,n2,n3 are its neighbors.
• set_pos – boolean (default: False); whether to set the position dictionary (for plotting) to reflect the
combinatorial embedding. Note that this value will default to False if set_emb is set to False. Also,
the position dictionary will only be updated if a planar embedding is found.
EXAMPLES:
sage: g = graphs.CubeGraph(4)
sage: g.is_planar()
False
sage: g = graphs.CircularLadderGraph(4)
sage: g.is_planar(set_embedding=True)
True
sage: g.get_embedding()
{0: [1, 4, 3],
1: [2, 5, 0],
2: [3, 6, 1],
3: [0, 7, 2],
4: [0, 5, 7],
5: [1, 6, 4],
6: [2, 7, 5],
7: [4, 6, 3]}
sage: g = graphs.PetersenGraph()
sage: (g.is_planar(kuratowski=True))[1].adjacency_matrix()
[0 1 0 0 0 1 0 0 0]
[1 0 1 0 0 0 1 0 0]
[0 1 0 1 0 0 0 1 0]
[0 0 1 0 0 0 0 0 1]
[0 0 0 0 0 0 1 1 0]
[1 0 0 0 0 0 0 1 1]
[0 1 0 0 1 0 0 0 1]
[0 0 1 0 1 1 0 0 0]
[0 0 0 1 0 1 1 0 0]
sage: G.is_planar(set_pos=True)
Traceback (most recent call last):
...
NotImplementedError: cannot compute with embeddings of multiple-edged or looped␣
˓→graphs
sage: G.is_planar(set_embedding=True)
Traceback (most recent call last):
...
NotImplementedError: cannot compute with embeddings of multiple-edged or looped␣
˓→graphs
sage: G.is_planar(kuratowski=True)
(True, None)
sage: G = graphs.CompleteGraph(5)
sage: G = Graph(G, multiedges=True)
sage: G.add_edge(0, 1)
sage: G.is_planar()
False
sage: b,k = G.is_planar(kuratowski=True)
sage: b
False
sage: k.vertices(sort=True)
[0, 1, 2, 3, 4]
is_regular(k=None)
Check whether this graph is (𝑘-)regular.
INPUT:
• k – integer (default: None); the degree of regularity to check for
EXAMPLES:
sage: G = graphs.HoffmanSingletonGraph()
sage: G.is_regular()
True
sage: G.is_regular(9)
False
So the Hoffman-Singleton graph is regular, but not 9-regular. In fact, we can now find the degree easily as
follows:
sage: next(G.degree_iterator())
7
sage: graphs.HouseGraph().is_regular()
False
sage: Graph().is_regular()
True
is_self_complementary()
Check whether the graph is self-complementary.
A (di)graph is self-complementary if it is isomorphic to its (di)graph complement. For instance, the path
graph 𝑃4 and the cycle graph 𝐶5 are self-complementary.
See also:
EXAMPLES:
sage: graphs.PathGraph(4).is_self_complementary()
True
sage: graphs.PathGraph(5).is_self_complementary()
False
sage: digraphs.Path(2).is_self_complementary()
True
sage: digraphs.Path(3).is_self_complementary()
False
sage: G = graphs.PaleyGraph(9)
sage: G.is_self_complementary()
True
Warning: The arguments induced and up_to_isomorphism are set respectively to True and False
by default.
INPUT:
• other – a Sage (Di)Graph
• induced – boolean (default: True); if set to True check whether the graph is an induced subgraph
of other that is if the vertices of the graph are also vertices of other, and the edges of the graph are
equal to the edges of other between the vertices contained in the graph.
If set to False tests whether the graph is a subgraph of other that is if all vertices of the graph are
also in other and all edges of the graph are also in other.
• up_to_isomorphism – boolean (default: False); if set to True check whether other is a subgraph
ignoring the labeling of vertices and edges. Otherwise, vertex and edge labellings must coincide in the
copy or induced copy.
OUTPUT:
boolean – True iff the graph is a (possibly induced) subgraph of other.
See also:
For more advanced search of subgraphs isomorphic to a given graph, you could consider the following
methods:
• subgraph_search() – find a subgraph isomorphic to other inside of the graph
• subgraph_search_count() – count the number of such copies
• subgraph_search_iterator() – iterator over all the copies of other contained in the graph
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: G = P.subgraph(range(6))
sage: G.is_subgraph(P)
True
sage: H = graphs.CycleGraph(5)
sage: G = graphs.PathGraph(5)
sage: G.is_subgraph(H)
False
sage: G.is_subgraph(H, induced=False)
True
sage: H.is_subgraph(G, induced=False)
False
The 4x4 grid contains a path of length 15 and an induced path of length 11:
sage: p11 = graphs.PathGraph(11)
sage: p15 = graphs.PathGraph(15)
sage: g = graphs.Grid2dGraph(4, 4)
sage: p15.is_subgraph(g, induced=False, up_to_isomorphism=True)
True
sage: p15.is_subgraph(g, induced=True, up_to_isomorphism=True)
False
sage: p11.is_subgraph(g, induced=True, up_to_isomorphism=True)
True
is_transitively_reduced()
Check whether the digraph is transitively reduced.
A digraph is transitively reduced if it is equal to its transitive reduction. A graph is transitively reduced if
it is a forest.
EXAMPLES:
sage: d = DiGraph({0: [1], 1: [2], 2: [3]})
sage: d.is_transitively_reduced()
True
sage: G = Graph({0:[1],1:[2]})
sage: G.is_vertex_transitive()
(continues on next page)
katz_centrality(alpha, u=None)
Return the Katz centrality of vertex 𝑢.
Katz centrality of a node is a measure of centrality in a graph network. Katz centrality computes the relative
influence of a node within a network. Connections made with distant neighbors are, however penalized by
an attenuation factor 𝛼.
See the Wikipedia article Katz_centrality for more information.
INPUT:
• alpha – a nonnegative real number, must be less than the reciprocal of the spectral radius of the graph
(the maximum absolute eigenvalue of the adjacency matrix).
• u – the vertex whose Katz centrality needs to be measured (default: None)
OUTPUT: a list containing the Katz centrality of each vertex if u=None otherwise Katz centrality of the
vertex u.
EXAMPLES:
We compute the Katz centrality of a 4-cycle (note that by symmetry, all 4 vertices have the same centrality)
sage: G = graphs.CycleGraph(4)
sage: G.katz_centrality(1/20)
{0: 1/9, 1: 1/9, 2: 1/9, 3: 1/9}
Note that in the below example the nodes having indegree 0 also have the Katz centrality value as 0, as
these nodes are not influenced by other nodes.
sage: G.katz_centrality(.85)
{1: 0.000000000000000,
2: 0.000000000000000,
3: 0.000000000000000,
4: 16.7319819819820,
5: 18.6846846846847,
6: 173.212076941807,
7: 0.000000000000000,
8: 18.6846846846847,
9: 0.000000000000000,
10: 20.9819819819820,
11: 202.778914049184}
See also:
• katz_matrix()
• Wikipedia article Katz_centrality
sage: G = graphs.CycleGraph(4)
sage: G.katz_matrix(1/20)
[1/198 5/99 1/198 5/99]
[ 5/99 1/198 5/99 1/198]
[1/198 5/99 1/198 5/99]
[ 5/99 1/198 5/99 1/198]
We find the Katz matrix of an undirected 4-cycle with all entries other than those which correspond to
non-edges zeroed out.
sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)])
sage: H.katz_matrix(1/10)
[ 169/2256 545/4512 25/188 605/4512 25/188 545/4512 485/
˓→4512]
See also:
• katz_centrality()
• Wikipedia article Katz_centrality
Note that any additional keywords will be passed on to either the adjacency_matrix() or
weighted_adjacency_matrix() method.
AUTHORS:
• Tom Boothby
• Jason Grout
EXAMPLES:
sage: G = Graph(sparse=True)
sage: G.add_edges([(0, 1, 1), (1, 2, 2), (0, 2, 3), (0, 3, 4)])
sage: M = G.kirchhoff_matrix(weighted=True); M
[ 8 -1 -3 -4]
[-1 3 -2 0]
[-3 -2 5 0]
[-4 0 0 4]
sage: M = G.kirchhoff_matrix(); M
[ 3 -1 -1 -1]
[-1 2 -1 0]
[-1 -1 2 0]
[-1 0 0 1]
sage: M = G.laplacian_matrix(normalized=True); M ␣
˓→ # optional - sage.symbolic
[ 1 -1/6*sqrt(3)*sqrt(2) -1/6*sqrt(3)*sqrt(2) -1/
˓→3*sqrt(3)]
[-1/6*sqrt(3)*sqrt(2) 1 -1/2 ␣
˓→ 0]
[-1/6*sqrt(3)*sqrt(2) -1/2 1 ␣
˓→ 0]
[ -1/3*sqrt(3) 0 0 ␣
˓→ 1]
sage: M = G.kirchhoff_matrix(weighted=True, signless=True); M
[8 1 3 4]
[1 3 2 0]
[3 2 5 0]
[4 0 0 4]
sage: G = Graph(sparse=True)
sage: G.add_edges([(0, 1, 1), (1, 2, 2), (0, 2, 3), (0, 3, 4)])
sage: M = G.kirchhoff_matrix(vertices=[3, 2, 1, 0]); M
[ 1 0 0 -1]
[ 0 2 -1 -1]
[ 0 -1 2 -1]
[-1 -1 -1 3]
sage: M = G.kirchhoff_matrix(weighted=True, vertices=[3, 2, 1, 0]); M
[ 4 0 0 -4]
[ 0 5 -2 -3]
[ 0 -2 3 -1]
[-4 -3 -1 8]
kronecker_product(other)
Return the tensor product of self and other.
The tensor product of 𝐺 and 𝐻 is the graph 𝐿 with vertex set 𝑉 (𝐿) equal to the Cartesian product of the
vertices 𝑉 (𝐺) and 𝑉 (𝐻), and ((𝑢, 𝑣), (𝑤, 𝑥)) is an edge iff - (𝑢, 𝑤) is an edge of self, and - (𝑣, 𝑥) is an
edge of other.
The tensor product is also known as the categorical product and the Kronecker product (referring to the
Kronecker matrix product). See the Wikipedia article Kronecker_product.
EXAMPLES:
sage: Z = graphs.CompleteGraph(2)
sage: C = graphs.CycleGraph(5)
sage: T = C.tensor_product(Z); T
Graph on 10 vertices
sage: T.size()
10
sage: T.plot() # long time
Graphics object consisting of 21 graphics primitives
sage: D = graphs.DodecahedralGraph()
sage: P = graphs.PetersenGraph()
sage: T = D.tensor_product(P); T
Graph on 200 vertices
sage: T.size()
900
(continues on next page)
sage: G = Graph(sparse=True)
sage: G.add_edges([(0, 1, 1), (1, 2, 2), (0, 2, 3), (0, 3, 4)])
sage: M = G.kirchhoff_matrix(weighted=True); M
[ 8 -1 -3 -4]
(continues on next page)
[-1/6*sqrt(3)*sqrt(2) 1 -1/2 ␣
˓→ 0]
[-1/6*sqrt(3)*sqrt(2) -1/2 1 ␣
˓→ 0]
[ -1/3*sqrt(3) 0 0 ␣
˓→ 1]
sage: M = G.kirchhoff_matrix(weighted=True, signless=True); M
[8 1 3 4]
[1 3 2 0]
[3 2 5 0]
[4 0 0 4]
sage: G = Graph(sparse=True)
sage: G.add_edges([(0, 1, 1), (1, 2, 2), (0, 2, 3), (0, 3, 4)])
sage: M = G.kirchhoff_matrix(vertices=[3, 2, 1, 0]); M
[ 1 0 0 -1]
(continues on next page)
latex_options()
Return an instance of GraphLatex for the graph.
Changes to this object will affect the LaTeX version of the graph. For a full explanation of how to use
LaTeX to render graphs, see the introduction to the graph_latex module.
EXAMPLES:
sage: g = graphs.PetersenGraph()
sage: opts = g.latex_options()
sage: opts
LaTeX options for Petersen graph: {}
sage: opts.set_option('tkz_style', 'Classic')
sage: opts
LaTeX options for Petersen graph: {'tkz_style': 'Classic'}
sage: g = digraphs.ButterflyGraph(1)
sage: D2 = g.layout(); D2 # random
{('0', 0): [2.69..., 0.43...],
('0', 1): [1.35..., 0.86...],
('1', 0): [0.89..., -0.42...],
('1', 1): [2.26..., -0.87...]}
˓→is chosen close to the center of the tree. Ignored unless ``layout='forest'``.
option iterations : The number of times to execute the spring layout algorithm.
option layout : A layout algorithm -- one of : "acyclic", "circular" (plots the␣
˓→graph with vertices evenly distributed on a circle), "ranked", "graphviz",
option save_pos : Whether or not to save the computed position for the graph.
option spring : Use spring layout to finalize the current layout.
option tree_orientation : The direction of tree branches -- 'up', 'down', 'left
˓→' or 'right'.
option tree_root : A vertex designation for drawing trees. A vertex of the tree␣
˓→to be used as the root for the ``layout='tree'`` option. If no root is␣
˓→specified, then one is chosen close to the center of the tree. Ignored unless␣
˓→``layout='tree'``.
Some of them only apply to certain layout algorithms. For details, see layout_acyclic(),
layout_planar(), layout_circular(), layout_spring(), . . .
Warning: graphviz and dot2tex are currently required to obtain a nice 'acyclic' layout. See
layout_graphviz() for installation instructions.
A subclass may implement another layout algorithm "blah", by implementing a method .layout_blah.
It may override the default layout by overriding layout_default(), and similarly override the predefined
layouts.
Todo: use this feature for all the predefined graphs classes (like for the Petersen graph, . . . ), rather than
systematically building the layout at construction time.
layout_default(by_component=True, **options)
Return a spring layout for this graph.
INPUT:
• by_components – boolean (default: True);
• **options – options for method spring_layout_fast()
OUTPUT: a dictionary mapping vertices to positions
EXAMPLES:
layout_extend_randomly(pos, dim=2)
Extend randomly a partial layout
INPUT:
• pos – a dictionary mapping vertices to positions
• dim – integer (default: 2); the number of dimensions of the layout, 2 or 3
OUTPUT: a dictionary mapping vertices to positions
The vertices not referenced in pos are assigned random positions within the box delimited by the other
vertices.
EXAMPLES:
sage: H = digraphs.ButterflyGraph(1)
sage: pos = {('0', 0): (0, 0), ('1', 1): (1, 1)}
sage: H.layout_extend_randomly(pos) # random
{('0', 0): (0, 0),
('0', 1): [0.0446..., 0.332...],
(continues on next page)
sage: g = digraphs.ButterflyGraph(2)
sage: g.layout_graphviz() # optional - dot2tex graphviz
{('...', ...): [...,...],
('...', ...): [...,...],
('...', ...): [...,...],
('...', ...): [...,...],
('...', ...): [...,...],
('...', ...): [...,...],
('...', ...): [...,...],
('...', ...): [...,...],
('...', ...): [...,...],
(continues on next page)
This requires graphviz and the dot2tex spkg. Here are some installation tips:
• Install graphviz >= 2.14 so that the programs dot, neato, etc. are in your path. The graphviz suite
can be download from http://graphviz.org.
• Install dot2tex with sage -i dot2tex
Todo: Use the graphviz functionality of Networkx 1.0 once it will be merged into Sage.
particular 𝑢𝑣 has to be an edge of the graph. If external_face == None, an arbitrary external face
is chosen.
• test – boolean (default: False); whether to perform sanity tests along the way
• circular – ignored
EXAMPLES:
sage: g = graphs.PathGraph(10)
sage: g.layout(layout='planar', save_pos=True, test=True)
{0: [0, 8],
1: [8, 1],
2: [1, 0],
3: [7, 1],
4: [1, 1],
5: [5, 3],
6: [2, 3],
7: [2, 4],
8: [1, 6],
9: [2, 5]}
sage: g = graphs.BalancedTree(3, 4)
sage: pos = g.layout(layout='planar', save_pos=True, test=True)
sage: pos[0]
[0, 119]
sage: pos[120]
[21, 37]
sage: g = graphs.CycleGraph(7)
sage: g.layout(layout='planar', save_pos=True, test=True)
{0: [0, 5], 1: [5, 1], 2: [1, 0], 3: [4, 1], 4: [1, 1], 5: [2, 2], 6: [1, 2]}
sage: g = graphs.CompleteGraph(5)
sage: g.layout(layout='planar', save_pos=True, test=True, set_embedding=True)
Traceback (most recent call last):
...
ValueError: Complete graph is not a planar graph
sage: g = graphs.CompleteGraph(4)
sage: g.layout(layout='planar', external_face=(0,1))
{0: [0, 2], 1: [2, 1], 2: [1, 0], 3: [1, 1]}
sage: g.layout(layout='planar', external_face=(3,1))
{0: [2, 1], 1: [0, 2], 2: [1, 1], 3: [1, 0]}
• heights – dictionary (default: None); a dictionary mapping heights to the list of vertices at this height
• dim – integer (default: 2); the number of dimensions of the layout, 2 or 3
• spring – boolean (default: False);
• **options – options for method spring_layout_fast()
OUTPUT: a dictionary mapping vertices to positions
Returns a layout computed by randomly arranging the vertices along the given heights
EXAMPLES:
sage: g = graphs.LadderGraph(3)
sage: g.layout_ranked(heights={i: (i, i+3) for i in range(3)}) # random
{0: [0.668..., 0],
1: [0.667..., 1],
2: [0.677..., 2],
3: [1.34..., 0],
4: [1.33..., 1],
5: [1.33..., 2]}
sage: g = graphs.LadderGraph(7)
sage: g.plot(layout="ranked", heights={i: (i, i+7) for i in range(7)})
Graphics object consisting of 34 graphics primitives
layout_spring(by_component=True, **options)
Return a spring layout for this graph.
INPUT:
• by_components – boolean (default: True);
• **options – options for method spring_layout_fast()
OUTPUT: a dictionary mapping vertices to positions
EXAMPLES:
• tree_orientation – string (default: 'down'); the direction in which the tree is growing, can be
'up', 'down', 'left' or 'right'
• dim – integer (default: 2); the number of dimensions of the layout, 2 or 3
• **options – other parameters not used here
If the tree has been given a planar embedding (fixed circular order on the set of neighbors of every vertex)
using set_embedding, the algorithm will create a layout that respects this embedding.
OUTPUT: a dictionary mapping vertices to positions
EXAMPLES:
sage: G = graphs.RandomTree(80)
sage: G.plot(layout="tree", tree_orientation="right")
Graphics object consisting of 160 graphics primitives
sage: G = graphs.HoffmanSingletonGraph()
sage: T = Graph()
sage: T.add_edges(G.min_spanning_tree(starting_vertex=0))
sage: T.show(layout='tree', tree_root=0)
sage: G = graphs.BalancedTree(2, 2)
sage: G.layout_tree(tree_root=0)
{0: [1.5, 0],
1: [2.5, -1],
2: [0.5, -1],
3: [3.0, -2],
4: [2.0, -2],
5: [1.0, -2],
6: [0.0, -2]}
sage: G = graphs.BalancedTree(2, 4)
sage: G.plot(layout="tree", tree_root=0, tree_orientation="up")
Graphics object consisting of 62 graphics primitives
sage: T = Graph([(0, 1), (0, 6), (0, 3), (1, 2), (1, 5), (3, 4), (3, 7), (3,␣
˓→8)])
EXAMPLES:
A Lex BFS is obviously an ordering of the vertices:
sage: g = graphs.CompleteGraph(6)
sage: len(g.lex_BFS()) == g.order()
True
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4, 5),
˓→ (5, 6)])
sage: g.lex_BFS()
[1, 2, 3, 5, 4, 6]
sage: g = graphs.PathGraph(3).lexicographic_product(graphs.CompleteGraph(2))
sage: g.lex_BFS(reverse=True)
[(2, 1), (2, 0), (1, 1), (1, 0), (0, 1), (0, 0)]
And the vertices at the end of the tree of discovery are, for chordal graphs, simplicial vertices (their neigh-
borhood is a complete graph):
sage: g = graphs.ClawGraph().lexicographic_product(graphs.CompleteGraph(2))
sage: v = g.lex_BFS()[-1]
sage: peo, tree = g.lex_BFS(initial_vertex = v, tree=True)
sage: leaves = [v for v in tree if tree.in_degree(v) ==0]
sage: all(g.subgraph(g.neighbors(v)).is_clique() for v in leaves)
True
sage: G = digraphs.DeBruijn(2,3)
sage: G.lex_BFS(initial_vertex='000', algorithm="fast")
['000', '001', '100', '010', '011', '110', '101', '111']
sage: G.lex_BFS(initial_vertex='000', algorithm="slow")
['000', '001', '100', '010', '011', '110', '101', '111']
sage: G.lex_DFS(initial_vertex='000')
['000', '001', '100', '010', '101', '110', '011', '111']
sage: G.lex_UP(initial_vertex='000')
['000', '001', '010', '101', '110', '111', '011', '100']
sage: G.lex_DOWN(initial_vertex='000')
['000', '001', '100', '011', '010', '110', '111', '101']
INPUT:
• G – a sage graph
• reverse – boolean (default: False); whether to return the vertices in discovery order, or the reverse
• tree – boolean (default: False); whether to return the discovery directed tree (each vertex being
linked to the one that saw it for the first time)
• initial_vertex – (default: None); the first vertex to consider
ALGORITHM:
This algorithm maintains for each vertex left in the graph a code corresponding to the vertices already
removed. The vertex of maximal code (according to the lexicographic order) is then removed, and the
codes are updated. Lex DFS differs from Lex BFS only in the way codes are updated after each iteration.
Time complexity is 𝑂(𝑛 + 𝑚) where 𝑛 is the number of vertices and 𝑚 is the number of edges.
See [CK2008] for more details on the algorithm.
See also:
EXAMPLES:
A Lex DFS is obviously an ordering of the vertices:
sage: g = graphs.CompleteGraph(6)
sage: len(g.lex_DFS()) == g.order()
True
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4, 5),
˓→ (5, 6)])
sage: g.lex_DFS()
[1, 2, 3, 5, 6, 4]
sage: G = digraphs.DeBruijn(2,3)
sage: G.lex_BFS(initial_vertex='000')
['000', '001', '100', '010', '011', '110', '101', '111']
sage: G.lex_DFS(initial_vertex='000')
['000', '001', '100', '010', '101', '110', '011', '111']
sage: G.lex_UP(initial_vertex='000')
['000', '001', '010', '101', '110', '111', '011', '100']
(continues on next page)
EXAMPLES:
A Lex DOWN is obviously an ordering of the vertices:
sage: g = graphs.CompleteGraph(6)
sage: len(g.lex_DOWN()) == g.order()
True
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4, 5),
˓→ (5, 6)])
sage: g.lex_DOWN()
[1, 2, 3, 4, 6, 5]
sage: G = digraphs.DeBruijn(2,3)
sage: G.lex_BFS(initial_vertex='000')
['000', '001', '100', '010', '011', '110', '101', '111']
sage: G.lex_DFS(initial_vertex='000')
['000', '001', '100', '010', '101', '110', '011', '111']
sage: G.lex_UP(initial_vertex='000')
['000', '001', '010', '101', '110', '111', '011', '100']
sage: G.lex_DOWN(initial_vertex='000')
['000', '001', '100', '011', '010', '110', '111', '101']
EXAMPLES:
A Lex UP is obviously an ordering of the vertices:
sage: g = graphs.CompleteGraph(6)
sage: len(g.lex_UP()) == g.order()
True
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4, 5),
˓→ (5, 6)])
sage: g.lex_UP()
[1, 2, 4, 5, 6, 3]
sage: G = digraphs.DeBruijn(2,3)
sage: G.lex_BFS(initial_vertex='000')
['000', '001', '100', '010', '011', '110', '101', '111']
sage: G.lex_DFS(initial_vertex='000')
['000', '001', '100', '010', '101', '110', '011', '111']
sage: G.lex_UP(initial_vertex='000')
['000', '001', '010', '101', '110', '111', '011', '100']
sage: G.lex_DOWN(initial_vertex='000')
['000', '001', '100', '011', '010', '110', '111', '101']
lexicographic_product(other)
Return the lexicographic product of self and other.
The lexicographic product of 𝐺 and 𝐻 is the graph 𝐿 with vertex set 𝑉 (𝐿) = 𝑉 (𝐺) × 𝑉 (𝐻), and
((𝑢, 𝑣), (𝑤, 𝑥)) is an edge iff :
• (𝑢, 𝑤) is an edge of 𝐺, or
• 𝑢 = 𝑤 and (𝑣, 𝑥) is an edge of 𝐻.
EXAMPLES:
sage: Z = graphs.CompleteGraph(2)
sage: C = graphs.CycleGraph(5)
sage: L = C.lexicographic_product(Z); L
Graph on 10 vertices
sage: L.plot() # long time
Graphics object consisting of 36 graphics primitives
sage: D = graphs.DodecahedralGraph()
sage: P = graphs.PetersenGraph()
sage: L = D.lexicographic_product(P); L
Graph on 200 vertices
sage: L.plot() # long time
Graphics object consisting of 3501 graphics primitives
line_graph(g, labels=True)
Return the line graph of the (di)graph g.
INPUT:
• labels – boolean (default: True); whether edge labels should be taken in consideration. If
labels=True, the vertices of the line graph will be triples (u,v,label), and pairs of vertices other-
wise.
The line graph of an undirected graph G is an undirected graph H such that the vertices of H are the edges
of G and two vertices e and f of H are adjacent if e and f share a common vertex in G. In other words, an
edge in H represents a path of length 2 in G.
The line graph of a directed graph G is a directed graph H such that the vertices of H are the edges of G
and two vertices e and f of H are adjacent if e and f share a common vertex in G and the terminal vertex of
e is the initial vertex of f. In other words, an edge in H represents a (directed) path of length 2 in G.
Note: As a Graph object only accepts hashable objects as vertices (and as the vertices of the line graph
are the edges of the graph), this code will fail if edge labels are not hashable. You can also set the argument
labels=False to ignore labels.
See also:
EXAMPLES:
sage: g = graphs.CompleteGraph(4)
sage: h = g.line_graph()
sage: h.vertices(sort=True)
[(0, 1, None),
(0, 2, None),
(0, 3, None),
(1, 2, None),
(1, 3, None),
(2, 3, None)]
sage: h.am()
[0 1 1 1 1 0]
[1 0 1 1 0 1]
[1 1 0 0 1 1]
[1 1 0 0 1 1]
[1 0 1 1 0 1]
[0 1 1 1 1 0]
sage: h2 = g.line_graph(labels=False)
sage: h2.vertices(sort=True)
[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
sage: h2.am() == h.am()
True
sage: g = DiGraph([[1..4], lambda i,j: i < j])
sage: h = g.line_graph()
sage: h.vertices(sort=True)
[(1, 2, None),
(1, 3, None),
(1, 4, None),
(2, 3, None),
(2, 4, None),
(3, 4, None)]
sage: h.edges(sort=True)
[((1, 2, None), (2, 3, None), None),
((1, 2, None), (2, 4, None), None),
((1, 3, None), (3, 4, None), None),
((2, 3, None), (3, 4, None), None)]
INPUT:
• s – a vertex (default: None); forces the source of the path (the method then returns the longest path
starting at s). The argument is set to None by default, which means that no constraint is set upon the
first vertex in the path.
• t – a vertex (default: None); forces the destination of the path (the method then returns the longest
path ending at t). The argument is set to None by default, which means that no constraint is set upon
the last vertex in the path.
• use_edge_labels – boolean (default: False); whether to compute a path with maximum weight
where the weight of an edge is defined by its label (a label set to None or {} being considered as a
weight of 1), or to compute a path with the longest possible number of edges (i.e., edge weights are set
to 1)
• algorithm – string (default: "MILP"); the algorithm to use among "MILP" and "backtrack". Two
remarks on this respect:
– While the MILP formulation returns an exact answer, the backtrack algorithm is a randomized
heuristic.
– As the backtrack algorithm does not support edge weighting, setting use_edge_labels=True
will force the use of the MILP algorithm.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
Note: The length of a path is assumed to be the number of its edges, or the sum of their labels (when
use_edge_labels == True).
OUTPUT:
A subgraph of self corresponding to a (directed if self is directed) longest path. If use_edge_labels
== True, a pair weight, path is returned.
ALGORITHM:
Mixed Integer Linear Programming (this problem is known to be NP-Hard).
EXAMPLES:
Petersen’s graph being hypohamiltonian, it has a longest path of length 𝑛 − 2:
sage: g = graphs.PetersenGraph()
sage: lp = g.longest_path()
sage: lp.order() >= g.order() - 2
True
sage: g = graphs.PetersenGraph()
sage: p = g.longest_path(algorithm="backtrack").edges(sort=True, labels=False)
sage: len(p)
9
1 4
6 9
7 8
2 3
Let us compute the longest path on a random graph with random weights, and ensure the resulting graph is
indeed a path:
loop_edges(labels=True)
Return a list of all loops in the (di)graph
INPUT:
• labels – boolean (default: True); whether returned edges have labels ((u,v,l)) or not ((u,v))
EXAMPLES:
sage: G = Graph(loops=True); G
Looped graph on 0 vertices
sage: G.has_loops()
False
sage: G.allows_loops()
True
sage: G.add_edges([(0, 0), (1, 1), (2, 2), (3, 3), (2, 3)])
sage: G.loop_edges()
[(0, 0, None), (1, 1, None), (2, 2, None), (3, 3, None)]
sage: G.loop_edges(labels=False)
[(0, 0), (1, 1), (2, 2), (3, 3)]
sage: G.allows_loops()
True
sage: G.has_loops()
True
sage: G.allow_loops(False)
sage: G.has_loops()
False
sage: G.loop_edges()
[]
sage: G.edges(sort=True)
[(2, 3, None)]
sage: D = DiGraph(loops=True); D
Looped digraph on 0 vertices
sage: D.has_loops()
False
sage: D.allows_loops()
True
sage: D.add_edge((0, 0))
sage: D.has_loops()
True
sage: D.loops()
[(0, 0, None)]
sage: D.allow_loops(False); D
(continues on next page)
sage: G = graphs.PetersenGraph()
sage: G.loops()
[]
loop_vertices()
Return a list of vertices with loops
EXAMPLES:
loops(labels=True)
Return a list of all loops in the (di)graph
INPUT:
• labels – boolean (default: True); whether returned edges have labels ((u,v,l)) or not ((u,v))
EXAMPLES:
sage: G = Graph(loops=True); G
Looped graph on 0 vertices
sage: G.has_loops()
False
sage: G.allows_loops()
True
sage: G.add_edges([(0, 0), (1, 1), (2, 2), (3, 3), (2, 3)])
sage: G.loop_edges()
[(0, 0, None), (1, 1, None), (2, 2, None), (3, 3, None)]
sage: G.loop_edges(labels=False)
[(0, 0), (1, 1), (2, 2), (3, 3)]
sage: G.allows_loops()
True
(continues on next page)
sage: D = DiGraph(loops=True); D
Looped digraph on 0 vertices
sage: D.has_loops()
False
sage: D.allows_loops()
True
sage: D.add_edge((0, 0))
sage: D.has_loops()
True
sage: D.loops()
[(0, 0, None)]
sage: D.allow_loops(False); D
Digraph on 1 vertex
sage: D.has_loops()
False
sage: D.edges(sort=True)
[]
sage: G = graphs.PetersenGraph()
sage: G.loops()
[]
sage: g = graphs.CompleteBipartiteGraph(5,6)
sage: [ value, edges, [ setA, setB ]] = g.max_cut(vertices=True)
sage: value == 5*6
True
sage: bsetA, bsetB = map(list,g.bipartite_sets())
sage: (bsetA == setA and bsetB == setB ) or ((bsetA == setB and bsetB == setA ))
True
sage: g=graphs.PetersenGraph()
sage: g.max_cut()
12
merge_vertices(vertices)
Merge vertices.
This function replaces a set 𝑆 of vertices by a single vertex 𝑣𝑛𝑒𝑤 , such that the edge 𝑢𝑣𝑛𝑒𝑤 exists if and
only if ∃𝑣 ′ ∈ 𝑆 : (𝑢, 𝑣 ′ ) ∈ 𝐺.
The new vertex is named after the first vertex in the list given in argument. If this first name is 𝑁 𝑜𝑛𝑒, a
new vertex is created.
In the case of multigraphs, the multiplicity is preserved.
INPUT:
• vertices – the list of vertices to be merged
Note: If u and v are distinct vertices in vertices, any edges between u and v will be lost.
EXAMPLES:
sage: g = graphs.CycleGraph(3)
sage: g.merge_vertices([0, 1])
sage: g.edges(sort=True)
(continues on next page)
sage: P = graphs.PetersenGraph()
sage: P.merge_vertices([5, 7])
sage: P.vertices(sort=True)
[0, 1, 2, 3, 4, 5, 6, 8, 9]
sage: g = graphs.CycleGraph(5)
sage: g.vertices(sort=True)
[0, 1, 2, 3, 4]
sage: g.merge_vertices([None, 1, 3])
sage: g.edges(sort=True, labels=False)
[(0, 4), (0, 5), (2, 5), (4, 5)]
With a Multigraph
sage: g = graphs.CycleGraph(3)
sage: g.allow_multiple_edges(True)
sage: g.merge_vertices([0, 1])
sage: g.edges(sort=True, labels=False)
[(0, 2), (0, 2)]
current method. See the documentation of the corresponding functions for details on what sort of
sanity checks will be performed.
• weight_function – function (default: None); a function that takes as input an edge (u, v, l) and
outputs its weight. If not None, by_weight is automatically set to True. If None and by_weight is
True, we use the edge label l , if l is not None, else 1 as a weight. The weight_function can be
used to transform the label into a weight (note that, if the weight returned is not convertible to a float,
an error is raised)
• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise all
edges have weight 1
• check_weight – boolean (default: True); whether to check that the weight_function outputs a
number for each edge.
OUTPUT:
The edges of a minimum spanning tree of G, if one exists, otherwise returns the empty list.
See also:
• sage.graphs.spanning_tree.kruskal()
• sage.graphs.spanning_tree.filter_kruskal()
• sage.graphs.spanning_tree.boruvka()
• sage.graphs.base.boost_graph.min_spanning_tree()
EXAMPLES:
Kruskal’s algorithm:
sage: g = graphs.CompleteGraph(5)
sage: len(g.min_spanning_tree())
4
sage: weight = lambda e: 1 / ((e[0] + 1) * (e[1] + 1))
sage: sorted(g.min_spanning_tree(weight_function=weight))
[(0, 4, None), (1, 4, None), (2, 4, None), (3, 4, None)]
sage: sorted(g.min_spanning_tree(weight_function=weight, algorithm='Kruskal_
˓→Boost'))
Boruvka’s algorithm:
sage: sorted(g.min_spanning_tree(algorithm='Boruvka'))
[(0, 1, None), (0, 4, None), (0, 5, None), (1, 2, None), (1, 6, None), (2, 3,␣
˓→None), (2, 7, None), (3, 8, None), (4, 9, None)]
Prim’s algorithm:
sage: g = graphs.CompleteGraph(5)
sage: sorted(g.min_spanning_tree(algorithm='Prim_edge', starting_vertex=2,␣
˓→weight_function=weight))
NetworkX algorithm:
sage: sorted(g.min_spanning_tree(algorithm='NetworkX'))
[(0, 1, None), (0, 2, None), (0, 3, None), (0, 4, None)]
If the graph is not weighted, edge labels are not considered, even if they are numbers:
In order to use weights, we need either to set variable weighted to True, or to specify a weight function
or set by_weight to True:
sage: g.weighted(True)
sage: sorted(g.min_spanning_tree())
[(1, 2, 1), (2, 3, 1)]
sage: g.weighted(False)
sage: sorted(g.min_spanning_tree())
[(1, 2, 1), (1, 3, 2)]
sage: sorted(g.min_spanning_tree(by_weight=True))
[(1, 2, 1), (2, 3, 1)]
sage: sorted(g.min_spanning_tree(weight_function=lambda e: e[2]))
[(1, 2, 1), (2, 3, 1)]
sage: g = Graph([(1, 2, 3), (2, 3, 5), (3, 4, 8), (4, 1, 13), (1, 3, 250), (5,␣
˓→6, 9), (6, 7, 17), (7, 5, 20)])
sage: sorted(g.minimum_cycle_basis(by_weight=True))
[[1, 2, 3], [1, 2, 3, 4], [5, 6, 7]]
sage: sorted(g.minimum_cycle_basis(by_weight=False))
[[1, 2, 3], [1, 3, 4], [5, 6, 7]]
sage: sorted(g.minimum_cycle_basis(by_weight=True, algorithm='NetworkX'))
[[1, 2, 3], [1, 2, 3, 4], [5, 6, 7]]
sage: g.minimum_cycle_basis(by_weight=False, algorithm='NetworkX')
[[1, 2, 3], [1, 3, 4], [5, 6, 7]]
sage: g = Graph([(1, 2), (2, 3), (3, 4), (4, 5), (5, 1), (5, 3)])
sage: sorted(g.minimum_cycle_basis(by_weight=False))
[[1, 2, 3, 5], [3, 4, 5]]
sage: sorted(g.minimum_cycle_basis(by_weight=False, algorithm='NetworkX'))
[[1, 2, 3, 5], [3, 4, 5]]
See also:
• cycle_basis()
• Wikipedia article Cycle_basis
sage: g = graphs.PetersenGraph()
sage: matching = [(u,v) for u,v,_ in g.matching()]
sage: h = g.multicommodity_flow(matching)
sage: len(h)
5
We could also have considered g as symmetric and computed the multicommodity flow in this version
instead. In this case, however edges can be used in both directions at the same time:
sage: h = DiGraph(g).multicommodity_flow(matching)
sage: len(h)
5
Such a cut is said to be minimum when its cardinality (or weight) is minimum.
INPUT:
• vertices – iterable; the set of vertices
• value_only – boolean (default: False); whether to return only the size of the minimum multiway
cut, or to return the list of edges of the multiway cut
• use_edge_labels – boolean (default: False); whether to compute a weighted minimum multiway
cut where the weight of an edge is defined by its label (if an edge has no label, 1 is assumed), or to
compute a cut of minimum cardinality (i.e., edge weights are set to 1)
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
EXAMPLES:
Of course, a multiway cut between two vertices correspond to a minimum edge cut:
sage: g = graphs.PetersenGraph()
sage: g.edge_cut(0,3) == g.multiway_cut([0,3], value_only = True)
True
As Petersen’s graph is 3-regular, a minimum multiway cut between three vertices contains at most 2 × 3
edges (which could correspond to the neighborhood of 2 vertices):
In this case, though, the vertices are an independent set. If we pick instead vertices 0, 9, and 7, we can save
4 edges in the multiway cut:
This example, though, does not work in the directed case anymore, as it is not possible in Petersen’s graph
to mutualise edges:
sage: g = DiGraph(g)
sage: g.multiway_cut([0,7,9], value_only = True) == 3*3
True
Of course, a multiway cut between the whole vertex set contains all the edges of the graph:
sage: C = g.multiway_cut(g.vertices(sort=False))
sage: set(C) == set(g.edges(sort=False))
True
name(new=None)
Return or set the graph’s name.
INPUT:
• new – string (default: None); by default (new == None), the method returns the name of the graph.
When name is set, the string representation of that object becomes the new name of the (di)graph (new
== '' removes any name).
EXAMPLES:
sage: d = {0: [1,4,5], 1: [2,6], 2: [3,7], 3: [4,8], 4: [9], 5: [7, 8], 6: [8,
˓→9], 7: [9]}
sage: G = Graph(d); G
Graph on 10 vertices
sage: G.name("Petersen Graph"); G
Petersen Graph: Graph on 10 vertices
sage: G.name(new=""); G
Graph on 10 vertices
sage: G.name()
''
sage: G.name(42); G
42: Graph on 10 vertices
sage: G.name()
'42'
neighbor_iterator(vertex, closed=False)
Return an iterator over neighbors of vertex.
When closed is set to True, the returned iterator also contains vertex.
INPUT:
• vertex – a vertex of self
• closed – a boolean (default: False); whether to return the closed neighborhood of vertex, i.e.,
including vertex, or the open neighborhood in which vertex is included only if there is a loop on
that vertex.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: for i in G.neighbor_iterator(0):
....: print(i)
1
4
5
sage: D = G.to_directed()
sage: for i in D.neighbor_iterator(0):
....: print(i)
1
4
5
sage: g = graphs.CubeGraph(3)
sage: sorted(g.neighbor_iterator('010', closed=True))
['000', '010', '011', '110']
neighbors(vertex, closed=False)
Return a list of neighbors (in and out if directed) of vertex.
G[vertex] also works. When closed is set to True, the returned iterator also contains vertex.
INPUT:
• vertex – a vertex of self
• closed – a boolean (default: False); whether to return the closed neighborhood of vertex, i.e.,
including vertex, or the open neighborhood in which vertex is included only if there is a loop on
that vertex.
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: sorted(P.neighbors(3))
[2, 4, 8]
sage: sorted(P[4])
[0, 3, 9]
sage: sorted(P.neighbors(3, closed=True))
[2, 3, 4, 8]
networkx_graph(weight_function=None)
Return a new NetworkX graph from the Sage graph.
INPUT:
• weight_function – function (default: None); a function that takes as input an edge (u, v, l) and
outputs its weight.
EXAMPLES:
sage: G = graphs.TetrahedralGraph()
sage: N = G.networkx_graph()
sage: type(N)
<class 'networkx.classes.graph.Graph'>
sage: H = G2.networkx_graph(weight_function=weight_fn)
(continues on next page)
A nowhere zero flow on a graph 𝐺 = (𝑉, 𝐸) is a flow (𝐷, 𝑓 ) such that 𝑓 (𝑒) ̸= 0 for every 𝑒 ∈ 𝐸.
For a positive integer 𝑘, a 𝑘-flow on a graph 𝐺 = (𝑉, 𝐸) is a flow (𝐷, 𝑓 ) such that 𝑓 : 𝐸 → 𝑍 and
−(𝑘 − 1) ≤ 𝑓 (𝑒) ≤ 𝑘 − 1 for every 𝑒 ∈ 𝐸. A 𝑘-flow is positive if 𝑓 (𝑒) > 0 for every 𝑒 ∈ 𝐸. A 𝑘-flow
which is nowhere zero is called a 𝑘-nowhere zero flow (or 𝑘-NZF).
The following are equivalent.
• 𝐺 admits a positive 𝑘-flow.
• 𝐺 admits a 𝑘-NZF.
• Every orientation of 𝐺 admits a 𝑘-NZF.
Furthermore, a (di)graph admits a 𝑘-NZF if and only if it is bridgeless and every bridgeless graph admits
a 6-NZF [Sey1981]. See the Wikipedia article Nowhere-zero_flow for more details.
ALGORITHM:
If self is not directed, we search for a 𝑘-NZF on any orientation of self and then build a positive 𝑘-NZF
by reverting edges with negative flow.
INPUT:
• k – integer (default: 6); when set to a positive integer ≥ 2, search for a 𝑘-nowhere zero flow
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
OUTPUT:
A digraph with flow values stored as edge labels if a 𝑘-nowhere zero flow is found. If self is undirected,
the edges of this digraph indicate the selected orientation. If no feasible solution is found, an error is raised.
EXAMPLES:
The Petersen graph admits a (positive) 5-nowhere zero flow, but no 4-nowhere zero flow:
sage: g = graphs.PetersenGraph()
sage: h = g.nowhere_zero_flow(k=5)
sage: sorted(set(h.edge_labels()))
[1, 2, 3, 4]
sage: h = g.nowhere_zero_flow(k=3)
(continues on next page)
sage: g = digraphs.DeBruijn(2, 3)
sage: h = g.nowhere_zero_flow(k=2)
sage: sorted(set(h.edge_labels()))
[-1, 1]
num_edges()
Return the number of edges.
Note that num_edges() also returns the number of edges in 𝐺.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.size()
15
num_faces(embedding=None)
Return the number of faces of an embedded graph.
If no embedding is provided or stored as self._embedding, this method uses Euler’s formula (see the
Wikipedia article Euler_characteristic) to determine the number of faces if the graph is planar. If the graph
is not planar, an error is raised.
If an embedding is provided or stored as self._embedding, this method calls method faces() to get the
list of faces induced by the embedding in each connected component of the graph. Then it returns the sum
of size of these lists minus the number of connected components plus one to ensure that the external face
is counted only once.
INPUT:
• embedding – dictionary (default: None); a combinatorial embedding dictionary. Format: {v1:
[v2,v3], v2: [v1], v3: [v1]} (clockwise ordering of neighbors at each vertex). If set to
None (default) the method will use the embedding stored as self._embedding. If none is stored, the
method will compute the set of faces from the embedding returned by is_planar() (if the graph is,
of course, planar).
EXAMPLES:
sage: T = graphs.TetrahedralGraph()
sage: T.num_faces()
4
sage: (T + T).num_faces()
7
sage: (T + T + T).num_faces()
10
sage: T = graphs.RandomTree(10)
sage: T.num_faces()
1
sage: (T + T).num_faces()
1
num_verts()
Return the number of vertices.
Note that len(G) and num_verts() also return the number of vertices in 𝐺.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.order()
10
sage: G = graphs.TetrahedralGraph()
sage: len(G)
4
number_of_loops()
Return the number of edges that are loops
EXAMPLES:
odd_girth(algorithm='bfs', certificate=False)
Return the odd girth of the graph.
The odd girth is the length of the shortest cycle of odd length in the graph (directed cycle if the graph is
directed). Bipartite graphs have infinite odd girth.
INPUT:
• algorithm – string (default: "bfs"); the algorithm to use:
– "bfs" – BFS-based algorithm
– any algorithm accepted by charpoly() for computation from the characteristic polynomial (see
[Har1962] and [Big1993], p. 45)
• certificate – boolean (default: False); whether to return (g, c), where g is the odd girth and c
is a list of vertices of a (directed) cycle of length g in the graph, thus providing a certificate that the
odd girth is at most g, or None if g is infinite. So far, this parameter is accepted only when algorithm
= "bfs".
EXAMPLES:
The McGee graph has girth 7 and therefore its odd girth is 7 as well:
sage: G = graphs.McGeeGraph()
sage: G.girth()
7
sage: G.odd_girth()
7
Any complete (directed) graph on more than 2 vertices contains a (directed) triangle and has thus odd girth
3:
sage: G = graphs.CompleteGraph(5)
sage: G.odd_girth(certificate=True) # random
(3, [2, 1, 0])
sage: G = digraphs.Complete(5)
sage: G.odd_girth(certificate=True) # random
(3, [1, 2, 0])
Bipartite graphs have no odd cycle and consequently have infinite odd girth:
See also:
order()
Return the number of vertices.
Note that len(G) and num_verts() also return the number of vertices in 𝐺.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.order()
10
sage: G = graphs.TetrahedralGraph()
sage: len(G)
4
Note: Parameters alpha, by_weight and weight_function are common to all algorithms. Parameters
personalization and dangling are used only by algorithms NetworkX, Numpy and Scipy.
EXAMPLES:
sage: G = graphs.CycleGraph(4)
sage: G.pagerank(algorithm="Networkx")
{0: 0.25, 1: 0.25, 2: 0.25, 3: 0.25}
sage: G.pagerank(alpha=0.50, algorithm="igraph") # optional - python_igraph #␣
˓→abs tol 1e-9
See also:
planar_dual(embedding=None)
Return the planar dual of an embedded graph.
A combinatorial embedding of a graph is a clockwise ordering of the neighbors of each vertex. From this
information one can obtain the dual of a plane graph, which is what the method returns. The vertices of the
dual graph correspond to faces of the primal graph.
INPUT:
• embedding – dictionary (default: None); a combinatorial embedding dictionary. Format: {v1:
[v2,v3], v2: [v1], v3: [v1]} (clockwise ordering of neighbors at each vertex). If set to
None (default) the method will use the embedding stored as self._embedding. If none is stored, the
method will compute the set of faces from the embedding returned by is_planar() (if the graph is,
of course, planar).
EXAMPLES:
sage: C = graphs.CubeGraph(3)
sage: C.planar_dual()
Graph on 6 vertices
sage: graphs.IcosahedralGraph().planar_dual().is_isomorphic(graphs.
˓→DodecahedralGraph())
True
The planar dual of the planar dual is isomorphic to the graph itself:
sage: g = graphs.BuckyBall()
sage: g.planar_dual().planar_dual().is_isomorphic(g)
True
See also:
• faces()
• set_embedding()
• get_embedding()
• is_planar()
Todo: Implement the method for graphs that are not 3-vertex-connected, or at least have a faster 3-vertex-
connectivity test (trac ticket #24635).
plot(**options)
Return a Graphics object representing the (di)graph.
INPUT:
• pos – an optional positioning dictionary
• layout – string (default: None); specifies a kind of layout to use, takes precedence over pos
– 'circular' – plots the graph with vertices evenly distributed on a circle
– 'spring' – uses the traditional spring layout, using the graph’s current positions as initial posi-
tions
– 'tree' – the (di)graph must be a tree. One can specify the root of the tree using the keyword
tree_root, otherwise a root will be selected at random. Then the tree will be plotted in levels,
depending on minimum distance for the root.
• vertex_labels – boolean (default: True); whether to print vertex labels
• edge_labels – boolean (default: False); whether to print edge labels. If True, the result of str(l)
is printed on the edge for each label 𝑙. Labels equal to None are not printed (to set edge labels, see
set_edge_label()).
• edge_labels_background – the color of the edge labels background. The default is “white”. To
achieve a transparent background use “transparent”.
• vertex_size – size of vertices displayed
• vertex_shape – the shape to draw the vertices, for example "o" for circle or "s" for square. Whole
list is available at https://matplotlib.org/api/markers_api.html. (Not available for multiedge digraphs.)
• graph_border – boolean (default: False); whether to include a box around the graph
• vertex_colors – dictionary (default: None); optional dictionary to specify vertex colors: each key
is a color recognizable by matplotlib, and each corresponding entry is a list of vertices. If a vertex is
not listed, it looks invisible on the resulting plot (it doesn’t get drawn).
• edge_colors – dictionary (default: None); a dictionary specifying edge colors: each key is a color
recognized by matplotlib, and each entry is a list of edges.
• partition – a partition of the vertex set (default: None); if specified, plot will show each cell in a
different color. vertex_colors takes precedence.
• talk – boolean (default: False); if True, prints large vertices with white backgrounds so that labels
are legible on slides
• iterations – integer; how many iterations of the spring layout algorithm to go through, if applicable
• color_by_label – a boolean or dictionary or function (default: False); whether to color each edge
with a different color according to its label; the colors are chosen along a rainbow, unless they are speci-
fied by a function or dictionary mapping labels to colors; this option is incompatible with edge_color
and edge_colors.
• heights – dictionary (default: None); if specified, this is a dictionary from a set of floating point
heights to a set of vertices
• edge_style – keyword arguments passed into the edge-drawing routine. This currently only works
for directed graphs, since we pass off the undirected graph to networkx
• tree_root – a vertex (default: None); if specified, this vertex is used as the root for the
layout="tree" option. Otherwise, then one is chosen at random. Ignored unless layout='tree'.
• tree_orientation – string (default: "down"); one of “up” or “down”. If “up” (resp., “down”),
then the root of the tree will appear on the bottom (resp., top) and the tree will grow upwards (resp.
downwards). Ignored unless layout='tree'.
• save_pos – boolean (default: False); save position computed during plotting
Note:
• This method supports any parameter accepted by sage.plot.graphics.Graphics.show().
• See the documentation of the sage.graphs.graph_plot module for information and examples of
how to define parameters that will be applied to all graph plots.
• Default parameters for this method and a specific graph can also be set through the options mecha-
nism. For more information on this different way to set default parameters, see the help of the options
decorator.
• See also the sage.graphs.graph_latex module for ways to use LaTeX to produce an image of a
graph.
EXAMPLES:
sage: from sage.graphs.graph_plot import graphplot_options
sage: sorted(graphplot_options.items())
[...]
sage: C = graphs.CubeGraph(8)
sage: P = C.plot(vertex_labels=False, vertex_size=0, graph_border=True)
sage: P.show()
sage: G = graphs.HeawoodGraph()
sage: for u, v, l in G.edges(sort=False):
....: G.set_edge_label(u, v, '(' + str(u) + ',' + str(v) + ')')
sage: G.plot(edge_labels=True).show()
sage: D = DiGraph( { 0: [1, 10, 19], 1: [8, 2], 2: [3, 6], 3: [19, 4], 4: [17,␣
˓→5], 5: [6, 15], 6: [7], 7: [8, 14], 8: [9], 9: [10, 13], 10: [11], 11: [12,␣
˓→18], 12: [16, 13], 13: [14], 14: [15], 15: [16], 16: [17], 17: [18], 18: [19],
sage: D = graphs.DodecahedralGraph()
sage: Pi = [[6,5,15,14,7], [16,13,8,2,4], [12,17,9,3,1], [0,19,18,10,11]]
sage: D.show(partition=Pi)
sage: G = graphs.PetersenGraph()
sage: G.allow_loops(True)
sage: G.add_edge(0, 0)
sage: G.show()
sage: pos = {0: [0.0, 1.5], 1: [-0.8, 0.3], 2: [-0.6, -0.8], 3: [0.6, -0.8], 4:␣
˓→[0.8, 0.3]}
sage: G = Graph()
sage: P = G.plot()
sage: P.axes()
False
sage: G = DiGraph()
sage: P = G.plot()
sage: P.axes()
False
sage: G = graphs.PetersenGraph()
sage: G.get_pos()
{0: (0.0..., 1.0...),
1: (-0.95..., 0.30...),
2: (-0.58..., -0.80...),
3: (0.58..., -0.80...),
4: (0.95..., 0.30...),
(continues on next page)
sage: T = list(graphs.trees(7))
sage: t = T[3]
sage: t.plot(heights={0: [0], 1: [4, 5, 1], 2: [2], 3: [3, 6]})
Graphics object consisting of 14 graphics primitives
sage: T = list(graphs.trees(7))
sage: t = T[3]
sage: t.plot(heights={0: [0], 1: [4, 5, 1], 2: [2], 3: [3, 6]})
Graphics object consisting of 14 graphics primitives
sage: t.set_edge_label(0, 1, -7)
sage: t.set_edge_label(0, 5, 3)
sage: t.set_edge_label(0, 5, 99)
sage: t.set_edge_label(1, 2, 1000)
sage: t.set_edge_label(3, 2, 'spam')
sage: t.set_edge_label(2, 6, 3/2)
sage: t.set_edge_label(0, 4, 66)
sage: t.plot(heights={0: [0], 1: [4, 5, 1], 2: [2], 3: [3, 6]}, edge_
˓→labels=True)
sage: T = list(graphs.trees(7))
sage: t = T[3]
sage: t.plot(layout='tree')
Graphics object consisting of 14 graphics primitives
sage: t = DiGraph('JCC???@A??GO??CO??GO??')
sage: t.plot(layout='tree', tree_root=0, tree_orientation="up")
Graphics object consisting of 22 graphics primitives
sage: D = DiGraph({0: [1, 2, 3], 2: [1, 4], 3: [0]})
sage: D.plot()
(continues on next page)
sage: D = DiGraph(multiedges=True,sparse=True)
sage: for i in range(5):
....: D.add_edge((i, i + 1, 'a'))
....: D.add_edge((i, i - 1, 'b'))
sage: D.plot(edge_labels=True, edge_colors=D._color_by_label())
Graphics object consisting of 34 graphics primitives
sage: D.plot(edge_labels=True, color_by_label={'a': 'blue', 'b': 'red'}, edge_
˓→style='dashed')
sage: S = SupersingularModule(389)
sage: H = S.hecke_matrix(2)
sage: D = DiGraph(H,sparse=True)
sage: P = D.plot()
sage: G=Graph({'a':['a','b','b','b','e'],'b':['c','d','e'],'c':['c','d','d','d
˓→'],'d':['e']}, sparse=True)
sage: G.show(pos={'a':[0,1],'b':[1,1],'c':[2,0],'d':[1,0],'e':[0,0]})
sage: G = graphs.CubeGraph(5)
sage: G.plot3d(iterations=500, edge_size=None, vertex_size=0.04) # long time
Graphics3d Object
sage: A5 = AlternatingGroup(5); A5
Alternating group of order 5!/2 as a permutation group
sage: G = A5.cayley_graph()
sage: G.plot3d(vertex_size=0.03, edge_size=0.01, vertex_colors={(1,1,1):␣
˓→list(G)}, bgcolor=(0,0,0), color_by_label=True, iterations=200) # long time
Graphics3d Object
sage: D = graphs.DodecahedralGraph()
sage: P3D = D.plot3d(engine='tachyon')
sage: P3D.show() # long time
sage: G = graphs.PetersenGraph()
sage: G.plot3d(engine='tachyon', vertex_colors={(0,0,1): list(G)}).show() #␣
˓→long time
sage: C = graphs.CubeGraph(4)
sage: C.plot3d(engine='tachyon', edge_colors={(0,1,0): C.edges(sort=False)},␣
˓→vertex_colors={(1,1,1): list(C)}, bgcolor=(0,0,0)).show() # long time
sage: K = graphs.CompleteGraph(3)
sage: K.plot3d(engine='tachyon', edge_colors={(1,0,0): [(0,1,None)], (0,1,0):␣
˓→[(0,2,None)], (0,0,1): [(1,2,None)]}).show() # long time
sage: D = DiGraph({0: [1, 10, 19], 1: [8, 2], 2: [3, 6], 3: [19, 4],
....: 4: [17, 5], 5: [6, 15], 6: [7], 7: [8, 14],
....: 8: [9], 9: [10, 13], 10: [11], 11: [12, 18],
....: 12: [16, 13], 13: [14], 14: [15], 15: [16], 16: [17],
(continues on next page)
sage: P = graphs.PetersenGraph().to_directed()
sage: from sage.plot.colors import rainbow
sage: R = rainbow(P.size(), 'rgbtuple')
sage: edge_colors = {R[i]: [e] for i, e in enumerate(P.edge_iterator())}
sage: P.plot3d(engine='tachyon', edge_colors=edge_colors).show() # long time
sage: G=Graph({'a':['a','b','b','b','e'],'b':['c','d','e'],'c':['c','d','d','d
˓→'],'d':['e']},sparse=True)
sage: G.show3d()
Traceback (most recent call last):
...
NotImplementedError: 3D plotting of multiple edges or loops not implemented
sage: G = graphs.WheelGraph(7)
sage: G.plot3d(partition=[[0], [1, 2, 3, 4, 5, 6]])
Graphics3d Object
See also:
• plot()
• graphviz_string()
random_edge(**kwds)
Return a random edge of self.
INPUT:
• **kwds – arguments to be passed down to the edge_iterator() method
EXAMPLES:
The returned value is an edge of self:
sage: g = graphs.PetersenGraph()
sage: u,v = g.random_edge(labels=False)
sage: g.has_edge(u,v)
True
As the edges() method would, this function returns by default a triple (u, v, l) of values, in which l
is the label of edge (u, v):
random_edge_iterator(*args, **kwds)
Return an iterator over random edges of self.
The returned iterator enables to amortize the cost of accessing random edges, as can be done with multiple
calls to method random_edge().
INPUT:
• *args and **kwds – arguments to be passed down to the edge_iterator() method.
EXAMPLES:
The returned value is an iterator over the edges of self:
sage: g = graphs.PetersenGraph()
sage: it = g.random_edge_iterator()
sage: [g.has_edge(next(it)) for _ in range(5)]
[True, True, True, True, True]
As the edges() method would, this function returns by default a triple (u, v, l) of values, in which l
is the label of edge (u,v):
random_subgraph(p, inplace=False)
Return a random subgraph containing each vertex with probability p.
INPUT:
• p – the probability of choosing a vertex
• inplace – boolean (default: False); using inplace=True will simply delete the extra vertices and
edges from the current graph. This will modify the graph.
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.random_subgraph(.25)
Subgraph of (Petersen graph): Graph on ... vert...
random_vertex(**kwds)
Return a random vertex of self.
INPUT:
• **kwds – arguments to be passed down to the vertex_iterator() method
EXAMPLES:
The returned value is a vertex of self:
sage: g = graphs.PetersenGraph()
sage: v = g.random_vertex()
sage: v in g
True
random_vertex_iterator(*args, **kwds)
Return an iterator over random vertices of self.
The returned iterator enables to amortize the cost of accessing random vertices, as can be done with multiple
calls to method random_vertex().
INPUT:
• *args and **kwds – arguments to be passed down to the vertex_iterator() method
EXAMPLES:
The returned value is an iterator over the vertices of self:
sage: g = graphs.PetersenGraph()
sage: it = g.random_vertex_iterator()
sage: [next(it) in g for _ in range(5)]
[True, True, True, True, True]
sage: G = graphs.PathGraph(3)
sage: G.am()
[0 1 0]
[1 0 1]
[0 1 0]
Relabeling using a dictionary. Note that the dictionary does not define the new label of vertex 0:
This is because the method automatically “extends” the relabeling to the missing vertices (whose label
will not change). Checking that all vertices have an image can require some time, and this feature can be
disabled (at your own risk):
sage: G = graphs.PathGraph(3)
sage: from sage.groups.perm_gps.permgroup_named import SymmetricGroup ␣
˓→ # optional - sage.groups
sage: S = SymmetricGroup(3) ␣
˓→ # optional - sage.groups
sage: gamma = S('(1,2)') ␣
˓→ # optional - sage.groups
sage: G.relabel(gamma, inplace=False).am() ␣
˓→ # optional - sage.groups
[0 0 1]
[0 0 1]
[1 1 0]
sage: G.edges(sort=True)
[(0, 1, None), (1, 2, None)]
sage: H = G.relabel(lambda i: i+10, inplace=False)
sage: H.vertices(sort=True)
[10, 11, 12]
sage: H.edges(sort=True)
[(10, 11, None), (11, 12, None)]
sage: G.edges(sort=True)
[(0, 1, None), (1, 2, None)]
sage: G.relabel(lambda i: 0, inplace=False)
Traceback (most recent call last):
...
NotImplementedError: Non injective relabeling
sage: G.edges(sort=True)
[(0, 1, None), (1, 2, None)]
sage: G.relabel(lambda i: 0, check_input = False)
sage: G.edges(sort=True)
[]
sage: G = graphs.CubeGraph(3)
sage: G.relabel(range(8), return_map=True)
{'000': 0,
'001': 1,
'010': 2,
'011': 3,
'100': 4,
'101': 5,
'110': 6,
'111': 7}
When no permutation is given, the relabeling is done to integers from 0 to N-1 but in an arbitrary order:
sage: G = graphs.CubeGraph(3)
sage: G.vertices(sort=True)
['000', '001', '010', '011', '100', '101', '110', '111']
sage: G.relabel()
sage: G.vertices(sort=True)
[0, 1, 2, 3, 4, 5, 6, 7]
sage: G = graphs.PathGraph(3)
sage: G.relabel(lambda i: i+10, return_map=True)
{0: 10, 1: 11, 2: 12}
remove_loops(vertices=None)
Remove loops on vertices in vertices.
If vertices is None, removes all loops.
EXAMPLES:
remove_multiple_edges()
Remove all multiple edges, retaining one edge for each.
See also:
See also allow_multiple_edges()
EXAMPLES:
sage: G.remove_multiple_edges()
sage: G.edges(sort=True, labels=False)
[(0, 1), (1, 2)]
set_edge_label(u, v, l)
Set the edge label of a given edge.
Note: There can be only one edge from u to v for this to make sense. Otherwise, an error is raised.
INPUT:
• u, v – the vertices (and direction if digraph) of the edge
• l – the new label
EXAMPLES:
sage: G = graphs.HeawoodGraph()
sage: for u,v,l in G.edges(sort=False):
....: G.set_edge_label(u, v, '(' + str(u) + ',' + str(v) + ')')
sage: G.edges(sort=True)
[(0, 1, '(0,1)'),
(0, 5, '(0,5)'),
(0, 13, '(0,13)'),
...
(11, 12, '(11,12)'),
(12, 13, '(12,13)')]
set_embedding(embedding)
Set a combinatorial embedding dictionary to _embedding attribute.
The dictionary embedding represents a combinatorial embedding of self and is organized as a mapping
from vertex labels to list of vertex neighbors in clockwise order.
Parameter embedding is error-checked for validity.
Warning: Combinatorial embeddings are defined for simple graphs only (i.e., without loops or mul-
tiple edges). Therefore, an error is raised when this method is used for a graph with loops or multiple
edges.
INPUT:
• embedding – dictionary representing a combinatorial embedding of self. Format: “{v1: [v2,v3],
v2: [v1], v3: [v1]}” (clockwise ordering of neighbors at each vertex).
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.set_embedding({0: [1, 5, 4], 1: [0, 2, 6], 2: [1, 3, 7], 3: [8, 2, 4],␣
˓→4: [0, 9, 3], 5: [0, 8, 7], 6: [8, 1, 9], 7: [9, 2, 5], 8: [3, 5, 6], 9: [4,␣
˓→6, 7]})
sage: G.set_embedding({'s': [1, 5, 4], 1: [0, 2, 6], 2: [1, 3, 7], 3: [8, 2, 4],
˓→ 4: [0, 9, 3], 5: [0, 8, 7], 6: [8, 1, 9], 7: [9, 2, 5], 8: [3, (continues
5, 6], on9:next[4,␣
page)
˓→6, 7]})
set_latex_options(**kwds)
Set multiple options for rendering a graph with LaTeX.
INPUT:
• kwds – any number of option/value pairs to set many graph latex options at once (a variable number,
in any order). Existing values are overwritten, new values are added. Existing values can be cleared
by setting the value to None. Possible options are documented at sage.graphs.graph_latex.
GraphLatex.set_option().
This method is a convenience for setting the options of a graph directly on an instance of the graph. For a
full explanation of how to use LaTeX to render graphs, see the introduction to the graph_latex module.
EXAMPLES:
sage: g = graphs.PetersenGraph()
sage: g.set_latex_options(tkz_style='Welsh')
sage: opts = g.latex_options()
sage: opts.get_option('tkz_style')
'Welsh'
set_pos(pos, dim=2)
Set the position dictionary.
The position dictionary specifies the coordinates of each vertex.
INPUT:
• pos – a position dictionary for the vertices of the (di)graph
• dim – integer (default: 2); the number of coordinates per vertex
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.get_pos()
{0: (..., ...),
...
9: (..., ...)}
The method get_pos() check the position dictionary so that invalid positioning are ignored:
sage: G.set_pos(dict(enumerate('abcdefghi')))
sage: P = G.plot() # positions are ignored
sage: G.get_pos() is None
True
set_vertex(vertex, object)
Associate an arbitrary object with a vertex.
INPUT:
• vertex – which vertex
• object – object to associate to vertex
EXAMPLES:
sage: T = graphs.TetrahedralGraph()
sage: T.vertices(sort=True)
[0, 1, 2, 3]
sage: T.set_vertex(1, graphs.FlowerSnark())
sage: T.get_vertex(1)
Flower Snark: Graph on 20 vertices
sage: T.set_vertex(4, 'foo')
Traceback (most recent call last):
...
ValueError: vertex (4) not in the graph
set_vertices(vertex_dict)
Associate arbitrary objects with each vertex, via an association dictionary.
INPUT:
• vertex_dict – the association dictionary
EXAMPLES:
sage: d[2]
Moebius-Kantor Graph: Graph on 16 vertices
sage: T = graphs.TetrahedralGraph()
sage: T.vertices(sort=True)
[0, 1, 2, 3]
sage: T.set_vertices(d)
sage: T.get_vertex(1)
Flower Snark: Graph on 20 vertices
Note: If there are negative weights and algorithm is None, the result is not reliable. This
occurs because, for performance reasons, we cannot check whether there are edges with neg-
ative weights before running the algorithm. If there are, the user should explicitly input
algorithm='Bellman-Ford_Boost'.
• weight_function – function (default: None); a function that takes as input an edge (u, v, l) and
outputs its weight. If not None, by_weight is automatically set to True. If None and by_weight is
True, we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs a num-
ber for each edge
EXAMPLES:
sage: D = graphs.DodecahedralGraph()
sage: D.shortest_path(4, 9)
[4, 17, 16, 12, 13, 9]
sage: D.shortest_path(4, 9, algorithm='BFS')
[4, 3, 2, 1, 8, 9]
sage: D.shortest_path(4, 8, algorithm='Dijkstra_NetworkX')
[4, 3, 2, 1, 8]
sage: D.shortest_path(4, 8, algorithm='Dijkstra_Bid_NetworkX')
[4, 3, 2, 1, 8]
sage: D.shortest_path(4, 9, algorithm='Dijkstra_Bid')
[4, 3, 19, 0, 10, 9]
sage: D.shortest_path(5, 5)
[5]
sage: D.delete_edges(D.edges_incident(13))
sage: D.shortest_path(13, 4)
[]
sage: G = Graph({0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2}}, sparse␣
˓→= True)
Note: There is a Cython version of this method that is usually much faster for large graphs, as most of the
time is actually spent building the final double dictionary. Everything on the subject is to be found in the
distances_all_pairs module.
EXAMPLES:
Some standard examples (see shortest_paths() for more examples on how to use the input variables):
sage: G = Graph( { 0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2} },␣
˓→sparse=True)
˓→{0: 4, 1: 0, 2: 3, 3: 4, 4: None}}
sage: pred[0]
{0: None, 1: 0, 2: 1, 3: 2, 4: 0}
sage: G = Graph( { 0: {1: {'weight':1}}, 1: {2: {'weight':1}}, 2: {3: {'weight
˓→':1}}, 3: {4: {'weight':2}}, 4: {0: {'weight':2}} }, sparse=True)
sage: dist
{0: {0: 0, 1: 1, 2: 2, 3: 3, 4: 2}, 1: {0: 1, 1: 0, 2: 1, 3: 2, 4: 3}, 2: {0: 2,
˓→ 1: 1, 2: 0, 3: 1, 4: 3}, 3: {0: 3, 1: 2, 2: 1, 3: 0, 4: 2}, 4: {0: 2, 1: 3,␣
˓→2: 3, 3: 2, 4: 0}}
sage: pred
{0: {0: None, 1: 0, 2: 1, 3: 2, 4: 0}, 1: {0: 1, 1: None, 2: 1, 3: 2, 4: 0}, 2:
˓→{0: 1, 1: 2, 2: None, 3: 2, 4: 3}, 3: {0: 1, 1: 2, 2: 3, 3: None, 4: 3}, 4:
˓→{0: 4, 1: 0, 2: 3, 3: 4, 4: None}}
So for example the shortest weighted path from 0 to 3 is obtained as follows. The predecessor of 3 is
pred[0][3] == 2, the predecessor of 2 is pred[0][2] == 1, and the predecessor of 1 is pred[0][1]
== 0.
sage: G = Graph( { 0: {1:None}, 1: {2:None}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2} },␣
˓→sparse=True )
sage: G.shortest_path_all_pairs()
({0: {0: 0, 1: 1, 2: 2, 3: 2, 4: 1},
1: {0: 1, 1: 0, 2: 1, 3: 2, 4: 2},
2: {0: 2, 1: 1, 2: 0, 3: 1, 4: 2},
3: {0: 2, 1: 2, 2: 1, 3: 0, 4: 1},
4: {0: 1, 1: 2, 2: 2, 3: 1, 4: 0}},
{0: {0: None, 1: 0, 2: 1, 3: 4, 4: 0},
1: {0: 1, 1: None, 2: 1, 3: 2, 4: 0},
2: {0: 1, 1: 2, 2: None, 3: 2, 4: 3},
3: {0: 4, 1: 2, 2: 3, 3: None, 4: 3},
4: {0: 4, 1: 0, 2: 3, 3: 4, 4: None}})
sage: G.shortest_path_all_pairs(weight_function=lambda e:(e[2] if e[2] is not␣
˓→None else 1))
sage: g = graphs.Grid2dGraph(5,5)
(continues on next page)
sage: g = digraphs.RandomDirectedGNM(6,12)
sage: d1, _ = g.shortest_path_all_pairs(algorithm="BFS")
sage: d2, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Cython")
sage: d3, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Python")
sage: d4, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX")
sage: d5, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost")
sage: d6, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost")
sage: d7, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost")
sage: d8, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy")
sage: d1 == d2 == d3 == d4 == d5 == d6 == d7 == d8
True
Checking that weighted distances are equal regardless of the algorithm used:
sage: g = graphs.CompleteGraph(5)
sage: import random
sage: for v, w in g.edges(labels=False, sort=False):
....: g.add_edge(v, w, random.uniform(1, 10))
sage: d1, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Python")
sage: d2, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX")
sage: d3, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost")
sage: d4, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost")
sage: d5, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost")
sage: d6, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy")
sage: d1 == d2 == d3 == d4 == d5 == d6
True
Negative weights:
sage: g = DiGraph([(0,1,1),(1,2,2)])
sage: g.shortest_path_all_pairs(algorithm='BFS')
({0: {0: 0, 1: 1, 2: 2}, 1: {1: 0, 2: 1}, 2: {2: 0}},
{0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}})
sage: g.shortest_path_all_pairs(algorithm='Dijkstra_NetworkX')
({0: {0: 0, 1: 1, 2: 2}, 1: {1: 0, 2: 1}, 2: {2: 0}},
{0: {0: None, 1: 1, 2: 1}, 1: {1: None, 2: 2}, 2: {2: None}})
sage: g.shortest_path_all_pairs(algorithm='Dijkstra_Boost')
({0: {0: 0, 1: 1, 2: 2}, 1: {1: 0, 2: 1}, 2: {2: 0}},
{0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}})
sage: g.shortest_path_all_pairs(algorithm='Floyd-Warshall-Python')
({0: {0: 0, 1: 1, 2: 2}, 1: {1: 0, 2: 1}, 2: {2: 0}},
{0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}})
sage: g.shortest_path_all_pairs(algorithm='Floyd-Warshall-Cython')
({0: {0: 0, 1: 1, 2: 2}, 1: {1: 0, 2: 1}, 2: {2: 0}},
{0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}})
sage: g.shortest_path_all_pairs(algorithm='Floyd-Warshall_SciPy')
({0: {0: 0.0, 1: 1.0, 2: 2.0}, 1: {1: 0.0, 2: 1.0}, 2: {2: 0.0}},
{0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}})
In order to change the default behavior if the graph is disconnected, we can use default values with dictio-
naries:
sage: G = 2*graphs.PathGraph(2)
sage: d,_ = G.shortest_path_all_pairs()
sage: import itertools
sage: from sage.rings.infinity import Infinity
sage: for u,v in itertools.combinations(G.vertex_iterator(), 2):
....: print("dist({}, {}) = {}".format(u,v, d[u].get(v,+Infinity)))
dist(0, 1) = 1
dist(0, 2) = +Infinity
dist(0, 3) = +Infinity
dist(1, 2) = +Infinity
dist(1, 3) = +Infinity
dist(2, 3) = 1
• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise all
edges have weight 1
• algorithm – string (default: None); one of the following algorithms:
– 'BFS': performs a BFS from u. Does not work with edge weights.
– 'BFS_Bid': performs a BFS from u and from v. Does not work with edge weights.
– 'Dijkstra_NetworkX': the Dijkstra algorithm, implemented in NetworkX. Works only with
positive weights.
– 'Dijkstra_Bid_NetworkX': performs a Dijkstra visit from u and from v (NetworkX implemen-
tation). Works only with positive weights.
– 'Dijkstra_Bid': a Cython implementation that performs a Dijkstra visit from u and from v.
Works only with positive weights.
– 'Bellman-Ford_Boost': the Bellman-Ford algorithm, implemented in Boost. Works also with
negative weights, if there is no negative cycle.
– None (default): Sage chooses the best algorithm: 'BFS_Bid' if by_weight is False,
'Dijkstra_Bid' otherwise.
Note: If there are negative weights and algorithm is None, the result is not reliable. This
occurs because, for performance reasons, we cannot check whether there are edges with neg-
ative weights before running the algorithm. If there are, the user should explicitly input
algorithm='Bellman-Ford_Boost'.
• weight_function – function (default: None); a function that takes as input an edge (u, v, l) and
outputs its weight. If not None, by_weight is automatically set to True. If None and by_weight is
True, we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs a num-
ber for each edge
EXAMPLES:
Standard examples:
sage: D = graphs.DodecahedralGraph()
sage: D.shortest_path_length(4, 9)
5
sage: D.shortest_path_length(4, 9, algorithm='BFS')
5
sage: D.shortest_path_length(4, 9, algorithm='Dijkstra_NetworkX')
5
sage: D.shortest_path_length(4, 9, algorithm='Dijkstra_Bid_NetworkX')
5
sage: D.shortest_path_length(4, 9, algorithm='Dijkstra_Bid')
5
sage: D.shortest_path_length(4, 9, algorithm='Bellman-Ford_Boost')
5
sage: D.shortest_path_length(5, 5)
0
sage: D.delete_edges(D.edges_incident(13))
sage: D.shortest_path_length(13, 4)
+Infinity
(continues on next page)
3
sage: G.shortest_path_length(0, 3, by_weight=True, algorithm='Dijkstra_Bid_
˓→NetworkX')
sage: G = DiGraph({0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: -2}},␣
˓→sparse = True)
-1
-1000
sage: G.shortest_path_length(0, 2, by_weight=True)
2
– 'Dijkstra_NetworkX': the Dijkstra algorithm, implemented in NetworkX (works only with pos-
itive weights).
– 'Dijkstra_Boost': the Dijkstra algorithm, implemented in Boost (works only with positive
weights).
– 'Bellman-Ford_Boost': the Bellman-Ford algorithm, implemented in Boost (works also with
negative weights, if there is no negative cycle).
– None (default): Sage chooses the best algorithm: 'BFS' if by_weight is False,
'Dijkstra_Boost' if all weights are positive, 'Bellman-Ford_Boost' otherwise.
• weight_function – function (default: None); a function that takes as input an edge (u, v, l) and
outputs its weight. If not None, by_weight is automatically set to True. If None and by_weight is
True, we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs a num-
ber for each edge
EXAMPLES:
Unweighted case:
sage: D = graphs.DodecahedralGraph()
sage: D.shortest_path_lengths(0)
{0: 0, 1: 1, 2: 2, 3: 2, 4: 3, 5: 4, 6: 3, 7: 3, 8: 2, 9: 2, 10: 1, 11: 2, 12:␣
˓→3, 13: 3, 14: 4, 15: 5, 16: 4, 17: 3, 18: 2, 19: 1}
Weighted case:
sage: G = Graph( { 0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2} },␣
˓→sparse=True)
sage: D = DiGraph([(0,1,{'weight':1}),(1,2,{'weight':3}),(0,2,{'weight':5})])
sage: weight_function = lambda e:e[2]['weight']
sage: D.shortest_path_lengths(1, algorithm='Dijkstra_NetworkX', by_weight=False)
{1: 0, 2: 1}
sage: D.shortest_path_lengths(0, weight_function=weight_function)
{0: 0, 1: 1, 2: 4}
sage: D.shortest_path_lengths(1, weight_function=weight_function)
{1: 0, 2: 3}
Negative weights:
sage: D = DiGraph([(0,1,{'weight':-1}),(1,2,{'weight':3}),(0,2,{'weight':5})])
sage: D.shortest_path_lengths(0, weight_function=weight_function)
{0: 0, 1: -1, 2: 2}
Negative cycles:
sage: D = DiGraph([(0,1,{'weight':-5}),(1,2,{'weight':3}),(2,0,{'weight':1})])
sage: D.shortest_path_lengths(0, weight_function=weight_function)
Traceback (most recent call last):
(continues on next page)
˓→10], 11: [0, 10, 11], 12: [0, 10, 11, 12], 13: [0, 10, 9, 13], 14: [0, 1, 8,␣
(continues
˓→7, 14], 15: [0, 19, 18, 17, 16, 15], 16: [0, 19, 18, 17, 16], 17: [0, 19,on next page)
18,␣
˓→17], 18: [0, 19, 18], 19: [0, 19]}
True
sage: G = Graph( { 0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2} },␣
˓→sparse=True)
sage: D = DiGraph([(0,1,1),(1,2,3),(0,2,5)])
sage: D.shortest_paths(0)
{0: [0], 1: [0, 1], 2: [0, 2]}
sage: D.shortest_paths(0, by_weight=True)
{0: [0], 1: [0, 1], 2: [0, 1, 2]}
sage: D = DiGraph([(0,1,{'weight':1}),(1,2,{'weight':3}),(0,2,{'weight':5})])
sage: weight_function = lambda e:e[2]['weight']
sage: D.shortest_paths(0, weight_function=weight_function)
{0: [0], 1: [0, 1], 2: [0, 1, 2]}
Negative weights:
sage: D = DiGraph([(0,1,1),(1,2,-2),(0,2,4)])
sage: D.shortest_paths(0, by_weight=True)
{0: [0], 1: [0, 1], 2: [0, 1, 2]}
Negative cycles:
sage: D.add_edge(2,0,0)
sage: D.shortest_paths(0, by_weight=True)
Traceback (most recent call last):
...
ValueError: the graph contains a negative cycle
sage: g = DiGraph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), (3, 5, 10),␣
˓→(4, 5, 30)])
[(20, [(1, 3), (3, 5)]), (40, [(1, 2), (2, 5)]), (60, [(1, 4), (4, 5)])]
sage: list(g.shortest_simple_paths(1, 5, report_edges=True, report_weight=True))
[(2, [(1, 4), (4, 5)]), (2, [(1, 3), (3, 5)]), (2, [(1, 2), (2, 5)])]
sage: list(g.shortest_simple_paths(1, 5, by_weight=True, report_edges=True))
[[(1, 3), (3, 5)], [(1, 2), (2, 5)], [(1, 4), (4, 5)]]
sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Feng",␣
˓→report_edges=True, labels=True))
[[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]]
sage: g = Graph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), (3, 5, 10), (4,
˓→ 5, 30), (1, 6, 100), (5, 6, 5)])
show(method='matplotlib', **kwds)
Show the (di)graph.
INPUT:
• method – string (default: "matplotlib"); method to use to display the graph, either "matplotlib",
or "js" to visualize it in a browser using d3.js.
• Any other argument supported by the drawing functions:
– "matplotlib" – see GenericGraph.plot and sage.plot.graphics.Graphics.show()
– "js" – see gen_html_code()
EXAMPLES:
sage: C = graphs.CubeGraph(8)
sage: P = C.plot(vertex_labels=False, vertex_size=0, graph_border=True)
sage: P.show() # long time (3s on sage.math, 2011)
EXAMPLES:
sage: G = graphs.CubeGraph(5)
sage: G.show3d(iterations=500, edge_size=None, vertex_size=0.04) # long time
sage: A5 = AlternatingGroup(5); A5
Alternating group of order 5!/2 as a permutation group
sage: G = A5.cayley_graph()
sage: G.show3d(vertex_size=0.03, edge_size=0.01, edge_size2=0.02,
....: vertex_colors={(1,1,1): list(G)}, bgcolor=(0,0,0),
....: color_by_label=True, iterations=200) # long time
sage: D = graphs.DodecahedralGraph()
sage: D.show3d(engine='tachyon') # long time
sage: G = graphs.PetersenGraph()
sage: G.show3d(engine='tachyon', vertex_colors={(0,0,1): list(G)}) # long time
sage: C = graphs.CubeGraph(4)
sage: C.show3d(engine='tachyon', edge_colors={(0,1,0): C.edges(sort=False)},␣
˓→vertex_colors={(1,1,1): list(C)}, bgcolor=(0,0,0)) # long time
sage: K = graphs.CompleteGraph(3)
sage: K.show3d(engine='tachyon', edge_colors={(1,0,0): [(0, 1, None)], (0, 1,␣
˓→0): [(0, 2, None)], (0, 0, 1): [(1, 2, None)]}) # long time
size()
Return the number of edges.
Note that num_edges() also returns the number of edges in 𝐺.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.size()
15
spanning_trees_count(root_vertex=None)
Return the number of spanning trees in a graph.
In the case of a digraph, counts the number of spanning out-trees rooted in root_vertex. Default is to set
first vertex as root.
This computation uses Kirchhoff’s Matrix Tree Theorem [1] to calculate the number of spanning trees.
For complete graphs on 𝑛 vertices the result can also be reached using Cayley’s formula: the number of
spanning trees are 𝑛( 𝑛 − 2).
For digraphs, the augmented Kirchhoff Matrix as defined in [2] is used for calculations. Here the result is
the number of out-trees rooted at a specific vertex.
INPUT:
• root_vertex – a vertex (default: None); the vertex that will be used as root for all spanning out-trees
if the graph is a directed graph. Otherwise, the first vertex returned by vertex_iterator() is used.
This argument is ignored if the graph is not a digraph.
See also:
spanning_trees() – enumerates all spanning trees of a graph
REFERENCES:
• [1] http://mathworld.wolfram.com/MatrixTreeTheorem.html
• [2] Lih-Hsing Hsu, Cheng-Kuan Lin, “Graph Theory and Interconnection Networks”
AUTHORS:
• Anders Jonsson (2009-10-10)
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.spanning_trees_count()
2000
sage: n = 11
sage: G = graphs.CompleteGraph(n)
sage: ST = G.spanning_trees_count()
sage: ST == n ^ (n - 2)
True
spectral_radius(G, prec=1e-10)
Return an interval of floating point number that encloses the spectral radius of this graph
The input graph G must be strongly connected.
INPUT:
• prec – (default 1e-10) an upper bound for the relative precision of the interval
The algorithm is iterative and uses an inequality valid for non-negative matrices. Namely, if 𝐴 is a non-
negative square matrix with Perron-Frobenius eigenvalue 𝜆 then the following inequality is valid for any
vector 𝑥
(𝐴𝑥)𝑖 (𝐴𝑥)𝑖
min ≤ 𝜆 ≤ max
𝑖 𝑥𝑖 𝑖 𝑥𝑖
Note: The speed of convergence of the algorithm is governed by the spectral gap (the distance to the second
largest modulus of other eigenvalues). If this gap is small, then this function might not be appropriate.
The algorithm is not smart and not parallel! It uses basic interval arithmetic and native floating point
arithmetic.
EXAMPLES:
sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(2,4),(3,4)])
sage: e_min, e_max = spectral_radius(G, 1e-14)
sage: e = max(G.adjacency_matrix().charpoly().roots(AA, multiplicities=False))
sage: e_min < e < e_max
True
A larger example:
sage: G = DiGraph()
sage: G.add_edges((i,i+1) for i in range(200))
sage: G.add_edge(200,0)
sage: G.add_edge(1,0)
sage: e_min, e_max = spectral_radius(G, 0.00001)
sage: p = G.adjacency_matrix(sparse=True).charpoly()
sage: p
x^201 - x^199 - 1
sage: r = p.roots(AA, multiplicities=False)[0]
sage: e_min < r < e_max
True
sage: G = DiGraph(100000)
sage: r = list(range(100000))
sage: while not G.is_strongly_connected():
....: shuffle(r)
....: G.add_edges(enumerate(r), loops=False)
sage: spectral_radius(G, 1e-10) # random
(1.9997956006500042, 1.9998043797692782)
sage: G = DiGraph(2,loops=True,multiedges=True)
sage: G.add_edges([(0,0),(0,0),(0,1),(1,0)])
sage: spectral_radius(G, 1e-14) # abs tol 1e-14
(2.414213562373094, 2.414213562373095)
sage: max(G.adjacency_matrix().eigenvalues(AA))
2.414213562373095?
sage: G = Graph([(0,1),(0,3),(2,3)])
sage: G.spectral_radius() # abs tol 1e-10
(1.6180339887253428, 1.6180339887592732)
sage: G = DiGraph([(0,1),(0,3),(2,3),(3,0),(1,0),(1,2)])
sage: G.spectral_radius() # abs tol 1e-10
(1.5537739740270458, 1.553773974033029)
sage: G = graphs.CompleteBipartiteGraph(1,3)
sage: G.spectral_radius() # abs tol 1e-10
(1.7320508075688772, 1.7320508075688774)
spectrum(laplacian=False)
Return a list of the eigenvalues of the adjacency matrix.
INPUT:
• laplacian – boolean (default: False); if True, use the Laplacian matrix (see
kirchhoff_matrix())
OUTPUT:
A list of the eigenvalues, including multiplicities, sorted with the largest eigenvalue first.
See also:
The method spectral_radius() returns floating point approximation of the maximum eigenvalue.
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.spectrum()
[3, 1, 1, 1, 1, 1, -2, -2, -2, -2]
sage: P.spectrum(laplacian=True)
[5, 5, 5, 5, 2, 2, 2, 2, 2, 0]
sage: D = P.to_directed()
sage: D.delete_edge(7, 9)
sage: D.spectrum()
[2.9032119259..., 1, 1, 1, 1, 0.8060634335..., -1.7092753594..., -2, -2, -2]
sage: C = graphs.CycleGraph(8)
sage: C.spectrum()
[2, 1.4142135623..., 1.4142135623..., 0, 0, -1.4142135623..., -1.4142135623...,␣
˓→-2]
A digraph may have complex eigenvalues. Previously, the complex parts of graph eigenvalues were being
dropped. For a 3-cycle, we have:
Note:
• This problem being defined on undirected graphs, the orientation is not considered if the current graph
is actually a digraph.
• The graph is assumed not to have multiple edges.
ALGORITHM:
Solved through Linear Programming.
COMPLEXITY:
NP-Hard.
Note that this algorithm first checks whether the given set of vertices induces a connected graph, returning
one of its spanning trees if weighted is set to False, and thus answering very quickly in some cases
EXAMPLES:
The Steiner Tree of the first 5 vertices in a random graph is, of course, always a tree:
An exception is raised when the problem is impossible, i.e. if the given vertices are not all included in the
same connected component:
sage: g = 2 * graphs.PetersenGraph()
sage: st = g.steiner_tree([5, 15])
Traceback (most recent call last):
...
EmptySetError: the given vertices do not all belong to the same connected␣
˓→component. This problem has no solution !
strong_product(other)
Return the strong product of self and other.
The strong product of 𝐺 and 𝐻 is the graph 𝐿 with vertex set 𝑉 (𝐿) = 𝑉 (𝐺) × 𝑉 (𝐻), and ((𝑢, 𝑣), (𝑤, 𝑥))
is an edge of 𝐿 iff either :
• (𝑢, 𝑤) is an edge of 𝐺 and 𝑣 = 𝑥, or
• (𝑣, 𝑥) is an edge of 𝐻 and 𝑢 = 𝑤, or
• (𝑢, 𝑤) is an edge of 𝐺 and (𝑣, 𝑥) is an edge of 𝐻.
In other words, the edges of the strong product is the union of the edges of the tensor and Cartesian products.
EXAMPLES:
sage: Z = graphs.CompleteGraph(2)
sage: C = graphs.CycleGraph(5)
sage: S = C.strong_product(Z); S
Graph on 10 vertices
sage: S.plot() # long time
Graphics object consisting of 36 graphics primitives
sage: D = graphs.DodecahedralGraph()
sage: P = graphs.PetersenGraph()
sage: S = D.strong_product(P); S
Graph on 200 vertices
sage: S.plot() # long time
Graphics object consisting of 1701 graphics primitives
subdivide_edge(*args)
Subdivide an edge 𝑘 times.
INPUT:
The following forms are all accepted to subdivide 8 times the edge between vertices 1 and 2 labeled with
"my_label".
• G.subdivide_edge( 1, 2, 8 )
• G.subdivide_edge( (1, 2), 8 )
• G.subdivide_edge( (1, 2, "my_label"), 8 )
Note:
• If the given edge is labelled with 𝑙, all the edges created by the subdivision will have the same label
• If no label is given, the label used will be the one returned by the method edge_label() on the pair
u,v
EXAMPLES:
Subdividing 5 times an edge in a path of length 3 makes it a path of length 8:
sage: g = graphs.PathGraph(3)
sage: edge = next(g.edge_iterator())
sage: g.subdivide_edge(edge, 5)
sage: g.is_isomorphic(graphs.PathGraph(8))
True
sage: g = Graph()
sage: g.add_edge(0, 1, "label1")
sage: g.add_edge(1, 2, "label2")
sage: print(g.edges(sort=True))
[(0, 1, 'label1'), (1, 2, 'label2')]
sage: g.subdivide_edge(0,1,1,1,1,1,1,1,1,1,1)
Traceback (most recent call last):
...
ValueError: this method takes at most 4 arguments
The same goes when the given edge does not exist:
See also:
subdivide_edges(edges, k)
Subdivide 𝑘 times edges from an iterable container.
For more information on the behaviour of this method, please refer to the documentation of
subdivide_edge().
INPUT:
• edges – a list of edges
• k – integer; common length of the subdivisions
Note: If a given edge is labelled with 𝑙, all the edges created by its subdivision will have the same label.
EXAMPLES:
If we are given the disjoint union of several paths:
sage: k = 6
sage: g.subdivide_edges(edges, k)
Let us check this by creating the graph we expect to have built through subdivision:
sage: paths2 = [2 + k, 5 + k, 9 + k]
sage: paths2 = map(graphs.PathGraph, paths2)
sage: g2 = Graph()
sage: for P in paths2:
....: g2 = g2 + P
sage: g.is_isomorphic(g2)
True
See also:
• vertices – a single vertex or an iterable container of vertices, e.g. a list, set, graph, file or numeric
array. If not passed (i.e., None), defaults to the entire graph.
• edges – as with vertices, edges can be a single edge or an iterable container of edges (e.g., a list,
set, file, numeric array, etc.). By default (edges=None), all edges are assumed and the returned graph
is an induced subgraph. In the case of multiple edges, specifying an edge as (𝑢, 𝑣) means to keep all
edges (𝑢, 𝑣), regardless of the label.
• vertex_property – function (default: None); a function that inputs a vertex and outputs a boolean
value, i.e., a vertex v in vertices is kept if vertex_property(v) == True
• edge_property – function (default: None); a function that inputs an edge and outputs a boolean
value, i.e., a edge e in edges is kept if edge_property(e) == True
• algorithm – string (default: None); one of the following:
– If algorithm="delete" or inplace=True, then the graph is constructed by deleting edges and
vertices
– If algorithm="add", then the graph is constructed by building a new graph from the appropriate
vertices and edges. Implies inplace=False.
– If algorithm=None, then the algorithm is chosen based on the number of vertices in the subgraph.
• immutable – boolean (default: None); whether to create a mutable/immutable subgraph.
immutable=None (default) means that the graph and its subgraph will behave the same way.
EXAMPLES:
sage: G = graphs.CompleteGraph(9)
sage: H = G.subgraph([0, 1, 2]); H
Subgraph of (Complete graph): Graph on 3 vertices
sage: G
Complete graph: Graph on 9 vertices
sage: J = G.subgraph(edges=[(0, 1)])
sage: J.edges(sort=True, labels=False)
[(0, 1)]
sage: set(J) == set(G)
True
sage: G.subgraph([0, 1, 2], inplace=True); G
Subgraph of (Complete graph): Graph on 3 vertices
sage: G.subgraph() == G
True
sage: D = digraphs.Complete(9)
sage: H = D.subgraph([0, 1, 2]); H
Subgraph of (Complete digraph): Digraph on 3 vertices
sage: H = D.subgraph(edges=[(0, 1), (0, 2)])
sage: H.edges(sort=True, labels=False)
[(0, 1), (0, 2)]
sage: set(H) == set(D)
True
sage: D
Complete digraph: Digraph on 9 vertices
sage: D.subgraph([0, 1, 2], inplace=True); D
Subgraph of (Complete digraph): Digraph on 3 vertices
sage: D.subgraph() == D
True
sage: P = graphs.PetersenGraph()
sage: S = P.subgraph(vertex_property=lambda v: not (v % 2))
sage: S.vertices(sort=True)
[0, 2, 4, 6, 8]
sage: C = graphs.CubeGraph(2)
sage: S = C.subgraph(edge_property=(lambda e: e[0][0] == e[1][0]))
sage: C.edges(sort=True)
[('00', '01', None), ('00', '10', None), ('01', '11', None), ('10', '11', None)]
sage: S.edges(sort=True)
[('00', '01', None), ('10', '11', None)]
The algorithm is not specified, then a reasonable choice is made for speed:
sage: g = graphs.PathGraph(1000)
sage: g.subgraph(list(range(10))) # uses the 'add' algorithm
Subgraph of (Path graph): Graph on 10 vertices
subgraph_search(G, induced=False)
Return a copy of G in self.
INPUT:
• G – the (di)graph whose copy we are looking for in self
• induced – boolean (default: False); whether or not to search for an induced copy of G in self
OUTPUT:
If induced=False, return a copy of G in this graph. Otherwise, return an induced copy of G in self. If G
is the empty graph, return the empty graph since it is a subgraph of every graph. Now suppose G is not the
empty graph. If there is no copy (induced or otherwise) of G in self, we return None.
Note: The vertex labels and the edge labels in the graph are ignored.
See also:
ALGORITHM:
See the documentation of SubgraphSearch .
EXAMPLES:
The Petersen graph contains the path graph 𝑃5 :
sage: g = graphs.PetersenGraph()
sage: h1 = g.subgraph_search(graphs.PathGraph(5)); h1
Subgraph of (Petersen graph): Graph on 5 vertices
sage: h1.vertices(sort=True); h1.edges(sort=True, labels=False)
[0, 1, 2, 3, 4]
[(0, 1), (1, 2), (2, 3), (3, 4)]
sage: I1 = g.subgraph_search(graphs.PathGraph(5), induced=True); I1
Subgraph of (Petersen graph): Graph on 5 vertices
sage: I1.vertices(sort=True); I1.edges(sort=True, labels=False)
[0, 1, 2, 3, 8]
[(0, 1), (1, 2), (2, 3), (3, 8)]
sage: h2 = g.subgraph_search(graphs.ClawGraph()); h2
Subgraph of (Petersen graph): Graph on 4 vertices
sage: h2.vertices(sort=True); h2.edges(sort=True, labels=False)
[0, 1, 4, 5]
[(0, 1), (0, 4), (0, 5)]
sage: I2 = g.subgraph_search(graphs.ClawGraph(), induced=True); I2
Subgraph of (Petersen graph): Graph on 4 vertices
sage: I2.vertices(sort=True); I2.edges(sort=True, labels=False)
[0, 1, 4, 5]
[(0, 1), (0, 4), (0, 5)]
Of course the induced copies are isomorphic to the graphs we were looking for:
sage: I1.is_isomorphic(graphs.PathGraph(5))
True
sage: I2.is_isomorphic(graphs.ClawGraph())
True
sage: g.subgraph_search(graphs.EmptyGraph())
Graph on 0 vertices
sage: g.subgraph_search(graphs.EmptyGraph(), induced=True)
Graph on 0 vertices
subgraph_search_count(G, induced=False)
Return the number of labelled occurrences of G in self.
INPUT:
• G – the (di)graph whose copies we are looking for in self
• induced – boolean (default: False); whether or not to count induced copies of G in self
Note: The vertex labels and the edge labels in the graph are ignored.
ALGORITHM:
See the documentation of SubgraphSearch .
See also:
EXAMPLES:
Counting the number of paths 𝑃5 in a PetersenGraph:
sage: g = graphs.PetersenGraph()
sage: g.subgraph_search_count(graphs.PathGraph(5))
240
If we define the graph 𝑇𝑘 (the transitive tournament on 𝑘 vertices) as the graph on {0, ..., 𝑘 − 1} such that
𝑖𝑗 ∈ 𝑇𝑘 if 𝑖 < 𝑗, how many directed triangles can be found in 𝑇5 ? The answer is of course 0:
sage: T5 = digraphs.TransitiveTournament(5)
sage: T5.subgraph_search_count(digraphs.Circuit(3))
0
sage: T3 = digraphs.TransitiveTournament(3)
sage: T5.subgraph_search_count(T3)
10
sage: binomial(5,3)
10
sage: T3.is_isomorphic(T5.subgraph(vertices=[0, 1, 2]))
True
sage: g.subgraph_search_count(graphs.EmptyGraph())
1
If the graph has vertex labels or edge labels, the label is just ignored:
Note: The vertex labels and the edge labels in the graph are ignored.
ALGORITHM:
See the documentation of SubgraphSearch .
OUTPUT:
Iterator over the labelled copies of G in self, as lists or (di)graphs. For each value (𝑣1 , 𝑣2 , ..., 𝑣𝑘 ) returned,
the first vertex of 𝐺 is associated with 𝑣1 , the second with 𝑣2 , etc.
See also:
EXAMPLES:
Iterating through all the labelled 𝑃3 of 𝑃5 :
sage: g = graphs.PathGraph(5)
sage: P3 = graphs.PathGraph(3)
sage: for p in g.subgraph_search_iterator(P3, return_graphs=False):
....: print(p)
[0, 1, 2]
[1, 2, 3]
[2, 1, 0]
[2, 3, 4]
[3, 2, 1]
[4, 3, 2]
sage: for p in g.subgraph_search_iterator(P3, return_graphs=True):
....: print(p)
Subgraph of (Path graph)
Subgraph of (Path graph)
Subgraph of (Path graph)
Subgraph of (Path graph)
Subgraph of (Path graph)
Subgraph of (Path graph)
sage: all(h.is_isomorphic(P3) for h in g.subgraph_search_iterator(P3))
True
If the graph has vertex labels or edge labels, the label is just ignored:
sage: H = graphs.HouseGraph()
sage: P4 = graphs.PathGraph(4)
sage: all(h.is_isomorphic(P4) for h in H.subgraph_search_iterator(P4,␣
˓→induced=True))
True
sage: sum(1 for h in H.subgraph_search_iterator(P4, induced=True))
4
sage: sum(1 for h in H.subgraph_search_iterator(P4, induced=False))
20
sage: H = digraphs.Complete(5)
sage: P4 = digraphs.Path(4)
sage: sum(1 for _ in H.subgraph_search_iterator(P4, induced=True))
0
sage: sum(1 for _ in H.subgraph_search_iterator(P4, induced=False))
120
symmetric_edge_polytope(backend=None)
Return the symmetric edge polytope of self.
The symmetric edge polytope (SEP) of a Graph on 𝑛 vertices is the polytope in Z𝑛 defined as the convex
hull of 𝑒𝑖 − 𝑒𝑗 and 𝑒𝑗 − 𝑒𝑖 for each edge (𝑖, 𝑗). Here 𝑒1 , . . . , 𝑒𝑛 denotes the standard basis.
INPUT:
• backend – string or None (default); the backend to use; see sage.geometry.polyhedron.
constructor.Polyhedron()
EXAMPLES:
The SEP of a 4-cycle is a cube:
sage: G = graphs.CycleGraph(4)
sage: P = G.symmetric_edge_polytope(); P
A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 8 vertices
sage: P.is_combinatorially_isomorphic(polytopes.cube())
True
sage: G = graphs.CompleteGraph(4)
sage: P = G.symmetric_edge_polytope(); P
A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 12 vertices
sage: P.is_combinatorially_isomorphic(polytopes.cuboctahedron())
True
The SEP of a graph with edges on 𝑛 vertices has dimension 𝑛 minus the number of connected components:
The SEP of a graph is isomorphic to the subdirect sum of its connected components SEP’s:
sage: n = randint(3, 6)
sage: G1 = graphs.RandomGNP(n, 0.2)
sage: n = randint(3, 6)
sage: G2 = graphs.RandomGNP(n, 0.2)
sage: G = G1.disjoint_union(G2)
sage: P = G.symmetric_edge_polytope()
sage: P1 = G1.symmetric_edge_polytope()
sage: P2 = G2.symmetric_edge_polytope()
sage: P.is_combinatorially_isomorphic(P1.subdirect_sum(P2))
True
sage: len(list(graphs(5)))
34
sage: polys = []
sage: for G in graphs(5):
....: P = G.symmetric_edge_polytope()
....: for P1 in polys:
....: if P.is_combinatorially_isomorphic(P1):
....: break
....: else:
....: polys.append(P)
sage: len(polys)
25
sage: G1 = graphs.CycleGraph(4)
sage: G1.add_edges([[0, 5], [5, 2], [1, 6], [6, 2]])
sage: G2 = copy(G1)
(continues on next page)
sage: n = randint(3, 7)
sage: g1 = graphs.RandomGNP(n, 0.2)
sage: g2 = graphs.RandomGNP(n, 0.2)
sage: G = g1.disjoint_union(g2)
sage: H = copy(G)
sage: G.merge_vertices(((0, randrange(n)), (1, randrange(n))))
sage: H.merge_vertices(((0, randrange(n)), (1, randrange(n))))
sage: PG = G.symmetric_edge_polytope()
sage: PH = H.symmetric_edge_polytope()
sage: PG.is_combinatorially_isomorphic(PH)
True
szeged_index(G, algorithm=None)
Return the Szeged index of the graph 𝐺.
Let 𝐺 = (𝑉, 𝐸) be a connected graph, and for any 𝑢𝑣 ∈ 𝐸, let 𝑁𝑢 (𝑢𝑣) = {𝑤 ∈ 𝑉 : 𝑑(𝑢, 𝑤) < 𝑑(𝑣, 𝑤)}
and 𝑛𝑢 (𝑢𝑣) = |𝑁𝑢 (𝑢𝑣)|. The Szeged index of 𝐺 is then defined as [KRG1996]
∑︁
‘ 𝑛𝑢 (𝑢𝑣) × 𝑛𝑣 (𝑢𝑣)‘
𝑢𝑣∈𝐸(𝐺)
sage: g = Graph()
sage: g.add_edges(graphs.CubeGraph(5).min_spanning_tree())
sage: g.wiener_index() == szeged_index(g)
True
tensor_product(other)
Return the tensor product of self and other.
The tensor product of 𝐺 and 𝐻 is the graph 𝐿 with vertex set 𝑉 (𝐿) equal to the Cartesian product of the
vertices 𝑉 (𝐺) and 𝑉 (𝐻), and ((𝑢, 𝑣), (𝑤, 𝑥)) is an edge iff - (𝑢, 𝑤) is an edge of self, and - (𝑣, 𝑥) is an
edge of other.
The tensor product is also known as the categorical product and the Kronecker product (referring to the
Kronecker matrix product). See the Wikipedia article Kronecker_product.
EXAMPLES:
sage: Z = graphs.CompleteGraph(2)
sage: C = graphs.CycleGraph(5)
sage: T = C.tensor_product(Z); T
Graph on 10 vertices
sage: T.size()
10
sage: T.plot() # long time
Graphics object consisting of 21 graphics primitives
sage: D = graphs.DodecahedralGraph()
sage: P = graphs.PetersenGraph()
sage: T = D.tensor_product(P); T
Graph on 200 vertices
sage: T.size()
900
sage: T.plot() # long time
Graphics object consisting of 1101 graphics primitives
to_dictionary(edge_labels=False, multiple_edges=False)
Return the graph as a dictionary.
INPUT:
• edge_labels – boolean (default: False); whether to include edge labels in the output
• multiple_edges – boolean (default: False); whether to include multiple edges in the output
OUTPUT:
The output depends on the input:
• If edge_labels == False and multiple_edges == False, the output is a dictionary associating
to each vertex the list of its neighbors.
• If edge_labels == False and multiple_edges == True, the output is a dictionary the same as
previously with one difference: the neighbors are listed with multiplicity.
• If edge_labels == True and multiple_edges == False, the output is a dictionary associating
to each vertex 𝑢 [a dictionary associating to each vertex 𝑣 incident to 𝑢 the label of edge (𝑢, 𝑣)].
• If edge_labels == True and multiple_edges == True, the output is a dictionary associating to
each vertex 𝑢 [a dictionary associating to each vertex 𝑣 incident to 𝑢 [the list of labels of all edges
between 𝑢 and 𝑣]].
Note: When used on directed graphs, the explanations above can be understood by replacing the word
“neighbors” by “out-neighbors”
EXAMPLES:
sage: g = graphs.PetersenGraph().to_dictionary()
sage: [(key, sorted(g[key])) for key in g]
[(0, [1, 4, 5]),
(1, [0, 2, 6]),
(2, [1, 3, 7]),
(3, [2, 4, 8]),
(4, [0, 3, 9]),
(5, [0, 7, 8]),
(6, [1, 8, 9]),
(7, [2, 5, 9]),
(8, [3, 5, 6]),
(9, [4, 6, 7])]
sage: graphs.PetersenGraph().to_dictionary(multiple_edges=True)
{0: [1, 4, 5], 1: [0, 2, 6],
2: [1, 3, 7], 3: [2, 4, 8],
4: [0, 3, 9], 5: [0, 7, 8],
6: [1, 8, 9], 7: [2, 5, 9],
8: [3, 5, 6], 9: [4, 6, 7]}
sage: graphs.PetersenGraph().to_dictionary(edge_labels=True)
{0: {1: None, 4: None, 5: None},
1: {0: None, 2: None, 6: None},
2: {1: None, 3: None, 7: None},
3: {2: None, 4: None, 8: None},
4: {0: None, 3: None, 9: None},
5: {0: None, 7: None, 8: None},
6: {1: None, 8: None, 9: None},
7: {2: None, 5: None, 9: None},
8: {3: None, 5: None, 6: None},
9: {4: None, 6: None, 7: None}}
sage: graphs.PetersenGraph().to_dictionary(edge_labels=True,multiple_edges=True)
{0: {1: [None], 4: [None], 5: [None]},
1: {0: [None], 2: [None], 6: [None]},
2: {1: [None], 3: [None], 7: [None]},
(continues on next page)
Warning: 'min' and 'max' only works if the labels can be compared. A TypeError might be raised
when working with non-comparable objects in Python 3.
EXAMPLES:
transitive_closure(loops=True)
Return the transitive closure of the (di)graph.
The transitive closure of a graph 𝐺 has an edge (𝑥, 𝑦) if and only if there is a path between 𝑥 and 𝑦 in 𝐺.
The transitive closure of any (strongly) connected component of a (di)graph is a complete graph. The
transitive closure of a directed acyclic graph is a directed acyclic graph representing the full partial order.
Note: If the (di)graph allows loops, its transitive closure will by default have one loop edge per vertex.
This can be prevented by disallowing loops in the (di)graph (self.allow_loops(False)).
EXAMPLES:
sage: g = graphs.PathGraph(4)
sage: g.transitive_closure()
Transitive closure of Path graph: Graph on 4 vertices
sage: g.transitive_closure().is_isomorphic(graphs.CompleteGraph(4))
True
sage: g = DiGraph({0: [1, 2], 1: [3], 2: [4, 5]})
sage: g.transitive_closure().edges(sort=True, labels=False)
[(0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (1, 3), (2, 4), (2, 5)]
On an immutable digraph:
sage: digraphs.Path(5).copy(immutable=True).transitive_closure()
Transitive closure of Path: Digraph on 5 vertices
The transitive closure of a (di)graph allowing loops has by default a loop edge per vertex. Parameter loops
allows to prevent that:
sage: G = digraphs.Circuit(3)
sage: G.transitive_closure().loop_edges(labels=False)
[]
sage: G.allow_loops(True)
sage: G.transitive_closure().loop_edges(labels=False)
[(0, 0), (1, 1), (2, 2)]
sage: G = graphs.CycleGraph(3)
sage: G.transitive_closure().loop_edges(labels=False)
[]
sage: G.allow_loops(True)
sage: G.transitive_closure().loop_edges(labels=False)
[(0, 0), (1, 1), (2, 2)]
transitive_reduction()
Return a transitive reduction of a graph.
A transitive reduction 𝐻 of 𝐺 has a path from 𝑥 to 𝑦 if and only if there was a path from 𝑥 to 𝑦 in 𝐺.
Deleting any edge of 𝐻 destroys this property. A transitive reduction is not unique in general. A transitive
reduction has the same transitive closure as the original graph.
A transitive reduction of a complete graph is a tree. A transitive reduction of a tree is itself.
EXAMPLES:
sage: g = graphs.PathGraph(4)
sage: g.transitive_reduction() == g
True
sage: g = graphs.CompleteGraph(5)
sage: h = g.transitive_reduction(); h.size()
4
sage: g = DiGraph({0: [1, 2], 1: [2, 3, 4, 5], 2: [4, 5]})
sage: g.transitive_reduction().size()
5
Note: This function is correctly defined for both graph and digraphs. In the second case, the returned
EXAMPLES:
The Heawood graph is known to be Hamiltonian:
sage: g = graphs.HeawoodGraph()
sage: tsp = g.traveling_salesman_problem()
sage: tsp
TSP from Heawood graph: Graph on 14 vertices
sage: tsp.is_connected()
True
sage: tsp.is_regular(k=2)
True
sage: g = graphs.PetersenGraph()
sage: tsp = g.traveling_salesman_problem()
Traceback (most recent call last):
...
EmptySetError: the given graph is not Hamiltonian
One easy way to change it is obviously to add to this graph the edges corresponding to a Hamiltonian cycle.
If we do this by setting the cost of these new edges to 2, while the others are set to 1, we notice that not all
the edges we added are used in the optimal solution
If we pick 1/2 instead of 2 as a cost for these new edges, they clearly become the optimal solution:
sage: G = Graph([(0, 1, 1), (0, 2, 2), (0, 3, 1), (1, 2, 1), (1, 3, 2), (2, 3,␣
˓→1)])
triangles_count(algorithm=None)
Return the number of triangles in the (di)graph.
For digraphs, we count the number of directed circuit of length 3.
INPUT:
• algorithm – string (default: None); specifies the algorithm to use (note that only 'iter' is available
for directed graphs):
– 'sparse_copy' – counts the triangles in a sparse copy of the graph (see sage.graphs.base.
static_sparse_graph ). Calls static_sparse_graph.triangles_count
– 'dense_copy' – counts the triangles in a dense copy of the graph (see sage.graphs.base.
static_dense_graph ). Calls static_dense_graph.triangles_count
– 'matrix' uses the trace of the cube of the adjacency matrix
– 'iter' iterates over the pairs of neighbors of each vertex. No copy of the graph is performed
– None – for undirected graphs, uses "sparse_copy" or "dense_copy" depending on whether the
graph is stored as dense or sparse. For directed graphs, uses 'iter'.
EXAMPLES:
The Petersen graph is triangle free and thus:
sage: G = graphs.PetersenGraph()
sage: G.triangles_count()
0
sage: G = graphs.CompleteGraph(15)
sage: G.triangles_count() == binomial(15, 3)
True
sage: G = digraphs.DeBruijn(2,2)
sage: G.triangles_count()
2
sage: G = digraphs.Circuit(10)
sage: G.triangles_count()
0
union(other, immutable=None)
Return the union of self and other.
If the graphs have common vertices, the common vertices will be identified.
If one of the two graphs allows loops (or multiple edges), the resulting graph will allow loops (or multiple
edges).
If both graphs are weighted the resulting graphs is weighted.
If both graphs are immutable, the resulting graph is immutable, unless requested otherwise.
INPUT:
• immutable – boolean (default: None); whether to create a mutable/immutable union.
immutable=None (default) means that the graphs and their union will behave the same way.
See also:
• disjoint_union()
• join()
EXAMPLES:
sage: G = graphs.CycleGraph(3)
sage: H = graphs.CycleGraph(4)
sage: J = G.union(H); J
Graph on 4 vertices
sage: J.vertices(sort=True)
[0, 1, 2, 3]
sage: J.edges(sort=True, labels=False)
[(0, 1), (0, 2), (0, 3), (1, 2), (2, 3)]
vertex_boundary(vertices1, vertices2=None)
Return a list of all vertices in the external boundary of vertices1, intersected with vertices2.
If vertices2 is None, then vertices2 is the complement of vertices1. This is much faster if
vertices1 is smaller than vertices2.
The external boundary of a set of vertices is the union of the neighborhoods of each vertex in the set. Note
that in this implementation, since vertices2 defaults to the complement of vertices1, if a vertex 𝑣 has
a loop, then vertex_boundary(v) will not contain 𝑣.
In a digraph, the external boundary of a vertex 𝑣 are those vertices 𝑢 with an arc (𝑣, 𝑢).
EXAMPLES:
sage: G = graphs.CubeGraph(4)
sage: l = ['0111', '0000', '0001', '0011', '0010', '0101', '0100', '1111', '1101
˓→', '1011', '1001']
Note:
• When the graph is directed, this method actually computes the strong connectivity, (i.e. a directed
graph is strongly 𝑘-connected if there are 𝑘 vertex disjoint paths between any two vertices 𝑢, 𝑣). If you
do not want to consider strong connectivity, the best is probably to convert your DiGraph object to a
Graph object, and compute the connectivity of this other graph.
• By convention, a complete graph on 𝑛 vertices is 𝑛 − 1 connected. In this case, no certificate can
be given as there is no pair of vertices split by a cut of order 𝑘 − 1. For this reason, the certificates
returned in this situation are empty.
INPUT:
• G – the input Sage (Di)Graph
• value_only – boolean (default: True)
– When set to True (default), only the value is returned.
– When set to False, both the value and a minimum vertex cut are returned.
• sets – boolean (default: False); whether to also return the two sets of vertices that are discon-
nected by the cut (implies value_only=False)
• k – integer (default: None); when specified, check if the vertex connectivity of the (di)graph is larger
or equal to 𝑘. The method thus outputs a boolean only.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
EXAMPLES:
A basic application on a PappusGraph:
In a grid, the vertex connectivity is equal to the minimum degree, in which case one of the two sets is of
cardinality 1:
When value_only = True, this function is optimized for small connectivity values and does not need to
build a linear program.
It is the case for connected graphs which are not connected:
sage: g = 2 * graphs.PetersenGraph()
sage: vertex_connectivity(g)
0
sage: g = graphs.PathGraph(10)
sage: vertex_connectivity(g)
1
For directed graphs, the strong connectivity is tested through the dedicated function:
sage: g = digraphs.ButterflyGraph(3)
sage: vertex_connectivity(g)
0
sage: g = graphs.CompleteGraph(10)
sage: vertex_connectivity(g)
9
sage: g = DiGraph(graphs.CompleteGraph(10))
sage: vertex_connectivity(g)
9
When parameter k is set, we only check for the existence of a vertex cut of order at least k:
sage: g = graphs.PappusGraph()
sage: vertex_connectivity(g, k=3)
True
sage: vertex_connectivity(g, k=4)
False
A vertex cut between two non-adjacent vertices is a set 𝑈 of vertices of self such that the graph ob-
tained by removing 𝑈 from self is disconnected. For more information, see the Wikipedia article
Cut_(graph_theory).
INPUT:
• value_only – boolean (default: True); whether to return only the size of the minimum cut, or to also
return the set 𝑈 of vertices of the cut
• vertices – boolean (default: False); whether to also return the two sets of vertices that are discon-
nected by the cut. Implies value_only set to False.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
OUTPUT:
Real number or tuple, depending on the given arguments (examples are given below).
EXAMPLES:
A basic application in the Pappus graph:
sage: g = graphs.PappusGraph()
sage: g.vertex_cut(1, 16, value_only=True)
3
In the bipartite complete graph 𝐾2,8 , a cut between the two vertices in the size 2 part consists of the other
8 vertices:
sage: g = graphs.CompleteBipartiteGraph(2, 8)
sage: [value, vertices] = g.vertex_cut(0, 1, value_only=False)
sage: print(value)
8
sage: vertices == list(range(2, 10))
True
Clearly, in this case the two sides of the cut are singletons:
sage: g = graphs.CompleteBipartiteGraph(2, 3)
sage: g.vertex_disjoint_paths(0, 1)
[[0, 2, 1], [0, 3, 1], [0, 4, 1]]
sage: P = graphs.PetersenGraph()
sage: for v in P.vertex_iterator():
....: print(v)
0
1
2
...
8
9
sage: G = graphs.TetrahedralGraph()
sage: for i in G:
....: print(i)
0
1
2
3
sage: H = graphs.PathGraph(5)
sage: prop = lambda l: l % 3 == 1
sage: for v in H.vertex_iterator(degree=1, vertex_property=prop):
....: print(v)
4
Note that since the intersection option is available, the vertex_iterator() function is sub-optimal, speed-wise,
but note the following optimization:
Warning: Since any object may be a vertex, there is no guarantee that any two vertices will be com-
parable. With default objects for vertices (all integers), or when all the vertices are of the same simple
type, then there should not be a problem with how the vertices will be sorted. However, if you need to
guarantee a total order for the sorting of the edges, use the key argument, as illustrated in the examples
below.
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.vertices(sort=True)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
If you do not care about sorted output and you are concerned about the time taken to sort, consider the
following alternative:
sage: G = graphs.HanoiTowerGraph(3, 3)
sage: G.vertices(sort=True)
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), ... (2, 2, 1), (2, 2, 2)]
sage: G.vertices(sort=True, key = lambda x: (x[1], x[2], x[0]))
[(0, 0, 0), (1, 0, 0), (2, 0, 0), (0, 0, 1), ... (1, 2, 2), (2, 2, 2)]
The discriminant of a polynomial is a function that returns an integer. We build a graph whose vertices
are polynomials, and use the discriminant function to provide an ordering. Note that since functions are
first-class objects in Python, we can specify precisely the function from the Sage library that we wish to
use as the key:
weighted(new=None)
Whether the (di)graph is to be considered as a weighted (di)graph.
INPUT:
• new – boolean (default: None); if it is provided, then the weightedness flag is set accordingly. This is
not allowed for immutable graphs.
Note: Changing the weightedness flag changes the ==-class of a graph and is thus not allowed for im-
mutable graphs.
Edge weightings can still exist for (di)graphs G where G.weighted() is False.
EXAMPLES:
Here we have two graphs with different labels, but weighted() is False for both, so we just check for the
presence of edges:
Now one is weighted and the other is not, and thus the graphs are not equal:
sage: G.weighted(True)
sage: H.weighted()
(continues on next page)
sage: H.weighted(True)
sage: G == H
False
[0 1 3 4]
[1 0 2 0]
[3 2 0 0]
[4 0 0 0]
As an immutable matrix:
sage: M = G.weighted_adjacency_matrix(immutable=True); M
[0 1 3 4]
[1 0 2 0]
[3 2 0 0]
[4 0 0 0]
sage: M[2, 2] = 1
Traceback (most recent call last):
...
ValueError: matrix is immutable; please change a copy instead (i.e., use␣
˓→copy(M) to change a copy of M).
• check_weight – boolean (default: True); if True, we check that the weight_function outputs a num-
ber for each edge
Note: Some algorithms (e.g., Boost algorithms) use floating point numbers for internal computations.
Whenever the solution is integral, we try to convert the returned value to an integer.
EXAMPLES:
sage: G = Graph( { 0: {1: None}, 1: {2: None}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2} }
˓→, sparse=True)
sage: G.wiener_index()
15
sage: G.wiener_index(weight_function=lambda e:(e[2] if e[2] is not None else 1))
20
sage: G.wiener_index(weight_function=lambda e:(e[2] if e[2] is not None else␣
˓→200))
820
sage: G.wiener_index(algorithm='BFS')
15
sage: G.wiener_index(algorithm='Floyd-Warshall-Cython')
15
sage: G.wiener_index(algorithm='Floyd-Warshall-Python')
15
sage: G.wiener_index(algorithm='Dijkstra_Boost')
15
sage: G.wiener_index(algorithm='Bellman-Ford_Boost')
15
sage: G.wiener_index(algorithm='Johnson_Boost')
15
sage: G.wiener_index(algorithm='Dijkstra_NetworkX')
15
sage: n = 5
sage: g = graphs.CompleteGraph(n)
sage: g.wiener_index() == (n * (n - 1)) / 2
True
sage: g = digraphs.Complete(n)
sage: g.wiener_index() == n * (n - 1)
True
sage: n = 7
sage: g = digraphs.Circuit(n)
sage: w = lambda x: (x*x*(x-1))/2
sage: g.wiener_index(algorithm='Dijkstra_Boost') == w(n)
True
sage: Graph(1).wiener_index()
0
sage: Graph().wiener_index()
Traceback (most recent call last):
...
ValueError: Wiener index is not defined for the empty graph
sage.graphs.generic_graph.graph_isom_equivalent_non_edge_labeled_graph(g, partition=None,
standard_label=None,
re-
turn_relabeling=False,
re-
turn_edge_labels=False,
inplace=False, ig-
nore_edge_labels=False)
Helper function for canonical labeling of edge labeled (di)graphs.
Translates to a bipartite incidence-structure type graph appropriate for computing canonical labels of edge labeled
and/or multi-edge graphs. Note that this is actually computationally equivalent to implementing a change on an
inner loop of the main algorithm – namely making the refinement procedure sort for each label.
If the graph is a multigraph, it is translated to a non-multigraph, where each instance of multiple edges is con-
verted to a single edge labeled with a list [[label1, multiplicity], [label2, multiplicity], ...]
describing how many edges of each label were originally there. Then in either case we are working on a graph
without multiple edges. At this point, we create another (partially bipartite) graph, whose left vertices are the
original vertices of the graph, and whose right vertices represent the labeled edges. Any unlabeled edges in the
original graph are also present in the new graph, and – this is the bipartite aspect – for every labeled edge 𝑒 from
𝑣 to 𝑤 in the original graph, there is an edge between the right vertex corresponding to 𝑒 and each of the left
vertices corresponding to 𝑣 and 𝑤. We partition the left vertices as they were originally, and the right vertices by
common labels: only automorphisms taking edges to like-labeled edges are allowed, and this additional partition
information enforces this on the new graph.
INPUT:
• g – Graph or DiGraph
• partition – list (default: None); a partition of the vertices as a list of lists of vertices. If given, the partition
of the vertices is as well relabeled
• standard_label – (default: None); edges in g with this label are preserved in the new graph
• return_relabeling – boolean (default: False); whether to return a dictionary containing the relabeling
• return_edge_labels – boolean (default: False); whether the different edge_labels are returned (use-
ful if inplace is True)
• inplace – boolean (default: False); whether the input (di)graph g is modified or the return a new
(di)graph. Note that attributes of g are not copied for speed issues, only edges and vertices.
• ignore_edge_labels – boolean (default: False): if True, ignore edge labels, so when constructing the
new graph, only multiple edges are replaced with vertices. Labels on multiple edges are ignored – only the
multiplicity is relevant, so multiple edges with the same multiplicity in the original graph correspond to
right vertices in the same partition in the new graph.
OUTPUT:
• if inplace is False: the unlabeled graph without multiple edges
sage: G = Graph(multiedges=True,sparse=True)
sage: G.add_edges((0, 1, i) for i in range(10))
sage: G.add_edge(1,2,'string')
sage: G.add_edge(2,123)
sage: graph_isom_equivalent_non_edge_labeled_graph(G, partition=[[0,123],[1,2]])
[Graph on 6 vertices, [[1, 0], [2, 3], [5], [4]]]
sage: g = graph_isom_equivalent_non_edge_labeled_graph(G,standard_label='string',
˓→return_edge_labels=True)
sage: g[0]
Graph on 6 vertices
sage: g[0].edges(sort=True)
[(0, 5, None), (1, 4, None), (2, 3, None), (2, 4, None), (3, 5, None)]
sage: g[1]
[[0, 1, 2, 3], [4], [5]]
sage: g[2]
[[['string', 1]], [[0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 1],␣
˓→[8, 1], [9, 1]], [[None, 1]]]
sage: G = Graph(multiedges=True,sparse=True)
sage: G.add_edges((0, 1) for i in range(10))
sage: G.add_edge(1, 2, 'a')
sage: G.add_edge(1, 3, 'b')
sage: G.add_edge(2, 3, 'b')
sage: graph_isom_equivalent_non_edge_labeled_graph(G)[0]
Graph on 8 vertices
sage: graph_isom_equivalent_non_edge_labeled_graph(G, ignore_edge_labels=True)[0]
Graph on 5 vertices
sage: G = Graph(multiedges=True,sparse=True)
sage: G.add_edges((0, 1, i) for i in range(5))
sage: G.add_edges((0, 2, i+10) for i in range(5))
sage: G.add_edges((0, 3) for i in range(4))
(continues on next page)
sage: G = graphs.TetrahedralGraph()
sage: from sage.graphs.generic_graph import tachyon_vertex_plot
sage: T,p = tachyon_vertex_plot(G, pos3d=G.layout(dim=3))
sage: type(T)
<class 'sage.plot.plot3d.tachyon.Tachyon'>
sage: type(p)
<... 'dict'>
Basic methods
bipartite_color() Return a dictionary with vertices as the keys and the color class as the values.
bipartite_double() Return the (extended) bipartite double of this graph.
bipartite_sets() Return (𝑋, 𝑌 ) where 𝑋 and 𝑌 are the nodes in each bipartite set of graph 𝐺.
graph6_string() Return the graph6 representation of the graph as an ASCII string.
is_directed() Since graph is undirected, returns False.
join() Return the join of self and other.
sparse6_string() Return the sparse6 representation of the graph as an ASCII string.
to_directed() Return a directed version of the graph.
to_undirected() Since the graph is already undirected, simply returns a copy of itself.
write_to_eps() Write a plot of the graph to filename in eps format.
Clique-related methods
Coloring
Computes an orientation of self such that every vertex 𝑣 has out-degree less
bounded_outdegree_orientation()
than 𝑏(𝑣)
bridges() Return an iterator over the bridges (or cut edges).
cleave() Return the connected subgraphs separated by the input vertex cut.
Returns a degree-constrained subgraph.
degree_constrained_subgraph()
ear_decomposition() Return an Ear decomposition of the graph.
gomory_hu_tree() Return a Gomory-Hu tree of self.
is_triconnected() Check whether the graph is triconnected.
Returns an orientation of self with the smallest possible maximum outdegree.
minimum_outdegree_orientation()
orientations() Return an iterator over orientations of self.
random_orientation() Return a random orientation of a graph 𝐺.
random_spanning_tree() Return a random spanning tree of the graph.
spanning_trees() Return an iterator over all spanning trees of the graph 𝑔.
spqr_tree() Return an SPQR-tree representing the triconnected components of the graph.
strong_orientation() Returns a strongly connected orientation of the current graph.
Returns an iterator over all strong orientations of a graph 𝐺.
strong_orientations_iterator()
Distances
Domination
Expansion properties
Graph properties
Leftovers
Traversals
lex_M() Return an ordering of the vertices according the LexM graph traversal.
Return an ordering of the vertices according a maximum cardinality search.
maximum_cardinality_search()
Return the ordering and the edges of the triangulation produced by MCS-M.
maximum_cardinality_search_M()
AUTHORS:
• Robert L. Miller (2006-10-22): initial version
• William Stein (2006-12-05): Editing
• Robert L. Miller (2007-01-13): refactoring, adjusting for NetworkX-0.33, fixed plotting bugs (2007-01-
23): basic tutorial, edge labels, loops, multiple edges and arcs (2007-02-07): graph6 and sparse6 formats,
matrix input
• Emily Kirkmann (2007-02-11): added graph_border option to plot and show
• Robert L. Miller (2007-02-12): vertex color-maps, graph boundaries, graph6 helper functions in Cython
• Robert L. Miller Sage Days 3 (2007-02-17-21): 3d plotting in Tachyon
• Robert L. Miller (2007-02-25): display a partition
• Robert L. Miller (2007-02-28): associate arbitrary objects to vertices, edge and arc label display (in 2d),
edge coloring
• Robert L. Miller (2007-03-21): Automorphism group, isomorphism check, canonical label
• Robert L. Miller (2007-06-07-09): NetworkX function wrapping
Supported formats
Sage Graphs can be created from a wide range of inputs. A few examples are covered here.
• NetworkX dictionary format:
• A NetworkX graph:
sage: s = ':I`AKGsaOs`cI]Gb~'
sage: G = Graph(s, sparse=True); G
Looped multi-graph on 10 vertices
sage: G.plot().show() # or G.show()
Note that the \ character is an escape character in Python, and also a character used by graph6 strings:
sage: G = Graph('Ihe\n@GUA')
Traceback (most recent call last):
...
RuntimeError: the string (Ihe) seems corrupt: for n = 10, the string is too␣
˓→short
sage: G = Graph('Ihe\\n@GUA')
sage: G.plot().show() # or G.show()
• adjacency matrix: In an adjacency matrix, each column and each row represent a vertex. If a 1 shows up
in row 𝑖, column 𝑗, there is an edge (𝑖, 𝑗).
sage: M = Matrix([(0,1,0,0,1,1,0,0,0,0),(1,0,1,0,0,0,1,0,0,0), \
(0,1,0,1,0,0,0,1,0,0), (0,0,1,0,1,0,0,0,1,0),(1,0,0,1,0,0,0,0,0,1), \
(1,0,0,0,0,0,0,1,1,0), (0,1,0,0,0,0,0,0,1,1),(0,0,1,0,0,1,0,0,0,1), \
(0,0,0,1,0,1,1,0,0,0), (0,0,0,0,1,0,1,1,0,0)])
sage: M
[0 1 0 0 1 1 0 0 0 0]
[1 0 1 0 0 0 1 0 0 0]
[0 1 0 1 0 0 0 1 0 0]
[0 0 1 0 1 0 0 0 1 0]
[1 0 0 1 0 0 0 0 0 1]
[1 0 0 0 0 0 0 1 1 0]
[0 1 0 0 0 0 0 0 1 1]
[0 0 1 0 0 1 0 0 0 1]
[0 0 0 1 0 1 1 0 0 0]
[0 0 0 0 1 0 1 1 0 0]
sage: G = Graph(M); G
(continues on next page)
• incidence matrix: In an incidence matrix, each row represents a vertex and each column represents an
edge.
• a list of edges:
sage: g = Graph([(1,3),(3,8),(5,2)])
sage: g
Graph on 5 vertices
• an igraph Graph:
1.2.2 Generators
Similarly graphs() will iterate through all graphs. The complete graph of 4 vertices is of course the smallest graph
with chromatic number bigger than three:
and hit {tab}. Most of these graphs come with their own custom plot, so you can see how people usually visualize
these graphs.
sage: G = graphs.PetersenGraph()
sage: G.plot().show() # or G.show()
sage: G.degree_histogram()
[0, 0, 0, 10]
sage: G.adjacency_matrix()
[0 1 0 0 1 1 0 0 0 0]
[1 0 1 0 0 0 1 0 0 0]
[0 1 0 1 0 0 0 1 0 0]
[0 0 1 0 1 0 0 0 1 0]
[1 0 0 1 0 0 0 0 0 1]
[1 0 0 0 0 0 0 1 1 0]
[0 1 0 0 0 0 0 0 1 1]
[0 0 1 0 0 1 0 0 0 1]
[0 0 0 1 0 1 1 0 0 0]
[0 0 0 0 1 0 1 1 0 0]
sage: S = G.subgraph([0,1,2,3])
sage: S.plot().show() # or S.show()
sage: S.density()
1/2
1.2.3 Labels
Each vertex can have any hashable object as a label. These are things like strings, numbers, and tuples. Each edge
is given a default label of None, but if specified, edges can have any label at all. Edges between vertices 𝑢 and 𝑣 are
represented typically as (u, v, l), where l is the label for the edge.
Note that vertex labels themselves cannot be mutable items:
However, if one wants to define a dictionary, with the same keys and arbitrary objects for entries, one can make that
association:
1.2.4 Database
There is a database available for searching for graphs that satisfy a certain set of parameters, including number of
vertices and edges, density, maximum and minimum degree, diameter, radius, and connectivity. To see a list of all
search parameter keywords broken down by their designated table names, type
sage: graph_db_info()
{...}
The results of a query can be viewed with the show method, or can be viewed individually by iterating through the
results
sage: for g in Q:
....: show(g)
1.2.5 Visualization
To see a graph 𝐺 you are working with, there are three main options. You can view the graph in two dimensions via
matplotlib with show().
sage: G = graphs.RandomGNP(15,.3)
sage: G.show()
And you can view it in three dimensions via jmol with show3d().
sage: G.show3d()
Or it can be rendered with LATEX. This requires the right additions to a standard TEX installation. Then standard Sage
commands, such as view(G) will display the graph, or latex(G) will produce a string suitable for inclusion in a LATEX
document. More details on this are at the sage.graphs.graph_latex module.
1.2.6 Mutability
Graphs are mutable, and thus unusable as dictionary keys, unless data_structure="static_sparse" is used:
sage: G = graphs.PetersenGraph()
sage: {G:1}[G]
Traceback (most recent call last):
...
TypeError: This graph is mutable, and thus not hashable. Create an immutable copy by `g.
˓→copy(immutable=True)`
1.2.7 Methods
{0: [-1,-1],
1: [ 1,-1],
2: [ 1, 1],
3: [-1, 1]}
• name – (must be an explicitly named parameter, i.e., name="complete") gives the graph a name
• loops – boolean (default: None); whether to allow loops (ignored if data is an instance of the Graph
class)
• multiedges – boolean (default: None); whether to allow multiple edges (ignored if data is an instance
of the Graph class).
• weighted – boolean (default: None); whether graph thinks of itself as weighted or not. See weighted().
• format – if set to None (default), Graph tries to guess input’s format. To avoid this possibly time-
consuming step, one of the following values can be specified (see description above): "int",
"graph6", "sparse6", "rule", "list_of_edges", "dict_of_lists", "dict_of_dicts",
"adjacency_matrix", "weighted_adjacency_matrix", "seidel_adjacency_matrix",
"incidence_matrix", "NX", "igraph".
• sparse – boolean (default: True); sparse=True is an alias for data_structure="sparse", and
sparse=False is an alias for data_structure="dense".
• data_structure – one of the following (for more information, see overview)
– "dense" – selects the dense_graph backend.
– "sparse" – selects the sparse_graph backend.
– "static_sparse" – selects the static_sparse_backend (this backend is faster than the sparse
backend and smaller in memory, and it is immutable, so that the resulting graphs can be used as
dictionary keys).
• immutable – boolean (default: False); whether to create a immutable graph. Note that immutable=True
is actually a shortcut for data_structure='static_sparse'. Set to False by default.
• vertex_labels – boolean (default: True); whether to allow any object as a vertex (slower), or only the
integers 0, ..., 𝑛 − 1, where 𝑛 is the number of vertices.
• convert_empty_dict_labels_to_None – this arguments sets the default edge labels used by Net-
workX (empty dictionaries) to be replaced by None, the default Sage edge label. It is set to True
iff a NetworkX graph is on the input.
EXAMPLES:
We illustrate the first seven input formats (the other two involve packages that are currently not standard in Sage):
1. An integer giving the number of vertices:
sage: g = Graph(5); g
Graph on 5 vertices
sage: g.vertices(sort=True)
[0, 1, 2, 3, 4]
sage: g.edges(sort=False)
[]
2. A dictionary of dictionaries:
The labels (‘x’, ‘z’, ‘a’, ‘out’) are labels for edges. For example, ‘out’ is the label for the edge on 2 and 5.
Labels can be used as weights, if all the labels share some common parent.:
Graph on 4 vertices
3. A dictionary of lists:
4. A list of vertices and a function describing adjacencies. Note that the list of vertices and the function must
be enclosed in a list (i.e., [list of vertices, function]).
Construct the Paley graph over GF(13).:
sage: g=graphs.CompleteGraph(4)
sage: line_graph=Graph([g.edges(sort=True, labels=false), \
lambda i,j: len(set(i).intersection(set(j)))>0], \
loops=False)
sage: line_graph.vertices(sort=True)
[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
sage: line_graph.adjacency_matrix()
[0 1 1 1 1 0]
[1 0 1 1 0 1]
[1 1 0 0 1 1]
[1 1 0 0 1 1]
[1 0 1 1 0 1]
[0 1 1 1 1 0]
5. A graph6 or sparse6 string: Sage automatically recognizes whether a string is in graph6 or sparse6 format:
sage: s = ':I`AKGsaOs`cI]Gb~'
sage: Graph(s,sparse=True)
Looped multi-graph on 10 vertices
sage: G = Graph('G?????')
sage: G = Graph("G'?G?C")
Traceback (most recent call last):
...
RuntimeError: the string seems corrupt: valid characters are
?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
sage: G = Graph('G??????')
Traceback (most recent call last):
...
RuntimeError: the string (G??????) seems corrupt: for n = 8, the string is too␣
˓→long
sage: G = Graph(":I'AKGsaOs`cI]Gb~")
Traceback (most recent call last):
...
RuntimeError: the string seems corrupt: valid characters are
?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
sage: s = ':IgMoqoCUOqeb\n:I`AKGsaOs`cI]Gb~\n:I`EDOAEQ?PccSsge\\N\n'
sage: graphs_list.from_sparse6(s)
[Looped multi-graph on 10 vertices, Looped multi-graph on 10 vertices, Looped␣
˓→multi-graph on 10 vertices]
6. A Sage matrix: Note: If format is not specified, then Sage assumes a symmetric square matrix is an adja-
cency matrix, otherwise an incidence matrix.
• an adjacency matrix:
sage: M = graphs.PetersenGraph().am(); M
[0 1 0 0 1 1 0 0 0 0]
[1 0 1 0 0 0 1 0 0 0]
[0 1 0 1 0 0 0 1 0 0]
[0 0 1 0 1 0 0 0 1 0]
[1 0 0 1 0 0 0 0 0 1]
[1 0 0 0 0 0 0 1 1 0]
[0 1 0 0 0 0 0 0 1 1]
[0 0 1 0 0 1 0 0 0 1]
[0 0 0 1 0 1 1 0 0 0]
[0 0 0 0 1 0 1 1 0 0]
sage: Graph(M)
Graph on 10 vertices
sage: Graph(matrix([[1,2],[2,4]]),loops=True,sparse=True)
Looped multi-graph on 2 vertices
sage: M = Matrix([[0,1,-1],[1,0,-1/2],[-1,-1/2,0]]); M
[ 0 1 -1]
[ 1 0 -1/2]
[ -1 -1/2 0]
sage: G = Graph(M,sparse=True); G
Graph on 3 vertices
sage: G.weighted()
True
• an incidence matrix:
[-1 0 0 0 1]
[ 1 -1 0 0 0]
[ 0 1 -1 0 0]
[ 0 0 1 -1 0]
[ 0 0 0 1 -1]
[ 0 0 0 0 0]
sage: Graph(M)
Graph on 6 vertices
sage: Graph(Matrix([[1],[1],[1]]))
Traceback (most recent call last):
...
ValueError: there must be one or two nonzero entries per column in an␣
˓→incidence matrix, got entries [1, 1, 1] in column 0
sage: Graph(Matrix([[1],[1],[0]]))
Graph on 3 vertices
sage: M = Matrix([[0,1,-1],[1,0,-1],[-1,-1,0]]); M
[ 0 1 -1]
[ 1 0 -1]
[-1 -1 0]
(continues on next page)
sage: M = Matrix([[0,1,1],[1,0,1],[-1,-1,0]]); M
[ 0 1 1]
[ 1 0 1]
[-1 -1 0]
sage: Graph(M)
Traceback (most recent call last):
...
ValueError: there must be one or two nonzero entries per column in an␣
˓→incidence matrix, got entries [1, 1] in column 2
(16, 6, 2, 2)
sage: g.loops()
(continues on next page)
9. A NetworkX MultiGraph:
If vertex_labels is True, the names of the vertices are given by the vertex attribute 'name', if available:
sage: Graph(g).vertices(sort=True) #␣
˓→optional - python_igraph
sage: Graph(g).vertices(sort=True) #␣
˓→optional - python_igraph
[0, 1, 2]
If the igraph Graph has edge attributes, they are used as edge labels:
sage: Graph(g).edges(sort=True) ␣
˓→ # optional - python_igraph
[(0, 1, {'name': 'a', 'weight': 1}), (0, 2, {'name': 'b', 'weight': 3})]
When defining an undirected graph from a function f, it is very important that f be symmetric. If it is not,
anything can happen:
By default, graphs are mutable and can thus not be used as a dictionary key:
sage: G = graphs.PetersenGraph()
sage: {G:1}[G]
Traceback (most recent call last):
...
TypeError: This graph is mutable, and thus not hashable. Create an immutable copy␣
˓→by `g.copy(immutable=True)`
Note: Currently only implemented for undirected graphs. Use to_undirected() to convert a digraph to
an undirected graph.
INPUT:
• min_size – integer (default: 0); minimum size of reported cliques. When set to 0 (default), this
method searches for maximum cliques. In such case, parameter max_size must also be set to 0.
• max_size – integer (default: 0); maximum size of reported cliques. When set to 0 (default), the
maximum size of the cliques is unbounded. When min_size is set to 0, this parameter must be set to
0.
ALGORITHM:
This function is based on Cliquer [NO2003].
EXAMPLES:
sage: G = graphs.CompleteGraph(5)
sage: list(sage.graphs.cliquer.all_cliques(G))
[[0, 1, 2, 3, 4]]
sage: list(sage.graphs.cliquer.all_cliques(G, 2, 3))
[[3, 4],
(continues on next page)
Todo: Use the re-entrant functionality of Cliquer [NO2003] to avoid storing all cliques.
antipodal_graph()
Return the antipodal graph of self.
The antipodal graph of a graph 𝐺 has the same vertex set of 𝐺 and two vertices are adjacent if their distance
in 𝐺 is equal to the diameter of 𝐺.
OUTPUT:
A new graph. self is not touched.
EXAMPLES:
sage: G = graphs.JohnsonGraph(10, 5)
sage: G.antipodal_graph()
Antipodal graph of Johnson graph with parameters 10,5: Graph on 252 vertices
sage: G = graphs.HammingGraph(8, 2)
sage: G.antipodal_graph()
Antipodal graph of Hamming Graph with parameters 8,2: Graph on 256 vertices
sage: G = Graph(5)
sage: H = G.antipodal_graph()
sage: H.is_isomorphic(G.complement())
True
apex_vertices(k=None)
Return the list of apex vertices.
A graph is apex if it can be made planar by the removal of a single vertex. The deleted vertex is called
an apex of the graph, and a graph may have more than one apex. For instance, in the minimal nonplanar
graphs 𝐾5 or 𝐾3,3 , every vertex is an apex. The apex graphs include graphs that are themselves planar,
in which case again every vertex is an apex. The null graph is also counted as an apex graph even though
it has no vertex to remove. If the graph is not connected, we say that it is apex if it has at most one non
planar connected component and that this component is apex. See the Wikipedia article Apex_graph for
more information.
See also:
• is_apex()
• is_planar()
INPUT:
• k – integer (default: None); when set to None, the method returns the list of all apex of the graph,
possibly empty if the graph is not apex. When set to a positive integer, the method ends as soon as 𝑘
apex vertices are found.
OUTPUT:
By default, the method returns the list of all apex of the graph. When parameter k is set to a positive integer,
the returned list is bounded to 𝑘 apex vertices.
EXAMPLES:
𝐾5 and 𝐾3,3 are apex graphs, and each of their vertices is an apex:
sage: G = graphs.CompleteGraph(5)
sage: G.apex_vertices()
[0, 1, 2, 3, 4]
sage: G = graphs.CompleteBipartiteGraph(3,3)
sage: G.is_apex()
True
sage: G.apex_vertices()
[0, 1, 2, 3, 4, 5]
sage: G.apex_vertices(k=3)
[0, 1, 2]
A4
𝑡𝑖𝑚𝑒𝑠4-grid is apex and each of its vertices is an apex. When adding a universal vertex, the resulting graph
is apex and the universal vertex is the unique apex vertex
sage: G = graphs.Grid2dGraph(4,4)
sage: set(G.apex_vertices()) == set(G.vertices(sort=False))
True
sage: G.add_edges([('universal',v) for v in G])
sage: G.apex_vertices()
['universal']
sage: G = graphs.PetersenGraph()
sage: G.apex_vertices()
[]
A graph is apex if all its connected components are apex, but at most one is not planar:
sage: M = graphs.Grid2dGraph(3,3)
sage: K5 = graphs.CompleteGraph(5)
sage: (M+K5).apex_vertices()
[9, 10, 11, 12, 13]
sage: (M+K5+K5).apex_vertices()
[]
sage: G = graphs.Grid2dGraph(5,5)
sage: v = (666, 666)
sage: G.add_path([(1, 1), v, (3, 3)])
sage: G.is_planar()
False
sage: G.degree(v)
2
sage: sorted(G.apex_vertices())
[(1, 1), (2, 2), (3, 3), (666, 666)]
arboricity(certificate=False)
Return the arboricity of the graph and an optional certificate.
The arboricity is the minimum number of forests that covers the graph.
See Wikipedia article Arboricity
INPUT:
• certificate – boolean (default: False); whether to return a certificate.
OUTPUT:
When certificate = True, then the function returns (𝑎, 𝐹 ) where 𝑎 is the arboricity and 𝐹 is a list of
𝑎 disjoint forests that partitions the edge set of 𝑔. The forests are represented as subgraphs of the original
graph.
If certificate = False, the function returns just a integer indicating the arboricity.
ALGORITHM:
Represent the graph as a graphical matroid, then apply matroid sage.matroid.partition() algorithm
from the matroids module.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: a,F = G.arboricity(True)
sage: a
2
sage: all([f.is_forest() for f in F])
True
sage: len(set.union(*[set(f.edges(sort=False)) for f in F])) == G.size()
True
sage: G = Graph({'a': ['b', 'k'], 'b': ['c'], 'c': ['d', 'j', 'k'],
....: 'd': ['e', 'f', 'j', 'k'], 'e': ['g'],
....: 'f': ['g', 'j', 'k'], 'g': ['j', 'k'], 'h': ['i', 'j'],
....: 'i': ['k'], 'j': ['k']})
sage: atoms, cliques = G.atoms_and_clique_separators()
sage: sorted(sorted(a) for a in atoms)
[['a', 'b', 'c', 'k'],
['c', 'd', 'j', 'k'],
['d', 'e', 'f', 'g', 'j', 'k'],
['h', 'i', 'j', 'k']]
sage: sorted(sorted(c) for c in cliques)
[['c', 'k'], ['d', 'j', 'k'], ['j', 'k']]
sage: T = G.atoms_and_clique_separators(tree=True)
sage: T.is_tree()
True
sage: T.diameter() == len(atoms)
True
sage: all(u[1] in atoms for u in T if T.degree(u) == 1)
True
(continues on next page)
sage: G = graphs.WindmillGraph(3, 4)
sage: G.atoms_and_clique_separators()
([{0, 1, 2}, {0, 3, 4}, {0, 5, 6}, {0, 8, 7}], [{0}, {0}, {0}])
sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
________{0}________
/ /
{0, 1, 2} _______{0}______
/ /
{0, 3, 4} ____{0}___
/ /
{0, 8, 7} {0, 5, 6}
When the removal of a clique separator results in 𝑘 > 2 connected components, this separator is repeated
𝑘 − 1 times, but the repetitions are not necessarily contiguous:
sage: G = Graph(2)
sage: for i in range(5):
....: G.add_cycle([0, 1, G.add_vertex()])
sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
_________{0, 1}_____
/ /
{0, 1, 4} ________{0, 1}_____
/ /
{0, 1, 2} _______{0, 1}___
/ /
{0, 1, 3} ____{0, 1}
/ /
{0, 1, 5} {0, 1, 6}
sage: G = graphs.StarGraph(3)
sage: G.subdivide_edges(G.edges(sort=False), 2)
sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
(continues on next page)
If the graph is not connected, we insert empty separators between the lists of separators of each connected
components. For instance, let 𝐺 be a graph with 3 connected components. The method returns the list
𝑆𝑐 = [𝑆0 , · · · , 𝑆𝑖 , . . . , 𝑆𝑗 , . . . , 𝑆𝑘−1 ] of 𝑘 clique separators, where 𝑖 and 𝑗 are the indexes of the inserted
empty separators and 0 ≤ 𝑖 < 𝑗 < 𝑘 − 1. The method also returns the list 𝐴 = [𝐴0 , . . . , 𝑆𝑘 ] of the 𝑘 + 1
atoms, with 𝑘 + 1 ≥ 3. The lists of atoms and clique separators of each of the connected components are
respectively [𝐴0 , . . . , 𝐴𝑖 ] and [𝑆0 , . . . , 𝑆𝑖−1 ], [𝐴𝑖+1 , . . . , 𝐴𝑗 ] and [𝑆𝑖+1 , . . . , 𝑆𝑗−1 ], and [𝐴𝑗+1 , . . . , 𝐴𝑘 ]
and [𝑆𝑗+1 , . . . , 𝑆𝑘−1 ]. One can check that for each connected component, we get one atom more than
clique separators:
sage: G = graphs.PathGraph(3) * 3
sage: A, Sc = G.atoms_and_clique_separators()
sage: A
[{1, 2}, {0, 1}, {4, 5}, {3, 4}, {8, 7}, {6, 7}]
sage: Sc
[{1}, {}, {4}, {}, {7}]
sage: i , j = [i for i, s in enumerate(Sc) if not s]
sage: i, j
(1, 3)
sage: A[:i+1], Sc[:i]
([{1, 2}, {0, 1}], [{1}])
sage: A[i+1:j+1], Sc[i+1:j]
([{4, 5}, {3, 4}], [{4}])
sage: A[j+1:], Sc[j+1:]
([{8, 7}, {6, 7}], [{7}])
sage: I = [-1, i, j, len(Sc)]
sage: for i, j in zip(I[:-1], I[1:]):
....: print(A[i+1:j+1], Sc[i+1:j])
[{1, 2}, {0, 1}] [{1}]
[{4, 5}, {3, 4}] [{4}]
[{8, 7}, {6, 7}] [{7}]
sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
______{1}______
/ /
{1, 2} ______{}______
(continues on next page)
sage: G.allow_loops(True)
sage: G.add_edges([(u, u) for u in G])
sage: G.allow_multiple_edges(True)
sage: G.add_edges(G.edges(sort=False))
sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
______{1}______
/ /
{1, 2} ______{}______
/ /
{0, 1} _____{4}_____
/ /
{4, 5} ____{}_____
/ /
{3, 4} __{7}__
/ /
{6, 7} {8, 7}
bipartite_color()
Return a dictionary with vertices as the keys and the color class as the values.
Fails with an error if the graph is not bipartite.
EXAMPLES:
sage: graphs.CycleGraph(4).bipartite_color()
{0: 1, 1: 0, 2: 1, 3: 0}
sage: graphs.CycleGraph(5).bipartite_color()
Traceback (most recent call last):
...
RuntimeError: Graph is not bipartite.
bipartite_double(extended=False)
Return the (extended) bipartite double of this graph.
The bipartite double of a graph 𝐺 has vertex set {(𝑣, 0), (𝑣, 1) : 𝑣 ∈ 𝐺} and for any edge (𝑢, 𝑣) in 𝐺 it has
edges ((𝑢, 0), (𝑣, 1)) and ((𝑢, 1), (𝑣, 0)). Note that this is the tensor product of 𝐺 with 𝐾2 .
The extended bipartite double of 𝐺 is the bipartite double of 𝐺 after added all edges ((𝑣, 0), (𝑣, 1)) for all
vertices 𝑣.
INPUT:
• extended – boolean (default: False); Whether to return the extended bipartite double, or only the
bipartite double (default)
OUTPUT:
A graph; self is left untouched.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: H = G.bipartite_double()
sage: G == graphs.PetersenGraph() # G is left invariant
True
sage: H.order() == 2 * G.order()
True
sage: H.size() == 2 * G.size()
True
sage: H.is_bipartite()
True
sage: H.bipartite_sets() == (set([(v, 0) for v in G]),
....: set([(v, 1) for v in G]))
True
sage: H.is_isomorphic(G.tensor_product(graphs.CompleteGraph(2)))
True
sage: G1 = graphs.PetersenGraph()
sage: G2 = graphs.HoffmanGraph()
sage: G = G1.disjoint_union(G2)
sage: H = G.bipartite_double()
sage: H1 = G1.bipartite_double()
sage: H2 = G2.bipartite_double()
sage: H.is_isomorphic(H1.disjoint_union(H2))
True
See also:
Wikipedia article Bipartite_double_cover, WolframAlpha Bipartite Double, [VDKT2016] p. 20 for the
extended bipartite double.
bipartite_sets()
Return (𝑋, 𝑌 ) where 𝑋 and 𝑌 are the nodes in each bipartite set of graph 𝐺.
Fails with an error if graph is not bipartite.
EXAMPLES:
sage: graphs.CycleGraph(4).bipartite_sets()
({0, 2}, {1, 3})
sage: graphs.CycleGraph(5).bipartite_sets()
Traceback (most recent call last):
...
RuntimeError: Graph is not bipartite.
• An integer 𝑘. In this case, computes an orientation whose maximum out-degree is less than 𝑘.
• A dictionary associating to each vertex its associated maximum out-degree.
• A function associating to each vertex its associated maximum out-degree.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
OUTPUT:
A DiGraph representing the orientation if it exists. A ValueError exception is raised otherwise.
ALGORITHM:
The problem is solved through a maximum flow :
Given a graph 𝐺, we create a DiGraph 𝐷 defined on 𝐸(𝐺) ∪ 𝑉 (𝐺) ∪ {𝑠, 𝑡}. We then link 𝑠 to all of 𝑉 (𝐺)
(these edges having a capacity equal to the bound associated to each element of 𝑉 (𝐺)), and all the elements
of 𝐸(𝐺) to 𝑡 . We then link each 𝑣 ∈ 𝑉 (𝐺) to each of its incident edges in 𝐺. A maximum integer flow of
value |𝐸(𝐺)| corresponds to an admissible orientation of 𝐺. Otherwise, none exists.
EXAMPLES:
There is always an orientation of a graph 𝐺 such that a vertex 𝑣 has out-degree at most ⌈ 𝑑(𝑣)
2 ⌉:
Chvatal’s graph, being 4-regular, can be oriented in such a way that its maximum out-degree is 2:
sage: g = graphs.ChvatalGraph()
sage: D = g.bounded_outdegree_orientation(2)
sage: max(D.out_degree())
2
For any graph 𝐺, it is possible to compute an orientation such that the maximum out-degree is at most the
maximum average degree of 𝐺 divided by 2. Anything less, though, is impossible.
sage: g = graphs.RandomGNP(40, .4) sage: mad = g.maximum_average_degree()
Hence this is possible
sage: d = g.bounded_outdegree_orientation(integer_ceil(mad/2))
sage: try:
....: g.bounded_outdegree_orientation(integer_ceil(mad/2-1))
....: print("Error")
....: except ValueError:
....: pass
bridges(G, labels=True)
Return an iterator over the bridges (or cut edges).
A bridge is an edge whose deletion disconnects the undirected graph. A disconnected graph has no bridge.
INPUT:
• labels – boolean (default: True); if False, each bridge is a tuple (𝑢, 𝑣) of vertices
EXAMPLES:
sage: g = graphs.RandomTree(100)
sage: sum(1 for _ in g.bridges()) == 99
True
• weight_function – function (default: None); a function that takes as input an edge (u, v, l) and
outputs its weight. If not None, by_weight is automatically set to True. If None and by_weight is
True, we use the edge label l as a weight, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs a
number for each edge
EXAMPLES:
Is Central African Republic in the center of Africa in graph theoretic sense? Yes:
sage: A = graphs.AfricaMap(continental=True)
sage: sorted(A.center())
['Cameroon', 'Central Africa']
sage: G = graphs.DiamondGraph()
sage: G.center()
[1, 2]
sage: P = graphs.PetersenGraph()
sage: P.subgraph(P.center()) == P
True
sage: S = graphs.StarGraph(19)
sage: S.center()
[0]
centrality_degree(v=None)
Return the degree centrality of a vertex.
The degree centrality of a vertex 𝑣 is its degree, divided by |𝑉 (𝐺)| − 1. For more information, see the
Wikipedia article Centrality.
INPUT:
• v – a vertex (default: None); set to None (default) to get a dictionary associating each vertex with its
centrality degree.
See also:
• centrality_closeness()
• centrality_betweenness()
EXAMPLES:
sage: (graphs.ChvatalGraph()).centrality_degree()
{0: 4/11, 1: 4/11, 2: 4/11, 3: 4/11, 4: 4/11, 5: 4/11,
6: 4/11, 7: 4/11, 8: 4/11, 9: 4/11, 10: 4/11, 11: 4/11}
sage: D = graphs.DiamondGraph()
sage: D.centrality_degree()
{0: 2/3, 1: 1, 2: 1, 3: 2/3}
sage: D.centrality_degree(v=1)
1
cheeger_constant(g)
Return the cheeger constant of the graph.
The Cheeger constant of a graph 𝐺 = (𝑉, 𝐸) is the minimum of |𝜕𝑆|/|𝑉 𝑜𝑙(𝑆)| where 𝑉 𝑜𝑙(𝑆) is the sum
of degrees of element in 𝑆, 𝜕𝑆 is the edge boundary of 𝑆 (number of edges with one end in 𝑆 and one end
in 𝑉 ∖ 𝑆) and the minimum is taken over all non-empty subsets 𝑆 of vertices so that |𝑉 𝑜𝑙(𝑆)| ≤ |𝐸|.
See also:
Alternative but similar quantities can be obtained via the methods edge_isoperimetric_number() and
vertex_isoperimetric_number().
EXAMPLES:
sage: graphs.PetersenGraph().cheeger_constant()
1/3
[3/5, 1/2, 3/5, 5/9, 4/7, 5/9, 1/2, 5/9, 1/2, 5/9]
More examples:
sage: G = Graph([(0, 1), (0, 3), (0, 8), (1, 4), (1, 6), (2, 4), (2, 7), (2, 9),
....: (3, 6), (3, 8), (4, 9), (5, 6), (5, 7), (5, 8), (7, 9)])
sage: G.cheeger_constant()
1/6
sage: G = Graph([(0, 1), (0, 2), (1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (3, 4),
˓→ (3, 5)])
sage: G.cheeger_constant()
1/2
sage: Graph([[1,2,3,4],[(1,2),(3,4)]]).cheeger_constant()
0
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
This method is a frontend for method sage.graphs.graph_coloring.edge_coloring() that uses a
mixed integer-linear programming formulation to compute the chromatic index.
See also:
EXAMPLES:
The clique 𝐾𝑛 has chromatic index 𝑛 when 𝑛 is odd and 𝑛 − 1 when 𝑛 is even:
sage: graphs.CompleteGraph(4).chromatic_index()
3
sage: graphs.CompleteGraph(5).chromatic_index()
5
sage: graphs.CompleteGraph(6).chromatic_index()
5
sage: graphs.PathGraph(5).chromatic_index()
2
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
See also:
For more functions related to graph coloring, see the module sage.graphs.graph_coloring.
EXAMPLES:
sage: graphs.RandomBipartite(50,50,0.7).chromatic_number()
2
True
The complete graph has the largest chromatic number from all the graphs of order 𝑛. Namely its chromatic
number is 𝑛:
The Kneser graph with parameters (𝑛, 2) for 𝑛 > 3 has chromatic number 𝑛 − 2:
The Flower Snark graph has chromatic index 4 hence its line graph has chromatic number 4:
sage: graphs.FlowerSnark().line_graph().chromatic_number()
4
sage: graphs.CycleGraph(4).chromatic_polynomial()
x^4 - 4*x^3 + 6*x^2 - 3*x
sage: graphs.CycleGraph(3).chromatic_polynomial()
x^3 - 3*x^2 + 2*x
sage: graphs.CubeGraph(3).chromatic_polynomial()
x^8 - 12*x^7 + 66*x^6 - 214*x^5 + 441*x^4 - 572*x^3 + 423*x^2 - 133*x
sage: graphs.PetersenGraph().chromatic_polynomial()
x^10 - 15*x^9 + 105*x^8 - 455*x^7 + 1353*x^6 - 2861*x^5 + 4275*x^4 - 4305*x^3 +␣
˓→2606*x^2 - 704*x
sage: graphs.CompleteBipartiteGraph(3,3).chromatic_polynomial()
x^6 - 9*x^5 + 36*x^4 - 75*x^3 + 78*x^2 - 31*x
sage: for i in range(2,7):
....: graphs.CompleteGraph(i).chromatic_polynomial().factor()
(x - 1) * x
(x - 2) * (x - 1) * x
(x - 3) * (x - 2) * (x - 1) * x
(x - 4) * (x - 3) * (x - 2) * (x - 1) * x
(x - 5) * (x - 4) * (x - 3) * (x - 2) * (x - 1) * x
sage: graphs.CycleGraph(5).chromatic_polynomial().factor()
(x - 2) * (x - 1) * x * (x^2 - 2*x + 2)
sage: graphs.OctahedralGraph().chromatic_polynomial().factor()
(x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32)
sage: graphs.WheelGraph(5).chromatic_polynomial().factor()
(x - 2) * (x - 1) * x * (x^2 - 5*x + 7)
sage: graphs.WheelGraph(6).chromatic_polynomial().factor()
(x - 3) * (x - 2) * (x - 1) * x * (x^2 - 4*x + 5)
sage: C(x)=graphs.LCFGraph(24, [12,7,-7], 8).chromatic_polynomial() # long␣
˓→time (6s on sage.math, 2011)
By definition, the chromatic number of a graph G is the least integer k such that the chromatic polynomial
of G is strictly positive at k:
sage: G = graphs.PetersenGraph()
sage: P = G.chromatic_polynomial()
sage: min(i for i in range(11) if P(i) > 0) == G.chromatic_number()
True
sage: G = graphs.RandomGNP(10,0.7)
(continues on next page)
Check that algorithms "C" and "Python" return the same results:
chromatic_quasisymmetric_function(t=None, R=None)
Return the chromatic quasisymmetric function of self.
Let 𝐺 be a graph whose vertex set is totally ordered. The chromatic quasisymmetric function 𝑋𝐺 (𝑡) was
first described in [SW2012]. We use the equivalent definition given in [BC2018]:
∑︁
𝑋𝐺 (𝑡) = 𝑡asc(𝜎) 𝑀|𝜎1 |,...,|𝜎𝑛 | ,
𝜎=(𝜎1 ,...,𝜎𝑛 )
where we sum over all ordered set partitions of the vertex set of 𝐺 such that each block 𝜎𝑖 is an independent
(i.e., stable) set of 𝐺, and where asc(𝜎) denotes the number of edges {𝑢, 𝑣} of 𝐺 such that 𝑢 < 𝑣 and 𝑣
appears in a later part of 𝜎 than 𝑢.
INPUT:
• t – (optional) the parameter 𝑡; uses the variable 𝑡 in Z[𝑡] by default
• R – (optional) the base ring for the quasisymmetric functions; uses the parent of 𝑡 by default
EXAMPLES:
sage: p = SymmetricFunctions(QQ).p()
sage: G = graphs.CycleGraph(5)
sage: XG = G.chromatic_quasisymmetric_function(t=1); XG
120*M[1, 1, 1, 1, 1] + 30*M[1, 1, 1, 2] + 30*M[1, 1, 2, 1]
+ 30*M[1, 2, 1, 1] + 10*M[1, 2, 2] + 30*M[2, 1, 1, 1]
+ 10*M[2, 1, 2] + 10*M[2, 2, 1]
sage: p(XG.to_symmetric_function())
p[1, 1, 1, 1, 1] - 5*p[2, 1, 1, 1] + 5*p[2, 2, 1]
+ 5*p[3, 1, 1] - 5*p[3, 2] - 5*p[4, 1] + 4*p[5]
sage: G = graphs.ClawGraph()
sage: XG = G.chromatic_quasisymmetric_function(t=1); XG
24*M[1, 1, 1, 1] + 6*M[1, 1, 2] + 6*M[1, 2, 1] + M[1, 3]
+ 6*M[2, 1, 1] + M[3, 1]
sage: p(XG.to_symmetric_function())
p[1, 1, 1, 1] - 3*p[2, 1, 1] + 3*p[3, 1] - p[4]
chromatic_symmetric_function(R=None)
Return the chromatic symmetric function of self.
Let 𝐺 be a graph. The chromatic symmetric function 𝑋𝐺 was described in [Sta1995], specifically Theorem
2.5 states that
∑︁
𝑋𝐺 = (−1)|𝐹 | 𝑝𝜆(𝐹 ) ,
𝐹 ⊆𝐸(𝐺)
where 𝜆(𝐹 ) is the partition of the sizes of the connected components of the subgraph induced by the edges
𝐹 and 𝑝𝜇 is the powersum symmetric function.
INPUT:
• R – (optional) the base ring for the symmetric functions; this uses Z by default
EXAMPLES:
sage: s = SymmetricFunctions(ZZ).s()
sage: G = graphs.CycleGraph(5)
sage: XG = G.chromatic_symmetric_function(); XG
p[1, 1, 1, 1, 1] - 5*p[2, 1, 1, 1] + 5*p[2, 2, 1]
+ 5*p[3, 1, 1] - 5*p[3, 2] - 5*p[4, 1] + 4*p[5]
sage: s(XG)
30*s[1, 1, 1, 1, 1] + 10*s[2, 1, 1, 1] + 10*s[2, 2, 1]
sage: G = graphs.ClawGraph()
sage: XG = G.chromatic_symmetric_function(); XG
p[1, 1, 1, 1] - 3*p[2, 1, 1] + 3*p[3, 1] - p[4]
sage: s(XG)
8*s[1, 1, 1, 1] + 5*s[2, 1, 1] - s[2, 2] + s[3, 1]
We show that given a triangle {𝑒1 , 𝑒2 , 𝑒3 }, we have 𝑋𝐺 = 𝑋𝐺−𝑒1 + 𝑋𝐺−𝑒2 − 𝑋𝐺−𝑒1 −𝑒2 :
sage: G = Graph([[1,2],[1,3],[2,3]])
sage: XG = G.chromatic_symmetric_function()
sage: G1 = copy(G)
(continues on next page)
sage: G.delete_edge(0, 1)
sage: S1,C1,f1 = cleave(G, cut_vertices=[0, 1])
sage: [g.order() for g in S1]
[4, 4, 4]
sage: C1.order(), C1.size()
(2, 3)
sage: f1.vertices(sort=True), f1.edges(sort=True)
([0, 1], [(0, 1, None)])
If virtual_edges == False and the cut vertices are not connected by an edge:
If 𝐺 is a biconnected multigraph:
sage: G = graphs.CompleteBipartiteGraph(2, 3)
sage: G.add_edge(2, 3)
sage: G.allow_multiple_edges(True)
sage: G.add_edges(G.edge_iterator())
sage: G.add_edges([(0, 1), (0, 1), (0, 1)])
sage: S,C,f = cleave(G, cut_vertices=[0, 1])
sage: for g in S:
....: print(g.edges(sort=True, labels=0))
[(0, 1), (0, 1), (0, 1), (0, 2), (0, 2), (0, 3), (0, 3), (1, 2), (1, 2), (1, 3),
˓→ (1, 3), (2, 3), (2, 3)]
[(0, 1), (0, 1), (0, 1), (0, 4), (0, 4), (1, 4), (1, 4)]
clique_complex()
Return the clique complex of self.
This is the largest simplicial complex on the vertices of self whose 1-skeleton is self.
This is only makes sense for undirected simple graphs.
EXAMPLES:
sage: g = Graph({0:[1,2],1:[2],4:[]})
sage: g.clique_complex()
Simplicial complex with vertex set (0, 1, 2, 4) and facets {(4,), (0, 1, 2)}
sage: h = Graph({0:[1,2,3,4],1:[2,3,4],2:[3]})
sage: x = h.clique_complex()
sage: x
Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(0, 1, 4), (0, 1,
˓→ 2, 3)}
sage: i = x.graph()
sage: i==h
True
sage: x==i.clique_complex()
True
Note: Currently only implemented for undirected graphs. Use to_undirected to convert a digraph to an
undirected graph.
ALGORITHM:
This function is based on Cliquer [NO2003].
EXAMPLES:
Using Cliquer (default):
sage: C = graphs.PetersenGraph()
sage: C.clique_maximum()
[7, 9]
sage: C = Graph('DJ{')
sage: C.clique_maximum()
[1, 2, 3, 4]
sage: len(C.clique_maximum(algorithm="MILP"))
4
Note: Currently only implemented for undirected graphs. Use to_undirected to convert a digraph to
an undirected graph.
INPUT:
• algorithm – the algorithm to be used :
– If algorithm = "Cliquer", wraps the C program Cliquer [NO2003].
– If algorithm = "networkx", uses the NetworkX’s implementation of the Bron and Kerbosch
Algorithm [BK1973].
– If algorithm = "MILP", the problem is solved through a Mixed Integer Linear Program.
(see MixedIntegerLinearProgram)
– If algorithm = "mcqd", uses the MCQD solver (http://insilab.org/maxclique/). Note that the
MCQD package must be installed.
• cliques – an optional list of cliques that can be input if already computed. Ignored unless
algorithm=="networkx".
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
ALGORITHM:
This function is based on Cliquer [NO2003] and [BK1973].
EXAMPLES:
sage: C = Graph('DJ{')
sage: C.clique_number()
4
sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
sage: G.show(figsize=[2,2])
(continues on next page)
True
clique_polynomial(t=None)
Return the clique polynomial of self.
This is the polynomial where the coefficient of 𝑡𝑛 is the number of cliques in the graph with 𝑛 vertices. The
constant term of the clique polynomial is always taken to be one.
EXAMPLES:
sage: g = Graph()
sage: g.clique_polynomial()
1
sage: g = Graph({0:[1]})
sage: g.clique_polynomial()
t^2 + 2*t + 1
sage: g = graphs.CycleGraph(4)
sage: g.clique_polynomial()
4*t^2 + 4*t + 1
cliques_containing_vertex(vertices=None, cliques=None)
Return the cliques containing each vertex, represented as a dictionary of lists of lists, keyed by vertex.
Returns a single list if only one input vertex.
Note: Currently only implemented for undirected graphs. Use to_undirected to convert a digraph to an
undirected graph.
INPUT:
• vertices – the vertices to inspect (default is entire graph)
• cliques – list of cliques (if already computed)
EXAMPLES:
sage: C = Graph('DJ{')
sage: C.cliques_containing_vertex()
(continues on next page)
sage: E = C.cliques_maximal()
sage: E
[[0, 4], [1, 2, 3, 4]]
sage: C.cliques_containing_vertex(cliques=E)
{0: [[0, 4]], 1: [[1, 2, 3, 4]], 2: [[1, 2, 3, 4]], 3: [[1, 2, 3, 4]], 4: [[0,␣
˓→4], [1, 2, 3, 4]]}
Since each clique of a 2 dimensional grid corresponds to an edge, the number of cliques in which a vertex
is involved equals its degree:
sage: F = graphs.Grid2dGraph(2,3)
sage: d = F.cliques_containing_vertex()
sage: all(F.degree(u) == len(cliques) for u,cliques in d.items())
True
sage: d = F.cliques_containing_vertex(vertices=[(0, 1)])
sage: list(d)
[(0, 1)]
sage: sorted(sorted(x for x in L) for L in d[(0, 1)])
[[(0, 0), (0, 1)], [(0, 1), (0, 2)], [(0, 1), (1, 1)]]
cliques_get_clique_bipartite(**kwds)
Return a bipartite graph constructed such that maximal cliques are the right vertices and the left vertices
are retained from the given graph. Right and left vertices are connected if the bottom vertex belongs to the
clique represented by a top vertex.
Note: Currently only implemented for undirected graphs. Use to_undirected to convert a digraph to an
undirected graph.
EXAMPLES:
sage: (graphs.ChvatalGraph()).cliques_get_clique_bipartite()
Bipartite graph on 36 vertices
sage: ((graphs.ChvatalGraph()).cliques_get_clique_bipartite()).show(figsize=[2,
˓→2], vertex_size=20, vertex_labels=False)
cliques_get_max_clique_graph()
Return the clique graph.
Vertices of the result are the maximal cliques of the graph, and edges of the result are between maximal
cliques with common members in the original graph.
Note: Currently only implemented for undirected graphs. Use to_undirected to convert a digraph to an
undirected graph.
EXAMPLES:
sage: (graphs.ChvatalGraph()).cliques_get_max_clique_graph()
Graph on 24 vertices
sage: ((graphs.ChvatalGraph()).cliques_get_max_clique_graph()).show(figsize=[2,
˓→2], vertex_size=20, vertex_labels=False)
sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
sage: G.show(figsize=[2,2])
sage: G.cliques_get_max_clique_graph()
Graph on 2 vertices
sage: (G.cliques_get_max_clique_graph()).show(figsize=[2,2])
cliques_maximal(algorithm='native')
Return the list of all maximal cliques.
Each clique is represented by a list of vertices. A clique is an induced complete subgraph, and a maximal
clique is one not contained in a larger one.
INPUT:
• algorithm – can be set to "native" (default) to use Sage’s own implementation, or to "NetworkX"
to use NetworkX’ implementation of the Bron and Kerbosch Algorithm [BK1973].
Note: This method sorts its output before returning it. If you prefer to save the extra time, you can call
sage.graphs.independent_sets.IndependentSets directly.
Note: Sage’s implementation of the enumeration of maximal independent sets is not much faster than
NetworkX’ (expect a 2x speedup), which is surprising as it is written in Cython. This being said, the
algorithm from NetworkX appears to be slightly different from this one, and that would be a good thing to
explore if one wants to improve the implementation.
ALGORITHM:
This function is based on NetworkX’s implementation of the Bron and Kerbosch Algorithm [BK1973].
EXAMPLES:
sage: graphs.ChvatalGraph().cliques_maximal()
[[0, 1], [0, 4], [0, 6], [0, 9], [1, 2], [1, 5], [1, 7], [2, 3],
[2, 6], [2, 8], [3, 4], [3, 7], [3, 9], [4, 5], [4, 8], [5, 10],
[5, 11], [6, 10], [6, 11], [7, 8], [7, 11], [8, 10], [9, 10], [9, 11]]
sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
sage: G.show(figsize=[2, 2])
sage: G.cliques_maximal()
[[0, 1, 2], [0, 1, 3]]
sage: C = graphs.PetersenGraph()
sage: C.cliques_maximal()
[[0, 1], [0, 4], [0, 5], [1, 2], [1, 6], [2, 3], [2, 7], [3, 4],
(continues on next page)
sage: g = graphs.RandomGNP(20,.7)
sage: s1 = Set(map(Set, g.cliques_maximal(algorithm="NetworkX")))
sage: s2 = Set(map(Set, g.cliques_maximal(algorithm="native")))
sage: s1 == s2
True
cliques_maximum(graph)
Return the vertex sets of ALL the maximum complete subgraphs.
Returns the list of all maximum cliques, with each clique represented by a list of vertices. A clique is an
induced complete subgraph, and a maximum clique is one of maximal order.
Note: Currently only implemented for undirected graphs. Use to_undirected() to convert a digraph to
an undirected graph.
ALGORITHM:
This function is based on Cliquer [NO2003].
EXAMPLES:
cliques_number_of(vertices=None, cliques=None)
Return a dictionary of the number of maximal cliques containing each vertex, keyed by vertex.
This returns a single value if only one input vertex.
Note: Currently only implemented for undirected graphs. Use to_undirected to convert a digraph to an
undirected graph.
INPUT:
sage: C = Graph('DJ{')
sage: C.cliques_number_of()
{0: 1, 1: 1, 2: 1, 3: 1, 4: 2}
sage: E = C.cliques_maximal()
sage: E
[[0, 4], [1, 2, 3, 4]]
sage: C.cliques_number_of(cliques=E)
{0: 1, 1: 1, 2: 1, 3: 1, 4: 2}
sage: F = graphs.Grid2dGraph(2,3)
sage: F.cliques_number_of()
{(0, 0): 2, (0, 1): 3, (0, 2): 2, (1, 0): 2, (1, 1): 3, (1, 2): 2}
sage: F.cliques_number_of(vertices=[(0, 1), (1, 2)])
{(0, 1): 3, (1, 2): 2}
sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
sage: G.show(figsize=[2,2])
sage: G.cliques_number_of()
{0: 2, 1: 2, 2: 1, 3: 1}
Note: Currently only implemented for undirected graphs. Use to_undirected to convert a digraph to an
undirected graph.
INPUT:
• algorithm – either cliquer or networkx
– cliquer – This wraps the C program Cliquer [NO2003].
– networkx – This function is based on NetworkX’s implementation of the Bron and Kerbosch
Algorithm [BK1973].
EXAMPLES:
sage: C = Graph('DJ{')
sage: C.cliques_vertex_clique_number()
{0: 2, 1: 4, 2: 4, 3: 4, 4: 4}
sage: E = C.cliques_maximal()
sage: E
[[0, 4], [1, 2, 3, 4]]
sage: C.cliques_vertex_clique_number(cliques=E,algorithm="networkx")
{0: 2, 1: 4, 2: 4, 3: 4, 4: 4}
(continues on next page)
sage: G = Graph("Fooba")
sage: P = G.coloring(algorithm="MILP")
sage: Q = G.coloring(algorithm="DLX")
sage: def are_equal_colorings(A, B):
....: return Set(map(Set, A)) == Set(map(Set, B))
sage: are_equal_colorings(P, [[1, 2, 3], [0, 5, 6], [4]])
True
sage: are_equal_colorings(P, Q)
True
sage: G.plot(partition=P)
Graphics object consisting of 16 graphics primitives
sage: G.coloring(hex_colors=True, algorithm="MILP")
{'#0000ff': [4], '#00ff00': [0, 6, 5], '#ff0000': [2, 1, 3]}
sage: H = G.coloring(hex_colors=True, algorithm="DLX")
sage: H
{'#0000ff': [4], '#00ff00': [1, 2, 3], '#ff0000': [0, 5, 6]}
(continues on next page)
1 6
4
5
common_neighbors_matrix(vertices, nonedgesonly=None, base_ring=True, **kwds)
Return a matrix of numbers of common neighbors between each pairs.
The (𝑖, 𝑗) entry of the matrix gives the number of common neighbors between vertices 𝑖 and 𝑗.
This method is only valid for simple (no loops, no multiple edges) graphs.
INPUT:
• nonedgesonly– boolean (default: True); if True, assigns 0 value to adjacent vertices.
• vertices – list (default: None); the ordering of the vertices defining how they should appear in the
matrix. By default, the ordering given by GenericGraph.vertices() is used.
• base_ring – a ring (default: None); the base ring of the matrix space to use
• **kwds – other keywords to pass to matrix()
OUTPUT: matrix
EXAMPLES:
The common neighbors matrix for a straight linear 2-tree counting only non-adjacent vertex pairs
sage: G1 = Graph()
sage: G1.add_edges([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)])
sage: G1.common_neighbors_matrix(nonedgesonly = True)
[0 0 0 2 1 0]
[0 0 0 0 2 1]
[0 0 0 0 0 2]
[2 0 0 0 0 0]
[1 2 0 0 0 0]
[0 1 2 0 0 0]
We now show the common neighbors matrix which includes adjacent vertices
The common neighbors matrix for a fan on 6 vertices counting only non-adjacent vertex pairs
sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)])
sage: H.common_neighbors_matrix()
[0 0 0 0 0 0 0]
[0 0 0 2 1 1 1]
[0 0 0 0 2 1 1]
[0 2 0 0 0 2 1]
[0 1 2 0 0 0 1]
[0 1 1 2 0 0 1]
[0 1 1 1 1 1 0]
sage: H.common_neighbors_matrix(base_ring=RDF)
[0.0 0.0 0.0 0.0 0.0 0.0 0.0]
[0.0 0.0 0.0 2.0 1.0 1.0 1.0]
[0.0 0.0 0.0 0.0 2.0 1.0 1.0]
[0.0 2.0 0.0 0.0 0.0 2.0 1.0]
[0.0 1.0 2.0 0.0 0.0 0.0 1.0]
[0.0 1.0 1.0 2.0 0.0 0.0 1.0]
[0.0 1.0 1.0 1.0 1.0 1.0 0.0]
sage: G = Graph([(0,0)],loops=True)
sage: G.common_neighbors_matrix()
Traceback (most recent call last):
...
ValueError: This method is not known to work on graphs with loops.
Perhaps this method can be updated to handle them, but in the
meantime if you want to use it please disallow loops using
allow_loops().
See also:
convexity_properties()
Return a ConvexityProperties object corresponding to self.
This object contains the methods related to convexity in graphs (convex hull, hull number) and caches useful
information so that it becomes comparatively cheaper to compute the convex hull of many different sets of
the same graph.
See also:
In order to know what can be done through this object, please refer to module sage.graphs.
convexity_properties.
Note: If you want to compute many convex hulls, keep this object in memory ! When it is created, it
builds a table of useful information to compute convex hulls. As a result
sage: g = graphs.PetersenGraph()
sage: g.convexity_properties().hull([1, 3])
[1, 2, 3]
sage: g.convexity_properties().hull([3, 7])
[2, 3, 7]
sage: g = graphs.PetersenGraph()
sage: CP = g.convexity_properties()
sage: CP.hull([1, 3])
[1, 2, 3]
sage: CP.hull([3, 7])
[2, 3, 7]
cores(k=None, with_labels=False)
Return the core number for each vertex in an ordered list.
(for homomorphisms cores, see the Graph.has_homomorphism_to() method)
DEFINITIONS:
• K-cores in graph theory were introduced by Seidman in 1983 and by Bollobas in 1984 as a method of
(destructively) simplifying graph topology to aid in analysis and visualization. They have been more
recently defined as the following by Batagelj et al:
Given a graph `G` with vertices set `V` and edges set `E`, the `k`-core of `G` is the graph obtained
from `G` by recursively removing the vertices with degree less than `k`, for as long as there are any.
This operation can be useful to filter or to study some properties of the graphs. For instance, when you
compute the 2-core of graph G, you are cutting all the vertices which are in a tree part of graph. (A
tree is a graph with no loops). See the Wikipedia article K-core.
[PSW1996] defines a 𝑘-core of 𝐺 as the largest subgraph (it is unique) of 𝐺 with minimum degree at
least 𝑘.
• Graph cores is also a notion related to graph homomorphisms. For this second meaning, see Graph.
has_homomorphism_to().
• Wikipedia article Degeneracy_(graph_theory)
EXAMPLES:
sage: (graphs.FruchtGraph()).cores()
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
sage: (graphs.FruchtGraph()).cores(with_labels=True)
{0: 3, 1: 3, 2: 3, 3: 3, 4: 3, 5: 3, 6: 3, 7: 3, 8: 3, 9: 3, 10: 3, 11: 3}
sage: set_random_seed(0)
sage: a = random_matrix(ZZ, 20, x=2, sparse=True, density=.1)
sage: b = Graph(20)
sage: b.add_edges(a.nonzero_positions(), loops=False)
sage: cores = b.cores(with_labels=True); cores
{0: 3, 1: 3, 2: 3, 3: 3, 4: 2, 5: 2, 6: 3, 7: 1, 8: 3, 9: 3, 10: 3, 11: 3, 12:␣
˓→3, 13: 3, 14: 2, 15: 3, 16: 3, 17: 3, 18: 3, 19: 3}
sage: G = graphs.BullGraph()
sage: G.cores(with_labels=True)
{0: 2, 1: 2, 2: 2, 3: 1, 4: 1}
sage: G.cores(k=2)
([3, 4], [0, 1, 2])
sage: G.allow_multiple_edges(True)
sage: G.add_edges(G.edges(sort=False))
sage: G.cores(with_labels=True)
{0: 4, 1: 4, 2: 4, 3: 2, 4: 2}
sage: G.cores(k=4)
([3, 4], [0, 1, 2])
Note:
• This algorithm computes the degree-constrained subgraph of minimum weight.
• If the graph’s edges are weighted, these are taken into account.
• This problem can be solved in polynomial time.
EXAMPLES:
Is there a perfect matching in an even cycle?
sage: g = graphs.CycleGraph(6)
sage: bounds = lambda x: [1,1]
sage: m = g.degree_constrained_subgraph(bounds=bounds)
sage: m.size()
3
The more symmetric a graph is, the smaller (diameter - radius) is:
sage: G = graphs.BarbellGraph(9, 3)
sage: G.radius()
3
sage: G.diameter()
6
sage: G = graphs.OctahedralGraph()
sage: G.radius()
2
sage: G.diameter()
2
distance_graph(dist)
Return the graph on the same vertex set as the original graph but vertices are adjacent in the returned graph
if and only if they are at specified distances in the original graph.
INPUT:
• dist – a nonnegative integer or a list of nonnegative integers; specified distance(s) for the connecting
vertices. Infinity may be used here to describe vertex pairs in separate components.
OUTPUT:
The returned value is an undirected graph. The vertex set is identical to the calling graph, but edges of the
returned graph join vertices whose distance in the calling graph are present in the input dist. Loops will
only be present if distance 0 is included. If the original graph has a position dictionary specifying locations
of vertices for plotting, then this information is copied over to the distance graph. In some instances this
layout may not be the best, and might even be confusing when edges run on top of each other due to
symmetries chosen for the layout.
EXAMPLES:
sage: G = graphs.CompleteGraph(3)
sage: H = G.cartesian_product(graphs.CompleteGraph(2))
sage: K = H.distance_graph(2)
sage: K.am()
[0 0 0 1 0 1]
[0 0 1 0 1 0]
[0 1 0 0 0 1]
[1 0 0 0 1 0]
[0 1 0 1 0 0]
[1 0 1 0 0 0]
To obtain the graph where vertices are adjacent if their distance apart is d or less use a range() command
to create the input, using d + 1 as the input to range. Notice that this will include distance 0 and hence
place a loop at each vertex. To avoid this, use range(1, d + 1):
sage: G = graphs.OddGraph(4)
sage: d = G.diameter()
sage: n = G.num_verts()
sage: H = G.distance_graph(list(range(d+1)))
sage: H.is_isomorphic(graphs.CompleteGraph(n))
False
sage: H = G.distance_graph(list(range(1,d+1)))
(continues on next page)
A complete collection of distance graphs will have adjacency matrices that sum to the matrix of all ones:
sage: P = graphs.PathGraph(20)
sage: all_ones = sum([P.distance_graph(i).am() for i in range(20)])
sage: all_ones == matrix(ZZ, 20, 20, [1]*400)
True
Four-bit strings differing in one bit is the same as four-bit strings differing in three bits:
sage: G = graphs.CubeGraph(4)
sage: H = G.distance_graph(3)
sage: G.is_isomorphic(H)
True
sage: G = graphs.CompleteGraph(3)
sage: H = G.disjoint_union(graphs.CompleteGraph(2))
sage: L = H.distance_graph(Infinity)
sage: L.am()
[0 0 0 1 1]
[0 0 0 1 1]
[0 0 0 1 1]
[1 1 1 0 0]
[1 1 1 0 0]
sage: L.is_isomorphic(graphs.CompleteBipartiteGraph(3, 2))
True
AUTHOR:
Rob Beezer, 2009-11-25, trac ticket #7533
ear_decomposition()
Return an Ear decomposition of the graph.
An ear of an undirected graph 𝐺 is a path 𝑃 where the two endpoints of the path may coincide (i.e., form a
cycle), but where otherwise no repetition of edges or vertices is allowed, so every internal vertex of 𝑃 has
degree two in 𝑃 .
An ear decomposition of an undirected graph 𝐺 is a partition of its set of edges into a sequence of ears, such
that the one or two endpoints of each ear belong to earlier ears in the sequence and such that the internal
vertices of each ear do not belong to any earlier ear.
For more information, see the Wikipedia article Ear_decomposition.
sage: g = Graph('LlCG{O@?GBOMW?')
sage: g.ear_decomposition()
[[0, 3, 2, 1, 0],
[0, 7, 4, 3],
[0, 11, 9, 8, 7],
[1, 12, 2],
[3, 6, 5, 4],
[4, 6],
[7, 10, 8],
[7, 11],
[8, 11]]
sage: g = graphs.CycleGraph(4)
sage: g.ear_decomposition()
[[0, 3, 2, 1, 0]]
sage: G = Graph()
sage: G.add_cycle([0,1,2])
sage: G.add_edge(0,3)
sage: G.add_cycle([3,4,5,6])
sage: G.ear_decomposition()
[[0, 2, 1, 0], [3, 6, 5, 4, 3]]
The ear decomposition of a multigraph with loops is the same as the ear decomposition of the underlying
simple graph:
sage: g = graphs.BullGraph()
sage: g.allow_multiple_edges(True)
sage: g.add_edges(g.edges(sort=False))
sage: g.allow_loops(True)
sage: u = g.random_vertex()
sage: g.add_edge(u, u)
sage: g
Bull graph: Looped multi-graph on 5 vertices
sage: h = g.to_simple()
sage: g.ear_decomposition() == h.ear_decomposition()
True
For more information and examples on how to use input variables, see shortest_path_all_pairs(),
shortest_path_lengths() and shortest_paths()
INPUT:
• v - either a single vertex or a list of vertices. If it is not specified, then it is taken to be all vertices.
• by_weight – boolean (default: False); if True, edge weights are taken into account; if False, all
edges have weight 1
• algorithm – string (default: None); one of the following algorithms:
– 'BFS' - the computation is done through a BFS centered on each vertex successively. Works only
if by_weight==False.
– 'DHV' - the computation is done using the algorithm proposed in [Dragan2018]. Works only if
self has non-negative edge weights and v is None or v should contain all vertices of self. For
more information see method sage.graphs.distances_all_pairs.eccentricity() and
sage.graphs.base.boost_graph.eccentricity_DHV().
– 'Floyd-Warshall-Cython' - a Cython implementation of the Floyd-Warshall algorithm. Works
only if by_weight==False and v is None or v should contain all vertices of self.
– 'Floyd-Warshall-Python' - a Python implementation of the Floyd-Warshall algorithm. Works
also with weighted graphs, even with negative weights (but no negative cycle is allowed). However,
v must be None or v should contain all vertices of self.
– 'Dijkstra_NetworkX' - the Dijkstra algorithm, implemented in NetworkX. It works with
weighted graphs, but no negative weight is allowed.
– 'Dijkstra_Boost' - the Dijkstra algorithm, implemented in Boost (works only with positive
weights).
– 'Johnson_Boost' - the Johnson algorithm, implemented in Boost (works also with negative
weights, if there is no negative cycle). Works only if v is None or v should contain all vertices
of self.
– 'From_Dictionary' - uses the (already computed) distances, that are provided by input variable
dist_dict.
– None (default): Sage chooses the best algorithm: 'From_Dictionary' if dist_dict is
not None, 'BFS' for unweighted graphs, 'Dijkstra_Boost' if all weights are positive,
'Johnson_Boost' otherwise.
• weight_function – function (default: None); a function that takes as input an edge (u, v, l) and
outputs its weight. If not None, by_weight is automatically set to True. If None and by_weight is
True, we use the edge label l as a weight, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs a
number for each edge
• dist_dict – a dictionary (default: None); a dict of dicts of distances (used only if
algorithm=='From_Dictionary')
• with_labels – boolean (default: False); whether to return a list or a dictionary keyed by vertices.
EXAMPLES:
sage: G = graphs.KrackhardtKiteGraph()
sage: G.eccentricity()
[4, 4, 4, 4, 4, 3, 3, 2, 3, 4]
sage: G.vertices(sort=True)
(continues on next page)
edge_isoperimetric_number(g)
Return the edge-isoperimetric number of the graph.
The edge-isoperimetric number of a graph 𝐺 = (𝑉, 𝐸) is also sometimes called the isoperimetric number.
It is defined as the minimum of |𝜕𝑆|/|𝑆| where 𝜕𝑆 is the edge boundary of 𝑆 (number of edges with one
end in 𝑆 and one end in 𝑉 ∖ 𝑆) and the minimum is taken over all subsets of vertices whose cardinality
does not exceed half the size |𝑉 | of the graph.
See also:
Alternative but similar quantities can be obtained via the methods cheeger_constant() and
vertex_isoperimetric_number().
EXAMPLES:
The edge-isoperimetric number of a complete graph on 𝑛 vertices is ⌈𝑛/2⌉:
In general, for 𝑑-regular graphs the edge-isoperimetric number is 𝑑 times larger than the Cheeger constant
of the graph:
sage: Graph([[1,2,3,4],[(1,2),(3,4)]]).edge_isoperimetric_number()
0
effective_resistance(i, j, base_ring)
Return the effective resistance between nodes 𝑖 and 𝑗.
The resistance distance between vertices 𝑖 and 𝑗 of a simple connected graph 𝐺 is defined as the effective
resistance between the two vertices on an electrical network constructed from 𝐺 replacing each edge of the
graph by a unit (1 ohm) resistor.
See the Wikipedia article Resistance_distance for more information.
INPUT:
• i, j – vertices of the graph
• base_ring – a ring (default: None); the base ring of the matrix space to use
OUTPUT: rational number denoting resistance between nodes 𝑖 and 𝑗
EXAMPLES:
Effective resistances in a straight linear 2-tree on 6 vertices
sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)])
sage: G.effective_resistance(0,1)
34/55
sage: G.effective_resistance(0,3)
49/55
sage: G.effective_resistance(1,4)
9/11
sage: G.effective_resistance(0,5)
15/11
sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)])
sage: H.effective_resistance(1,5)
6/5
sage: H.effective_resistance(1,3)
49/55
sage: H.effective_resistance(1,1)
0
See also:
sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)])
sage: G.effective_resistance_matrix()
[ 0 0 0 49/55 59/55 15/11]
[ 0 0 0 0 9/11 59/55]
[ 0 0 0 0 0 49/55]
[49/55 0 0 0 0 0]
[59/55 9/11 0 0 0 0]
[15/11 59/55 49/55 0 0 0]
The same effective resistance matrix, this time including adjacent vertices
sage: G.effective_resistance_matrix(nonedgesonly=False)
[ 0 34/55 34/55 49/55 59/55 15/11]
[34/55 0 26/55 31/55 9/11 59/55]
[34/55 26/55 0 5/11 31/55 49/55]
[49/55 31/55 5/11 0 26/55 34/55]
[59/55 9/11 31/55 26/55 0 34/55]
[15/11 59/55 49/55 34/55 34/55 0]
This example illustrates the common neighbors matrix for a fan on 6 vertices counting only non-adjacent
vertex pairs
sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)])
sage: H.effective_resistance_matrix()
[ 0 0 0 0 0 0 0]
[ 0 0 0 49/55 56/55 6/5 89/55]
[ 0 0 0 0 4/5 56/55 81/55]
[ 0 49/55 0 0 0 49/55 16/11]
[ 0 56/55 4/5 0 0 0 81/55]
[ 0 6/5 56/55 49/55 0 0 89/55]
[ 0 89/55 81/55 16/11 81/55 89/55 0]
See also:
folded_graph(check=False)
Return the antipodal fold of this graph.
Given an antipodal graph 𝐺 let 𝐺𝑑 be its distance-𝑑 graph. Then the folded graph of 𝐺 has a vertex for
each maximal clique of 𝐺𝑑 and two cliques are adjacent if there is an edge in 𝐺 connecting the two.
See also:
sage.graphs.graph.is_antipodal()
INPUT:
• check – boolean (default: False); whether to check if the graph is antipodal. If check is True and
the graph is not antipodal, then return False.
OUTPUT:
This function returns a new graph and self is not touched.
Note: The input is expected to be an antipodal graph. You can check that a graph is antipodal using
sage.graphs.graph.is_antipodal().
EXAMPLES:
sage: G = graphs.JohnsonGraph(10, 5)
sage: H = G.folded_graph(); H
Folded Johnson graph with parameters 10,5: Graph on 126 vertices
sage: Gd = G.distance_graph(G.diameter())
sage: all(i == 1 for i in Gd.degree())
True
sage: H.is_distance_regular(True)
([25, 16, None], [None, 1, 4])
sage: G = graphs.PetersenGraph()
sage: G.is_antipodal()
False
sage: G.folded_graph() # some garbage
Folded Petersen graph: Graph on 2 vertices
sage: G.folded_graph(check=True)
False
REFERENCES:
See [BCN1989] p. 438 or [Sam2012] for this definition of folded graph.
fractional_chromatic_index(G, solver='PPL', verbose_constraints=False, verbose=0)
Return the fractional chromatic index of the graph.
The fractional chromatic index is a relaxed version of edge-coloring. An edge coloring of a graph being
actually a covering of its edges into the smallest possible number of matchings, the fractional chromatic
index of a graph 𝐺 is the smallest real value 𝜒𝑓 (𝐺) such that there exists a list of matchings 𝑀1 , . . . , 𝑀𝑘 of
𝐺 and coefficients 𝛼1 , . . . , 𝛼𝑘 with the property that each edge is covered by the matchings in the following
relaxed way
∑︁
∀𝑒 ∈ 𝐸(𝐺), 𝛼𝑖 ≥ 1.
𝑒∈𝑀𝑖
Such that :
∑︁
∀𝑀 matching ⊆ 𝐺, 𝑟𝑣 ≤ 1
𝑒∈𝑀
INPUT:
• G – a graph
• solver – (default: "PPL"); specify a Linear Program (LP) solver to be used. If set to None, the
default one is used. For more information on LP solvers and which default solver is used, see the
method solve of the class MixedIntegerLinearProgram.
Note: The default solver used here is "PPL" which provides exact results, i.e. a rational number,
although this may be slower that using other solvers. Be aware that this method may loop endlessly
when using some non exact solvers as reported in trac ticket #23658 and trac ticket #23798.
• verbose_constraints – boolean (default: False); whether to display which constraints are being
generated
• verbose – integer (default: 0); sets the level of verbosity of the LP solver
EXAMPLES:
The fractional chromatic index of a 𝐶5 is 5/2:
sage: g = graphs.CycleGraph(5)
sage: g.fractional_chromatic_index()
5/2
Such that :
∑︁
∀𝑣 ∈ 𝑉 (𝐺), 𝑥𝑣 ≥ 1
𝐼∈ℐ(𝐺), 𝑣∈𝐼
∀𝐼 ∈ ℐ(𝐺), 𝑥𝐼 ≥ 0
where ℐ(𝐺) is the set of maximal independent sets of 𝐺 (see Section 2.1 of [CFKPR2010] to know why it
is sufficient to consider maximal independent sets). As optional optimisations, we construct the LP on each
biconnected component of 𝐺 (and output the maximum value), and avoid using the LP if G is bipartite (as
then the output must be 1 or 2).
Note: Computing the fractional chromatic number can be very slow. Since the variables of the LP are inde-
pendent sets, in general the LP has size exponential in the order of the graph. In the current implementation
a list of all maximal independent sets is created and stored, which can be both slow and memory-hungry.
INPUT:
• G – a graph
• solver – (default: "PPL"); specify a Linear Program (LP) solver to be used. If set to None, the
default one is used. For more information on LP solvers and which default solver is used, see the
method solve of the class MixedIntegerLinearProgram.
Note: The default solver used here is "PPL" which provides exact results, i.e. a rational number,
although this may be slower that using other solvers.
• verbose – integer (default: 0); sets the level of verbosity of the LP solver
• check_components – boolean (default: True); whether the method is called on each biconnected
component of 𝐺
• check_bipartite – boolean (default: True); whether the graph is checked for bipartiteness. If the
graph is bipartite then we can avoid creating and solving the LP.
EXAMPLES:
The fractional chromatic number of a 𝐶5 is 5/2:
sage: g = graphs.CycleGraph(5)
sage: g.fractional_chromatic_number()
5/2
Note: The default solver used here is "PPL" which provides exact results, i.e. a rational number,
although this may be slower that using other solvers.
• verbose – integer (default: 0); sets the level of verbosity of the LP solver
• check_components – boolean (default: True); whether the method is called on each biconnected
component of 𝐺
• check_bipartite – boolean (default: True); whether the graph is checked for bipartiteness. If the
graph is bipartite then we can avoid creating and solving the LP.
EXAMPLES:
The fractional clique number of a 𝐶7 is 7/3:
sage: g = graphs.CycleGraph(7)
sage: g.fractional_clique_number()
7/3
geodetic_closure(G, S)
Return the geodetic closure of the set of vertices 𝑆 in 𝐺.
The geodetic closure 𝑔(𝑆) of a subset of vertices 𝑆 of a graph 𝐺 is in [HLT1993] as the set of all vertices
that lie on a shortest 𝑢 − 𝑣 path for any pair of vertices 𝑢, 𝑣 ∈ 𝑆. We assume that 𝑔(∅) = ∅ and that
𝑔({𝑢}) = {𝑢} for any 𝑢 in 𝐺.
Warning: This operation is not a closure function. Indeed, a closure function must satisfy the property
that 𝑓 (𝑓 (𝑋)) should be equal to 𝑓 (𝑋), which is not always the case here. The term closure is used
here to follow the terminology of the domain. See for instance [HLT1993].
Here, we implement a simple algorithm to determine this set. Roughly, for each vertex 𝑢 ∈ 𝑆, the algorithm
first performs a breadth first search from 𝑢 to get distances, and then identifies the vertices of 𝐺 lying on
a shortest path from 𝑢 to any 𝑣 ∈ 𝑆 using a reversal traversal from vertices in 𝑆. This algorithm has time
complexity in 𝑂(|𝑆|(𝑛 + 𝑚)) and space complexity in 𝑂(𝑛 + 𝑚).
INPUT:
• G – a Sage graph
• S – a subset of vertices of 𝐺
EXAMPLES:
The vertices of the Petersen graph can be obtained by a geodetic closure of four of its vertices:
sage: G = graphs.Grid2dGraph(4, 4)
sage: c = G.geodetic_closure([(0, 0), (3, 3)])
sage: len(c) == G.order()
True
If two vertices belong to different connected components of a graph, their geodetic closure is trivial:
The geodetic closure does not satisfy the closure function property that 𝑓 (𝑓 (𝑋)) should be equal to 𝑓 (𝑋):
sage: G = graphs.DiamondGraph()
sage: G.subdivide_edge((1, 2), 1)
sage: geodetic_closure(G, [0, 3])
[0, 1, 2, 3]
sage: geodetic_closure(G, geodetic_closure(G, [0, 3]))
[0, 1, 2, 3, 4]
gomory_hu_tree(algorithm=None)
Return a Gomory-Hu tree of self.
Given a tree 𝑇 with labeled edges representing capacities, it is very easy to determine the maximum flow
between any pair of vertices : it is the minimal label on the edges of the unique path between them.
Given a graph 𝐺, a Gomory-Hu tree 𝑇 of 𝐺 is a tree with the same set of vertices, and such that the maximum
flow between any two vertices is the same in 𝐺 as in 𝑇 . See the Wikipedia article Gomory–Hu_tree. Note
that, in general, a graph admits more than one Gomory-Hu tree.
See also 15.4 (Gomory-Hu trees) from [Sch2003].
INPUT:
• algorithm – select the algorithm used by the edge_cut() method. Refer to its documentation for
allowed values and default behaviour.
OUTPUT:
A graph with labeled edges
EXAMPLES:
Taking the Petersen graph:
sage: g = graphs.PetersenGraph()
sage: t = g.gomory_hu_tree()
sage: t.is_tree()
True
Note that if the original graph is not connected, then the Gomory-Hu tree is in fact a forest:
sage: (2*g).gomory_hu_tree().is_forest()
True
sage: (2*g).gomory_hu_tree().is_connected()
False
On the other hand, such a tree has lost nothing of the initial graph connectedness:
True
Just to make sure, we can check that the same is true for two vertices in a random graph:
sage: g = graphs.RandomGNP(20,.3)
sage: t = g.gomory_hu_tree()
sage: g.flow(0,1) == t.flow(0,1)
True
graph6_string()
Return the graph6 representation of the graph as an ASCII string.
This is only valid for simple (no loops, no multiple edges) graphs on at most 218 − 1 = 262143 vertices.
Note: As the graph6 format only handles graphs with vertex set {0, ..., 𝑛 − 1}, a relabelled copy will
be encoded, if necessary.
See also:
EXAMPLES:
sage: G = graphs.KrackhardtKiteGraph()
sage: G.graph6_string()
'IvUqwK@?G'
A homomorphism from a graph 𝐺 to a graph 𝐻 is a function 𝜑 : 𝑉 (𝐺) ↦→ 𝑉 (𝐻) such that for any edge
𝑢𝑣 ∈ 𝐸(𝐺) the pair 𝜑(𝑢)𝜑(𝑣) is an edge of 𝐻.
Saying that a graph can be 𝑘-colored is equivalent to saying that it has a homomorphism to 𝐾𝑘 , the complete
graph on 𝑘 elements.
For more information, see the Wikipedia article Graph_homomorphism.
INPUT:
• H – the graph to which self should be sent.
• core – boolean (default: False; whether to minimize the size of the mapping’s image (see note
below). This is set to False by default.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
Note: One can compute the core of a graph (with respect to homomorphism) with this method
sage: g = graphs.CycleGraph(10)
sage: mapping = g.has_homomorphism_to(g, core = True)
sage: print("The size of the core is {}".format(len(set(mapping.values()))))
The size of the core is 2
OUTPUT:
This method returns False when the homomorphism does not exist, and returns the homomorphism oth-
erwise as a dictionary associating a vertex of 𝐻 to a vertex of 𝐺.
EXAMPLES:
Is Petersen’s graph 3-colorable:
sage: P = graphs.PetersenGraph()
sage: P.has_homomorphism_to(graphs.CompleteGraph(3)) is not False
True
An odd cycle admits a homomorphism to a smaller odd cycle, but not to an even cycle:
sage: g = graphs.CycleGraph(9)
sage: g.has_homomorphism_to(graphs.CycleGraph(5)) is not False
True
sage: g.has_homomorphism_to(graphs.CycleGraph(7)) is not False
True
sage: g.has_homomorphism_to(graphs.CycleGraph(4)) is not False
False
sage: graphs.PetersenGraph().has_perfect_matching()
True
sage: graphs.WheelGraph(6).has_perfect_matching()
True
sage: graphs.WheelGraph(5).has_perfect_matching()
False
sage: graphs.PetersenGraph().has_perfect_matching(algorithm="LP_matching")
True
sage: graphs.WheelGraph(6).has_perfect_matching(algorithm="LP_matching")
True
sage: graphs.WheelGraph(5).has_perfect_matching(algorithm="LP_matching")
False
sage: graphs.PetersenGraph().has_perfect_matching(algorithm="LP_matching")
True
sage: graphs.WheelGraph(6).has_perfect_matching(algorithm="LP_matching")
True
sage: graphs.WheelGraph(5).has_perfect_matching(algorithm="LP_matching")
False
– 'basic' is an exhaustive algorithm considering all possible 4-tuples and so have time complexity
in 𝑂(𝑛4 ).
– 'CCL' is an exact algorithm proposed in [CCL2015]. It considers the 4-tuples in an ordering
allowing to cut the search space as soon as a new lower bound is found (see the module’s docu-
mentation). This algorithm can be turned into a approximation algorithm.
– 'CCL+FA' or 'CCL+' uses the notion of far-apart pairs as proposed in [Sot2011] to significantly
reduce the overall computation time of the 'CCL' algorithm.
– 'BCCM' is an exact algorithm proposed in [BCCM2015]. It improves 'CCL+FA' by cutting several
4-tuples (for more information, see the module’s documentation).
– 'dom' is an approximation with additive constant four. It computes the hyperbolicity of the ver-
tices of a dominating set of the graph. This is sometimes slower than 'CCL' and sometimes faster.
Try it to know if it is interesting for you. The additive_gap and approximation_factor pa-
rameters cannot be used in combination with this method and so are ignored.
• approximation_factor – (default: None) When the approximation factor is set to some value (larger
than 1.0), the function stop computations as soon as the ratio between the upper bound and the best
found solution is less than the approximation factor. When the approximation factor is 1.0, the problem
is solved optimally. This parameter is used only when the chosen algorithm is 'CCL', 'CCL+FA', or
'BCCM'.
• additive_gap – (default: None) When sets to a positive number, the function stop computations as
soon as the difference between the upper bound and the best found solution is less than additive gap.
When the gap is 0.0, the problem is solved optimally. This parameter is used only when the chosen
algorithm is 'CCL' or 'CCL+FA', or 'BCCM'.
• verbose – (default: False) is a boolean set to True to display some information during execution:
new upper and lower bounds, etc.
OUTPUT:
This function returns the tuple ( delta, certificate, delta_UB ), where:
• delta – the hyperbolicity of the graph (half-integer value).
• certificate – is the list of the 4 vertices for which the maximum value has been computed, and so
the hyperbolicity of the graph.
• delta_UB – is an upper bound for delta. When delta == delta_UB, the returned solution is op-
timal. Otherwise, the approximation factor if delta_UB/delta.
EXAMPLES:
Hyperbolicity of a 3 × 3 grid:
Hyperbolicity of a PetersenGraph:
(2, 5/2)
sage: L,C,U = hyperbolicity(G, algorithm='CCL+FA', additive_gap=1); L,U
(2, 5/2)
Comparison of results:
The hyperbolicity of a graph is the maximum value over all its biconnected components:
ihara_zeta_function_inverse()
Compute the inverse of the Ihara zeta function of the graph.
This is a polynomial in one variable with integer coefficients. The Ihara zeta function itself is the inverse
of this polynomial.
See the Wikipedia article Ihara zeta function for more information.
ALGORITHM:
This is computed here as the (reversed) characteristic polynomial of a square matrix of size twice the number
of edges, related to the adjacency matrix of the line graph, see for example Proposition 9 in [SS2008] and
Def. 4.1 in [Ter2011].
The graph is first replaced by its 2-core, as this does not change the Ihara zeta function.
EXAMPLES:
sage: G = graphs.CompleteGraph(4)
sage: factor(G.ihara_zeta_function_inverse())
(2*t - 1) * (t + 1)^2 * (t - 1)^3 * (2*t^2 + t + 1)^3
sage: G = graphs.CompleteGraph(5)
sage: factor(G.ihara_zeta_function_inverse())
(-1) * (3*t - 1) * (t + 1)^5 * (t - 1)^6 * (3*t^2 + t + 1)^4
(continues on next page)
sage: G = graphs.PetersenGraph()
sage: factor(G.ihara_zeta_function_inverse())
(-1) * (2*t - 1) * (t + 1)^5 * (t - 1)^6 * (2*t^2 + 2*t + 1)^4
* (2*t^2 - t + 1)^5
sage: G = graphs.RandomTree(10)
sage: G.ihara_zeta_function_inverse()
1
REFERENCES:
[HST2001]
independent_set(algorithm, value_only='Cliquer', reduction_rules=False, solver=True, verbose=None,
integrality_tolerance=0)
Return a maximum independent set.
An independent set of a graph is a set of pairwise non-adjacent vertices. A maximum independent set is an
independent set of maximum cardinality. It induces an empty subgraph.
Equivalently, an independent set is defined as the complement of a vertex cover.
For more information, see the Wikipedia article Independent_set_(graph_theory) and the Wikipedia article
Vertex_cover.
INPUT:
• algorithm – the algorithm to be used
– If algorithm = "Cliquer" (default), the problem is solved using Cliquer [NO2003].
(see the Cliquer modules)
– If algorithm = "MILP", the problem is solved through a Mixed Integer Linear Program.
(see MixedIntegerLinearProgram)
• value_only – boolean (default: False); if set to True, only the size of a maximum independent set
is returned. Otherwise, a maximum independent set is returned as a list of vertices.
• reduction_rules – (default: True); specify if the reductions rules from kernelization must be ap-
plied as pre-processing or not. See [ACFLSS04] for more details. Note that depending on the instance,
it might be faster to disable reduction rules.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
Note: While Cliquer/MCAD are usually (and by far) the most efficient implementations, the MILP for-
mulation sometimes proves faster on very “symmetrical” graphs.
EXAMPLES:
Using Cliquer:
sage: C = graphs.PetersenGraph()
sage: C.independent_set()
[0, 3, 6, 7]
As a linear program:
sage: C = graphs.PetersenGraph()
sage: len(C.independent_set(algorithm="MILP"))
4
1 4
6 9
7 8
2 3
independent_set_of_representatives(family, solver, verbose=None, integrality_tolerance=0)
Return an independent set of representatives.
Given a graph 𝐺 and a family 𝐹 = {𝐹𝑖 : 𝑖 ∈ [1, ..., 𝑘]} of subsets of g.vertices(sort=False), an
Independent Set of Representatives (ISR) is an assignation of a vertex 𝑣𝑖 ∈ 𝐹𝑖 to each set 𝐹𝑖 such that
𝑣𝑖 ! = 𝑣𝑗 if 𝑖 < 𝑗 (they are representatives) and the set ∪𝑖 𝑣𝑖 is an independent set in 𝐺.
sage: g = graphs.CompleteBipartiteGraph(3,3)
sage: g.delete_edge(1,4)
sage: g.independent_set_of_representatives([[0,1,2],[3,4,5]])
[1, 4]
The Petersen Graph is 3-colorable, which can be expressed as an independent set of representatives problem
: take 3 disjoint copies of the Petersen Graph, each one representing one color. Then take as a partition of
the set of vertices the family defined by the three copies of each vertex. The ISR of such a family defines a
3-coloring:
sage: g = 3 * graphs.PetersenGraph()
sage: n = g.order() / 3
sage: f = [[i, i + n, i + 2*n] for i in range(n)]
sage: isr = g.independent_set_of_representatives(f)
sage: c = [integer_floor(i / n) for i in isr]
sage: color_classes = [[], [], []]
sage: for v, i in enumerate(c):
....: color_classes[i].append(v)
sage: for classs in color_classes:
....: g.subgraph(classs).size() == 0
True
True
True
is_antipodal()
Check whether this graph is antipodal.
A graph 𝐺 of diameter 𝑑 is said to be antipodal if its distance-𝑑 graph is a disjoint union of cliques.
EXAMPLES:
sage: G = graphs.JohnsonGraph(10, 5)
sage: G.is_antipodal()
(continues on next page)
REFERENCES:
See [BCN1989] p. 438 or [Sam2012] for this definition of antipodal graphs.
is_apex()
Test if the graph is apex.
A graph is apex if it can be made planar by the removal of a single vertex. The deleted vertex is called
an apex of the graph, and a graph may have more than one apex. For instance, in the minimal nonplanar
graphs 𝐾5 or 𝐾3,3 , every vertex is an apex. The apex graphs include graphs that are themselves planar,
in which case again every vertex is an apex. The null graph is also counted as an apex graph even though
it has no vertex to remove. If the graph is not connected, we say that it is apex if it has at most one non
planar connected component and that this component is apex. See the Wikipedia article Apex_graph for
more information.
See also:
• apex_vertices()
• is_planar()
EXAMPLES:
𝐾5 and 𝐾3,3 are apex graphs, and each of their vertices is an apex:
sage: G = graphs.CompleteGraph(5)
sage: G.is_apex()
True
sage: G = graphs.CompleteBipartiteGraph(3,3)
sage: G.is_apex()
True
sage: G = graphs.PetersenGraph()
sage: G.is_apex()
False
A graph is apex if all its connected components are apex, but at most one is not planar:
sage: M = graphs.Grid2dGraph(3,3)
sage: K5 = graphs.CompleteGraph(5)
sage: (M+K5).is_apex()
True
sage: (M+K5+K5).is_apex()
False
is_arc_transitive()
Check if self is an arc-transitive graph
A graph is arc-transitive if its automorphism group acts transitively on its pairs of adjacent vertices.
Equivalently, if there exists for any pair of edges 𝑢𝑣, 𝑢′ 𝑣 ′ ∈ 𝐸(𝐺) an automorphism 𝜑1 of 𝐺 such that
𝜑1 (𝑢) = 𝑢′ and 𝜑1 (𝑣) = 𝑣 ′ , as well as another automorphism 𝜑2 of 𝐺 such that 𝜑2 (𝑢) = 𝑣 ′ and 𝜑2 (𝑣) = 𝑢′
See also:
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.is_arc_transitive()
True
sage: G = graphs.GrayGraph()
sage: G.is_arc_transitive()
False
is_asteroidal_triple_free(G, certificate=False)
Test if the input graph is asteroidal triple-free
An independent set of three vertices such that each pair is joined by a path that avoids the neighborhood
of the third one is called an asteroidal triple. A graph is asteroidal triple-free (AT-free) if it contains no
asteroidal triples. See the module's documentation for more details.
This method returns True is the graph is AT-free and False otherwise.
INPUT:
• G – a Graph
• certificate – boolean (default: False); by default, this method returns True if the graph is aster-
oidal triple-free and False otherwise. When certificate==True, this method returns in addition a
list of three vertices forming an asteroidal triple if such a triple is found, and the empty list otherwise.
EXAMPLES:
The complete graph is AT-free, as well as its line graph:
sage: G = graphs.CompleteGraph(5)
sage: G.is_asteroidal_triple_free()
True
sage: G.is_asteroidal_triple_free(certificate=True)
(True, [])
sage: LG = G.line_graph()
sage: LG.is_asteroidal_triple_free()
True
sage: LLG = LG.line_graph()
sage: LLG.is_asteroidal_triple_free()
False
is_biconnected()
Test if the graph is biconnected.
A biconnected graph is a connected graph on two or more vertices that is not broken into disconnected
pieces by deleting any single vertex.
See also:
• is_connected()
• blocks_and_cut_vertices()
• blocks_and_cuts_tree()
• Wikipedia article Biconnected_graph
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.is_biconnected()
True
sage: G.add_path([0,'a','b'])
sage: G.is_biconnected()
False
sage: G.add_edge('b', 1)
sage: G.is_biconnected()
True
is_block_graph()
Return whether this graph is a block graph.
A block graph is a connected graph in which every biconnected component (block) is a clique.
See also:
EXAMPLES:
is_cactus()
Check whether the graph is cactus graph.
A graph is called cactus graph if it is connected and every pair of simple cycles have at most one common
vertex.
There are other definitions, see the Wikipedia article Cactus_graph.
EXAMPLES:
sage: g = Graph({1: [2], 2: [3, 4], 3: [4, 5, 6, 7], 8: [3, 5], 9: [6, 7]})
sage: g.is_cactus()
True
sage: c6 = graphs.CycleGraph(6)
sage: naphthalene = c6 + c6
sage: naphthalene.is_cactus() # Not connected
False
sage: naphthalene.merge_vertices([0, 6])
sage: naphthalene.is_cactus()
True
sage: naphthalene.merge_vertices([1, 7])
sage: naphthalene.is_cactus()
False
• sage.graphs.generic_graph.GenericGraph.cartesian_product()
• graph_products – a module on graph products.
Note: This algorithm may run faster whenever the graph’s vertices are integers (see relabel()). Give it
a try if it is too slow !
EXAMPLES:
The Petersen graph is prime:
sage: g = graphs.PetersenGraph()
sage: is_cartesian_product(g)
False
sage: g = graphs.Grid2dGraph(5,5)
sage: p1, p2 = is_cartesian_product(g, certificate = True)
sage: p1.is_isomorphic(graphs.PathGraph(5))
True
sage: p2.is_isomorphic(graphs.PathGraph(5))
True
sage: g.relabel()
sage: b,D = g.is_cartesian_product(g, relabeling=True)
sage: b
True
sage: D # random isomorphism
{0: (20, 0), 1: (20, 1), 2: (20, 2), 3: (20, 3), 4: (20, 4),
5: (15, 0), 6: (15, 1), 7: (15, 2), 8: (15, 3), 9: (15, 4),
10: (10, 0), 11: (10, 1), 12: (10, 2), 13: (10, 3), 14: (10, 4),
15: (5, 0), 16: (5, 1), 17: (5, 2), 18: (5, 3), 19: (5, 4),
20: (0, 0), 21: (0, 1), 22: (0, 2), 23: (0, 3), 24: (0, 4)}
And of course, we find the factors back when we build a graph from a product:
sage: g = graphs.PetersenGraph().cartesian_product(graphs.CycleGraph(3))
sage: g1, g2 = is_cartesian_product(g, certificate = True)
sage: any( x.is_isomorphic(graphs.PetersenGraph()) for x in [g1,g2])
True
sage: any( x.is_isomorphic(graphs.CycleGraph(3)) for x in [g1,g2])
True
is_circumscribable(solver='ppl', verbose=0)
Test whether the graph is the graph of a circumscribed polyhedron.
A polyhedron is circumscribed if all of its facets are tangent to a sphere. By a theorem of Rivin
([HRS1993]), this can be checked by solving a linear program that assigns weights between 0 and 1/2
on each edge of the polyhedron, so that the weights on any face add to exactly one and the weights on any
non-facial cycle add to more than one. If and only if this can be done, the polyhedron can be circumscribed.
INPUT:
• solver – (default: "ppl"); specify a Linear Program (LP) solver to be used. If set to None, the
default one is used. For more information on LP solvers and which default solver is used, see the
method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
EXAMPLES:
sage: C = graphs.CubeGraph(3)
sage: C.is_circumscribable()
True
sage: O = graphs.OctahedralGraph()
sage: O.is_circumscribable()
True
sage: TT = polytopes.truncated_tetrahedron().graph()
sage: TT.is_circumscribable()
False
sage: f = set(flatten(choice(O.faces())))
sage: O.add_edges([[6, i] for i in f])
sage: O.is_circumscribable()
False
See also:
• is_polyhedral()
• is_inscribable()
is_cograph()
Check whether the graph is cograph.
A cograph is defined recursively: the single-vertex graph is cograph, complement of cograph is cograph,
and disjoint union of two cographs is cograph. There are many other characterizations, see the Wikipedia
article Cograph.
EXAMPLES:
sage: graphs.HouseXGraph().is_cograph()
True
sage: graphs.HouseGraph().is_cograph()
False
Todo: Implement faster recognition algorithm, as for instance the linear time recognition algorithm using
LexBFS proposed in [Bre2008].
– "MILP" – a Mixed Integer Linear Program formulation of the problem. Beware, for this implemen-
tation is unable to return negative certificates ! When certificate = True, negative certificates
are always equal to None. True certificates are valid, though.
• certificate (boolean) – whether to return a certificate. Yes-answers the certificate is a transitive
orientation of 𝐺, and a no certificates is an odd cycle of sequentially forcing edges.
• check (boolean) – whether to check that the yes-certificates are indeed transitive. As it is very quick
compared to the rest of the operation, it is enabled by default.
• solver – (default: None); Specify a Linear Program (LP) solver to be used. If set to None, the default
one is used. For more information on LP solvers and which default solver is used, see the method
solve() of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
EXAMPLES:
is_directed()
Since graph is undirected, returns False.
EXAMPLES:
sage: Graph().is_directed()
False
is_distance_regular(G, parameters=False)
Test if the graph is distance-regular
A graph 𝐺 is distance-regular if for any integers 𝑗, 𝑘 the value of |{𝑥 : 𝑑𝐺 (𝑥, 𝑢) = 𝑗, 𝑥 ∈ 𝑉 (𝐺)} ∩ {𝑦 :
𝑑𝐺 (𝑦, 𝑣) = 𝑗, 𝑦 ∈ 𝑉 (𝐺)}| is constant for any two vertices 𝑢, 𝑣 ∈ 𝑉 (𝐺) at distance 𝑖 from each other. In
particular 𝐺 is regular, of degree 𝑏0 (see below), as one can take 𝑢 = 𝑣.
Equivalently a graph is distance-regular if there exist integers 𝑏𝑖 , 𝑐𝑖 such that for any two vertices 𝑢, 𝑣 at
distance 𝑖 we have
• 𝑏𝑖 = |{𝑥 : 𝑑𝐺 (𝑥, 𝑢) = 𝑖 + 1, 𝑥 ∈ 𝑉 (𝐺)} ∩ 𝑁𝐺 (𝑣)}|, 0 ≤ 𝑖 ≤ 𝑑 − 1
• 𝑐𝑖 = |{𝑥 : 𝑑𝐺 (𝑥, 𝑢) = 𝑖 − 1, 𝑥 ∈ 𝑉 (𝐺)} ∩ 𝑁𝐺 (𝑣)}|, 1 ≤ 𝑖 ≤ 𝑑,
where 𝑑 is the diameter of the graph. For more information on distance-regular graphs, see the Wikipedia
article Distance-regular_graph.
INPUT:
• parameters – boolean (default: False); if set to True, the function returns the pair (b, c) of lists
of integers instead of a boolean answer (see the definition above)
See also:
• is_regular()
• is_strongly_regular()
EXAMPLES:
sage: g = graphs.PetersenGraph()
sage: g.is_distance_regular()
True
sage: g.is_distance_regular(parameters = True)
([3, 2, None], [None, 1, 1])
Cube graphs, which are not strongly regular, are a bit more interesting:
sage: graphs.CubeGraph(4).is_distance_regular()
True
sage: graphs.OddGraph(5).is_distance_regular()
True
Disconnected graph:
sage: (2*graphs.CubeGraph(4)).is_distance_regular()
True
sage: g = graphs.CycleGraph(5)
sage: g.is_dominating([0,1], [4, 2])
True
sage: g.is_dominating([0,1])
False
is_edge_transitive()
Check if self is an edge transitive graph.
A graph is edge-transitive if its automorphism group acts transitively on its edge set.
Equivalently, if there exists for any pair of edges 𝑢𝑣, 𝑢′ 𝑣 ′ ∈ 𝐸(𝐺) an automorphism 𝜑 of 𝐺 such that
𝜑(𝑢𝑣) = 𝑢′ 𝑣 ′ (note this does not necessarily mean that 𝜑(𝑢) = 𝑢′ and 𝜑(𝑣) = 𝑣 ′ ).
See also:
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.is_edge_transitive()
True
sage: C = graphs.CubeGraph(3)
sage: C.is_edge_transitive()
True
sage: G = graphs.GrayGraph()
sage: G.is_edge_transitive()
True
sage: P = graphs.PathGraph(4)
sage: P.is_edge_transitive()
False
is_even_hole_free(certificate=False)
Tests whether self contains an induced even hole.
A Hole is a cycle of length at least 4 (included). It is said to be even (resp. odd) if its length is even (resp.
odd).
Even-hole-free graphs always contain a bisimplicial vertex, which ensures that their chromatic number is
at most twice their clique number [ACHRS2008].
INPUT:
• certificate – boolean (default: False); when certificate = False, this method only returns
True or False. If certificate = True, the subgraph found is returned instead of False.
EXAMPLES:
Is the Petersen Graph even-hole-free
sage: g = graphs.PetersenGraph()
sage: g.is_even_hole_free()
False
As any chordal graph is hole-free, interval graphs behave the same way:
sage: g = graphs.RandomIntervalGraph(20)
sage: g.is_even_hole_free()
True
It is clear, though, that a random Bipartite Graph which is not a forest has an even hole:
More generally, every Hamiltonian graph with an odd number of vertices is factor-critical:
sage: F = graphs.FriendshipGraph(4)
sage: M = F.matching()
sage: F.is_factor_critical(matching=M)
True
sage: F.is_factor_critical(matching=Graph(M))
True
is_forest(certificate=False, output='vertex')
Tests if the graph is a forest, i.e. a disjoint union of trees.
INPUT:
• certificate – boolean (default: False); whether to return a certificate. The method only returns
boolean answers when certificate = False (default). When it is set to True, it either answers
(True, None) when the graph is a forest or (False, cycle) when it contains a cycle.
• output – either 'vertex' (default) or 'edge'; whether the certificate is given as a list of vertices
(output = 'vertex') or a list of edges (output = 'edge').
EXAMPLES:
With certificates:
sage: g = graphs.RandomTree(30)
sage: g.is_forest(certificate=True)
(True, None)
sage: (2*g + graphs.PetersenGraph() + g).is_forest(certificate=True)
(False, [68, 66, 69, 67, 65])
is_half_transitive()
Check if self is a half-transitive graph.
A graph is half-transitive if it is both vertex and edge transitive but not arc-transitive.
See also:
EXAMPLES:
The Petersen Graph is not half-transitive:
sage: P = graphs.PetersenGraph()
sage: P.is_half_transitive()
False
sage: H = graphs.HoltGraph()
sage: H.is_half_transitive()
True
is_inscribable(solver='ppl', verbose=0)
Test whether the graph is the graph of an inscribed polyhedron.
A polyhedron is inscribed if all of its vertices are on a sphere. This is dual to the notion of circumscribed
polyhedron: A Polyhedron is inscribed if and only if its polar dual is circumscribed and hence a graph is
inscribable if and only if its planar dual is circumscribable.
INPUT:
• solver – (default: "ppl"); specify a Linear Program (LP) solver to be used. If set to None, the
default one is used. For more information on LP solvers and which default solver is used, see the
method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
EXAMPLES:
sage: H = graphs.HerschelGraph()
sage: H.is_inscribable() # long time (> 1 sec)
False
sage: H.planar_dual().is_inscribable() # long time (> 1 sec)
True
sage: C = graphs.CubeGraph(3)
sage: C.is_inscribable()
True
sage: C = graphs.CubeGraph(3)
sage: v = next(C.vertex_iterator())
sage: triangle = [_ + v for _ in C.neighbors(v)]
sage: C.add_edges(Combinations(triangle, 2))
sage: C.add_edges(zip(triangle, C.neighbors(v)))
sage: C.delete_vertex(v)
sage: C.is_inscribable()
False
sage: C = graphs.CubeGraph(3)
sage: face = choice(C.faces())
sage: C.add_edge([face[0][0], face[2][0]])
sage: C.is_inscribable()
False
See also:
• is_polyhedral()
• is_circumscribable()
is_line_graph(g, certificate=False)
Check whether the graph 𝑔 is a line graph.
INPUT:
• certificate (boolean) – whether to return a certificate along with the boolean result. Here is what
happens when certificate = True:
– If the graph is not a line graph, the method returns a pair (b, subgraph) where b is False and
subgraph is a subgraph isomorphic to one of the 9 forbidden induced subgraphs of a line graph.
– If the graph is a line graph, the method returns a triple (b,R,isom) where b is True, R is a graph
whose line graph is the graph given as input, and isom is a map associating an edge of R to each
vertex of the graph.
Note: This method wastes a bit of time when the input graph is not connected. If you have performance
in mind, it is probably better to only feed it with connected graphs only.
See also:
EXAMPLES:
A complete graph is always the line graph of a star:
sage: graphs.CompleteGraph(5).is_line_graph()
True
sage: graphs.PetersenGraph().is_line_graph()
False
sage: C = graphs.PetersenGraph().is_line_graph(certificate=True)[1]
sage: C.is_isomorphic(graphs.ClawGraph())
True
sage: g = graphs.HouseGraph()
sage: g.is_line_graph()
True
is_long_antihole_free(g, certificate=False)
Tests whether the given graph contains an induced subgraph that is isomorphic to the complement of a
cycle of length at least 5.
INPUT:
• certificate – boolean (default: False)
Whether to return a certificate. When certificate = True, then the function returns
– (False, Antihole) if g contains an induced complement of a cycle of length at least 5 returned
as Antihole.
– (True, []) if g does not contain an induced complement of a cycle of length at least 5. For this
case it is not known how to provide a certificate.
When certificate = False, the function returns just True or False accordingly.
ALGORITHM:
This algorithm tries to find a cycle in the graph of all induced 𝑃4 of 𝑔, where two copies 𝑃 and 𝑃 ′ of 𝑃4
are adjacent if there exists a (not necessarily induced) copy of 𝑃5 = 𝑢1 𝑢2 𝑢3 𝑢4 𝑢5 such that 𝑃 = 𝑢1 𝑢2 𝑢3 𝑢4
and 𝑃 ′ = 𝑢2 𝑢3 𝑢4 𝑢5 .
This is done through a depth-first-search. For efficiency, the auxiliary graph is constructed on-the-fly and
never stored in memory.
The run time of this algorithm is 𝑂(𝑚2 ) [NP2007] (where 𝑚 is the number of edges of the graph).
EXAMPLES:
The Petersen Graph contains an antihole:
sage: g = graphs.PetersenGraph()
sage: g.is_long_antihole_free()
False
sage: g = graphs.CycleGraph(6).complement()
sage: r,a = g.is_long_antihole_free(certificate=True)
sage: r
False
sage: a.complement().is_isomorphic(graphs.CycleGraph(6))
True
is_long_hole_free(g, certificate=False)
Tests whether g contains an induced cycle of length at least 5.
INPUT:
• certificate – boolean (default: False)
Whether to return a certificate. When certificate = True, then the function returns
– (True, []) if g does not contain such a cycle. For this case, it is not known how to provide a
certificate.
– (False, Hole) if g contains an induced cycle of length at least 5. Hole returns this cycle.
If certificate = False, the function returns just True or False accordingly.
ALGORITHM:
This algorithm tries to find a cycle in the graph of all induced 𝑃4 of 𝑔, where two copies 𝑃 and 𝑃 ′ of 𝑃4
are adjacent if there exists a (not necessarily induced) copy of 𝑃5 = 𝑢1 𝑢2 𝑢3 𝑢4 𝑢5 such that 𝑃 = 𝑢1 𝑢2 𝑢3 𝑢4
and 𝑃 ′ = 𝑢2 𝑢3 𝑢4 𝑢5 .
This is done through a depth-first-search. For efficiency, the auxiliary graph is constructed on-the-fly and
never stored in memory.
The run time of this algorithm is 𝑂(𝑚2 ) [NP2007] ( where 𝑚 is the number of edges of the graph ) .
EXAMPLES:
The Petersen Graph contains a hole:
sage: g = graphs.PetersenGraph()
sage: g.is_long_hole_free()
False
sage: g = graphs.FlowerSnark()
sage: r,h = g.is_long_hole_free(certificate=True)
sage: r
False
sage: Graph(h).is_isomorphic(graphs.CycleGraph(h.order()))
True
is_odd_hole_free(certificate=False)
Tests whether self contains an induced odd hole.
A Hole is a cycle of length at least 4 (included). It is said to be even (resp. odd) if its length is even (resp.
odd).
It is interesting to notice that while it is polynomial to check whether a graph has an odd hole or an odd anti-
hole [CCLSV2005], it is not known whether testing for one of these two cases independently is polynomial
too.
INPUT:
• certificate – boolean (default: False); when certificate = False, this method only returns
True or False. If certificate = True, the subgraph found is returned instead of False.
EXAMPLES:
Is the Petersen Graph odd-hole-free
sage: g = graphs.PetersenGraph()
sage: g.is_odd_hole_free()
False
sage: g.girth()
5
sage: g = graphs.RandomIntervalGraph(20)
sage: g.is_odd_hole_free()
True
is_overfull()
Tests whether the current graph is overfull.
A graph 𝐺 on 𝑛 vertices and 𝑚 edges is said to be overfull if:
• 𝑛 is odd
• It satisfies 2𝑚 > (𝑛 − 1)∆(𝐺), where ∆(𝐺) denotes the maximum degree among all vertices in 𝐺.
An overfull graph must have a chromatic index of ∆(𝐺) + 1.
EXAMPLES:
A complete graph of order 𝑛 > 1 is overfull if and only if 𝑛 is odd:
sage: graphs.CompleteGraph(6).is_overfull()
False
sage: graphs.CompleteGraph(7).is_overfull()
True
sage: graphs.CompleteGraph(1).is_overfull()
False
sage: G = graphs.HoltGraph()
sage: G.is_overfull()
True
Checking that all complete graphs 𝐾𝑛 for even 0 ≤ 𝑛 ≤ 100 are not overfull:
The null graph, i.e. the graph with no vertices, is not overfull:
sage: Graph().is_overfull()
False
sage: graphs.CompleteGraph(0).is_overfull()
False
Checking that all complete graphs 𝐾𝑛 for odd 1 < 𝑛 ≤ 100 are overfull:
The Petersen Graph, though, is not overfull while its chromatic index is ∆ + 1:
sage: g = graphs.PetersenGraph()
sage: g.is_overfull()
False
sage: from sage.graphs.graph_coloring import edge_coloring
sage: max(g.degree()) + 1 == edge_coloring(g, value_only=True)
True
is_partial_cube(G, certificate=False)
Test whether the given graph is a partial cube.
A partial cube is a graph that can be isometrically embedded into a hypercube, i.e., its vertices can be
labelled with (0,1)-vectors of some fixed length such that the distance between any two vertices in the
graph equals the Hamming distance of their labels.
Originally written by D. Eppstein for the PADS library (http://www.ics.uci.edu/~eppstein/PADS/), see also
[Epp2008]. The algorithm runs in 𝑂(𝑛2 ) time, where 𝑛 is the number of vertices. See the documentation
of partial_cube for an overview of the algorithm.
INPUT:
• certificate – boolean (default: False); this function returns True or False according to the graph,
when certificate = False. When certificate = True and the graph is a partial cube, the
function returns (True, mapping), where mapping is an isometric mapping of the vertices of the
graph to the vertices of a hypercube ((0, 1)-strings of a fixed length). When certificate = True
and the graph is not a partial cube, (False, None) is returned.
EXAMPLES:
The Petersen graph is not a partial cube:
sage: g = graphs.PetersenGraph()
sage: g.is_partial_cube()
False
sage: g = graphs.CycleGraph(10).cartesian_product(graphs.CompleteGraph(2))
sage: g.is_partial_cube()
True
is_path()
Check whether self is a path.
A connected graph of order 𝑛 ≥ 2 is a path if it is a tree (see is_tree()) with 𝑛 − 2 vertices of degree 2
and two of degree 1. By convention, a graph of order 1 without loops is a path, but the empty graph is not
a path.
EXAMPLES:
sage: G = graphs.PathGraph(5) sage: G.is_path() True sage: H = graphs.CycleGraph(5) sage:
H.is_path() False sage: D = graphs.PathGraph(5).disjoint_union(graphs.CycleGraph(5)) sage:
D.is_path() False sage: E = graphs.EmptyGraph() sage: E.is_path() False sage: O = Graph([[1],
[]]) sage: O.is_path() True sage: O.allow_loops(True) sage: O.add_edge(1, 1) sage: O.is_path()
False
is_perfect(certificate=False)
Tests whether the graph is perfect.
A graph 𝐺 is said to be perfect if 𝜒(𝐻) = 𝜔(𝐻) hold for any induced subgraph 𝐻 ⊆𝑖 𝐺 (and so for 𝐺
itself, too), where 𝜒(𝐻) represents the chromatic number of 𝐻, and 𝜔(𝐻) its clique number. The Strong
Perfect Graph Theorem [CRST2006] gives another characterization of perfect graphs:
A graph is perfect if and only if it contains no odd hole (cycle on an odd number 𝑘 of vertices, 𝑘 > 3) nor
any odd antihole (complement of a hole) as an induced subgraph.
INPUT:
• certificate – boolean (default: False); whether to return a certificate.
OUTPUT:
When certificate = False, this function returns a boolean value. When certificate = True, it
returns a subgraph of self isomorphic to an odd hole or an odd antihole if any, and None otherwise.
EXAMPLES:
sage: g = graphs.RandomBipartite(8,4,.5)
sage: g.is_perfect()
True
sage: g = graphs.RandomBipartite(4,3,0.7)
sage: g.line_graph().is_perfect() # long time
True
sage: g = graphs.CompleteGraph(3).cartesian_product(graphs.CompleteGraph(3))
sage: g.is_perfect()
True
sage: g = graphs.RandomIntervalGraph(7)
sage: g.is_perfect()
True
The PetersenGraph, which is triangle-free and has chromatic number 3 is obviously not perfect:
sage: g = graphs.PetersenGraph()
sage: g.is_perfect()
False
sage: g.is_perfect(certificate=True)
Subgraph of (Petersen graph): Graph on 5 vertices
• solver – (default: None); Specify a Linear Program (LP) solver to be used. If set to None, the default
one is used. For more information on LP solvers and which default solver is used, see the method
solve() of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
Note: As the True certificate is a Permutation object, the segment intersection model of the permutation
graph can be visualized through a call to Permutation.show.
EXAMPLES:
A permutation realizing the bull graph:
is_polyhedral()
Check whether the graph is the graph of the polyhedron.
By a theorem of Steinitz (Satz 43, p. 77 of [St1922]), graphs of three-dimensional polyhedra are exactly
the simple 3-vertex-connected planar graphs.
EXAMPLES:
sage: C = graphs.CubeGraph(3)
sage: C.is_polyhedral()
True
sage: K33=graphs.CompleteBipartiteGraph(3, 3)
sage: K33.is_polyhedral()
False
sage: graphs.CycleGraph(17).is_polyhedral()
False
sage: [i for i in range(9) if graphs.CompleteGraph(i).is_polyhedral()]
[4]
See also:
• vertex_connectivity()
• is_planar()
• is_circumscribable()
• is_inscribable()
• Wikipedia article Polyhedral_graph
is_prime(algorithm=None)
Test whether the current graph is prime.
A graph is prime if all its modules are trivial (i.e. empty, all of the graph or singletons) – see
modular_decomposition(). Use the 𝑂(𝑛3 ) algorithm of [HM1979].
EXAMPLES:
The Petersen Graph and the Bull Graph are both prime:
sage: graphs.PetersenGraph().is_prime()
True
sage: graphs.BullGraph().is_prime()
True
Warning: The assumption is made that focus (if provided) does not contain repeated vertices.
EXAMPLES:
sage: G = graphs.CubeGraph(3)
sage: G.is_redundant(['000', '101'], ['011'])
True
sage: G.is_redundant(['000', '101'])
False
is_semi_symmetric()
Check if self is semi-symmetric.
A graph is semi-symmetric if it is regular, edge-transitive but not vertex-transitive.
See also:
EXAMPLES:
The Petersen graph is not semi-symmetric:
sage: P = graphs.PetersenGraph()
sage: P.is_semi_symmetric()
False
sage: G = graphs.GrayGraph()
sage: G.is_semi_symmetric()
True
sage: L = graphs.LjubljanaGraph()
sage: L.is_semi_symmetric()
True
is_split()
Returns True if the graph is a Split graph, False otherwise.
A Graph 𝐺 is said to be a split graph if its vertices 𝑉 (𝐺) can be partitioned into two sets 𝐾 and 𝐼 such that
the vertices of 𝐾 induce a complete graph, and those of 𝐼 are an independent set.
There is a simple test to check whether a graph is a split graph (see, for instance, the book “Graph Classes,
a survey” [BLS1999] page 203) :
Given the degree sequence 𝑑1 ≥ ... ≥ 𝑑𝑛 of 𝐺, a graph is a split graph if and only if :
𝜔
∑︁ 𝑛
∑︁
𝑑𝑖 = 𝜔(𝜔 − 1) + 𝑑𝑖
𝑖=1 𝑖=𝜔+1
sage: graphs.PetersenGraph().is_split()
False
We can easily build some “random” split graph by creating a complete graph, and adding vertices only
connected to some random vertices of the clique:
sage: g = graphs.CompleteGraph(10)
sage: sets = Subsets(Set(range(10)))
sage: for i in range(10, 25):
....: g.add_edges([(i,k) for k in sets.random_element()])
sage: g.is_split()
True
Another characterisation of split graph states that a graph is a split graph if and only if does not contain the
4-cycle, 5-cycle or 2𝐾2 as an induced subgraph. Hence for the above graph we have:
is_strongly_regular(g, parameters=False)
Check whether the graph is strongly regular.
A simple graph 𝐺 is said to be strongly regular with parameters (𝑛, 𝑘, 𝜆, 𝜇) if and only if:
• 𝐺 has 𝑛 vertices
• 𝐺 is 𝑘-regular
• Any two adjacent vertices of 𝐺 have 𝜆 common neighbors
• Any two non-adjacent vertices of 𝐺 have 𝜇 common neighbors
By convention, the complete graphs, the graphs with no edges and the empty graph are not strongly regular.
See the Wikipedia article Strongly regular graph.
INPUT:
• parameters – boolean (default: False); whether to return the quadruple (𝑛, 𝑘, 𝜆, 𝜇). If parameters
= False (default), this method only returns True and False answers. If parameters = True, the
True answers are replaced by quadruples (𝑛, 𝑘, 𝜆, 𝜇). See definition above.
EXAMPLES:
Petersen’s graph is strongly regular:
sage: g = graphs.PetersenGraph()
sage: g.is_strongly_regular()
True
sage: g.is_strongly_regular(parameters=True)
(10, 3, 0, 1)
sage: g = graphs.ClebschGraph()
sage: g.is_strongly_regular()
True
sage: g.is_strongly_regular(parameters=True)
(16, 5, 0, 2)
sage: g = graphs.ChvatalGraph()
sage: g.is_strongly_regular()
False
sage: g = graphs.CompleteGraph(5)
sage: g.is_strongly_regular()
False
sage: g = graphs.CompleteGraph(5).complement()
sage: g.is_strongly_regular()
False
sage: g = graphs.EmptyGraph()
sage: g.is_strongly_regular()
False
sage: Graph([(1,1),(2,2)],loops=True).is_strongly_regular()
Traceback (most recent call last):
...
ValueError: This method is not known to work on graphs with
loops. Perhaps this method can be updated to handle them, but in the
meantime if you want to use it please disallow loops using
allow_loops().
sage: Graph([(1,2),(1,2)],multiedges=True).is_strongly_regular()
Traceback (most recent call last):
...
ValueError: This method is not known to work on graphs with
multiedges. Perhaps this method can be updated to handle them, but in
the meantime if you want to use it please disallow multiedges using
allow_multiple_edges().
is_tree(certificate=False, output='vertex')
Tests if the graph is a tree
The empty graph is defined to be not a tree.
INPUT:
• certificate – boolean (default: False); whether to return a certificate. The method only returns
boolean answers when certificate = False (default). When it is set to True, it either answers
(True, None) when the graph is a tree or (False, cycle) when it contains a cycle. It returns
(False, None) when the graph is empty or not connected.
• output – either 'vertex' (default) or 'edge'; whether the certificate is given as a list of vertices
(output = 'vertex') or a list of edges (output = 'edge').
When the certificate cycle is given as a list of edges, the edges are given as (𝑣𝑖 , 𝑣𝑖+1 , 𝑙) where 𝑣1 , 𝑣2 , . . . , 𝑣𝑛
are the vertices of the cycles (in their cyclic order).
EXAMPLES:
With certificates:
sage: g = graphs.RandomTree(30)
sage: g.is_tree(certificate=True)
(True, None)
(continues on next page)
sage: g = graphs.CycleGraph(4)
sage: g.is_tree(certificate=True, output='edge')
(False, [(3, 2, None), (2, 1, None), (1, 0, None), (0, 3, None)])
is_triangle_free(algorithm='dense_graph', certificate=False)
Check whether self is triangle-free
INPUT:
• algorithm – (default: 'dense_graph') specifies the algorithm to use among:
– 'matrix' – tests if the trace of the adjacency matrix is positive.
– 'bitset' – encodes adjacencies into bitsets and uses fast bitset operations to test if the input
graph contains a triangle. This method is generally faster than standard matrix multiplication.
– 'dense_graph' – use the implementation of sage.graphs.base.static_dense_graph
• certificate – boolean (default: False); whether to return a triangle if one is found. This parameter
is ignored when algorithm is 'matrix'.
EXAMPLES:
The Petersen Graph is triangle-free:
sage: g = graphs.PetersenGraph()
sage: g.is_triangle_free()
True
sage: G = graphs.CompleteBipartiteGraph(5,6)
sage: G.is_triangle_free(algorithm='matrix')
True
sage: G.is_triangle_free(algorithm='bitset')
True
sage: G.is_triangle_free(algorithm='dense_graph')
True
sage: G = (3 * graphs.CompleteGraph(5)).complement()
sage: G.is_triangle_free(algorithm='matrix')
False
sage: G.is_triangle_free(algorithm='bitset')
False
sage: G.is_triangle_free(algorithm='dense_graph')
False
sage: K4 = graphs.CompleteGraph(4)
sage: K4.is_triangle_free(algorithm='dense_graph', certificate=True)
(False, [0, 1, 2])
sage: K4.is_triangle_free(algorithm='bitset', certificate=True)
(False, [0, 1, 2])
is_triconnected(G)
Check whether the graph is triconnected.
A triconnected graph is a connected graph on 3 or more vertices that is not broken into disconnected pieces
by deleting any pair of vertices.
EXAMPLES:
The Petersen graph is triconnected:
sage: G = graphs.PetersenGraph()
sage: G.is_triconnected()
True
sage: G = graphs.Grid2dGraph(3, 3)
sage: G.is_triconnected()
False
sage: G = graphs.CycleGraph(3)
sage: G.is_triconnected()
True
Comparing different methods on random graphs that are not always triconnected:
sage: G = graphs.RandomBarabasiAlbert(50, 3)
sage: G.is_triconnected() == G.vertex_connectivity(k=3)
True
See also:
• is_connected()
• is_biconnected()
• spqr_tree()
• Wikipedia article SPQR_tree
is_weakly_chordal(g, certificate=False)
Tests whether the given graph is weakly chordal, i.e., the graph and its complement have no induced cycle
of length at least 5.
INPUT:
• certificate – Boolean value (default: False) whether to return a certificate. If certificate =
False, return True or False according to the graph. If certificate = True, return
– (False, forbidden_subgraph) when the graph contains a forbidden subgraph H, this graph
is returned.
– (True, []) when the graph is weakly chordal. For this case, it is not known how to provide a
certificate.
ALGORITHM:
This algorithm checks whether the graph g or its complement contain an induced cycle of length at least 5.
Using is_long_hole_free() and is_long_antihole_free() yields a run time of 𝑂(𝑚2 ) (where 𝑚 is the number
of edges of the graph).
EXAMPLES:
The Petersen Graph is not weakly chordal and contains a hole:
sage: g = graphs.PetersenGraph()
sage: r,s = g.is_weakly_chordal(certificate=True)
sage: r
False
sage: l = s.order()
sage: s.is_isomorphic(graphs.CycleGraph(l))
True
• union()
• disjoint_union()
EXAMPLES:
sage: G = graphs.CycleGraph(3)
sage: H = Graph(2)
sage: J = G.join(H); J
Cycle graph join : Graph on 5 vertices
sage: J.vertices(sort=True)
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1)]
sage: J = G.join(H, labels='integers'); J
Cycle graph join : Graph on 5 vertices
sage: J.vertices(sort=True)
[0, 1, 2, 3, 4]
sage: J.edges(sort=True)
[(0, 1, None), (0, 2, None), (0, 3, None), (0, 4, None), (1, 2, None), (1, 3,␣
˓→None), (1, 4, None), (2, 3, None), (2, 4, None)]
sage: G = Graph(3)
sage: G.name("Graph on 3 vertices")
sage: H = Graph(2)
sage: H.name("Graph on 2 vertices")
sage: J = G.join(H); J
Graph on 3 vertices join Graph on 2 vertices: Graph on 5 vertices
sage: J.vertices(sort=True)
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1)]
sage: J = G.join(H, labels='integers'); J
Graph on 3 vertices join Graph on 2 vertices: Graph on 5 vertices
sage: J.edges(sort=True)
[(0, 3, None), (0, 4, None), (1, 3, None), (1, 4, None), (2, 3, None), (2, 4,␣
˓→None)]
kirchhoff_symanzik_polynomial(name='t')
Return the Kirchhoff-Symanzik polynomial of a graph.
This is a polynomial in variables 𝑡𝑒 (each of them representing an edge of the graph 𝐺) defined as a sum
over all spanning trees:
∑︁ ∏︁
Ψ𝐺 (𝑡) = 𝑡𝑒
𝑇 ⊆𝑉 𝑒̸∈𝐸(𝑇 )
a spanning tree
This is also called the first Symanzik polynomial or the Kirchhoff polynomial.
INPUT:
• name – name of the variables (default: 't')
OUTPUT:
• a polynomial with integer coefficients
ALGORITHM:
This is computed here using a determinant, as explained in Section 3.1 of [Mar2009a].
As an intermediate step, one computes a cycle basis 𝒞 of 𝐺 and a rectangular |𝒞| × |𝐸(𝐺)| ma-
trix with entries in {−1, 0, 1}, which describes which edge belong to which cycle of 𝒞 and their
respective orientations.
More precisely, after fixing an arbitrary orientation for each edge 𝑒 ∈ 𝐸(𝐺) and each cycle 𝐶 ∈ 𝒞,
one gets a sign for every incident pair (edge, cycle) which is 1 if the orientation coincide and −1
otherwise.
EXAMPLES:
For the cycle of length 5:
sage: G = graphs.CycleGraph(5)
sage: G.kirchhoff_symanzik_polynomial()
t0 + t1 + t2 + t3 + t4
sage: G.kirchhoff_symanzik_polynomial(name='u')
u0 + u1 + u2 + u3 + u4
sage: G = graphs.CompleteGraph(4)
sage: G.kirchhoff_symanzik_polynomial()
t0*t1*t3 + t0*t2*t3 + t1*t2*t3 + t0*t1*t4 + t0*t2*t4 + t1*t2*t4
+ t1*t3*t4 + t2*t3*t4 + t0*t1*t5 + t0*t2*t5 + t1*t2*t5 + t0*t3*t5
+ t2*t3*t5 + t0*t4*t5 + t1*t4*t5 + t3*t4*t5
REFERENCES:
[Bro2011]
least_effective_resistance(nonedgesonly=True)
Return a list of pairs of nodes with the least effective resistance.
The resistance distance between vertices 𝑖 and 𝑗 of a simple connected graph 𝐺 is defined as the effective
resistance between the two vertices on an electrical network constructed from 𝐺 replacing each edge of the
graph by a unit (1 ohm) resistor.
INPUT:
• nonedgesonly – Boolean (default: 𝑇 𝑟𝑢𝑒); if true, assign zero resistance to pairs of adjacent vertices
OUTPUT: list
EXAMPLES:
Pairs of non-adjacent nodes with least effective resistance in a straight linear 2-tree on 6 vertices:
sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)])
sage: G.least_effective_resistance()
[(1, 4)]
Pairs of (adjacent or non-adjacent) nodes with least effective resistance in a straight linear 2-tree on 6
vertices
Pairs of non-adjacent nodes with least effective resistance in a fan on 6 vertices counting only non-adjacent
vertex pairs
sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)])
sage: H.least_effective_resistance()
[(2, 4)]
See also:
INPUT:
• triangulation – boolean (default: False); whether to return a list of edges that need to be added
in order to triangulate the graph
• labels – boolean (default: False); whether to return the labels assigned to each vertex
• initial_vertex – (default: None); the first vertex to consider
• algorithm – string (default: None); one of the following algorithms:
– 'lex_M_slow': slower implementation of LexM traversal
– 'lex_M_fast': faster implementation of LexM traversal (works only when labels is set to
False)
– None: Sage chooses the best algorithm: 'lex_M_slow' if labels is set to True, 'lex_M_fast'
otherwise.
OUTPUT:
Depending on the values of the parameters triangulation and labels the method will return one or
more of the following (in that order):
• an ordering of vertices of the graph according to LexM ordering scheme
• the labels assigned to each vertex
• a list of edges that when added to the graph will triangulate it
EXAMPLES:
LexM produces an ordering of the vertices:
sage: g = graphs.CompleteGraph(6)
sage: ord = g.lex_M(algorithm='lex_M_fast')
sage: len(ord) == g.order()
True
sage: set(ord) == set(g.vertices(sort=False))
True
sage: ord = g.lex_M(algorithm='lex_M_slow')
sage: len(ord) == g.order()
True
sage: set(ord) == set(g.vertices(sort=False))
True
Both algorithms produce a valid LexM ordering 𝛼 (i.e the neighbors of 𝛼(𝑖) in 𝐺[{𝛼(𝑖), ..., 𝛼(𝑛)}] induce
a clique):
sage: G = graphs.PetersenGraph()
sage: _, F = G.lex_M(triangulation=True)
sage: H = Graph(F, format='list_of_edges')
sage: H.is_chordal()
True
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4, 5),
˓→ (5, 6)])
sage: g.lex_M()
[6, 4, 5, 3, 2, 1]
lovasz_theta(graph)
Return the value of Lovász theta-function of graph.
For a graph 𝐺 this function is denoted by 𝜃(𝐺), and it can be computed in polynomial time. Mathematically,
its most important property is the following:
with 𝛼(𝐺) and 𝜒(𝐺) being, respectively, the maximum size of an independent set set of 𝐺 and the
chromatic number of the complement 𝐺 of 𝐺.
For more information, see the Wikipedia article Lovász_number.
Note:
• Implemented for undirected graphs only. Use to_undirected to convert a digraph to an undirected
graph.
• This function requires the optional package csdp, which you can install with sage -i csdp.
EXAMPLES:
sage: C = graphs.PetersenGraph()
sage: C.lovasz_theta() # optional csdp
4.0
sage: graphs.CycleGraph(5).lovasz_theta() # optional csdp
2.236068
magnitude_function()
Return the magnitude function of the graph as a rational function.
This is defined as the sum of all coefficients in the inverse of the matrix 𝑍 whose coefficient 𝑍𝑖,𝑗 indexed
by a pair of vertices (𝑖, 𝑗) is 𝑞 𝑑 (𝑖, 𝑗) where 𝑑 is the distance function in the graph.
By convention, if the distance from 𝑖 to 𝑗 is infinite (for two vertices not path connected) then 𝑍𝑖,𝑗 = 0.
The value of the magnitude function at 𝑞 = 0 is the cardinality of the graph. The magnitude function
of a disjoint union is the sum of the magnitudes functions of the connected components. The magnitude
function of a Cartesian product is the product of the magnitudes functions of the factors.
EXAMPLES:
sage: g = graphs.CycleGraph(4)
sage: g.magnitude_function()
4/(q^2 + 2*q + 1)
sage: g = graphs.CycleGraph(5)
sage: m = g.magnitude_function(); m
5/(2*q^2 + 2*q + 1)
sage: q = QQ[['q']].gen()
sage: m(q)
5 - 10*q + 10*q^2 - 20*q^4 + 40*q^5 - 40*q^6 + ...
One can also use the substitution 𝑞 = 𝑒𝑥𝑝(−𝑡) to obtain the magnitude function as a function of 𝑡:
sage: g = graphs.CycleGraph(6)
sage: m = g.magnitude_function()
sage: t = var('t') # optional -
˓→ sage.symbolic
REFERENCES:
matching(value_only, algorithm=False, use_edge_labels='Edmonds', solver=False, verbose=None,
integrality_tolerance=0)
Return a maximum weighted matching of the graph represented by the list of its edges.
∀𝑥 ∈ 𝐺, 𝑏𝑥 is a binary variable
INPUT:
• value_only – boolean (default: False); when set to True, only the cardinal (or the weight) of the
matching is returned
• algorithm – string (default: "Edmonds")
– "Edmonds" selects Edmonds’ algorithm as implemented in NetworkX
– "LP" uses a Linear Program formulation of the matching problem
• use_edge_labels – boolean (default: False)
– when set to True, computes a weighted matching where each edge is weighted by its label (if an
edge has no label, 1 is assumed)
– when set to False, each edge has weight 1
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity: set to 0 by default, which means quiet (only
useful when algorithm == "LP")
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
OUTPUT:
• When value_only=False (default), this method returns an EdgesView containing the edges of a
maximum matching of 𝐺.
• When value_only=True, this method returns the sum of the weights (default: 1) of the edges of a
maximum matching of 𝐺. The type of the output may vary according to the type of the edge labels
and the algorithm used.
ALGORITHM:
The problem is solved using Edmond’s algorithm implemented in NetworkX, or using Linear Programming
depending on the value of algorithm.
EXAMPLES:
Maximum matching in a Pappus Graph:
sage: g = graphs.PappusGraph()
sage: g.matching(value_only=True)
9
sage: g = graphs.PappusGraph()
sage: g.matching(algorithm="LP", value_only=True)
9
6
1 5
7 12 11
13 17
14 16
8 15 10
2 4
9
3
matching_polynomial(G, complement=True, name=None)
Computes the matching polynomial of the graph 𝐺.
If 𝑝(𝐺, 𝑘) denotes the number of 𝑘-matchings (matchings with 𝑘 edges) in 𝐺, then the matching polynomial
is defined as [God1993]:
∑︁
𝜇(𝑥) = (−1)𝑘 𝑝(𝐺, 𝑘)𝑥𝑛−2𝑘
𝑘≥0
INPUT:
• complement - (default: True) whether to use Godsil’s duality theorem to compute the matching poly-
nomial from that of the graphs complement (see ALGORITHM).
• name - optional string for the variable name in the polynomial
Note: The complement option uses matching polynomials of complete graphs, which are cached. So if
you are crazy enough to try computing the matching polynomial on a graph with millions of vertices, you
might not want to use this option, since it will end up caching millions of polynomials of degree in the
millions.
ALGORITHM:
The algorithm used is a recursive one, based on the following observation [God1993]:
• If 𝑒 is an edge of 𝐺, 𝐺′ is the result of deleting the edge 𝑒, and 𝐺′′ is the result of deleting each vertex
in 𝑒, then the matching polynomial of 𝐺 is equal to that of 𝐺′ minus that of 𝐺′′ .
(the algorithm actually computes the signless matching polynomial, for which the recursion is the same
when one replaces the subtraction by an addition. It is then converted into the matching polynomial
and returned)
Depending on the value of complement, Godsil’s duality theorem [God1993] can also be used to compute
𝜇(𝑥) :
∑︁
𝜇(𝐺, 𝑥) = 𝑝(𝐺, 𝑘)𝜇(𝐾𝑛−2𝑘 , 𝑥)
𝑘≥0
sage: g = graphs.PetersenGraph()
sage: g.matching_polynomial()
x^10 - 15*x^8 + 75*x^6 - 145*x^4 + 90*x^2 - 6
sage: g.matching_polynomial(complement=False)
x^10 - 15*x^8 + 75*x^6 - 145*x^4 + 90*x^2 - 6
sage: g.matching_polynomial(name='tom')
tom^10 - 15*tom^8 + 75*tom^6 - 145*tom^4 + 90*tom^2 - 6
sage: g = Graph()
sage: L = [graphs.RandomGNP(8, .3) for i in range(1, 6)]
sage: prod([h.matching_polynomial() for h in L]) == sum(L, g).matching_
˓→polynomial() # long time (up to 10s on sage.math, 2011)
True
sage: g = graphs.RandomGNP(20,.3)
sage: mad_g = g.maximum_average_degree()
sage: g.average_degree() <= mad_g
True
Unlike the average degree, the 𝑀 𝑎𝑑 of the disjoint union of two graphs is the maximum of the 𝑀 𝑎𝑑 of
each graphs:
sage: h = graphs.RandomGNP(20,.3)
sage: mad_h = h.maximum_average_degree()
sage: (g+h).maximum_average_degree() == max(mad_g, mad_h)
True
The subgraph of a regular graph realizing the maximum average degree is always the whole graph
sage: g = graphs.CompleteGraph(5)
sage: mad_g = g.maximum_average_degree(value_only=False)
sage: g.is_isomorphic(mad_g)
True
sage: g = graphs.CompleteBipartiteGraph(3,4)
sage: mad_g = g.maximum_average_degree(value_only=False)
sage: g.is_isomorphic(mad_g)
True
INPUT:
• G – a Sage Graph
• reverse – boolean (default: False); whether to return the vertices in discovery order, or the reverse
• tree – boolean (default: False); whether to also return the discovery directed tree (each vertex being
linked to the one that saw it for the first time)
• initial_vertex – (default: None); the first vertex to consider
OUTPUT:
By default, return the ordering 𝛼 as a list. When tree is True, the method returns a tuple (𝛼, 𝑇 ), where 𝑇
is a directed tree with the same set of vertices as 𝐺 to 𝑣 if 𝑢 was the first vertex to saw 𝑣.
EXAMPLES:
When specified, the initial_vertex is placed at the end of the ordering, unless parameter reverse is
True, in which case it is placed at the beginning:
sage: G = graphs.PathGraph(4)
sage: G.maximum_cardinality_search(initial_vertex=0)
[3, 2, 1, 0]
sage: G.maximum_cardinality_search(initial_vertex=1)
[0, 3, 2, 1]
sage: G.maximum_cardinality_search(initial_vertex=2)
[0, 1, 3, 2]
sage: G.maximum_cardinality_search(initial_vertex=3)
[0, 1, 2, 3]
sage: G.maximum_cardinality_search(initial_vertex=3, reverse=True)
[3, 2, 1, 0]
sage: G = graphs.PathGraph(4)
sage: _, T = G.maximum_cardinality_search(tree=True, initial_vertex=0)
(continues on next page)
maximum_cardinality_search_M(G, initial_vertex=None)
Return the ordering and the edges of the triangulation produced by MCS-M.
Maximum cardinality search M (MCS-M) is an extension of MCS (maximum_cardinality_search())
in the same way that Lex-M (lex_M()) is an extension of Lex-BFS (lex_BFS()). That is, in MCS-M when
𝑢 receives number 𝑖 at step 𝑛 − 𝑖 + 1, it increments the weight of all unnumbered vertices 𝑣 for which there
exists a path between 𝑢 and 𝑣 consisting only of unnumbered vertices with weight strictly less than 𝑤− (𝑢)
and 𝑤− (𝑣), where 𝑤− is the number of times a vertex has been reached during previous iterations. See
[BBHP2004] for the details of this 𝑂(𝑛𝑚) time algorithm.
If 𝐺 is not connected, the orderings of each of its connected components are added consecutively. Further-
more, if 𝐺 has 𝑘 connected components 𝐶𝑖 for 0 ≤ 𝑖 < 𝑘, 𝑋 contains at least one vertex of 𝐶𝑖 for each
𝑖 ≥ 1. Hence, |𝑋| ≥ 𝑘 − 1. In particular, some isolated vertices (i.e., of degree 0) can appear in 𝑋 as for
such a vertex 𝑥, we have that 𝐺 ∖ 𝑁 (𝑥) = 𝐺 is not connected.
INPUT:
• G – a Sage graph
• initial_vertex – (default: None); the first vertex to consider
OUTPUT: a tuple (𝛼, 𝐹, 𝑋), where
• 𝛼 is the resulting ordering of the vertices. If an initial vertex is specified, it gets the last position in the
ordering 𝛼.
• 𝐹 is the list of edges of a minimal triangulation of 𝐺 according 𝛼
• 𝑋 is a list of vertices such that for each 𝑥 ∈ 𝑋, the neighborhood of 𝑥 in 𝐺 is a separator (i.e., 𝐺∖𝑁 (𝑥)
is not connected). Note that we may have 𝑁 (𝑥) = ∅ if 𝐺 is not connected and 𝑥 has degree 0.
EXAMPLES:
Chordal graphs have a perfect elimination ordering, and so the set 𝐹 of edges of the triangulation is empty:
sage: G = graphs.RandomChordalGraph(20)
sage: alpha, F, X = G.maximum_cardinality_search_M(); F
[]
The cycle of order 4 is not chordal and so the triangulation has one edge:
sage: G = graphs.CycleGraph(4)
sage: alpha, F, X = G.maximum_cardinality_search_M(); len(F)
1
The number of edges needed to triangulate of a cycle graph or order 𝑛 is 𝑛 − 3, independently of the initial
vertex:
When an initial vertex is specified, it gets the last position in the ordering:
sage: G = graphs.PathGraph(4)
sage: G.maximum_cardinality_search_M(initial_vertex=0)
([3, 2, 1, 0], [], [2, 3])
sage: G.maximum_cardinality_search_M(initial_vertex=1)
([3, 2, 0, 1], [], [2, 3])
sage: G.maximum_cardinality_search_M(initial_vertex=2)
([0, 1, 3, 2], [], [0, 1])
sage: G.maximum_cardinality_search_M(initial_vertex=3)
([0, 1, 2, 3], [], [0, 1])
When 𝐺 is not connected, the orderings of each of its connected components are added consecutively, the
vertices of the component containing the initial vertex occupying the last positions:
sage: G = graphs.CycleGraph(4) * 2
sage: G.maximum_cardinality_search_M()[0]
[5, 4, 6, 7, 2, 3, 1, 0]
sage: G.maximum_cardinality_search_M(initial_vertex=7)[0]
[2, 1, 3, 0, 5, 6, 4, 7]
Furthermore, if 𝐺 has 𝑘 connected components, 𝑋 contains at least one vertex per connected component,
except for the first one, and so at least 𝑘 − 1 vertices:
sage: G = Graph({'a': ['b', 'k'], 'b': ['c'], 'c': ['d', 'j', 'k'],
....: 'd': ['e', 'f', 'j', 'k'], 'e': ['g'],
....: 'f': ['g', 'j', 'k'], 'g': ['j', 'k'], 'h': ['i', 'j'],
....: 'i': ['k'], 'j': ['k']})
sage: _, F, _ = G.maximum_cardinality_search_M(initial_vertex='a')
sage: len(F)
3
INPUT:
• G – a graph.
• to_dominate – vertex iterable or None (default: None); the set of vertices to be dominated.
• work_on_copy – boolean (default: True); whether or not to work on a copy of the input graph; if set
to False, the input graph will be modified (relabeled).
OUTPUT:
An iterator over the inclusion-minimal sets of vertices of G. If to_dominate is provided, return an iterator
over the inclusion-minimal sets of vertices that dominate the vertices of to_dominate.
ALGORITHM: The algorithm described in [BDHPR2019].
AUTHOR: Jean-Florent Raymond (2019-03-04) – initial version.
EXAMPLES:
sage: G = graphs.ButterflyGraph()
sage: ll = list(G.minimal_dominating_sets())
sage: pp = [{0, 1}, {1, 3}, {0, 2}, {2, 3}, {4}]
sage: len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in␣
˓→pp)
True
sage: ll = list(G.minimal_dominating_sets([0,3]))
sage: pp = [{0}, {3}, {4}]
sage: len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in␣
˓→pp)
True
sage: ll = list(G.minimal_dominating_sets([4]))
sage: pp = [{4}, {0}, {1}, {2}, {3}]
sage: len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in␣
˓→pp)
True
sage: ll = list(graphs.PetersenGraph().minimal_dominating_sets())
sage: pp = [{0, 2, 6},
....: {0, 9, 3},
....: {0, 8, 7},
....: {1, 3, 7},
....: {1, 4, 5},
....: {8, 1, 9},
....: {8, 2, 4},
....: {9, 2, 5},
....: {3, 5, 6},
....: {4, 6, 7},
....: {0, 8, 2, 9},
....: {0, 3, 6, 7},
....: {1, 3, 5, 9},
....: {8, 1, 4, 7},
....: {2, 4, 5, 6},
....: {0, 1, 2, 3, 4},
....: {0, 1, 2, 5, 7},
(continues on next page)
True
sage: g = graphs.CompleteBipartiteGraph(3,4)
sage: o = g.minimum_outdegree_orientation()
sage: max(o.out_degree()) == integer_ceil((4*3)/(3+4))
True
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
OUTPUT:
A dictionary associating to each vertex of 𝐻 the set of vertices in the current graph representing it.
ALGORITHM:
Mixed Integer Linear Programming
COMPLEXITY:
Theoretically, when 𝐻 is fixed, testing for the existence of a 𝐻-minor is polynomial. The known algorithms
are highly exponential in 𝐻, though.
Note: This function can be expected to be very slow, especially where the minor does not exist.
EXAMPLES:
Trying to find a minor isomorphic to 𝐾4 in the 4 × 4 grid:
sage: g = graphs.GridGraph([4,4])
sage: h = graphs.CompleteGraph(4)
sage: L = g.minor(h)
sage: gg = g.subgraph(flatten(L.values(), max_level = 1))
sage: _ = [gg.merge_vertices(l) for l in L.values() if len(l)>1]
sage: gg.is_isomorphic(h)
True
We can also try to prove this way that the Petersen graph is not planar, as it has a 𝐾5 minor:
sage: g = graphs.PetersenGraph()
sage: K5_minor = g.minor(graphs.CompleteGraph(5)) # long time
(It is much faster to use the linear-time test of planarity in this situation, though.)
As there is no cycle in a tree, looking for a 𝐾3 minor is useless. This function will raise an exception in
this case:
sage: g = graphs.RandomGNP(20,.5)
sage: g = g.subgraph(edges = g.min_spanning_tree())
sage: g.is_tree()
True
sage: L = g.minor(graphs.CompleteGraph(3))
Traceback (most recent call last):
...
ValueError: This graph has no minor isomorphic to H !
modular_decomposition(algorithm=None, style='tuple')
Return the modular decomposition of the current graph.
A module of an undirected graph is a subset of vertices such that every vertex outside the module is ei-
ther connected to all members of the module or to none of them. Every graph that has a nontrivial mod-
ule can be partitioned into modules, and the increasingly fine partitions into modules form a tree. The
modular_decomposition function returns that tree, using an 𝑂(𝑛3 ) algorithm of [HM1979].
INPUT:
• style – string (default: 'tuple'); specifies the output format:
– 'tuple' – as nested tuples.
– 'tree' – as LabelledRootedTree.
OUTPUT:
A pair of two values (recursively encoding the decomposition) :
• The type of the current module :
– "PARALLEL"
– "PRIME"
– "SERIES"
• The list of submodules (as list of pairs (type, list), recursively. . . ) or the vertex’s name if the
module is a singleton.
Crash course on modular decomposition:
A module 𝑀 of a graph 𝐺 is a proper subset of its vertices such that for all 𝑢 ∈ 𝑉 (𝐺) − 𝑀, 𝑣, 𝑤 ∈ 𝑀 the
relation 𝑢 ∼ 𝑣 ⇔ 𝑢 ∼ 𝑤 holds, where ∼ denotes the adjacency relation in 𝐺. Equivalently, 𝑀 ⊂ 𝑉 (𝐺) is
a module if all its vertices have the same adjacency relations with each vertex outside of the module (vertex
by vertex).
Hence, for a set like a module, it is very easy to encode the information of the adjacencies between the
vertices inside and outside the module – we can actually add a new vertex 𝑣𝑀 to our graph representing
our module 𝑀 , and let 𝑣𝑀 be adjacent to 𝑢 ∈ 𝑉 (𝐺) − 𝑀 if and only if some 𝑣 ∈ 𝑀 (and hence all the
vertices contained in the module) is adjacent to 𝑢. We can now independently (and recursively) study the
structure of our module 𝑀 and the new graph 𝐺 − 𝑀 + {𝑣𝑀 }, without any loss of information.
Here are two very simple modules :
• A connected component 𝐶 (or the union of some –but not all– of them) of a disconnected graph 𝐺,
for instance, is a module, as no vertex of 𝐶 has a neighbor outside of it.
• An anticomponent 𝐶 (or the union of some –but not all– of them) of an non-anticonnected graph 𝐺,
for the same reason (it is just the complement of the previous graph !).
These modules being of special interest, the disjoint union of graphs is called a Parallel composition, and the
complement of a disjoint union is called a Series composition. A graph whose only modules are singletons
is called Prime.
For more information on modular decomposition, in particular for an explanation of the terms “Parallel,”
“Prime” and “Series,” see the Wikipedia article Modular_decomposition.
You may also be interested in the survey from Michel Habib and Christophe Paul entitled “A survey on
Algorithmic aspects of modular decomposition” [HP2010].
EXAMPLES:
The Bull Graph is prime:
sage: graphs.BullGraph().modular_decomposition()
(PRIME, [1, 2, 0, 3, 4])
sage: graphs.PetersenGraph().modular_decomposition()
(PRIME, [1, 4, 5, 0, 2, 6, 3, 7, 8, 9])
This a clique on 5 vertices with 2 pendant edges, though, has a more interesting decomposition:
sage: g = graphs.CompleteGraph(5)
sage: g.add_edge(0,5)
sage: g.add_edge(0,6)
sage: g.modular_decomposition()
(SERIES, [(PARALLEL, [(SERIES, [1, 2, 3, 4]), 5, 6]), 0])
sage: g.modular_decomposition(style='tree')
SERIES[0[], PARALLEL[5[], 6[], SERIES[1[], 2[], 3[], 4[]]]]
sage: ascii_art(g.modular_decomposition(style='tree'))
__SERIES
/ /
0 ___PARALLEL
/ / /
5 6 __SERIES
/ / / /
1 2 3 4
ALGORITHM:
This function uses the algorithm of M. Habib and M. Maurer [HM1979].
See also:
Note: A buggy implementation of linear time algorithm from [TCHP2008] was removed in Sage 9.7, see
trac ticket #25872.
most_common_neighbors(nonedgesonly=True)
Return vertex pairs with maximal number of common neighbors.
This method is only valid for simple (no loops, no multiple edges) graphs with order ≥ 2
INPUT:
• nonedgesonly– boolean (default: True); if True, assigns 0 value to adjacent vertices.
OUTPUT: list of tuples of edge pairs
EXAMPLES:
The maximum common neighbor (non-adjacent) pairs for a straight linear 2-tree
sage: G1 = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)])
sage: G1.most_common_neighbors()
[(0, 3), (1, 4), (2, 5)]
The common neighbors matrix for a fan on 6 vertices counting only non-adjacent vertex pairs
sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)])
sage: H.most_common_neighbors()
[(1, 3), (2, 4), (3, 5)]
See also:
orientations(data_structure=None, sparse=None)
Return an iterator over orientations of self.
An orientation of an undirected graph is a directed graph such that every edge is assigned a direction. Hence
there are 2𝑠 oriented digraphs for a simple graph with 𝑠 edges.
INPUT:
• data_structure – one of "sparse", "static_sparse", or "dense"; see the documentation of
Graph or DiGraph ; default is the data structure of self
• sparse – boolean (default: None); sparse=True is an alias for data_structure="sparse", and
sparse=False is an alias for data_structure="dense". By default (None), guess the most suitable
data structure.
Warning: This always considers multiple edges of graphs as distinguishable, and hence, may have
repeated digraphs.
See also:
• strong_orientation()
• strong_orientations_iterator()
• nauty_directg()
• random_orientation()
EXAMPLES:
sage: it = G.orientations()
sage: D = next(it)
sage: D.edges(sort=True)
[(1, 2, 'a'), (1, 3, 'b')]
(continues on next page)
EXAMPLES:
The pathwidth of a cycle is equal to 2:
sage: g = graphs.CycleGraph(6)
sage: g.pathwidth()
2
sage: pw, decomp = g.pathwidth(certificate=True)
sage: sorted(decomp, key=str)
[{0, 1, 5}, {1, 2, 5}, {2, 3, 4}, {2, 4, 5}]
sage: g = graphs.PetersenGraph()
sage: g.pathwidth()
5
sage: g.pathwidth(k=2)
False
sage: g.pathwidth(k=6)
True
sage: g.pathwidth(k=6, certificate=True)
(True, Graph on 5 vertices)
perfect_matchings(labels=False)
Return an iterator over all perfect matchings of the graph.
ALGORITHM:
Choose a vertex 𝑣, then recurse through all edges incident to 𝑣, removing one edge at a time whenever an
edge is added to a matching.
INPUT:
• labels – boolean (default: False); when True, the edges in each perfect matching are triples (con-
taining the label as the third element), otherwise the edges are pairs.
See also:
matching()
EXAMPLES:
sage: G=graphs.GridGraph([2,3])
sage: for m in G.perfect_matchings():
....: print(sorted(m))
[((0, 0), (0, 1)), ((0, 2), (1, 2)), ((1, 0), (1, 1))]
[((0, 0), (1, 0)), ((0, 1), (0, 2)), ((1, 1), (1, 2))]
[((0, 0), (1, 0)), ((0, 1), (1, 1)), ((0, 2), (1, 2))]
sage: G = graphs.CompleteGraph(4)
sage: for m in G.perfect_matchings(labels=True):
....: print(sorted(m))
[(0, 1, None), (2, 3, None)]
[(0, 2, None), (1, 3, None)]
[(0, 3, None), (1, 2, None)]
sage: G = graphs.CompleteGraph(8)
sage: mpc = G.matching_polynomial().coefficients(sparse=False)[0]
sage: len(list(G.perfect_matchings())) == mpc
True
sage: G = graphs.PetersenGraph().copy(immutable=True)
sage: [sorted(m) for m in G.perfect_matchings()]
[[(0, 1), (2, 3), (4, 9), (5, 7), (6, 8)],
[(0, 1), (2, 7), (3, 4), (5, 8), (6, 9)],
(continues on next page)
sage: list(Graph().perfect_matchings())
[[]]
sage: G = graphs.CompleteGraph(5)
sage: list(G.perfect_matchings())
[]
sage: G = graphs.DiamondGraph()
sage: G.periphery()
[0, 3]
sage: P = graphs.PetersenGraph()
sage: P.subgraph(P.periphery()) == P
True
sage: S = graphs.StarGraph(19)
sage: S.periphery()
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
sage: G = Graph()
sage: G.periphery()
[]
sage: G.add_vertex()
0
sage: G.periphery()
[0]
A private neighbor of a vertex 𝑣 with respect to a vertex subset 𝐷 is a closed neighbor of 𝑣 that is not
dominated by a vertex of 𝐷 ∖ {𝑣}.
INPUT:
• vertex – a vertex of G.
• dom – iterable of vertices of G; the vertices possibly stealing private neighbors from vertex.
OUTPUT:
Return the closed neighbors of vertex that are not closed neighbors of any other vertex of dom.
EXAMPLES:
sage: g = graphs.PathGraph(5)
sage: list(g.private_neighbors(1, [1, 3, 4]))
[1, 0]
sage: G = graphs.BarbellGraph(9, 3)
sage: G.radius()
3
sage: G.diameter()
6
sage: G = graphs.OctahedralGraph()
sage: G.radius()
2
sage: G.diameter()
2
random_orientation(G)
Return a random orientation of a graph 𝐺.
An orientation of an undirected graph is a directed graph such that every edge is assigned a direction. Hence
there are 2𝑚 oriented digraphs for a simple graph with 𝑚 edges.
INPUT:
• G – a Graph.
EXAMPLES:
See also:
• orientations()
• strong_orientation()
• strong_orientations_iterator()
• nauty_directg()
used to transform the label into a weight (note that, if the weight returned is not convertible to a float,
an error is raised)
• check_weight – boolean (default: True); whether to check that the weight_function outputs a
number for each edge.
See also:
spanning_trees_count() and spanning_trees()
EXAMPLES:
sage: G = graphs.TietzeGraph()
sage: G.random_spanning_tree(output_as_graph=True)
Graph on 12 vertices
sage: rg = G.random_spanning_tree(); rg # random
[(0, 9),
(9, 11),
(0, 8),
(8, 7),
(7, 6),
(7, 2),
(2, 1),
(1, 5),
(9, 10),
(5, 4),
(2, 3)]
sage: Graph(rg).is_tree()
True
sage: G = graphs.Grid2dGraph(6, 6)
sage: pos = G.get_pos()
sage: T = G.random_spanning_tree(True)
sage: T.set_pos(pos)
sage: T.show(vertex_labels=False)
We can also use edge weights to change the probability of returning a spanning tree:
Check that the spanning tree returned when using weights is a tree:
sage: G = graphs.RandomBarabasiAlbert(50, 2)
sage: for u, v in G.edge_iterator(labels=False):
....: G.set_edge_label(u, v, randint(1, 10))
sage: T = G.random_spanning_tree(by_weight=True, output_as_graph=True)
sage: T.is_tree()
True
rank_decomposition(G, verbose=False)
Compute an optimal rank-decomposition of the given graph.
This function is available as a method of the Graph class. See rank_decomposition.
INPUT:
• verbose – boolean (default: False); whether to display progress information while computing the
decomposition
OUTPUT:
A pair (rankwidth, decomposition_tree), where rankwidth is a numerical value and
decomposition_tree is a ternary tree describing the decomposition (cf. the module’s documen-
tation).
EXAMPLES:
sage: g = Graph()
sage: rank_decomposition(g)
(0, Graph on 0 vertices)
• base_ring – a ring (default: None); the base ring of the matrix space to use
• **kwds – other keywords to pass to matrix()
EXAMPLES:
sage: G = graphs.CycleGraph(5)
sage: G = G.disjoint_union(graphs.CompleteGraph(1))
sage: G.seidel_adjacency_matrix().minpoly()
x^2 - 5
seidel_switching(s, inplace=True)
Return the Seidel switching of self w.r.t. subset of vertices s.
Returns the graph obtained by Seidel switching of self with respect to the subset of vertices s. This is
the graph given by Seidel adjacency matrix 𝐷𝑆𝐷, for 𝑆 the Seidel adjacency matrix of self, and 𝐷 the
diagonal matrix with -1s at positions corresponding to s, and 1s elsewhere.
INPUT:
• s – a list of vertices of self.
• inplace – boolean (default: True); whether to do the modification inplace, or to return a copy of the
graph after switching.
EXAMPLES:
sage: G = graphs.CycleGraph(5)
sage: G = G.disjoint_union(graphs.CompleteGraph(1))
sage: G.seidel_switching([(0,1),(1,0),(0,0)])
sage: G.seidel_adjacency_matrix().minpoly()
x^2 - 5
sage: G.is_connected()
True
spanning_trees(g, labels=False)
Return an iterator over all spanning trees of the graph 𝑔.
A disconnected graph has no spanning tree.
Uses the Read-Tarjan backtracking algorithm [RT1975a].
INPUT:
• labels – boolean (default: False); whether to return edges labels in the spanning trees or not
EXAMPLES:
See also:
sparse6_string()
Return the sparse6 representation of the graph as an ASCII string.
Only valid for undirected graphs on 0 to 262143 vertices, but loops and multiple edges are permitted.
Note: As the sparse6 format only handles graphs whose vertex set is {0, ..., 𝑛 − 1}, a relabelled copy
of your graph will be encoded if necessary.
EXAMPLES:
sage: G = graphs.BullGraph()
sage: G.sparse6_string()
':Da@en'
sage: G = Graph(2)
sage: for i in range(3):
....: G.add_path([0, G.add_vertex(), G.add_vertex(), 1])
sage: Tree = spqr_tree(G)
sage: Tree.order()
4
sage: C4 = graphs.CycleGraph(4)
sage: all(u[1].is_isomorphic(C4) for u in Tree if u[0] == 'S')
True
sage: G.is_isomorphic(spqr_tree_to_graph(Tree))
True
sage: G.allow_multiple_edges(True)
sage: G.add_edges(G.edge_iterator())
sage: Tree = spqr_tree(G)
sage: Tree.order()
13
sage: all(u[1].is_isomorphic(C4) for u in Tree if u[0] == 'S')
True
sage: G.is_isomorphic(spqr_tree_to_graph(Tree))
True
(continues on next page)
sage: G = graphs.CycleGraph(6)
sage: Tree = spqr_tree(G)
sage: Tree.order()
1
sage: G.is_isomorphic(spqr_tree_to_graph(Tree))
True
sage: G.add_edge(0, 3)
sage: Tree = spqr_tree(G)
sage: Tree.order()
3
sage: G.is_isomorphic(spqr_tree_to_graph(Tree))
True
sage: G = Graph('LlCG{O@?GBoMw?')
sage: T = spqr_tree(G, algorithm="Hopcroft_Tarjan")
sage: G.is_isomorphic(spqr_tree_to_graph(T))
True
sage: T2 = spqr_tree(G, algorithm='cleave')
sage: G.is_isomorphic(spqr_tree_to_graph(T2))
True
strong_orientation()
Returns a strongly connected orientation of the current graph.
An orientation of an undirected graph is a digraph obtained by giving an unique direction to each of its
edges. An orientation is said to be strong if there is a directed path between each pair of vertices. See also
the Wikipedia article Strongly_connected_component.
If the graph is 2-edge-connected, a strongly connected orientation can be found in linear time. If the
given graph is not 2-connected, the orientation returned will ensure that each 2-connected component has
a strongly connected orientation.
OUTPUT:
A digraph representing an orientation of the current graph.
Note:
• This method assumes the graph is connected.
• This algorithm works in O(m).
See also:
• orientations()
• strong_orientations_iterator()
• nauty_directg()
• random_orientation()
EXAMPLES:
For a 2-regular graph, a strong orientation gives to each vertex an out-degree equal to 1:
sage: g = graphs.CycleGraph(5)
sage: g.strong_orientation().out_degree()
[1, 1, 1, 1, 1]
The Petersen Graph is 2-edge connected. It then has a strongly connected orientation:
sage: g = graphs.PetersenGraph()
sage: o = g.strong_orientation()
sage: len(o.strongly_connected_components())
1
sage: all(len(graphs.CubeGraph(i).strong_orientation().strongly_connected_
˓→components()) == 1 for i in range(2,6))
True
strong_orientations_iterator(G)
Returns an iterator over all strong orientations of a graph 𝐺.
A strong orientation of a graph is an orientation of its edges such that the obtained digraph is strongly
connected (i.e. there exist a directed path between each pair of vertices).
ALGORITHM:
It is an adaptation of the algorithm published in [CGMRV16]. It runs in 𝑂(𝑚𝑛) amortized time, where
𝑚 is the number of edges and 𝑛 is the number of vertices. The amortized time can be improved to 𝑂(𝑚)
with a more involved method. In this function, first the graph is preprocessed and a spanning tree is gener-
ated. Then every orientation of the non-tree edges of the graph can be extended to at least one new strong
orientation by orienting properly the edges of the spanning tree (this property is proved in [CGMRV16]).
Therefore, this function generates all partial orientations of the non-tree edges and then launches a helper
function corresponding to the generation algorithm described in [CGMRV16]. In order to avoid trivial
symmetries, the orientation of an arbitrary edge is fixed before the start of the enumeration process.
INPUT:
• G – an undirected graph.
OUTPUT:
• an iterator which will produce all strong orientations of this graph.
Note: Works only for simple graphs (no multiple edges). To avoid symmetries an orientation of an arbitrary
edge is fixed.
See also:
• orientations()
• strong_orientation()
• nauty_directg()
• random_orientation()
EXAMPLES:
A cycle has one possible (non-symmetric) strong orientation:
sage: g = graphs.CycleGraph(4)
sage: it = g.strong_orientations_iterator()
sage: len(list(it))
1
sage: g = graphs.RandomTree(100)
sage: len(list(g.strong_orientations_iterator()))
0
sage: g = graphs.CompleteGraph(6)
sage: g.add_vertex(7)
sage: len(list(g.strong_orientations_iterator()))
0
to_directed(data_structure=None, sparse=None)
Return a directed version of the graph.
A single edge becomes two edges, one in each direction.
INPUT:
• data_structure – one of "sparse", "static_sparse", or "dense". See the documentation of
Graph or DiGraph .
• sparse – boolean (default: None); sparse=True is an alias for data_structure="sparse", and
sparse=False is an alias for data_structure="dense".
EXAMPLES:
sage: graphs.PetersenGraph().to_directed()
Petersen graph: Digraph on 10 vertices
to_undirected()
Since the graph is already undirected, simply returns a copy of itself.
EXAMPLES:
sage: graphs.PetersenGraph().to_undirected()
Petersen graph: Graph on 10 vertices
The topological 𝐻-minor found is returned as a subgraph 𝑀 of self, such that the vertex 𝑣 of 𝑀 that
represents a vertex ℎ ∈ 𝐻 has h as a label (see get_vertex and set_vertex), and such that every edge
of 𝑀 has as a label the edge of 𝐻 it (partially) represents.
If no topological minor is found, this method returns False.
ALGORITHM:
Mixed Integer Linear Programming.
COMPLEXITY:
Theoretically, when 𝐻 is fixed, testing for the existence of a topological 𝐻-minor is polynomial. The known
algorithms are highly exponential in 𝐻, though.
Note: This function can be expected to be very slow, especially where the topological minor does not
exist.
(CPLEX seems to be much more efficient than GLPK on this kind of problem)
EXAMPLES:
Petersen’s graph has a topological 𝐾4 -minor:
sage: g = graphs.PetersenGraph()
sage: g.topological_minor(graphs.CompleteGraph(4))
Subgraph of (Petersen graph): Graph on ...
sage: g.topological_minor(graphs.CompleteBipartiteGraph(3,3))
Subgraph of (Petersen graph): Graph on ...
sage: g = graphs.RandomGNP(15,.3)
sage: g = g.subgraph(edges = g.min_spanning_tree())
sage: g.topological_minor(graphs.CycleGraph(3))
False
G.treelength() returns the treelength of 𝐺. When 𝑘 is specified, it returns False when no tree-
decomposition of length ≤ 𝑘 exists or True otherwise. When certificate=True, the tree-decomposition
is also returned.
ALGORITHM:
This method virtually explores the graph of all pairs (vertex_cut, connected_component), where
vertex_cut is a vertex cut of the graph of length ≤ 𝑘, and connected_component is a connected com-
ponent of the graph induced by G - vertex_cut.
We deduce that the pair (vertex_cut, connected_component) is feasible with treelength 𝑘 if
connected_component is empty, or if a vertex v from vertex_cut can be replaced with a vertex from
connected_component, such that the pair (vertex_cut + v, connected_component - v) is feasi-
ble.
In practice, this method decomposes the graph by its clique minimal separators into atoms, computes the
treelength of each of atom and returns the maximum value over all the atoms. Indeed, we have that 𝑡𝑙(𝐺) =
max𝑋∈𝐴 𝑡𝑙(𝐺[𝑋]) where 𝐴 is the set of atoms of the decomposition by clique separators of 𝐺. When
certificate == True, the tree-decompositions of the atoms are connected to each others by adding
edges with respect to the clique separators.
See also:
EXAMPLES:
The PetersenGraph has treelength 2:
sage: G = graphs.PetersenGraph()
sage: G.treelength()
2
sage: G = Graph(2)
sage: G.treelength()
+Infinity
sage: G.treelength(k=+Infinity)
True
sage: G.treelength(k=2)
False
sage: G.treelength(certificate=True)
Traceback (most recent call last):
...
ValueError: the tree decomposition of a disconnected graph is not defined
sage: G = graphs.RandomChordalGraph(30)
sage: while not G.is_connected():
....: G = graphs.RandomChordalGraph(30)
(continues on next page)
Note: The implementation would be much faster if cc, the argument of the recursive function, was a
bitset. It would also be very nice to not copy the graph in order to compute connected components, for this
is really a waste of time.
See also:
path_decomposition() computes the pathwidth of a graph. See also the vertex_separation module.
EXAMPLES:
The PetersenGraph has treewidth 4:
sage: graphs.PetersenGraph().treewidth()
4
(continues on next page)
sage: graphs.Grid2dGraph(2,5).treewidth()
2
sage: graphs.Grid2dGraph(3,5).treewidth()
3
When parameter kmin is specified, the method search for a tree-decomposition of width at least kmin:
sage: g = graphs.PetersenGraph()
sage: g.treewidth()
4
sage: g.treewidth(kmin=2, algorithm='sage')
4
sage: g.treewidth(kmin=g.order(), certificate=True, algorithm='sage')
Tree decomposition: Graph on 1 vertex
sage: P = graphs.PetersenGraph()
sage: P.tutte_polynomial()
x^9 + 6*x^8 + 21*x^7 + 56*x^6 + 12*x^5*y + y^6 + 114*x^5 + 70*x^4*y
+ 30*x^3*y^2 + 15*x^2*y^3 + 10*x*y^4 + 9*y^5 + 170*x^4 + 170*x^3*y
+ 105*x^2*y^2 + 65*x*y^3 + 35*y^4 + 180*x^3 + 240*x^2*y + 171*x*y^2
+ 75*y^3 + 120*x^2 + 168*x*y + 84*y^2 + 36*x + 36*y
The Tutte polynomial of a connected graph 𝐺 evaluated at (1,1) is the number of spanning trees of 𝐺:
sage: G = graphs.RandomGNP(10,0.6)
sage: while not G.is_connected():
....: G = graphs.RandomGNP(10,0.6)
sage: G.tutte_polynomial()(1,1) == G.spanning_trees_count()
True
Given that 𝑇 (𝑥, 𝑦) is the Tutte polynomial of a graph 𝐺 with 𝑛 vertices and 𝑐 connected components, then
(−1)𝑛−𝑐 𝑥𝑘 𝑇 (1 − 𝑥, 0) is the chromatic polynomial of 𝐺.
sage: G = graphs.OctahedralGraph()
sage: T = G.tutte_polynomial()
sage: R = PolynomialRing(ZZ, 'x')
sage: R((-1)^5*x*T(1-x,0)).factor()
(x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32)
sage: G.chromatic_polynomial().factor()
(x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32)
for all 𝑖, the set 𝐶𝑖 is a graph of maximal degree 2 (a disjoint union of paths and cycles).
INPUT:
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
EXAMPLES:
The Complete Graph on 7 vertices is a 6-regular graph, so it can be edge-partitionned into 2-regular graphs:
sage: g = graphs.CompleteGraph(7)
sage: classes = g.two_factor_petersen()
sage: for c in classes:
....: gg = Graph()
....: gg.add_edges(c)
....: print(max(gg.degree())<=2)
True
True
True
sage: Set(set(classes[0]) | set(classes[1]) | set(classes[2])).cardinality() ==␣
˓→g.size()
True
twograph()
Return the two-graph of self
Returns the two-graph with the triples 𝑇 = {𝑡 ∈ 2 ∩ 𝐸 odd} where 𝑉 and 𝐸 are vertices and
(︀𝑉 )︀ ⃒(︀ 𝑡 )︀ ⃒
3 :
⃒ ⃒
edges of self, respectively.
EXAMPLES:
sage: p=graphs.PetersenGraph()
sage: p.twograph()
Incidence structure with 10 points and 60 blocks
sage: p=graphs.chang_graphs()
sage: T8 = graphs.CompleteGraph(8).line_graph()
sage: C = T8.seidel_switching([(0,1,None),(2,3,None),(4,5,None),(6,7,None)],
˓→inplace=False)
See also:
INPUT:
• algorithm – string (default: "Cliquer"). Indicating which algorithm to use. It can be one of those
values.
– "Cliquer" will compute a minimum vertex cover using the Cliquer package.
– "MILP" will compute a minimum vertex cover through a mixed integer linear program.
– "mcqd" will use the MCQD solver (http://www.sicmm.org/~konc/maxclique/). Note that the
MCQD package must be installed.
• value_only – boolean (default: False); if set to True, only the size of a minimum vertex cover is
returned. Otherwise, a minimum vertex cover is returned as a list of vertices.
• reduction_rules – (default: True); specify if the reductions rules from kernelization must be ap-
plied as pre-processing or not. See [ACFLSS04] for more details. Note that depending on the instance,
it might be faster to disable reduction rules.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
EXAMPLES:
On the Pappus graph:
sage: g = graphs.PappusGraph()
sage: g.vertex_cover(value_only=True)
9
6
1 5
7 12 11
13 17
14 16
8 15 10
2 4
9
3
vertex_isoperimetric_number(g)
Return the vertex-isoperimetric number of the graph.
The vertex-isoperimetric number of a graph 𝐺 = (𝑉, 𝐸) is also sometimes called the magnifying constant.
It is defined as the minimum of |𝑁 (𝑆)|/|𝑆| where |𝑁 (𝑆)| is the vertex boundary of 𝑆 and the minimum is
taken over the subsets 𝑆 of vertices of size at most half of the vertices.
See also:
Alternative but similar quantities can be obtained via the methods cheeger_constant() and
edge_isoperimetric_number().
EXAMPLES:
The vertex-isoperimetric number of a complete graph on 𝑛 vertices is ⌈𝑛/2⌉/⌊𝑛/2⌋:
sage: Graph([[1,2,3],[(1,2)]]).vertex_isoperimetric_number()
0
sage: G = graphs.CycleGraph(6)
sage: G.vertex_isoperimetric_number()
2/3
sage: G.allow_multiple_edges(True)
sage: G.add_edges(G.edges(sort=False))
sage: G.vertex_isoperimetric_number()
2/3
write_to_eps(filename, **options)
Write a plot of the graph to filename in eps format.
INPUT:
• filename – a string
• **options – same layout options as layout()
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.write_to_eps(tmp_filename(ext='.eps'))
It is relatively simple to include this file in a LaTeX document. \usepackage{graphics} must appear
in the preamble, and \includegraphics{filename} will include the file. To compile the document
to pdf with pdflatex or xelatex the file needs first to be converted to pdf, for example with ps2pdf
filename.eps filename.pdf.
This module implements functions and operations involving directed graphs. Here is what they can do
Graph basic operations:
layout_acyclic_dummy() Compute a (dummy) ranked layout so that all edges point upward.
layout_acyclic() Compute a ranked layout so that all edges point upward.
reverse() Return a copy of digraph with edges reversed in direction.
reverse_edge() Reverse an edge.
reverse_edges() Reverse a list of edges.
out_degree_sequence() Return the outdegree sequence.
out_degree_iterator() Same as degree_iterator, but for out degree.
out_degree() Same as degree, but for out degree.
in_degree_sequence() Return the indegree sequence of this digraph.
in_degree_iterator() Same as degree_iterator, but for in degree.
in_degree() Same as degree, but for in-degree.
neighbors_out() Return the list of the out-neighbors of a given vertex.
neighbor_out_iterator() Return an iterator over the out-neighbors of a given vertex.
neighbors_in() Return the list of the in-neighbors of a given vertex.
neighbor_in_iterator() Return an iterator over the in-neighbors of vertex.
outgoing_edges() Return a list of edges departing from vertices.
outgoing_edge_iterator() Return an iterator over all departing edges from vertices
incoming_edges() Return a list of edges arriving at vertices.
incoming_edge_iterator() Return an iterator over all arriving edges from vertices
sources() Return the list of all sources (vertices without incoming edges) of this digraph.
sinks() Return the list of all sinks (vertices without outgoing edges) of this digraph.
to_undirected() Return an undirected version of the graph.
to_directed() Since the graph is already directed, simply returns a copy of itself.
is_directed() Since digraph is directed, returns True.
dig6_string() Return the dig6 representation of the digraph as an ASCII string.
Distances:
Representation theory:
path_semigroup() Return the (partial) semigroup formed by the paths of the digraph.
Connectivity:
Acyclicity:
Hard stuff:
Miscellaneous:
1.3.1 Methods
• name – string (default: None); gives the graph a name (e.g., name=”complete”)
• loops – boolean (default: None); whether to allow loops (ignored if data is an instance of the DiGraph
class)
• multiedges – boolean (default: None); whether to allow multiple edges (ignored if data is an instance of
the DiGraph class)
• weighted – boolean (default: None); whether digraph thinks of itself as weighted or not. See self.
weighted()
• format – string (default: None); if set to None, DiGraph tries to guess input’s format. To avoid this
possibly time-consuming step, one of the following values can be specified (see description above): "int",
"dig6", "rule", "list_of_edges", "dict_of_lists", "dict_of_dicts", "adjacency_matrix",
"weighted_adjacency_matrix", "incidence_matrix", "NX", "igraph".
• sparse – boolean (default: True); sparse=True is an alias for data_structure="sparse", and
sparse=False is an alias for data_structure="dense"
• data_structure – string (default: "sparse"); one of the following (for more information, see
overview):
– "dense" – selects the dense_graph backend
– "sparse" – selects the sparse_graph backend
– "static_sparse" – selects the static_sparse_backend (this backend is faster than the sparse
backend and smaller in memory, and it is immutable, so that the resulting graphs can be used as
dictionary keys).
• immutable – boolean (default: False); whether to create a immutable digraph. Note that
immutable=True is actually a shortcut for data_structure='static_sparse'.
• vertex_labels – boolean (default: True); whether to allow any object as a vertex (slower), or only the
integers 0, ..., 𝑛 − 1, where 𝑛 is the number of vertices.
• convert_empty_dict_labels_to_None – boolean (default: None); this arguments sets the default edge
labels used by NetworkX (empty dictionaries) to be replaced by None, the default Sage edge label. It is set
to True iff a NetworkX graph is on the input.
EXAMPLES:
1. A dictionary of dictionaries:
The labels (‘x’, ‘z’, ‘a’, ‘out’) are labels for edges. For example, ‘out’ is the label for the edge from 2 to 5.
Labels can be used as weights, if all the labels share some common parent.
2. A dictionary of lists (or iterables):
3. A list of vertices and a function describing adjacencies. Note that the list of vertices and the function must
be enclosed in a list (i.e., [list of vertices, function]).
We construct a graph on the integers 1 through 12 such that there is a directed edge from 𝑖 to 𝑗 if and only
if 𝑖 divides 𝑗:
4. A Sage matrix: Note: If format is not specified, then Sage assumes a square matrix is an adjacency matrix,
and a nonsquare matrix is an incidence matrix.
• an adjacency matrix:
[0 1 1 1 0]
[0 0 0 0 0]
[0 0 0 0 1]
[0 0 0 0 0]
[0 0 0 0 0]
sage: DiGraph(M)
Digraph on 5 vertices
sage: M = Matrix([[0,1,-1],[-1,0,-1/2],[1,1/2,0]]); M
[ 0 1 -1]
[ -1 0 -1/2]
[ 1 1/2 0]
sage: G = DiGraph(M,sparse=True,weighted=True); G
Digraph on 3 vertices
sage: G.weighted()
True
• an incidence matrix:
[-1 0 0 0 1]
[ 1 -1 0 0 0]
[ 0 1 -1 0 0]
[ 0 0 1 -1 0]
[ 0 0 0 1 -1]
[ 0 0 0 0 0]
sage: DiGraph(M)
Digraph on 6 vertices
5. A dig6 string: Sage automatically recognizes whether a string is in dig6 format, which is a directed version
of graph6:
sage: D = DiGraph('IRAaDCIIOWEOKcPWAo')
sage: D
Digraph on 10 vertices
sage: D = DiGraph('IRAaDCIIOEOKcPWAo')
Traceback (most recent call last):
...
RuntimeError: the string (IRAaDCIIOEOKcPWAo) seems corrupt: for n = 10, the␣
˓→string is too short
sage: D = DiGraph("IRAaDCI'OWEOKcPWAo")
Traceback (most recent call last):
...
RuntimeError: the string seems corrupt: valid characters are
?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
6. A NetworkX MultiDiGraph:
7. A NetworkX digraph:
If vertex_labels is True, the names of the vertices are given by the vertex attribute 'name', if available:
If the igraph Graph has edge attributes, they are used as edge labels:
• all_simple_cycles()
AUTHOR:
Alexandre Blondin Masse
EXAMPLES:
sage: g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']},␣
˓→loops=True)
sage: it = g.all_cycles_iterator()
sage: for _ in range(7): print(next(it))
['a', 'a']
['a', 'a', 'a']
['c', 'd', 'c']
['a', 'a', 'a', 'a']
['a', 'a', 'a', 'a', 'a']
['c', 'd', 'c', 'd', 'c']
['a', 'a', 'a', 'a', 'a', 'a']
sage: g = DiGraph()
sage: it = g.all_cycles_iterator()
sage: list(it)
[]
sage: g = DiGraph({0:[1]})
sage: it = g.all_cycles_iterator()
sage: list(it)
[]
sage: g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']},␣
˓→loops=True)
sage: it = g.all_cycles_iterator(max_length=3)
sage: list(it)
[['a', 'a'], ['a', 'a', 'a'], ['c', 'd', 'c'],
['a', 'a', 'a', 'a']]
By default, cycles differing only by their starting point are not all enumerated, but this may be parametrized:
One may prefer to enumerate simple cycles, i.e. cycles such that the only vertex occurring twice in it is the
starting and ending one (see also all_simple_cycles()):
sage: it = g.all_cycles_iterator(simple=True)
sage: list(it)
[['a', 'a'], ['c', 'd', 'c']]
sage: g = digraphs.Circuit(4)
sage: list(g.all_cycles_iterator(simple=True))
[[0, 1, 2, 3, 0]]
• trivial - boolean (default: False); if set to True, then the empty paths are also enumerated.
• use_multiedges – boolean (default: False); this parameter is used only if the graph has multiple
edges.
– If False, the graph is considered as simple and an edge label is arbitrarily selected for each edge as
in sage.graphs.generic_graph.GenericGraph.to_simple() if report_edges is True
– If True, a path will be reported as many times as the edges multiplicities along that path (when
report_edges = False or labels = False), or with all possible combinations of edge labels
(when report_edges = True and labels = True)
• report_edges – boolean (default: False); whether to report paths as list of vertices (default) or list
of edges, if False then labels parameter is ignored
• labels – boolean (default: False); if False, each edge is simply a pair (u, v) of vertices. Other-
wise a list of edges along with its edge labels are used to represent the path.
OUTPUT:
iterator
AUTHOR:
Alexandre Blondin Masse
EXAMPLES:
sage: g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']},␣
˓→loops=True)
sage: list(pi)
[[('a', 'b'), ('b', 'c'), ('c', 'd')]]
sage: g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']},␣
˓→loops=True)
sage: pi = g.all_paths_iterator()
sage: [len(next(pi)) - 1 for _ in range(7)]
[1, 1, 1, 1, 1, 2, 2]
Note: Although the number of simple cycles of a finite graph is always finite, computing all its cycles may
take a very long time.
EXAMPLES:
sage: g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']},␣
˓→loops=True)
sage: g.all_simple_cycles()
[['a', 'a'], ['c', 'd', 'c']]
sage: g = graphs.PetersenGraph().to_directed()
sage: g.all_simple_cycles(max_length=4)
[[0, 1, 0], [0, 4, 0], [0, 5, 0], [1, 2, 1], [1, 6, 1], [2, 3, 2],
[2, 7, 2], [3, 8, 3], [3, 4, 3], [4, 9, 4], [5, 8, 5], [5, 7, 5],
[6, 8, 6], [6, 9, 6], [7, 9, 7]]
sage: g.all_simple_cycles(max_length=6)
[[0, 1, 0], [0, 4, 0], [0, 5, 0], [1, 2, 1], [1, 6, 1], [2, 3, 2],
[2, 7, 2], [3, 8, 3], [3, 4, 3], [4, 9, 4], [5, 8, 5], [5, 7, 5],
[6, 8, 6], [6, 9, 6], [7, 9, 7], [0, 1, 2, 3, 4, 0],
[0, 1, 2, 7, 5, 0], [0, 1, 6, 8, 5, 0], [0, 1, 6, 9, 4, 0],
[0, 4, 9, 6, 1, 0], [0, 4, 9, 7, 5, 0], [0, 4, 3, 8, 5, 0],
[0, 4, 3, 2, 1, 0], [0, 5, 8, 3, 4, 0], [0, 5, 8, 6, 1, 0],
[0, 5, 7, 9, 4, 0], [0, 5, 7, 2, 1, 0], [1, 2, 3, 8, 6, 1],
[1, 2, 7, 9, 6, 1], [1, 6, 8, 3, 2, 1], [1, 6, 9, 7, 2, 1],
[2, 3, 8, 5, 7, 2], [2, 3, 4, 9, 7, 2], [2, 7, 9, 4, 3, 2],
[2, 7, 5, 8, 3, 2], [3, 8, 6, 9, 4, 3], [3, 4, 9, 6, 8, 3],
[5, 8, 6, 9, 7, 5], [5, 7, 9, 6, 8, 5], [0, 1, 2, 3, 8, 5, 0],
[0, 1, 2, 7, 9, 4, 0], [0, 1, 6, 8, 3, 4, 0],
[0, 1, 6, 9, 7, 5, 0], [0, 4, 9, 6, 8, 5, 0],
[0, 4, 9, 7, 2, 1, 0], [0, 4, 3, 8, 6, 1, 0],
[0, 4, 3, 2, 7, 5, 0], [0, 5, 8, 3, 2, 1, 0],
[0, 5, 8, 6, 9, 4, 0], [0, 5, 7, 9, 6, 1, 0],
[0, 5, 7, 2, 3, 4, 0], [1, 2, 3, 4, 9, 6, 1],
[1, 2, 7, 5, 8, 6, 1], [1, 6, 8, 5, 7, 2, 1],
[1, 6, 9, 4, 3, 2, 1], [2, 3, 8, 6, 9, 7, 2],
[2, 7, 9, 6, 8, 3, 2], [3, 8, 5, 7, 9, 4, 3],
[3, 4, 9, 7, 5, 8, 3]]
sage: g = graphs.CompleteGraph(4).to_directed()
sage: g.all_simple_cycles()
[[0, 1, 0], [0, 2, 0], [0, 3, 0], [1, 2, 1], [1, 3, 1], [2, 3, 2],
[0, 1, 2, 0], [0, 1, 3, 0], [0, 2, 1, 0], [0, 2, 3, 0],
[0, 3, 1, 0], [0, 3, 2, 0], [1, 2, 3, 1], [1, 3, 2, 1],
[0, 1, 2, 3, 0], [0, 1, 3, 2, 0], [0, 2, 1, 3, 0],
[0, 2, 3, 1, 0], [0, 3, 1, 2, 0], [0, 3, 2, 1, 0]]
If the graph contains a large number of cycles, one can bound the length of the cycles, or simply restrict the
possible starting vertices of the cycles:
sage: g = graphs.CompleteGraph(20).to_directed()
sage: g.all_simple_cycles(max_length=2)
[[0, 1, 0], [0, 2, 0], [0, 3, 0], [0, 4, 0], [0, 5, 0], [0, 6, 0],
[0, 7, 0], [0, 8, 0], [0, 9, 0], [0, 10, 0], [0, 11, 0],
[0, 12, 0], [0, 13, 0], [0, 14, 0], [0, 15, 0], [0, 16, 0],
(continues on next page)
One may prefer to distinguish equivalent cycles having distinct starting vertices (compare the following
examples):
sage: g = graphs.CompleteGraph(4).to_directed()
sage: g.all_simple_cycles(max_length=2, rooted=False)
[[0, 1, 0], [0, 2, 0], [0, 3, 0], [1, 2, 1], [1, 3, 1], [2, 3, 2]]
sage: g.all_simple_cycles(max_length=2, rooted=True)
[[0, 1, 0], [0, 2, 0], [0, 3, 0], [1, 0, 1], [1, 2, 1], [1, 3, 1],
(continues on next page)
Note: Although the number of simple paths of a finite graph is always finite, computing all its paths may
take a very long time.
EXAMPLES:
sage: g = DiGraph({0: [0, 1], 1: [2], 2: [3], 3: [2]}, loops=True)
sage: g.all_simple_paths()
[[3, 2],
[2, 3],
[1, 2],
[0, 0],
[0, 1],
[0, 1, 2],
[1, 2, 3],
[2, 3, 2],
[3, 2, 3],
(continues on next page)
[[0, 1, 2]]
sage: g.all_simple_paths(starting_vertices=[0], ending_vertices=[2], use_
˓→multiedges=True)
[[(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)]]
sage: g.all_simple_paths(starting_vertices=[0], ending_vertices=[2], use_
˓→multiedges=True, report_edges=True, labels=True)
One may compute all paths having specific starting and/or ending vertices:
sage: g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']},␣
˓→loops=True)
sage: g.all_simple_paths(starting_vertices=['a'])
[['a', 'a'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'd']]
sage: g.all_simple_paths(starting_vertices=['a'], ending_vertices=['c'])
[['a', 'b', 'c']]
sage: g.all_simple_paths(starting_vertices=['a'], ending_vertices=['b', 'c'])
[['a', 'b'], ['a', 'b', 'c']]
By default, empty paths are not enumerated, but this can be parametrized:
sage: g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']},␣
˓→loops=True)
sage: G = digraphs.Circuit(9)
sage: G.center()
[0, 1, 2, 3, 4, 5, 6, 7, 8]
sage: G.subgraph(G.center()) == G
True
sage: G = digraphs.Path(5)
sage: G.center()
[0]
sage: G = DiGraph([(0,1,2), (1,2,3), (2,0,2)])
sage: G.center(by_weight=True)
[2]
degree_polynomial()
Return the generating polynomial of degrees of vertices in self.
This is the sum
∑︁
𝑥in(𝑣) 𝑦 out(𝑣) ,
𝑣∈𝐺
where in(v) and out(v) are the number of incoming and outgoing edges at vertex 𝑣 in the digraph 𝐺.
Because this polynomial is multiplicative for Cartesian product of digraphs, it is useful to help see if the
digraph can be isomorphic to a Cartesian product.
See also:
num_verts() for the value at (𝑥, 𝑦) = (1, 1)
EXAMPLES:
sage: G = posets.PentagonPoset().hasse_diagram()
sage: G.degree_polynomial()
x^2 + 3*x*y + y^2
sage: G = posets.BooleanLattice(4).hasse_diagram()
sage: G.degree_polynomial().factor()
(x + y)^4
sage: G = digraphs.DeBruijn(5,4)
sage: G.diameter()
4
sage: G = digraphs.GeneralizedDeBruijn(9, 3)
sage: G.diameter()
2
dig6_string()
Return the dig6 representation of the digraph as an ASCII string.
This is only valid for single (no multiple edges) digraphs on at most 218 − 1 = 262143 vertices.
Note: As the dig6 format only handles graphs with vertex set {0, . . . , 𝑛 − 1}, a relabelled copy will
be encoded, if necessary.
See also:
EXAMPLES:
• v - either a single vertex or a list of vertices. If it is not specified, then it is taken to be all vertices.
• by_weight – boolean (default: False); if True, edge weights are taken into account; if False, all
edges have weight 1
• algorithm – string (default: None); one of the following algorithms:
– 'BFS' - the computation is done through a BFS centered on each vertex successively. Works only
if by_weight==False.
– 'Floyd-Warshall-Cython' - a Cython implementation of the Floyd-Warshall algorithm. Works
only if by_weight==False and v is None or v should contain all vertices of self.
– 'Floyd-Warshall-Python' - a Python implementation of the Floyd-Warshall algorithm. Works
also with weighted graphs, even with negative weights (but no negative cycle is allowed). However,
v must be None or v should contain all vertices of self.
– 'Dijkstra_NetworkX' - the Dijkstra algorithm, implemented in NetworkX. It works with
weighted graphs, but no negative weight is allowed.
– 'Dijkstra_Boost' - the Dijkstra algorithm, implemented in Boost (works only with positive
weights).
– 'Johnson_Boost' - the Johnson algorithm, implemented in Boost (works also with negative
weights, if there is no negative cycle). Works only if v is None or v should contain all vertices
of self.
– 'From_Dictionary' - uses the (already computed) distances, that are provided by input variable
dist_dict.
– None (default): Sage chooses the best algorithm: 'From_Dictionary' if dist_dict is
not None, 'BFS' for unweighted graphs, 'Dijkstra_Boost' if all weights are positive,
'Johnson_Boost' otherwise.
• weight_function – function (default: None); a function that takes as input an edge (u, v, l) and
outputs its weight. If not None, by_weight is automatically set to True. If None and by_weight is
True, we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs a
number for each edge
• dist_dict – a dictionary (default: None); a dict of dicts of distances (used only if
algorithm=='From_Dictionary')
• with_labels – boolean (default: False); whether to return a list or a dictionary keyed by vertices.
EXAMPLES:
sage: G = graphs.KrackhardtKiteGraph().to_directed()
sage: G.eccentricity()
[4, 4, 4, 4, 4, 3, 3, 2, 3, 4]
sage: G.vertices(sort=True)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sage: G.eccentricity(7)
2
sage: G.eccentricity([7,8,9])
[2, 3, 4]
sage: G.eccentricity([7,8,9], with_labels=True) == {8: 3, 9: 4, 7: 2}
True
sage: G = DiGraph(3)
sage: G.eccentricity(with_labels=True)
(continues on next page)
Such that :
∀(𝑢, 𝑣) ∈ 𝐺, 𝑑𝑢 − 𝑑𝑣 + 𝑛 · 𝑏(𝑢,𝑣) ≥ 0
∀𝑢 ∈ 𝐺, 0 ≤ 𝑑𝑢 ≤ |𝐺|
An explanation:
An acyclic digraph can be seen as a poset, and every poset has a linear extension. This means that in any
acyclic digraph the vertices can be ordered with a total order < in such a way that if (𝑢, 𝑣) ∈ 𝐺, then 𝑢 < 𝑣.
Thus, this linear program is built in order to assign to each vertex 𝑣 a number 𝑑𝑣 ∈ [0, . . . , 𝑛 − 1] such that
if there exists an edge (𝑢, 𝑣) ∈ 𝐺 such that 𝑑𝑣 < 𝑑𝑢 , then the edge (𝑢, 𝑣) is removed.
The number of edges removed is then minimized, which is the objective.
(Constraint Generation)
If the parameter constraint_generation is enabled, a more efficient formulation is used :
∑︁
Minimize : 𝑏(𝑢,𝑣)
(𝑢,𝑣)∈𝐺
Such that :
∑︁
∀𝐶 circuits ⊆ 𝐺, 𝑏(𝑢,𝑣) ≥ 1
𝑢𝑣∈𝐶
As the number of circuits contained in a graph is exponential, this LP is solved through constraint genera-
tion. This means that the solver is sequentially asked to solved the problem, knowing only a portion of the
circuits contained in 𝐺, each time adding to the list of its constraints the circuit which its last answer had
left intact.
EXAMPLES:
If the digraph is created from a graph, and hence is symmetric (if 𝑢𝑣 is an edge, then 𝑣𝑢 is an edge too),
then obviously the cardinality of its feedback arc set is the number of edges in the first graph:
sage: cycle=graphs.CycleGraph(5)
sage: dcycle=DiGraph(cycle)
sage: cycle.size()
5
sage: dcycle.feedback_edge_set(value_only=True)
5
And in this situation, for any edge 𝑢𝑣 of the first graph, 𝑢𝑣 of 𝑣𝑢 is in the returned feedback arc set:
sage: g = graphs.RandomGNP(5,.3)
sage: while not g.num_edges():
....: g = graphs.RandomGNP(5,.3)
sage: dg = DiGraph(g)
sage: feedback = dg.feedback_edge_set()
sage: u,v,l = next(g.edge_iterator())
sage: (u,v) in feedback or (v,u) in feedback
True
Note: Flow polytopes can also be built through the polytopes.<tab> object:
sage: polytopes.flow_polytope(digraphs.Path(5))
A 0-dimensional polyhedron in QQ^4 defined as the convex hull of 1 vertex
EXAMPLES:
A commutative square:
A tournament on 4 vertices:
sage: H = digraphs.TransitiveTournament(4)
sage: fl = H.flow_polytope(); fl
A 3-dimensional polyhedron in QQ^6 defined as the convex hull
of 4 vertices
sage: fl.vertices()
(A vertex at (0, 0, 1, 0, 0, 0),
A vertex at (0, 1, 0, 0, 0, 1),
A vertex at (1, 0, 0, 0, 1, 0),
A vertex at (1, 0, 0, 1, 0, 1))
in_branchings(source, spanning=True)
Return an iterator over the in branchings rooted at given vertex in self.
An in-branching is a directed tree rooted at source whose arcs are directed to source from leaves. An
in-branching is spanning if it contains all vertices of the digraph.
If no spanning in branching rooted at source exist, raises ValueError or return non spanning in branching
rooted at source, depending on the value of spanning.
INPUT:
• source – vertex used as the source for all in branchings.
• spanning – boolean (default: True); if False return maximum in branching to source. Otherwise,
return spanning in branching if exists.
OUTPUT:
An iterator over the in branchings rooted in the given source.
See also:
ALGORITHM:
Recursively computes all in branchings.
At each step:
0. clean the graph (see below)
1. pick an edge e incoming to source
sage: G = graphs.PetersenGraph().to_directed()
sage: len(list(G.in_branchings(0)))
2000
sage: G.in_branchings(0)
Traceback (most recent call last):
...
ValueError: no spanning in branching to vertex (0) exist
With multiedges:
sage: next(G.in_branchings(0)) == G
True
in_degree(vertices=None, labels=False)
Same as degree, but for in degree.
EXAMPLES:
in_degree_iterator(vertices=None, labels=False)
Same as degree_iterator, but for in degree.
EXAMPLES:
sage: D = graphs.Grid2dGraph(2,4).to_directed()
sage: sorted(D.in_degree_iterator())
[2, 2, 2, 2, 3, 3, 3, 3]
sage: sorted(D.in_degree_iterator(labels=True))
[((0, 0), 2),
((0, 1), 3),
((0, 2), 3),
((0, 3), 2),
((1, 0), 2),
((1, 1), 3),
((1, 2), 3),
((1, 3), 2)]
in_degree_sequence()
Return the in-degree sequence.
EXAMPLES:
The in-degree sequences of two digraphs:
sage: g = DiGraph({1: [2, 5, 6], 2: [3, 6], 3: [4, 6], 4: [6], 5: [4, 6]})
sage: g.in_degree_sequence()
[5, 2, 1, 1, 1, 0]
incoming_edge_iterator(vertices, labels=True)
Return an iterator over all arriving edges from vertices.
INPUT:
• vertices – a vertex or a list of vertices
• labels – boolean (default: True); whether to return edges as pairs of vertices, or as triples containing
the labels
EXAMPLES:
incoming_edges(vertices, labels=True)
Return a list of edges arriving at vertices.
INPUT:
• vertices – a vertex or a list of vertices
• labels – boolean (default: True); whether to return edges as pairs of vertices, or as triples containing
the labels.
EXAMPLES:
is_aperiodic()
Return whether the current DiGraph is aperiodic.
A directed graph is aperiodic if there is no integer 𝑘 > 1 that divides the length of every cycle in the graph.
See the Wikipedia article Aperiodic_graph for more information.
EXAMPLES:
The following graph has period 2, so it is not aperiodic:
The following graph has a cycle of length 2 and a cycle of length 3, so it is aperiodic:
See also:
period()
is_directed()
Since digraph is directed, return True.
EXAMPLES:
sage: DiGraph().is_directed()
True
is_directed_acyclic(certificate=False)
Return whether the digraph is acyclic or not.
A directed graph is acyclic if for any vertex 𝑣, there is no directed path that starts and ends at 𝑣. Every
directed acyclic graph (DAG) corresponds to a partial ordering of its vertices, however multiple dags may
lead to the same partial ordering.
INPUT:
• certificate – boolean (default: False); whether to return a certificate
OUTPUT:
• When certificate=False, returns a boolean value.
• When certificate=True:
– If the graph is acyclic, returns a pair (True, ordering) where ordering is a list of the vertices
such that u appears before v in ordering if u, v is an edge.
– Else, returns a pair (False, cycle) where cycle is a list of vertices representing a circuit in
the graph.
EXAMPLES:
At first, the following graph is acyclic:
sage: D = DiGraph({0:[1, 2, 3], 4:[2, 5], 1:[8], 2:[7], 3:[7], 5:[6,7], 7:[8],␣
˓→6:[9], 8:[10], 9:[10]})
sage: D.plot(layout='circular').show()
sage: D.is_directed_acyclic()
True
sage: D.add_edge(9, 7)
sage: D.is_directed_acyclic()
True
We can obtain as a proof an ordering of the vertices such that 𝑢 appears before 𝑣 if 𝑢𝑣 is an edge of the
graph:
sage: D.is_directed_acyclic(certificate=True)
(True, [4, 5, 6, 9, 0, 1, 2, 3, 7, 8, 10])
sage: D.add_edge(7, 4)
sage: D.is_directed_acyclic()
False
sage: D.is_directed_acyclic(certificate=True)
(False, [7, 4, 5])
....: return h
...
(continues on next page)
is_strongly_connected(G)
Check whether the current DiGraph is strongly connected.
EXAMPLES:
The circuit is obviously strongly connected:
is_tournament()
Check whether the digraph is a tournament.
A tournament is a digraph in which each pair of distinct vertices is connected by a single arc.
EXAMPLES:
sage: g = digraphs.RandomTournament(6)
sage: g.is_tournament()
True
sage: u,v = next(g.edge_iterator(labels=False))
sage: g.add_edge(v, u)
sage: g.is_tournament()
False
sage: g.add_edges([(u, v), (v, u)])
sage: g.is_tournament()
False
See also:
is_transitive(g, certificate=False)
Tests whether the digraph is transitive.
A digraph is transitive if for any pair of vertices 𝑢, 𝑣 ∈ 𝐺 linked by a 𝑢𝑣-path the edge 𝑢𝑣 belongs to 𝐺.
INPUT:
• certificate – whether to return a certificate for negative answers.
– If certificate = False (default), this method returns True or False according to the graph.
– If certificate = True, this method either returns True answers or yield a pair of vertices 𝑢𝑣
such that there exists a 𝑢𝑣-path in 𝐺 but 𝑢𝑣 ̸∈ 𝐺.
EXAMPLES:
sage: digraphs.Circuit(4).is_transitive()
False
sage: digraphs.Circuit(4).is_transitive(certificate=True)
(0, 2)
sage: digraphs.RandomDirectedGNP(30,.2).is_transitive()
False
sage: D = digraphs.DeBruijn(5, 2)
sage: D.is_transitive()
False
sage: cert = D.is_transitive(certificate=True)
sage: D.has_edge(*cert)
False
sage: bool(D.shortest_path(*cert))
True
sage: digraphs.RandomDirectedGNP(20,.2).transitive_closure().is_transitive()
True
layout_acyclic(rankdir='up', **options)
Return a ranked layout so that all edges point upward.
To this end, the heights of the vertices are set according to the level set decomposition of the graph (see
level_sets()).
This is achieved by calling graphviz and dot2tex if available (see layout_graphviz()), and using a
spring layout with fixed vertical placement of the vertices otherwise (see layout_acyclic_dummy() and
layout_ranked()).
Non acyclic graphs are partially supported by graphviz, which then chooses some edges to point down.
INPUT:
• rankdir – string (default: 'up'); indicates which direction the edges should point toward among
'up', 'down', 'left', or 'right'
• **options – passed down to layout_ranked() or layout_graphviz()
EXAMPLES:
sage: H = DiGraph({0: [1, 2], 1: [3], 2: [3], 3: [], 5: [1, 6], 6: [2, 3]})
The actual layout computed depends on whether dot2tex and graphviz are installed, so we don’t test its
relative values:
sage: H.layout_acyclic()
{0: [..., ...], 1: [..., ...], 2: [..., ...], 3: [..., ...], 5: [..., ...], 6:␣
˓→[..., ...]}
sage: H = DiGraph({0: [1, 2], 1: [3], 2: [3], 3: [], 5: [1, 6], 6: [2, 3]})
sage: H.layout_acyclic_dummy()
{0: [1.0..., 0], 1: [1.0..., 1], 2: [1.5..., 2], 3: [1.5..., 3], 5: [2.0..., 0],
˓→ 6: [2.0..., 1]}
level_sets()
Return the level set decomposition of the digraph.
OUTPUT:
• a list of non empty lists of vertices of this graph
The level set decomposition of the digraph is a list 𝑙 such that the level 𝑙[𝑖] contains all the vertices having
all their predecessors in the levels 𝑙[𝑗] for 𝑗 < 𝑖, and at least one in level 𝑙[𝑖 − 1] (unless 𝑖 = 0).
The level decomposition contains exactly the vertices not occurring in any cycle of the graph. In particular,
the graph is acyclic if and only if the decomposition forms a set partition of its vertices, and we recover the
usual level set decomposition of the corresponding poset.
EXAMPLES:
sage: H = DiGraph({0: [1, 2], 1: [3], 2: [3], 3: [], 5: [1, 6], 6: [2, 3]})
sage: H.level_sets()
[[0, 5], [1, 6], [2], [3]]
sage: H = DiGraph({0: [1, 2], 1: [3], 2: [3], 3: [1], 5: [1, 6], 6: [2, 3]})
sage: H.level_sets()
[[0, 5], [6], [2]]
Complexity: 𝑂(𝑛 + 𝑚) in time and 𝑂(𝑛) in memory (besides the storage of the graph itself), where 𝑛 and
𝑚 are respectively the number of vertices and edges (assuming that appending to a list is constant time,
which it is not quite).
neighbor_in_iterator(vertex)
Return an iterator over the in-neighbors of vertex.
An vertex 𝑢 is an in-neighbor of a vertex 𝑣 if 𝑢𝑣 in an edge.
EXAMPLES:
neighbor_out_iterator(vertex)
Return an iterator over the out-neighbors of a given vertex.
A vertex 𝑢 is an out-neighbor of a vertex 𝑣 if 𝑣𝑢 in an edge.
EXAMPLES:
neighbors_in(vertex)
Return the list of the in-neighbors of a given vertex.
neighbors_out(vertex)
Return the list of the out-neighbors of a given vertex.
A vertex 𝑢 is an out-neighbor of a vertex 𝑣 if 𝑣𝑢 in an edge.
EXAMPLES:
out_branchings(source, spanning=True)
Return an iterator over the out branchings rooted at given vertex in self.
An out-branching is a directed tree rooted at source whose arcs are directed from source to leaves. An
out-branching is spanning if it contains all vertices of the digraph.
If no spanning out branching rooted at source exist, raises ValueError or return non spanning out branching
rooted at source, depending on the value of spanning.
INPUT:
• source – vertex used as the source for all out branchings.
• spanning – boolean (default: True); if False return maximum out branching from source. Other-
wise, return spanning out branching if exists.
OUTPUT:
An iterator over the out branchings rooted in the given source.
See also:
ALGORITHM:
Recursively computes all out branchings.
At each step:
0. clean the graph (see below)
1. pick an edge e out of source
2. find all out branchings that do not contain e by first removing it
3. find all out branchings that do contain e by first merging the end vertices of e
Cleaning the graph implies to remove loops and replace multiedges by a single one with an appropriate
label since these lead to similar steps of computation.
EXAMPLES:
A bidirectional 4-cycle:
sage: G = graphs.PetersenGraph().to_directed()
sage: len(list(G.out_branchings(0)))
2000
With multiedges:
sage: next(G.out_branchings(0)) == G
True
out_degree(vertices=None, labels=False)
Same as degree, but for out degree.
EXAMPLES:
out_degree_iterator(vertices=None, labels=False)
Same as degree_iterator, but for out degree.
EXAMPLES:
sage: D = graphs.Grid2dGraph(2,4).to_directed()
sage: sorted(D.out_degree_iterator())
[2, 2, 2, 2, 3, 3, 3, 3]
sage: sorted(D.out_degree_iterator(labels=True))
[((0, 0), 2),
((0, 1), 3),
((0, 2), 3),
((0, 3), 2),
((1, 0), 2),
((1, 1), 3),
((1, 2), 3),
((1, 3), 2)]
out_degree_sequence()
Return the outdegree sequence of this digraph.
EXAMPLES:
The outdegree sequences of two digraphs:
sage: g = DiGraph({1: [2, 5, 6], 2: [3, 6], 3: [4, 6], 4: [6], 5: [4, 6]})
sage: g.out_degree_sequence()
[3, 2, 2, 2, 1, 0]
outgoing_edge_iterator(vertices, labels=True)
Return an iterator over all departing edges from vertices.
INPUT:
• vertices – a vertex or a list of vertices
• labels – boolean (default: True); whether to return edges as pairs of vertices, or as triples containing
the labels.
EXAMPLES:
outgoing_edges(vertices, labels=True)
Return a list of edges departing from vertices.
INPUT:
path_semigroup()
The partial semigroup formed by the paths of this quiver.
EXAMPLES:
period()
Return the period of the current DiGraph.
The period of a directed graph is the largest integer that divides the length of every cycle in the graph. See
the Wikipedia article Aperiodic_graph for more information.
EXAMPLES:
The following graph has period 2:
The following graph has a cycle of length 2 and a cycle of length 3, so it has period 1:
Here is an example of computing the period of a digraph which is not strongly connected. By definition, it
is the gcd() of the periods of its strongly connected components:
ALGORITHM:
See the networkX implementation of is_aperiodic, that is based on breadth first search.
See also:
is_aperiodic()
sage: G = graphs.DiamondGraph().to_directed()
sage: G.periphery()
[0, 3]
sage: P = digraphs.Path(5)
sage: P.periphery()
[1, 2, 3, 4]
sage: G = digraphs.Complete(5)
sage: G.subgraph(G.periphery()) == G
True
sage: G = digraphs.Circuit(9)
sage: G.radius()
8
sage: G.diameter()
8
reverse()
Return a copy of digraph with edges reversed in direction.
EXAMPLES:
If multiedges is True, self will be forced to allow parallel edges when and only when it is necessary:
Even if multiedges is True, self will not be forced to allow parallel edges when it is not necessary:
If user specifies multiedges = False, self will not be forced to allow parallel edges and a parallel edge
will get deleted:
Note that in the following graph, specifying multiedges = False will result in overwriting the label of
(1, 2) with the label of (2, 1):
If input edge in digraph has weight/label, then the weight/label should be preserved in the output digraph.
User does not need to specify the weight/label when calling function:
If self has multiple copies (parallel edges) of the input edge, only 1 of the parallel edges is reversed:
If self has multiple copies (parallel edges) of the input edge but with distinct labels and no input label
is specified, only 1 of the parallel edges is reversed (the edge that is labeled by the first label on the list
returned by edge_label()):
sage: D.edge_label(0, 1)
['cat', 'mouse', 'B', 'A']
sage: D.reverse_edge(0, 1)
sage: D.edges(sort=True)
[(0, 1, 'A'), (0, 1, 'B'), (0, 1, 'mouse'), (1, 0, 'cat')]
Finally, an exception is raised when Sage does not know how to choose between allowing multiple edges
and losing some data:
The following syntax is supported, but note that you must use the label keyword:
sage: D = DiGraph()
sage: D.add_edge((1, 2), label='label')
sage: D.edges(sort=True)
[(1, 2, 'label')]
sage: D.reverse_edge((1, 2), label='label')
sage: D.edges(sort=True)
[(2, 1, 'label')]
sage: D.add_edge((1, 2), 'label')
sage: D.edges(sort=False)
[((1, 2), 'label', None), (2, 1, 'label')]
sage: D.reverse_edge((1, 2), 'label')
sage: D.edges(sort=False)
[('label', (1, 2), None), (2, 1, 'label')]
If multiedges is True, self will be forced to allow parallel edges when and only when it is necessary:
Even if multiedges is True, self will not be forced to allow parallel edges when it is not necessary:
If multiedges is False, self will not be forced to allow parallel edges and an edge will get deleted:
If input edge in digraph has weight/label, then the weight/label should be preserved in the output digraph.
User does not need to specify the weight/label when calling function:
sinks()
Return a list of sinks of the digraph.
OUTPUT:
• list of the vertices of the digraph that have no edges beginning at them
EXAMPLES:
sources()
Return a list of sources of the digraph.
OUTPUT:
• list of the vertices of the digraph that have no edges going into them
EXAMPLES:
strong_articulation_points(G)
Return the strong articulation points of this digraph.
A vertex is a strong articulation point if its deletion increases the number of strongly connected components.
This method implements the algorithm described in [ILS2012]. The time complexity is dominated by the
sage: D = digraphs.Complete(4) * 2
sage: D.add_edges([(0, 4), (7, 3)])
sage: sorted(strong_articulation_points(D))
[0, 3, 4, 7]
sage: D.add_edge(1, 5)
sage: sorted(strong_articulation_points(D))
[3, 7]
sage: D.add_edge(6, 2)
sage: strong_articulation_points(D)
[]
See also:
• strongly_connected_components()
• dominator_tree()
strongly_connected_component_containing_vertex(G, v)
Return the strongly connected component containing a given vertex
INPUT:
• G – the input DiGraph
• v – a vertex
EXAMPLES:
In the symmetric digraph of a graph, the strongly connected components are the connected components:
sage: g = graphs.PetersenGraph()
sage: d = DiGraph(g)
sage: strongly_connected_component_containing_vertex(d, 0)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sage: d.strongly_connected_component_containing_vertex(0)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sage: g = DiGraph([(0, 1), (1, 0), (1, 2), (2, 3), (3, 2)])
sage: strongly_connected_component_containing_vertex(g, 0)
[0, 1]
strongly_connected_components(G)
Return the lists of vertices in each strongly connected components (SCCs).
This method implements the Tarjan algorithm to compute the strongly connected components of the di-
graph. It returns a list of lists of vertices, each list of vertices representing a strongly connected component.
The basic idea of the algorithm is this: a depth-first search (DFS) begins from an arbitrary start node (and
subsequent DFSes are conducted on any nodes that have not yet been found). As usual with DFSes, the
search visits every node of the graph exactly once, declining to revisit any node that has already been
explored. Thus, the collection of search trees is a spanning forest of the graph. The strongly connected
components correspond to the subtrees of this spanning forest that have no edge directed outside the subtree.
To recover these components, during the DFS, we keep the index of a node, that is, the position in the DFS
tree, and the lowlink: as soon as the subtree rooted at 𝑣 has been fully explored, the lowlink of 𝑣 is the
smallest index reachable from 𝑣 passing from descendants of 𝑣. If the subtree rooted at 𝑣 has been fully
explored, and the index of 𝑣 equals the lowlink of 𝑣, that whole subtree is a new SCC.
For more information, see the Wikipedia article Tarjan%27s_strongly_connected_components_algorithm.
EXAMPLES:
sage: tarjan_strongly_connected_components(digraphs.Path(3))
[[2], [1], [0]]
sage: D = DiGraph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )
sage: D.connected_components()
[[0, 1, 2, 3], [4, 5, 6]]
sage: D = DiGraph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )
sage: D.strongly_connected_components()
[[3], [2], [1], [0], [6], [5], [4]]
sage: D.add_edge([2,0])
sage: D.strongly_connected_components()
[[3], [0, 1, 2], [6], [5], [4]]
sage: D = DiGraph([('a','b'), ('b','c'), ('c', 'd'), ('d', 'b'), ('c', 'e')])
sage: [sorted(scc) for scc in D.strongly_connected_components()]
[['e'], ['b', 'c', 'd'], ['a']]
strongly_connected_components_digraph(G, keep_labels=False)
Return the digraph of the strongly connected components
The digraph of the strongly connected components of a graph 𝐺 has a vertex per strongly connected com-
ponent included in 𝐺. There is an edge from a component 𝐶1 to a component 𝐶2 if there is an edge in 𝐺
from a vertex 𝑢1 ∈ 𝐶1 to a vertex 𝑢2 ∈ 𝐶2 .
INPUT:
• G – the input DiGraph
• keep_labels – boolean (default: False); when keep_labels=True, the resulting digraph has an
edge from a component 𝐶𝑖 to a component 𝐶𝑗 for each edge in 𝐺 from a vertex 𝑢𝑖 ∈ 𝐶𝑖 to a vertex 𝑢𝑗 ∈
𝐶𝑗 . Hence the resulting digraph may have loops and multiple edges. However, edges in the result with
same source, target, and label are not duplicated (see examples below). When keep_labels=False,
the return digraph is simple, so without loops nor multiple edges, and edges are unlabelled.
EXAMPLES:
Such a digraph is always acyclic:
The vertices of the digraph of strongly connected components are exactly the strongly connected compo-
nents:
sage: g = digraphs.ButterflyGraph(2)
sage: scc_digraph = strongly_connected_components_digraph(g)
sage: g.is_directed_acyclic()
True
sage: V_scc = list(scc_digraph)
sage: all(Set(scc) in V_scc for scc in g.strongly_connected_components())
True
The following digraph has three strongly connected components, and the digraph of those is a
TransitiveTournament():
sage: g = DiGraph({0: {1: "01", 2: "02", 3: "03"}, 1: {2: "12"}, 2:{1: "21", 3:
˓→"23"}})
By default, the labels are discarded, and the result has no loops nor multiple edges. If keep_labels is
True, then the labels are kept, and the result is a multi digraph, possibly with multiple edges and loops.
However, edges in the result with same source, target, and label are not duplicated (see the edges from 0 to
the strongly connected component {1, 2} below):
strongly_connected_components_subgraphs(G)
Return the strongly connected components as a list of subgraphs.
EXAMPLES:
In the symmetric digraph of a graph, the strongly connected components are the connected components:
sage: g = graphs.PetersenGraph()
sage: d = DiGraph(g)
sage: strongly_connected_components_subgraphs(d)
[Subgraph of (Petersen graph): Digraph on 10 vertices]
sage: d.strongly_connected_components_subgraphs()
[Subgraph of (Petersen graph): Digraph on 10 vertices]
sage: g = DiGraph([(0, 1), (1, 0), (1, 2), (2, 3), (3, 2)])
sage: strongly_connected_components_subgraphs(g)
[Subgraph of (): Digraph on 2 vertices, Subgraph of (): Digraph on 2 vertices]
to_directed()
Since the graph is already directed, simply returns a copy of itself.
EXAMPLES:
to_undirected(data_structure=None, sparse=None)
Return an undirected version of the graph.
Every directed edge becomes an edge.
INPUT:
• data_structure – string (default: None); one of "sparse", "static_sparse", or "dense". See
the documentation of Graph or DiGraph .
• sparse – boolean (default: None); sparse=True is an alias for data_structure="sparse", and
sparse=False is an alias for data_structure="dense".
EXAMPLES:
topological_sort(implementation='default')
Return a topological sort of the digraph if it is acyclic.
If the digraph contains a directed cycle, a TypeError is raised. As topological sorts are not necessarily
unique, different implementations may yield different results.
A topological sort is an ordering of the vertices of the digraph such that each vertex comes before all of its
successors. That is, if 𝑢 comes before 𝑣 in the sort, then there may be a directed path from 𝑢 to 𝑣, but there
will be no directed path from 𝑣 to 𝑢.
INPUT:
• implementation – string (default: "default"); either use the default Cython implementation, or
the default NetworkX library (implementation = "NetworkX")
See also:
• is_directed_acyclic() – Tests whether a directed graph is acyclic (can also join a certificate – a
topological sort or a circuit in the graph).
EXAMPLES:
sage: D.add_edge(9, 7)
sage: D.topological_sort()
[4, 5, 6, 9, 0, 1, 2, 3, 7, 8, 10]
sage: D.add_edge(7, 4)
sage: D.topological_sort()
Traceback (most recent call last):
...
TypeError: digraph is not acyclic; there is no topological sort
topological_sort_generator()
Return an iterator over all topological sorts of the digraph if it is acyclic.
If the digraph contains a directed cycle, a TypeError is raised.
A topological sort is an ordering of the vertices of the digraph such that each vertex comes before all of its
successors. That is, if u comes before v in the sort, then there may be a directed path from u to v, but there
will be no directed path from v to u. See also topological_sort().
AUTHORS:
• Mike Hansen - original implementation
• Robert L. Miller: wrapping, documentation
REFERENCE:
• [1] Pruesse, Gara and Ruskey, Frank. Generating Linear Extensions Fast. SIAM J. Comput., Vol. 23
(1994), no. 2, pp. 373-386.
EXAMPLES:
EXAMPLES:
1. No inputs or None for the input creates an empty graph:
sage: B = BipartiteGraph()
sage: type(B)
<class 'sage.graphs.bipartite_graph.BipartiteGraph'>
sage: B.order()
0
sage: B == BipartiteGraph(None)
True
sage: B = BipartiteGraph(graphs.CycleGraph(4))
sage: B = BipartiteGraph(graphs.CycleGraph(5))
Traceback (most recent call last):
...
ValueError: input graph is not bipartite
sage: G = Graph({0: [5, 6], 1: [4, 5], 2: [4, 6], 3: [4, 5, 6]})
sage: B = BipartiteGraph(G)
sage: B == G
True
sage: B.left
{0, 1, 2, 3}
sage: B.right
{4, 5, 6}
sage: B = BipartiteGraph({0: [5, 6], 1: [4, 5], 2: [4, 6], 3: [4, 5, 6]})
sage: B == G
True
sage: B.left
{0, 1, 2, 3}
sage: B.right
{4, 5, 6}
3. If a Graph or DiGraph is used as data, you can specify a partition using partition argument. Note that
if such graph is not bipartite, then Sage will raise an error. However, if one specifies check=False, the
offending edges are simply deleted (along with those vertices not appearing in either list). We also lump
creating one bipartite graph from another into this category:
sage: P = graphs.PetersenGraph()
sage: partition = [list(range(5)), list(range(5, 10))]
sage: B = BipartiteGraph(P, partition)
Traceback (most recent call last):
...
TypeError: input graph is not bipartite with respect to the given partition
sage: G = Graph({0: [5, 6], 1: [4, 5], 2: [4, 6], 3: [4, 5, 6]})
sage: B = BipartiteGraph(G)
(continues on next page)
sage: d = DiGraph(6)
sage: d.add_edge(0, 1)
sage: part=[[1, 2, 3], [0, 4, 5]]
sage: b = BipartiteGraph(d, part)
sage: b.left
{1, 2, 3}
sage: b.right
{0, 4, 5}
:: sage: B = BipartiteGraph(‘Bo’, partition=[[0], [1, 2]]) sage: B.left {0} sage: B.right {1, 2}
sage: B.left
{0, 1, 2}
sage: B.show()
add_edges(edges, loops=True)
Add edges from an iterable container.
INPUT:
• edges – an iterable of edges, given either as (u, v) or (u, v, label).
• loops – ignored
See add_edges() for more detail.
This method simply checks that the edge endpoints are in different partitions. If a new vertex is to be
created, it will be added to the proper partition. If both vertices are created, the first one will be added to
the left partition, the second to the right partition.
EXAMPLES:
sage: bg = BipartiteGraph()
sage: bg.add_vertices([0, 1, 2], left=[True, False, True])
sage: bg.add_edges([(0, 1), (2, 1)])
sage: bg.add_edges([[0, 2]])
Traceback (most recent call last):
...
RuntimeError: edge vertices must lie in different partitions
sage: G = BipartiteGraph()
sage: G.add_vertex(left=True)
0
sage: G.add_vertex(right=True)
1
(continues on next page)
sage: bg = BipartiteGraph()
sage: bg.add_vertices([0, 1, 2], left=True)
sage: bg.add_vertices([3, 4, 5], left=[True, False, True])
sage: bg.add_vertices([6, 7, 8], right=[True, False, True])
sage: bg.add_vertices([9, 10, 11], right=True)
sage: bg.left
{0, 1, 2, 3, 5, 7}
sage: bg.right
{4, 6, 8, 9, 10, 11}
allow_loops(new, check=True)
Change whether loops are permitted in the (di)graph
Note: This method overwrite the allow_loops() method to ensure that loops are forbidden in
BipartiteGraph .
INPUT:
• new – boolean
EXAMPLES:
sage: B = BipartiteGraph()
sage: B.allow_loops(True)
Traceback (most recent call last):
...
ValueError: loops are not allowed in bipartite graphs
bipartition()
Return the underlying bipartition of the bipartite graph.
EXAMPLES:
sage: B = BipartiteGraph(graphs.CycleGraph(4))
sage: B.bipartition()
({0, 2}, {1, 3})
Note: Make sure you always compare canonical forms obtained by the same algorithm.
• return_graph – boolean (default: True). When set to False, returns the list of edges of the canonical
graph instead of the canonical graph; only available when 'bliss' is explicitly set as algorithm.
EXAMPLES:
sage: B = BipartiteGraph( [(0, 4), (0, 5), (0, 6), (0, 8), (1, 5),
....: (1, 7), (1, 8), (2, 6), (2, 7), (2, 8),
....: (3, 4), (3, 7), (3, 8), (4, 9), (5, 9),
....: (6, 9), (7, 9)] )
sage: C = B.canonical_label(partition=(B.left,B.right), algorithm='sage')
sage: C
Bipartite graph on 10 vertices
sage: C.left
{0, 1, 2, 3, 4}
sage: C.right
{5, 6, 7, 8, 9}
sage: B = BipartiteGraph( [(0, 4), (0, 5), (0, 6), (0, 8), (1, 5),
....: (1, 7), (1, 8), (2, 6), (2, 7), (2, 8),
....: (3, 4), (3, 7), (3, 8), (4, 9), (5, 9),
....: (6, 9), (7, 9)] )
sage: C, cert = B.canonical_label(partition=(B.left,B.right), certificate=True,␣
˓→algorithm='sage') (continues on next page)
sage: G = Graph({0: [5, 6], 1: [4, 5], 2: [4, 6], 3: [4, 5, 6]})
sage: B = BipartiteGraph(G)
sage: C = B.canonical_label(partition=(B.left,B.right), edge_labels=True,␣
˓→algorithm='sage')
sage: C.left
{0, 1, 2, 3}
sage: C.right
{4, 5, 6}
See also:
canonical_label()
complement()
Return a complement of this graph.
Given a simple BipartiteGraph 𝐺 = (𝐿, 𝑅, 𝐸) with vertex set 𝐿∪𝑅 and edge set 𝐸, this method returns
a Graph 𝐻 = (𝑉, 𝐹 ), where 𝑉 = 𝐿 ∪ 𝑅 and 𝐹 is the set of edges of a complete graph of order |𝑉 | minus
the edges in 𝐸.
Warning: This method returns the complement of a bipartite graph 𝐺 = (𝑉 = 𝐿 ∪ 𝑅, 𝐸) with respect
the complete graph of order |𝑉 |. If looking for the complement with respect the complete bipartite graph
𝐾 = (𝐿, 𝑅, 𝐿 × 𝑅), use method complement_bipartite().
See also:
complement_bipartite()
EXAMPLES:
complement_bipartite()
Return the bipartite complement of this bipartite graph.
Given a simple BipartiteGraph 𝐺 = (𝐿, 𝑅, 𝐸) with vertex set 𝐿∪𝑅 and edge set 𝐸, this method returns
a BipartiteGraph 𝐻 = (𝐿 ∪ 𝑅, 𝐹 ), where 𝐹 is the set of edges of a complete bipartite graph between
vertex sets 𝐿 and 𝑅 minus the edges in 𝐸.
See also:
complement()
EXAMPLES:
sage: B = BipartiteGraph({0: [1, 2, 3]}) sage: C = B.complement_bipartite() sage: C Bipar-
tite graph on 4 vertices sage: C.is_bipartite() True sage: B.left == C.left and B.right == C.right
True sage: C.size() == len(B.left)*len(B.right) - B.size() True sage: G = B.complement() sage:
G.is_bipartite() False
delete_vertex(vertex, in_order=False)
Delete vertex, removing all incident edges.
Deleting a non-existent vertex will raise an exception.
INPUT:
• vertex – a vertex to delete.
• in_order – boolean (default False); if True, deletes the 𝑖-th vertex in the sorted list of vertices, i.e.
G.vertices(sort=True)[i].
EXAMPLES:
sage: B = BipartiteGraph(graphs.CycleGraph(4))
sage: B
Bipartite cycle graph: graph on 4 vertices
sage: B.delete_vertex(0)
sage: B
Bipartite cycle graph: graph on 3 vertices
sage: B.left
{2}
sage: B.edges(sort=True)
[(1, 2, None), (2, 3, None)]
sage: B.delete_vertex(3)
sage: B.right
{1}
sage: B.edges(sort=True)
[(1, 2, None)]
sage: B.delete_vertex(0)
Traceback (most recent call last):
...
ValueError: vertex (0) not in the graph
delete_vertices(vertices)
Remove vertices from the bipartite graph taken from an iterable sequence of vertices.
Deleting a non-existent vertex will raise an exception.
INPUT:
• vertices – a sequence of vertices to remove
EXAMPLES:
sage: B = BipartiteGraph(graphs.CycleGraph(4))
sage: B
Bipartite cycle graph: graph on 4 vertices
sage: B.delete_vertices([0, 3])
sage: B
Bipartite cycle graph: graph on 2 vertices
sage: B.left
{2}
sage: B.right
{1}
sage: B.edges(sort=True)
[(1, 2, None)]
sage: B.delete_vertices([0])
Traceback (most recent call last):
...
ValueError: vertex (0) not in the graph
is_bipartite(certificate=False)
Check whether the graph is bipartite.
This method always returns True as first value, plus a certificate when certificate == True.
INPUT:
• certificate – boolean (default: False); whether to return a certificate. If set to True, the certificate
returned is a proper 2-coloring of the vertices.
See also:
is_bipartite()
EXAMPLES:
load_afile(fname)
Load into the current object the bipartite graph specified in the given file name.
This file should follow David MacKay’s alist format, see http://www.inference.phy.cam.ac.uk/mackay/
codes/data.html for examples and definition of the format.
EXAMPLES:
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
See also:
EXAMPLES:
Maximum matching in a cycle graph:
sage: G = BipartiteGraph(graphs.CycleGraph(10))
sage: G.matching()
[(0, 1, None), (2, 3, None), (4, 5, None), (6, 7, None), (8, 9, None)]
sage: G = BipartiteGraph(graphs.CompleteBipartiteGraph(4,5))
sage: G.matching(algorithm="Eppstein", value_only=True)
4
matching_polynomial(algorithm='Godsil', name=None)
Compute the matching polynomial.
The matching polynomial is defined as in [God1993], where 𝑝(𝐺, 𝑘) denotes the number of 𝑘-matchings
(matchings with 𝑘 edges) in 𝐺 :
∑︁
𝜇(𝑥) = (−1)𝑘 𝑝(𝐺, 𝑘)𝑥𝑛−2𝑘
𝑘≥0
INPUT:
• algorithm – string (default: "Godsil"); either “Godsil” or “rook”; “rook” is usually faster for larger
graphs
• name – string (default: None); name of the variable in the polynomial, set to 𝑥 when name is None
EXAMPLES:
sage: BipartiteGraph(graphs.CubeGraph(3)).matching_polynomial()
x^8 - 12*x^6 + 42*x^4 - 44*x^2 + 9
sage: x = polygen(QQ)
sage: g = BipartiteGraph(graphs.CompleteBipartiteGraph(16, 16))
sage: bool(factorial(16) * laguerre(16, x^2) == g.matching_polynomial(algorithm=
˓→'rook')) # optional - sage.symbolic
True
sage: g = graphs.RandomTree(20)
sage: p = g.characteristic_polynomial()
sage: p == BipartiteGraph(g).matching_polynomial(algorithm='rook')
True
perfect_matchings(labels=False)
Return an iterator over all perfect matchings of the bipartite graph.
ALGORITHM:
Choose a vertex 𝑣 in the right set of vertices, then recurse through all edges incident to 𝑣, removing one
edge at a time whenever an edge is added to a matching.
INPUT:
• labels – boolean (default: False); when True, the edges in each perfect matching are triples (con-
taining the label as the third element), otherwise the edges are pairs.
See also:
perfect_matchings() matching()
EXAMPLES:
sage: B = BipartiteGraph({0: [5, 7], 1: [4, 6, 7], 2: [4, 5, 8], 3: [4, 5, 6],␣
˓→6: [9], 8: [9]})
sage: len(list(B.perfect_matchings()))
6
sage: G = Graph(B.edges(sort=False))
sage: len(list(G.perfect_matchings()))
6
The algorithm ensures that for any edge of a perfect matching, the first vertex is on the left set of vertices
and the second vertex in the right set:
sage: B = BipartiteGraph({0: [5, 7], 1: [4, 6, 7], 2: [4, 5, 8], 3: [4, 5, 6],␣
˓→6: [9], 8: [9]})
sage: m = next(B.perfect_matchings(labels=False))
sage: B.left
{0, 1, 2, 3, 9}
sage: B.right
{4, 5, 6, 7, 8}
sage: sorted(m)
[(0, 7), (1, 4), (2, 5), (3, 6), (9, 8)]
sage: all((u in B.left and v in B.right) for u, v in m)
True
sage: B = BipartiteGraph({0: [5, 7], 1: [4, 6, 7], 2: [4, 5, 8], 3: [4, 5, 6],␣
˓→6: [9], 8: [9]})
sage: B.allow_multiple_edges(True)
sage: B.add_edge(0, 7)
sage: len(list(B.perfect_matchings()))
10
Empty graph:
sage: list(BipartiteGraph().perfect_matchings())
[[]]
Check that the number of perfect matchings of a complete bipartite graph is consistent with the matching
polynomial:
plot(*args, **kwds)
Override Graph’s plot function, to illustrate the bipartite nature.
EXAMPLES:
sage: B = BipartiteGraph(graphs.CycleGraph(20))
sage: B.plot()
Graphics object consisting of 41 graphics primitives
project_left()
Project self onto left vertices. Edges are 2-paths in the original.
EXAMPLES:
sage: B = BipartiteGraph(graphs.CycleGraph(20))
sage: G = B.project_left()
sage: G.order(), G.size()
(10, 10)
project_right()
Project self onto right vertices. Edges are 2-paths in the original.
EXAMPLES:
sage: B = BipartiteGraph(graphs.CycleGraph(20))
sage: G = B.project_right()
sage: G.order(), G.size()
(10, 10)
Multi-edge graphs also return a matrix over ZZ, unless a base ring is specified:
Weighted graphs will return a matrix over the ring given by their (first) weights, unless a base ring is
specified:
save_afile(fname)
Save the graph to file in alist format.
Saves this graph to file in David MacKay’s alist format, see http://www.inference.phy.cam.ac.uk/mackay/
codes/data.html for examples and definition of the format.
EXAMPLES:
to_undirected()
Return an undirected Graph (without bipartite constraint) of the given object.
EXAMPLES:
sage: BipartiteGraph(graphs.CycleGraph(6)).to_undirected()
Cycle graph: Graph on 6 vertices
INPUT:
• algorithm – string (default: "Konig"); algorithm to use among:
– "Konig" will compute a minimum vertex cover using Konig’s algorithm (Wikipedia article
Kőnig%27s_theorem_(graph_theory))
– "Cliquer" will compute a minimum vertex cover using the Cliquer package
– "MILP" will compute a minimum vertex cover through a mixed integer linear program
– "mcqd" will use the MCQD solver (http://www.sicmm.org/~konc/maxclique/), and the MCQD
package must be installed
• value_only – boolean (default: False); if set to True, only the size of a minimum vertex cover is
returned. Otherwise, a minimum vertex cover is returned as a list of vertices.
• reduction_rules – (default: True); specify if the reductions rules from kernelization must be ap-
plied as pre-processing or not. See [ACFLSS04] for more details. Note that depending on the instance,
it might be faster to disable reduction rules. This parameter is currently ignored when algorithm ==
"Konig".
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
EXAMPLES:
On the Cycle Graph:
sage: B = BipartiteGraph(graphs.CycleGraph(6))
sage: len(B.vertex_cover())
3
sage: B.vertex_cover(value_only=True)
3
This module implements views for (di)graphs. A view is a read-only iterable container enabling operations like for
e in E and e in E. It is updated as the graph is updated. Hence, the graph should not be updated while iterating
through a view. Views can be iterated multiple times.
Todo:
• View of neighborhood to get open/close neighborhood of a vertex/set of vertices, and also the vertex boundary
1.5.1 Classes
class sage.graphs.views.EdgesView
Bases: object
EdgesView class.
This class implements a read-only iterable container of edges enabling operations like for e in E and e in
E. An EdgesView can be iterated multiple times, and checking membership is done in constant time. It avoids
the construction of edge lists and so consumes little memory. It is updated as the graph is updated. Hence, the
graph should not be updated while iterating through an EdgesView.
INPUT:
• G – a (di)graph
• vertices – list (default: None); an iterable container of vertices or None. When set, consider only edges
incident to specified vertices.
• labels – boolean (default: True); if False, each edge is simply a pair (u, v) of vertices
• ignore_direction – boolean (default: False); only applies to directed graphs. If True, searches across
edges in either direction.
• sort – boolean (default: None); whether to sort edges
– if None, sort edges according to the default ordering and give a deprecation warning as sorting will be
set to False by default in the future
– if True, edges are sorted according the ordering specified with parameter key
– if False, edges are not sorted. This is the fastest and less memory consuming method for iterating
over edges. This will become the default behavior in the future.
• key – a function (default: None); a function that takes an edge (a pair or a triple, according to the labels
keyword) as its one argument and returns a value that can be used for comparisons in the sorting algorithm.
This parameter is ignored when sort = False.
• sort_vertices – boolean (default: True); whether to sort the ends of the edges; not sorting the ends is
faster; only applicable to undirected graphs when sort is False
Warning: Since any object may be a vertex, there is no guarantee that any two vertices will be comparable,
and thus no guarantee how two edges may compare. With default objects for vertices (all integers), or when
all the vertices are of the same simple type, then there should not be a problem with how the vertices will be
sorted. However, if you need to guarantee a total order for the sorting of the edges, use the key argument, as
illustrated in the examples below.
EXAMPLES:
sage: G = graphs.CycleGraph(3)
sage: print(E)
[(0, 1), (0, 2), (1, 2)]
sage: print(E)
[(0, 1), (0, 2), (1, 2)]
sage: for e in E:
....: for ee in E:
....: print((e, ee))
((0, 1), (0, 1))
((0, 1), (0, 2))
((0, 1), (1, 2))
((0, 2), (0, 1))
((0, 2), (0, 2))
((0, 2), (1, 2))
((1, 2), (0, 1))
((1, 2), (0, 2))
((1, 2), (1, 2))
When sort is True, edges are sorted by default in the default fashion:
This can be overridden by specifying a key function. This first example just ignores the labels in the third
component of the triple:
sage: G = Graph()
sage: G.add_edges([[1,2], [2,3], [0,3]])
sage: E = EdgesView(G, sort=False, sort_vertices=False); E
[(3, 0, None), (2, 1, None), (3, 2, None)]
sage: G = digraphs.DeBruijn(2, 2)
sage: E = EdgesView(G, labels=False, sort=True); E
[('00', '00'), ('00', '01'), ('01', '10'), ('01', '11'),
('10', '00'), ('10', '01'), ('11', '10'), ('11', '11')]
sage: E = EdgesView(G, labels=False, sort=True, key=lambda e:(e[1], e[0])); E
[('00', '00'), ('10', '00'), ('00', '01'), ('10', '01'),
('01', '10'), ('11', '10'), ('01', '11'), ('11', '11')]
sage: G = graphs.CycleGraph(5)
sage: E = EdgesView(G, vertices=[0, 1], labels=False, sort=True); E
[(0, 1), (0, 4), (1, 2)]
sage: E = EdgesView(G, vertices=[0], labels=False, sort=True); E
[(0, 1), (0, 4)]
sage: E = EdgesView(G, vertices=None, labels=False, sort=True); E
[(0, 1), (0, 4), (1, 2), (2, 3), (3, 4)]
sage: G = digraphs.Circuit(5)
sage: E = EdgesView(G, vertices=[0, 1], labels=False, sort=True); E
[(0, 1), (1, 2)]
We can ignore the direction of the edges of a directed graph, in which case we search across edges in either
direction:
sage: G = digraphs.Circuit(5)
sage: E = EdgesView(G, vertices=[0, 1], labels=False, sort=True, ignore_
˓→direction=False); E
sage: G = Graph()
sage: E = EdgesView(G, vertices=[0, 3], labels=False, sort=True); E
[]
sage: G.add_edges([(0, 1), (1, 2)])
sage: E
[(0, 1)]
sage: G.add_edge(2, 3)
sage: E
[(0, 1), (2, 3)]
Hence, the graph should not be updated while iterating through a view:
sage: G = Graph([('a', 'b'), ('b', 'c')])
sage: E = EdgesView(G, labels=False, sort=False); E
[('a', 'b'), ('b', 'c')]
sage: for u, v in E:
....: G.add_edge(u + u, v + v)
Traceback (most recent call last):
...
RuntimeError: dictionary changed size during iteration
Two EdgesView are considered equal if they report either both directed, or both undirected edges, they have the
same settings for ignore_direction, they have the same settings for labels, and they report the same edges
in the same order:
sage: G = graphs.HouseGraph()
sage: EG = EdgesView(G, sort=False)
sage: H = Graph(EG)
sage: EH = EdgesView(H, sort=False)
sage: EG == EH
True
sage: G.add_edge(0, 10)
sage: EG = EdgesView(G, sort=False)
sage: EG == EH
False
sage: H.add_edge(0, 10)
sage: EH = EdgesView(H, sort=False)
sage: EG == EH
True
sage: H = G.strong_orientation()
sage: EH = EdgesView(H, sort=False)
(continues on next page)
The sum of two EdgesView is a list containing the edges in both EdgesView:
Recall that a EdgesView is read-only and that this method returns a list:
sage: E1 += E2
sage: type(E1) is list
True
Recall that a EdgesView is read-only and that this method returns a list:
sage: E *= 2
sage: type(E) is list
True
We can ask for the 𝑖-th edge, or a slice of the edges as a list:
TWO
All graphs in Sage can be built through the graphs object. In order to build a complete graph on 15 elements, one can
do:
sage: g = graphs.CompleteGraph(15)
sage: p = graphs.PathGraph(4)
sage: h = graphs.HouseGraph()
More interestingly, one can get the list of all graphs that Sage knows how to build by typing graphs. in Sage and then
hitting tab.
Basic structures
Small Graphs
A small graph is just a single graph and has no parameter influencing the number of edges or vertices.
457
Graph Theory, Release 9.7
Families of graphs
A family of graph is an infinite set of graphs which can be indexed by fixed number of parameters, e.g. two integer
parameters. (A method whose name starts with a small letter does not return a single graph object but a graph iterator
or a list of graphs or . . . )
Chessboard Graphs
Intersection graphs
These graphs are generated by geometric representations. The objects of the representation correspond to the graph
vertices and the intersections of objects yield the graph edges.
Random graphs
DegreeSequence DegreeSequenceConfigurationModel
DegreeSequenceTree
DegreeSequenceBipartite DegreeSequenceExpected
Miscellaneous
WorldMap AfricaMap
EuropeMap USAMap
AUTHORS:
• Robert Miller (2006-11-05): initial version, empty, random, petersen
• Emily Kirkman (2006-11-12): basic structures, node positioning for all constructors
• Emily Kirkman (2006-11-19): docstrings, examples
• William Stein (2006-12-05): Editing.
• Robert Miller (2007-01-16): Cube generation and plotting
• Emily Kirkman (2007-01-16): more basic structures, docstrings
• Emily Kirkman (2007-02-14): added more named graphs
• Robert Miller (2007-06-08-11): Platonic solids, random graphs, graphs with a given degree sequence, random
directed graphs
• Robert Miller (2007-10-24): Isomorph free exhaustive generation
• Nathann Cohen (2009-08-12): WorldMap
• Michael Yurko (2009-9-01): added hyperstar, (n,k)-star, n-star, and bubblesort graphs
• Anders Jonsson (2009-10-15): added generalized Petersen graphs
• Harald Schilly and Yann Laigle-Chapuy (2010-03-24): added Fibonacci Tree
• Jason Grout (2010-06-04): cospectral_graphs
• Edward Scheinerman (2010-08-11): RandomTree
• Ed Scheinerman (2010-08-21): added Grotzsch graph and Mycielski graphs
• Ed Scheinerman (2010-11-15): added RandomTriangulation
• Minh Van Nguyen (2010-11-26): added more named graphs
• Keshav Kini (2011-02-16): added Shrikhande and Dyck graphs
• David Coudert (2012-02-10): new RandomGNP generator
• David Coudert (2012-08-02): added chessboard graphs: Queen, King, Knight, Bishop, and Rook graphs
class sage.graphs.graph_generators.GraphGenerators
Bases: object
A class consisting of constructors for several common graphs, as well as orderly generation of isomorphism class
representatives. See the module's help for a list of supported constructors.
A list of all graphs and graph structures (other than isomorphism class representatives) in this database is available
via tab completion. Type “graphs.” and then hit the tab key to see which graphs are available.
The docstrings include educational information about each named graph with the hopes that this class can be
used as a reference.
For all the constructors in this class (except the octahedral, dodecahedral, random and empty graphs), the position
dictionary is filled to override the spring-layout algorithm.
ORDERLY GENERATION:
This syntax accesses the generator of isomorphism class representatives. Iterates over distinct, exhaustive repre-
sentatives.
Also: see the use of the nauty package for generating graphs at the nauty_geng() method.
INPUT:
• vertices – a natural number or None to infinitely generate bigger and bigger graphs.
• property – (default: lambda x: True) any property to be tested on graphs before generation, but note
that in general the graphs produced are not the same as those produced by using the property function to
filter a list of graphs produced by using the lambda x: True default. The generation process assumes
the property has certain characteristics set by the augment argument, and only in the case of inherited
properties such that all subgraphs of the relevant kind (for augment='edges' or augment='vertices')
of a graph with the property also possess the property will there be no missing graphs. (The property
argument is ignored if degree_sequence is specified.)
• augment – (default: 'edges') possible values:
– 'edges' – augments a fixed number of vertices by adding one edge. In this case, all graphs on exactly
n=vertices are generated. If for any graph G satisfying the property, every subgraph, obtained from
G by deleting one edge but not the vertices incident to that edge, satisfies the property, then this will
generate all graphs with that property. If this does not hold, then all the graphs generated will satisfy
the property, but there will be some missing.
– 'vertices' – augments by adding a vertex and edges incident to that vertex. In this case, all graphs
up to n=vertices are generated. If for any graph G satisfying the property, every subgraph, obtained
from G by deleting one vertex and only edges incident to that vertex, satisfies the property, then this
will generate all graphs with that property. If this does not hold, then all the graphs generated will
satisfy the property, but there will be some missing.
• size – (default: None) the size of the graph to be generated.
• degree_sequence – (default: None) a sequence of non-negative integers, or None. If specified, the gen-
erated graphs will have these integers for degrees. In this case, property and size are both ignored.
• loops – (default: False) whether to allow loops in the graph or not.
• sparse – (default: True); whether to use a sparse or dense data structure. See the documentation of Graph .
• copy (boolean) – If set to True (default) this method makes copies of the graphs before returning them. If
set to False the method returns the graph it is working on. The second alternative is faster, but modifying
any of the graph instances returned by the method may break the function’s behaviour, as it is using these
graphs to compute the next ones: only use copy = False when you stick to reading the graphs returned.
EXAMPLES:
Print graphs on 3 or less vertices:
Remember that the property argument does not behave as a filter, except for appropriately inheritable properties:
Generate all simple graphs, allowing loops: (see OEIS sequence A000666)
Generate all graphs with a specified degree sequence (see OEIS sequence A002851):
(4, 1)
(6, 2)
(8, 5)
sage: for i in [4,6,8]: # long time (7s on sage.math, 2012)
....: print((i, len([g for g in graphs(i, augment='vertices', degree_
˓→sequence=[3]*i) if g.is_connected()])))
(4, 1)
(6, 2)
(8, 5)
(10, 19)
Make sure that the graphs are really independent and the generator survives repeated vertex removal (trac ticket
#8458):
REFERENCE:
• Brendan D. McKay, Isomorph-Free Exhaustive generation. Journal of Algorithms, Volume 26, Issue 2,
February 1998, pages 306-324.
static AffineOrthogonalPolarGraph(d, q, sign='+')
Return the affine polar graph 𝑉 𝑂+ (𝑑, 𝑞), 𝑉 𝑂− (𝑑, 𝑞) or 𝑉 𝑂(𝑑, 𝑞).
Affine Polar graphs are built from a 𝑑-dimensional vector space over 𝐹𝑞 , and a quadratic form which is
hyperbolic, elliptic or parabolic according to the value of sign.
Note that 𝑉 𝑂+ (𝑑, 𝑞), 𝑉 𝑂− (𝑑, 𝑞) are strongly regular graphs, while 𝑉 𝑂(𝑑, 𝑞) is not.
For more information on Affine Polar graphs, see Affine Polar Graphs page of Andries Brouwer’s website.
INPUT:
• d – integer; d must be even if sign is not None, and odd otherwise
• q – integer; a power of a prime number, as 𝐹𝑞 must exist
• sign – string (default: "+"); must be equal to "+", "-", or None to compute (respectively)
𝑉 𝑂+ (𝑑, 𝑞), 𝑉 𝑂− (𝑑, 𝑞) or 𝑉 𝑂(𝑑, 𝑞)
Note: The graph 𝑉 𝑂𝜖 (𝑑, 𝑞) is the graph induced by the non-neighbors of a vertex in an Orthogonal
Polar Graph 𝑂𝜖 (𝑑 + 2, 𝑞).
EXAMPLES:
The Brouwer-Haemers graph is isomorphic to 𝑉 𝑂− (4, 3):
sage: g = graphs.AffineOrthogonalPolarGraph(4,3,"-")
sage: g.is_isomorphic(graphs.BrouwerHaemersGraph())
True
sage: g = graphs.AffineOrthogonalPolarGraph(6,2,"-"); g
Affine Polar Graph VO^-(6,2): Graph on 64 vertices
sage: g.is_strongly_regular(parameters=True)
(64, 27, 10, 12)
sage: g = graphs.AffineOrthogonalPolarGraph(6,2,"+"); g
Affine Polar Graph VO^+(6,2): Graph on 64 vertices
sage: g.is_strongly_regular(parameters=True)
(64, 35, 18, 20)
sage: g = graphs.AffineOrthogonalPolarGraph(5,2,None); g
Affine Polar Graph VO^-(5,2): Graph on 32 vertices
sage: g.is_strongly_regular(parameters=True)
False
sage: g.is_regular()
True
sage: g.is_vertex_transitive()
True
sage: g=graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5); g
AS(5); GQ(4, 6): Graph on 125 vertices
sage: g.is_strongly_regular(parameters=True)
(125, 28, 3, 7)
sage: g=graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5,dual=True); g
AS(5)*; GQ(6, 4): Graph on 175 vertices
sage: g.is_strongly_regular(parameters=True)
(175, 30, 5, 5)
static AlternatingFormsGraph(n, q)
Return the alternating forms graph with the given parameters.
This builds a graph whose vertices are all 𝑛 skew-symmetric matrices over 𝐺𝐹 (𝑞) with zero diagonal. Two
vertices are adjacent if and only if the difference of the two matrices has rank 2.
𝑛
This grap is distance-regular with classical parameters (⌊ 𝑛2 ⌋, 𝑞 2 , 𝑞 2 − 1, 𝑞 2⌈ 2 ⌉−1 ).
INPUT:
• n – integer
• q – a prime power
EXAMPLES:
REFERENCES:
See [BCN1989] pp. 282-284 for a rather detailed discussion, otherwise see [VDKT2016] p. 22.
static AztecDiamondGraph(n)
Return the Aztec Diamond graph of order n.
See the Wikipedia article Aztec_diamond for more information.
EXAMPLES:
sage: graphs.AztecDiamondGraph(2)
Aztec Diamond graph of order 2
sage: G = graphs.AztecDiamondGraph(3)
sage: sum(1 for p in G.perfect_matchings())
64
static Balaban10Cage(embedding=1)
Return the Balaban 10-cage.
The Balaban 10-cage is a 3-regular graph with 70 vertices and 105 edges. See the Wikipedia article
Balaban_10-cage.
The default embedding gives a deeper understanding of the graph’s automorphism group. It is divided into
4 layers (each layer being a set of points at equal distance from the drawing’s center). From outside to
inside:
• L1: The outer layer (vertices which are the furthest from the origin) is actually the disjoint union of
two cycles of length 10.
• L2: The second layer is an independent set of 20 vertices.
• L3: The third layer is a matching on 10 vertices.
• L4: The inner layer (vertices which are the closest from the origin) is also the disjoint union of two
cycles of length 10.
This graph is not vertex-transitive, and its vertices are partitioned into 3 orbits: L2, L3, and the union of
L1 of L4 whose elements are equivalent.
INPUT:
• embedding – integer (default: 1); two embeddings are available, and can be selected by setting
embedding to be either 1 or 2
EXAMPLES:
sage: g = graphs.Balaban10Cage()
sage: g.girth()
10
sage: g.chromatic_number()
2
sage: g.diameter()
6
sage: g.is_hamiltonian()
(continues on next page)
static Balaban11Cage(embedding=1)
Return the Balaban 11-cage.
For more information, see the Wikipedia article Balaban_11-cage.
INPUT:
• embedding – integer (default: 1); three embeddings are available, and can be selected by setting
embedding to be 1, 2, or 3
– The first embedding is the one appearing on page 9 of the Fifth Annual Graph Drawing Contest
report [EMMN1998]. It separates vertices based on their eccentricity (see eccentricity()).
– The second embedding has been produced just for Sage and is meant to emphasize the automor-
phism group’s 6 orbits.
– The last embedding is the default one produced by the LCFGraph() constructor.
EXAMPLES:
Basic properties:
sage: g = graphs.Balaban11Cage()
sage: g.order()
112
sage: g.size()
168
sage: g.girth()
11
sage: g.diameter()
8
sage: g.automorphism_group().cardinality()
64
sage: g1 = graphs.Balaban11Cage(embedding=1)
sage: g2 = graphs.Balaban11Cage(embedding=2)
sage: g3 = graphs.Balaban11Cage(embedding=3)
sage: g1.show(figsize=[10,10]) # long time
sage: g2.show(figsize=[10,10]) # long time
sage: g3.show(figsize=[10,10]) # long time
static BalancedTree(r, h)
Returns the perfectly balanced tree of height ℎ ≥ 1, whose root has degree 𝑟 ≥ 2.
𝑟 ℎ+1 −1
The number of vertices of this graph is 1 + 𝑟 + 𝑟2 + · · · + 𝑟ℎ , that is, 𝑟−1 . The number of edges is one
less than the number of vertices.
INPUT:
• r – positive integer ≥ 2. The degree of the root node.
• h – positive integer ≥ 1. The height of the balanced tree.
OUTPUT:
The perfectly balanced tree of height ℎ ≥ 1 and whose root has degree 𝑟 ≥ 2. A NetworkXError is
returned if 𝑟 < 2 or ℎ < 1.
ALGORITHM:
Uses NetworkX.
EXAMPLES:
A balanced tree whose root node has degree 𝑟 = 2, and of height ℎ = 1, has order 3 and size 2:
sage: G = graphs.BalancedTree(3, 5)
sage: G.show() # long time
• n2 – nonnegative integer. The order of the path graph connecting the two complete graphs.
OUTPUT:
A barbell graph of order 2*n1 + n2. A ValueError is returned if n1 < 2 or n2 < 0.
PLOTTING:
Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention,
each barbell graph will be displayed with the two complete graphs in the lower-left and upper-right corners,
with the path graph connecting diagonally between the two. Thus the n1-th node will be drawn at a 45
degree angle from the horizontal right center of the first complete graph, and the n1 + n2 + 1-th node
will be drawn 45 degrees below the left horizontal center of the second complete graph.
EXAMPLES:
Construct and show a barbell graph Bar = 4, Bells = 9:
An n1 >= 2, n2 >= 0 barbell graph has order 2*n1 + n2. It has the complete graph on n1 vertices as a
subgraph. It also has the path graph on n2 vertices as a subgraph.
static BidiakisCube()
Return the Bidiakis cube.
For more information, see the Wikipedia article Bidiakis_cube.
EXAMPLES:
The Bidiakis cube is a 3-regular graph having 12 vertices and 18 edges. This means that each vertex has a
degree of 3:
sage: g = graphs.BidiakisCube(); g
Bidiakis cube: Graph on 12 vertices
sage: g.show() # long time
sage: g.order()
12
sage: g.size()
18
sage: g.is_regular(3)
True
sage: g.is_hamiltonian()
True
sage: g.diameter()
3
sage: g.girth()
4
It is a planar graph with characteristic polynomial (𝑥 − 3)(𝑥 − 2)(𝑥4 )(𝑥 + 1)(𝑥 + 2)(𝑥2 + 𝑥 − 4)2 and
chromatic number 3:
sage: g.is_planar()
True
sage: char_poly = g.characteristic_polynomial()
sage: x = char_poly.parent()('x')
sage: char_poly == (x - 3) * (x - 2) * (x^4) * (x + 1) * (x + 2) * (x^2 + x -␣
˓→4)^2
True
sage: g.chromatic_number()
3
static BiggsSmithGraph(embedding=1)
Return the Biggs-Smith graph.
For more information, see the Wikipedia article Biggs-Smith_graph.
INPUT:
• embedding – integer (default: 1); two embeddings are available, and can be selected by setting
embedding to be 1 or 2
EXAMPLES:
Basic properties:
sage: g = graphs.BiggsSmithGraph()
sage: g.order()
102
sage: g.size()
153
sage: g.girth()
9
sage: g.diameter()
7
sage: g.automorphism_group().cardinality() # long time
2448
sage: g.show(figsize=[10, 10]) # long time
static BilinearFormsGraph(d, e, q)
Return a bilinear forms graph with the given parameters.
This builds a graph whose vertices are all 𝑑 matrices over 𝐺𝐹 (𝑞). Two vertices are adjacent if the difference
of the two matrices has rank 1.
The graph is distance-regular with classical parameters (min(𝑑, 𝑒), 𝑞, 𝑞 − 1, 𝑞 max(𝑑,𝑒) − 1).
INPUT:
• d, e – integers; dimension of the matrices
• q – integer; a prime power
EXAMPLES:
sage: G = graphs.BilinearFormsGraph(3, 3, 2)
sage: G.is_distance_regular(True)
([49, 36, 16, None], [None, 1, 6, 28])
sage: G = graphs.BilinearFormsGraph(3,3,3) # not tested (20 s)
sage: G.order() # not tested (due to above)
19683
sage: G = graphs.BilinearFormsGraph(3, 4, 2) # long time
sage: G.is_distance_regular(True) # long time
([105, 84, 48, None], [None, 1, 6, 28])
REFERENCES:
See [BCN1989] pp. 280-282 for a rather detailed discussion, otherwise see [VDKT2016] p. 21.
static BishopGraph(dim_list, radius=None, relabel=False)
Return the 𝑑-dimensional Bishop Graph with prescribed dimensions.
The 2-dimensional Bishop Graph of parameters 𝑛 and 𝑚 is a graph with 𝑛𝑚 vertices in which each vertex
represents a square in an 𝑛 × 𝑚 chessboard, and each edge corresponds to a legal move by a bishop.
The 𝑑-dimensional Bishop Graph with 𝑑 >= 2 has for vertex set the cells of a 𝑑-dimensional grid with
prescribed dimensions, and each edge corresponds to a legal move by a bishop in any pairs of dimensions.
The Bishop Graph is not connected.
INPUT:
• dim_list – iterable (list, set, dict); provides the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1, of the
chessboard
• radius – integer (default: None); by setting the radius to a positive integer, one may decrease the
power of the bishop to at most radius steps.
• relabel – boolean (default: False); indicates whether the vertices must be relabeled as integers
EXAMPLES:
The (n,m)-Bishop Graph is not connected:
static BlanusaFirstSnarkGraph()
Return the first Blanusa Snark Graph.
The Blanusa graphs are two snarks on 18 vertices and 27 edges. For more information on them, see the
Wikipedia article Blanusa_snarks.
See also:
• BlanusaSecondSnarkGraph().
EXAMPLES:
sage: g = graphs.BlanusaFirstSnarkGraph()
sage: g.order()
18
sage: g.size()
27
sage: g.diameter()
4
sage: g.girth()
5
sage: g.automorphism_group().cardinality()
8
static BlanusaSecondSnarkGraph()
Return the second Blanusa Snark Graph.
The Blanusa graphs are two snarks on 18 vertices and 27 edges. For more information on them, see the
Wikipedia article Blanusa_snarks.
See also:
• BlanusaFirstSnarkGraph().
EXAMPLES:
sage: g = graphs.BlanusaSecondSnarkGraph()
sage: g.order()
18
sage: g.size()
27
sage: g.diameter()
4
sage: g.girth()
5
sage: g.automorphism_group().cardinality()
4
static BrinkmannGraph()
Return the Brinkmann graph.
For more information, see the Wikipedia article Brinkmann_graph.
EXAMPLES:
The Brinkmann graph is a 4-regular graph having 21 vertices and 42 edges. This means that each vertex
has degree 4:
sage: G = graphs.BrinkmannGraph(); G
Brinkmann graph: Graph on 21 vertices
sage: G.show() # long time
sage: G.order()
21
sage: G.size()
42
sage: G.is_regular(4)
True
sage: G.is_eulerian()
True
sage: G.radius()
3
sage: G.diameter()
3
sage: G.girth()
5
sage: G.is_hamiltonian()
True
sage: G.chromatic_number()
4
sage: ag = G.automorphism_group()
sage: ag.is_isomorphic(DihedralGroup(7))
True
static BrouwerHaemersGraph()
Return the Brouwer-Haemers Graph.
The Brouwer-Haemers is the only strongly regular graph of parameters (81, 20, 1, 6). It is build in Sage as
the Affine Orthogonal graph 𝑉 𝑂− (6, 3). For more information on this graph, see its corresponding page
on Andries Brouwer’s website.
EXAMPLES:
sage: g = graphs.BrouwerHaemersGraph()
sage: g
Brouwer-Haemers: Graph on 81 vertices
static BubbleSortGraph(n)
Returns the bubble sort graph 𝐵(𝑛).
The vertices of the bubble sort graph are the set of permutations on 𝑛 symbols. Two vertices are adjacent
if one can be obtained from the other by swapping the labels in the 𝑖-th and (𝑖 + 1)-th positions for 1 ≤
𝑖 ≤ 𝑛 − 1. In total, 𝐵(𝑛) has order 𝑛!. Swapping two labels as described previously corresponds to
multiplying on the right the permutation corresponding to the node by an elementary transposition in the
SymmetricGroup.
The bubble sort graph is the underlying graph of the permutahedron().
INPUT:
• n – positive integer. The number of symbols to permute.
OUTPUT:
The bubble sort graph 𝐵(𝑛) on 𝑛 symbols. If 𝑛 < 1, a ValueError is returned.
EXAMPLES:
sage: g = graphs.BubbleSortGraph(4); g
Bubble sort: Graph on 24 vertices
sage: g.plot() # long time
Graphics object consisting of 61 graphics primitives
sage: graphs.BubbleSortGraph(1)
Bubble sort: Graph on 1 vertex
sage: n = randint(1, 8)
sage: g = graphs.BubbleSortGraph(n)
sage: g.order() == factorial(n)
True
See also:
• permutahedron()
AUTHORS:
• Michael Yurko (2009-09-01)
static BuckyBall()
Return the Bucky Ball graph.
This graph is a 3-regular 60-vertex planar graph. Its vertices and edges correspond precisely to the carbon
atoms and bonds in buckminsterfullerene. When embedded on a sphere, its 12 pentagon and 20 hexagon
faces are arranged exactly as the sections of a soccer ball.
EXAMPLES:
The Bucky Ball is planar:
sage: g = graphs.BuckyBall()
sage: g.is_planar()
True
The Bucky Ball can also be created by extracting the 1-skeleton of the Bucky Ball polyhedron, but this is
much slower:
sage: g = polytopes.buckyball().vertex_graph()
sage: g.remove_loops()
sage: h = graphs.BuckyBall()
sage: g.is_isomorphic(h)
True
static BullGraph()
Return a bull graph with 5 nodes.
A bull graph is named for its shape. It’s a triangle with horns. See the Wikipedia article Bull_graph for
more information.
PLOTTING:
Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention,
the bull graph is drawn as a triangle with the first node (0) on the bottom. The second and third nodes (1
and 2) complete the triangle. Node 3 is the horn connected to 1 and node 4 is the horn connected to node
2.
EXAMPLES:
Construct and show a bull graph:
sage: g = graphs.BullGraph(); g
Bull graph: Graph on 5 vertices
sage: g.show() # long time
The bull graph has 5 vertices and 5 edges. Its radius is 2, its diameter 3, and its girth 3. The bull graph is
planar with chromatic number 3 and chromatic index also 3:
The bull graph has chromatic polynomial 𝑥(𝑥 − 2)(𝑥 − 1)3 and Tutte polynomial 𝑥4 + 𝑥3 + 𝑥2 𝑦. Its
characteristic polynomial is 𝑥(𝑥2 − 𝑥 − 3)(𝑥2 + 𝑥 − 1), which follows from the definition of characteristic
polynomials for graphs, i.e. det(𝑥𝐼 − 𝐴), where 𝑥 is a variable, 𝐴 the adjacency matrix of the graph, and
𝐼 the identity matrix of the same dimensions as 𝐴:
static ButterflyGraph()
Return the butterfly graph.
Let 𝐶3 be the cycle graph on 3 vertices. The butterfly or bowtie graph is obtained by joining two copies
of 𝐶3 at a common vertex, resulting in a graph that is isomorphic to the friendship graph 𝐹2 . See the
Wikipedia article Butterfly_graph for more information.
See also:
• GraphGenerators.FriendshipGraph()
EXAMPLES:
The butterfly graph is a planar graph on 5 vertices and having 6 edges:
sage: G = graphs.ButterflyGraph(); G
Butterfly graph: Graph on 5 vertices
sage: G.show() # long time
sage: G.is_planar()
True
sage: G.order()
5
sage: G.size()
6
sage: G.diameter()
2
sage: G.girth()
3
sage: G.radius()
1
sage: G.is_eulerian()
True
sage: G.chromatic_number()
3
sage: G = graphs.CycleGraph(4)
sage: CFI, p = graphs.CaiFurerImmermanGraph(G)
sage: sorted(CFI, key=str)
[(0, ()), (0, (0, 'a')), (0, (0, 'b')), (0, (0, 1)), (0, (1, 'a')),
(0, (1, 'b')), (1, ()), (1, (0, 'a')), (1, (0, 'b')), (1, (0, 1)),
(1, (1, 'a')), (1, (1, 'b')), (2, ()), (2, (0, 'a')), (2, (0, 'b')),
(2, (0, 1)), (2, (1, 'a')), (2, (1, 'b')), (3, ()), (3, (0, 'a')),
(3, (0, 'b')), (3, (0, 1)), (3, (1, 'a')), (3, (1, 'b'))]
sage: sorted(CFI.edge_iterator(), key=str)
[((0, ()), (0, (0, 'b')), None),
((0, ()), (0, (1, 'b')), None),
((0, (0, 'a')), (1, (0, 'a')), None),
((0, (0, 'b')), (1, (0, 'b')), None),
((0, (0, 1)), (0, (0, 'a')), None),
((0, (0, 1)), (0, (1, 'a')), None),
((0, (1, 'a')), (3, (0, 'a')), None),
((0, (1, 'b')), (3, (0, 'b')), None),
((1, ()), (1, (0, 'b')), None),
((1, ()), (1, (1, 'b')), None),
(continues on next page)
static CameronGraph()
Return the Cameron graph.
The Cameron graph is strongly regular with parameters 𝑣 = 231, 𝑘 = 30, 𝜆 = 9, 𝜇 = 3.
For more information on the Cameron graph, see https://www.win.tue.nl/~aeb/graphs/Cameron.html.
EXAMPLES:
sage: g = graphs.CameronGraph()
sage: g.order()
231
sage: g.size()
3465
sage: g.is_strongly_regular(parameters = True) # long time
(231, 30, 9, 3)
static Cell120()
Return the 120-Cell graph.
This is the adjacency graph of the 120-cell. It has 600 vertices and 1200 edges. For more information, see
the Wikipedia article 120-cell.
EXAMPLES:
static Cell600(embedding=1)
Return the 600-Cell graph.
This is the adjacency graph of the 600-cell. It has 120 vertices and 720 edges. For more information, see
the Wikipedia article 600-cell.
INPUT:
• embedding – integer (default: 1); two different embeddings for a plot
EXAMPLES:
sage: H = (graphs.CompleteGraph(3)).cartesian_product(graphs.CompleteGraph(4))
sage: G.is_isomorphic(H)
True
static ChvatalGraph()
Return the Chvatal graph.
Chvatal graph is one of the few known graphs to satisfy Grunbaum’s conjecture that for every 𝑚, 𝑛, there
is an 𝑚-regular, 𝑚-chromatic graph of girth at least 𝑛. For more information, see the Wikipedia article
Chv%C3%A1tal_graph.
EXAMPLES:
The Chvatal graph has 12 vertices and 24 edges. It is a 4-regular, 4-chromatic graph with radius 2, diameter
2, and girth 4:
sage: G = graphs.ChvatalGraph(); G
Chvatal graph: Graph on 12 vertices
sage: G.order(); G.size()
12
24
sage: G.degree()
[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]
sage: G.chromatic_number()
4
sage: G.radius(); G.diameter(); G.girth()
2
2
4
We next view many cycle graphs as a Sage graphics array. First we use the CirculantGraph constructor,
which fills in the position dictionary:
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.CirculantGraph(i+4, i+1)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
sage: g = []
sage: j = []
sage: for i in range(9):
....: spr = networkx.cycle_graph(i+3)
....: k = Graph(spr)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
sage: graphs.CirculantGraph(6,1)==graphs.CycleGraph(6)
True
sage: graphs.CirculantGraph(7,[1,3]).edges(sort=True, labels=false)
[(0, 1),
(0, 3),
(0, 4),
(0, 6),
(1, 2),
(1, 4),
(1, 5),
(2, 3),
(2, 5),
(continues on next page)
static CircularLadderGraph(n)
Return a circular ladder graph with 2 * 𝑛 nodes.
A Circular ladder graph is a ladder graph that is connected at the ends, i.e.: a ladder bent around so that
top meets bottom. Thus it can be described as two parallel cycle graphs connected at each corresponding
node pair.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, the circular ladder graph is displayed as an inner and outer cycle pair, with the first 𝑛 nodes
drawn on the inner circle. The first (0) node is drawn at the top of the inner-circle, moving clockwise after
that. The outer circle is drawn with the (𝑛 + 1), we rotate the outer circle by an angle of 𝜋/8 to ensure that
all edges are visible (otherwise the 4 vertices of the graph would be placed on a single line).
EXAMPLES:
Construct and show a circular ladder graph with 26 nodes:
sage: g = graphs.CircularLadderGraph(13)
sage: g.show() # long time
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.CircularLadderGraph(i+3)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
static ClawGraph()
Return a claw graph.
A claw graph is named for its shape. It is actually a complete bipartite graph with (n1, n2) = (1, 3).
PLOTTING: See CompleteBipartiteGraph().
EXAMPLES:
Show a Claw graph:
sage: G = graphs.ClawGraph()
sage: G
Claw graph: Graph on 4 vertices
static ClebschGraph()
Return the Clebsch graph.
See the Wikipedia article Clebsch_graph for more information.
EXAMPLES:
sage: g = graphs.ClebschGraph()
sage: g.automorphism_group().cardinality()
1920
sage: g.girth()
4
sage: g.chromatic_number()
4
sage: g.diameter()
2
sage: g.show(figsize=[10, 10]) # long time
Notice here how the spring-layout tends to center the nodes of 𝑛1:
View many complete bipartite graphs with a Sage Graphics Array, with this constructor (i.e., the position
dictionary filled):
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.CompleteBipartiteGraph(i+1,4)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
sage: g = []
sage: j = []
sage: for i in range(9):
....: spr = networkx.complete_bipartite_graph(i+1,4)
....: k = Graph(spr)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
sage: graphs.CompleteBipartiteGraph(5,6).complement()
complement(Complete bipartite graph of order 5+6): Graph on 11 vertices
static CompleteGraph(n)
Return a complete graph on 𝑛 nodes.
A Complete Graph is a graph in which all nodes are connected to all other nodes.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, each complete graph will be displayed with the first (0) node at the top, with the rest following
in a counterclockwise manner.
In the complete graph, there is a big difference visually in using the spring-layout algorithm vs. the position
dictionary used in this constructor. The position dictionary flattens the graph, making it clear which nodes
an edge is connected to. But the complete graph offers a good example of how the spring-layout works.
The edges push outward (everything is connected), causing the graph to appear as a 3-dimensional pointy
ball. (See examples below).
EXAMPLES:
We view many Complete graphs with a Sage Graphics Array, first with this constructor (i.e., the position
dictionary filled):
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.CompleteGraph(i+3)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
We compare plotting:
static CompleteMultipartiteGraph(L)
Return a complete multipartite graph.
INPUT:
• L – a list of integers; the respective sizes of the components
PLOTTING: Produce a layout of the vertices so that vertices in the same vertex set are adjacent and clearly
separated from vertices in other vertex sets.
This is done by calculating the vertices of an 𝑟-gon then calculating the slope between adjacent vertices.
We then ‘walk’ around the 𝑟-gon placing graph vertices in regular intervals between adjacent vertices of
the 𝑟-gon.
Makes a nicely organized graph like in this picture: https://commons.wikimedia.org/wiki/File:Turan_13-4.
svg
EXAMPLES:
A complete tripartite graph with sets of sizes 5, 6, 8:
sage: g.chromatic_number()
3
static ConwaySmith_for_3S7()
Return the Conway-Smith graph related to 3𝑆𝑦𝑚(7).
This is a distance-regular graph with intersection array [10, 6, 4, 1; 1, 2, 6, 10].
EXAMPLES:
sage: G = graphs.ConwaySmith_for_3S7()
sage: G.is_distance_regular(True)
([10, 6, 4, 1, None], [None, 1, 2, 6, 10])
REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 399.
static CossidentePenttilaGraph(q)
Return the Cossidente-Penttila ((𝑞 3 + 1)(𝑞 + 1)/2, (𝑞 2 + 1)(𝑞 − 1)/2, (𝑞 − 3)/2, (𝑞 − 1)2 /2)-strongly
regular graph
For each odd prime power 𝑞, one can partition the points of the 𝑂6− (𝑞)-generalized quadrangle 𝐺𝑄(𝑞, 𝑞 2 )
into two parts, so that on any of them the induced subgraph of the point graph of the GQ has parameters as
above [CP2005].
Directly following the construction in [CP2005] is not efficient, as one then needs to construct the dual
𝐺𝑄(𝑞 2 , 𝑞). Thus we describe here a more efficient approach that we came up with, following a suggestion
by T.Penttila. Namely, this partition is invariant under the subgroup 𝐻 = Ω3 (𝑞 2 ) < 𝑂6− (𝑞). We build
the appropriate 𝐻, which leaves the form 𝐵(𝑋, 𝑌, 𝑍) = 𝑋𝑌 + 𝑍 2 invariant, and pick up two orbits of
𝐻 on the 𝐹𝑞 -points. One them is 𝐵-isotropic, and we take the representative (1 : 0 : 0). The other one
corresponds to the points of 𝑃 𝐺(2, 𝑞 2 ) that have all the lines on them either missing the conic specified
by 𝐵, or intersecting the conic in two points. We take (1 : 1 : 𝑒) as the representative. It suffices to pick
𝑒 so that 𝑒2 + 1 is not a square in 𝐹𝑞2 . Indeed, The conic can be viewed as the union of {(0 : 1 : 0)}
and {(1 : −𝑡2 : 𝑡)|𝑡 ∈ 𝐹𝑞2 }. The coefficients of a generic line on (1 : 1 : 𝑒) are [1 : −1 − 𝑒𝑏 : 𝑏], for
−1 ̸= 𝑒𝑏. Thus, to make sure the intersection with the conic is always even, we need that the discriminant
of 1 + (1 + 𝑒𝑏)𝑡2 + 𝑡𝑏 = 0 never vanishes, and this is if and only if 𝑒2 + 1 is not a square. Further, we
need to adjust 𝐵, by multiplying it by appropriately chosen 𝜈, so that (1 : 1 : 𝑒) becomes isotropic under
the relative trace norm 𝜈𝐵(𝑋, 𝑌, 𝑍) + (𝜈𝐵(𝑋, 𝑌, 𝑍))𝑞 . The latter is used then to define the graph.
INPUT:
• q – an odd prime power.
EXAMPLES:
For 𝑞 = 3 one gets Sims-Gewirtz graph.
static CoxeterGraph()
Return the Coxeter graph.
See the Wikipedia article Coxeter_graph.
EXAMPLES:
sage: g = graphs.CoxeterGraph()
sage: g.automorphism_group().cardinality()
336
sage: g.girth()
7
sage: g.chromatic_number()
3
sage: g.diameter()
4
sage: g.show(figsize=[10, 10]) # long time
static CubeConnectedCycle(d)
Return the cube-connected cycle of dimension 𝑑.
The cube-connected cycle of order 𝑑 is the 𝑑-dimensional hypercube with each of its vertices replaced by
a cycle of length 𝑑. This graph has order 𝑑 × 2𝑑 . The construction is as follows: Construct vertex (𝑥, 𝑦)
for 0 ≤ 𝑥 < 2𝑑 , 0 ≤ 𝑦 < 𝑑. For each vertex, (𝑥, 𝑦), add an edge between it and (𝑥, (𝑦 − 1) mod 𝑑)),
(𝑥, (𝑦 + 1) mod 𝑑), and (𝑥 ⊕ 2𝑦 , 𝑦), where ⊕ is the bitwise xor operator.
For 𝑑 = 1 and 2, the cube-connected cycle graph contains self-loops or multiple edges between a pair of
vertices, but for all other 𝑑, it is simple.
INPUT:
• d – The dimension of the desired hypercube as well as the length of the cycle to be placed at each
vertex of the 𝑑-dimensional hypercube. 𝑑 must be a positive integer.
EXAMPLES:
The order of the graph is 𝑑 × 2𝑑
sage: d = 3
sage: g = graphs.CubeConnectedCycle(d)
sage: len(g) == d*2**d
True
sage: d = 4
sage: g = graphs.CubeConnectedCycle(d)
sage: g.diameter() == 2*d+d//2-2
True
sage: g = graphs.CubeConnectedCycle(5)
sage: all(g.degree(v) == 3 for v in g)
True
EXAMPLES:
The distance between 0100110 and 1011010 is 5, as expected:
sage: g = graphs.CubeGraph(7)
sage: g.distance('0100110','1011010')
5
sage: g = []
sage: j = []
sage: for i in range(6):
....: k = graphs.CubeGraph(i+1)
....: g.append(k)
...
sage: for i in range(2):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
...
sage: G = graphics_array(j)
sage: G.show(figsize=[6,4]) # long time
AUTHORS:
• Robert Miller
• David Coudert
static CycleGraph(n)
Return a cycle graph with 𝑛 nodes.
A cycle graph is a basic structure which is also typically called an 𝑛-gon.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, each cycle graph will be displayed with the first (0) node at the top, with the rest following
in a counterclockwise manner.
The cycle graph is a good opportunity to compare efficiency of filling a position dictionary vs. using the
spring-layout algorithm for plotting. Because the cycle graph is very symmetric, the resulting plots should
be similar (in cases of small 𝑛).
Filling the position dictionary in advance adds 𝑂(𝑛) to the constructor.
EXAMPLES:
Compare plotting using the predefined layout and networkx:
We next view many cycle graphs as a Sage graphics array. First we use the CycleGraph constructor, which
fills in the position dictionary:
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.CycleGraph(i+3)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
sage: g = []
sage: j = []
sage: for i in range(9):
....: spr = networkx.cycle_graph(i+3)
....: k = Graph(spr)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
static DartGraph()
Return a dart graph with 5 nodes.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, the dart graph is drawn as a dart, with the sharp part on the bottom.
EXAMPLES:
Construct and show a dart graph:
sage: g = graphs.DartGraph()
sage: g.show() # long time
static DegreeSequence(deg_sequence)
Return a graph with the given degree sequence.
This method raises a NetworkX error if the proposed degree sequence cannot be that of a graph.
Graph returned is the one returned by the Havel-Hakimi algorithm, which constructs a simple graph by
connecting vertices of highest degree to other vertices of highest degree, resorting the remaining vertices
by degree and repeating the process. See Theorem 1.4 in [CL1996].
INPUT:
• deg_sequence – list of integers with each entry corresponding to the degree of a different vertex
EXAMPLES:
sage: G = graphs.DegreeSequence([3,3,3,3])
sage: G.edges(sort=True, labels=False)
[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
sage: G.show() # long time
sage: G = graphs.DegreeSequence([3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3])
sage: G.show() # long time
sage: G = graphs.DegreeSequence([4,4,4,4,4,4,4,4])
sage: G.show() # long time
sage: G = graphs.DegreeSequence([1,2,3,4,3,4,3,2,3,2,1])
sage: G.show() # long time
sage: g = graphs.DegreeSequenceBipartite([2,2,2,2,2],[5,5])
sage: g.is_isomorphic(graphs.CompleteBipartiteGraph(5,2))
True
Some sequences being incompatible if, for example, their sums are different, the functions raises a
ValueError when no graph corresponding to the degree sequences exists:
sage: g = graphs.DegreeSequenceBipartite([2,2,2,2,1],[5,5])
Traceback (most recent call last):
...
ValueError: there exists no bipartite graph corresponding to the given degree␣
˓→sequences
sage: G = graphs.DegreeSequenceConfigurationModel([1,1])
sage: G.adjacency_matrix()
[0 1]
[1 0]
REFERENCE:
[New2003]
static DegreeSequenceExpected(deg_sequence, seed=None)
Return a random graph with expected given degree sequence.
This method raises a NetworkX error if the proposed degree sequence cannot be that of a graph.
One requirement is that the sum of the degrees must be even, since every edge must be incident with two
vertices.
INPUT:
• deg_sequence – list of integers with each entry corresponding to the expected degree of a different
vertex
• seed – (optional) a random.Random seed or a Python int for the random number generator
EXAMPLES:
sage: G = graphs.DegreeSequenceExpected([1,2,3,2,3])
sage: G
Looped graph on 5 vertices
sage: G.show() # long time
REFERENCE:
[CL2002]
static DegreeSequenceTree(deg_sequence)
Return a tree with the given degree sequence.
This method raises a NetworkX error if the proposed degree sequence cannot be that of a tree.
Since every tree has one more vertex than edge, the degree sequence must satisfy len(deg_sequence) -
sum(deg_sequence)/2 == 1.
INPUT:
• deg_sequence – list of integers with each entry corresponding to the expected degree of a different
vertex
EXAMPLES:
sage: G = graphs.DegreeSequenceTree([3,1,3,3,1,1,1,2,1])
sage: G
Graph on 9 vertices
sage: G.show() # long time
static DejterGraph()
Return the Dejter graph.
The Dejter graph is obtained from the binary 7-cube by deleting a copy of the Hamming code of length 7. It
is 6-regular, with 112 vertices and 336 edges. For more information, see the Wikipedia article Dejter_graph.
EXAMPLES:
sage: g = graphs.DejterGraph(); g
Dejter Graph: Graph on 112 vertices
sage: g.is_regular(k=6)
True
sage: g.girth()
4
static DesarguesGraph()
Return the Desargues graph.
PLOTTING: The layout chosen is the same as on the cover of [Har1994].
EXAMPLES:
sage: D = graphs.DesarguesGraph()
sage: L = graphs.LCFGraph(20,[5,-5,9,-9],5)
sage: D.is_isomorphic(L)
True
sage: D.show() # long time
static DiamondGraph()
Return a diamond graph with 4 nodes.
A diamond graph is a square with one pair of diagonal nodes connected.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, the diamond graph is drawn as a diamond, with the first node on top, second on the left,
third on the right, and fourth on the bottom; with the second and third node connected.
EXAMPLES:
Construct and show a diamond graph:
sage: g = graphs.DiamondGraph()
sage: g.show() # long time
static DipoleGraph(n)
Returns a dipole graph with n edges.
A dipole graph is a multigraph consisting of 2 vertices connected with n parallel edges.
EXAMPLES:
Construct and show a dipole graph with 13 edges:
sage: g = graphs.DipoleGraph(13); g
Dipole graph: Multi-graph on 2 vertices
sage: g.show() # long time
static DodecahedralGraph()
Return a Dodecahedral graph (with 20 nodes)
The dodecahedral graph is cubic symmetric, so the spring-layout algorithm will be very effective for display.
It is dual to the icosahedral graph.
PLOTTING: The Dodecahedral graph should be viewed in 3 dimensions. We choose to use a planar em-
bedding of the graph. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a
argument will be added to select the desired layout.
EXAMPLES:
Construct and show a Dodecahedral graph:
sage: g = graphs.DodecahedralGraph()
sage: g.show() # long time
Create several dodecahedral graphs in a Sage graphics array They will be drawn differently due to the use
of the spring-layout algorithm:
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.DodecahedralGraph()
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
static DorogovtsevGoltsevMendesGraph(n)
Construct the n-th generation of the Dorogovtsev-Goltsev-Mendes graph.
EXAMPLES:
sage: G = graphs.DorogovtsevGoltsevMendesGraph(8)
sage: G.size()
6561
REFERENCE:
• [1] Dorogovtsev, S. N., Goltsev, A. V., and Mendes, J. F. F., Pseudofractal scale-free web, Phys. Rev.
E 066122 (2002).
static DoubleGeneralizedPetersenGraph(n, k)
Return a double generalized Petersen graph with 4𝑛 nodes.
The double generalized Petersen graphs is a family of graphs proposed in [ZF2012] as a variant of gener-
alized Petersen graphs. The variables 𝑛, 𝑘 are integers such that 𝑛 > 2 and 0 < 𝑘 ≤ ⌊(𝑛 − 1)/2⌋.
INPUT:
• n – the number of nodes is 4 * 𝑛
• k – integer such that 0 < 𝑘 ≤ ⌊(𝑛 − 1)/2⌋ determining how vertices on second and third inner rims
are connected
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the double generalized Petersen graphs are displayed as 4 cocentric cycles, with the first n nodes
drawn on the outer circle. The first (0) node is drawn at the top of the outer-circle, moving counterclockwise
after that. The second circle is drawn with the (n)th node at the top, then counterclockwise as well. The
tird cycle is drawn with the (2n)th node at the top, then counterclockwise. And the fourth cycle is drawn
with the (3n)th node at the top, then again counterclockwise.
EXAMPLES:
When 𝑛 is even the resulting graph will be isomorphic to a double generalized Petersen graph with 𝑘 ′ =
𝑛/2 − 𝑘:
sage: g = graphs.DoubleGeneralizedPetersenGraph(10, 2)
sage: g2 = graphs.DoubleGeneralizedPetersenGraph(10, 3)
sage: g.is_isomorphic(g2)
True
static DoubleGrassmannGraph(q, e)
Return the bipartite double of the distance-𝑒 graph of the Grassmann graph 𝐽𝑞 (𝑛, 𝑒).
This graph can also be descirbed as follows: Let 𝑉 be the vector space of dimension 𝑛 over 𝐺𝐹 (𝑞). The
vertex set is the set of 𝑒 + 1 or 𝑒 subspaces of 𝑉 . Two vertices are adjacent if one subspace is contained in
the other.
This graph is distance-transitive.
INPUT:
• q – a prime power
• e – integer
EXAMPLES:
sage: G = graphs.DoubleGrassmannGraph(2,1)
sage: G.diameter()
3
sage: G.is_distance_regular(True)
([3, 2, 2, None], [None, 1, 1, 3])
REFERENCES:
See [BCN1989] pp. 272, 273 or [VDKT2016] p. 25.
static DoubleOddGraph(n)
Return the double odd graph on 2𝑛 + 1 points.
The graph is obtained using the subsets of size 𝑛 and 𝑛 + 1 of 1, 2, ..., 2𝑛 + 1 as vertices. Two vertices are
adjacent if one is included in the other.
The graph is distance-transitive.
INPUT:
• n – integer; must be greater than 0
EXAMPLES:
sage: G = graphs.DoubleOddGraph(5)
sage: G.is_distance_regular(True)
([6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, None],
[None, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6])
sage: G = graphs.DoubleOddGraph(3)
sage: G.diameter()
7
sage: G.is_distance_regular(True)
([4, 3, 3, 2, 2, 1, 1, None], [None, 1, 1, 2, 2, 3, 3, 4])
REFERENCES:
See [BCN1989] pp. 259-261 or [VDKT2016] p. 25.
static DoubleStarSnark()
Return the double star snark.
The double star snark is a 3-regular graph on 30 vertices. See the Wikipedia article Double-star_snark.
EXAMPLES:
sage: g = graphs.DoubleStarSnark()
sage: g.order()
30
sage: g.size()
45
sage: g.chromatic_number()
3
sage: g.is_hamiltonian()
False
sage: g.automorphism_group().cardinality()
80
sage: g.show()
static DoublyTruncatedWittGraph()
Return the doubly truncated Witt graph.
This builds the truncated Witt graph, then removes all vertices whose codeword start with a 1.
The graph is distance-regular with intersection array [7, 6, 4, 4; 1, 1, 1, 6].
EXAMPLES:
sage: G = graphs.DoublyTruncatedWittGraph()
sage: G.is_distance_regular(True)
([7, 6, 4, 4, None], [None, 1, 1, 1, 6])
REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 368.
static DurerGraph()
Return the Dürer graph.
For more information, see the Wikipedia article D%C3%BCrer_graph.
EXAMPLES:
The Dürer graph is named after Albrecht Dürer. It is a planar graph with 12 vertices and 18 edges:
sage: G = graphs.DurerGraph(); G
Durer graph: Graph on 12 vertices
sage: G.is_planar()
True
sage: G.order()
12
sage: G.size()
18
sage: G.chromatic_number()
3
sage: G.diameter()
4
sage: G.girth()
3
sage: ag = G.automorphism_group()
sage: ag.is_isomorphic(DihedralGroup(6))
True
static DyckGraph()
Return the Dyck graph.
For more information, see the MathWorld article on the Dyck graph or the Wikipedia article Dyck_graph.
EXAMPLES:
The Dyck graph was defined by Walther von Dyck in 1881. It has 32 vertices and 48 edges, and is a cubic
graph (regular of degree 3):
sage: G = graphs.DyckGraph(); G
Dyck graph: Graph on 32 vertices
sage: G.order()
32
sage: G.size()
48
sage: G.is_regular()
True
sage: G.is_regular(3)
True
sage: G.is_planar()
False
sage: G.is_hamiltonian()
True
sage: G.is_bipartite()
True
sage: G.radius()
5
sage: G.diameter()
5
sage: G.girth()
6
sage: G.chromatic_number()
2
sage: G.automorphism_group().cardinality()
192
sage: G.characteristic_polynomial().factor()
(x - 3) * (x + 3) * (x - 1)^9 * (x + 1)^9 * (x^2 - 5)^6
It is a toroidal graph, and its embedding on a torus is dual to an embedding of the Shrikhande graph
(ShrikhandeGraph ).
static EgawaGraph(p, s)
Return the Egawa graph with parameters 𝑝, 𝑠.
Egawa graphs are a peculiar family of graphs devised by Yoshimi Egawa in [Ega1981] . The Shrikhande
graph is a special case of this family of graphs, with parameters (1, 0). All the graphs in this family are not
recognizable by 1-WL (Weisfeiler Lehamn algorithm of the first order) and 2-WL, that is their orbits are
not correctly returned by k-WL for k lower than 3.
Furthermore, all the graphs in this family are distance-regular, but they are not distance-transitive if 𝑝 ̸= 0.
The Egawa graph with parameters (0, 𝑠) is isomorphic to the Hamming graph with parameters (𝑠, 4), when
the underlying set of the Hamming graph is [0, 1, 2, 3]
INPUT:
• p – power to which the graph named 𝑌 in the reference provided above will be raised
• s – power to which the graph named 𝑋 in the reference provided above will be raised
OUTPUT:
• G – The Egawa graph with parameters (p,s)
EXAMPLES:
Every Egawa graph is distance regular.
sage: g = graphs.EgawaGraph(1, 2)
sage: g.is_distance_regular()
True
An Egawa graph with parameters (0,s) is isomorphic to the Hamming graph with parameters (s, 4).
sage: g = graphs.EgawaGraph(0, 4)
sage: g.is_isomorphic(graphs.HammingGraph(4,4))
True
static EllinghamHorton54Graph()
Return the Ellingham-Horton 54-graph.
For more information, see the Wikipedia article Ellingham-Horton_graph.
EXAMPLES:
This graph is 3-regular:
sage: g = graphs.EllinghamHorton54Graph()
sage: g.is_regular(k=3)
True
It is not Hamiltonian:
static EllinghamHorton78Graph()
Return the Ellingham-Horton 78-graph.
For more information, see the Wikipedia article Ellingham%E2%80%93Horton_graph
EXAMPLES:
This graph is 3-regular:
sage: g = graphs.EllinghamHorton78Graph()
sage: g.is_regular(k=3)
True
It is not Hamiltonian:
static EmptyGraph()
Return an empty graph (0 nodes and 0 edges).
This is useful for constructing graphs by adding edges and vertices individually or in a loop.
PLOTTING: When plotting, this graph will use the default spring-layout algorithm, unless a position dic-
tionary is specified.
EXAMPLES:
Add one vertex to an empty graph and then show:
static ErreraGraph()
Return the Errera graph.
For more information, see the Wikipedia article Errera_graph.
EXAMPLES:
The Errera graph is named after Alfred Errera. It is a planar graph on 17 vertices and having 45 edges:
sage: G = graphs.ErreraGraph(); G
Errera graph: Graph on 17 vertices
sage: G.is_planar()
True
sage: G.order()
17
(continues on next page)
The Errera graph is Hamiltonian with radius 3, diameter 4, girth 3, and chromatic number 4:
sage: G.is_hamiltonian()
True
sage: G.radius()
3
sage: G.diameter()
4
sage: G.girth()
3
sage: G.chromatic_number()
4
Each vertex degree is either 5 or 6. That is, if 𝑓 counts the number of vertices of degree 5 and 𝑠 counts the
number of vertices of degree 6, then 𝑓 + 𝑠 is equal to the order of the Errera graph:
sage: D = G.degree_sequence()
sage: D.count(5) + D.count(6) == G.order()
True
The automorphism group of the Errera graph is isomorphic to the dihedral group of order 20:
sage: ag = G.automorphism_group()
sage: ag.is_isomorphic(DihedralGroup(10))
True
static F26AGraph()
Return the F26A graph.
The F26A graph is a symmetric bipartite cubic graph with 26 vertices and 39 edges. For more information,
see the Wikipedia article F26A_graph.
EXAMPLES:
sage: g = graphs.F26AGraph(); g
F26A Graph: Graph on 26 vertices
sage: g.order(),g.size()
(26, 39)
sage: g.automorphism_group().cardinality()
78
sage: g.girth()
6
sage: g.is_bipartite()
True
sage: g.characteristic_polynomial().factor()
(x - 3) * (x + 3) * (x^4 - 5*x^2 + 3)^6
static FibonacciTree(n)
Return the graph of the Fibonacci Tree 𝐹𝑖 of order 𝑛.
The Fibonacci tree 𝐹𝑖 is recursively defined as the tree with a root vertex and two attached child trees 𝐹𝑖−1
and 𝐹𝑖−2 , where 𝐹1 is just one vertex and 𝐹0 is empty.
INPUT:
• n - the recursion depth of the Fibonacci Tree
EXAMPLES:
sage: g = graphs.FibonacciTree(3)
sage: g.is_tree()
True
AUTHORS:
• Harald Schilly and Yann Laigle-Chapuy (2010-03-25)
static FlowerSnark()
Return a Flower Snark.
A flower snark has 20 vertices. It is part of the class of biconnected cubic graphs with edge chromatic
number = 4, known as snarks. (i.e.: the Petersen graph). All snarks are not Hamiltonian, non-planar and
have Petersen graph graph minors. See the Wikipedia article Flower_snark.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, the nodes are drawn 0-14 on the outer circle, and 15-19 in an inner pentagon.
EXAMPLES: Inspect a flower snark:
sage: F = graphs.FlowerSnark()
sage: F
Flower Snark: Graph on 20 vertices
sage: F.graph6_string()
'ShCGHC@?GGg@?@?Gp?K??C?CA?G?_G?Cc'
static FoldedCubeGraph(n)
Returns the folded cube graph of order 2𝑛−1 .
The folded cube graph on 2𝑛−1 vertices can be obtained from a cube graph on 2𝑛 vertices by merging
together opposed vertices. Alternatively, it can be obtained from a cube graph on 2𝑛−1 vertices by adding
an edge between opposed vertices. This second construction is the one produced by this method.
See the Wikipedia article Folded_cube_graph for more information.
EXAMPLES:
The folded cube graph of order five is the Clebsch graph:
sage: fc = graphs.FoldedCubeGraph(5)
sage: clebsch = graphs.ClebschGraph()
sage: fc.is_isomorphic(clebsch)
True
static FolkmanGraph()
Return the Folkman graph.
See the Wikipedia article Folkman_graph.
EXAMPLES:
sage: g = graphs.FolkmanGraph()
sage: g.order()
20
sage: g.size()
40
sage: g.diameter()
4
sage: g.girth()
4
sage: g.charpoly().factor()
(x - 4) * (x + 4) * x^10 * (x^2 - 6)^4
sage: g.chromatic_number()
2
sage: g.is_eulerian()
True
sage: g.is_hamiltonian()
True
sage: g.is_vertex_transitive()
False
sage: g.is_bipartite()
True
static ForkGraph()
Return a fork graph with 5 nodes.
A fork graph, sometimes also called chair graph, is 5 vertex tree.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, the fork graph is drawn as a fork, with the sharp part on the bottom.
EXAMPLES:
Construct and show a fork graph:
sage: g = graphs.ForkGraph()
sage: g.show() # long time
static FosterGraph()
Return the Foster graph.
See the Wikipedia article Foster_graph.
EXAMPLES:
sage: g = graphs.FosterGraph()
sage: g.order()
90
sage: g.size()
135
sage: g.diameter()
8
sage: g.girth()
10
sage: g.automorphism_group().cardinality()
4320
sage: g.is_hamiltonian()
True
static FosterGraph3S6()
Return the Foster graph for 3.𝑆𝑦𝑚(6).
This graph is distance-regular with intersection array [6, 4, 2, 1; 1, 1, 4, 6].
The graph is also distance transitive.
EXAMPLES:
sage: G = graphs.FosterGraph3S6()
sage: G.is_distance_regular(True)
([6, 4, 2, 1, None], [None, 1, 1, 4, 6])
REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 397.
static FranklinGraph()
Return the Franklin graph.
For more information, see the Wikipedia article Franklin_graph.
EXAMPLES:
The Franklin graph is named after Philip Franklin. It is a 3-regular graph on 12 vertices and having 18
edges:
sage: G = graphs.FranklinGraph(); G
Franklin graph: Graph on 12 vertices
sage: G.is_regular(3)
True
sage: G.order()
12
sage: G.size()
18
The Franklin graph is a Hamiltonian, bipartite graph with radius 3, diameter 3, and girth 4:
sage: G.is_hamiltonian()
True
sage: G.is_bipartite()
True
sage: G.radius()
3
sage: G.diameter()
3
sage: G.girth()
4
static FriendshipGraph(n)
Return the friendship graph 𝐹𝑛 .
The friendship graph is also known as the Dutch windmill graph. Let 𝐶3 be the cycle graph on 3 vertices.
Then 𝐹𝑛 is constructed by joining 𝑛 ≥ 1 copies of 𝐶3 at a common vertex. If 𝑛 = 1, then 𝐹1 is isomorphic
to 𝐶3 (the triangle graph). If 𝑛 = 2, then 𝐹2 is the butterfly graph, otherwise known as the bowtie graph.
For more information, see the Wikipedia article Friendship_graph.
INPUT:
• n – positive integer; the number of copies of 𝐶3 to use in constructing 𝐹𝑛 .
OUTPUT:
• The friendship graph 𝐹𝑛 obtained from 𝑛 copies of the cycle graph 𝐶3 .
See also:
• GraphGenerators.ButterflyGraph()
EXAMPLES:
The first few friendship graphs.
sage: A = []; B = []
sage: for i in range(9):
(continues on next page)
For 𝑛 = 1, the friendship graph 𝐹1 is isomorphic to the cycle graph 𝐶3 , whose visual representation is a
triangle.
sage: G = graphs.FriendshipGraph(1); G
Friendship graph: Graph on 3 vertices
sage: G.show() # long time
sage: G.is_isomorphic(graphs.CycleGraph(3))
True
For 𝑛 = 2, the friendship graph 𝐹2 is isomorphic to the butterfly graph, otherwise known as the bowtie
graph.
sage: G = graphs.FriendshipGraph(2); G
Friendship graph: Graph on 5 vertices
sage: G.is_isomorphic(graphs.ButterflyGraph())
True
If 𝑛 ≥ 2, then the friendship graph 𝐹𝑛 has 2𝑛 + 1 vertices and 3𝑛 edges. It has radius 1, diameter 2, girth
3, and chromatic number 3. Furthermore, 𝐹𝑛 is planar and Eulerian.
static FruchtGraph()
Return a Frucht Graph.
A Frucht graph has 12 nodes and 18 edges. It is the smallest cubic identity graph. It is planar and Hamil-
tonian. See the Wikipedia article Frucht_graph.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, the first seven nodes are on the outer circle, with the next four on an inner circle and the last
in the center.
EXAMPLES:
sage: G, p = graphs.FurerGadget(3)
sage: sorted(G, key=str)
[(), (0, 'a'), (0, 'b'), (0, 1), (0, 2),
(1, 'a'), (1, 'b'), (1, 2), (2, 'a'), (2, 'b')]
sage: sorted(G.edge_iterator(), key=str)
[((), (0, 'b'), None), ((), (1, 'b'), None),
((), (2, 'b'), None), ((0, 'b'), (1, 2), None),
((0, 1), (0, 'a'), None), ((0, 1), (1, 'a'), None),
((0, 1), (2, 'b'), None), ((0, 2), (0, 'a'), None),
((0, 2), (1, 'b'), None), ((0, 2), (2, 'a'), None),
((1, 2), (1, 'a'), None), ((1, 2), (2, 'a'), None)]
static FuzzyBallGraph(partition, q)
Construct a Fuzzy Ball graph with the integer partition partition and q extra vertices.
Let 𝑞 be an integer and let 𝑚1 , 𝑚2 , ..., 𝑚𝑘 be a set of positive integers. Let 𝑛 = 𝑞 + 𝑚1 + ... + 𝑚𝑘 . The
Fuzzy Ball graph with partition 𝑚1 , 𝑚2 , ..., 𝑚𝑘 and 𝑞 extra vertices is the graph constructed from the graph
𝐺 = 𝐾𝑛 by attaching, for each 𝑖 = 1, 2, ..., 𝑘, a new vertex 𝑎𝑖 to 𝑚𝑖 distinct vertices of 𝐺.
For given positive integers 𝑘 and 𝑚 and nonnegative integer 𝑞, the set of graphs FuzzyBallGraph(p, q)
for all partitions 𝑝 of 𝑚 with 𝑘 parts are cospectral with respect to the normalized Laplacian.
EXAMPLES:
sage: F = graphs.FuzzyBallGraph([3,1],2)
sage: F.adjacency_matrix(vertices=list(F))
[0 0 1 1 1 0 0 0]
[0 0 0 0 0 1 0 0]
[1 0 0 1 1 1 1 1]
[1 0 1 0 1 1 1 1]
[1 0 1 1 0 1 1 1]
[0 1 1 1 1 0 1 1]
[0 0 1 1 1 1 0 1]
[0 0 1 1 1 1 1 0]
Pick positive integers 𝑚 and 𝑘 and a nonnegative integer 𝑞. All the FuzzyBallGraphs constructed from
partitions of 𝑚 with 𝑘 parts should be cospectral with respect to the normalized Laplacian:
static GemGraph()
Return a gem graph with 5 nodes.
A gem graph is a fan graph (4,1).
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, the gem graph is drawn as a gem, with the sharp part on the bottom.
EXAMPLES:
Construct and show a gem graph:
sage: g = graphs.GemGraph()
sage: g.show() # long time
static GeneralisedDodecagonGraph(s, t)
Return the point-graph of a generalised dodecagon of order (𝑠, 𝑡).
INPUT:
• s, t – integers; order of the generalised dodecagon
EXAMPLES:
Note: This function indirectly uses the GAP’s AtlasRep package. Thus you may need an internet connec-
tion and the optional Sage’s package gap_packages.
REFERENCES:
See [BCN1989] pp. 200-205 for a discussion of distance-regular graphs from generalised polygons.
static GeneralisedHexagonGraph(s, t)
Return the point-graph of a generalised hexagon of order (𝑠, 𝑡).
INPUT:
• s, t – integers; order of the generalised hexagon
EXAMPLES:
Note: This function uses the GAP’s AtlasRep package to build GHs of order (𝑞, 𝑞), (𝑞, 𝑞 3 ) or (𝑞 3 , 𝑞). For
those graphs you need an internet connection and Sage’s optional package gap_packages.
REFERENCES:
See [BCN1989] pp. 200-205 for a discussion of distance-regular graphs from generalised polygons.
static GeneralisedOctagonGraph(s, t)
Return the point-graph of a generalised octagon of order (𝑠, 𝑡).
INPUT:
• s, t – integers; order of the generalised octagon
EXAMPLES:
sage: G = graphs.GeneralisedOctagonGraph(1, 4)
sage: G.is_distance_regular(True)
([5, 4, 4, 4, None], [None, 1, 1, 1, 5])
sage: G = graphs.GeneralisedOctagonGraph(2, 4) # optional - gap_packages␣
˓→internet
Note: This function uses the GAP’s AtlasRep package to build the graphs of order (2, 4) or (4, 2). For
those graphs you need an internet connection and Sage’s optional package gap_packages.
REFERENCES:
See [BCN1989] pp. 200-205 for a discussion of distance-regular graphs from generalised polygons.
static GeneralizedPetersenGraph(n, k)
Returns a generalized Petersen graph with 2𝑛 nodes. The variables 𝑛, 𝑘 are integers such that 𝑛 > 2 and
0 < 𝑘 ≤ ⌊(𝑛 − 1)/2⌋
For 𝑘 = 1 the result is a graph isomorphic to the circular ladder graph with the same 𝑛. The regular Petersen
Graph has 𝑛 = 5 and 𝑘 = 2. Other named graphs that can be described using this notation include the
Desargues graph and the Möbius-Kantor graph.
INPUT:
• n - the number of nodes is 2 * 𝑛.
• k - integer 0 < 𝑘 ≤ ⌊(𝑛 − 1)/2⌋. Decides how inner vertices are connected.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, the generalized Petersen graphs are displayed as an inner and outer cycle pair, with the
first n nodes drawn on the outer circle. The first (0) node is drawn at the top of the outer-circle, moving
counterclockwise after that. The inner circle is drawn with the (n)th node at the top, then counterclockwise
as well.
EXAMPLES: For 𝑘 = 1 the resulting graph will be isomorphic to a circular ladder graph.
sage: g = graphs.GeneralizedPetersenGraph(13,1)
sage: g2 = graphs.CircularLadderGraph(13)
sage: g.is_isomorphic(g2)
True
sage: g = graphs.GeneralizedPetersenGraph(10,3)
sage: g.girth()
6
sage: g.is_bipartite()
True
AUTHORS:
• Anders Jonsson (2009-10-15)
static GeneralizedSierpinskiGraph(G, k, stretch=None)
Return the generalized Sierpinski graph of 𝐺 of dimension 𝑘.
Generalized Sierpinski graphs have been introduced in [GKP2011] to generalize the notion of Sierpinski
graphs [KM1997].
Given a graph 𝐺 = (𝑉, 𝐸) of order 𝑛 and a parameter 𝑘, the generalized Sierpinski graph of 𝐺 of dimension
𝑘, denoted by 𝑆(𝐺, 𝑘), can be constructed recursively from 𝐺 as follows. 𝑆(𝐺, 1) is isomorphic to 𝐺. To
construct 𝑆(𝐺, 𝑘) for 𝑘 > 1, copy 𝑛 times 𝑆(𝐺, 𝑘 − 1), once per vertex 𝑢 ∈ 𝑉 , and add 𝑢 at the beginning
of the labels of each vertex in the copy of 𝑆(𝐺, 𝑘 − 1) corresponding to vertex 𝑢. Then for any edge
{𝑢, 𝑣} ∈ 𝐸, add an edge between vertex (𝑢, 𝑣, . . . , 𝑣) and vertex (𝑣, 𝑢, . . . , 𝑢).
INPUT:
• G – a sage Graph
• k – integer; the dimension
• stretch – integer (default: None); stretching factor used to determine the positions of the vertices
of the output graph. By default (None), this value is set to twice the maximum Euclidian distance
between the vertices of 𝐺. This parameter is used only when the vertices of 𝐺 have positions.
See also:
• SierpinskiGasketGraph()
• HanoiTowerGraph()
EXAMPLES:
The generalized Sierpinski graph of dimension 1 of any graph 𝐺 is isomorphic to 𝐺:
When 𝐺 is a clique of order 3, the generalized Sierpinski graphs of 𝐺 are isomorphic to Hanoi Tower
graphs:
sage: k = randint(1, 5)
sage: S = graphs.GeneralizedSierpinskiGraph(graphs.CompleteGraph(3), k)
sage: H = graphs.HanoiTowerGraph(3, k)
sage: S.is_isomorphic(H)
True
The generalized Sierpinski graph of dimension 𝑘 of any graph 𝐺 with 𝑛 vertices and 𝑚 edges has 𝑛𝑘
∑︀𝑘−1
vertices and 𝑚 𝑖=0 𝑛𝑖 edges:
sage: n = randint(2, 6)
sage: k = randint(1, 5)
sage: G = graphs.RandomGNP(n, .5)
sage: m = G.size()
sage: S = graphs.GeneralizedSierpinskiGraph(G, k)
sage: S.order() == n**k
True
sage: S.size() == m*sum([n**i for i in range(k)])
True
sage: G = graphs.CompleteGraph(n)
sage: S = graphs.GeneralizedSierpinskiGraph(G, k)
sage: S.order() == n**k
True
sage: S.size() == (n*(n - 1)/2)*sum([n**i for i in range(k)])
True
The positions of the vertices of the output graph are determined from the positions of the vertices of 𝐺, if
any:
sage: G = graphs.HouseGraph()
sage: G.get_pos() is not None
True
sage: H = graphs.GeneralizedSierpinskiGraph(G, 2)
sage: H.get_pos() is not None
True
sage: G = Graph([(0, 1)])
sage: G.get_pos() is not None
False
sage: H = graphs.GeneralizedSierpinskiGraph(G, 2)
sage: H.get_pos() is not None
False
static GoethalsSeidelGraph(k, r)
Returns the graph Goethals-Seidel(𝑘, 𝑟).
The graph Goethals-Seidel(𝑘, 𝑟) comes from a construction presented in Theorem 2.4 of [GS1970]. It
relies on a (v,k)-BIBD with 𝑟 blocks and a hadamard_matrix() of order 𝑟 + 1. The result is a sage.
graphs.strongly_regular_db.strongly_regular_graph() on 𝑣(𝑟 + 1) vertices with degree 𝑘 =
(𝑛 + 𝑟 − 1)/2.
It appears under this name in Andries Brouwer’s database of strongly regular graphs.
INPUT:
• k,r – integers
See also:
• is_goethals_seidel()
EXAMPLES:
sage: graphs.GoethalsSeidelGraph(3,3)
Graph on 28 vertices
sage: graphs.GoethalsSeidelGraph(3,3).is_strongly_regular(parameters=True)
(28, 15, 6, 10)
static GoldnerHararyGraph()
Return the Goldner-Harary graph.
For more information, see the Wikipedia article Goldner%E2%80%93Harary_graph.
EXAMPLES:
The Goldner-Harary graph is named after A. Goldner and Frank Harary. It is a planar graph having 11
vertices and 27 edges:
sage: G = graphs.GoldnerHararyGraph(); G
Goldner-Harary graph: Graph on 11 vertices
sage: G.is_planar()
True
sage: G.order()
11
sage: G.size()
27
sage: G.is_chordal()
True
sage: G.radius()
2
sage: G.diameter()
2
sage: G.girth()
3
Its chromatic number is 4 and its automorphism group is isomorphic to the dihedral group 𝐷6 :
sage: G.chromatic_number()
4
sage: ag = G.automorphism_group()
sage: ag.is_isomorphic(DihedralGroup(6))
True
static GolombGraph()
Return the Golomb graph.
See the Wikipedia article Golomb_graph for more information.
EXAMPLES:
The Golomb graph is a planar and Hamiltonian graph with 10 vertices and 18 edges. It has chromatic
number 4, diameter 3, radius 2 and girth 3. It can be drawn in the plane as a unit distance graph:
sage: G = graphs.GolombGraph(); G
Golomb graph: Graph on 10 vertices
sage: pos = G.get_pos()
sage: dist2 = lambda u,v:(u[0]-v[0])**2 + (u[1]-v[1])**2
sage: all(dist2(pos[u], pos[v]) == 1 for u, v in G.edge_iterator(labels=None))
True
static GossetGraph()
Return the Gosset graph.
The Gosset graph is the skeleton of the Gosset_3_21() polytope. It has with 56 vertices and degree 27.
For more information, see the Wikipedia article Gosset_graph.
EXAMPLES:
sage: g = graphs.GossetGraph(); g
Gosset Graph: Graph on 56 vertices
sage: g.order(), g.size()
(56, 756)
sage: G = graphs.GrassmannGraph(2, 4, 2)
sage: G.is_distance_regular(True)
([18, 8, None], [None, 1, 9])
REFERENCES:
See [BCN1989] pp. 268-272 or [VDKT2016] p. 21.
static GrayGraph(embedding=1)
Return the Gray graph.
See the Wikipedia article Gray_graph.
INPUT:
• embedding – integer (default: 1); two embeddings are available, and can be selected by setting
embedding to 1 or 2
EXAMPLES:
sage: g = graphs.GrayGraph()
sage: g.order()
54
sage: g.size()
(continues on next page)
sage: g = graphs.Grid2dGraph(5,7)
sage: g.show() # long time
static GridGraph(dim_list)
Return an 𝑛-dimensional grid graph.
INPUT:
• dim_list – a list of integers representing the number of nodes to extend in each dimension
PLOTTING: When plotting, this graph will use the default spring-layout algorithm, unless a position dic-
tionary is specified.
EXAMPLES:
sage: G = graphs.GridGraph([2,3,4])
sage: G.show() # long time
sage: C = graphs.CubeGraph(4)
sage: G = graphs.GridGraph([2,2,2,2])
sage: C.show() # long time
sage: G.show() # long time
static GritsenkoGraph()
Return SRG(65, 32, 15, 16) constructed by Gritsenko.
We took the adjacency matrix from O.Gritsenko’s [Gri2021] and extracted orbits of the automorphism
group on the edges.
EXAMPLES:
sage: H = graphs.GritsenkoGraph(); H
Gritsenko strongly regular graph: Graph on 65 vertices
sage: H.is_strongly_regular(parameters=True)
(65, 32, 15, 16)
static GrotzschGraph()
Return the Grötzsch graph.
The Grötzsch graph is an example of a triangle-free graph with chromatic number equal to 4. For more
information, see the Wikipedia article Gr%C3%B6tzsch_graph.
EXAMPLES:
The Grötzsch graph is named after Herbert Grötzsch. It is a Hamiltonian graph with 11 vertices and 20
edges:
sage: G = graphs.GrotzschGraph(); G
Grotzsch graph: Graph on 11 vertices
sage: G.is_hamiltonian()
True
sage: G.order()
11
sage: G.size()
20
The Grötzsch graph is triangle-free and having radius 2, diameter 2, and girth 4:
sage: G.is_triangle_free()
True
sage: G.radius()
2
sage: G.diameter()
2
sage: G.girth()
4
Its chromatic number is 4 and its automorphism group is isomorphic to the dihedral group 𝐷5 :
sage: G.chromatic_number()
4
sage: ag = G.automorphism_group()
sage: ag.is_isomorphic(DihedralGroup(5))
True
sets 𝐼𝑘 of size 𝑞 2 each. Each vertex in 𝐼𝑗 is adjacent to 𝑞 vertices from 𝐼𝑘 . Each 𝐼𝑘 is paired to some 𝐼𝑘′ ,
according to hyperoval_matching. One adds edges (𝑠, 𝑡) for 𝑠, 𝑡 ∈ 𝐼𝑘 whenever 𝑠 and 𝑡 are adjacent to
some 𝑢 ∈ 𝐼𝑘′ , and removes all the edges between 𝐼𝑘 and 𝐼𝑘′ .
INPUT:
• q – a power of two
• hyperoval_matching – if None (default), pair each 𝑖-th point of hyperoval with (𝑖 + 1)-th. Oth-
erwise, specifies the pairing in the format ((𝑖1 , 𝑖′1 ), (𝑖2 , 𝑖′2 ), ...).
• hyperoval – a hyperoval defining 𝑇2* (𝑞)* . If None (default), the classical hyperoval obtained from a
conic is used. See the documentation of T2starGeneralizedQuadrangleGraph(), for more infor-
mation.
• field – an instance of a finite field of order 𝑞, must be provided if hyperoval is provided
• check_hyperoval – boolean (default: True); whether to check hyperoval for correctness or not
EXAMPLES:
using the built-in constructions:
sage: g=graphs.HaemersGraph(4); g
Haemers(4): Graph on 96 vertices
sage: g.is_strongly_regular(parameters=True)
(96, 19, 2, 4)
sage: g=graphs.HaemersGraph(4,hyperoval_matching=((0,5),(1,4),(2,3))); g
Haemers(4): Graph on 96 vertices
sage: g.is_strongly_regular(parameters=True)
(96, 19, 2, 4)
static HalfCube(n)
Return the halved cube in 𝑛 dimensions.
The graph is distance-regular with classical parameters (⌊ 𝑛2 ⌋, 1, 2, 2⌈ 𝑛2 ⌉ − 1).
INPUT:
• n – integer; must be greater than 2
EXAMPLES:
sage: G = graphs.HalfCube(8)
sage: G.is_distance_regular(True)
([28, 15, 6, 1, None], [None, 1, 6, 15, 28])
sage: G = graphs.HalfCube(4)
sage: G.is_distance_regular(True)
([6, 1, None], [None, 1, 6])
REFERENCES:
See [BCN1989] pp. 264, 265 or [VDKT2016] p. 21. This construction can be found on Wikipedia article
Halved_cube_graph#Equivalent_constructions
static HallJankoGraph(from_string=True)
Return the Hall-Janko graph.
For more information on the Hall-Janko graph, see the Wikipedia article Hall-Janko_graph.
The construction used to generate this graph in Sage is by a 100-point permutation representation of the
Janko group 𝐽2 , as described in version 3 of the ATLAS of Finite Group representations, in particular on
the page ATLAS: J2 – Permutation representation on 100 points.
INPUT:
• from_string – boolean (default: True); whether to build the graph from its sparse6 string or through
GAP. The two methods return the same graph though doing it through GAP takes more time.
EXAMPLES:
sage: g = graphs.HallJankoGraph()
sage: g.is_regular(36)
True
sage: g.is_vertex_transitive()
True
sage: nu = set(g.neighbors(0))
sage: for v in range(1, 100):
....: if v in nu:
....: expected = 14
....: else:
....: expected = 12
....: nv = set(g.neighbors(v))
....: nv.discard(0)
....: if len(nu & nv) != expected:
....: print("Something is wrong here!!!")
....: break
sage: g.diameter()
2
sage: g.girth()
3
sage: factor(g.characteristic_polynomial())
(x - 36) * (x - 6)^36 * (x + 4)^63
sage: g = graphs.HammingGraph(3, 7)
sage: g.is_distance_regular()
True
sage: g.is_regular()
True
sage: g.is_vertex_transitive()
True
A Hamming graph with parameters (1,q) is isomorphic to the Complete graph with parameter q.
sage: X = ['a','b','c','d','e']
sage: g = graphs.HammingGraph(2, 3, X)
Traceback (most recent call last):
...
ValueError: q must be the cardinality of X
REFERENCES:
For a more accurate description, see the following wikipedia page: Wikipedia article Hamming_graph
static HanoiTowerGraph(pegs, disks, labels=True, positions=True)
Returns the graph whose vertices are the states of the Tower of Hanoi puzzle, with edges representing legal
moves between states.
INPUT:
• pegs - the number of pegs in the puzzle, 2 or greater
• disks - the number of disks in the puzzle, 1 or greater
• labels - default: True, if True the graph contains more meaningful labels, see explanation below.
For large instances, turn off labels for much faster creation of the graph.
• positions - default: True, if True the graph contains layout information. This creates a planar layout
for the case of three pegs. For large instances, turn off layout information for much faster creation of
the graph.
OUTPUT:
The Tower of Hanoi puzzle has a certain number of identical pegs and a certain number of disks, each of a
different radius. Initially the disks are all on a single peg, arranged in order of their radii, with the largest
on the bottom.
The goal of the puzzle is to move the disks to any other peg, arranged in the same order. The one constraint
is that the disks resident on any one peg must always be arranged with larger radii lower down.
The vertices of this graph represent all the possible states of this puzzle. Each state of the puzzle is a tuple
with length equal to the number of disks, ordered by largest disk first. The entry of the tuple is the peg
where that disk resides. Since disks on a given peg must go down in size as we go up the peg, this totally
describes the state of the puzzle.
For example (2,0,0) means the large disk is on peg 2, the medium disk is on peg 0, and the small disk is
on peg 0 (and we know the small disk must be above the medium disk). We encode these tuples as integers
with a base equal to the number of pegs, and low-order digits to the right.
Two vertices are adjacent if we can change the puzzle from one state to the other by moving a single disk.
For example, (2,0,0) is adjacent to (2,0,1) since we can move the small disk off peg 0 and onto (the
empty) peg 1. So the solution to a 3-disk puzzle (with at least two pegs) can be expressed by the shortest
path between (0,0,0) and (1,1,1). For more on this representation of the graph, or its properties, see
[AD2010].
For greatest speed we create graphs with integer vertices, where we encode the tuples as integers with a
base equal to the number of pegs, and low-order digits to the right. So for example, in a 3-peg puzzle with
5 disks, the state (1,2,0,1,1) is encoded as 1 * 34 + 2 * 33 + 0 * 32 + 1 * 31 + 1 * 30 = 139.
For smaller graphs, the labels that are the tuples are informative, but slow down creation of the graph.
Likewise computing layout information also incurs a significant speed penalty. For maximum speed, turn
off labels and layout and decode the vertices explicitly as needed. The sage.rings.integer.Integer.
digits() with the padsto option is a quick way to do this, though you may want to reverse the list that is
output.
See also:
• GeneralizedSierpinskiGraph()
PLOTTING:
The layout computed when positions = True will look especially good for the three-peg case, when the
graph is known to be planar. Except for two small cases on 4 pegs, the graph is otherwise not planar, and
likely there is a better way to layout the vertices.
EXAMPLES:
A classic puzzle uses 3 pegs. We solve the 5 disk puzzle using integer labels and report the minimum
number of moves required. Note that 35 − 1 is the state where all 5 disks are on peg 2.
For a small graph, labels and layout information can be useful. Here we explicitly list a solution as a list of
states.
True
sage: H.chromatic_number()
3
sage: len(H.independent_set()) == 3^(4-1)
True
AUTHOR:
• Rob Beezer, (2009-12-26), with assistance from Su Doree
static HararyGraph(k, n)
Returns the Harary graph on 𝑛 vertices and connectivity 𝑘, where 2 ≤ 𝑘 < 𝑛.
A 𝑘-connected graph 𝐺 on 𝑛 vertices requires the minimum degree 𝛿(𝐺) ≥ 𝑘, so the minimum number of
edges 𝐺 should have is ⌈𝑘𝑛/2⌉. Harary graphs achieve this lower bound, that is, Harary graphs are minimal
𝑘-connected graphs on 𝑛 vertices.
The construction provided uses the method CirculantGraph. For more details, see the book D. B. West,
Introduction to Graph Theory, 2nd Edition, Prentice Hall, 2001, p. 150–151; or the MathWorld article on
Harary graphs.
EXAMPLES:
Harary graphs 𝐻𝑘,𝑛 :
sage: h = graphs.HararyGraph(5,9); h
Harary graph 5, 9: Graph on 9 vertices
sage: h.order()
9
sage: h.size()
23
sage: h.vertex_connectivity()
5
static HarborthGraph()
Return the Harborth Graph.
The Harborth graph has 104 edges and 52 vertices, and is the smallest known example of a 4-regular
matchstick graph. For more information, see the Wikipedia article Harborth_graph.
EXAMPLES:
sage: g = graphs.HarborthGraph(); g
Harborth Graph: Graph on 52 vertices
sage: g.is_regular(4)
True
static HarriesGraph(embedding=1)
Return the Harries Graph.
The Harries graph is a Hamiltonian 3-regular graph on 70 vertices. See the Wikipedia article Harries_graph.
The default embedding here is to emphasize the graph’s 4 orbits. This graph actually has a funny con-
struction. The following procedure gives an idea of it, though not all the adjacencies are being properly
defined.
1. Take two disjoint copies of a Petersen graph . Their vertices will form an orbit of the final graph.
2. Subdivide all the edges once, to create 15+15=30 new vertices, which together form another orbit.
3. Create 15 vertices, each of them linked to 2 corresponding vertices of the previous orbit, one in each
of the two subdivided Petersen graphs. At the end of this step all vertices from the previous orbit have
degree 3, and the only vertices of degree 2 in the graph are those that were just created.
4. Create 5 vertices connected only to the ones from the previous orbit so that the graph becomes 3-
regular.
INPUT:
• embedding – integer (default: 1); two embeddings are available, and can be selected by setting
embedding to 1 or 2
EXAMPLES:
sage: g = graphs.HarriesGraph()
sage: g.order()
70
sage: g.size()
105
sage: g.girth()
10
sage: g.diameter()
6
sage: g.show(figsize=[10, 10]) # long time
sage: graphs.HarriesGraph(embedding=2).show(figsize=[10, 10]) # long time
static HarriesWongGraph(embedding=1)
Return the Harries-Wong Graph.
See the Wikipedia article Harries-Wong_graph.
About the default embedding:
The default embedding is an attempt to emphasize the graph’s 8 (!!!) different orbits. In order to understand
this better, one can picture the graph as being built in the following way.
1. One first creates a 3-dimensional cube (8 vertices, 12 edges), whose vertices define the first orbit of
the final graph.
2. The edges of this graph are subdivided once, to create 12 new vertices which define a second orbit.
3. The edges of the graph are subdivided once more, to create 24 new vertices giving a third orbit.
4. 4 vertices are created and made adjacent to the vertices of the second orbit so that they have degree 3.
These 4 vertices also define a new orbit.
5. In order to make the vertices from the third orbit 3-regular (they all miss one edge), one creates a
binary tree on 1 + 3 + 6 + 12 vertices. The leaves of this new tree are made adjacent to the 12 vertices
of the third orbit, and the graph is now 3-regular. This binary tree contributes 4 new orbits to the
Harries-Wong graph.
INPUT:
• embedding – integer (default: 1); two embeddings are available, and can be selected by setting
embedding to 1 or 2
EXAMPLES:
sage: g = graphs.HarriesWongGraph()
sage: g.order()
70
sage: g.size()
105
sage: g.girth()
10
sage: g.diameter()
6
sage: orbits = g.automorphism_group(orbits=True)[-1] # long time
sage: g.show(figsize=[15, 15], partition=orbits) # long time
Alternative embedding:
static HeawoodGraph()
Return a Heawood graph.
The Heawood graph is a cage graph that has 14 nodes. It is a cubic symmetric graph. (See also the Möbius-
Kantor graph, MobiusKantorGraph()). It is nonplanar and Hamiltonian. It has diameter 3, radius 3, girth
6, and chromatic number 2. It is 4-transitive but not 5-transitive. See the Wikipedia article Heawood_graph.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, the nodes are positioned in a circular layout with the first node appearing at the top, and
then continuing counterclockwise.
EXAMPLES:
sage: H = graphs.HeawoodGraph()
sage: H
Heawood graph: Graph on 14 vertices
sage: H.graph6_string()
'MhEGHC@AI?_PC@_G_'
sage: (graphs.HeawoodGraph()).show() # long time
static HermitianFormsGraph(n, r)
Return the Hermitian forms graph with the given parameters.
We build a graph whose vertices are all n``x``n Hermitian matrices over GF(r^2). Two vertices are
adjacent if the difference of the two vertices has rank 1.
This graph is distance-regular with classical parameters (𝑛, −𝑟, −𝑟 − 1, −(−𝑟)𝑑 − 1).
INPUT:
• n – integer
• r – a prime power
EXAMPLES:
sage: G = graphs.HermitianFormsGraph(2, 2)
sage: G.is_distance_regular(True)
([5, 4, None], [None, 1, 2])
sage: G = graphs.HermitianFormsGraph(3, 3) # not tested (2 min)
(continues on next page)
REFERENCES:
See [BCN1989] p. 285 or [VDKT2016] p. 22.
static HerschelGraph()
Return the Herschel graph.
For more information, see the Wikipedia article Herschel_graph.
EXAMPLES:
The Herschel graph is named after Alexander Stewart Herschel. It is a planar, bipartite graph with 11
vertices and 18 edges:
sage: G = graphs.HerschelGraph(); G
Herschel graph: Graph on 11 vertices
sage: G.is_planar()
True
sage: G.is_bipartite()
True
sage: G.order()
11
sage: G.size()
18
The Herschel graph is a perfect graph with radius 3, diameter 4, and girth 4:
sage: G.is_perfect()
True
sage: G.radius()
3
sage: G.diameter()
4
sage: G.girth()
4
Its chromatic number is 2 and its automorphism group is isomorphic to the dihedral group 𝐷6 :
sage: G.chromatic_number()
2
sage: ag = G.automorphism_group()
sage: ag.is_isomorphic(DihedralGroup(6))
True
static HexahedralGraph()
Return a hexahedral graph (with 8 nodes).
A regular hexahedron is a 6-sided cube. The hexahedral graph corresponds to the connectivity of the
vertices of the hexahedron. This graph is equivalent to a 3-cube.
PLOTTING: The Hexahedral graph should be viewed in 3 dimensions. We choose to use a planar em-
bedding of the graph. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a
argument will be added to select the desired layout.
EXAMPLES:
Construct and show a Hexahedral graph:
sage: g = graphs.HexahedralGraph()
sage: g.show() # long time
Create several hexahedral graphs in a Sage graphics array. They will be drawn differently due to the use of
the spring-layout algorithm:
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.HexahedralGraph()
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
static HigmanSimsGraph(relabel=True)
Return the Higman-Sims graph.
The Higman-Sims graph is a remarkable strongly regular graph of degree 22 on 100 vertices. For example,
it can be split into two sets of 50 vertices each, so that each half induces a subgraph isomorphic to the
Hoffman-Singleton graph (HoffmanSingletonGraph()). This can be done in 352 ways (see Higman-
Sims graph by Andries E. Brouwer, accessed 24 October 2009.)
Its most famous property is that the automorphism group has an index 2 subgroup which is one of the 26
sporadic groups [HS1968].
The construction used here follows [Haf2004].
See also the Wikipedia article Higman–Sims_graph.
INPUT:
• relabel – boolean (default: True); whether to relabel the vertices with consecutive integers. If
False the labels are strings that are three digits long. “xyz” means the vertex is in group 𝑥 (zero
through three), pentagon or pentagram 𝑦 (zero through four), and is vertex 𝑧 (zero through four) of
that pentagon or pentagram. See [Haf2004] for more.
OUTPUT:
The Higman-Sims graph.
EXAMPLES:
A split into the first 50 and last 50 vertices will induce two copies of the Hoffman-Singleton graph, and we
illustrate another such split, which is obvious based on the construction used:
sage: H = graphs.HigmanSimsGraph()
sage: A = H.subgraph(range(0,50))
sage: B = H.subgraph(range(50,100))
sage: K = graphs.HoffmanSingletonGraph()
sage: K.is_isomorphic(A) and K.is_isomorphic(B)
(continues on next page)
The automorphism group contains only one nontrivial proper normal subgroup, which is of index 2 and is
simple. It is known as the Higman-Sims group:
sage: H = graphs.HigmanSimsGraph()
sage: G = H.automorphism_group()
sage: g=G.order(); g
88704000
sage: K = G.normal_subgroups()[1]
sage: K.is_simple()
True
sage: g//K.order()
2
AUTHOR:
• Rob Beezer (2009-10-24)
static HoffmanGraph()
Return the Hoffman Graph.
See the Wikipedia article Hoffman_graph.
EXAMPLES:
sage: g = graphs.HoffmanGraph()
sage: g.is_bipartite()
True
sage: g.is_hamiltonian() # long time
True
sage: g.radius()
3
sage: g.diameter()
4
sage: g.automorphism_group().cardinality()
48
static HoffmanSingletonGraph()
Return the Hoffman-Singleton graph.
The Hoffman-Singleton graph is the Moore graph of degree 7, diameter 2 and girth 5. The Hoffman-
Singleton theorem states that any Moore graph with girth 5 must have degree 2, 3, 7 or 57. The first three
respectively are the pentagon, the Petersen graph, and the Hoffman-Singleton graph. The existence of a
Moore graph with girth 5 and degree 57 is still open.
A Moore graph is a graph with diameter 𝑑 and girth 2𝑑 + 1. This implies that the graph is regular, and
distance regular.
For more details, see [GR2001] and the Wikipedia article Hoffman–Singleton_graph.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. A
novel algorithm written by Tom Boothby gives a random layout which is pleasing to the eye.
EXAMPLES:
sage: HS = graphs.HoffmanSingletonGraph()
sage: Set(HS.degree())
{7}
sage: HS.girth()
5
sage: HS.diameter()
2
sage: HS.num_verts()
50
Note that you get a different layout each time you create the graph.
static HoltGraph()
Return the Holt graph (also called the Doyle graph).
See the Wikipedia article Holt_graph.
EXAMPLES:
sage: g = graphs.HoltGraph();g
Holt graph: Graph on 27 vertices
sage: g.is_regular()
True
sage: g.is_vertex_transitive()
True
sage: g.chromatic_number()
3
sage: g.is_hamiltonian() # long time
True
sage: g.radius()
3
sage: g.diameter()
3
sage: g.girth()
5
sage: g.automorphism_group().cardinality()
54
static HortonGraph()
Return the Horton Graph.
The Horton graph is a cubic 3-connected non-hamiltonian graph. For more information, see the Wikipedia
article Horton_graph.
EXAMPLES:
sage: g = graphs.HortonGraph()
sage: g.order()
(continues on next page)
static HouseGraph()
Return a house graph with 5 nodes.
A house graph is named for its shape. It is a triangle (roof) over a square (walls).
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, the house graph is drawn with the first node in the lower-left corner of the house, the second
in the lower-right corner of the house. The third node is in the upper-left corner connecting the roof to the
wall, and the fourth is in the upper-right corner connecting the roof to the wall. The fifth node is the top of
the roof, connected only to the third and fourth.
EXAMPLES:
Construct and show a house graph:
sage: g = graphs.HouseGraph()
sage: g.show() # long time
static HouseXGraph()
Return a house X graph with 5 nodes.
A house X graph is a house graph with two additional edges. The upper-right corner is connected to the
lower-left. And the upper-left corner is connected to the lower-right.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, the house X graph is drawn with the first node in the lower-left corner of the house, the
second in the lower-right corner of the house. The third node is in the upper-left corner connecting the roof
to the wall, and the fourth is in the upper-right corner connecting the roof to the wall. The fifth node is the
top of the roof, connected only to the third and fourth.
EXAMPLES:
Construct and show a house X graph:
sage: g = graphs.HouseXGraph()
sage: g.show() # long time
static HyperStarGraph(n, k)
Return the hyper-star graph 𝐻𝑆(𝑛, 𝑘).
The vertices of the hyper-star graph are the set of binary strings of length 𝑛 which contain 𝑘 1s. Two
vertices, 𝑢 and 𝑣, are adjacent only if 𝑢 can be obtained from 𝑣 by swapping the first bit with a different
symbol in another position. For instance, vertex '011100' of 𝐻𝑆(6, 3) is adjacent to vertices '101100',
'110100' and '111000'. See [LKOL2002] for more details.
INPUT:
• n – non-negative integer; length of the binary strings
• k – non-negative integer; number of 1s per binary string
EXAMPLES:
sage: g = graphs.HyperStarGraph(6,3)
sage: sorted(g.neighbors('011100'))
['101100', '110100', '111000']
sage: g.plot() # long time
Graphics object consisting of 51 graphics primitives
AUTHORS:
• Michael Yurko (2009-09-01)
static IGraph(n, j, k)
Return an I-graph with 2𝑛 nodes.
The I-Graph family as been proposed in [BCMS1988] as a generalization of the generalized Petersen graphs.
The variables 𝑛, 𝑗, 𝑘 are integers such that 𝑛 > 2 and 0 < 𝑗, 𝑘 ≤ ⌊(𝑛 − 1)/2⌋. When 𝑗 = 1 the resulting
graph is isomorphic to the generalized Petersen graph with the same 𝑛 and 𝑘.
INPUT:
• n – the number of nodes is 2 * 𝑛
• j – integer such that 0 < 𝑗 ≤ ⌊(𝑛 − 1)/2⌋ determining how outer vertices are connected
• k – integer such that 0 < 𝑘 ≤ ⌊(𝑛 − 1)/2⌋ determining how inner vertices are connected
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, the I-graphs are displayed as an inner and outer cycle pair, with the first n nodes drawn on
the outer circle. The first (0) node is drawn at the top of the outer-circle, moving counterclockwise after
that. The inner circle is drawn with the (n)th node at the top, then counterclockwise as well.
EXAMPLES:
When 𝑗 = 1 the resulting graph will be isomorphic to a generalized Petersen graph:
sage: g = graphs.IGraph(7,1,2)
sage: g2 = graphs.GeneralizedPetersenGraph(7,2)
sage: g.is_isomorphic(g2)
True
The IGraph with parameters (𝑛, 𝑗, 𝑘) is isomorphic to the IGraph with parameters (𝑛, 𝑘, 𝑗):
sage: g = graphs.IGraph(7, 2, 3)
sage: h = graphs.IGraph(7, 3, 2)
sage: g.is_isomorphic(h)
True
static IcosahedralGraph()
Return an Icosahedral graph (with 12 nodes).
The regular icosahedron is a 20-sided triangular polyhedron. The icosahedral graph corresponds to the
connectivity of the vertices of the icosahedron. It is dual to the dodecahedral graph. The icosahedron is
symmetric, so the spring-layout algorithm will be very effective for display.
PLOTTING: The Icosahedral graph should be viewed in 3 dimensions. We choose to use a planar em-
bedding of the graph. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a
argument will be added to select the desired layout.
EXAMPLES:
Construct and show an Octahedral graph:
sage: g = graphs.IcosahedralGraph()
sage: g.show() # long time
Create several icosahedral graphs in a Sage graphics array. They will be drawn differently due to the use of
the spring-layout algorithm:
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.IcosahedralGraph()
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
static IntersectionGraph(S)
Return the intersection graph of the family 𝑆
The intersection graph of a family 𝑆 is a graph 𝐺 with 𝑉 (𝐺) = 𝑆 such that two elements 𝑠1 , 𝑠2 ∈ 𝑆 are
adjacent in 𝐺 if and only if 𝑠1 ∩ 𝑠2 ̸= ∅.
INPUT:
• S – a list of sets/tuples/iterables
Note: The elements of 𝑆 must be finite, hashable, and the elements of any 𝑠 ∈ 𝑆 must be
hashable too.
EXAMPLES:
sage: graphs.IntersectionGraph([(1,2,3),(3,4,5),(5,6,7)])
Intersection Graph: Graph on 3 vertices
• points_ordered – states whether every interval (𝑎𝑖 , 𝑏𝑖 ) of 𝑖𝑛𝑡𝑒𝑟𝑣𝑎𝑙𝑠 satisfies 𝑎𝑖 < 𝑏𝑖 . If satisfied
then setting points_ordered to True will speed up the creation of the graph.
Note:
• The vertices are named 0, 1, 2, and so on. The intervals used to create the graph are saved with the
graph and can be recovered using get_vertex() or get_vertices().
EXAMPLES:
The following line creates the sequence of intervals (𝑖, 𝑖 + 2) for i in [0, ..., 8]:
sage: g = graphs.IntervalGraph(intervals)
sage: g.get_vertex(3)
(3, 5)
sage: neigh = g.neighbors(3)
sage: for v in neigh: print(g.get_vertex(v))
(1, 3)
(2, 4)
(4, 6)
(5, 7)
sage: g.is_interval()
True
The endpoints of the intervals are not ordered we get the same graph (except for the vertex labels).
static IoninKharaghani765Graph()
Return a (765, 192, 48, 48)-strongly regular graph.
Existence of a strongly regular graph with these parameters was claimed in [IK2003]. Implementing the
construction in the latter did not work, however. This function implements the following instructions, shared
by Yury Ionin and Hadi Kharaghani.
Let 𝐴 be the affine plane over the field 𝐺𝐹 (3) = {−1, 0, 1}. Let
𝜑1 (𝑥, 𝑦) = 𝑥
𝜑2 (𝑥, 𝑦) = 𝑦
𝜑3 (𝑥, 𝑦) = 𝑥 + 𝑦
𝜑4 (𝑥, 𝑦) = 𝑥 − 𝑦
For 𝑖 = 1, 2, 3, 4 and 𝑗 ∈ 𝐺𝐹 (3), let 𝐿𝑖,𝑗 be the line in 𝐴 defined by 𝜑𝑖 (𝑥, 𝑦) = 𝑗. Let ℳ
be the set of all 12 lines 𝐿𝑖,𝑗 , plus the empty set. Let 𝜋 be the permutation defined on ℳ by
𝜋(𝐿𝑖,𝑗 ) = 𝐿𝑖,𝑗+1 and 𝜋(∅) = ∅, so that 𝜋 has three orbits of cardinality 3 and one of cardinality
1.
Let 𝐴 = (𝑝1 , ..., 𝑝9 ) with 𝑝1 = (−1, 1), 𝑝2 = (−1, 0), 𝑝3 = (−1, 1), 𝑝4 = (0, −1), 𝑝5 = (0, 0),
𝑝6 = (0, 1), 𝑝7 = (1, −1), 𝑝8 = (1, 0), 𝑝9 = (1, 1). Note that 𝑝𝑖 + 𝑝10−𝑖 = (0, 0). For any
subset 𝑋 of 𝐴, let 𝑀 (𝑋) be the (0, 1)-matrix of order 9 whose (𝑖, 𝑗)-entry equals 1 if and only
if 𝑝10−𝑖 − 𝑝𝑗 ∈ 𝑋. Note that 𝑀 is a symmetric matrix.
An 𝑀 𝐹 -tuple is an ordered quintuple (𝑋1 , 𝑋2 , 𝑋3 , 𝑋4 , 𝑋5 ) of subsets of 𝐴, of which one is
the empty set and the other four are pairwise non-parallel lines. Such a quintuple generates the
following block matrix:
⎛ ⎞
𝑀 (𝑋1 ) 𝑀 (𝑋2 ) 𝑀 (𝑋3 ) 𝑀 (𝑋4 ) 𝑀 (𝑋5 )
⎜ 𝑀 (𝑋2 ) 𝑀 (𝑋3 ) 𝑀 (𝑋4 ) 𝑀 (𝑋5 ) 𝑀 (𝑋1 ) ⎟
⎜ ⎟
⎜ 𝑀 (𝑋3 ) 𝑀 (𝑋4 ) 𝑀 (𝑋5 ) 𝑀 (𝑋1 ) 𝑀 (𝑋2 ) ⎟
𝑁 (𝑋1 , 𝑋2 , 𝑋3 , 𝑋4 , 𝑋5 ) = ⎜ ⎟
⎝ 𝑀 (𝑋4 ) 𝑀 (𝑋5 ) 𝑀 (𝑋1 ) 𝑀 (𝑋2 ) 𝑀 (𝑋3 ) ⎠
𝑀 (𝑋5 ) 𝑀 (𝑋1 ) 𝑀 (𝑋2 ) 𝑀 (𝑋3 ) 𝑀 (𝑋4 )
𝜎(𝑋1 , 𝑋2 , 𝑋3 , 𝑋4 , 𝑋5 ) = (𝑋2 , 𝑋3 , 𝑋4 , 𝑋5 , 𝑋1 )
𝜋(𝑋1 , 𝑋2 , 𝑋3 , 𝑋4 , 𝑋5 ) = (𝜋(𝑋1 ), 𝜋(𝑋2 ), 𝜋(𝑋3 ), 𝜋(𝑋4 ), 𝜋(𝑋5 ))
Observe that 𝜎 and 𝜋 commute, and generate a (cyclic) group 𝐺 of order 15. We will from now
on identify 𝐺 with the (cyclic) multiplicative group of the field 𝐺𝐹 (16) equal to {𝜔 0 , ..., 𝜔 14 }.
Let 𝑊 = [𝑤𝑖𝑗 ] be the following matrix of order 17 over 𝐺𝐹 (16) = {𝑎1 , ..., 𝑎1 6}:
𝑎𝑖 + 𝑎𝑗 if 1 ≤ 𝑖 ≤ 16, 1 ≤ 𝑗 ≤ 16,
⎧
⎪
if 𝑖 = 17, 𝑗 ̸= 17,
⎪
1
⎨
𝑤𝑖𝑗 =
⎪ 1 if 𝑖 ̸= 17, 𝑗 = 17,
if 𝑖 = 𝑗 = 17
⎪
0
⎩
The diagonal entries of 𝑊 are equal to 0, each off-diagonal entry can be represented as 𝜔 𝑘 with
0 ≤ 𝑘 ≤ 14. Matrix 𝑊 is a symmetric 𝐵𝐺𝑊 (17, 16, 15; 𝐺).
Fix an 𝑀 𝐹 -tuple (𝑋1 , 𝑋2 , 𝑋3 , 𝑋4 , 𝑋5 ) and let 𝑆 be the block matrix obtained from 𝑊 by re-
placing every diagonal entry of 𝑊 by the zero matrix of order 45, and every off-diagonal entry
𝜔 𝑘 by the matrix 𝑁 (𝜎 𝑘 (𝑋1 , 𝑋2 , 𝑋3 , 𝑋4 , 𝑋5 )) (through the association of 𝜔 𝑘 with an element
of 𝐺). Then 𝑆 is a symmetric incidence matrix of a symmetric (765, 192, 48)-design with zero
diagonal, and therefore 𝑆 is an adjacency matrix of a strongly regular graph with parameters
(765, 192, 48, 48).
EXAMPLES:
sage: g = graphs.IoninKharaghani765Graph(); g
Ionin-Kharaghani: Graph on 765 vertices
Todo: An update to [IK2003] meant to fix the problem encountered became available 2016/02/24, see
http://www.cs.uleth.ca/~hadi/research/IoninKharaghani.pdf
static IvanovIvanovFaradjevGraph()
Return the IvanovIvanovFaradjev graph.
The graph is distance-transitive with automorphism group 3.𝑀22 .
EXAMPLES:
REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 369.
static J2Graph()
Return the distance-transitive graph with automorphism group 𝐽2 .
EXAMPLES:
REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 408.
static JankoKharaghaniGraph(v)
Return a (936, 375, 150, 150)-srg or a (1800, 1029, 588, 588)-srg.
This functions returns a strongly regular graph for the two sets of parameters shown to be realizable in
[JK2002]. The paper also uses a construction from [GM1987].
INPUT:
• v – integer; one of 936 or 1800
EXAMPLES:
static JankoKharaghaniTonchevGraph()
Return a (324, 153, 72, 72)-strongly regular graph from [JKT2001].
Build the graph using the description given in [JKT2001], taking sets B1 and B163 in the text as adjacencies
of vertices 1 and 163, respectively, and taking the edge orbits of the group 𝐺 provided.
EXAMPLES:
static JohnsonGraph(n, k)
Returns the Johnson graph with parameters 𝑛, 𝑘.
Johnson graphs are a special class of undirected graphs defined from systems of sets. The vertices of the
Johnson graph 𝐽(𝑛, 𝑘) are the 𝑘-element subsets of an 𝑛-element set; two vertices are adjacent when they
meet in a (𝑘 − 1)-element set. See the Wikipedia article Johnson_graph for more information.
EXAMPLES:
The Johnson graph is a Hamiltonian graph:
sage: g = graphs.JohnsonGraph(7, 3)
sage: g.is_hamiltonian()
True
sage: g = graphs.JohnsonGraph(6, 4)
sage: g.is_vertex_transitive()
True
The complement of the Johnson graph 𝐽(𝑛, 2) is isomorphic to the Kneser Graph 𝐾(𝑛, 2). In particular
the complement of 𝐽(5, 2) is isomorphic to the Petersen graph.:
sage: g = graphs.JohnsonGraph(5,2)
sage: g.complement().is_isomorphic(graphs.PetersenGraph())
True
The King Graph with large enough radius is isomorphic to a Queen Graph:
static KittellGraph()
Return the Kittell Graph.
For more information, see the Wolfram page about the Kittel Graph.
EXAMPLES:
sage: g = graphs.KittellGraph()
sage: g.order()
23
sage: g.size()
63
sage: g.radius()
3
sage: g.diameter()
4
sage: g.girth()
3
sage: g.chromatic_number()
4
static Klein3RegularGraph()
Return the Klein 3-regular graph.
The cubic Klein graph has 56 vertices and can be embedded on a surface of genus 3. It is the dual of
Klein7RegularGraph(). For more information, see the Wikipedia article Klein_graphs.
EXAMPLES:
sage: g = graphs.Klein3RegularGraph(); g
Klein 3-regular Graph: Graph on 56 vertices
sage: g.order(), g.size()
(56, 84)
sage: g.girth()
7
sage: g.automorphism_group().cardinality()
336
(continues on next page)
static Klein7RegularGraph()
Return the Klein 7-regular graph.
The 7-valent Klein graph has 24 vertices and can be embedded on a surface of genus 3. It is the dual of
Klein3RegularGraph(). For more information, see the Wikipedia article Klein_graphs.
EXAMPLES:
sage: g = graphs.Klein7RegularGraph(); g
Klein 7-regular Graph: Graph on 24 vertices
sage: g.order(), g.size()
(24, 84)
sage: g.girth()
3
sage: g.automorphism_group().cardinality()
336
sage: g.chromatic_number()
4
static KneserGraph(n, k)
Returns the Kneser Graph with parameters 𝑛, 𝑘.
The Kneser Graph with parameters 𝑛, 𝑘 is the graph whose vertices are the 𝑘-subsets of [0, 1, . . . , 𝑛 − 1],
and such that two vertices are adjacent if their corresponding sets are disjoint.
For example, the Petersen Graph can be defined as the Kneser Graph with parameters 5, 2.
EXAMPLES:
sage: KG = graphs.KneserGraph(5,2)
sage: sorted(KG.vertex_iterator(), key=str)
[{1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 3}, {2, 4}, {2, 5},
{3, 4}, {3, 5}, {4, 5}]
sage: P = graphs.PetersenGraph()
sage: P.is_isomorphic(KG)
True
• relabel – boolean (default: False); indicates whether the vertices must be relabeled as integers
EXAMPLES:
The (3, 3)-Knight Graph has an isolated vertex:
static KrackhardtKiteGraph()
Return a Krackhardt kite graph with 10 nodes.
The Krackhardt kite graph was originally developed by David Krackhardt for the purpose of studying social
networks (see [Kre2002] and the Wikipedia article Krackhardt_kite_graph). It is used to show the distinc-
tion between degree centrality, betweenness centrality, and closeness centrality. For more information read
the plotting section below in conjunction with the example.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, the graph is drawn left to right, in top to bottom row sequence of [2, 3, 2, 1, 1, 1] nodes on
each row. This places the fourth node (3) in the center of the kite, with the highest degree. But the fourth
node only connects nodes that are otherwise connected, or those in its clique (i.e.: Degree Centrality). The
eighth (7) node is where the kite meets the tail. It has degree = 3, less than the average, but is the only
connection between the kite and tail (i.e.: Betweenness Centrality). The sixth and seventh nodes (5 and 6)
are drawn in the third row and have degree = 5. These nodes have the shortest path to all other nodes in the
graph (i.e.: Closeness Centrality). Please execute the example for visualization.
EXAMPLES:
Construct and show a Krackhardt kite graph
sage: g = graphs.KrackhardtKiteGraph()
sage: g.show() # long time
sage: G.degree()
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
sage: G.diameter()
3
sage: G.show() # long time
PLOTTING: LCF Graphs are plotted as an n-cycle with edges in the middle, as described above.
REFERENCES:
• [1] Frucht, R. “A Canonical Representation of Trivalent Hamiltonian Graphs.” J. Graph Th. 1, 45-60,
1976.
• [2] Grunbaum, B. Convex Polytope es. New York: Wiley, pp. 362-364, 1967.
• [3] Lederberg, J. ‘DENDRAL-64: A System for Computer Construction, Enumeration and Notation of
Organic Molecules as Tree Structures and Cyclic Graphs. Part II. Topology of Cyclic Graphs.’ Interim
Report to the National Aeronautics and Space Administration. Grant NsG 81-60. December 15, 1965.
http://profiles.nlm.nih.gov/BB/A/B/I/U/_/bbabiu.pdf.
static LadderGraph(n)
Return a ladder graph with 2 * 𝑛 nodes.
A ladder graph is a basic structure that is typically displayed as a ladder, i.e.: two parallel path graphs
connected at each corresponding node pair.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, each ladder graph will be displayed horizontally, with the first n nodes displayed left to right
on the top horizontal line.
EXAMPLES:
Construct and show a ladder graph with 14 nodes:
sage: g = graphs.LadderGraph(7)
sage: g.show() # long time
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.LadderGraph(i+2)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
static LargeWittGraph()
Return the large Witt graph.
This is a distance-regular graph with intersection array [30, 28, 24; 1, 3, 15].
EXAMPLES:
sage: g = graphs.LargeWittGraph()
sage: g.is_distance_regular(True)
([30, 28, 24, None], [None, 1, 3, 15])
REFERENCES:
A description of this graph can be found in [BCN1989] p. 366. This construction is taken from http:
//mathworld.wolfram.com/LargeWittGraph.html
static LeonardGraph()
Return the Leonard graph.
The graph is distance-regular with intersection array [12, 11, 10, 7; 1, 2, 5, 12].
EXAMPLES:
sage: G = graphs.LeonardGraph()
sage: G.is_distance_regular(True)
([12, 11, 10, 7, None], [None, 1, 2, 5, 12])
REFERENCES:
For a description of this graph see [BCN1989] p. 371.
static LivingstoneGraph()
Return the Livingstone Graph.
The Livingstone graph is a distance-transitive graph on 266 vertices whose automorphism group is the J1
group. For more information, see the Wikipedia article Livingstone_graph.
EXAMPLES:
static LjubljanaGraph(embedding=1)
Return the Ljubljana Graph.
The Ljubljana graph is a bipartite 3-regular graph on 112 vertices and 168 edges. It is not vertex-transitive
as it has two orbits which are also independent sets of size 56. See the Wikipedia article Ljubljana_graph.
The default embedding is obtained from the Heawood graph.
INPUT:
• embedding – integer (default: 1); two embeddings are available, and can be selected by setting
embedding to 1 or 2
EXAMPLES:
sage: g = graphs.LjubljanaGraph()
sage: g.order()
112
sage: g.size()
168
sage: g.girth()
10
sage: g.diameter()
8
sage: g.show(figsize=[10, 10]) # long time
sage: graphs.LjubljanaGraph(embedding=2).show(figsize=[10, 10]) # long time
static LocalMcLaughlinGraph()
Return the local McLaughlin graph.
The local McLaughlin graph is a strongly regular graph with parameters (162, 56, 10, 24). It can be obtained
from McLaughlinGraph() by considering the stabilizer of a point: one of its orbits has cardinality 162.
EXAMPLES:
EXAMPLES:
Construct and show a lollipop graph Candy = 13, Stick = 4:
sage: g = graphs.LollipopGraph(13,4); g
Lollipop graph: Graph on 17 vertices
sage: g.show() # long time
static M22Graph()
Return the M22 graph.
The 𝑀22 graph is the unique strongly regular graph with parameters 𝑣 = 77, 𝑘 = 16, 𝜆 = 0, 𝜇 = 4.
For more information on the 𝑀22 graph, see https://www.win.tue.nl/~aeb/graphs/M22.html.
EXAMPLES:
sage: g = graphs.M22Graph()
sage: g.order()
77
sage: g.size()
616
sage: g.is_strongly_regular(parameters = True)
(77, 16, 0, 4)
static MarkstroemGraph()
Return the Markström Graph.
The Markström Graph is a cubic planar graph with no cycles of length 4 nor 8, but containing cycles of
length 16. For more information, see the Wolfram page about the Markström Graph.
EXAMPLES:
sage: g = graphs.MarkstroemGraph()
sage: g.order()
24
sage: g.size()
36
sage: g.is_planar()
True
sage: g.is_regular(3)
True
sage: g.subgraph_search(graphs.CycleGraph(4)) is None
True
sage: g.subgraph_search(graphs.CycleGraph(8)) is None
True
sage: g.subgraph_search(graphs.CycleGraph(16))
Subgraph of (Markstroem Graph): Graph on 16 vertices
static MathonPseudocyclicMergingGraph(M, t)
Mathon’s merging of classes in a pseudo-cyclic 3-class association scheme
Construct strongly regular graphs from p.97 of [BL1984].
INPUT:
• M – the list of matrices in a pseudo-cyclic 3-class association scheme. The identity matrix must be the
first entry.
• t (integer) – the number of the graph, from 0 to 2.
See also:
• is_muzychuk_S6()
• is_mathon_PC_srg()
EXAMPLES:
Using default G and L.
sage: G=MathonPseudocyclicStronglyRegularGraph(1); G
Mathon's PC SRG on 45 vertices: Graph on 45 vertices
sage: G.is_strongly_regular(parameters=True)
(45, 22, 10, 11)
sage: G = graphs.PaleyGraph(9)
sage: a = G.automorphism_group(partition=[sorted(G)])
sage: it = (x for x in a.normal_subgroups() if x.order() == 9)
sage: subg = next(iter(it))
sage: r = [matrix(libgap.PermutationMat(libgap(z), 9).sage())
....: for z in subg]
sage: ff = list(map(lambda y: (y[0]-1,y[1]-1),
....: Permutation(map(lambda x: 1+r.index(x^-1), r)).cycle_
˓→tuples()[1:]))
sage: G.relabel(range(9))
sage: G3x3=graphs.MathonPseudocyclicStronglyRegularGraph(2,G=G,L=L)
sage: G3x3.is_strongly_regular(parameters=True)
(441, 220, 109, 110)
sage: G3x3.automorphism_group(algorithm="bliss").order() # optional - bliss
27
sage: G9=graphs.MathonPseudocyclicStronglyRegularGraph(2)
sage: G9.is_strongly_regular(parameters=True)
(441, 220, 109, 110)
sage: G9.automorphism_group(algorithm="bliss").order() # optional - bliss
9
static MathonStronglyRegularGraph(t)
Return one of Mathon’s graphs on 784 vertices.
INPUT:
• t – integer; the number of the graph, from 0 to 2
EXAMPLES:
static McGeeGraph(embedding=2)
Return the McGee Graph.
See the Wikipedia article McGee_graph.
INPUT:
• embedding – integer (default: 2); two embeddings are available, and can be selected by setting
embedding to 1 or 2
EXAMPLES:
sage: g = graphs.McGeeGraph()
sage: g.order()
24
sage: g.size()
36
sage: g.girth()
7
sage: g.diameter()
4
sage: g.show()
sage: graphs.McGeeGraph(embedding=1).show() # long time
static McLaughlinGraph()
Return the McLaughlin Graph.
The McLaughlin Graph is the unique strongly regular graph of parameters (275, 112, 30, 56).
For more information on the McLaughlin Graph, see its web page on Andries Brouwer’s website which
gives the definition that this method implements.
Note: To create this graph you must have the gap_packages spkg installed.
EXAMPLES:
static MeredithGraph()
Return the Meredith Graph.
The Meredith Graph is a 4-regular 4-connected non-hamiltonian graph. For more information on the
Meredith Graph, see the Wikipedia article Meredith_graph.
EXAMPLES:
sage: g = graphs.MeredithGraph()
sage: g.is_regular(4)
True
sage: g.order()
70
sage: g.size()
140
sage: g.radius()
7
sage: g.diameter()
8
sage: g.girth()
4
sage: g.chromatic_number()
3
sage: g.is_hamiltonian() # long time
False
static MoebiusKantorGraph()
Return a Möbius-Kantor Graph.
A Möbius-Kantor graph is a cubic symmetric graph. (See also the Heawood graph). It has 16 nodes and 24
edges. It is nonplanar and Hamiltonian. It has diameter 4, girth 6, and chromatic number 2. It is identical
to the Generalized Petersen graph, P[8, 3].
For more details, see Möbius-Kantor Graph - from Wolfram MathWorld.
PLOTTING: See the plotting section for the generalized Petersen graphs.
EXAMPLES:
sage: MK = graphs.MoebiusKantorGraph()
sage: MK
Moebius-Kantor Graph: Graph on 16 vertices
sage: MK.graph6_string()
'OhCGKE?O@?ACAC@I?Q_AS'
sage: (graphs.MoebiusKantorGraph()).show() # long time
static MoserSpindle()
Return the Moser spindle.
For more information, see the Wikipedia article Moser_spindle.
EXAMPLES:
The Moser spindle is a planar graph having 7 vertices and 11 edges:
sage: G = graphs.MoserSpindle(); G
Moser spindle: Graph on 7 vertices
sage: G.is_planar()
True
sage: G.order()
7
sage: G.size()
11
sage: G.is_hamiltonian()
True
sage: G.radius()
2
sage: G.diameter()
2
sage: G.girth()
3
The Moser spindle can be drawn in the plane as a unit distance graph, has chromatic number 4, and its
automorphism group is isomorphic to the dihedral group 𝐷4 :
Some details on Φ and Σ are as follows. Let 𝐿 be the complete graph on 𝑀 := {0, ..., 𝑚 − 1} with the
matching {(2𝑖, 2𝑖 + 1)|𝑖 = 0, ..., 𝑚/2} removed. Then one arbitrarily chooses injections Φ𝑖 from the edges
of 𝐿 on 𝑖 ∈ 𝑀 into sets of parallel classes of affine 𝑑-dimensional designs; our implementation uses the
designs of hyperplanes in 𝑑-dimensional affine geometries over 𝐺𝐹 (𝑛). Finally, for each edge 𝑖𝑗 of 𝐿 one
arbitrarily chooses bijections Σ𝑖𝑗 between Φ𝑖 and Φ𝑗 . More details, in particular how these choices lead to
non-isomorphic graphs, are in [Muz2007].
INPUT:
• n (integer)– a prime power
• d (integer)– must be odd if 𝑛 is odd
• Phi is an optional parameter of the construction; it must be either
– ‘fixed’– this will generate fixed default Φ𝑖 , for 𝑖 ∈ 𝑀 , or
– ‘random’– Φ𝑖 are generated at random, or
– A dictionary describing the functions Φ𝑖 ; for 𝑖 ∈ 𝑀 , Phi[(i, T)] in 𝑀 , for each edge T of 𝐿 on 𝑖.
Also, each Φ𝑖 must be injective.
• Sigma is an optional parameter of the construction; it must be either
– ‘fixed’– this will generate a fixed default Σ, or
– ‘random’– Σ is generated at random.
• verbose (Boolean)– default is False. If True, print progress information
See also:
• is_muzychuk_S6()
Todo: Implement the possibility to explicitly supply the parameter Σ of the construction.
EXAMPLES:
• relabel Relabel the vertices so their names are the integers range(n) where n is the number of
vertices in the graph.
EXAMPLES:
The Mycielski graph 𝑀𝑘 is triangle-free and has chromatic number equal to 𝑘.
sage: g = graphs.MycielskiGraph(5)
sage: g.is_triangle_free()
True
sage: g.chromatic_number()
5
sage: g = graphs.MycielskiGraph(4)
sage: g.is_isomorphic(graphs.GrotzschGraph())
True
REFERENCES:
• [1] Weisstein, Eric W. “Mycielski Graph.” From MathWorld–A Wolfram Web Resource. http:
//mathworld.wolfram.com/MycielskiGraph.html
static MycielskiStep(g)
Perform one iteration of the Mycielski construction.
See the documentation for MycielskiGraph which uses this method. We expose it to all users in case they
may find it useful.
EXAMPLE. One iteration of the Mycielski step applied to the 5-cycle yields a graph isomorphic to the
Grotzsch graph
sage: g = graphs.CycleGraph(5)
sage: h = graphs.MycielskiStep(g)
sage: h.is_isomorphic(graphs.GrotzschGraph())
True
static NKStarGraph(n, k)
Returns the (n,k)-star graph.
The vertices of the (n,k)-star graph are the set of all arrangements of n symbols into labels of length k. There
are two adjacency rules for the (n,k)-star graph. First, two vertices are adjacent if one can be obtained from
the other by swapping the first symbol with another symbol. Second, two vertices are adjacent if one can
be obtained from the other by swapping the first symbol with an external symbol (a symbol not used in the
original label).
INPUT:
• n
• k
EXAMPLES:
sage: g = graphs.NKStarGraph(4,2)
sage: g.plot() # long time
Graphics object consisting of 31 graphics primitives
REFERENCES:
• Wei-Kuo, Chiang, and Chen Rong-Jaye. “The (n, k)-star graph: A generalized star graph.” Information
Processing Letters 56, no. 5 (December 8, 1995): 259-264.
AUTHORS:
• Michael Yurko (2009-09-01)
static NStarGraph(n)
Returns the n-star graph.
The vertices of the n-star graph are the set of permutations on n symbols. There is an edge between two
vertices if their labels differ only in the first and one other position.
INPUT:
• n
EXAMPLES:
sage: g = graphs.NStarGraph(4)
sage: g.plot() # long time
Graphics object consisting of 61 graphics primitives
REFERENCES:
• S.B. Akers, D. Horel and B. Krishnamurthy, The star graph: An attractive alternative to the previous
n-cube. In: Proc. Internat. Conf. on Parallel Processing (1987), pp. 393–400.
AUTHORS:
• Michael Yurko (2009-09-01)
static NauruGraph(embedding=2)
Return the Nauru Graph.
See the Wikipedia article Nauru_graph.
INPUT:
• embedding – integer (default: 2); two embeddings are available, and can be selected by setting
embedding to 1 or 2
EXAMPLES:
sage: g = graphs.NauruGraph()
sage: g.order()
24
sage: g.size()
36
sage: g.girth()
6
sage: g.diameter()
4
sage: g.show()
sage: graphs.NauruGraph(embedding=1).show() # long time
• 𝑚 even: assume further that 𝑞 = 2 or 3. Returns the graph of the points (in the underlying projective
space) 𝑥 satisfying 𝐹 (𝑥) = 1, with adjacency given by orthogonality w.r.t. 𝐹 . Parameter perp is
ignored.
• 𝑚 odd: if perp is not None, then we assume that 𝑞 = 5 and return the graph of the points 𝑥 satisfying
𝐹 (𝑥) = ±1 if sign="+", respectively 𝐹 (𝑥) ∈ {2, 3} if sign="-", with adjacency given by orthog-
onality w.r.t. 𝐹 (cf. Sect 7.D of [BL1984]). Otherwise return the graph of nongenerate hyperplanes
of type sign, adjacent whenever the intersection is degenerate (cf. Sect. 7.C of [BL1984]). Note that
for 𝑞 = 2 one will get a complete graph.
For more information, see Sect. 9.9 of [BH2012] and [BL1984]. Note that the page of Andries Brouwer’s
website uses different notation.
INPUT:
• m – integer; half the dimension of the underlying vectorspace
• q – a power of a prime number, the size of the underlying field
• sign – string (default: "+"); must be either "+" or "-"
EXAMPLES:
𝑁 𝑂− (4, 2) is isomorphic to Petersen graph:
sage: g=graphs.NonisotropicOrthogonalPolarGraph(4,2,'-'); g
NO^-(4, 2): Graph on 10 vertices
sage: g.is_strongly_regular(parameters=True)
(10, 3, 0, 1)
sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,2,'-')
sage: g.is_strongly_regular(parameters=True)
(36, 15, 6, 6)
sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,2,'+'); g
NO^+(6, 2): Graph on 28 vertices
sage: g.is_strongly_regular(parameters=True)
(28, 15, 6, 10)
𝑁 𝑂+ (8, 2):
sage: g=graphs.NonisotropicOrthogonalPolarGraph(8,2,'+')
sage: g.is_strongly_regular(parameters=True)
(120, 63, 30, 36)
sage: graphs.NonisotropicOrthogonalPolarGraph(5,5,perp=1).is_strongly_
˓→regular(parameters=True) # long time
(325, 60, 15, 10)
sage: graphs.NonisotropicOrthogonalPolarGraph(5,5,'-',perp=1).is_strongly_
˓→regular(parameters=True) # long time
(300, 65, 10, 15)
Wilbrink’s graphs:
sage: g=graphs.NonisotropicOrthogonalPolarGraph(5,4,'+')
sage: g.is_strongly_regular(parameters=True)
(136, 75, 42, 40)
sage: g=graphs.NonisotropicOrthogonalPolarGraph(5,4,'-')
sage: g.is_strongly_regular(parameters=True)
(120, 51, 18, 24)
sage: g=graphs.NonisotropicOrthogonalPolarGraph(7,4,'+'); g # not tested (long␣
˓→time)
static NonisotropicUnitaryPolarGraph(m, q)
Return the Graph 𝑁 𝑈 (𝑚, 𝑞).
This returns the graph on nonisotropic, with respect to a nondegenerate Hermitean form, points of the
(𝑚 − 1)-dimensional projective space over 𝐹𝑞 , with points adjacent whenever they lie on a tangent (to the
set of isotropic points) line. For more information, see Sect. 9.9 of [BH2012] and series C14 in [Hub1975].
INPUT:
• m,q – integers; 𝑞 must be a prime power
EXAMPLES:
sage: g=graphs.NonisotropicUnitaryPolarGraph(5,2); g
NU(5, 2): Graph on 176 vertices
sage: g.is_strongly_regular(parameters=True)
(176, 135, 102, 108)
𝐶 contains 𝑞(𝑞 − 1)2 /2 words without 0 entries. The subgraph of the strongly regular graph of 𝐶 induced
on the latter words is also strongly regular, assuming 𝑞 > 4. This is a construction due to A.E.Brouwer
[Bro2016], and leads to graphs with parameters also given by a construction in [HHL2009]. According to
[Bro2016], these two constructions are likely to produce isomorphic graphs.
INPUT:
• q – a power of two
• hyperoval – a hyperoval (i.e. a complete 2-arc; a set of points in the plane meeting every line in 0 or
2 points) in 𝑃 𝐺(2, 𝑞) over the field field. Each point of hyperoval must be a length 3 vector over
field with 1st non-0 coordinate equal to 1. By default, hyperoval and field are not specified, and
constructed on the fly. In particular, hyperoval we build is the classical one, i.e. a conic with the
point of intersection of its tangent lines.
• field – an instance of a finite field of order 𝑞, must be provided if hyperoval is provided.
• check_hyperoval – boolean (default: True); whether to check hyperoval for correctness or not
See also:
• is_nowhere0_twoweight()
EXAMPLES:
using the built-in construction:
sage: g=graphs.Nowhere0WordsTwoWeightCodeGraph(8); g
Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices
sage: g.is_strongly_regular(parameters=True)
(196, 60, 14, 20)
sage: g=graphs.Nowhere0WordsTwoWeightCodeGraph(16) # not tested (long time)
sage: g.is_strongly_regular(parameters=True) # not tested (long time)
(1800, 728, 268, 312)
sage: F=GF(8)
sage: O=[vector(F,(0,0,1)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F]
sage: g=graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F); g
Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices
sage: g.is_strongly_regular(parameters=True)
(196, 60, 14, 20)
static OctahedralGraph()
Return an Octahedral graph (with 6 nodes).
The regular octahedron is an 8-sided polyhedron with triangular faces. The octahedral graph corresponds
to the connectivity of the vertices of the octahedron. It is the line graph of the tetrahedral graph. The
octahedral is symmetric, so the spring-layout algorithm will be very effective for display.
PLOTTING: The Octahedral graph should be viewed in 3 dimensions. We choose to use a planar embed-
ding of the graph. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a argument
will be added to select the desired layout.
EXAMPLES:
Construct and show an Octahedral graph:
sage: g = graphs.OctahedralGraph()
sage: g.show() # long time
Create several octahedral graphs in a Sage graphics array They will be drawn differently due to the use of
the spring-layout algorithm:
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.OctahedralGraph()
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
static OddGraph(n)
Returns the Odd Graph with parameter 𝑛.
The Odd Graph with parameter 𝑛 is defined as the Kneser Graph with parameters 2𝑛−1, 𝑛−1. Equivalently,
the Odd Graph is the graph whose vertices are the 𝑛 − 1-subsets of [0, 1, . . . , 2(𝑛 − 1)], and such that two
vertices are adjacent if their corresponding sets are disjoint.
For example, the Petersen Graph can be defined as the Odd Graph with parameter 3.
EXAMPLES:
sage: OG = graphs.OddGraph(3)
sage: sorted(OG.vertex_iterator(), key=str)
[{1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 3}, {2, 4}, {2, 5},
{3, 4}, {3, 5}, {4, 5}]
sage: P = graphs.PetersenGraph()
sage: P.is_isomorphic(OG)
True
As transversal designs and orthogonal arrays (OA for short) are equivalent objects, this graph can also be
built from the blocks of an 𝑂𝐴(𝑘, 𝑛), two of them being adjacent if one of their coordinates match.
For more information on these graphs, see Andries Brouwer’s page on Orthogonal Array graphs.
Warning:
• Brouwer’s website uses the notation 𝑂𝐴(𝑛, 𝑘) instead of 𝑂𝐴(𝑘, 𝑛)
• For given parameters 𝑘 and 𝑛 there can be many 𝑂𝐴(𝑘, 𝑛) : the graphs returned are not uniquely
defined by their parameters (see the examples below).
• If the function is called only with the parameter k and n the results might be different with two
versions of Sage, or even worse : some could not be available anymore.
See also:
sage.combinat.designs.orthogonal_arrays
INPUT:
• k,n (integers)
• OA – An orthogonal array. If set to None (default) then orthogonal_array() is called to compute
an 𝑂𝐴(𝑘, 𝑛).
EXAMPLES:
sage: G = graphs.OrthogonalArrayBlockGraph(5,5); G
OA(5,5): Graph on 25 vertices
sage: G.is_strongly_regular(parameters=True)
(25, 20, 15, 20)
sage: G = graphs.OrthogonalArrayBlockGraph(4,10); G
(continues on next page)
Two graphs built from different orthogonal arrays are also different:
sage: k=4;n=10
sage: OAa = designs.orthogonal_arrays.build(k,n)
sage: OAb = [[(x+1)%n for x in R] for R in OAa]
sage: set(map(tuple,OAa)) == set(map(tuple,OAb))
False
sage: Ga = graphs.OrthogonalArrayBlockGraph(k,n,OAa)
sage: Gb = graphs.OrthogonalArrayBlockGraph(k,n,OAb)
sage: Ga == Gb
False
As OAb was obtained from OAa by a relabelling the two graphs are isomorphic:
sage: Ga.is_isomorphic(Gb)
True
But there are examples of 𝑂𝐴(𝑘, 𝑛) for which the resulting graphs are not isomorphic:
sage: oa0 = [[0, 0, 1], [0, 1, 3], [0, 2, 0], [0, 3, 2],
....: [1, 0, 3], [1, 1, 1], [1, 2, 2], [1, 3, 0],
....: [2, 0, 0], [2, 1, 2], [2, 2, 1], [2, 3, 3],
....: [3, 0, 2], [3, 1, 0], [3, 2, 3], [3, 3, 1]]
sage: oa1 = [[0, 0, 1], [0, 1, 0], [0, 2, 3], [0, 3, 2],
....: [1, 0, 3], [1, 1, 2], [1, 2, 0], [1, 3, 1],
....: [2, 0, 0], [2, 1, 1], [2, 2, 2], [2, 3, 3],
....: [3, 0, 2], [3, 1, 3], [3, 2, 1], [3, 3, 0]]
sage: g0 = graphs.OrthogonalArrayBlockGraph(3,4,oa0)
sage: g1 = graphs.OrthogonalArrayBlockGraph(3,4,oa1)
sage: g0.is_isomorphic(g1)
False
sage: g0.spectrum()
[9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3]
sage: g1.spectrum()
[9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3]
Note that the graph g0 is actually isomorphic to the affine polar graph 𝑉 𝑂+ (4, 2):
sage: graphs.AffineOrthogonalPolarGraph(4,2,'+').is_isomorphic(g0)
True
static OrthogonalDualPolarGraph(e, d, q)
Return the dual polar graph on 𝐺𝑂𝑒 (𝑛, 𝑞) of diameter 𝑑.
The value of 𝑛 is determined by 𝑑 and 𝑒.
The graph is distance-regular with classical parameters (𝑑, 𝑞, 0, 𝑞 𝑒 ).
INPUT:
• e – integer; type of the orthogonal polar space to consider; must be −1, 0 or 1.
• d – integer; diameter of the graph
• q – integer; prime power; order of the finite field over which to build the polar space
EXAMPLES:
sage: G = graphs.OrthogonalDualPolarGraph(1,3,2)
sage: G.is_distance_regular(True)
([7, 6, 4, None], [None, 1, 3, 7])
sage: G = graphs.OrthogonalDualPolarGraph(0,3,3) # long time
sage: G.is_distance_regular(True) # long time
([39, 36, 27, None], [None, 1, 4, 13])
sage: G.order() # long time
1120
REFERENCES:
See [BCN1989] pp. 274-279 or [VDKT2016] p. 22.
static OrthogonalPolarGraph(m, q, sign='+')
Return the Orthogonal Polar Graph 𝑂𝜖 (𝑚, 𝑞).
For more information on Orthogonal Polar graphs, see the page of Andries Brouwer’s website.
INPUT:
• m,q – integers; 𝑞 must be a prime power
• sign – string (default: "+"); must be "+" or "-" if 𝑚 is even, "+" (default) otherwise
EXAMPLES:
sage: G = graphs.OrthogonalPolarGraph(6,3,"+"); G
Orthogonal Polar Graph O^+(6, 3): Graph on 130 vertices
sage: G.is_strongly_regular(parameters=True)
(130, 48, 20, 16)
sage: G = graphs.OrthogonalPolarGraph(6,3,"-"); G
Orthogonal Polar Graph O^-(6, 3): Graph on 112 vertices
sage: G.is_strongly_regular(parameters=True)
(112, 30, 2, 10)
sage: G = graphs.OrthogonalPolarGraph(5,3); G
Orthogonal Polar Graph O(5, 3): Graph on 40 vertices
sage: G.is_strongly_regular(parameters=True)
(40, 12, 2, 4)
sage: G = graphs.OrthogonalPolarGraph(8,2,"+"); G
Orthogonal Polar Graph O^+(8, 2): Graph on 135 vertices
sage: G.is_strongly_regular(parameters=True)
(135, 70, 37, 35)
sage: G = graphs.OrthogonalPolarGraph(8,2,"-"); G
Orthogonal Polar Graph O^-(8, 2): Graph on 119 vertices
sage: G.is_strongly_regular(parameters=True)
(119, 54, 21, 27)
static PaleyGraph(q)
Paley graph with 𝑞 vertices
sage: G = graphs.PaleyGraph(9); G
Paley graph with parameter 9: Graph on 9 vertices
sage: G.is_regular()
True
sage: G.is_self_complementary()
True
static PappusGraph()
Return the Pappus graph, a graph on 18 vertices.
The Pappus graph is cubic, symmetric, and distance-regular.
EXAMPLES:
sage: G = graphs.PappusGraph()
sage: G.show() # long time
sage: L = graphs.LCFGraph(18, [5,7,-7,7,-7,-5], 3)
sage: L.show() # long time
sage: G.is_isomorphic(L)
True
static PasechnikGraph(n)
Pasechnik strongly regular graph on (4𝑛 − 1)2 vertices
A strongly regular graph with parameters of the orthogonal array graph OrthogonalArrayBlockGraph(),
also known as pseudo Latin squares graph 𝐿2𝑛−1 (4𝑛 − 1), constructed from a skew Hadamard matrix of
order 4𝑛 following [Pas1992].
See also:
• is_orthogonal_array_block_graph()
EXAMPLES:
sage: graphs.PasechnikGraph(4).is_strongly_regular(parameters=True)
(225, 98, 43, 42)
sage: graphs.PasechnikGraph(5).is_strongly_regular(parameters=True) # long time
(361, 162, 73, 72)
sage: graphs.PasechnikGraph(9).is_strongly_regular(parameters=True) # not␣
˓→tested
• pos – string (default: None); indicates the embedding to use between ‘circle’, ‘line’ or the default
algorithm. See the plotting section below for more detail.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, the graph may be drawn in one of two ways: The ‘line’ argument will draw the graph in
a horizontal line (left to right) if there are less than 11 nodes. Otherwise the ‘line’ argument will append
horizontal lines of length 10 nodes below, alternating left to right and right to left. The ‘circle’ argument
will cause the graph to be drawn in a cycle-shape, with the first node at the top and then about the circle
in a clockwise manner. By default (without an appropriate string argument) the graph will be drawn as a
‘circle’ if 10 < 𝑛 < 41 and as a ‘line’ for all other 𝑛.
EXAMPLES: Show default drawing by size: ‘line’: 𝑛 ≤ 10
sage: p = graphs.PathGraph(10)
sage: p.show() # long time
sage: q = graphs.PathGraph(25)
sage: q.show() # long time
‘line’: 𝑛 ≥ 41
sage: r = graphs.PathGraph(55)
sage: r.show() # long time
sage: s = graphs.PathGraph(5,'circle')
sage: s.show() # long time
static PerkelGraph()
Return the Perkel Graph.
The Perkel Graph is a 6-regular graph with 57 vertices and 171 edges. It is the unique distance-regular graph
with intersection array (6, 5, 2; 1, 1, 3). For more information, see the Wikipedia article Perkel_graph or
https://www.win.tue.nl/~aeb/graphs/Perkel.html.
EXAMPLES:
sage: g = graphs.PerkelGraph(); g
Perkel Graph: Graph on 57 vertices
sage: g.is_distance_regular(parameters=True)
([6, 5, 2, None], [None, 1, 1, 3])
vertex in this graph for each element from 1 to 𝑛, two vertices 𝑖, 𝑗 being adjacent if the segments
𝑖 and 𝑗 cross each other.
The set of edges of the permutation graph can thus be identified with the set of inversions of the inverse of
the given permutation 𝜎.
A more general notion of permutation graph can be defined as follows: If 𝑆 is a set, and (𝑎1 , 𝑎2 , . . . , 𝑎𝑛 )
and (𝑏1 , 𝑏2 , . . . , 𝑏𝑛 ) are two lists of elements of 𝑆, each of which lists contains every element of 𝑆 exactly
once, then the permutation graph defined by these two lists is the graph on the vertex set 𝑆 in which two
vertices 𝑖 and 𝑗 are connected by an edge if and only if the order in which these vertices appear in the
list (𝑎1 , 𝑎2 , . . . , 𝑎𝑛 ) is the opposite of the order in which they appear in the list (𝑏1 , 𝑏2 , . . . , 𝑏𝑛 ). When
(𝑎1 , 𝑎2 , . . . , 𝑎𝑛 ) = (1, 2, . . . , 𝑛), this graph is the permutation graph of the permutation (𝑏1 , 𝑏2 , . . . , 𝑏𝑛 ) ∈
𝑆𝑛 . Notice that 𝑆 does not have to be a set of integers here, but can be a set of strings, tuples, or anything
else. We can still use the above visual description to construct the permutation graph, but now we have to
mark points 𝑎1 , 𝑎2 , . . . , 𝑎𝑛 from left to right on the first horizontal line and points 𝑏1 , 𝑏2 , . . . , 𝑏𝑛 from left
to right on the second horizontal line.
INPUT:
• second_permutation – the unique permutation/list defining the graph, or the second of the two (if
the graph is to be built from two permutations/lists).
• first_permutation (optional) – the first of the two permutations/lists from which the graph should
be built, if it is to be built from two permutations/lists.
When first_permutation is None (default), it is set to be equal to
sorted(second_permutation), which yields the expected ordering when the elements of
the graph are integers.
See also:
EXAMPLES:
sage: p = Permutations(5).random_element()
sage: PG = graphs.PermutationGraph(p)
sage: edges = PG.edges(sort=True, labels=False)
sage: set(edges) == set(p.inverse().inversions())
True
sage: PG = graphs.PermutationGraph([3,4,5,1,2])
sage: sorted(PG.edges(sort=True))
[(1, 3, None),
(1, 4, None),
(1, 5, None),
(2, 3, None),
(2, 4, None),
(2, 5, None)]
sage: PG = graphs.PermutationGraph([3,4,5,1,2], [1,4,2,5,3])
sage: sorted(PG.edges(sort=True))
(continues on next page)
sage: graphs.PermutationGraph([]).edges(sort=True)
[]
sage: graphs.PermutationGraph([], []).edges(sort=True)
[]
static PetersenGraph()
Return the Petersen Graph.
The Petersen Graph is a named graph that consists of 10 vertices and 15 edges, usually drawn as a five-point
star embedded in a pentagon.
The Petersen Graph is a common counterexample. For example, it is not Hamiltonian.
PLOTTING: See the plotting section for the generalized Petersen graphs.
EXAMPLES: We compare below the Petersen graph with the default spring-layout versus a planned posi-
tion dictionary of (𝑥, 𝑦) tuples:
static PoussinGraph()
Return the Poussin Graph.
For more information on the Poussin Graph, see its corresponding Wolfram page.
EXAMPLES:
sage: g = graphs.PoussinGraph()
sage: g.order()
15
sage: g.is_planar()
True
The Queen Graph can be obtained from the Rook Graph and the Bishop Graph:
sage: G = graphs.RandomBarabasiAlbert(6,2)
sage: G.order(), G.size()
(6, 8)
sage: G.degree_sequence() # random
[4, 3, 3, 2, 2, 2]
sage: ba = graphs.RandomBarabasiAlbert(12,3)
sage: ba.show() # long time
sage: g = []
sage: j = []
sage: for i in range(1,10):
....: k = graphs.RandomBarabasiAlbert(i+3, 3)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
EXAMPLES:
INPUT:
• m – integer; number of blocks (at least one).
• k – integer; minimum number of vertices of a block (at least two).
• kmax – integer (default: None) By default, each block has 𝑘 vertices. When the parameter 𝑘𝑚𝑎𝑥 is
specified (with 𝑘𝑚𝑎𝑥 ≥ 𝑘), the number of vertices of each block is randomly chosen between 𝑘 and
𝑘𝑚𝑎𝑥.
• incidence_structure – boolean (default: False) when set to True, the incidence structure of the
graphs is returned instead of the graph itself, that is the list of the lists of vertices in each block. This
is useful for the creation of some hypergraphs.
• seed – a random.Random seed or a Python int for the random number generator (default: None)
OUTPUT:
A Graph when incidence_structure==False (default), and otherwise an incidence structure.
EXAMPLES:
A block graph with a single block is a clique:
sage: B = graphs.RandomBlockGraph(1, 4)
sage: B.is_clique()
True
sage: B = graphs.RandomBlockGraph(10, 2)
sage: B.is_tree()
True
sage: m, k = 6, 4
sage: B = graphs.RandomBlockGraph(m, k)
sage: B.order() == m*(k-1)+1
True
sage: m, k = 6, 4
sage: IS = graphs.RandomBlockGraph(m, k, incidence_structure=True)
sage: from sage.combinat.designs.incidence_structures import IncidenceStructure
sage: IncidenceStructure(IS)
Incidence structure with 19 points and 6 blocks
sage: m*(k-1)+1
19
Note: The tolerance representation used to create the graph can be recovered using get_vertex() or
get_vertices().
INPUT:
sage: g = graphs.RandomBoundedToleranceGraph(8)
sage: g.clique_number() == g.chromatic_number()
True
EXAMPLES:
See also:
• growing_subtrees()
• connecting_nodes()
• pruned_tree()
• Wikipedia article Chordal_graph
• is_chordal()
• IntersectionGraph()
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.RandomGNM(i+3, i^2-i)
....: g.append(k)
sage: for i in range(3):
(continues on next page)
sage: set_random_seed(0)
sage: graphs.RandomGNP(6, .4).edges(sort=true, labels=False)
[(0, 3), (1, 2), (2, 3), (2, 4)]
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.RandomGNP(i+3,.43)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
(continues on next page)
REFERENCE:
[HK2002a]
static RandomIntervalGraph(n, seed=None)
Returns a random interval graph.
An interval graph is built from a list (𝑎𝑖 , 𝑏𝑖 )1≤𝑖≤𝑛 of intervals : to each interval of the list is associated one
vertex, two vertices being adjacent if the two corresponding intervals intersect.
A random interval graph of order 𝑛 is generated by picking random values for the (𝑎𝑖 , 𝑏𝑗 ), each of the two
coordinates being generated from the uniform distribution on the interval [0, 1].
This definitions follows [BF2001].
Note: The vertices are named 0, 1, 2, and so on. The intervals used to create the graph are saved with the
graph and can be recovered using get_vertex() or get_vertices().
INPUT:
• n – integer; the number of vertices in the random graph
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
As for any interval graph, the chromatic number is equal to the clique number
sage: g = graphs.RandomIntervalGraph(8)
sage: g.clique_number() == g.chromatic_number()
True
REFERENCE:
[NWS2002]
static RandomRegular(d, n, seed=None)
Return a random 𝑑-regular graph on 𝑛 vertices, or False on failure.
Since every edge is incident to two vertices, 𝑛 × 𝑑 must be even.
INPUT:
• d – degree
• n – number of vertices
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
We check that a random graph with 8 nodes each of degree 3 is 3-regular:
sage: G = graphs.RandomRegular(3, 8)
sage: G.is_regular(k=3)
True
sage: G.degree_histogram()
[0, 0, 0, 8]
REFERENCES:
• [KV2003]
• [SW1999]
static RandomRegularBipartite(n1, n2, d1, set_position=False, seed=None)
Return a random regular bipartite graph on 𝑛1 + 𝑛2 vertices.
The bipartite graph has 𝑛1*𝑑1 edges. Hence, 𝑛2 must divide 𝑛1*𝑑1. Each vertex of the set of cardinality 𝑛1
has degree 𝑑1 (which can be at most 𝑛2) and each vertex in the set of cardinality 𝑛2 has degree (𝑛1*𝑑1)/𝑛2.
The bipartite graph has no multiple edges.
This generator implements an algorithm inspired by that of [MW1990] for the uniform generation of random
regular bipartite graphs. It performs well when 𝑑1 = 𝑜(𝑛21/3 ) or (𝑛2 − 𝑑1 = 𝑜(𝑛21/3 )). In other cases,
the running time can be huge. Note that the currently implemented algorithm does not generate uniformly
random graphs.
INPUT:
• n1, n2 – number of vertices in each side
• d1 – degree of the vertices in the set of cardinality 𝑛1.
• set_position – boolean (default False); if set to True, we assign positions to the vertices so that
the set of cardinality 𝑛1 is on the line 𝑦 = 1 and the set of cardinality 𝑛2 is on the line 𝑦 = 0.
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
sage: g = graphs.RandomRegularBipartite(4, 6, 3)
sage: g.order(), g.size()
(10, 12)
sage: set(g.degree())
{2, 3}
sage: G = graphs.RandomShell([(10,20,0.8),(20,40,0.8)])
sage: G.order(), G.size()
(continues on next page)
Note: The vertices are named 0, 1, . . . , n-1. The tolerance representation used to create the graph is saved
with the graph and can be recovered using get_vertex() or get_vertices().
INPUT:
• n – number of vertices of the random graph
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
Every tolerance graph is perfect. Hence, the chromatic number is equal to the clique number
sage: g = graphs.RandomToleranceGraph(8)
sage: g.clique_number() == g.chromatic_number()
True
sage: G = graphs.RandomTree(10)
sage: G.is_tree()
True
sage: G.show() # long time
INPUT:
• n – number of vertices
• gamma – exponent of power law distribution
• tries – number of attempts to adjust sequence to make a tree
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
We check that the generated graph is a tree:
sage: G = graphs.RandomTreePowerlaw(10, 3)
sage: G.is_tree()
True
sage: G.order(), G.size()
(10, 9)
sage: G = graphs.RandomTreePowerlaw(15, 2)
sage: if G:
....: G.show() # random output, long time
See also:
triangulations(), RandomTwoSphere().
EXAMPLES:
sage: G = graphs.RingedTree(5)
sage: P = G.plot(vertex_labels=False, vertex_size=10)
sage: P.show() # long time
sage: G.vertices(sort=True)
['', '0', '00', '000', '0000', '0001', '001', '0010', '0011', '01',
'010', '0100', '0101', '011', '0110', '0111', '1', '10', '100',
'1000', '1001', '101', '1010', '1011', '11', '110', '1100', '1101',
'111', '1110', '1111']
static RobertsonGraph()
Return the Robertson graph.
See the Wikipedia article Robertson_graph.
EXAMPLES:
sage: g = graphs.RobertsonGraph()
sage: g.order()
19
sage: g.size()
38
sage: g.diameter()
3
sage: g.girth()
5
sage: g.charpoly().factor()
(x - 4) * (x - 1)^2 * (x^2 + x - 5) * (x^2 + x - 1) * (x^2 - 3)^2 * (x^2 + x -␣
˓→4)^2 * (x^2 + x - 3)^2
sage: g.chromatic_number()
3
sage: g.is_hamiltonian()
True
sage: g.is_vertex_transitive()
False
The 𝑑-dimensional Rook Graph with 𝑑 >= 2 has for vertex set the cells of a 𝑑-dimensional grid with
prescribed dimensions, and each edge corresponds to a legal move by a rook in any of the dimensions.
The Rook’s Graph for an 𝑛 × 𝑚 chessboard may also be defined as the Cartesian product of two complete
graphs 𝐾𝑛 𝐾𝑚 .
INPUT:
• dim_list – iterable (list, set, dict); provides the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1, of the
chessboard
• radius – integer (default: None); by setting the radius to a positive integer, one may decrease the power
of the rook to at most radius steps. When the radius is 1, the resulting graph is a 𝑑-dimensional grid.
• relabel – boolean (default: False); indicates whether the vertices must be relabeled as integers
EXAMPLES:
The (𝑛, 𝑚)-Rook’s Graph is isomorphic to the Cartesian product of two complete graphs:
sage: G.is_isomorphic( H )
True
static RoseWindowGraph(n, a, r)
Return a rose window graph with 2𝑛 nodes.
The rose window graphs is a family of tetravalant graphs introduced in [Wilson2008]. The parameters 𝑛,
𝑎 and 𝑟 are integers such that 𝑛 > 2, 1 ≤ 𝑎, 𝑟 < 𝑛, and 𝑟 ̸= 𝑛/2.
INPUT:
• n – the number of nodes is 2 * 𝑛
• a – integer such that 1 ≤ 𝑎 < 𝑛 determining a-spoke edges
• r – integer such that 1 ≤ 𝑟 < 𝑛 and 𝑟 ̸= 𝑛/2 determining how inner vertices are connected
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, the rose window graphs are displayed as an inner and outer cycle pair, with the first n nodes
drawn on the outer circle. The first (0) node is drawn at the top of the outer-circle, moving counterclockwise
after that. The inner circle is drawn with the (n)th node at the top, then counterclockwise as well. Vertices
in the outer circle are connected in the circular manner, vertices in the inner circle are connected when their
label have difference 𝑟 (mod n). Vertices on the outer rim are connected with the vertices on the inner rim
when they are at the same position and when they are 𝑎 apart.
EXAMPLES:
The vertices of a rose window graph have all degree 4:
sage: G = graphs.RoseWindowGraph(5, 1, 2)
sage: all(G.degree(u) == 4 for u in G)
True
sage: G = graphs.RoseWindowGraph(3, 2, 1)
sage: all(G.degree(u) == 4 for u in G)
True
static SchlaefliGraph()
Return the Schläfli graph.
The Schläfli graph is the only strongly regular graphs of parameters (27, 16, 10, 8) (see [GR2001]).
For more information, see the Wikipedia article Schläfli_graph.
See also:
Graph.is_strongly_regular() – tests whether a graph is strongly regular and/or returns its parameters.
EXAMPLES:
Checking that the method actually returns the Schläfli graph:
sage: S = graphs.SchlaefliGraph()
sage: S.is_strongly_regular(parameters = True)
(27, 16, 10, 8)
sage: S.is_vertex_transitive()
True
The neighborhood of each vertex is isomorphic to the complement of the Clebsch graph:
static ShrikhandeGraph()
Return the Shrikhande graph.
For more information, see the MathWorld article on the Shrikhande graph or the Wikipedia article
Shrikhande_graph.
See also:
Graph.is_strongly_regular() – tests whether a graph is strongly regular and/or returns its parameters.
EXAMPLES:
The Shrikhande graph was defined by S. S. Shrikhande in 1959. It has 16 vertices and 48 edges, and is
strongly regular of degree 6 with parameters (2, 2):
sage: G = graphs.ShrikhandeGraph(); G
Shrikhande graph: Graph on 16 vertices
sage: G.order()
16
sage: G.size()
(continues on next page)
sage: G.is_planar()
False
sage: G.is_hamiltonian()
True
sage: G.is_eulerian()
True
sage: G.radius()
2
sage: G.diameter()
2
sage: G.girth()
3
sage: G.chromatic_number()
4
sage: G.automorphism_group().cardinality()
192
sage: G.characteristic_polynomial().factor()
(x - 6) * (x - 2)^6 * (x + 2)^9
It is a toroidal graph, and its embedding on a torus is dual to an embedding of the Dyck graph (DyckGraph ).
static SierpinskiGasketGraph(n)
Return the Sierpinski Gasket graph of generation 𝑛.
All vertices but 3 have valence 4.
INPUT:
• 𝑛 – an integer
OUTPUT:
a graph 𝑆𝑛 with 3(3𝑛−1 + 1)/2 vertices and 3𝑛 edges, closely related to the famous Sierpinski triangle
fractal.
All these graphs have a triangular shape, and three special vertices at top, bottom left and bottom right.
These are the only vertices of valence 2, all the other ones having valence 4.
The graph 𝑆1 (generation 1) is a triangle.
The graph 𝑆𝑛+1 is obtained from the disjoint union of three copies A,B,C of 𝑆𝑛 by identifying pairs of
vertices: the top vertex of A with the bottom left vertex of B, the bottom right vertex of B with the top
vertex of C, and the bottom left vertex of C with the bottom right vertex of A.
See also:
• HanoiTowerGraph(). There is another family of graphs called Sierpinski graphs, where all vertices
but 3 have valence 3. They are available using graphs.HanoiTowerGraph(3, n).
• GeneralizedSierpinskiGraph()
EXAMPLES:
sage: s4 = graphs.SierpinskiGasketGraph(4); s4
Graph on 42 vertices
sage: s4.size()
81
sage: s4.degree_histogram()
[0, 0, 3, 0, 39]
sage: s4.is_hamiltonian()
True
REFERENCES:
[LLWC2011]
static SimsGewirtzGraph()
Return the Sims-Gewirtz Graph.
This graph is obtained from the Higman Sims graph by considering the graph induced by the vertices at
distance two from the vertices of an (any) edge. It is the only strongly regular graph with parameters 𝑣 = 56,
𝑘 = 10, 𝜆 = 0, 𝜇 = 2
For more information on the Sylvester graph, see https://www.win.tue.nl/~aeb/graphs/Sims-Gewirtz.html
or its Wikipedia article Gewirtz_graph.
See also:
• HigmanSimsGraph().
EXAMPLES:
sage: g = graphs.SimsGewirtzGraph(); g
Sims-Gewirtz Graph: Graph on 56 vertices
sage: g.order()
56
sage: g.size()
280
sage: g.is_strongly_regular(parameters = True)
(56, 10, 0, 2)
static SousselierGraph()
Return the Sousselier Graph.
The Sousselier graph is a hypohamiltonian graph on 16 vertices and 27 edges. For more information, see
Wikipedia article Sousselier_graph or the corresponding French Wikipedia page.
EXAMPLES:
sage: g = graphs.SousselierGraph()
sage: g.order()
16
sage: g.size()
27
sage: g.radius()
2
sage: g.diameter()
3
sage: g.automorphism_group().cardinality()
2
sage: g.is_hamiltonian()
False
sage: g.delete_vertex(g.random_vertex())
sage: g.is_hamiltonian()
True
static SquaredSkewHadamardMatrixGraph(n)
Pseudo-𝑂𝐴(2𝑛, 4𝑛 − 1)-graph from a skew Hadamard matrix of order 4𝑛
A strongly regular graph with parameters of the orthogonal array graph OrthogonalArrayBlockGraph(),
also known as pseudo Latin squares graph 𝐿2𝑛 (4𝑛−1), constructed from a skew Hadamard matrix of order
4𝑛, due to Goethals and Seidel, see [BL1984].
See also:
• is_orthogonal_array_block_graph()
EXAMPLES:
sage: graphs.SquaredSkewHadamardMatrixGraph(4).is_strongly_
˓→regular(parameters=True)
static StarGraph(n)
Return a star graph with 𝑛 + 1 nodes.
A Star graph is a basic structure where one node is connected to all other nodes.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, each star graph will be displayed with the first (0) node in the center, the second node (1) at
the top, with the rest following in a counterclockwise manner. (0) is the node connected to all other nodes.
The star graph is a good opportunity to compare efficiency of filling a position dictionary vs. using the
spring-layout algorithm for plotting. As far as display, the spring-layout should push all other nodes away
from the (0) node, and thus look very similar to this constructor’s positioning.
EXAMPLES:
sage: n = networkx.star_graph(23)
sage: spring23 = Graph(n)
sage: posdict23 = graphs.StarGraph(23)
sage: spring23.show() # long time
sage: posdict23.show() # long time
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.StarGraph(i+3)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
sage: g = []
sage: j = []
sage: for i in range(9):
....: spr = networkx.star_graph(i+3)
....: k = Graph(spr)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
static SuzukiGraph()
Return the Suzuki Graph.
The Suzuki graph has 1782 vertices, and is strongly regular with parameters (1782, 416, 100, 96). Known
as S.15 in [Hub1975].
Note: It takes approximately 50 seconds to build this graph. Do not be too impatient.
EXAMPLES:
static SwitchedSquaredSkewHadamardMatrixGraph(n)
A strongly regular graph in Seidel switching class of 𝑆𝑞𝑢𝑎𝑟𝑒𝑑𝑆𝑘𝑒𝑤𝐻𝑎𝑑𝑎𝑚𝑎𝑟𝑑𝑀 𝑎𝑡𝑟𝑖𝑥𝐺𝑟𝑎𝑝ℎ
A strongly regular graph in the Seidel switching class of the disjoint union of a 1-vertex graph and the
one produced by Pseudo-L_{2n}(4n-1)
In this case, the other possible parameter set of a strongly regular graph in the Seidel switching class of the
latter graph (see [BH2012]) coincides with the set of parameters of the complement of the graph returned
by this function.
See also:
• is_switch_skewhad()
EXAMPLES:
sage: g=graphs.SwitchedSquaredSkewHadamardMatrixGraph(4)
sage: g.is_strongly_regular(parameters=True)
(226, 105, 48, 49)
sage: from sage.combinat.designs.twographs import twograph_descendant
sage: twograph_descendant(g,0).is_strongly_regular(parameters=True)
(225, 112, 55, 56)
sage: twograph_descendant(g.complement(),0).is_strongly_regular(parameters=True)
(225, 112, 55, 56)
static SylvesterGraph()
Return the Sylvester Graph.
This graph is obtained from the Hoffman Singleton graph by considering the graph induced by the vertices
at distance two from the vertices of an (any) edge.
For more information on the Sylvester graph, see https://www.win.tue.nl/~aeb/graphs/Sylvester.html.
See also:
• HoffmanSingletonGraph().
EXAMPLES:
sage: g = graphs.SylvesterGraph(); g
Sylvester Graph: Graph on 36 vertices
sage: g.order()
36
sage: g.size()
90
sage: g.is_regular(k=5)
True
static SymplecticDualPolarGraph(m, q)
Return the Symplectic Dual Polar Graph 𝐷𝑆𝑝(𝑚, 𝑞).
For more information on Symplectic Dual Polar graphs, see [BCN1989] and Sect. 2.3.1 of [Coh1981].
INPUT:
• m,q – integers; 𝑞 must be a prime power, and 𝑚 must be even
EXAMPLES:
sage: g = graphs.SymplecticPolarGraph(6,2)
sage: g.is_strongly_regular(parameters=True)
(63, 30, 13, 15)
(continues on next page)
The parameters of 𝑆𝑝(4, 𝑞) are the same as of 𝑂(5, 𝑞), but they are not isomorphic if 𝑞 is odd:
sage: G = graphs.SymplecticPolarGraph(4,3)
sage: G.is_strongly_regular(parameters=True)
(40, 12, 2, 4)
sage: O=graphs.OrthogonalPolarGraph(5,3)
sage: O.is_strongly_regular(parameters=True)
(40, 12, 2, 4)
sage: O.is_isomorphic(G)
False
sage: graphs.SymplecticPolarGraph(6,4,algorithm="gap").is_strongly_
˓→regular(parameters=True) # not tested (long time)
static SzekeresSnarkGraph()
Return the Szekeres Snark Graph.
The Szekeres graph is a snark with 50 vertices and 75 edges. For more information on this graph, see the
Wikipedia article Szekeres_snark.
EXAMPLES:
sage: g = graphs.SzekeresSnarkGraph()
sage: g.order()
50
sage: g.size()
75
sage: g.chromatic_number()
3
EXAMPLES:
using the built-in construction:
sage: g=graphs.T2starGeneralizedQuadrangleGraph(4); g
T2*(O,4); GQ(3, 5): Graph on 64 vertices
sage: g.is_strongly_regular(parameters=True)
(64, 18, 2, 6)
sage: g=graphs.T2starGeneralizedQuadrangleGraph(4,dual=True); g
T2*(O,4)*; GQ(5, 3): Graph on 96 vertices
sage: g.is_strongly_regular(parameters=True)
(96, 20, 4, 4)
sage: F=GF(4,'b')
sage: O=[vector(F,(0,0,0,1)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x␣
˓→in F]
static TabacjnGraph(n, a, b, r)
Return a Tabačjn graph with 2𝑛 nodes.
The Tabačjn graphs is a family of pentavalent bicirculants graphs proposed in [AHKOS2014] as a gen-
eralization of generalized Petersen graphs. The parameters 𝑛, 𝑎, 𝑏, 𝑟 are integers such that 𝑛 ≥ 3,
1 ≤ 𝑎, 𝑏, 𝑟 ≤ 𝑛 − 1, with 𝑎 ̸= 𝑏 and 𝑟 ̸= 𝑛/2.
INPUT:
• n – the number of nodes is 2 * 𝑛
• a – integer such that 0 < 𝑎 < 𝑛 and 𝑎 ̸= 𝑏, that determines a-spoke edges
• b – integer such that 0 < 𝑏 < 𝑛 and 𝑏 ̸= 𝑎, that determines b-spoke edges
• r – integer such that 0 < 𝑟 < 𝑛 and 𝑟 ̸= 𝑛/2 determining how inner vertices are connected
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, the rose window graphs are displayed as an inner and outer cycle pair, with the first n nodes
drawn on the outer circle. The first (0) node is drawn at the top of the outer-circle, moving counterclockwise
after that. The inner circle is drawn with the (n)th node at the top, then counterclockwise as well. Vertices
in the outer circle are connected in the circular manner, vertices in the inner circle are connected when their
label have difference 𝑟 (mod n). Vertices on the outer rim are connected with the vertices on the inner rim
when they are at the same position and when they are 𝑎 and 𝑏 apart.
EXAMPLES:
sage: G = graphs.TabacjnGraph(3, 1, 2, 1)
sage: G.degree()
[5, 5, 5, 5, 5, 5]
sage: G.is_isomorphic(graphs.CompleteGraph(6))
True
sage: G = graphs.TabacjnGraph(6, 1, 5, 2)
sage: I = graphs.IcosahedralGraph()
sage: G.is_isomorphic(I)
True
sage: g=graphs.TaylorTwographDescendantSRG(3); g
Taylor two-graph descendant SRG: Graph on 27 vertices
sage: g.is_strongly_regular(parameters=True)
(27, 10, 1, 5)
sage: from sage.combinat.designs.twographs import taylor_twograph
sage: T = taylor_twograph(3) # long time
sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long time
True
sage: g=graphs.TaylorTwographDescendantSRG(5) # not tested (long time)
sage: g.is_strongly_regular(parameters=True) # not tested (long time)
(125, 52, 15, 26)
static TaylorTwographSRG(q)
Return a strongly regular graph from the Taylor’s two-graph for 𝑈3 (𝑞), 𝑞 odd
This is a strongly regular graph with parameters (𝑣, 𝑘, 𝜆, 𝜇) = (𝑞 3 +1, 𝑞(𝑞 2 +1)/2, (𝑞 2 +3)(𝑞 −1)/4, (𝑞 2 +
1)(𝑞 + 1)/4) in the Seidel switching class of Taylor two-graph. Details are in §7E of [BL1984].
INPUT:
• q – a power of an odd prime number
See also:
• TaylorTwographDescendantSRG()
EXAMPLES:
sage: t=graphs.TaylorTwographSRG(3); t
Taylor two-graph SRG: Graph on 28 vertices
sage: t.is_strongly_regular(parameters=True)
(28, 15, 6, 10)
static TetrahedralGraph()
Return a tetrahedral graph (with 4 nodes).
A tetrahedron is a 4-sided triangular pyramid. The tetrahedral graph corresponds to the connectivity of the
vertices of the tetrahedron. This graph is equivalent to a wheel graph with 4 nodes and also a complete
graph on four nodes. (See examples below).
PLOTTING: The Tetrahedral graph should be viewed in 3 dimensions. We choose to use a planar em-
bedding of the graph. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a
argument will be added to select the desired layout.
EXAMPLES:
Construct and show a Tetrahedral graph:
sage: g = graphs.TetrahedralGraph()
sage: g.show() # long time
Compare this Tetrahedral, Wheel(4), Complete(4), and the Tetrahedral plotted with the spring-layout algo-
rithm below in a Sage graphics array:
static ThomsenGraph()
Return the Thomsen Graph.
The Thomsen Graph is actually a complete bipartite graph with (𝑛1, 𝑛2) = (3, 3). It is also called the
Utility graph.
PLOTTING: See CompleteBipartiteGraph.
EXAMPLES:
sage: T = graphs.ThomsenGraph()
sage: T
Thomsen graph: Graph on 6 vertices
sage: T.graph6_string()
'EFz_'
sage: (graphs.ThomsenGraph()).show() # long time
static TietzeGraph()
Return the Tietze Graph.
For more information on the Tietze Graph, see the Wikipedia article Tietze%27s_graph.
EXAMPLES:
sage: g = graphs.TietzeGraph()
sage: g.order()
12
sage: g.size()
18
sage: g.diameter()
3
sage: g.girth()
3
sage: g.automorphism_group().cardinality()
12
sage: g.automorphism_group().is_isomorphic(groups.permutation.Dihedral(6))
True
static ToleranceGraph(tolrep)
Return the graph generated by the tolerance representation tolrep.
The tolerance representation tolrep is described by the list ((𝑙0 , 𝑟0 , 𝑡0 ), (𝑙1 , 𝑟1 , 𝑡1 ), . . . , (𝑙𝑘 , 𝑟𝑘 , 𝑡𝑘 )) where
𝐼𝑖 = (𝑙𝑖 , 𝑟𝑖 ) denotes a closed interval on the real line with 𝑙𝑖 < 𝑟𝑖 and 𝑡𝑖 a strictly positive value, called
tolerance. This representation generates the tolerance graph with the vertex set {0, 1, . . . , 𝑘} and the edge
set {(𝑖, 𝑗) : |𝐼𝑖 ∩ 𝐼𝑗 | ≥ min{𝑡𝑖 , 𝑡𝑗 }} where |𝐼𝑖 ∩ 𝐼𝑗 | denotes the length of the intersection of 𝐼𝑖 and 𝐼𝑗 .
INPUT:
• tolrep – list of triples (𝑙𝑖 , 𝑟𝑖 , 𝑡𝑖 ) where (𝑙𝑖 , 𝑟𝑖 ) denotes a closed interval on the real line and 𝑡𝑖 a
positive value.
Note: The vertices are named 0, 1, . . . , 𝑘. The tolerance representation used to create the graph is saved
with the graph and can be recovered using get_vertex() or get_vertices().
EXAMPLES:
The following code creates a tolerance representation tolrep, generates its tolerance graph g, and applies
some checks:
static Toroidal6RegularGrid2dGraph(p, q)
Return a toroidal 6-regular grid.
The toroidal 6-regular grid is a 6-regular graph on 𝑝 × 𝑞 vertices and its elements have coordinates (𝑖, 𝑗)
for 𝑖 ∈ {0...𝑝 − 1} and 𝑗 ∈ {0...𝑞 − 1}.
Its edges are those of the ToroidalGrid2dGraph(), to which are added the edges between (𝑖, 𝑗) and
((𝑖 + 1)%𝑝, (𝑗 + 1)%𝑞).
INPUT:
• p, q – integers (see above)
EXAMPLES:
The toroidal 6-regular grid on 25 elements:
sage: g = graphs.Toroidal6RegularGrid2dGraph(5,5)
sage: g.is_regular(k=6)
True
sage: g.is_vertex_transitive()
True
sage: g.line_graph().is_vertex_transitive()
True
sage: g.automorphism_group().cardinality()
300
sage: g.is_hamiltonian()
True
static ToroidalGrid2dGraph(p, q)
Return a toroidal 2-dimensional grid graph with 𝑝 × 𝑞 nodes (𝑝 rows and 𝑞 columns).
The toroidal 2-dimensional grid with parameters 𝑝, 𝑞 is the 2-dimensional grid graph with identical param-
eters to which are added the edges ((𝑖, 0), (𝑖, 𝑞 − 1)) and ((0, 𝑖), (𝑝 − 1, 𝑖)).
EXAMPLES:
The toroidal 2-dimensional grid is a regular graph, while the usual 2-dimensional grid is not
static TruncatedIcosidodecahedralGraph()
Return the truncated icosidodecahedron.
The truncated icosidodecahedron is an Archimedean solid with 30 square faces, 20 regular hexagonal faces,
12 regular decagonal faces, 120 vertices and 180 edges. For more information, see the Wikipedia article
Truncated_icosidodecahedron.
EXAMPLES:
Unfortunately, this graph can not be constructed currently, due to numerical issues:
sage: g = graphs.TruncatedIcosidodecahedralGraph(); g
Traceback (most recent call last):
...
ValueError: *Error: Numerical inconsistency is found. Use the GMP exact␣
˓→arithmetic.
static TruncatedTetrahedralGraph()
Return the truncated tetrahedron.
The truncated tetrahedron is an Archimedean solid with 12 vertices and 18 edges. For more information,
see the Wikipedia article Truncated_tetrahedron.
EXAMPLES:
sage: g = graphs.TruncatedTetrahedralGraph(); g
Truncated Tetrahedron: Graph on 12 vertices
sage: g.order(), g.size()
(12, 18)
sage: g.is_isomorphic(polytopes.simplex(3).truncation().graph())
True
static TruncatedWittGraph()
Return the truncated Witt graph.
This builds the large Witt graph, then removes all vertices whose codeword start with a 1.
The graph is distance-regular with intersection array [15, 14, 12; 1, 1, 9].
EXAMPLES:
REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 367.
static TuranGraph(n, r)
Returns the Turan graph with parameters 𝑛, 𝑟.
Turan graphs are complete multipartite graphs with 𝑛 vertices and 𝑟 subsets, denoted 𝑇 (𝑛, 𝑟), with the
property that the sizes of the subsets are as close to equal as possible. The graph 𝑇 (𝑛, 𝑟) will have 𝑛
(mod 𝑟) subsets of size ⌊𝑛/𝑟⌋ and 𝑟 − (𝑛 (mod 𝑟)) subsets of size ⌈𝑛/𝑟⌉. See the Wikipedia article
Turan_graph for more information.
INPUT:
• n – integer; the number of vertices in the graph
• r – integer; the number of partitions of the graph
EXAMPLES:
The Turan graph is a complete multipartite graph:
sage: g = graphs.TuranGraph(13, 4)
sage: k = graphs.CompleteMultipartiteGraph([3,3,3,4])
sage: g.is_isomorphic(k)
True
sage: n = 12
sage: r = 8
sage: g = graphs.TuranGraph(n, r)
sage: def count(n, r):
....: s = n % r
....: return (r - 1) * (n**2 - s**2) / (2*r) + s*(s - 1)/2
sage: g.size() == count(n, r)
True
sage: n = randint(3, 100)
sage: r = randint(2, n - 1)
sage: g = graphs.TuranGraph(n, r)
sage: g.size() == count(n, r)
True
static Tutte12Cage()
Return the Tutte 12-Cage.
See the Wikipedia article Tutte_12-cage.
EXAMPLES:
sage: g = graphs.Tutte12Cage()
sage: g.order()
126
sage: g.size()
189
sage: g.girth()
12
sage: g.diameter()
(continues on next page)
static TutteCoxeterGraph(embedding=2)
Return the Tutte-Coxeter graph.
See the Wikipedia article Tutte-Coxeter_graph.
INPUT:
• embedding – integer (default: 2); two embeddings are available, and can be selected by setting
embedding to 1 or 2
EXAMPLES:
sage: g = graphs.TutteCoxeterGraph()
sage: g.order()
30
sage: g.size()
45
sage: g.girth()
8
sage: g.diameter()
4
sage: g.show()
sage: graphs.TutteCoxeterGraph(embedding=1).show() # long time
static TutteGraph()
Return the Tutte Graph.
The Tutte graph is a 3-regular, 3-connected, and planar non-hamiltonian graph. For more information on
the Tutte Graph, see the Wikipedia article Tutte_graph.
EXAMPLES:
sage: g = graphs.TutteGraph()
sage: g.order()
46
sage: g.size()
69
sage: g.is_planar()
True
sage: g.vertex_connectivity() # long time
3
sage: g.girth()
4
sage: g.automorphism_group().cardinality()
3
sage: g.is_hamiltonian()
False
static U42Graph216()
Return a (216,40,4,8)-strongly regular graph from [CRS2016].
Build the graph, interpreting the 𝑈4 (2)-action considered in [CRS2016] as the one on the hyperbolic lines
of the corresponding unitary polar space, and then doing the unique merging of the orbitals leading to a
graph with the parameters in question.
EXAMPLES:
static U42Graph540()
Return a (540,187,58,68)-strongly regular graph from [CRS2016].
Build the graph, interpreting the 𝑈4 (2)-action considered in [CRS2016] as the action of 𝑈4 (2) = 𝑆𝑝4 (3) <
𝑈4 (3) on the nonsingular, w.r.t. to the Hermitean form stabilised by 𝑈4 (3), points of the 3-dimensional pro-
jective space over 𝐺𝐹 (9). There are several possible mergings of orbitals, some leading to non-isomorphic
graphs with the same parameters. We found the merging here using [FK1991].
EXAMPLES:
static USAMap(continental=False)
Return states of USA as a graph of common border.
The graph has an edge between those states that have common land border line or point. Hence for example
Colorado and Arizona are marked as neighbors, but Michigan and Minnesota are not.
INPUT:
• continental – boolean (default: False); whether to exclude Alaska and Hawaii
EXAMPLES:
How many states are neighbor’s neighbor for Pennsylvania:
static UnitaryDualPolarGraph(m, q)
Return the Dual Unitary Polar Graph 𝑈 (𝑚, 𝑞).
For more information on Unitary Dual Polar graphs, see [BCN1989] and Sect. 2.3.1 of [Coh1981].
INPUT:
• m,q – integers; 𝑞 must be a prime power
EXAMPLES:
The point graph of a generalized quadrangle (see Wikipedia article Generalized_quadrangle, [PT2009]) of
order (8,4):
sage: G = graphs.UnitaryDualPolarGraph(4,2); G
Unitary Dual Polar Graph DU(4, 2); GQ(2, 4): Graph on 27 vertices
sage: G.is_isomorphic(graphs.OrthogonalPolarGraph(6,2,'-'))
True
A bigger graph:
sage: G = graphs.UnitaryPolarGraph(4,2); G
Unitary Polar Graph U(4, 2); GQ(4, 2): Graph on 45 vertices
sage: G.is_strongly_regular(parameters=True)
(45, 12, 3, 3)
sage: graphs.UnitaryPolarGraph(5,2).is_strongly_regular(parameters=True)
(165, 36, 3, 9)
sage: graphs.UnitaryPolarGraph(6,2) # not tested (long time)
Unitary Polar Graph U(6, 2): Graph on 693 vertices
static UstimenkoGraph(m, q)
Return the Ustimenko graph with parameters (𝑚, 𝑞).
This is the distance 1 or 2 graph of the dual polar graph 𝐶𝑚−1 (𝑞). The graph is distance-regular with
classical with parameters (𝑑, 𝑞 2 , 𝑞𝑏𝑖𝑛𝑜𝑚(3, 1, 𝑞) − 1, 𝑞𝑏𝑖𝑛𝑜𝑚(𝑚 + 1, 1, 𝑞) − 1)
INPUT:
• m, q – integers; q must be a prime power and m > 1.
EXAMPLES:
sage: G = graphs.UstimenkoGraph(4, 2)
sage: G.is_distance_regular(True)
([70, 32, None], [None, 1, 35])
REFERENCES:
See [BCN1989] p. 279 or [VDKT2016] p. 22.
static WagnerGraph()
Return the Wagner Graph.
See the Wikipedia article Wagner_graph.
EXAMPLES:
sage: g = graphs.WagnerGraph()
sage: g.order()
8
sage: g.size()
12
sage: g.girth()
4
sage: g.diameter()
2
sage: g.show()
static WatkinsSnarkGraph()
Return the Watkins Snark Graph.
The Watkins Graph is a snark with 50 vertices and 75 edges. For more information, see the Wikipedia
article Watkins_snark.
EXAMPLES:
sage: g = graphs.WatkinsSnarkGraph()
sage: g.order()
50
sage: g.size()
75
sage: g.chromatic_number()
3
static WellsGraph()
Return the Wells graph.
For more information on the Wells graph (also called Armanios-Wells graph), see this page.
The implementation follows the construction given on page 266 of [BCN1989]. This requires to create inter-
mediate graphs and run a small isomorphism test, while everything could be replaced by a pre-computed
list of edges. I believe that it is better to keep “the recipe” in the code, however, as it is quite unlikely
that this could become the most time-consuming operation in any sensible algorithm, and . . . . “preserves
knowledge”, which is what open-source software is meant to do.
EXAMPLES:
sage: g = graphs.WellsGraph(); g
Wells graph: Graph on 32 vertices
sage: g.order()
32
sage: g.size()
80
sage: g.girth()
(continues on next page)
static WheelGraph(n)
Returns a Wheel graph with n nodes.
A Wheel graph is a basic structure where one node is connected to all other nodes and those (outer) nodes
are connected cyclically.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, each wheel graph will be displayed with the first (0) node in the center, the second node at
the top, and the rest following in a counterclockwise manner.
With the wheel graph, we see that it doesn’t take a very large n at all for the spring-layout to give a counter-
intuitive display. (See Graphics Array examples below).
EXAMPLES:
We view many wheel graphs with a Sage Graphics Array, first with this constructor (i.e., the position
dictionary filled):
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.WheelGraph(i+3)
....: g.append(k)
...
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
...
sage: G = graphics_array(j)
sage: G.show() # long time
sage: n = networkx.wheel_graph(23)
sage: spring23 = Graph(n)
sage: posdict23 = graphs.WheelGraph(23)
sage: spring23.show() # long time
sage: posdict23.show() # long time
static WienerArayaGraph()
Return the Wiener-Araya Graph.
The Wiener-Araya Graph is a planar hypohamiltonian graph on 42 vertices and 67 edges. For more infor-
mation, see the Wolfram Page on the Wiener-Araya Graph or Wikipedia article Wiener-Araya_graph.
EXAMPLES:
sage: g = graphs.WienerArayaGraph()
sage: g.order()
42
sage: g.size()
67
sage: g.girth()
4
sage: g.is_planar()
True
sage: g.is_hamiltonian() # not tested -- around 30s long
False
sage: g.delete_vertex(g.random_vertex())
sage: g.is_hamiltonian()
True
static WindmillGraph(k, n)
Return the Windmill graph 𝑊 𝑑(𝑘, 𝑛).
The windmill graph 𝑊 𝑑(𝑘, 𝑛) is an undirected graph constructed for 𝑘 ≥ 2 and 𝑛 ≥ 2 by joining 𝑛 copies
of the complete graph 𝐾𝑘 at a shared vertex. It has (𝑘 − 1)𝑛 + 1 vertices and 𝑛𝑘(𝑘 − 1)/2 edges, girth 3
(if 𝑘 > 2), radius 1 and diameter 2. It has vertex connectivity 1 because its central vertex is an articulation
point; however, like the complete graphs from which it is formed, it is (𝑘 −1)-edge-connected. It is trivially
perfect and a block graph.
See also:
EXAMPLES:
The Windmill graph 𝑊 𝑑(2, 𝑛) is a star graph:
sage: n = 5
sage: W = graphs.WindmillGraph(2, n)
sage: W.is_isomorphic( graphs.StarGraph(n) )
True
sage: n = 5
sage: W = graphs.WindmillGraph(3, n)
sage: W.is_isomorphic( graphs.FriendshipGraph(n) )
True
sage: W = graphs.WindmillGraph(3, 2)
sage: W.is_isomorphic( graphs.ButterflyGraph() )
True
static WorldMap()
Return the Graph of all the countries, in which two countries are adjacent in the graph if they have a common
boundary.
This graph has been built from the data available in The CIA World Factbook [CIA] (2009-08-21).
The returned graph G has a member G.gps_coordinates equal to a dictionary containing the GPS coor-
dinates of each country’s capital city.
EXAMPLES:
sage: g = graphs.WorldMap()
sage: g.has_edge("France", "Italy")
True
sage: g.gps_coordinates["Bolivia"]
[[17, 'S'], [65, 'W']]
sage: sorted(g.connected_component_containing_vertex('Ireland'))
['Ireland', 'United Kingdom']
static chang_graphs()
Return the three Chang graphs.
Three of the four strongly regular graphs of parameters (28, 12, 6, 4) are called the Chang graphs. The
fourth is the line graph of 𝐾8 . For more information about the Chang graphs, see the Wikipedia article
Chang_graphs or https://www.win.tue.nl/~aeb/graphs/Chang.html.
EXAMPLES: check that we get 4 non-isomorphic s.r.g.’s with the same parameters:
sage: c3c5=graphs.CycleGraph(3).disjoint_union(graphs.CycleGraph(5))
sage: c8=graphs.CycleGraph(8)
sage: s=[K8.subgraph_search(c8).edges(sort=False),
....: [(0,1,None),(2,3,None),(4,5,None),(6,7,None)],
....: K8.subgraph_search(c3c5).edges(sort=False)]
sage: list(map(lambda x,G: T8.seidel_switching(x, inplace=False).is_
˓→isomorphic(G),
....: s, chang_graphs))
[True, True, True]
static cocliques_HoffmannSingleton()
Return the graph obtained from the cocliques of the Hoffmann-Singleton graph.
This is a distance-regular graph with intersection array [15, 14, 10, 3; 1, 5, 12, 15].
EXAMPLES:
sage: G = graphs.cocliques_HoffmannSingleton()
sage: G.is_distance_regular(True)
([15, 14, 10, 3, None], [None, 1, 5, 12, 15])
REFERENCES:
The construction of this graph can be found in [BCN1989] p. 392.
cospectral_graphs(vertices, matrix_function=<function GraphGenerators.<lambda> at
0x7fc0e3320670>, graphs=None)
Find all sets of graphs on vertices vertices (with possible restrictions) which are cospectral with respect
to a constructed matrix.
INPUT:
• vertices - The number of vertices in the graphs to be tested
• matrix_function - A function taking a graph and giving back a matrix. This defaults to the adja-
cency matrix. The spectra examined are the spectra of these matrices.
• graphs - One of three things:
– None (default) - test all graphs having vertices vertices
– a function taking a graph and returning True or False - test only the graphs on vertices vertices
for which the function returns True
– a list of graphs (or other iterable object) - these graphs are tested for cospectral sets. In this case,
vertices is ignored.
OUTPUT:
A list of lists of graphs. Each sublist will be a list of cospectral graphs (lists of cardinality 1 being
omitted).
See also:
Graph.is_strongly_regular() – tests whether a graph is strongly regular and/or returns its parameters.
EXAMPLES:
sage: g=graphs.cospectral_graphs(5)
sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g)
[['Dr?', 'Ds_']]
sage: g[0][1].am().charpoly()==g[0][1].am().charpoly()
True
There are two sets of cospectral graphs on six vertices with no isolated vertices:
There are two sets of cospectral graphs (with respect to the Laplacian matrix) on six vertices:
True
sage: g[1][1].laplacian_matrix().charpoly()==g[1][1].laplacian_matrix().
˓→charpoly()
True
To find cospectral graphs with respect to the normalized Laplacian, assuming the graphs do not have an
isolated vertex, it is enough to check the spectrum of the matrix 𝐷−1 𝐴, where 𝐷 is the diagonal matrix
of vertex degrees, and A is the adjacency matrix. We find two such cospectral graphs (for the normalized
Laplacian) on five vertices:
static distance_3_doubly_truncated_Golay_code_graph()
Return a distance-regular graph with intersection array [9, 8, 6, 3; 1, 1, 3, 8].
EXAMPLES:
ALGORITHM:
Compute the binary Golay code and truncate it twice. Compute its coset graph. Take a vertex and compute
the set of vertices at distance 3 from the vertex chosen. This set constitutes the set of vertices of our
distance-regular graph. Moreover we have an edge (𝑢, 𝑣) if the coset graph contains such edge.
REFERENCES:
Description and construction of this graph are taken from [BCN1989] p. 364.
static distance_regular_graph(arr, existence=False, check=True)
Return a distance-regular graph with the intersection array given.
INPUT:
• arr – list; intersection array of the graph
• existence – boolean (optional); instead of building the graph return:
– True - if a graph with the given intersection array exists;
– False - if there is no graph with the given intersection array;
– Unknown - if Sage doesn’t know if such a graph exists.
• check – boolean (optional); if True, then checks that the result of this function has the given inter-
section array. Default: True
EXAMPLES:
REFERENCES:
See [BCN1989] and [VDKT2016].
fullerenes(order, ipr=False)
Returns a generator which creates fullerene graphs using the buckygen generator (see [BGM2012]).
INPUT:
• order - a positive even integer smaller than or equal to 254. This specifies the number of vertices in
the generated fullerenes.
• ipr - default: False - if True only fullerenes that satisfy the Isolated Pentagon Rule are generated.
This means that no pentagonal faces share an edge.
OUTPUT:
A generator which will produce the fullerene graphs as Sage graphs with an embedding set. These will be
simple graphs: no loops, no multiple edges, no directed edges.
See also:
EXAMPLES:
There are 1812 isomers of C60 , i.e., 1812 fullerene graphs on 60 vertices:
However, there is only one IPR fullerene graph on 60 vertices: the famous Buckminster Fullerene:
fusenes(hexagon_count, benzenoids=False)
Returns a generator which creates fusenes and benzenoids using the benzene generator (see [BCH2002]).
Fusenes are planar polycyclic hydrocarbons with all bounded faces hexagons. Benzenoids are fusenes that
are subgraphs of the hexagonal lattice.
INPUT:
• hexagon_count - a positive integer smaller than or equal to 30. This specifies the number of hexagons
in the generated benzenoids.
• benzenoids - default: False - if True only benzenoids are generated.
OUTPUT:
A generator which will produce the fusenes as Sage graphs with an embedding set. These will be simple
graphs: no loops, no multiple edges, no directed edges.
See also:
EXAMPLES:
There is a unique fusene with 2 hexagons:
This fusene is naphthalene (C10 H8 ). In the fusene graph the H-atoms are not stored, so this is a graph on
just 10 vertices:
static graph_3O73()
Return the graph related to the group 3𝑂(7, 3).
This graph is distance-regular with intersection array [117, 80, 24, 1; 1, 12, 80, 117].
The graph is also distance transitive with 3.𝑂(7, 3) as automorphism group
EXAMPLES:
REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 400.
static line_graph_forbidden_subgraphs()
Returns the 9 forbidden subgraphs of a line graph.
See the Wikipedia article Line_graph for more information.
The graphs are returned in the ordering given by the Wikipedia drawing, read from left to right and from
top to bottom.
EXAMPLES:
sage: graphs.line_graph_forbidden_subgraphs()
[Claw graph: Graph on 4 vertices,
Graph on 6 vertices,
Graph on 6 vertices,
Graph on 5 vertices,
Graph on 6 vertices,
Graph on 6 vertices,
Graph on 6 vertices,
Graph on 6 vertices,
Graph on 5 vertices]
static locally_GQ42_distance_transitive_graph()
Return the unique amply regular graph with 𝜇 = 6 which is locally a generalised quadrangle.
This graph is distance-regular with intersection array [45, 32, 12, 1; 1, 6, 32, 45].
This graph is also distance-transitive.
EXAMPLES:
REFERENCES:
A description of this graph can be found in [BCN1989] p.399. This construction is due to Dima Pasechnik.
nauty_genbg(options='', debug=False)
Return a generator which creates bipartite graphs from nauty’s genbg program.
INPUT:
• options – string (default: ""); a string passed to genbg as if it was run at a system command line. At
a minimum, you must pass the number of vertices you desire in each side. Sage expects the bipartite
graphs to be in nauty’s “graph6” format, do not set an option to change this default or results will be
unpredictable.
• debug – boolean (default: False); if True the first line of geng’s output to standard error is captured
and the first call to the generator’s next() function will return this line as a string. A line leading with
“>A” indicates a successful initiation of the program with some information on the arguments, while
a line beginning with “>E” indicates an error with the input.
The possible options, obtained as output of genbg --help:
Options which cause genbg to use an output format different than the graph6 format are not listed above
(-s, -a) as they will confuse the creation of a Sage graph. Option -q which suppress auxiliary output
(except from -v) should never be used as we are unable to recover the partition of the vertices of the
bipartite graph without the auxiliary output. Hence the partition of the vertices of returned bipartite graphs
might not respect the requirement.
The res/mod option can be useful when using the output in a routine run several times in parallel.
OUTPUT:
A generator which will produce the graphs as BipartiteGraph. These will be simple bipartite graphs:
no loops, no multiple edges, no directed edges.
EXAMPLES:
The generator can be used to construct biparrtite graphs for testing, one at a time (usually inside a loop).
Or it can be used to create an entire list all at once if there is sufficient memory to contain it:
Connected bipartite graphs of order 6 with different number of vertices in each side:
Use nauty_geng() instead if you want the list of all bipartite graphs of order 𝑛. For instance, the list of
all connected bipartite graphs of order 6, which agrees with OEIS sequence A005142:
The debug switch can be used to examine genbg’s reaction to the input in the options string. A message
starting with “>A” indicates success and a message starting with “>E” indicates a failure:
nauty_geng(options='', debug=False)
Return a generator which creates graphs from nauty’s geng program.
INPUT:
• options – string (default: ""); a string passed to geng as if it was run at a system command line. At
a minimum, you must pass the number of vertices you desire. Sage expects the graphs to be in nauty’s
“graph6” format, do not set an option to change this default or results will be unpredictable.
• debug – boolean (default: False); if True the first line of geng’s output to standard error is captured
and the first call to the generator’s next() function will return this line as a string. A line leading with
“>A” indicates a successful initiation of the program with some information on the arguments, while
a line beginning with “>E” indicates an error with the input.
The possible options, obtained as output of geng --help:
Options which cause geng to use an output format different than the graph6 format are not listed above (-u,
-g, -s, -y, -h) as they will confuse the creation of a Sage graph. The res/mod option can be useful when
using the output in a routine run several times in parallel.
OUTPUT:
A generator which will produce the graphs as Sage graphs. These will be simple graphs: no loops, no
multiple edges, no directed edges.
See also:
Graph.is_strongly_regular() – tests whether a graph is strongly regular and/or returns its parameters.
EXAMPLES:
The generator can be used to construct graphs for testing, one at a time (usually inside a loop). Or it can be
used to create an entire list all at once if there is sufficient memory to contain it.
A list of all graphs on 7 vertices. This agrees with OEIS sequence A000088.
A list of just the connected graphs on 7 vertices. This agrees with OEIS sequence A001349.
The debug switch can be used to examine geng’s reaction to the input in the options string. We illustrate
success. (A failure will be a string beginning with “>E”.) Passing the “-q” switch to geng will suppress
the indicator of a successful initiation, and so the first returned value might be an empty string if debug is
True:
Options which cause gentreeg to use an output format different than the sparse6 format are not listed
above (-p, -l, -u) as they will confuse the creation of a Sage graph. The res/mod option can be useful when
using the output in a routine run several times in parallel.
OUTPUT:
A generator which will produce the graphs as Sage graphs. These will be simple graphs: no loops, no
multiple edges, no directed edges.
See also:
trees() – another generator of trees
EXAMPLES:
The generator can be used to construct trees for testing, one at a time (usually inside a loop). Or it can be
used to create an entire list all at once if there is sufficient memory to contain it:
The number of trees on the first few vertex counts. This agrees with OEIS sequence A000055:
The debug switch can be used to examine gentreeg’s reaction to the input in the options string. We
illustrate success. (A failure will be a string beginning with “>E”.) Passing the “-q” switch to gentreeg
will suppress the indicator of a successful initiation, and so the first returned value might be an empty string
if debug is True:
static petersen_family(generate=False)
Returns the Petersen family
The Petersen family is a collection of 7 graphs which are the forbidden minors of the linklessly embeddable
graphs. For more information see the Wikipedia article Petersen_family.
INPUT:
• generate (boolean) – whether to generate the family from the ∆ − 𝑌 transformations. When set to
False (default) a hardcoded version of the graphs (with a prettier layout) is returned.
EXAMPLES:
sage: graphs.petersen_family()
[Petersen graph: Graph on 10 vertices,
Complete graph: Graph on 6 vertices,
Multipartite Graph with set sizes [3, 3, 1]: Graph on 7 vertices,
Graph on 8 vertices,
Graph on 9 vertices,
(continues on next page)
sage: F1 = graphs.petersen_family(generate=False)
sage: F2 = graphs.petersen_family(generate=True)
sage: F1 = [g.canonical_label().graph6_string() for g in F1]
sage: F2 = [g.canonical_label().graph6_string() for g in F2]
sage: set(F1) == set(F2)
True
Note: The non-3-connected graphs will be returned several times, with all its possible embeddings.
INPUT:
• order - a positive integer smaller than or equal to 64. This specifies the number of vertices in the
generated graphs.
• minimum_degree - default: None - a value ≥ 1 and ≤ 5, or None. This specifies the minimum degree
of the generated graphs. If this is None and the order is 1, then this is set to 0. If this is None and the
minimum connectivity is specified, then this is set to the same value as the minimum connectivity. If
the minimum connectivity is also equal to None, then this is set to 1.
• minimum_connectivity - default: None - a value ≥ 1 and ≤ 3, or None. This specifies the minimum
connectivity of the generated graphs. If this is None and the minimum degree is specified, then this is
set to the minimum of the minimum degree and 3. If the minimum degree is also equal to None, then
this is set to 1.
• exact_connectivity - default: False - if True only graphs with exactly the specified connectivity
will be generated. This option cannot be used with minimum_connectivity=3, or if the minimum
connectivity is not explicitly set.
• minimum_edges – integer (default: None); lower bound on the number of edges
• maximum_edges – integer (default: None); upper bound on the number of edges
• maximum_face_size – integer (default: None); upper bound on the size of a face and so on the
maximum degree of the dual graph
• only_bipartite - default: False - if True only bipartite graphs will be generated. This option
cannot be used for graphs with a minimum degree larger than 3.
• dual - default: False - if True return instead the planar duals of the generated graphs.
OUTPUT:
An iterator which will produce all planar graphs with the given number of vertices as Sage graphs with an
embedding set. These will be simple graphs (no loops, no multiple edges, no directed edges) unless the
option dual=True is used.
See also:
EXAMPLES:
There are 6 planar graphs on 4 vertices:
The cycle of length 4 is the only 2-connected bipartite planar graph on 4 vertices:
There is one planar graph with one vertex. This graph obviously has minimum degree equal to 0:
1
sage: len(list(graphs.planar_graphs(4, maximum_face_size=4))) # optional␣
˓→plantri
plantri_gen(options='')
Iterator over planar graphs created using the plantri generator.
plantri is a (optional) program that generates certain types of graphs that are embedded on the sphere. It
outputs exactly one member of each isomorphism class, using an amount of memory almost independent
of the number of graphs produced. Isomorphisms are defined with respect to the embeddings, so in some
cases outputs may be isomorphic as abstract graphs.
This method allows for passing command directly to plantry, similarly to method nauty_geng(), provide
that the output format is not changed.
INPUT:
• options – string (default: ""); a string passed to plantri as if it was run at a system command
line. At a minimum, you must pass the number of vertices you desire. Sage expects the output of
plantri to be in “planar code” format, so do not set an option to change this default or results will be
unpredictable.
The possible options are:
If -b, -q, -p, -P and -A are absent, the graphs found are triangulations only restricted by connectivity and
minimum degree. In this case, there is the possibility of connectivity lower than 3.
Other options listed in the plantri guide might cause unpredictable behavior, in particular those changing
the output format of plantri as they will confuse the creation of a Sage graph.
OUTPUT:
An iterator which yields the graphs generated by plantri as Sage Graph .
See also:
• planar_graphs() – iterator over connected planar graphs using the plantri generator
• triangulations() – iterator over connected planar triangulations using the plantri generator
• quadrangulations() – iterator over connected planar quadrangulations using the plantri genera-
tor
EXAMPLES:
The generator can be used to construct graphs for testing, one at a time (usually inside a loop). Or it can be
used to create an entire list all at once if there is sufficient memory to contain it:
An overview of the number of quadrangulations on up to 12 vertices. This agrees with OEIS sequence
A113201:
EXAMPLES:
The cube is the only 3-connected planar quadrangulation on 8 vertices:
True
sage: next(gen) # optional␣
˓→plantri
An overview of the number of quadrangulations on up to 12 vertices. This agrees with OEIS sequence
A113201:
There are 2 planar quadrangulation on 12 vertices that do not have a non-facial quadrangle:
static shortened_000_111_extended_binary_Golay_code_graph()
Return a distance-regular graph with intersection array [21, 20, 16, 9, 2, 1; 1, 2, 3, 16, 20, 21].
EXAMPLES:
ALGORITHM:
Compute the extended binary Golay code. Compute its subcode whose codewords start with 000 or 111.
Remove the first 3 entries from all the codewords from the new linear code and compute its coset graph.
REFERENCES:
Description and construction of this graph can be found in [BCN1989] p. 365.
static shortened_00_11_binary_Golay_code_graph()
Return a distance-regular graph with intersection array [21, 20, 16, 6, 2, 1; 1, 2, 6, 16, 20, 21].
EXAMPLES:
ALGORITHM:
Compute the binary Golay code. Compute the subcode whose codewords start with 00 or 11. Remove the
first two entries from all codewords of the newly found linear code and compute its coset graph.
REFERENCES:
Description and construction of this graph can be found in [BCN1989] p. 365.
sage: graphs.strongly_regular_graph(10,3,0,1,existence=True)
True
sage: graphs.strongly_regular_graph(10,3,0,1)
complement(Johnson graph with parameters 5,2): Graph on 10 vertices
sage: graphs.strongly_regular_graph(10,3,0)
complement(Johnson graph with parameters 5,2): Graph on 10 vertices
sage: graphs.strongly_regular_graph(5,5,5,5,existence=True)
False
sage: graphs.strongly_regular_graph(5,5,5,5)
Traceback (most recent call last):
...
ValueError: There exists no (5, 5, 5, 5)-strongly regular graph
sage: graphs.strongly_regular_graph(324,57,0,12,existence=True)
False
sage: graphs.strongly_regular_graph(324,57,0,12)
Traceback (most recent call last):
...
EmptySetError: Andries Brouwer's database reports that no (324, 57, 0,
12)-strongly regular graph exists. Comments: <a
href="srgtabrefs.html#GavrilyukMakhnev05">Gavrilyuk & Makhnev</a> ...
sage: graphs.strongly_regular_graph(324,95,22,30,existence=True)
Unknown
sage: graphs.strongly_regular_graph(324,95,22,30)
Traceback (most recent call last):
...
RuntimeError: Andries Brouwer's database reports that no
(324, 95, 22, 30)-strongly regular graph is known to exist.
Comments:
sage: graphs.strongly_regular_graph(1394,175,0,25,existence=True)
Unknown
sage: graphs.strongly_regular_graph(1394,175,0,25)
Traceback (most recent call last):
...
RuntimeError: Sage cannot figure out if a (1394, 175, 0, 25)-strongly
regular graph exists.
sage: graphs.strongly_regular_graph(2058,242,91,20,existence=True)
False
static trees(vertices)
Returns a generator of the distinct trees on a fixed number of vertices.
INPUT:
• vertices - the size of the trees created.
OUTPUT:
A generator which creates an exhaustive, duplicate-free listing of the connected free (unlabeled) trees with
vertices number of vertices. A tree is a graph with no cycles.
ALGORITHM:
Uses an algorithm that generates each new tree in constant time. See the documentation for, and imple-
mentation of, the sage.graphs.trees module, including a citation.
EXAMPLES:
We create an iterator, then loop over its elements.
The number of trees on the first few vertex counts. This is sequence A000055 in Sloane’s OEIS.
EXAMPLES:
The unique planar embedding of the 𝐾4 is the only planar triangulations on 4 vertices:
An overview of the number of 5-connected triangulations on up to 22 vertices. This agrees with OEIS
sequence A081621:
12 1
13 0
14 1
15 1
16 3
17 4
18 12
19 23
20 71
21 187
22 627
There are 5 triangulations with 9 vertices and minimum degree equal to 4 that are 3-connected, but only
one of them is not 4-connected:
5
sage: len([g for g in graphs.triangulations(9, minimum_degree=4, minimum_
˓→connectivity=3, exact_connectivity=True)]) # optional plantri
static vanLintSchrijverGraph()
Return the van Lint-Schrijver graph.
The graph is distance-regular with intersection array [6, 5, 5, 4; 1, 1, 2, 6].
EXAMPLES:
sage: G = graphs.vanLintSchrijverGraph()
sage: G.is_distance_regular(True)
([6, 5, 5, 4, None], [None, 1, 1, 2, 6])
REFERENCES:
For a description of this graph see [BCN1989] p. 373.
sage.graphs.graph_generators.canaug_traverse_edge(g, aut_gens, property, dig=False, loops=False,
sparse=True)
Main function for exhaustive generation. Recursive traversal of a canonically generated tree of isomorph free
graphs satisfying a given property.
INPUT:
• g - current position on the tree.
• aut_gens - list of generators of Aut(g), in list notation.
• property - check before traversing below g.
EXAMPLES:
The best way to access this function is through the graphs() iterator:
Print graphs on 3 or less vertices.
The best way to access this function is through the graphs() iterator:
Print graphs on 3 or less vertices.
sage.graphs.graph_generators.check_aut(aut_gens, cut_vert, n)
Helper function for exhaustive generation.
At the start, check_aut is given a set of generators for the automorphism group, aut_gens. We already know we
are looking for an element of the auto- morphism group that sends cut_vert to n, and check_aut generates these
for the canaug_traverse function.
EXAMPLES:
Note that the last two entries indicate that none of the automorphism group has yet been searched - we are starting
at the identity [0, 1, 2, 3] and so far that is all we have seen. We return automorphisms mapping 2 to 3:
All digraphs in Sage can be built through the digraphs object. In order to build a circuit on 15 elements, one can do:
sage: g = digraphs.Circuit(15)
sage: p = digraphs.Circulant(10,[2,3])
More interestingly, one can get the list of all digraphs that Sage knows how to build by typing digraphs. in Sage and
then hitting tab.
AUTHORS:
• Robert L. Miller (2006)
• Emily A. Kirkman (2006)
• Michael C. Yurko (2009)
• David Coudert (2012)
class sage.graphs.digraph_generators.DiGraphGenerators
Bases: object
A class consisting of constructors for several common digraphs, including orderly generation of isomorphism
class representatives.
A list of all graphs and graph structures in this database is available via tab completion. Type “digraphs.” and
then hit tab to see which graphs are available.
The docstrings include educational information about each named digraph with the hopes that this class can be
used as a reference.
The constructors currently in this class include:
Families of Graphs:
- Complete
- DeBruijn
- GeneralizedDeBruijn
- Kautz
- Path
- ImaseItoh
- RandomTournament
- TransitiveTournament
- tournaments_nauty
ButterflyGraph(n, vertices='strings')
Return a 𝑛-dimensional butterfly graph.
The vertices consist of pairs (𝑣, 𝑖), where 𝑣 is an 𝑛-dimensional tuple (vector) with binary entries (or a
string representation of such) and 𝑖 is an integer in [0..𝑛]. A directed edge goes from (𝑣, 𝑖) to (𝑤, 𝑖 + 1) if
𝑣 and 𝑤 are identical except for possibly when 𝑣[𝑖] ̸= 𝑤[𝑖].
A butterfly graph has (2𝑛 )(𝑛 + 1) vertices and 𝑛2𝑛+1 edges.
INPUT:
• n – a non negative integer; the dimension of the butterfly graph
• vertices – string (default: 'strings'); specifies whether the vertices are zero-one strings (default)
or tuples over GF(2) (vertices='vectors')
EXAMPLES:
Circuit(n)
Return the circuit on 𝑛 vertices.
The circuit is an oriented CycleGraph.
EXAMPLES:
A circuit is the smallest strongly connected digraph:
Circulant(n, integers)
Return a circulant digraph on 𝑛 vertices from a set of integers.
INPUT:
sage: digraphs.Circulant(13,[3,5,7])
Circulant graph ([3, 5, 7]): Digraph on 13 vertices
Complete(n, loops=False)
Return the complete digraph on 𝑛 vertices.
INPUT:
• n – integer; number of vertices
• loops – boolean (default: False); whether to add loops or not, i.e., edges from 𝑢 to itself
See also:
• RandomSemiComplete()
• RandomTournament()
EXAMPLES:
sage: n = 10
sage: G = digraphs.Complete(n); G
Complete digraph: Digraph on 10 vertices
sage: G.size() == n*(n-1)
True
sage: G = digraphs.Complete(n, loops=True); G
Complete digraph with loops: Looped digraph on 10 vertices
sage: G.size() == n*n
True
sage: digraphs.Complete(-1)
Traceback (most recent call last):
...
ValueError: the number of vertices cannot be strictly negative
DeBruijn(k, n, vertices='strings')
Return the De Bruijn digraph with parameters 𝑘, 𝑛.
The De Bruijn digraph with parameters 𝑘, 𝑛 is built upon a set of vertices equal to the set of words of length
𝑛 from a dictionary of 𝑘 letters.
In this digraph, there is an arc 𝑤1 𝑤2 if 𝑤2 can be obtained from 𝑤1 by removing the leftmost letter and
adding a new letter at its right end. For more information, see the Wikipedia article De_Bruijn_graph.
INPUT:
• k – two possibilities for this parameter :
– An integer equal to the cardinality of the alphabet to use, that is, the degree of the digraph to be
produced.
– An iterable object to be used as the set of letters. The degree of the resulting digraph is the
cardinality of the set of letters.
• n – integer; length of words in the De Bruijn digraph when vertices == 'strings', and also the
diameter of the digraph.
• vertices – string (default: 'strings'); whether the vertices are words over an alphabet (default) or
integers (vertices='string')
EXAMPLES:
de Bruijn digraph of degree 2 and diameter 2:
GeneralizedDeBruijn(n, d)
Return the generalized de Bruijn digraph of order 𝑛 and degree 𝑑.
The generalized de Bruijn digraph was defined in [RPK1980] [RPK1983]. It has vertex set 𝑉 =
{0, 1, ..., 𝑛 − 1} and there is an arc from vertex 𝑢 ∈ 𝑉 to all vertices 𝑣 ∈ 𝑉 such that 𝑣 ≡ (𝑢 * 𝑑 + 𝑎)
mod 𝑛 with 0 ≤ 𝑎 < 𝑑.
When 𝑛 = 𝑑𝐷 , the generalized de Bruijn digraph is isomorphic to the de Bruijn digraph of degree 𝑑 and
diameter 𝐷.
INPUT:
• n – integer; number of vertices of the digraph (must be at least one)
• d – integer; degree of the digraph (must be at least one)
See also:
EXAMPLES:
sage: GB = digraphs.GeneralizedDeBruijn(8, 2)
sage: GB.is_isomorphic(digraphs.DeBruijn(2, 3), certificate = True)
(True, {0: '000', 1: '001', 2: '010', 3: '011', 4: '100', 5: '101', 6: '110',␣
˓→7: '111'})
ImaseItoh(n, d)
Return the Imase-Itoh digraph of order 𝑛 and degree 𝑑.
The Imase-Itoh digraph was defined in [II1983]. It has vertex set 𝑉 = {0, 1, ..., 𝑛 − 1} and there is an arc
from vertex 𝑢 ∈ 𝑉 to all vertices 𝑣 ∈ 𝑉 such that 𝑣 ≡ (−𝑢 * 𝑑 − 𝑎 − 1) mod 𝑛 with 0 ≤ 𝑎 < 𝑑.
When 𝑛 = 𝑑𝐷 , the Imase-Itoh digraph is isomorphic to the de Bruijn digraph of degree 𝑑 and diameter 𝐷.
When 𝑛 = 𝑑𝐷−1 (𝑑 + 1), the Imase-Itoh digraph is isomorphic to the Kautz digraph [Kau1968] of degree
𝑑 and diameter 𝐷.
INPUT:
• n – integer; number of vertices of the digraph (must be greater than or equal to two)
• d – integer; degree of the digraph (must be greater than or equal to one)
EXAMPLES:
sage: II = digraphs.ImaseItoh(8, 2)
sage: II.is_isomorphic(digraphs.DeBruijn(2, 3), certificate = True)
(True, {0: '010', 1: '011', 2: '000', 3: '001', 4: '110', 5: '111', 6: '100',␣
˓→7: '101'})
sage: II = digraphs.ImaseItoh(12, 2)
sage: b,D = II.is_isomorphic(digraphs.Kautz(2, 3), certificate=True)
sage: b
True
sage: D # random isomorphism
{0: '202', 1: '201', 2: '210', 3: '212', 4: '121',
5: '120', 6: '102', 7: '101', 8: '010', 9: '012',
10: '021', 11: '020'}
Kautz(k, D, vertices='strings')
Return the Kautz digraph of degree 𝑑 and diameter 𝐷.
The Kautz digraph has been defined in [Kau1968]. The Kautz digraph of degree 𝑑 and diameter 𝐷 has
𝑑𝐷−1 (𝑑 + 1) vertices. This digraph is built from a set of vertices equal to the set of words of length 𝐷
over an alphabet of 𝑑 + 1 letters such that consecutive letters are different. There is an arc from vertex 𝑢 to
vertex 𝑣 if 𝑣 can be obtained from 𝑢 by removing the leftmost letter and adding a new letter, distinct from
the rightmost letter of 𝑢, at the right end.
The Kautz digraph of degree 𝑑 and diameter 𝐷 is isomorphic to the Imase-Itoh digraph [II1983] of degree
𝑑 and order 𝑑𝐷−1 (𝑑 + 1).
See the Wikipedia article Kautz_graph for more information.
INPUT:
• k – two possibilities for this parameter. In either case the degree must be at least one:
– An integer equal to the degree of the digraph to be produced, that is, the cardinality of the alphabet
to be used minus one.
– An iterable object to be used as the set of letters. The degree of the resulting digraph is the
cardinality of the set of letters minus one.
• D – integer; diameter of the digraph, and length of a vertex label when vertices == 'strings'
(must be at least one)
• vertices – string (default: 'strings'); whether the vertices are words over an alphabet (default) or
integers (vertices='strings')
EXAMPLES:
sage: K = digraphs.Kautz(2, 3)
sage: b,D = K.is_isomorphic(digraphs.ImaseItoh(12, 2), certificate=True)
sage: b
True
sage: D # random isomorphism
{'010': 8, '012': 9, '020': 11, '021': 10, '101': 7, '102': 6,
'120': 5, '121': 4, '201': 1, '202': 0, '210': 2, '212': 3}
sage: K = digraphs.Kautz([1,'a','B'], 2)
sage: K.edges(sort=True)
[('1B', 'B1', '1'), ('1B', 'Ba', 'a'), ('1a', 'a1', '1'),
('1a', 'aB', 'B'), ('B1', '1B', 'B'), ('B1', '1a', 'a'),
('Ba', 'a1', '1'), ('Ba', 'aB', 'B'), ('a1', '1B', 'B'),
('a1', '1a', 'a'), ('aB', 'B1', '1'), ('aB', 'Ba', 'a')]
sage: K = digraphs.Kautz([1,'aA','BB'], 2)
sage: K.edges(sort=True)
[('1,BB', 'BB,1', '1'), ('1,BB', 'BB,aA', 'aA'),
('1,aA', 'aA,1', '1'), ('1,aA', 'aA,BB', 'BB'),
('BB,1', '1,BB', 'BB'), ('BB,1', '1,aA', 'aA'),
('BB,aA', 'aA,1', '1'), ('BB,aA', 'aA,BB', 'BB'),
('aA,1', '1,BB', 'BB'), ('aA,1', '1,aA', 'aA'),
('aA,BB', 'BB,1', '1'), ('aA,BB', 'BB,aA', 'aA')]
Paley(q)
Return a Paley digraph on 𝑞 vertices.
Parameter 𝑞 must be the power of a prime number and congruent to 3 mod 4.
See also:
EXAMPLES:
A Paley digraph has 𝑛 * (𝑛 − 1)/2 edges, its underlying graph is a clique, and so it is a tournament:
sage: g = digraphs.Paley(7); g
Paley digraph with parameter 7: Digraph on 7 vertices
sage: g.size() == g.order() * (g.order() - 1) / 2
True
sage: g.to_undirected().is_clique()
True
sage: g.complement().is_isomorphic(g)
True
Path(n)
Return a directed path on 𝑛 vertices.
INPUT:
sage: g = digraphs.Path(5)
sage: g.vertices(sort=True)
[0, 1, 2, 3, 4]
sage: g.size()
4
sage: g.automorphism_group().cardinality()
1
RandomDirectedAcyclicGraph(n, p, weight_max=None)
Return a random (weighted) directed acyclic graph of order 𝑛.
The method starts with the sink vertex and adds vertices one at a time. A vertex is connected only to
previously defined vertices, and the probability of each possible connection is given by the probability 𝑝.
The weight of an edge is a random integer between 1 and weight_max.
INPUT:
• n – number of nodes of the graph
• p – probability of an edge
• weight_max – (default: None); by default, the returned DAG is unweighted. When weight_max is
set to a positive integer, edges are assigned a random integer weight between 1 and weight_max.
EXAMPLES:
sage: D = digraphs.RandomDirectedGN(25)
sage: D.num_verts()
25
(continues on next page)
RandomDirectedGNC(n, seed=None)
Return a random growing network with copying (GNC) digraph with 𝑛 vertices.
The digraph is constructed by adding vertices with a link to one previously added vertex. The vertex to
link to is chosen with a preferential attachment model, i.e. probability is proportional to degree. The new
vertex is also linked to all of the previously added vertex’s successors. See [KR2005] for more details.
INPUT:
• n – integer; number of vertices
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
sage: D = digraphs.RandomDirectedGNC(25)
sage: D.is_directed_acyclic()
True
sage: D.topological_sort()
[24, 23, ..., 1, 0]
sage: D.show() # long time
RandomDirectedGNM(n, m, loops=False)
Return a random labelled digraph on 𝑛 nodes and 𝑚 arcs.
INPUT:
• n – integer; number of vertices
• m – integer; number of edges
• loops – boolean (default: False); whether to allow loops
PLOTTING: When plotting, this graph will use the default spring-layout algorithm, unless a position dic-
tionary is specified.
EXAMPLES:
sage: D = digraphs.RandomDirectedGNM(10, 5)
sage: D.num_verts()
10
sage: D.num_edges()
5
With loops:
RandomDirectedGNR(n, p, seed=None)
Return a random growing network with redirection (GNR) digraph with 𝑛 vertices and redirection proba-
bility 𝑝.
The digraph is constructed by adding vertices with a link to one previously added vertex. The vertex to
link to is chosen uniformly. With probability p, the arc is instead redirected to the successor vertex. The
digraph is always a tree. See [KR2001b] for more details.
INPUT:
• n – integer; number of vertices
• p – redirection probability
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
RandomSemiComplete(n)
Return a random semi-complete digraph on 𝑛 vertices.
A directed graph 𝐺 = (𝑉, 𝐸) is semi-complete if for any pair of vertices 𝑢 and 𝑣, there is at least one arc
between them.
To generate randomly a semi-complete digraph, we have to ensure, for any pair of distinct vertices 𝑢 and
𝑣, that with probability 1/3 we have only arc 𝑢𝑣, with probability 1/3 we have only arc 𝑣𝑢, and with
probability 1/3 we have both arc 𝑢𝑣 and arc 𝑣𝑢. We do so by selecting a random integer 𝑐𝑜𝑖𝑛 in [1, 3].
When 𝑐𝑜𝑖𝑛 == 1 we select only arc 𝑢𝑣, when 𝑐𝑜𝑖𝑛 == 3 we select only arc 𝑣𝑢, and when 𝑐𝑜𝑖𝑛 == 2 we
select both arcs. In other words, we select arc 𝑢𝑣 when 𝑐𝑜𝑖𝑛 ≤ 2 and arc 𝑣𝑢 when 𝑐𝑜𝑖𝑛 ≥ 2.
INPUT:
• n – integer; the number of nodes
See also:
• Complete()
• RandomTournament()
EXAMPLES:
sage: SC = digraphs.RandomSemiComplete(10); SC
Random Semi-Complete digraph: Digraph on 10 vertices
sage: SC.size() >= binomial(10, 2)
True
sage: digraphs.RandomSemiComplete(-1)
Traceback (most recent call last):
...
ValueError: the number of vertices cannot be strictly negative
RandomTournament(n)
Return a random tournament on 𝑛 vertices.
For every pair of vertices, the tournament has an edge from 𝑖 to 𝑗 with probability 1/2, otherwise it has an
edge from 𝑗 to 𝑖.
INPUT:
• n – integer; number of vertices
EXAMPLES:
sage: T = digraphs.RandomTournament(10); T
Random Tournament: Digraph on 10 vertices
sage: T.size() == binomial(10, 2)
True
sage: T.is_tournament()
True
sage: digraphs.RandomTournament(-1)
Traceback (most recent call last):
...
ValueError: the number of vertices cannot be strictly negative
See also:
• RandomSemiComplete()
TransitiveTournament(n)
Return a transitive tournament on 𝑛 vertices.
In this tournament there is an edge from 𝑖 to 𝑗 if 𝑖 < 𝑗.
See the Wikipedia article Tournament_(graph_theory) for more information.
INPUT:
• n – integer; number of vertices in the tournament
EXAMPLES:
sage: g = digraphs.TransitiveTournament(5)
sage: g.vertices(sort=True)
[0, 1, 2, 3, 4]
sage: g.size()
10
sage: g.automorphism_group().cardinality()
1
See also:
• debug (boolean) – default: False - if True directg standard error and standard output are displayed.
EXAMPLES:
See also:
• orientations()
• strong_orientation()
• strong_orientations_iterator()
• random_orientation()
AUTHORS:
• David Coudert (2012)
sage.graphs.graph_generators_pyx.RandomGNP(n, p, directed=False, loops=False, seed=None)
Return a random graph or a digraph on 𝑛 nodes.
Each edge is inserted independently with probability 𝑝.
INPUT:
• n – number of nodes of the digraph
• p – probability of an edge
• directed – boolean (default: False); whether the random graph is directed or undirected (default)
• loops – boolean (default: False); whether the random digraph may have loops or not. This value is used
only when directed == True
• seed – a random.Random seed or a Python int for the random number generator (default: None)
REFERENCES:
• [ER1959]
• [Gil1959]
EXAMPLES:
This module implements classes (GraphDatabase, GraphQuery, GenericGraphQuery) for interfacing with the
sqlite database graphs.db.
The GraphDatabase class interfaces with the sqlite database graphs.db. It is an immutable database that inherits
from SQLDatabase (see sage.databases.sql_db).
The database contains all unlabeled graphs with 7 or fewer nodes. This class will also interface with the optional
database package containing all unlabeled graphs with 8 or fewer nodes. The database(s) consists of five tables, and
has the structure given by the function graph_db_info() (For a full description including column data types, create
a GraphDatabase instance and call the method get_skeleton()).
AUTHORS:
• Emily A. Kirkman (2008-09-20): first version of interactive queries, cleaned up code and generalized many
elements to sage.databases.sql_db.py
• Emily A. Kirkman (2007-07-23): inherits GenericSQLDatabase, also added classes: GraphQuery and Generic-
GraphQuery
Note: This query class is generally intended for developers and more advanced users. It allows you to execute
any query, and so may be considered unsafe.
EXAMPLES:
See GraphDatabase class docstrings or enter:
sage: G = GraphDatabase()
sage: G.get_skeleton()
{...
to see the underlying structure of the database. Also see sage.databases.sql_db.SQLQuery in sage.
databases.sql_db for more info and a tutorial.
A piece of advice about ‘?’ and param_tuple: it is generally considered safer to query with a ‘?’ in place of each
value parameter, and using a second argument (a tuple of strings) in a call to the sqlite database. Successful
use of the param_tuple argument is exemplified:
sage: G = GraphDatabase()
sage: q = 'select graph_id,graph6,num_vertices,num_edges from graph_data where␣
˓→graph_id<=(?) and num_vertices=(?)'
class sage.graphs.graph_database.GraphDatabase
Bases: sage.databases.sql_db.SQLDatabase
Graph Database
This class interfaces with the sqlite database graphs.db. It is an immutable database that inherits from
SQLDatabase (see sage.databases.sql_db). The display functions and get_graphs_list create their own
queries, but it is also possible to query the database by constructing either a SQLQuery.
The database contains all unlabeled graphs with 7 or fewer nodes. This class will also interface with the optional
database package containing all unlabeled graphs with 8 or fewer nodes. The database consists of five tables.
For a full table and column structure, call graph_db_info().
The tables are associated by the unique primary key graph_id (int).
To query this database, we create a GraphQuery. This can be done directly with the query() method or by
initializing one of:
• GenericGraphQuery – allows direct entry of a query string and tuple of parameters. This is the route for
more advanced users that are familiar with SQL
• GraphQuery – a wrapper of SQLQuery, a general database/query wrapper of SQLite for new users
REFERENCES:
• Data provided by Jason Grout (Brigham Young University). [Online] Available: http://artsci.drake.edu/
grout/graphs/
EXAMPLES:
sage: G = GraphDatabase()
sage: G.get_skeleton()
{'aut_grp': {'aut_grp_size': {'index': True,
'primary_key': False,
'sql': 'INTEGER',
'unique': False},
'edge_transitive': {'index': True,
'primary_key': False,
'sql': 'BOOLEAN',
'unique': False},
'graph_id': {'index': False,
'primary_key': False,
'sql': 'INTEGER',
'unique': False},
'num_fixed_points': {'index': True,
'primary_key': False,
'sql': 'INTEGER',
'unique': False},
'num_orbits': {'index': True,
'primary_key': False,
'sql': 'INTEGER',
'unique': False},
'vertex_transitive': {'index': True,
'primary_key': False,
'sql': 'BOOLEAN',
'unique': False}},
'degrees': {'average_degree': {'index': True,
'primary_key': False,
'sql': 'REAL',
'unique': False},
'degree_sequence': {'index': False,
(continues on next page)
interactive_query(display_cols, **kwds)
Generate an interact shell to query the database.
This method generates an interact shell that allows the user to manipulate query parameters and see the
updated results.
Todo: This function could use improvement. Add full options of typical GraphQuery (i.e.: have it accept
list input); and update options in interact to make it less annoying to put in operators.
EXAMPLES:
sage: D = GraphDatabase()
sage: D.interactive_query(display_cols=['graph6', 'num_vertices', 'degree_
˓→sequence'], num_edges=5, max_degree=3)
sage: q.show()
Graph6 Num Vertices Degree Sequence
------------------------------------------------------------
@ 1 [0]
A? 2 [0, 0]
A_ 2 [1, 1]
B? 3 [0, 0, 0]
BG 3 [0, 1, 1]
BW 3 [1, 1, 2]
Bw 3 [2, 2, 2]
C? 4 [0, 0, 0, 0]
C@ 4 [0, 0, 1, 1]
CB 4 [0, 1, 1, 2]
CF 4 [1, 1, 1, 3]
CJ 4 [0, 2, 2, 2]
CK 4 [1, 1, 1, 1]
CL 4 [1, 1, 2, 2]
CN 4 [1, 2, 2, 3]
C] 4 [2, 2, 2, 2]
C^ 4 [2, 2, 3, 3]
D?? 5 [0, 0, 0, 0, 0]
D?C 5 [0, 0, 0, 1, 1]
D?K 5 [0, 0, 1, 1, 2]
D?[ 5 [0, 1, 1, 1, 3]
D?{ 5 [1, 1, 1, 1, 4]
D@K 5 [0, 0, 2, 2, 2]
D@O 5 [0, 1, 1, 1, 1]
D@S 5 [0, 1, 1, 2, 2]
D@[ 5 [0, 1, 2, 2, 3]
D@s 5 [1, 1, 1, 2, 3]
D@{ 5 [1, 1, 2, 2, 4]
DBW 5 [0, 2, 2, 2, 2]
DB[ 5 [0, 2, 2, 3, 3]
DBg 5 [1, 1, 2, 2, 2]
DBk 5 [1, 1, 2, 3, 3]
DIk 5 [1, 2, 2, 2, 3]
(continues on next page)
INPUT:
• graph_db – GraphDatabase (default: None); instance to apply the query to (If None, then a new instance
is created)
• query_dict – dict (default: None); a dictionary specifying the query itself. Format is: {'table_name':
'tblname', 'display_cols': ['col1', 'col2'], 'expression': [col, operator,
value]}. If not None, query_dict will take precedence over all other arguments.
• display_cols – list of strings (default: None); a list of column names (strings) to display in the result
when running or showing a query
• kwds – the columns of the database are all keywords. For a database table/column structure dictionary, call
graph_db_info(). Keywords accept both single values and lists of length 2. The list allows the user to
specify an expression other than equality. Valid expressions are strings, and for numeric values (i.e. Reals
and Integers) are: ‘=’,”,”,’=’,’=’. String values also accept ‘regexp’ as an expression argument. The only
keyword exception to this format is induced_subgraphs, which accepts one of the following options:
– ['one_of', String, ..., String] – will search for graphs containing a subgraph isomorphic to
any of the graph6 strings in the list
– ['all_of', String, ..., String] – will search for graphs containing a subgraph isomorphic to
each of the graph6 strings in the list
EXAMPLES:
sage: Q.number_of()
35
sage: Q.show()
Graph6 Num Vertices Degree Sequence
------------------------------------------------------------
A_ 2 [1, 1]
BW 3 [1, 1, 2]
CF 4 [1, 1, 1, 3]
CK 4 [1, 1, 1, 1]
CL 4 [1, 1, 2, 2]
CN 4 [1, 2, 2, 3]
D?{ 5 [1, 1, 1, 1, 4]
D@s 5 [1, 1, 1, 2, 3]
D@{ 5 [1, 1, 2, 2, 4]
DBg 5 [1, 1, 2, 2, 2]
DBk 5 [1, 1, 2, 3, 3]
DIk 5 [1, 2, 2, 2, 3]
DK[ 5 [1, 2, 2, 2, 3]
D_K 5 [1, 1, 1, 1, 2]
D`K 5 [1, 1, 2, 2, 2]
E?Bw 6 [1, 1, 1, 1, 1, 5]
E?Fg 6 [1, 1, 1, 1, 2, 4]
E?N? 6 [1, 1, 1, 1, 2, 2]
E?NG 6 [1, 1, 1, 1, 3, 3]
E@FG 6 [1, 1, 1, 2, 2, 3]
E@N? 6 [1, 1, 2, 2, 2, 2]
E@Q? 6 [1, 1, 1, 1, 1, 1]
E@QW 6 [1, 1, 1, 2, 2, 3]
E@YO 6 [1, 1, 2, 2, 2, 2]
E_?w 6 [1, 1, 1, 1, 1, 3]
E_Cg 6 [1, 1, 1, 1, 2, 2]
E_Cw 6 [1, 1, 1, 2, 2, 3]
E_Ko 6 [1, 1, 2, 2, 2, 2]
F??^? 7 [1, 1, 1, 1, 1, 2, 3]
F?LCG 7 [1, 1, 1, 1, 2, 2, 2]
FK??W 7 [1, 1, 1, 1, 1, 1, 2]
FK?GW 7 [1, 1, 1, 1, 2, 2, 2]
F_?@w 7 [1, 1, 1, 1, 1, 1, 4]
F_?Hg 7 [1, 1, 1, 1, 1, 2, 3]
F_?XO 7 [1, 1, 1, 1, 2, 2, 2]
get_graphs_list()
Return a list of Sage Graph objects that satisfy the query.
EXAMPLES:
sage: L = Q.get_graphs_list()
sage: L[0]
Graph on 2 vertices
sage: len(L)
35
number_of()
Return the number of graphs in the database that satisfy the query.
EXAMPLES:
sage: Q.number_of()
35
query_iterator()
Return an iterator over the results list of the GraphQuery.
EXAMPLES:
show(max_field_size=20, with_picture=False)
Display the results of a query in table format.
INPUT:
sage: G = GraphDatabase()
sage: Q = GraphQuery(G, display_cols=['graph6','num_vertices','aut_grp_size'],␣
˓→num_vertices=4, aut_grp_size=4)
sage: Q.show()
Graph6 Num Vertices Aut Grp Size
------------------------------------------------------------
C@ 4 4
C^ 4 4
sage: R.show()
Graph6 Num Vertices Degree Sequence
------------------------------------------------------------
C? 4 [0, 0, 0, 0]
C@ 4 [0, 0, 1, 1]
CB 4 [0, 1, 1, 2]
CF 4 [1, 1, 1, 3]
CJ 4 [0, 2, 2, 2]
CK 4 [1, 1, 1, 1]
CL 4 [1, 1, 2, 2]
CN 4 [1, 2, 2, 3]
C] 4 [2, 2, 2, 2]
C^ 4 [2, 2, 3, 3]
C~ 4 [3, 3, 3, 3]
Show your own query (note that the output is not reformatted for generic queries):
degree_sequence
--------------------
211
222
2211
2222
21111
22211
22211
22222
221111
221111
222211
222211
222211
222222
222222
2111111
2221111
2221111
2221111
2222211
2222211
2222211
2222211
2222222
2222222
sage.graphs.graph_database.data_to_degseq(data, graph6=None)
Convert a database integer data type to a degree sequence list.
INPUT:
• data – integer data type (one digit per vertex representing its degree, sorted high to low) to be converted
to a degree sequence list
• graph6 – string (default: None); the graph6 identifier is required for all graphs with no edges, so that the
correct number of zeros is returned.
EXAMPLES:
sage.graphs.graph_database.degseq_to_data(degree_sequence)
Convert a degree sequence list to a sorted (max-min) integer data type.
The input degree sequence list (of Integers) is converted to a sorted (max-min) integer data type, as used for
faster access in the underlying database.
INPUT:
• degree_sequence – list of integers; input degree sequence list
EXAMPLES:
sage.graphs.graph_database.graph6_to_plot(graph6)
Return a Graphics object from a graph6 string.
This method constructs a graph from a graph6 string and returns a sage.plot.graphics.Graphics object
with arguments preset for the sage.plot.graphics.Graphics.show() method.
INPUT:
• graph6 – a graph6 string
EXAMPLES:
sage.graphs.graph_database.graph_db_info(tablename=None)
Return a dictionary of allowed table and column names.
INPUT:
• tablename – restricts the output to a single table
EXAMPLES:
sage: sorted(graph_db_info())
['aut_grp', 'degrees', 'graph_data', 'misc', 'spectrum']
sage: graph_db_info(tablename='graph_data')
['complement_graph6',
'eulerian',
'graph6',
'lovasz_number',
'num_cycles',
'num_edges',
'num_hamiltonian_cycles',
'num_vertices',
'perfect',
'planar']
sage.graphs.graph_database.subgraphs_to_query(subgraphs, db)
Return a GraphQuery object required for the induced_subgraphs parameter.
This method constructs and returns a GraphQuery object respecting the special input required for the
induced_subgraphs parameter.
INPUT:
• subgraphs – list of strings; the list should be of one of the following two formats:
– ['one_of', String, ..., String] – will search for graphs containing a subgraph isomorphic to
any of the graph6 strings in the list
– ['all_of', String, ..., String] – will search for graphs containing a subgraph isomorphic to
each of the graph6 strings in the list
• db – a GraphDatabase
Note: This is a helper method called by the GraphQuery constructor to handle this special format. This method
should not be used on its own because it doesn’t set any display columns in the query string, causing a failure to
fetch the data when run.
EXAMPLES:
This module manages a database associating to a set of four integers (𝑣, 𝑘, 𝜆, 𝜇) a strongly regular graphs with these
parameters, when one exists.
Using Andries Brouwer’s database of strongly regular graphs, it can also return non-existence results. Note that some
constructions are missing, and that some strongly regular graphs that exist in the database cannot be automatically built
by Sage. Help us if you know any. An outline of the implementation can be found in [CP2016].
Note: Any missing/incorrect information in the database must be reported to Andries E. Brouwer directly, in order to
have a unique and updated source of information.
REFERENCES:
[BL1984]
2.5.1 Functions
sage.graphs.strongly_regular_db.SRG_100_44_18_20()
Return a (100, 44, 18, 20)-strongly regular graph.
This graph is built as a Cayley graph, using the construction for ∆1 with group 𝐻3 presented in Table 8.1 of
[JK2003]
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_100_45_20_20()
Return a (100, 45, 20, 20)-strongly regular graph.
This graph is built as a Cayley graph, using the construction for Γ3 with group 𝐻3 presented in Table 8.1 of
[JK2003].
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_105_32_4_12()
Return a (105, 32, 4, 12)-strongly regular graph.
The vertices are the flags of the projective plane of order 4. Two flags (𝑎, 𝐴) and (𝑏, 𝐵) are adjacent if the point 𝑎
is on the line 𝐵 or the point 𝑏 is on the line 𝐴, and 𝑎 ̸= 𝑏, 𝐴 ̸= 𝐵. See Theorem 2.7 in [GS1970], and [Coo2006].
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_120_63_30_36()
Return a (120, 63, 30, 36)-strongly regular graph
It is the distance-2 graph of JohnsonGraph(10,3).
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_120_77_52_44()
Return a (120, 77, 52, 44)-strongly regular graph.
To build this graph, we first build a 2 − (21, 7, 12) design, by removing two points from the WittDesign() on
23 points. We then build the intersection graph of blocks with intersection size 3.
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_126_25_8_4()
Return a (126, 25, 8, 4)-strongly regular graph
It is the distance-(1 or 4) graph of JohnsonGraph(9,4).
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_126_50_13_24()
Return a (126, 50, 13, 24)-strongly regular graph
This graph is a subgraph of SRG_175_72_20_36(). This construction, due to Goethals, is given in §10B.(vii)
of [BL1984].
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_1288_792_476_504()
Return a (1288, 792, 476, 504)-strongly regular graph.
This graph is built on the words of weight 12 in the BinaryGolayCode(). Two of them are then made adjacent
if their symmetric difference has weight 12 (cf [BE1992]).
See also:
strongly_regular_from_two_weight_code() – build a strongly regular graph from a two-weight code.
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_144_39_6_12()
Return a (144, 39, 6, 12)-strongly regular graph.
This graph is obtained as an orbit of length 2808 on sets of cardinality 2 (among 2 such orbits) of the group
𝑃 𝐺𝐿3 (3) acting on the (right) cosets of a subgroup of order 39.
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_175_72_20_36()
Return a (175, 72, 20, 36)-strongly regular graph
This graph is obtained from the line graph of HoffmanSingletonGraph(). Setting two vertices to be adjacent
if their distance in the line graph is exactly 2 yields the graph. For more information, see 10.B.(iv) in [BL1984]
and https://www.win.tue.nl/~aeb/graphs/McL.html.
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_176_105_68_54()
Return a (176, 105, 68, 54)-strongly regular graph.
To build this graph, we first build a 2 − (22, 7, 16) design, by removing one point from the WittDesign() on
23 points. We then build the intersection graph of blocks with intersection size 3. Known as S.7 in [Hub1975].
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_176_49_12_14()
Return a (176, 49, 12, 14)-strongly regular graph.
This graph is built from the symmetric Higman-Sims design. In [Bro1982], it is explained that there exists an
involution 𝜎 exchanging the points and blocks of the Higman-Sims design, such that each point is mapped on
a block that contains it (i.e. 𝜎 is a ‘polarity with all universal points’). The graph is then built by making two
vertices 𝑢, 𝑣 adjacent whenever 𝑣 ∈ 𝜎(𝑢).
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_176_90_38_54()
Return a (176, 90, 38, 54)-strongly regular graph
This graph is obtained from SRG_175_72_20_36() by attaching a isolated vertex and doing Seidel switch-
ing with respect to disjoint union of 18 maximum cliques, following a construction by W.Haemers given in
Sect.10.B.(vi) of [BL1984].
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_196_91_42_42()
Return a (196, 91, 42, 42)-strongly regular graph.
This strongly regular graph is built following the construction provided in Corollary 8.2.27 of [IS2006].
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_210_99_48_45()
Return a strongly regular graph with parameters (210, 99, 48, 45)
This graph is from Example 4.2 in [KPRWZ2010]. One considers the action of the symmetric group 𝑆7
on the 210 digraphs isomorphic to the disjoint union of 𝐾1 and the circulant 6-vertex digraph digraphs.
Circulant(6,[1,4]). It has 16 orbitals; the package [FK1991] found a megring of them, explicitly described
in [KPRWZ2010], resulting in this graph.
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_220_84_38_28()
Return a (220, 84, 38, 28)-strongly regular graph.
This graph is obtained from the intersection_graph() of a BIBD_45_9_8(). This construction appears in
VII.11.2 from [DesignHandbook]
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_243_110_37_60()
Return a (243, 110, 37, 60)-strongly regular graph.
Consider the orthogonal complement of the TernaryGolayCode(), which has 243 words. On them we define
a graph, in which two words are adjacent whenever their Hamming distance is 9. This construction appears in
[GS1975].
Note: A strongly regular graph with the same parameters is also obtained from the database of 2-weight codes.
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_253_140_87_65()
Return a (253, 140, 87, 65)-strongly regular graph.
To build this graph, we first build the WittDesign() on 23 points which is a 2 − (23, 7, 21) design. We then
build the intersection graph of blocks with intersection size 3. Known as S.6 in [Hub1975].
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_276_140_58_84()
Return a (276, 140, 58, 84)-strongly regular graph.
The graph is built from McLaughlinGraph(), with an added isolated vertex. We then perform a
seidel_switching() on a set of 28 disjoint 5-cliques, which exist by cf. [HT1996].
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_280_117_44_52()
Return a strongly regular graph with parameters (280, 117, 44, 52).
This graph is built according to a very pretty construction of Mathon and Rosa [MR1985]:
The vertices of the graph 𝐺 are all partitions of a set of 9 elements into {{𝑎, 𝑏, 𝑐}, {𝑑, 𝑒, 𝑓 }, {𝑔, ℎ, 𝑖}}.
The cross-intersection of two such partitions 𝑃 = {𝑃1 , 𝑃2 , 𝑃3 } and 𝑃 ′ = {𝑃1′ , 𝑃2′ , 𝑃3′ } being defined
as {𝑃𝑖 ∩ 𝑃𝑗′ : 1 ≤ 𝑖, 𝑗 ≤ 3}, two vertices of 𝐺 are set to be adjacent if the cross-intersection of their
respective partitions does not contain exactly 7 nonempty sets.
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_280_135_70_60()
Return a strongly regular graph with parameters (280, 135, 70, 60).
This graph is built from the action of 𝐽2 on the cosets of a 3.𝑃 𝐺𝐿(2, 9)-subgroup.
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_416_100_36_20()
Return a (416, 100, 36, 20)-strongly regular graph.
This graph is obtained as an orbit on sets of cardinality 2 (among 2 that exists) of the group 𝐺2 (4). This graph
is isomorphic to the subgraph of the from Suzuki Graph induced on the neighbors of a vertex. Known as S.14
in [Hub1975].
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_560_208_72_80()
Return a (560, 208, 72, 80)-strongly regular graph
This graph is obtained as the union of 4 orbits of sets of cardinality 2 (among the 13 that exist) of the group
𝑆𝑧(8).
EXAMPLES:
sage.graphs.strongly_regular_db.SRG_630_85_20_10()
Return a (630, 85, 20, 10)-strongly regular graph
This graph is the line graph of 𝑝𝑔(5, 18, 2); its point graph is SRG_175_72_20_36(). One selects a subset of
630 maximum cliques in the latter following a construction by W.Haemers given in Sect.10.B.(v) of [BL1984].
EXAMPLES:
EXAMPLES:
some graphs
an example with vertex-transitive automorphism group, found during the implementation of the case 𝑣 = 324
sage.graphs.strongly_regular_db.apparently_feasible_parameters(n)
Return a list of a priori feasible parameters (𝑣, 𝑘, 𝜆, 𝜇), with 0 < 𝜇 < 𝑘.
Note that some of those that it returns may also be infeasible for more involved reasons. The condition 0 < 𝜇 < 𝑘
makes sure we skip trivial cases of complete multipartite graphs and their complements.
INPUT:
• n (integer) – return all a-priori feasible tuples (𝑣, 𝑘, 𝜆, 𝜇) for 𝑣 < 𝑛
EXAMPLES:
All sets of parameters with 𝑣 < 20 which pass basic arithmetic tests are feasible:
True
But that becomes wrong for 𝑣 < 60 (because of the non-existence of a (49, 16, 3, 6)-strongly regular graph):
False
sage.graphs.strongly_regular_db.eigenmatrix(v, k, l, mu)
Return the first eigenmatrix of a (𝑣, 𝑘, 𝑙, 𝑚𝑢)-strongly regular graph.
The adjacency matrix 𝐴 of an s.r.g. commutes with the adjacency matrix 𝐴′ = 𝐽 − 𝐴 − 𝐼 of its complement
(here 𝐽 is all-1 matrix, and 𝐼 the identity matrix). Thus, they can be simultaneously diagonalized and so 𝐴 and
𝐴′ share eigenspaces.
The eigenvalues of 𝐽 are 𝑣 with multiplicity 1, and 0 with multiplicity 𝑣 − 1. Thus the eigenvalue of 𝐴′ corre-
sponding to the 1-dimension 𝑘-eigenspace of 𝐴 is 𝑣 − 𝑘 − 1. Respectively, the eigenvalues of 𝐴′ corresponding
to 𝑡-eigenspace of 𝐴, with 𝑡 unequal to 𝑘, equals −𝑡 − 1. The 1st eigenmatrix 𝑃 of the C-algebra 𝐶[𝐴] gener-
ated by 𝐴 encodes this eigenvalue information in its three columns; the 2nd (resp. 3rd) column contains distinct
eigenvalues of 𝐴 (resp. of 𝐴′ ), and the 1st column contains the corresponding eigenvalues of 𝐼. The matrix
𝑣𝑃 −1 is called the 2nd eigenvalue matrix of 𝐶[𝐴].
The most interesting feature of 𝑣𝑃 −1 is that it is the 1st eigenmatrix of the dual of 𝐶[𝐴] if the dual is generated
by the adjacency matrix of a strongly regular graph. See [BH2012] and [BI1984] for details.
If the set of parameters is not feasible, or if they correspond to a conference graph, the function returns None. Its
output is stable, assuming that the eigenvalues r,s used satisfy r>s; this holds for the current implementation of
eigenvalues().
INPUT:
• v,k,l,mu (integers)
EXAMPLES:
Petersen’s graph’s C-algebra does not have a dual coming from an s.r.g.:
sage: P=eigenmatrix(9,4,1,2); P
[ 1 4 4]
[ 1 1 -2]
[ 1 -2 1]
sage: 9*P^-1
[ 1 4 4]
[ 1 1 -2]
[ 1 -2 1]
A strongly regular graph with a non-isomorphic dual coming from another strongly regular graph:
sage.graphs.strongly_regular_db.is_GQqmqp(v, k, l, mu)
Test whether some 𝐺𝑄(𝑞 − 1, 𝑞 + 1) or 𝐺𝑄(𝑞 + 1, 𝑞 − 1)-graph is (𝑣, 𝑘, 𝜆, 𝜇)-srg.
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage.graphs.strongly_regular_db.is_NO_F2(v, k, l, mu)
Test whether some NO^e,perp(2n,2) graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
For more information, see sage.graphs.graph_generators.GraphGenerators.
NonisotropicOrthogonalPolarGraph().
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage.graphs.strongly_regular_db.is_NO_F3(v, k, l, mu)
Test whether some NO^e,perp(2n,3) graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
For more information, see sage.graphs.graph_generators.GraphGenerators.
NonisotropicOrthogonalPolarGraph().
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage.graphs.strongly_regular_db.is_NOodd(v, k, l, mu)
Test whether some NO^e(2n+1,q) graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
Here 𝑞 > 2, for in the case 𝑞 = 2 this graph is complete. For more information, see sage.
graphs.graph_generators.GraphGenerators.NonisotropicOrthogonalPolarGraph() and Sect. 7.C
of [BL1984].
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage.graphs.strongly_regular_db.is_NOperp_F5(v, k, l, mu)
Test whether some NO^e,perp(2n+1,5) graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
For more information, see sage.graphs.graph_generators.GraphGenerators.
NonisotropicOrthogonalPolarGraph() and Sect. 7.D of [BL1984].
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage.graphs.strongly_regular_db.is_NU(v, k, l, mu)
Test whether some NU(n,q)-graph, is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
Note that n>2; for n=2 there is no s.r.g. For more information, see sage.graphs.graph_generators.
GraphGenerators.NonisotropicUnitaryPolarGraph() and series C14 in [Hub1975].
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage.graphs.strongly_regular_db.is_RSHCD(v, k, l, mu)
Test whether some RSHCD graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
For more information, see SRG_from_RSHCD().
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage.graphs.strongly_regular_db.is_affine_polar(v, k, l, mu)
Test whether some Affine Polar graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
For more information, see https://www.win.tue.nl/~aeb/graphs/VO.html.
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage: t = is_affine_polar(5,5,5,5); t
sage.graphs.strongly_regular_db.is_complete_multipartite(v, k, l, mu)
Test whether some complete multipartite graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
Any complete multipartite graph with parts of the same size is strongly regular.
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage.graphs.strongly_regular_db.is_cossidente_penttila(v, k, l, mu)
Test whether some CossidentePenttilaGraph graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
For more information, see CossidentePenttilaGraph().
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage.graphs.strongly_regular_db.is_goethals_seidel(v, k, l, mu)
Test whether some GoethalsSeidelGraph() graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage: t = is_goethals_seidel(5,5,5,5); t
sage.graphs.strongly_regular_db.is_haemers(v, k, l, mu)
Test whether some HaemersGraph graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
sage.graphs.strongly_regular_db.is_johnson(v, k, l, mu)
Test whether some Johnson graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage: t = is_johnson(5,5,5,5); t
sage.graphs.strongly_regular_db.is_mathon_PC_srg(v, k, l, mu)
Test whether some Mathon’s Pseudocyclic s.r.g. is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
Todo: The current implementation only gives a subset of all possible graphs that can be obtained using this
construction. A full implementation should rely on a database of conference matrices (or, equivalently, on a
database of s.r.g.’s with parameters (4𝑡 + 1, 2𝑡, 𝑡 − 1, 𝑡). Currently we make an extra assumption that 4𝑡 + 1 is a
prime power. The first case where we miss a construction is 𝑡 = 11, where we could (recursively) use the graph
for 𝑡 = 1 to construct a graph on 83205 vertices.
EXAMPLES:
sage.graphs.strongly_regular_db.is_muzychuk_S6(v, k, l, mu)
Test whether some Muzychuk S6 graph is (v, k, l, mu)-strongly regular.
Tests whether a MuzychukS6Graph() has parameters (v, k, l, mu).
INPUT:
• v, k, l, mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the required graph if it exists, and None otherwise.
EXAMPLES:
sage.graphs.strongly_regular_db.is_nowhere0_twoweight(v, k, l, mu)
Test whether some graph of nowhere 0 words is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
Test whether a Nowhere0WordsTwoWeightCodeGraph() is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if the parameters match, and None otherwise.
EXAMPLES:
sage.graphs.strongly_regular_db.is_orthogonal_array_block_graph(v, k, l, mu)
Test whether some (pseudo)Orthogonal Array graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
We know how to construct graphs with parameters of an Orthogonal Array (𝑂𝐴(𝑚, 𝑛)), also known as Latin
squares graphs 𝐿𝑚 (𝑛), in several cases where no orthogonal array is known, or even in some cases for which
they are known not to exist.
Such graphs are usually called pseudo-Latin squares graphs. Namely, Sage can construct a graph with parameters
of an 𝑂𝐴(𝑚, 𝑛)-graph whenever there exists a skew-Hadamard matrix of order 𝑛 + 1, and 𝑚 = (𝑛 + 1)/2 or
𝑚 = (𝑛 − 1)/2. The construction in the former case is due to Goethals-Seidel [BL1984], and in the latter case
due to Pasechnik [Pas1992].
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage: t = is_orthogonal_array_block_graph(5,5,5,5); t
sage.graphs.strongly_regular_db.is_orthogonal_polar(v, k, l, mu)
Test whether some Orthogonal Polar graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
For more information, see https://www.win.tue.nl/~aeb/graphs/srghub.html.
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage: t = is_orthogonal_polar(5,5,5,5); t
sage.graphs.strongly_regular_db.is_paley(v, k, l, mu)
Test whether some Paley graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage.graphs.strongly_regular_db.is_polhill(v, k, l, mu)
Test whether some graph from [Pol2009] is (1024, 𝑘, 𝜆, 𝜇)-strongly regular.
Note: This function does not actually explore all strongly regular graphs produced in [Pol2009], but only those
on 1024 vertices.
John Polhill offered his help if we attempt to write a code to guess, given (𝑣, 𝑘, 𝜆, 𝜇), which of his construction
must be applied to find the graph.
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if the parameters match, and None otherwise.
EXAMPLES:
sage.graphs.strongly_regular_db.is_steiner(v, k, l, mu)
Test whether some Steiner graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
A Steiner graph is the intersection graph of a Steiner set system. For more information, see https://www.win.tue.
nl/~aeb/graphs/S.html.
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage: t = is_steiner(5,5,5,5); t
sage.graphs.strongly_regular_db.is_switch_OA_srg(v, k, l, mu)
Test whether some switch 𝑂𝐴(𝑘, 𝑛) + * is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
The “switch* 𝑂𝐴(𝑘, 𝑛) + * graphs appear on Andries Brouwer’s database and are built by adding an isolated
vertex to a OrthogonalArrayBlockGraph(), and a Seidel switching a set of disjoint 𝑛-cocliques.
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if the parameters match, and None otherwise.
EXAMPLES:
sage.graphs.strongly_regular_db.is_switch_skewhad(v, k, l, mu)
Test whether some switch skewhad^2+* is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
The switch skewhad^2+* graphs appear on Andries Brouwer’s database and are built by adding an isolated
vertex to the complement of SquaredSkewHadamardMatrixGraph(), and a Seidel switching a set of dis-
joint 𝑛-cocliques.
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if the parameters match, and None otherwise.
EXAMPLES:
sage.graphs.strongly_regular_db.is_taylor_twograph_srg(v, k, l, mu)
Test whether some Taylor two-graph SRG is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
For more information, see §7E of [BL1984].
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph TaylorTwographSRG if the parameters match,
and None otherwise.
EXAMPLES:
sage: g.is_strongly_regular(parameters=True)
(27, 10, 1, 5)
sage: t = is_twograph_descendant_of_srg(5,5,5,5); t
sage.graphs.strongly_regular_db.is_unitary_dual_polar(v, k, l, mu)
Test whether some Unitary Dual Polar graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
This must be the U_5(q) on totally isotropic lines. For more information, see https://www.win.tue.nl/~aeb/
graphs/srghub.html.
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage.graphs.strongly_regular_db.is_unitary_polar(v, k, l, mu)
Test whether some Unitary Polar graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
For more information, see https://www.win.tue.nl/~aeb/graphs/srghub.html.
INPUT:
• v,k,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage: t = is_unitary_polar(5,5,5,5); t
sage.graphs.strongly_regular_db.latin_squares_graph_parameters(v, k, l, mu)
Check whether (v,k,l,mu)-strongly regular graph has parameters of an 𝐿𝑔 (𝑛) s.r.g.
Also known as pseudo-OA(n,g) case, i.e. s.r.g. with parameters of an OA(n,g)-graph. Return g and n, if they
exist. See Sect. 9.1 of [BH2012] for details.
INPUT:
• v,k,l,mu – (integers) parameters of the graph
OUTPUT:
• (g, n) – parameters of an 𝐿𝑔 (𝑛) graph, or 𝑁 𝑜𝑛𝑒
sage.graphs.strongly_regular_db.strongly_regular_from_two_intersection_set(M)
Return a strongly regular graph from a 2-intersection set.
A set of points in the projective geometry 𝑃 𝐺(𝑘, 𝑞) is said to be a 2-intersection set if it intersects every hyper-
plane in either ℎ1 or ℎ2 points, where ℎ1 , ℎ2 ∈
𝑁𝑁.
From a 2-intersection set 𝑆 can be defined a strongly-regular graph in the following way:
• Place the points of 𝑆 on a hyperplane 𝐻 in 𝑃 𝐺(𝑘 + 1, 𝑞)
• Define the graph 𝐺 on all points of 𝑃 𝐺(𝑘 + 1, 𝑞)∖𝐻
• Make two points of 𝑉 (𝐺) = 𝑃 𝐺(𝑘 + 1, 𝑞)∖𝐻 adjacent if the line going through them intersects 𝑆
For more information, see e.g. [CD2013] where this explanation has been taken from.
INPUT:
• 𝑀 – a |𝑆| × 𝑘 matrix with entries in 𝐹𝑞 representing the points of the 2-intersection set. We assume that
the first non-zero entry of each row is equal to 1, that is, they give points in homogeneous coordinates.
The implementation does not check that 𝑆 is actually a 2-intersection set.
EXAMPLES:
sage.graphs.strongly_regular_db.strongly_regular_from_two_weight_code(L)
Return a strongly regular graph from a two-weight code.
A code is said to be a two-weight code the weight of its nonzero codewords (i.e. their number of nonzero
coordinates) can only be one of two integer values 𝑤1 , 𝑤2 . It is said to be projective if the minimum weight
of the dual code is ≥ 3. A strongly regular graph can be built from a two-weight projective code with weights
𝑤1 , 𝑤2 (assuming 𝑤1 < 𝑤2 ) by adding an edge between any two codewords whose difference has weight 𝑤1 .
For more information, see [LS1981] or [Del1972].
INPUT:
• L – a two-weight linear code, or its generating matrix.
EXAMPLES:
sage: x=("100022021001111",
....: "010011211122000",
....: "001021112100011",
....: "000110120222220")
sage: M = Matrix(GF(3),[list(l) for l in x])
sage: G = strongly_regular_from_two_weight_code(LinearCode(M))
sage: G.is_strongly_regular(parameters=True)
(81, 50, 31, 30)
This function relies partly on Andries Brouwer’s database of strongly regular graphs. See the documentation of
sage.graphs.strongly_regular_db for more information.
INPUT:
• v,k,l,mu (integers) – note that mu, if unspecified, is automatically determined from v,k,l.
• existence (boolean;``False``) – instead of building the graph, return:
– True – meaning that a (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular graph exists.
– Unknown – meaning that Sage does not know if such a strongly regular graph exists (see sage.misc.
unknown).
– False – meaning that no such strongly regular graph exists.
• check – (boolean) Whether to check that output is correct before returning it. As this is expected to be
useless (but we are cautious guys), you may want to disable it whenever you want speed. Set to True by
default.
EXAMPLES:
Petersen’s graph from its set of parameters:
sage: graphs.strongly_regular_graph(10,3,0,1,existence=True)
True
sage: graphs.strongly_regular_graph(10,3,0,1)
complement(Johnson graph with parameters 5,2): Graph on 10 vertices
sage: graphs.strongly_regular_graph(10,3,0)
complement(Johnson graph with parameters 5,2): Graph on 10 vertices
sage: graphs.strongly_regular_graph(5,5,5,5,existence=True)
False
sage: graphs.strongly_regular_graph(5,5,5,5)
Traceback (most recent call last):
...
ValueError: There exists no (5, 5, 5, 5)-strongly regular graph
sage: graphs.strongly_regular_graph(324,57,0,12,existence=True)
False
sage: graphs.strongly_regular_graph(324,57,0,12)
Traceback (most recent call last):
...
EmptySetError: Andries Brouwer's database reports that no (324, 57, 0,
12)-strongly regular graph exists. Comments: <a
href="srgtabrefs.html#GavrilyukMakhnev05">Gavrilyuk & Makhnev</a> ...
sage: graphs.strongly_regular_graph(324,95,22,30,existence=True)
Unknown
sage: graphs.strongly_regular_graph(324,95,22,30)
(continues on next page)
sage: graphs.strongly_regular_graph(1394,175,0,25,existence=True)
Unknown
sage: graphs.strongly_regular_graph(1394,175,0,25)
Traceback (most recent call last):
...
RuntimeError: Sage cannot figure out if a (1394, 175, 0, 25)-strongly
regular graph exists.
sage: graphs.strongly_regular_graph(2058,242,91,20,existence=True)
False
In this module we construct several distance regular graphs and group them in a function that maps intersection arrays
to graphs.
For a survey on distance-regular graph see [BCN1989] or [VDKT2016].
EXAMPLES:
sage: G = graphs.cocliques_HoffmannSingleton()
sage: G.is_distance_regular()
True
sage: H = graphs.distance_regular_graph([15, 14, 10, 3, 1, 5, 12, 15])
sage: H == G
True
sage: G = graphs.distance_regular_graph([27, 10, 1, 1, 10, 27])
sage: G.is_distance_regular(True)
([27, 10, 1, None], [None, 1, 10, 27])
AUTHORS:
• Ivo Maffei (2020-07-28): initial version
sage.graphs.generators.distance_regular.AlternatingFormsGraph(n, q)
Return the alternating forms graph with the given parameters.
This builds a graph whose vertices are all 𝑛 skew-symmetric matrices over 𝐺𝐹 (𝑞) with zero diagonal. Two
vertices are adjacent if and only if the difference of the two matrices has rank 2.
𝑛
This grap is distance-regular with classical parameters (⌊ 𝑛2 ⌋, 𝑞 2 , 𝑞 2 − 1, 𝑞 2⌈ 2 ⌉−1 ).
INPUT:
• n – integer
• q – a prime power
EXAMPLES:
REFERENCES:
See [BCN1989] pp. 282-284 for a rather detailed discussion, otherwise see [VDKT2016] p. 22.
sage.graphs.generators.distance_regular.BilinearFormsGraph(d, e, q)
Return a bilinear forms graph with the given parameters.
This builds a graph whose vertices are all 𝑑 matrices over 𝐺𝐹 (𝑞). Two vertices are adjacent if the difference of
the two matrices has rank 1.
The graph is distance-regular with classical parameters (min(𝑑, 𝑒), 𝑞, 𝑞 − 1, 𝑞 max(𝑑,𝑒) − 1).
INPUT:
• d, e – integers; dimension of the matrices
• q – integer; a prime power
EXAMPLES:
sage: G = graphs.BilinearFormsGraph(3, 3, 2)
sage: G.is_distance_regular(True)
([49, 36, 16, None], [None, 1, 6, 28])
sage: G = graphs.BilinearFormsGraph(3,3,3) # not tested (20 s)
sage: G.order() # not tested (due to above)
19683
sage: G = graphs.BilinearFormsGraph(3, 4, 2) # long time
sage: G.is_distance_regular(True) # long time
([105, 84, 48, None], [None, 1, 6, 28])
REFERENCES:
See [BCN1989] pp. 280-282 for a rather detailed discussion, otherwise see [VDKT2016] p. 21.
sage.graphs.generators.distance_regular.ConwaySmith_for_3S7()
Return the Conway-Smith graph related to 3𝑆𝑦𝑚(7).
This is a distance-regular graph with intersection array [10, 6, 4, 1; 1, 2, 6, 10].
EXAMPLES:
sage: G = graphs.ConwaySmith_for_3S7()
sage: G.is_distance_regular(True)
([10, 6, 4, 1, None], [None, 1, 2, 6, 10])
REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 399.
sage.graphs.generators.distance_regular.DoubleGrassmannGraph(q, e)
Return the bipartite double of the distance-𝑒 graph of the Grassmann graph 𝐽𝑞 (𝑛, 𝑒).
This graph can also be descirbed as follows: Let 𝑉 be the vector space of dimension 𝑛 over 𝐺𝐹 (𝑞). The vertex
set is the set of 𝑒 + 1 or 𝑒 subspaces of 𝑉 . Two vertices are adjacent if one subspace is contained in the other.
This graph is distance-transitive.
INPUT:
• q – a prime power
• e – integer
EXAMPLES:
sage: G = graphs.DoubleGrassmannGraph(2,1)
sage: G.diameter()
3
sage: G.is_distance_regular(True)
([3, 2, 2, None], [None, 1, 1, 3])
REFERENCES:
See [BCN1989] pp. 272, 273 or [VDKT2016] p. 25.
sage.graphs.generators.distance_regular.DoubleOddGraph(n)
Return the double odd graph on 2𝑛 + 1 points.
The graph is obtained using the subsets of size 𝑛 and 𝑛 + 1 of 1, 2, ..., 2𝑛 + 1 as vertices. Two vertices are
adjacent if one is included in the other.
The graph is distance-transitive.
INPUT:
• n – integer; must be greater than 0
EXAMPLES:
sage: G = graphs.DoubleOddGraph(5)
sage: G.is_distance_regular(True)
([6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, None],
[None, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6])
sage: G = graphs.DoubleOddGraph(3)
sage: G.diameter()
7
sage: G.is_distance_regular(True)
([4, 3, 3, 2, 2, 1, 1, None], [None, 1, 1, 2, 2, 3, 3, 4])
REFERENCES:
See [BCN1989] pp. 259-261 or [VDKT2016] p. 25.
sage.graphs.generators.distance_regular.DoublyTruncatedWittGraph()
Return the doubly truncated Witt graph.
This builds the truncated Witt graph, then removes all vertices whose codeword start with a 1.
The graph is distance-regular with intersection array [7, 6, 4, 4; 1, 1, 1, 6].
EXAMPLES:
sage: G = graphs.DoublyTruncatedWittGraph()
sage: G.is_distance_regular(True)
([7, 6, 4, 4, None], [None, 1, 1, 1, 6])
REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 368.
sage.graphs.generators.distance_regular.FosterGraph3S6()
Return the Foster graph for 3.𝑆𝑦𝑚(6).
This graph is distance-regular with intersection array [6, 4, 2, 1; 1, 1, 4, 6].
The graph is also distance transitive.
EXAMPLES:
sage: G = graphs.FosterGraph3S6()
sage: G.is_distance_regular(True)
([6, 4, 2, 1, None], [None, 1, 1, 4, 6])
REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 397.
sage.graphs.generators.distance_regular.GeneralisedDodecagonGraph(s, t)
Return the point-graph of a generalised dodecagon of order (𝑠, 𝑡).
INPUT:
• s, t – integers; order of the generalised dodecagon
EXAMPLES:
Note: This function indirectly uses the GAP’s AtlasRep package. Thus you may need an internet connection
and the optional Sage’s package gap_packages.
REFERENCES:
See [BCN1989] pp. 200-205 for a discussion of distance-regular graphs from generalised polygons.
sage.graphs.generators.distance_regular.GeneralisedHexagonGraph(s, t)
Return the point-graph of a generalised hexagon of order (𝑠, 𝑡).
INPUT:
• s, t – integers; order of the generalised hexagon
EXAMPLES:
Note: This function uses the GAP’s AtlasRep package to build GHs of order (𝑞, 𝑞), (𝑞, 𝑞 3 ) or (𝑞 3 , 𝑞). For those
graphs you need an internet connection and Sage’s optional package gap_packages.
REFERENCES:
See [BCN1989] pp. 200-205 for a discussion of distance-regular graphs from generalised polygons.
sage.graphs.generators.distance_regular.GeneralisedOctagonGraph(s, t)
Return the point-graph of a generalised octagon of order (𝑠, 𝑡).
INPUT:
• s, t – integers; order of the generalised octagon
EXAMPLES:
sage: G = graphs.GeneralisedOctagonGraph(1, 4)
sage: G.is_distance_regular(True)
([5, 4, 4, 4, None], [None, 1, 1, 1, 5])
sage: G = graphs.GeneralisedOctagonGraph(2, 4) # optional - gap_packages internet
sage: G.is_distance_regular(True) # optional - gap_packages internet
([10, 8, 8, 8, None], [None, 1, 1, 1, 5])
sage: G = graphs.GeneralisedOctagonGraph(5, 1)
sage: G.is_distance_regular(True)
([10, 5, 5, 5, None], [None, 1, 1, 1, 2])
Note: This function uses the GAP’s AtlasRep package to build the graphs of order (2, 4) or (4, 2). For those
graphs you need an internet connection and Sage’s optional package gap_packages.
REFERENCES:
See [BCN1989] pp. 200-205 for a discussion of distance-regular graphs from generalised polygons.
sage.graphs.generators.distance_regular.GrassmannGraph(q, n, input_e)
Return the Grassmann graph with parameters (𝑞, 𝑛, 𝑒).
This builds the Grassmann graph 𝐽𝑞 (𝑛, 𝑒). That is, for a vector space 𝑉 = F(𝑞)𝑛 the output is the graph on the
subspaces of dimension 𝑒 where two subspaces are adjacent if their intersection has dimension 𝑒 − 1.
This graph is distance-regular with classical parameters (min(𝑒, 𝑛 − 𝑒), 𝑞, 𝑞, 𝑛−𝑒+1
[︀ ]︀
1 𝑞
− 1)
INPUT:
• q – a prime power
• n, e – integers with n > e+1
EXAMPLES:
sage: G = graphs.GrassmannGraph(2, 4, 2)
sage: G.is_distance_regular(True)
([18, 8, None], [None, 1, 9])
REFERENCES:
See [BCN1989] pp. 268-272 or [VDKT2016] p. 21.
sage.graphs.generators.distance_regular.HalfCube(n)
Return the halved cube in 𝑛 dimensions.
The graph is distance-regular with classical parameters (⌊ 𝑛2 ⌋, 1, 2, 2⌈ 𝑛2 ⌉ − 1).
INPUT:
• n – integer; must be greater than 2
EXAMPLES:
sage: G = graphs.HalfCube(8)
sage: G.is_distance_regular(True)
([28, 15, 6, 1, None], [None, 1, 6, 15, 28])
sage: G = graphs.HalfCube(4)
sage: G.is_distance_regular(True)
([6, 1, None], [None, 1, 6])
REFERENCES:
See [BCN1989] pp. 264, 265 or [VDKT2016] p. 21. This construction can be found on Wikipedia article
Halved_cube_graph#Equivalent_constructions
sage.graphs.generators.distance_regular.HermitianFormsGraph(n, r)
Return the Hermitian forms graph with the given parameters.
We build a graph whose vertices are all n``x``n Hermitian matrices over GF(r^2). Two vertices are adjacent
if the difference of the two vertices has rank 1.
This graph is distance-regular with classical parameters (𝑛, −𝑟, −𝑟 − 1, −(−𝑟)𝑑 − 1).
INPUT:
• n – integer
• r – a prime power
EXAMPLES:
sage: G = graphs.HermitianFormsGraph(2, 2)
sage: G.is_distance_regular(True)
([5, 4, None], [None, 1, 2])
sage: G = graphs.HermitianFormsGraph(3, 3) # not tested (2 min)
sage: G.order() # not tested (bacuase of the above)
19683
REFERENCES:
See [BCN1989] p. 285 or [VDKT2016] p. 22.
sage.graphs.generators.distance_regular.IvanovIvanovFaradjevGraph()
Return the IvanovIvanovFaradjev graph.
The graph is distance-transitive with automorphism group 3.𝑀22 .
EXAMPLES:
REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 369.
sage.graphs.generators.distance_regular.J2Graph()
Return the distance-transitive graph with automorphism group 𝐽2 .
EXAMPLES:
REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 408.
sage.graphs.generators.distance_regular.LargeWittGraph()
Return the large Witt graph.
This is a distance-regular graph with intersection array [30, 28, 24; 1, 3, 15].
EXAMPLES:
sage: g = graphs.LargeWittGraph()
sage: g.is_distance_regular(True)
([30, 28, 24, None], [None, 1, 3, 15])
REFERENCES:
A description of this graph can be found in [BCN1989] p. 366. This construction is taken from http://mathworld.
wolfram.com/LargeWittGraph.html
sage.graphs.generators.distance_regular.LeonardGraph()
Return the Leonard graph.
The graph is distance-regular with intersection array [12, 11, 10, 7; 1, 2, 5, 12].
EXAMPLES:
sage: G = graphs.LeonardGraph()
sage: G.is_distance_regular(True)
([12, 11, 10, 7, None], [None, 1, 2, 5, 12])
REFERENCES:
For a description of this graph see [BCN1989] p. 371.
sage.graphs.generators.distance_regular.TruncatedWittGraph()
Return the truncated Witt graph.
This builds the large Witt graph, then removes all vertices whose codeword start with a 1.
The graph is distance-regular with intersection array [15, 14, 12; 1, 1, 9].
EXAMPLES:
REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 367.
sage.graphs.generators.distance_regular.UstimenkoGraph(m, q)
Return the Ustimenko graph with parameters (𝑚, 𝑞).
This is the distance 1 or 2 graph of the dual polar graph 𝐶𝑚−1 (𝑞). The graph is distance-regular with classical
with parameters (𝑑, 𝑞 2 , 𝑞𝑏𝑖𝑛𝑜𝑚(3, 1, 𝑞) − 1, 𝑞𝑏𝑖𝑛𝑜𝑚(𝑚 + 1, 1, 𝑞) − 1)
INPUT:
• m, q – integers; q must be a prime power and m > 1.
EXAMPLES:
sage: G = graphs.UstimenkoGraph(4, 2)
sage: G.is_distance_regular(True)
([70, 32, None], [None, 1, 35])
REFERENCES:
See [BCN1989] p. 279 or [VDKT2016] p. 22.
sage.graphs.generators.distance_regular.cocliques_HoffmannSingleton()
Return the graph obtained from the cocliques of the Hoffmann-Singleton graph.
This is a distance-regular graph with intersection array [15, 14, 10, 3; 1, 5, 12, 15].
EXAMPLES:
sage: G = graphs.cocliques_HoffmannSingleton()
sage: G.is_distance_regular(True)
([15, 14, 10, 3, None], [None, 1, 5, 12, 15])
REFERENCES:
The construction of this graph can be found in [BCN1989] p. 392.
sage.graphs.generators.distance_regular.distance_3_doubly_truncated_Golay_code_graph()
Return a distance-regular graph with intersection array [9, 8, 6, 3; 1, 1, 3, 8].
EXAMPLES:
ALGORITHM:
Compute the binary Golay code and truncate it twice. Compute its coset graph. Take a vertex and compute the
set of vertices at distance 3 from the vertex chosen. This set constitutes the set of vertices of our distance-regular
graph. Moreover we have an edge (𝑢, 𝑣) if the coset graph contains such edge.
REFERENCES:
Description and construction of this graph are taken from [BCN1989] p. 364.
sage.graphs.generators.distance_regular.distance_regular_graph(arr, existence=False,
check=True)
Return a distance-regular graph with the intersection array given.
INPUT:
• arr – list; intersection array of the graph
• existence – boolean (optional); instead of building the graph return:
– True - if a graph with the given intersection array exists;
– False - if there is no graph with the given intersection array;
– Unknown - if Sage doesn’t know if such a graph exists.
• check – boolean (optional); if True, then checks that the result of this function has the given intersection
array. Default: True
EXAMPLES:
REFERENCES:
See [BCN1989] and [VDKT2016].
sage.graphs.generators.distance_regular.graph_3O73()
Return the graph related to the group 3𝑂(7, 3).
This graph is distance-regular with intersection array [117, 80, 24, 1; 1, 12, 80, 117].
The graph is also distance transitive with 3.𝑂(7, 3) as automorphism group
EXAMPLES:
REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 400.
sage.graphs.generators.distance_regular.graph_from_GQ_spread(s, t)
Return the point graph of the generalised quadrangle with order (𝑠, 𝑡) after removing one of its spreads.
These graphs are antipodal covers of complete graphs and, in particular, distance-regular graphs of diameter 3.
INPUT:
• s, t – integers; order of the generalised quadrangle
EXAMPLES:
REFERENCES:
The graphs constructed here follow [BCN1989] pp. 385, 386.
sage.graphs.generators.distance_regular.graph_with_classical_parameters(d, b, alpha_in,
beta_in, gamma)
Return the graph with the classical parameters given.
The last parameter gamma is meant to be an element of the enum ClassicalParametersGraph used to identify
the family of graphs to construct. In particular this function doesn’t build any sporadic graph. To build such a
graph use sage.graphs.generators.distance_regular.distance_regular_graph().
INPUT:
• d, b, alpha_in, beta_in – numbers; the parameters of the graph; d and b must be integers
• gamma – element of the enum ClassicalParametersGraph
EXAMPLES:
The last parameter is very important as it takes precedence. This function will not check that the
other four parameters match the correct family. Use sage.graphs.generators.distance_regular.
is_classical_parameters_graph() to check the parameters:
REFERENCES:
See [BCN1989] chapter 9 for a discussion of distance-regular graphs with classical parameters. See also
[VDKT2016] section 3.1.1.
sage.graphs.generators.distance_regular.is_classical_parameters_graph(array)
Return a tuple of parameters representing the array given. If such no tuple can be produced, it returns False.
Given an intersection array, if it represents a family of distance-regular graphs with classical parameters, then
this function returns a tuple consisting of the parameters (𝑑, 𝑏, 𝛼, 𝛽) and a fourth parameter which is the enum
CalssicalParametersGraph indicating the family with the given itersection array. If the array doesn’t belong
to any classical parameter graph, then this function returns False. If the array belongs to a sporadic graph rather
than a family of graphs, then the function returns False. This is to reduce the overlap with sage.graphs.
generators.distance_regular._sporadic_graph_database.
Note: The array given as an input is expected to be an intersection array. If this is not the case, then some
exception may be raised.
INPUT:
• array – list; an intersection array
OUTPUT:
False or a tuple (d, b, alpha, beta, gamma).
EXAMPLES:
REFERENCES:
See [BCN1989] chapter 9 for a discussion of distance-regular graphs with classical parameters. See [BCN1989]
chapter 6.2 for a method to compute the classical parameters of a graph. See also [VDKT2016] section 3.1.1.
sage.graphs.generators.distance_regular.is_from_GQ_spread(arr)
Return a pair (𝑠, 𝑡) if the graph obtained from a GQ of order (𝑠, 𝑡) with a spread has the intersection array passed.
We also require that such GQ can be built by Sage. If no such pair exists, then return False.
INPUT:
• arr – list; an intersection array
EXAMPLES:
REFERENCES:
The graphs we are looking for are antipodal covers of complete graphs. See [BCN1989] pp. 385, 386 for a
discussion on these particular case.
sage.graphs.generators.distance_regular.is_near_polygon(array)
Return a tuple of parameters which identify the near polygon graph with the given intersection array. If such
tuple doesn’t exist, return False.
Note that array may be the intersection array of a near polygon, but if such graph has diameter less than 3, then
this function will return False.
INPUT:
REFERENCES:
See [BCN1989] pp. 198-206 for some theory about near polygons as well as a list of known examples.
sage.graphs.generators.distance_regular.is_pseudo_partition_graph(arr)
Return (𝑚, 𝑎) if the intersection array given satisfies: 𝑏𝑖 = (𝑚 − 𝑖)(1 + 𝑎(𝑚 − 1 − 𝑖)) for 0 ≤ 𝑖 < 𝑑
𝑐𝑖 = 𝑖(1 + 𝑎(𝑖 − 1)) for 0 ≤ 𝑖 < 𝑑 𝑐𝑑 = (2𝑑 + 2 − 𝑚)𝑑(1 + 𝑎(𝑑 − 1)) where 𝑑 is the diameter of the graph.
If such pair (𝑚, 𝑎) doesn’t exist or the diameter is less than 3, then this function returns False.
These graphs are called pseudo partition graphs in [BCN1989] chapter 6.3.
INPUT:
• arr – list; intersection array
OUTPUT:
A pair (𝑚, 𝑎) of integers or False if such pair doesn’t exist.
EXAMPLES:
REFERENCE:
See [BCN1989] pp. 197, 198 or [VDKT2016] pp. 38, 39.
sage.graphs.generators.distance_regular.locally_GQ42_distance_transitive_graph()
Return the unique amply regular graph with 𝜇 = 6 which is locally a generalised quadrangle.
This graph is distance-regular with intersection array [45, 32, 12, 1; 1, 6, 32, 45].
This graph is also distance-transitive.
EXAMPLES:
REFERENCES:
A description of this graph can be found in [BCN1989] p.399. This construction is due to Dima Pasechnik.
sage.graphs.generators.distance_regular.near_polygon_graph(family, params)
Return the near polygon graph with the given parameters.
The input is expected to be the result of the function sage.graphs.generators.distance_regular.
is_near_polygon().
INPUT:
• family – int; an element of the enum NearPolygonGraph.
• params – int or tuple; the parameters needed to construct a graph of the family family.
EXAMPLES:
sage: from sage.graphs.generators.distance_regular import (
....: is_near_polygon, near_polygon_graph)
sage: near_polygon_graph(*is_near_polygon([6, 5, 5, 4, 4, 3, 3, 2, 2, \
....: 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6]))
Bipartite double of Odd graph on a set of 11 elements: Graph on 924 vertices
sage: G=_; G.is_distance_regular(True)
([6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, None],
[None, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6])
REFERENCES:
See [BCN1989] pp. 198-206 for some theory about near polygons as well as a list of known examples.
sage.graphs.generators.distance_regular.pseudo_partition_graph(m, a)
Return a pseudo partition graph with the given parameters.
A graph is a pseudo partition graph if it is distance-regular with diameter at least 3 and whose intersection
numbers satisfy: 𝑏𝑖 = (𝑚 − 𝑖)(1 + 𝑎(𝑚 − 1 − 𝑖)) for 0 ≤ 𝑖 < 𝑑 𝑐𝑖 = 𝑖(1 + 𝑎(𝑖 − 1)) for 0 ≤ 𝑖 < 𝑑
𝑐𝑑 = (2𝑑 + 2 − 𝑚)𝑑(1 + 𝑎(𝑑 − 1)) where 𝑑 is the diameter of the graph.
INPUT:
• m, a – integers; parameters of the graph
EXAMPLES:
sage: from sage.graphs.generators.distance_regular import *
sage: pseudo_partition_graph(6, 1)
Folded Johnson graph with parameters 12,6: Graph on 462 vertices
Not all graphs built with this function are pseudo partition graphs as intended by sage.graphs.generators.
distance_regular.is_pseudo_partition_graph(), since that function requires the diameter to be at least
3:
REFERENCES:
See [BCN1989] pp. 197, 198 or [VDKT2016] pp. 38, 39 for a discussion of known pseudo partition graphs.
sage.graphs.generators.distance_regular.shortened_000_111_extended_binary_Golay_code_graph()
Return a distance-regular graph with intersection array [21, 20, 16, 9, 2, 1; 1, 2, 3, 16, 20, 21].
EXAMPLES:
ALGORITHM:
Compute the extended binary Golay code. Compute its subcode whose codewords start with 000 or 111. Remove
the first 3 entries from all the codewords from the new linear code and compute its coset graph.
REFERENCES:
Description and construction of this graph can be found in [BCN1989] p. 365.
sage.graphs.generators.distance_regular.shortened_00_11_binary_Golay_code_graph()
Return a distance-regular graph with intersection array [21, 20, 16, 6, 2, 1; 1, 2, 6, 16, 20, 21].
EXAMPLES:
ALGORITHM:
Compute the binary Golay code. Compute the subcode whose codewords start with 00 or 11. Remove the first
two entries from all codewords of the newly found linear code and compute its coset graph.
REFERENCES:
Description and construction of this graph can be found in [BCN1989] p. 365.
sage.graphs.generators.distance_regular.vanLintSchrijverGraph()
Return the van Lint-Schrijver graph.
The graph is distance-regular with intersection array [6, 5, 5, 4; 1, 1, 2, 6].
EXAMPLES:
sage: G = graphs.vanLintSchrijverGraph()
sage: G.is_distance_regular(True)
([6, 5, 5, 4, None], [None, 1, 1, 2, 6])
REFERENCES:
For a description of this graph see [BCN1989] p. 373.
These include graphs of polar spaces, affine polar graphs, graphs related to Hermitean unitals, graphs on nonisotropic
points, etc
The methods defined here appear in sage.graphs.graph_generators.
sage.graphs.generators.classical_geometries.AffineOrthogonalPolarGraph(d, q, sign='+')
Return the affine polar graph 𝑉 𝑂+ (𝑑, 𝑞), 𝑉 𝑂− (𝑑, 𝑞) or 𝑉 𝑂(𝑑, 𝑞).
Affine Polar graphs are built from a 𝑑-dimensional vector space over 𝐹𝑞 , and a quadratic form which is hyperbolic,
elliptic or parabolic according to the value of sign.
Note that 𝑉 𝑂+ (𝑑, 𝑞), 𝑉 𝑂− (𝑑, 𝑞) are strongly regular graphs, while 𝑉 𝑂(𝑑, 𝑞) is not.
For more information on Affine Polar graphs, see Affine Polar Graphs page of Andries Brouwer’s website.
INPUT:
• d – integer; d must be even if sign is not None, and odd otherwise
• q – integer; a power of a prime number, as 𝐹𝑞 must exist
• sign – string (default: "+"); must be equal to "+", "-", or None to compute (respectively)
𝑉 𝑂+ (𝑑, 𝑞), 𝑉 𝑂− (𝑑, 𝑞) or 𝑉 𝑂(𝑑, 𝑞)
Note: The graph 𝑉 𝑂𝜖 (𝑑, 𝑞) is the graph induced by the non-neighbors of a vertex in an Orthogonal Polar
Graph 𝑂𝜖 (𝑑 + 2, 𝑞).
EXAMPLES:
The Brouwer-Haemers graph is isomorphic to 𝑉 𝑂− (4, 3):
sage: g = graphs.AffineOrthogonalPolarGraph(4,3,"-")
sage: g.is_isomorphic(graphs.BrouwerHaemersGraph())
True
sage.graphs.generators.classical_geometries.AhrensSzekeresGeneralizedQuadrangleGraph(q,
dual=False)
Return the collinearity graph of the generalized quadrangle 𝐴𝑆(𝑞), or of its dual
Let 𝑞 be an odd prime power. 𝐴𝑆(𝑞) is a generalized quadrangle (Wikipedia article Generalized_quadrangle) of
order (𝑞 − 1, 𝑞 + 1), see 3.1.5 in [PT2009]. Its points are elements of 𝐹𝑞3 , and lines are sets of size 𝑞 of the form
• {(𝜎, 𝑎, 𝑏) | 𝜎 ∈ 𝐹𝑞 }
• {(𝑎, 𝜎, 𝑏) | 𝜎 ∈ 𝐹𝑞 }
• {(𝑐𝜎 2 − 𝑏𝜎 + 𝑎, −2𝑐𝜎 + 𝑏, 𝜎) | 𝜎 ∈ 𝐹𝑞 },
where 𝑎, 𝑏, 𝑐 are arbitrary elements of 𝐹𝑞 .
INPUT:
• q – a power of an odd prime number
• dual – boolean (default: False); whether to return the collinearity graph of 𝐴𝑆(𝑞) or of the dual 𝐴𝑆(𝑞)
(when True)
EXAMPLES:
sage: g=graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5); g
AS(5); GQ(4, 6): Graph on 125 vertices
sage: g.is_strongly_regular(parameters=True)
(125, 28, 3, 7)
sage: g=graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5,dual=True); g
AS(5)*; GQ(6, 4): Graph on 175 vertices
sage: g.is_strongly_regular(parameters=True)
(175, 30, 5, 5)
sage.graphs.generators.classical_geometries.CossidentePenttilaGraph(q)
Return the Cossidente-Penttila ((𝑞 3 + 1)(𝑞 + 1)/2, (𝑞 2 + 1)(𝑞 − 1)/2, (𝑞 − 3)/2, (𝑞 − 1)2 /2)-strongly regular
graph
For each odd prime power 𝑞, one can partition the points of the 𝑂6− (𝑞)-generalized quadrangle 𝐺𝑄(𝑞, 𝑞 2 ) into
two parts, so that on any of them the induced subgraph of the point graph of the GQ has parameters as above
[CP2005].
Directly following the construction in [CP2005] is not efficient, as one then needs to construct the dual 𝐺𝑄(𝑞 2 , 𝑞).
Thus we describe here a more efficient approach that we came up with, following a suggestion by T.Penttila.
Namely, this partition is invariant under the subgroup 𝐻 = Ω3 (𝑞 2 ) < 𝑂6− (𝑞). We build the appropriate 𝐻,
which leaves the form 𝐵(𝑋, 𝑌, 𝑍) = 𝑋𝑌 + 𝑍 2 invariant, and pick up two orbits of 𝐻 on the 𝐹𝑞 -points. One
them is 𝐵-isotropic, and we take the representative (1 : 0 : 0). The other one corresponds to the points of
𝑃 𝐺(2, 𝑞 2 ) that have all the lines on them either missing the conic specified by 𝐵, or intersecting the conic in
two points. We take (1 : 1 : 𝑒) as the representative. It suffices to pick 𝑒 so that 𝑒2 + 1 is not a square in 𝐹𝑞2 .
Indeed, The conic can be viewed as the union of {(0 : 1 : 0)} and {(1 : −𝑡2 : 𝑡)|𝑡 ∈ 𝐹𝑞2 }. The coefficients of
a generic line on (1 : 1 : 𝑒) are [1 : −1 − 𝑒𝑏 : 𝑏], for −1 ̸= 𝑒𝑏. Thus, to make sure the intersection with the
conic is always even, we need that the discriminant of 1 + (1 + 𝑒𝑏)𝑡2 + 𝑡𝑏 = 0 never vanishes, and this is if and
only if 𝑒2 + 1 is not a square. Further, we need to adjust 𝐵, by multiplying it by appropriately chosen 𝜈, so that
(1 : 1 : 𝑒) becomes isotropic under the relative trace norm 𝜈𝐵(𝑋, 𝑌, 𝑍) + (𝜈𝐵(𝑋, 𝑌, 𝑍))𝑞 . The latter is used
then to define the graph.
INPUT:
2.7. Families of graphs derived from classical geometries over finite fields 691
Graph Theory, Release 9.7
sage.graphs.generators.classical_geometries.HaemersGraph(q, hyperoval=None,
hyperoval_matching=None, field=None,
check_hyperoval=True)
Return the Haemers graph obtained from 𝑇2* (𝑞)*
Let 𝑞 be a power of 2. In Sect. 8.A of [BL1984] one finds a construction of a strongly regu-
lar graph with parameters (𝑞 2 (𝑞 + 2), 𝑞 2 + 𝑞 − 1, 𝑞 − 2, 𝑞) from the graph of 𝑇2* (𝑞)* , constructed by
T2starGeneralizedQuadrangleGraph(), by redefining adjacencies in the way specified by an arbitrary
hyperoval_matching of the points (i.e. partitioning into size two parts) of hyperoval defining 𝑇2* (𝑞)* .
While [BL1984] gives the construction in geometric terms, it can be formulated, and is implemented, in graph-
theoretic ones, of re-adjusting the edges. Namely, 𝐺 = 𝑇2* (𝑞)* has a partition into 𝑞 + 2 independent sets 𝐼𝑘
of size 𝑞 2 each. Each vertex in 𝐼𝑗 is adjacent to 𝑞 vertices from 𝐼𝑘 . Each 𝐼𝑘 is paired to some 𝐼𝑘′ , according to
hyperoval_matching. One adds edges (𝑠, 𝑡) for 𝑠, 𝑡 ∈ 𝐼𝑘 whenever 𝑠 and 𝑡 are adjacent to some 𝑢 ∈ 𝐼𝑘′ , and
removes all the edges between 𝐼𝑘 and 𝐼𝑘′ .
INPUT:
• q – a power of two
• hyperoval_matching – if None (default), pair each 𝑖-th point of hyperoval with (𝑖 + 1)-th. Otherwise,
specifies the pairing in the format ((𝑖1 , 𝑖′1 ), (𝑖2 , 𝑖′2 ), ...).
• hyperoval – a hyperoval defining 𝑇2* (𝑞)* . If None (default), the classical hyperoval obtained from a conic
is used. See the documentation of T2starGeneralizedQuadrangleGraph(), for more information.
• field – an instance of a finite field of order 𝑞, must be provided if hyperoval is provided
• check_hyperoval – boolean (default: True); whether to check hyperoval for correctness or not
EXAMPLES:
using the built-in constructions:
sage: g=graphs.HaemersGraph(4); g
Haemers(4): Graph on 96 vertices
sage: g.is_strongly_regular(parameters=True)
(96, 19, 2, 4)
sage: g=graphs.HaemersGraph(4,hyperoval_matching=((0,5),(1,4),(2,3))); g
Haemers(4): Graph on 96 vertices
(continues on next page)
sage.graphs.generators.classical_geometries.NonisotropicOrthogonalPolarGraph(m, q, sign='+',
perp=None)
Return the Graph 𝑁 𝑂𝑚
𝜖,⊥
(𝑞)
Let the vectorspace of dimension 𝑚 over 𝐹𝑞 be endowed with a nondegenerate quadratic form 𝐹 , of type sign
for 𝑚 even.
• 𝑚 even: assume further that 𝑞 = 2 or 3. Returns the graph of the points (in the underlying projective space)
𝑥 satisfying 𝐹 (𝑥) = 1, with adjacency given by orthogonality w.r.t. 𝐹 . Parameter perp is ignored.
• 𝑚 odd: if perp is not None, then we assume that 𝑞 = 5 and return the graph of the points 𝑥 satisfying
𝐹 (𝑥) = ±1 if sign="+", respectively 𝐹 (𝑥) ∈ {2, 3} if sign="-", with adjacency given by orthogonality
w.r.t. 𝐹 (cf. Sect 7.D of [BL1984]). Otherwise return the graph of nongenerate hyperplanes of type sign,
adjacent whenever the intersection is degenerate (cf. Sect. 7.C of [BL1984]). Note that for 𝑞 = 2 one will
get a complete graph.
For more information, see Sect. 9.9 of [BH2012] and [BL1984]. Note that the page of Andries Brouwer’s website
uses different notation.
INPUT:
• m – integer; half the dimension of the underlying vectorspace
• q – a power of a prime number, the size of the underlying field
• sign – string (default: "+"); must be either "+" or "-"
EXAMPLES:
𝑁 𝑂− (4, 2) is isomorphic to Petersen graph:
sage: g=graphs.NonisotropicOrthogonalPolarGraph(4,2,'-'); g
NO^-(4, 2): Graph on 10 vertices
sage: g.is_strongly_regular(parameters=True)
(10, 3, 0, 1)
sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,2,'-')
sage: g.is_strongly_regular(parameters=True)
(36, 15, 6, 6)
sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,2,'+'); g
NO^+(6, 2): Graph on 28 vertices
sage: g.is_strongly_regular(parameters=True)
(28, 15, 6, 10)
𝑁 𝑂+ (8, 2):
sage: g=graphs.NonisotropicOrthogonalPolarGraph(8,2,'+')
sage: g.is_strongly_regular(parameters=True)
(120, 63, 30, 36)
2.7. Families of graphs derived from classical geometries over finite fields 693
Graph Theory, Release 9.7
sage: graphs.NonisotropicOrthogonalPolarGraph(5,5,perp=1).is_strongly_
˓→regular(parameters=True) # long time
(325, 60, 15, 10)
sage: graphs.NonisotropicOrthogonalPolarGraph(5,5,'-',perp=1).is_strongly_
˓→regular(parameters=True) # long time
(300, 65, 10, 15)
Wilbrink’s graphs:
sage: g=graphs.NonisotropicOrthogonalPolarGraph(5,4,'+')
sage: g.is_strongly_regular(parameters=True)
(136, 75, 42, 40)
sage: g=graphs.NonisotropicOrthogonalPolarGraph(5,4,'-')
sage: g.is_strongly_regular(parameters=True)
(120, 51, 18, 24)
sage: g=graphs.NonisotropicOrthogonalPolarGraph(7,4,'+'); g # not tested (long␣
˓→time)
sage.graphs.generators.classical_geometries.NonisotropicUnitaryPolarGraph(m, q)
Return the Graph 𝑁 𝑈 (𝑚, 𝑞).
This returns the graph on nonisotropic, with respect to a nondegenerate Hermitean form, points of the (𝑚 − 1)-
dimensional projective space over 𝐹𝑞 , with points adjacent whenever they lie on a tangent (to the set of isotropic
points) line. For more information, see Sect. 9.9 of [BH2012] and series C14 in [Hub1975].
INPUT:
• m,q – integers; 𝑞 must be a prime power
EXAMPLES:
sage: g=graphs.NonisotropicUnitaryPolarGraph(5,2); g
NU(5, 2): Graph on 176 vertices
sage: g.is_strongly_regular(parameters=True)
(176, 135, 102, 108)
sage.graphs.generators.classical_geometries.Nowhere0WordsTwoWeightCodeGraph(q,
hyperoval=None,
field=None,
check_hyperoval=True)
Return the subgraph of nowhere 0 words from two-weight code of projective plane hyperoval.
Let 𝑞 = 2𝑘 and Π = 𝑃 𝐺(2, 𝑞). Fix a hyperoval 𝑂 ⊂ Π. Let 𝑉 = 𝐹𝑞3 and 𝐶 the two-weight 3-dimensional
linear code over 𝐹𝑞 with words 𝑐(𝑣) obtained from 𝑣 ∈ 𝑉 by computing
𝐶 contains 𝑞(𝑞 − 1)2 /2 words without 0 entries. The subgraph of the strongly regular graph of 𝐶 induced on
the latter words is also strongly regular, assuming 𝑞 > 4. This is a construction due to A.E.Brouwer [Bro2016],
and leads to graphs with parameters also given by a construction in [HHL2009]. According to [Bro2016], these
two constructions are likely to produce isomorphic graphs.
INPUT:
• q – a power of two
• hyperoval – a hyperoval (i.e. a complete 2-arc; a set of points in the plane meeting every line in 0 or 2
points) in 𝑃 𝐺(2, 𝑞) over the field field. Each point of hyperoval must be a length 3 vector over field
with 1st non-0 coordinate equal to 1. By default, hyperoval and field are not specified, and constructed
on the fly. In particular, hyperoval we build is the classical one, i.e. a conic with the point of intersection
of its tangent lines.
• field – an instance of a finite field of order 𝑞, must be provided if hyperoval is provided.
• check_hyperoval – boolean (default: True); whether to check hyperoval for correctness or not
See also:
• is_nowhere0_twoweight()
EXAMPLES:
using the built-in construction:
sage: g=graphs.Nowhere0WordsTwoWeightCodeGraph(8); g
Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices
sage: g.is_strongly_regular(parameters=True)
(196, 60, 14, 20)
sage: g=graphs.Nowhere0WordsTwoWeightCodeGraph(16) # not tested (long time)
sage: g.is_strongly_regular(parameters=True) # not tested (long time)
(1800, 728, 268, 312)
sage: F=GF(8)
sage: O=[vector(F,(0,0,1)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F]
sage: g=graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F); g
Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices
sage: g.is_strongly_regular(parameters=True)
(196, 60, 14, 20)
sage.graphs.generators.classical_geometries.OrthogonalDualPolarGraph(e, d, q)
Return the dual polar graph on 𝐺𝑂𝑒 (𝑛, 𝑞) of diameter 𝑑.
The value of 𝑛 is determined by 𝑑 and 𝑒.
The graph is distance-regular with classical parameters (𝑑, 𝑞, 0, 𝑞 𝑒 ).
INPUT:
• e – integer; type of the orthogonal polar space to consider; must be −1, 0 or 1.
• d – integer; diameter of the graph
• q – integer; prime power; order of the finite field over which to build the polar space
EXAMPLES:
sage: G = graphs.OrthogonalDualPolarGraph(1,3,2)
sage: G.is_distance_regular(True)
([7, 6, 4, None], [None, 1, 3, 7])
sage: G = graphs.OrthogonalDualPolarGraph(0,3,3) # long time
sage: G.is_distance_regular(True) # long time
([39, 36, 27, None], [None, 1, 4, 13])
sage: G.order() # long time
1120
2.7. Families of graphs derived from classical geometries over finite fields 695
Graph Theory, Release 9.7
REFERENCES:
See [BCN1989] pp. 274-279 or [VDKT2016] p. 22.
sage.graphs.generators.classical_geometries.OrthogonalPolarGraph(m, q, sign='+')
Return the Orthogonal Polar Graph 𝑂𝜖 (𝑚, 𝑞).
For more information on Orthogonal Polar graphs, see the page of Andries Brouwer’s website.
INPUT:
• m,q – integers; 𝑞 must be a prime power
• sign – string (default: "+"); must be "+" or "-" if 𝑚 is even, "+" (default) otherwise
EXAMPLES:
sage: G = graphs.OrthogonalPolarGraph(6,3,"+"); G
Orthogonal Polar Graph O^+(6, 3): Graph on 130 vertices
sage: G.is_strongly_regular(parameters=True)
(130, 48, 20, 16)
sage: G = graphs.OrthogonalPolarGraph(6,3,"-"); G
Orthogonal Polar Graph O^-(6, 3): Graph on 112 vertices
sage: G.is_strongly_regular(parameters=True)
(112, 30, 2, 10)
sage: G = graphs.OrthogonalPolarGraph(5,3); G
Orthogonal Polar Graph O(5, 3): Graph on 40 vertices
sage: G.is_strongly_regular(parameters=True)
(40, 12, 2, 4)
sage: G = graphs.OrthogonalPolarGraph(8,2,"+"); G
Orthogonal Polar Graph O^+(8, 2): Graph on 135 vertices
sage: G.is_strongly_regular(parameters=True)
(135, 70, 37, 35)
sage: G = graphs.OrthogonalPolarGraph(8,2,"-"); G
Orthogonal Polar Graph O^-(8, 2): Graph on 119 vertices
sage: G.is_strongly_regular(parameters=True)
(119, 54, 21, 27)
sage.graphs.generators.classical_geometries.SymplecticDualPolarGraph(m, q)
Return the Symplectic Dual Polar Graph 𝐷𝑆𝑝(𝑚, 𝑞).
For more information on Symplectic Dual Polar graphs, see [BCN1989] and Sect. 2.3.1 of [Coh1981].
INPUT:
• m,q – integers; 𝑞 must be a prime power, and 𝑚 must be even
EXAMPLES:
sage.graphs.generators.classical_geometries.SymplecticPolarGraph(d, q, algorithm=None)
Return the Symplectic Polar Graph 𝑆𝑝(𝑑, 𝑞).
The Symplectic Polar Graph 𝑆𝑝(𝑑, 𝑞) is built from a projective space of dimension 𝑑 − 1 over a field 𝐹𝑞 , and a
symplectic form 𝑓 . Two vertices 𝑢, 𝑣 are made adjacent if 𝑓 (𝑢, 𝑣) = 0.
See the page on symplectic graphs on Andries Brouwer’s website.
INPUT:
• d,q – integers; note that only even values of 𝑑 are accepted by the function.
• algorithm – string (default: None); if set to ‘gap’ then the computation is carried via GAP library interface,
computing totally singular subspaces, which is faster for 𝑞 > 3. Otherwise it is done directly.
EXAMPLES:
Computation of the spectrum of 𝑆𝑝(6, 2):
sage: g = graphs.SymplecticPolarGraph(6,2)
sage: g.is_strongly_regular(parameters=True)
(63, 30, 13, 15)
sage: set(g.spectrum()) == {-5, 3, 30}
True
The parameters of 𝑆𝑝(4, 𝑞) are the same as of 𝑂(5, 𝑞), but they are not isomorphic if 𝑞 is odd:
sage: G = graphs.SymplecticPolarGraph(4,3)
sage: G.is_strongly_regular(parameters=True)
(40, 12, 2, 4)
sage: O=graphs.OrthogonalPolarGraph(5,3)
sage: O.is_strongly_regular(parameters=True)
(40, 12, 2, 4)
sage: O.is_isomorphic(G)
False
sage: graphs.SymplecticPolarGraph(6,4,algorithm="gap").is_strongly_
˓→regular(parameters=True) # not tested (long time)
sage.graphs.generators.classical_geometries.T2starGeneralizedQuadrangleGraph(q, dual=False,
hyper-
oval=None,
field=None,
check_hyperoval=True)
Return the collinearity graph of the generalized quadrangle 𝑇2* (𝑞), or of its dual
Let 𝑞 = 2𝑘 and Θ = 𝑃 𝐺(3, 𝑞). 𝑇2* (𝑞) is a generalized quadrangle (Wikipedia article Generalized_quadrangle)
of order (𝑞 − 1, 𝑞 + 1), see 3.1.3 in [PT2009]. Fix a plane Π ⊂ Θ and a hyperoval 𝑂 ⊂ Π. The points of
𝑇2* (𝑞) := 𝑇2* (𝑂) are the points of Θ outside Π, and the lines are the lines of Θ outside Π that meet Π in a point
of 𝑂.
INPUT:
• q – a power of two
• dual – boolean (default: False); whether to return the graph of 𝑇2* (𝑂) or of the dual 𝑇2* (𝑂) (when True)
• hyperoval – a hyperoval (i.e. a complete 2-arc; a set of points in the plane meeting every line in 0
or 2 points) in the plane of points with 0th coordinate 0 in 𝑃 𝐺(3, 𝑞) over the field field. Each point
of hyperoval must be a length 4 vector over field with 1st non-0 coordinate equal to 1. By default,
hyperoval and field are not specified, and constructed on the fly. In particular, hyperoval we build is
the classical one, i.e. a conic with the point of intersection of its tangent lines.
• field – an instance of a finite field of order 𝑞, must be provided if hyperoval is provided
• check_hyperoval – boolean (default: True); whether to check hyperoval for correctness or not
EXAMPLES:
2.7. Families of graphs derived from classical geometries over finite fields 697
Graph Theory, Release 9.7
sage: g=graphs.T2starGeneralizedQuadrangleGraph(4); g
T2*(O,4); GQ(3, 5): Graph on 64 vertices
sage: g.is_strongly_regular(parameters=True)
(64, 18, 2, 6)
sage: g=graphs.T2starGeneralizedQuadrangleGraph(4,dual=True); g
T2*(O,4)*; GQ(5, 3): Graph on 96 vertices
sage: g.is_strongly_regular(parameters=True)
(96, 20, 4, 4)
sage: F=GF(4,'b')
sage: O=[vector(F,(0,0,0,1)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in␣
˓→F]
sage.graphs.generators.classical_geometries.TaylorTwographDescendantSRG(q,
clique_partition=False)
Return the descendant graph of the Taylor’s two-graph for 𝑈3 (𝑞), 𝑞 odd.
This is a strongly regular graph with parameters (𝑣, 𝑘, 𝜆, 𝜇) = (𝑞 3 , (𝑞 2 + 1)(𝑞 − 1)/2, (𝑞 − 1)3 /4 − 1, (𝑞 2 +
1)(𝑞 − 1)/4) obtained as a two-graph descendant of the Taylor's two-graph 𝑇 . This graph admits a partition
into cliques of size 𝑞, which are useful in TaylorTwographSRG(), a strongly regular graph on 𝑞 3 + 1 vertices
in the Seidel switching class of 𝑇 , for which we need (𝑞 2 + 1)/2 cliques. The cliques are the 𝑞 2 lines on 𝑣0 of
the projective plane containing the unital for 𝑈3 (𝑞), and intersecting the unital (i.e. the vertices of the graph and
the point we remove) in 𝑞 + 1 points. This is all taken from §7E of [BL1984].
INPUT:
• q – a power of an odd prime number
• clique_partition – boolean (default: False); when set to True, return 𝑞 2 − 1 cliques of size 𝑞 with
empty pairwise intersection. (Removing all of them leaves a clique, too), and the point removed from the
unital.
EXAMPLES:
sage: g=graphs.TaylorTwographDescendantSRG(3); g
Taylor two-graph descendant SRG: Graph on 27 vertices
sage: g.is_strongly_regular(parameters=True)
(27, 10, 1, 5)
sage: from sage.combinat.designs.twographs import taylor_twograph
sage: T = taylor_twograph(3) # long time
sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long time
True
sage: g=graphs.TaylorTwographDescendantSRG(5) # not tested (long time)
sage: g.is_strongly_regular(parameters=True) # not tested (long time)
(125, 52, 15, 26)
sage.graphs.generators.classical_geometries.TaylorTwographSRG(q)
Return a strongly regular graph from the Taylor’s two-graph for 𝑈3 (𝑞), 𝑞 odd
This is a strongly regular graph with parameters (𝑣, 𝑘, 𝜆, 𝜇) = (𝑞 3 + 1, 𝑞(𝑞 2 + 1)/2, (𝑞 2 + 3)(𝑞 − 1)/4, (𝑞 2 +
1)(𝑞 + 1)/4) in the Seidel switching class of Taylor two-graph. Details are in §7E of [BL1984].
INPUT:
• q – a power of an odd prime number
See also:
• TaylorTwographDescendantSRG()
EXAMPLES:
sage: t=graphs.TaylorTwographSRG(3); t
Taylor two-graph SRG: Graph on 28 vertices
sage: t.is_strongly_regular(parameters=True)
(28, 15, 6, 10)
sage.graphs.generators.classical_geometries.UnitaryDualPolarGraph(m, q)
Return the Dual Unitary Polar Graph 𝑈 (𝑚, 𝑞).
For more information on Unitary Dual Polar graphs, see [BCN1989] and Sect. 2.3.1 of [Coh1981].
INPUT:
• m,q – integers; 𝑞 must be a prime power
EXAMPLES:
The point graph of a generalized quadrangle (see Wikipedia article Generalized_quadrangle, [PT2009]) of order
(8,4):
sage: G = graphs.UnitaryDualPolarGraph(4,2); G
Unitary Dual Polar Graph DU(4, 2); GQ(2, 4): Graph on 27 vertices
sage: G.is_isomorphic(graphs.OrthogonalPolarGraph(6,2,'-'))
True
A bigger graph:
sage.graphs.generators.classical_geometries.UnitaryPolarGraph(m, q, algorithm='gap')
Return the Unitary Polar Graph 𝑈 (𝑚, 𝑞).
For more information on Unitary Polar graphs, see the page of Andries Brouwer’s website.
INPUT:
• m,q – integers; 𝑞 must be a prime power
2.7. Families of graphs derived from classical geometries over finite fields 699
Graph Theory, Release 9.7
• algorithm – string (default: "gap"); if set to ‘gap’ then the computation is carried via GAP library
interface, computing totally singular subspaces, which is faster for large examples (especially with 𝑞 > 2).
Otherwise it is done directly.
EXAMPLES:
sage: G = graphs.UnitaryPolarGraph(4,2); G
Unitary Polar Graph U(4, 2); GQ(4, 2): Graph on 45 vertices
sage: G.is_strongly_regular(parameters=True)
(45, 12, 3, 3)
sage: graphs.UnitaryPolarGraph(5,2).is_strongly_regular(parameters=True)
(165, 36, 3, 9)
sage: graphs.UnitaryPolarGraph(6,2) # not tested (long time)
Unitary Polar Graph U(6, 2): Graph on 693 vertices
sage: graphs.AztecDiamondGraph(2)
Aztec Diamond graph of order 2
sage: G = graphs.AztecDiamondGraph(3)
sage: sum(1 for p in G.perfect_matchings())
64
sage.graphs.generators.families.BalancedTree(r, h)
Returns the perfectly balanced tree of height ℎ ≥ 1, whose root has degree 𝑟 ≥ 2.
𝑟 ℎ+1 −1
The number of vertices of this graph is 1 + 𝑟 + 𝑟2 + · · · + 𝑟ℎ , that is, 𝑟−1 . The number of edges is one less
than the number of vertices.
INPUT:
• r – positive integer ≥ 2. The degree of the root node.
• h – positive integer ≥ 1. The height of the balanced tree.
OUTPUT:
The perfectly balanced tree of height ℎ ≥ 1 and whose root has degree 𝑟 ≥ 2. A NetworkXError is returned if
𝑟 < 2 or ℎ < 1.
ALGORITHM:
Uses NetworkX.
EXAMPLES:
A balanced tree whose root node has degree 𝑟 = 2, and of height ℎ = 1, has order 3 and size 2:
sage: G = graphs.BalancedTree(3, 5)
sage: G.show() # long time
sage.graphs.generators.families.BarbellGraph(n1, n2)
Returns a barbell graph with 2*n1 + n2 nodes. The argument n1 must be greater than or equal to 2.
A barbell graph is a basic structure that consists of a path graph of order n2 connecting two complete graphs of
order n1 each.
INPUT:
• n1 – integer ≥ 2. The order of each of the two complete graphs.
• n2 – nonnegative integer. The order of the path graph connecting the two complete graphs.
OUTPUT:
A barbell graph of order 2*n1 + n2. A ValueError is returned if n1 < 2 or n2 < 0.
PLOTTING:
Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, each
barbell graph will be displayed with the two complete graphs in the lower-left and upper-right corners, with the
path graph connecting diagonally between the two. Thus the n1-th node will be drawn at a 45 degree angle from
the horizontal right center of the first complete graph, and the n1 + n2 + 1-th node will be drawn 45 degrees
below the left horizontal center of the second complete graph.
EXAMPLES:
Construct and show a barbell graph Bar = 4, Bells = 9:
An n1 >= 2, n2 >= 0 barbell graph has order 2*n1 + n2. It has the complete graph on n1 vertices as a
subgraph. It also has the path graph on n2 vertices as a subgraph.
sage.graphs.generators.families.BubbleSortGraph(n)
Returns the bubble sort graph 𝐵(𝑛).
The vertices of the bubble sort graph are the set of permutations on 𝑛 symbols. Two vertices are adjacent if one
can be obtained from the other by swapping the labels in the 𝑖-th and (𝑖 + 1)-th positions for 1 ≤ 𝑖 ≤ 𝑛 − 1. In
total, 𝐵(𝑛) has order 𝑛!. Swapping two labels as described previously corresponds to multiplying on the right
the permutation corresponding to the node by an elementary transposition in the SymmetricGroup.
The bubble sort graph is the underlying graph of the permutahedron().
INPUT:
• n – positive integer. The number of symbols to permute.
OUTPUT:
The bubble sort graph 𝐵(𝑛) on 𝑛 symbols. If 𝑛 < 1, a ValueError is returned.
EXAMPLES:
sage: g = graphs.BubbleSortGraph(4); g
Bubble sort: Graph on 24 vertices
sage: g.plot() # long time
Graphics object consisting of 61 graphics primitives
sage: graphs.BubbleSortGraph(1)
Bubble sort: Graph on 1 vertex
sage: n = randint(1, 8)
sage: g = graphs.BubbleSortGraph(n)
sage: g.order() == factorial(n)
True
See also:
• permutahedron()
AUTHORS:
• Michael Yurko (2009-09-01)
sage.graphs.generators.families.CaiFurerImmermanGraph(G, twisted=False)
Return the a Cai-Furer-Immerman graph from 𝐺, possibly a twisted one, and a partition of its nodes.
A Cai-Furer-Immerman graph from/on 𝐺 is a graph created by applying the transformation described in
[CFI1992] on a graph 𝐺, that is substituting every vertex v in 𝐺 with a Furer gadget 𝐹 (𝑣) of order d equal
to the degree of the vertex, and then substituting every edge (𝑣, 𝑢) in 𝐺 with a pair of edges, one connecting the
two “a” nodes of 𝐹 (𝑣) and 𝐹 (𝑢) and the other their two “b” nodes. The returned coloring of the vertices is made
by the union of the colorings of each single Furer gadget, individualised for each vertex of 𝐺. To understand
better what these “a” and “b” nodes are, see the documentation on Furer gadgets.
Furthermore, this method can apply what is described in the paper mentioned above as a “twist” on an edge, that
is taking only one of the pairs of edges introduced in the new graph and swap two of their extremes, making each
edge go from an “a” node to a “b” node. This is only doable if the original graph G is connected.
A CaiFurerImmerman graph on a graph with no balanced vertex separators smaller than s and its twisted version
cannot be distinguished by k-WL for any k < s.
INPUT:
• G – An undirected graph on which to construct the Cai-Furer-Immerman graph
• twisted – A boolean indicating if the version to construct is a twisted one or not
OUTPUT:
• H – The Cai-Furer-Immerman graph on G
• coloring – A list of list of vertices, representing the partition induced by the coloring on H
EXAMPLES:
CaiFurerImmerman graph with no balanced vertex separator smaller than 2
sage: G = graphs.CycleGraph(4)
sage: CFI, p = graphs.CaiFurerImmermanGraph(G)
sage: sorted(CFI, key=str)
[(0, ()), (0, (0, 'a')), (0, (0, 'b')), (0, (0, 1)), (0, (1, 'a')),
(0, (1, 'b')), (1, ()), (1, (0, 'a')), (1, (0, 'b')), (1, (0, 1)),
(1, (1, 'a')), (1, (1, 'b')), (2, ()), (2, (0, 'a')), (2, (0, 'b')),
(2, (0, 1)), (2, (1, 'a')), (2, (1, 'b')), (3, ()), (3, (0, 'a')),
(3, (0, 'b')), (3, (0, 1)), (3, (1, 'a')), (3, (1, 'b'))]
sage: sorted(CFI.edge_iterator(), key=str)
[((0, ()), (0, (0, 'b')), None),
((0, ()), (0, (1, 'b')), None),
((0, (0, 'a')), (1, (0, 'a')), None),
((0, (0, 'b')), (1, (0, 'b')), None),
(continues on next page)
sage.graphs.generators.families.CirculantGraph(n, adjacency)
Returns a circulant graph with n nodes.
A circulant graph has the property that the vertex 𝑖 is connected with the vertices 𝑖 + 𝑗 and 𝑖 − 𝑗 for each j in
adjacency.
INPUT:
• n - number of vertices in the graph
• adjacency - the list of j values
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, each circulant graph will be displayed with the first (0) node at the top, with the rest following in a
counterclockwise manner.
Filling the position dictionary in advance adds O(n) to the constructor.
See also:
We next view many cycle graphs as a Sage graphics array. First we use the CirculantGraph constructor, which
fills in the position dictionary:
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.CirculantGraph(i+4, i+1)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
sage: g = []
sage: j = []
sage: for i in range(9):
....: spr = networkx.cycle_graph(i+3)
....: k = Graph(spr)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
sage: graphs.CirculantGraph(6,1)==graphs.CycleGraph(6)
True
sage: graphs.CirculantGraph(7,[1,3]).edges(sort=True, labels=false)
[(0, 1),
(0, 3),
(0, 4),
(0, 6),
(1, 2),
(1, 4),
(1, 5),
(2, 3),
(2, 5),
(2, 6),
(3, 4),
(3, 6),
(4, 5),
(5, 6)]
sage.graphs.generators.families.CubeConnectedCycle(d)
Return the cube-connected cycle of dimension 𝑑.
The cube-connected cycle of order 𝑑 is the 𝑑-dimensional hypercube with each of its vertices replaced by a cycle
of length 𝑑. This graph has order 𝑑 × 2𝑑 . The construction is as follows: Construct vertex (𝑥, 𝑦) for 0 ≤ 𝑥 < 2𝑑 ,
0 ≤ 𝑦 < 𝑑. For each vertex, (𝑥, 𝑦), add an edge between it and (𝑥, (𝑦 − 1) mod 𝑑)), (𝑥, (𝑦 + 1) mod 𝑑), and
(𝑥 ⊕ 2𝑦 , 𝑦), where ⊕ is the bitwise xor operator.
For 𝑑 = 1 and 2, the cube-connected cycle graph contains self-loops or multiple edges between a pair of vertices,
but for all other 𝑑, it is simple.
INPUT:
• d – The dimension of the desired hypercube as well as the length of the cycle to be placed at each vertex of
the 𝑑-dimensional hypercube. 𝑑 must be a positive integer.
EXAMPLES:
The order of the graph is 𝑑 × 2𝑑
sage: d = 3
sage: g = graphs.CubeConnectedCycle(d)
sage: len(g) == d*2**d
True
sage: d = 4
sage: g = graphs.CubeConnectedCycle(d)
sage: g.diameter() == 2*d+d//2-2
True
sage: g = graphs.CubeConnectedCycle(5)
sage: all(g.degree(v) == 3 for v in g)
True
sage.graphs.generators.families.CubeGraph(n, embedding=1)
Return the 𝑛-cube graph, also called the hypercube in 𝑛 dimensions.
The hypercube in 𝑛 dimension is build upon the binary strings on 𝑛 bits, two of them being adjacent if they differ
in exactly one bit. Hence, the distance between two vertices in the hypercube is the Hamming distance.
INPUT:
• n – integer; the dimension of the cube graph
• embedding – integer (default: 1); two embeddings of the 𝑛-cube are available:
– 1: the 𝑛-cube is projected inside a regular 2𝑛-gonal polygon by a skew orthogonal projection. See the
Wikipedia article Hypercube for more details.
– 2: orthogonal projection of the 𝑛-cube. This orientation shows columns of independent vertices such
that the neighbors of a vertex are located in the columns on the left and on the right. The number of
vertices in each column represents rows in Pascal’s triangle. See for instance the Wikipedia article
10-cube for more details.
– None or O: no embedding is provided
EXAMPLES:
The distance between 0100110 and 1011010 is 5, as expected:
sage: g = graphs.CubeGraph(7)
sage: g.distance('0100110','1011010')
5
sage: g = []
sage: j = []
sage: for i in range(6):
....: k = graphs.CubeGraph(i+1)
....: g.append(k)
...
sage: for i in range(2):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
...
sage: G = graphics_array(j)
sage: G.show(figsize=[6,4]) # long time
AUTHORS:
• Robert Miller
• David Coudert
sage.graphs.generators.families.DipoleGraph(n)
Returns a dipole graph with n edges.
A dipole graph is a multigraph consisting of 2 vertices connected with n parallel edges.
EXAMPLES:
Construct and show a dipole graph with 13 edges:
sage: g = graphs.DipoleGraph(13); g
Dipole graph: Multi-graph on 2 vertices
sage: g.show() # long time
sage.graphs.generators.families.DorogovtsevGoltsevMendesGraph(n)
Construct the n-th generation of the Dorogovtsev-Goltsev-Mendes graph.
EXAMPLES:
sage: G = graphs.DorogovtsevGoltsevMendesGraph(8)
sage: G.size()
6561
REFERENCE:
• [1] Dorogovtsev, S. N., Goltsev, A. V., and Mendes, J. F. F., Pseudofractal scale-free web, Phys. Rev. E
066122 (2002).
sage.graphs.generators.families.DoubleGeneralizedPetersenGraph(n, k)
Return a double generalized Petersen graph with 4𝑛 nodes.
The double generalized Petersen graphs is a family of graphs proposed in [ZF2012] as a variant of generalized
Petersen graphs. The variables 𝑛, 𝑘 are integers such that 𝑛 > 2 and 0 < 𝑘 ≤ ⌊(𝑛 − 1)/2⌋.
INPUT:
• n – the number of nodes is 4 * 𝑛
• k – integer such that 0 < 𝑘 ≤ ⌊(𝑛 − 1)/2⌋ determining how vertices on second and third inner rims are
connected
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the double generalized Petersen graphs are displayed as 4 cocentric cycles, with the first n nodes
drawn on the outer circle. The first (0) node is drawn at the top of the outer-circle, moving counterclockwise
after that. The second circle is drawn with the (n)th node at the top, then counterclockwise as well. The tird cycle
is drawn with the (2n)th node at the top, then counterclockwise. And the fourth cycle is drawn with the (3n)th
node at the top, then again counterclockwise.
EXAMPLES:
When 𝑛 is even the resulting graph will be isomorphic to a double generalized Petersen graph with 𝑘 ′ = 𝑛/2−𝑘:
sage: g = graphs.DoubleGeneralizedPetersenGraph(10, 2)
sage: g2 = graphs.DoubleGeneralizedPetersenGraph(10, 3)
sage: g.is_isomorphic(g2)
True
sage.graphs.generators.families.EgawaGraph(p, s)
Return the Egawa graph with parameters 𝑝, 𝑠.
Egawa graphs are a peculiar family of graphs devised by Yoshimi Egawa in [Ega1981] . The Shrikhande graph is
a special case of this family of graphs, with parameters (1, 0). All the graphs in this family are not recognizable
by 1-WL (Weisfeiler Lehamn algorithm of the first order) and 2-WL, that is their orbits are not correctly returned
by k-WL for k lower than 3.
Furthermore, all the graphs in this family are distance-regular, but they are not distance-transitive if 𝑝 ̸= 0.
The Egawa graph with parameters (0, 𝑠) is isomorphic to the Hamming graph with parameters (𝑠, 4), when the
underlying set of the Hamming graph is [0, 1, 2, 3]
INPUT:
• p – power to which the graph named 𝑌 in the reference provided above will be raised
• s – power to which the graph named 𝑋 in the reference provided above will be raised
OUTPUT:
• G – The Egawa graph with parameters (p,s)
EXAMPLES:
Every Egawa graph is distance regular.
sage: g = graphs.EgawaGraph(1, 2)
sage: g.is_distance_regular()
True
An Egawa graph with parameters (0,s) is isomorphic to the Hamming graph with parameters (s, 4).
sage: g = graphs.EgawaGraph(0, 4)
sage: g.is_isomorphic(graphs.HammingGraph(4,4))
True
sage.graphs.generators.families.FibonacciTree(n)
Return the graph of the Fibonacci Tree 𝐹𝑖 of order 𝑛.
The Fibonacci tree 𝐹𝑖 is recursively defined as the tree with a root vertex and two attached child trees 𝐹𝑖−1 and
𝐹𝑖−2 , where 𝐹1 is just one vertex and 𝐹0 is empty.
INPUT:
• n - the recursion depth of the Fibonacci Tree
EXAMPLES:
sage: g = graphs.FibonacciTree(3)
sage: g.is_tree()
True
AUTHORS:
• Harald Schilly and Yann Laigle-Chapuy (2010-03-25)
sage.graphs.generators.families.FoldedCubeGraph(n)
Returns the folded cube graph of order 2𝑛−1 .
The folded cube graph on 2𝑛−1 vertices can be obtained from a cube graph on 2𝑛 vertices by merging together
opposed vertices. Alternatively, it can be obtained from a cube graph on 2𝑛−1 vertices by adding an edge between
opposed vertices. This second construction is the one produced by this method.
See the Wikipedia article Folded_cube_graph for more information.
EXAMPLES:
The folded cube graph of order five is the Clebsch graph:
sage: fc = graphs.FoldedCubeGraph(5)
sage: clebsch = graphs.ClebschGraph()
sage: fc.is_isomorphic(clebsch)
True
sage.graphs.generators.families.FriendshipGraph(n)
Return the friendship graph 𝐹𝑛 .
The friendship graph is also known as the Dutch windmill graph. Let 𝐶3 be the cycle graph on 3 vertices. Then
𝐹𝑛 is constructed by joining 𝑛 ≥ 1 copies of 𝐶3 at a common vertex. If 𝑛 = 1, then 𝐹1 is isomorphic to 𝐶3
(the triangle graph). If 𝑛 = 2, then 𝐹2 is the butterfly graph, otherwise known as the bowtie graph. For more
information, see the Wikipedia article Friendship_graph.
INPUT:
• n – positive integer; the number of copies of 𝐶3 to use in constructing 𝐹𝑛 .
OUTPUT:
• The friendship graph 𝐹𝑛 obtained from 𝑛 copies of the cycle graph 𝐶3 .
See also:
• GraphGenerators.ButterflyGraph()
EXAMPLES:
The first few friendship graphs.
sage: A = []; B = []
sage: for i in range(9):
....: g = graphs.FriendshipGraph(i + 1)
....: A.append(g)
sage: for i in range(3):
....: n = []
....: for j in range(3):
....: n.append(A[3*i + j].plot(vertex_size=20, vertex_labels=False))
....: B.append(n)
sage: G = graphics_array(B)
sage: G.show() # long time
For 𝑛 = 1, the friendship graph 𝐹1 is isomorphic to the cycle graph 𝐶3 , whose visual representation is a triangle.
sage: G = graphs.FriendshipGraph(1); G
Friendship graph: Graph on 3 vertices
sage: G.show() # long time
sage: G.is_isomorphic(graphs.CycleGraph(3))
True
For 𝑛 = 2, the friendship graph 𝐹2 is isomorphic to the butterfly graph, otherwise known as the bowtie graph.
sage: G = graphs.FriendshipGraph(2); G
Friendship graph: Graph on 5 vertices
sage: G.is_isomorphic(graphs.ButterflyGraph())
True
If 𝑛 ≥ 2, then the friendship graph 𝐹𝑛 has 2𝑛 + 1 vertices and 3𝑛 edges. It has radius 1, diameter 2, girth 3, and
chromatic number 3. Furthermore, 𝐹𝑛 is planar and Eulerian.
sage.graphs.generators.families.FurerGadget(k, prefix=None)
Return a Furer gadget of order k and their coloring.
Construct the Furer gadget described in [CFI1992], a graph composed by a middle layer of 2( 𝑘 − 1) nodes and
two sets of nodes (𝑎0 , ..., 𝑎𝑘−1 ) and (𝑏0 , ..., 𝑏𝑘−1 ). Each node in the middle is connected to either 𝑎𝑖 or 𝑏𝑖 , for
each i in [0,k[. To read about the complete construction, see [CFI1992]. The returned coloring colors the middle
section with one color, and then each pair (𝑎𝑖 , 𝑏𝑖 ) with another color. Since this method is mainly used to create
Furer gadgets for the Cai-Furer-Immerman construction, returning gadgets that don’t always have the same vertex
labels is important, that’s why there is a parameter to manually set a prefix to be appended to each vertex label.
INPUT:
• k – The order of the returned Furer gadget, greater than 0.
• prefix – Prefix of to be appended to each vertex label, so as to individualise the returned Furer gadget.
Must be comparable for equality and hashable.
OUTPUT:
• G – The Furer gadget of order k
• coloring – A list of list of vertices, representing the partition induced by the coloring of G’s vertices
EXAMPLES:
Furer gadget of order 3, without any prefix.
sage: G, p = graphs.FurerGadget(3)
sage: sorted(G, key=str)
[(), (0, 'a'), (0, 'b'), (0, 1), (0, 2),
(1, 'a'), (1, 'b'), (1, 2), (2, 'a'), (2, 'b')]
sage: sorted(G.edge_iterator(), key=str)
[((), (0, 'b'), None), ((), (1, 'b'), None),
((), (2, 'b'), None), ((0, 'b'), (1, 2), None),
((0, 1), (0, 'a'), None), ((0, 1), (1, 'a'), None),
((0, 1), (2, 'b'), None), ((0, 2), (0, 'a'), None),
((0, 2), (1, 'b'), None), ((0, 2), (2, 'a'), None),
((1, 2), (1, 'a'), None), ((1, 2), (2, 'a'), None)]
sage.graphs.generators.families.FuzzyBallGraph(partition, q)
Construct a Fuzzy Ball graph with the integer partition partition and q extra vertices.
Let 𝑞 be an integer and let 𝑚1 , 𝑚2 , ..., 𝑚𝑘 be a set of positive integers. Let 𝑛 = 𝑞 + 𝑚1 + ... + 𝑚𝑘 . The Fuzzy
Ball graph with partition 𝑚1 , 𝑚2 , ..., 𝑚𝑘 and 𝑞 extra vertices is the graph constructed from the graph 𝐺 = 𝐾𝑛
by attaching, for each 𝑖 = 1, 2, ..., 𝑘, a new vertex 𝑎𝑖 to 𝑚𝑖 distinct vertices of 𝐺.
For given positive integers 𝑘 and 𝑚 and nonnegative integer 𝑞, the set of graphs FuzzyBallGraph(p, q) for
all partitions 𝑝 of 𝑚 with 𝑘 parts are cospectral with respect to the normalized Laplacian.
EXAMPLES:
sage: F = graphs.FuzzyBallGraph([3,1],2)
sage: F.adjacency_matrix(vertices=list(F))
[0 0 1 1 1 0 0 0]
[0 0 0 0 0 1 0 0]
[1 0 0 1 1 1 1 1]
[1 0 1 0 1 1 1 1]
[1 0 1 1 0 1 1 1]
[0 1 1 1 1 0 1 1]
[0 0 1 1 1 1 0 1]
[0 0 1 1 1 1 1 0]
Pick positive integers 𝑚 and 𝑘 and a nonnegative integer 𝑞. All the FuzzyBallGraphs constructed from partitions
of 𝑚 with 𝑘 parts should be cospectral with respect to the normalized Laplacian:
sage.graphs.generators.families.GeneralizedPetersenGraph(n, k)
Returns a generalized Petersen graph with 2𝑛 nodes. The variables 𝑛, 𝑘 are integers such that 𝑛 > 2 and
0 < 𝑘 ≤ ⌊(𝑛 − 1)/2⌋
For 𝑘 = 1 the result is a graph isomorphic to the circular ladder graph with the same 𝑛. The regular Petersen
Graph has 𝑛 = 5 and 𝑘 = 2. Other named graphs that can be described using this notation include the Desargues
graph and the Möbius-Kantor graph.
INPUT:
• n - the number of nodes is 2 * 𝑛.
• k - integer 0 < 𝑘 ≤ ⌊(𝑛 − 1)/2⌋. Decides how inner vertices are connected.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the generalized Petersen graphs are displayed as an inner and outer cycle pair, with the first n nodes
drawn on the outer circle. The first (0) node is drawn at the top of the outer-circle, moving counterclockwise
after that. The inner circle is drawn with the (n)th node at the top, then counterclockwise as well.
EXAMPLES: For 𝑘 = 1 the resulting graph will be isomorphic to a circular ladder graph.
sage: g = graphs.GeneralizedPetersenGraph(13,1)
sage: g2 = graphs.CircularLadderGraph(13)
sage: g.is_isomorphic(g2)
True
sage: g = graphs.GeneralizedPetersenGraph(10,3)
sage: g.girth()
6
sage: g.is_bipartite()
True
AUTHORS:
• Anders Jonsson (2009-10-15)
sage.graphs.generators.families.GeneralizedSierpinskiGraph(G, k, stretch=None)
Return the generalized Sierpinski graph of 𝐺 of dimension 𝑘.
Generalized Sierpinski graphs have been introduced in [GKP2011] to generalize the notion of Sierpinski graphs
[KM1997].
Given a graph 𝐺 = (𝑉, 𝐸) of order 𝑛 and a parameter 𝑘, the generalized Sierpinski graph of 𝐺 of dimension 𝑘,
denoted by 𝑆(𝐺, 𝑘), can be constructed recursively from 𝐺 as follows. 𝑆(𝐺, 1) is isomorphic to 𝐺. To construct
𝑆(𝐺, 𝑘) for 𝑘 > 1, copy 𝑛 times 𝑆(𝐺, 𝑘 − 1), once per vertex 𝑢 ∈ 𝑉 , and add 𝑢 at the beginning of the labels
of each vertex in the copy of 𝑆(𝐺, 𝑘 − 1) corresponding to vertex 𝑢. Then for any edge {𝑢, 𝑣} ∈ 𝐸, add an edge
between vertex (𝑢, 𝑣, . . . , 𝑣) and vertex (𝑣, 𝑢, . . . , 𝑢).
INPUT:
• G – a sage Graph
• k – integer; the dimension
• stretch – integer (default: None); stretching factor used to determine the positions of the vertices of the
output graph. By default (None), this value is set to twice the maximum Euclidian distance between the
vertices of 𝐺. This parameter is used only when the vertices of 𝐺 have positions.
See also:
• SierpinskiGasketGraph()
• HanoiTowerGraph()
EXAMPLES:
The generalized Sierpinski graph of dimension 1 of any graph 𝐺 is isomorphic to 𝐺:
When 𝐺 is a clique of order 3, the generalized Sierpinski graphs of 𝐺 are isomorphic to Hanoi Tower graphs:
sage: k = randint(1, 5)
sage: S = graphs.GeneralizedSierpinskiGraph(graphs.CompleteGraph(3), k)
sage: H = graphs.HanoiTowerGraph(3, k)
sage: S.is_isomorphic(H)
True
The generalized Sierpinski graph of dimension 𝑘 of any graph 𝐺 with 𝑛 vertices and 𝑚 edges has 𝑛𝑘 vertices
∑︀𝑘−1
and 𝑚 𝑖=0 𝑛𝑖 edges:
sage: n = randint(2, 6)
sage: k = randint(1, 5)
sage: G = graphs.RandomGNP(n, .5)
sage: m = G.size()
sage: S = graphs.GeneralizedSierpinskiGraph(G, k)
sage: S.order() == n**k
True
sage: S.size() == m*sum([n**i for i in range(k)])
True
sage: G = graphs.CompleteGraph(n)
sage: S = graphs.GeneralizedSierpinskiGraph(G, k)
sage: S.order() == n**k
True
sage: S.size() == (n*(n - 1)/2)*sum([n**i for i in range(k)])
True
The positions of the vertices of the output graph are determined from the positions of the vertices of 𝐺, if any:
sage: G = graphs.HouseGraph()
sage: G.get_pos() is not None
True
sage: H = graphs.GeneralizedSierpinskiGraph(G, 2)
sage: H.get_pos() is not None
True
sage: G = Graph([(0, 1)])
sage: G.get_pos() is not None
False
sage: H = graphs.GeneralizedSierpinskiGraph(G, 2)
sage: H.get_pos() is not None
False
sage.graphs.generators.families.GoethalsSeidelGraph(k, r)
Returns the graph Goethals-Seidel(𝑘, 𝑟).
The graph Goethals-Seidel(𝑘, 𝑟) comes from a construction presented in Theorem 2.4 of [GS1970]. It relies
on a (v,k)-BIBD with 𝑟 blocks and a hadamard_matrix() of order 𝑟 + 1. The result is a sage.graphs.
strongly_regular_db.strongly_regular_graph() on 𝑣(𝑟 + 1) vertices with degree 𝑘 = (𝑛 + 𝑟 − 1)/2.
It appears under this name in Andries Brouwer’s database of strongly regular graphs.
INPUT:
• k,r – integers
See also:
• is_goethals_seidel()
EXAMPLES:
sage: graphs.GoethalsSeidelGraph(3,3)
Graph on 28 vertices
sage: graphs.GoethalsSeidelGraph(3,3).is_strongly_regular(parameters=True)
(28, 15, 6, 10)
sage.graphs.generators.families.HammingGraph(n, q, X=None)
Returns the Hamming graph with parameters n, q over X.
Hamming graphs are graphs over the cartesian product of n copies of X, where 𝑞 = |𝑋|, where the vertices,
labelled with the corresponding tuple in 𝑋 𝑛 , are connected if the Hamming distance between their labels is 1.
All Hamming graphs are regular, vertex-transitive and distance-regular.
Hamming graphs with parameters (1, 𝑞) represent the complete graph with q vertices over the set X.
INPUT:
• n – power to which X will be raised to provide vertices for the Hamming graph
• q – cardinality of X
• X – list of labels representing the vertices of the underlying graph the Hamming graph will be based on;
if None (or left unused), the list [0, ..., 𝑞 − 1] will be used
OUTPUT:
• G – The Hamming graph with parameters (𝑛, 𝑞, 𝑋)
EXAMPLES:
Every Hamming graph is distance-regular, regular and vertex-transitive.
sage: g = graphs.HammingGraph(3, 7)
sage: g.is_distance_regular()
True
sage: g.is_regular()
True
sage: g.is_vertex_transitive()
True
A Hamming graph with parameters (1,q) is isomorphic to the Complete graph with parameter q.
sage: X = ['a','b','c','d','e']
sage: g = graphs.HammingGraph(2, 3, X)
Traceback (most recent call last):
...
ValueError: q must be the cardinality of X
REFERENCES:
For a more accurate description, see the following wikipedia page: Wikipedia article Hamming_graph
• GeneralizedSierpinskiGraph()
PLOTTING:
The layout computed when positions = True will look especially good for the three-peg case, when the graph
is known to be planar. Except for two small cases on 4 pegs, the graph is otherwise not planar, and likely there
is a better way to layout the vertices.
EXAMPLES:
A classic puzzle uses 3 pegs. We solve the 5 disk puzzle using integer labels and report the minimum number of
moves required. Note that 35 − 1 is the state where all 5 disks are on peg 2.
For a small graph, labels and layout information can be useful. Here we explicitly list a solution as a list of states.
True
sage: H.chromatic_number()
3
sage: len(H.independent_set()) == 3^(4-1)
True
AUTHOR:
• Rob Beezer, (2009-12-26), with assistance from Su Doree
sage.graphs.generators.families.HararyGraph(k, n)
Returns the Harary graph on 𝑛 vertices and connectivity 𝑘, where 2 ≤ 𝑘 < 𝑛.
A 𝑘-connected graph 𝐺 on 𝑛 vertices requires the minimum degree 𝛿(𝐺) ≥ 𝑘, so the minimum number of
edges 𝐺 should have is ⌈𝑘𝑛/2⌉. Harary graphs achieve this lower bound, that is, Harary graphs are minimal
𝑘-connected graphs on 𝑛 vertices.
The construction provided uses the method CirculantGraph. For more details, see the book D. B. West, Intro-
duction to Graph Theory, 2nd Edition, Prentice Hall, 2001, p. 150–151; or the MathWorld article on Harary
graphs.
EXAMPLES:
Harary graphs 𝐻𝑘,𝑛 :
sage: h = graphs.HararyGraph(5,9); h
Harary graph 5, 9: Graph on 9 vertices
sage: h.order()
(continues on next page)
sage.graphs.generators.families.HyperStarGraph(n, k)
Return the hyper-star graph 𝐻𝑆(𝑛, 𝑘).
The vertices of the hyper-star graph are the set of binary strings of length 𝑛 which contain 𝑘 1s. Two vertices,
𝑢 and 𝑣, are adjacent only if 𝑢 can be obtained from 𝑣 by swapping the first bit with a different symbol in
another position. For instance, vertex '011100' of 𝐻𝑆(6, 3) is adjacent to vertices '101100', '110100' and
'111000'. See [LKOL2002] for more details.
INPUT:
• n – non-negative integer; length of the binary strings
• k – non-negative integer; number of 1s per binary string
EXAMPLES:
sage: g = graphs.HyperStarGraph(6,3)
sage: sorted(g.neighbors('011100'))
['101100', '110100', '111000']
sage: g.plot() # long time
Graphics object consisting of 51 graphics primitives
AUTHORS:
• Michael Yurko (2009-09-01)
sage.graphs.generators.families.IGraph(n, j, k)
Return an I-graph with 2𝑛 nodes.
The I-Graph family as been proposed in [BCMS1988] as a generalization of the generalized Petersen graphs.
The variables 𝑛, 𝑗, 𝑘 are integers such that 𝑛 > 2 and 0 < 𝑗, 𝑘 ≤ ⌊(𝑛 − 1)/2⌋. When 𝑗 = 1 the resulting graph
is isomorphic to the generalized Petersen graph with the same 𝑛 and 𝑘.
INPUT:
• n – the number of nodes is 2 * 𝑛
• j – integer such that 0 < 𝑗 ≤ ⌊(𝑛 − 1)/2⌋ determining how outer vertices are connected
• k – integer such that 0 < 𝑘 ≤ ⌊(𝑛 − 1)/2⌋ determining how inner vertices are connected
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the I-graphs are displayed as an inner and outer cycle pair, with the first n nodes drawn on the outer
circle. The first (0) node is drawn at the top of the outer-circle, moving counterclockwise after that. The inner
circle is drawn with the (n)th node at the top, then counterclockwise as well.
EXAMPLES:
When 𝑗 = 1 the resulting graph will be isomorphic to a generalized Petersen graph:
sage: g = graphs.IGraph(7,1,2)
sage: g2 = graphs.GeneralizedPetersenGraph(7,2)
sage: g.is_isomorphic(g2)
True
The IGraph with parameters (𝑛, 𝑗, 𝑘) is isomorphic to the IGraph with parameters (𝑛, 𝑘, 𝑗):
sage: g = graphs.IGraph(7, 2, 3)
sage: h = graphs.IGraph(7, 3, 2)
sage: g.is_isomorphic(h)
True
sage.graphs.generators.families.JohnsonGraph(n, k)
Returns the Johnson graph with parameters 𝑛, 𝑘.
Johnson graphs are a special class of undirected graphs defined from systems of sets. The vertices of the Johnson
graph 𝐽(𝑛, 𝑘) are the 𝑘-element subsets of an 𝑛-element set; two vertices are adjacent when they meet in a (𝑘−1)-
element set. See the Wikipedia article Johnson_graph for more information.
EXAMPLES:
The Johnson graph is a Hamiltonian graph:
sage: g = graphs.JohnsonGraph(7, 3)
sage: g.is_hamiltonian()
True
sage: g = graphs.JohnsonGraph(6, 4)
sage: g.is_vertex_transitive()
True
The complement of the Johnson graph 𝐽(𝑛, 2) is isomorphic to the Kneser Graph 𝐾(𝑛, 2). In particular the
complement of 𝐽(5, 2) is isomorphic to the Petersen graph.:
sage: g = graphs.JohnsonGraph(5,2)
sage: g.complement().is_isomorphic(graphs.PetersenGraph())
True
sage.graphs.generators.families.KneserGraph(n, k)
Returns the Kneser Graph with parameters 𝑛, 𝑘.
The Kneser Graph with parameters 𝑛, 𝑘 is the graph whose vertices are the 𝑘-subsets of [0, 1, . . . , 𝑛 − 1], and
such that two vertices are adjacent if their corresponding sets are disjoint.
For example, the Petersen Graph can be defined as the Kneser Graph with parameters 5, 2.
EXAMPLES:
sage: KG = graphs.KneserGraph(5,2)
sage: sorted(KG.vertex_iterator(), key=str)
[{1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 3}, {2, 4}, {2, 5},
{3, 4}, {3, 5}, {4, 5}]
sage: P = graphs.PetersenGraph()
sage: P.is_isomorphic(KG)
True
variable shift_list = [s_0, s_1, . . . , s_k-1] describes edges to be created by the following scheme: for each i,
connect vertex i to vertex (i + s_i). Then, repeats specifies the number of times to repeat this process, where on
the jth repeat we connect vertex (i + j*len(shift_list)) to vertex ( i + j*len(shift_list) + s_i).
INPUT:
• n - the number of nodes.
• shift_list - a list of integer shifts mod n.
• repeats - the number of times to repeat the process.
EXAMPLES:
sage: G.degree()
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
sage: G.diameter()
3
sage: G.show() # long time
PLOTTING: LCF Graphs are plotted as an n-cycle with edges in the middle, as described above.
REFERENCES:
• [1] Frucht, R. “A Canonical Representation of Trivalent Hamiltonian Graphs.” J. Graph Th. 1, 45-60, 1976.
• [2] Grunbaum, B. Convex Polytope es. New York: Wiley, pp. 362-364, 1967.
• [3] Lederberg, J. ‘DENDRAL-64: A System for Computer Construction, Enumeration and Notation of
Organic Molecules as Tree Structures and Cyclic Graphs. Part II. Topology of Cyclic Graphs.’ Interim
Report to the National Aeronautics and Space Administration. Grant NsG 81-60. December 15, 1965.
http://profiles.nlm.nih.gov/BB/A/B/I/U/_/bbabiu.pdf.
sage.graphs.generators.families.LollipopGraph(n1, n2)
Returns a lollipop graph with n1+n2 nodes.
A lollipop graph is a path graph (order n2) connected to a complete graph (order n1). (A barbell graph minus
one of the bells).
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the complete graph will be drawn in the lower-left corner with the (n1)th node at a 45 degree angle
above the right horizontal center of the complete graph, leading directly into the path graph.
EXAMPLES:
sage: g = graphs.LollipopGraph(13,4); g
Lollipop graph: Graph on 17 vertices
sage: g.show() # long time
sage.graphs.generators.families.MathonPseudocyclicMergingGraph(M, t)
Mathon’s merging of classes in a pseudo-cyclic 3-class association scheme
Construct strongly regular graphs from p.97 of [BL1984].
INPUT:
• M – the list of matrices in a pseudo-cyclic 3-class association scheme. The identity matrix must be the first
entry.
• t (integer) – the number of the graph, from 0 to 2.
See also:
• is_muzychuk_S6()
• is_mathon_PC_srg()
EXAMPLES:
Using default G and L.
sage: G=MathonPseudocyclicStronglyRegularGraph(1); G
Mathon's PC SRG on 45 vertices: Graph on 45 vertices
sage: G.is_strongly_regular(parameters=True)
(45, 22, 10, 11)
sage: G = graphs.PaleyGraph(9)
sage: a = G.automorphism_group(partition=[sorted(G)])
sage: it = (x for x in a.normal_subgroups() if x.order() == 9)
sage: subg = next(iter(it))
sage: r = [matrix(libgap.PermutationMat(libgap(z), 9).sage())
....: for z in subg]
sage: ff = list(map(lambda y: (y[0]-1,y[1]-1),
....: Permutation(map(lambda x: 1+r.index(x^-1), r)).cycle_tuples()[1:]))
sage: L = sum(i*(r[a]-r[b]) for i,(a,b) in zip(range(1,len(ff)+1), ff)); L
[ 0 1 -1 -3 -2 -4 3 4 2]
[-1 0 1 -4 -3 -2 2 3 4]
[ 1 -1 0 -2 -4 -3 4 2 3]
[ 3 4 2 0 1 -1 -3 -2 -4]
[ 2 3 4 -1 0 1 -4 -3 -2]
[ 4 2 3 1 -1 0 -2 -4 -3]
[-3 -2 -4 3 4 2 0 1 -1]
[-4 -3 -2 2 3 4 -1 0 1]
[-2 -4 -3 4 2 3 1 -1 0]
sage: G.relabel(range(9))
sage: G3x3=graphs.MathonPseudocyclicStronglyRegularGraph(2,G=G,L=L)
sage: G3x3.is_strongly_regular(parameters=True)
(441, 220, 109, 110)
sage: G3x3.automorphism_group(algorithm="bliss").order() # optional - bliss
27
sage: G9=graphs.MathonPseudocyclicStronglyRegularGraph(2)
sage: G9.is_strongly_regular(parameters=True)
(441, 220, 109, 110)
sage: G9.automorphism_group(algorithm="bliss").order() # optional - bliss
9
– A dictionary describing the functions Φ𝑖 ; for 𝑖 ∈ 𝑀 , Phi[(i, T)] in 𝑀 , for each edge T of 𝐿 on 𝑖. Also,
each Φ𝑖 must be injective.
• Sigma is an optional parameter of the construction; it must be either
– ‘fixed’– this will generate a fixed default Σ, or
– ‘random’– Σ is generated at random.
• verbose (Boolean)– default is False. If True, print progress information
See also:
• is_muzychuk_S6()
Todo: Implement the possibility to explicitly supply the parameter Σ of the construction.
EXAMPLES:
sage.graphs.generators.families.MycielskiGraph(k=1, relabel=True)
Returns the 𝑘-th Mycielski Graph.
The graph 𝑀𝑘 is triangle-free and has chromatic number equal to 𝑘. These graphs show, constructively, that
there are triangle-free graphs with arbitrarily high chromatic number.
The Mycielski graphs are built recursively starting with 𝑀0 , an empty graph; 𝑀1 , a single vertex graph; and 𝑀2
is the graph 𝐾2 . 𝑀𝑘+1 is then built from 𝑀𝑘 as follows:
If the vertices of 𝑀𝑘 are 𝑣1 , . . . , 𝑣𝑛 , then the vertices of 𝑀𝑘+1 are 𝑣1 , . . . , 𝑣𝑛 , 𝑤1 , . . . , 𝑤𝑛 , 𝑧. Vertices 𝑣1 , . . . , 𝑣𝑛
induce a copy of 𝑀𝑘 . Vertices 𝑤1 , . . . , 𝑤𝑛 are an independent set. Vertex 𝑧 is adjacent to all the 𝑤𝑖 -vertices.
Finally, vertex 𝑤𝑖 is adjacent to vertex 𝑣𝑗 iff 𝑣𝑖 is adjacent to 𝑣𝑗 .
INPUT:
• k Number of steps in the construction process.
• relabel Relabel the vertices so their names are the integers range(n) where n is the number of vertices
in the graph.
EXAMPLES:
The Mycielski graph 𝑀𝑘 is triangle-free and has chromatic number equal to 𝑘.
sage: g = graphs.MycielskiGraph(5)
sage: g.is_triangle_free()
True
sage: g.chromatic_number()
5
sage: g = graphs.MycielskiGraph(4)
sage: g.is_isomorphic(graphs.GrotzschGraph())
True
REFERENCES:
• [1] Weisstein, Eric W. “Mycielski Graph.” From MathWorld–A Wolfram Web Resource. http://mathworld.
wolfram.com/MycielskiGraph.html
sage.graphs.generators.families.MycielskiStep(g)
Perform one iteration of the Mycielski construction.
See the documentation for MycielskiGraph which uses this method. We expose it to all users in case they may
find it useful.
EXAMPLE. One iteration of the Mycielski step applied to the 5-cycle yields a graph isomorphic to the Grotzsch
graph
sage: g = graphs.CycleGraph(5)
sage: h = graphs.MycielskiStep(g)
sage: h.is_isomorphic(graphs.GrotzschGraph())
True
sage.graphs.generators.families.NKStarGraph(n, k)
Returns the (n,k)-star graph.
The vertices of the (n,k)-star graph are the set of all arrangements of n symbols into labels of length k. There are
two adjacency rules for the (n,k)-star graph. First, two vertices are adjacent if one can be obtained from the other
by swapping the first symbol with another symbol. Second, two vertices are adjacent if one can be obtained from
the other by swapping the first symbol with an external symbol (a symbol not used in the original label).
INPUT:
• n
• k
EXAMPLES:
sage: g = graphs.NKStarGraph(4,2)
sage: g.plot() # long time
Graphics object consisting of 31 graphics primitives
REFERENCES:
• Wei-Kuo, Chiang, and Chen Rong-Jaye. “The (n, k)-star graph: A generalized star graph.” Information
Processing Letters 56, no. 5 (December 8, 1995): 259-264.
AUTHORS:
• Michael Yurko (2009-09-01)
sage.graphs.generators.families.NStarGraph(n)
Returns the n-star graph.
The vertices of the n-star graph are the set of permutations on n symbols. There is an edge between two vertices
if their labels differ only in the first and one other position.
INPUT:
• n
EXAMPLES:
sage: g = graphs.NStarGraph(4)
sage: g.plot() # long time
Graphics object consisting of 61 graphics primitives
REFERENCES:
• S.B. Akers, D. Horel and B. Krishnamurthy, The star graph: An attractive alternative to the previous n-cube.
In: Proc. Internat. Conf. on Parallel Processing (1987), pp. 393–400.
AUTHORS:
• Michael Yurko (2009-09-01)
sage.graphs.generators.families.OddGraph(n)
Returns the Odd Graph with parameter 𝑛.
The Odd Graph with parameter 𝑛 is defined as the Kneser Graph with parameters 2𝑛 − 1, 𝑛 − 1. Equivalently,
the Odd Graph is the graph whose vertices are the 𝑛−1-subsets of [0, 1, . . . , 2(𝑛−1)], and such that two vertices
are adjacent if their corresponding sets are disjoint.
For example, the Petersen Graph can be defined as the Odd Graph with parameter 3.
EXAMPLES:
sage: OG = graphs.OddGraph(3)
sage: sorted(OG.vertex_iterator(), key=str)
[{1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 3}, {2, 4}, {2, 5},
{3, 4}, {3, 5}, {4, 5}]
sage: P = graphs.PetersenGraph()
sage: P.is_isomorphic(OG)
True
sage.graphs.generators.families.PaleyGraph(q)
Paley graph with 𝑞 vertices
Parameter 𝑞 must be the power of a prime number and congruent to 1 mod 4.
EXAMPLES:
sage: G = graphs.PaleyGraph(9); G
Paley graph with parameter 9: Graph on 9 vertices
sage: G.is_regular()
True
sage: G.is_self_complementary()
True
sage.graphs.generators.families.PasechnikGraph(n)
Pasechnik strongly regular graph on (4𝑛 − 1)2 vertices
A strongly regular graph with parameters of the orthogonal array graph OrthogonalArrayBlockGraph(), also
known as pseudo Latin squares graph 𝐿2𝑛−1 (4𝑛 − 1), constructed from a skew Hadamard matrix of order 4𝑛
following [Pas1992].
See also:
• is_orthogonal_array_block_graph()
EXAMPLES:
sage: graphs.PasechnikGraph(4).is_strongly_regular(parameters=True)
(225, 98, 43, 42)
sage: graphs.PasechnikGraph(5).is_strongly_regular(parameters=True) # long time
(361, 162, 73, 72)
sage: graphs.PasechnikGraph(9).is_strongly_regular(parameters=True) # not tested
(1225, 578, 273, 272)
sage.graphs.generators.families.RingedTree(k, vertex_labels=True)
Return the ringed tree on k-levels.
A ringed tree of level 𝑘 is a binary tree with 𝑘 levels (counting the root as a level), in which all vertices at the
same level are connected by a ring.
More precisely, in each layer of the binary tree (i.e. a layer is the set of vertices [2𝑖 ...2𝑖+1 − 1]) two vertices 𝑢, 𝑣
are adjacent if 𝑢 = 𝑣 + 1 or if 𝑢 = 2𝑖 and 𝑣 =.
Ringed trees are defined in [CFHM2013].
INPUT:
• k – the number of levels of the ringed tree.
• vertex_labels (boolean) – whether to label vertices as binary words (default) or as integers.
EXAMPLES:
sage: G = graphs.RingedTree(5)
sage: P = G.plot(vertex_labels=False, vertex_size=10)
sage: P.show() # long time
sage: G.vertices(sort=True)
['', '0', '00', '000', '0000', '0001', '001', '0010', '0011', '01',
'010', '0100', '0101', '011', '0110', '0111', '1', '10', '100',
'1000', '1001', '101', '1010', '1011', '11', '110', '1100', '1101',
'111', '1110', '1111']
sage.graphs.generators.families.RoseWindowGraph(n, a, r)
Return a rose window graph with 2𝑛 nodes.
The rose window graphs is a family of tetravalant graphs introduced in [Wilson2008]. The parameters 𝑛, 𝑎 and
𝑟 are integers such that 𝑛 > 2, 1 ≤ 𝑎, 𝑟 < 𝑛, and 𝑟 ̸= 𝑛/2.
INPUT:
• n – the number of nodes is 2 * 𝑛
• a – integer such that 1 ≤ 𝑎 < 𝑛 determining a-spoke edges
• r – integer such that 1 ≤ 𝑟 < 𝑛 and 𝑟 ̸= 𝑛/2 determining how inner vertices are connected
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the rose window graphs are displayed as an inner and outer cycle pair, with the first n nodes drawn
on the outer circle. The first (0) node is drawn at the top of the outer-circle, moving counterclockwise after that.
The inner circle is drawn with the (n)th node at the top, then counterclockwise as well. Vertices in the outer circle
are connected in the circular manner, vertices in the inner circle are connected when their label have difference
𝑟 (mod n). Vertices on the outer rim are connected with the vertices on the inner rim when they are at the same
position and when they are 𝑎 apart.
EXAMPLES:
The vertices of a rose window graph have all degree 4:
sage: G = graphs.RoseWindowGraph(5, 1, 2)
sage: all(G.degree(u) == 4 for u in G)
True
sage: G = graphs.RoseWindowGraph(3, 2, 1)
sage: all(G.degree(u) == 4 for u in G)
True
sage.graphs.generators.families.SierpinskiGasketGraph(n)
Return the Sierpinski Gasket graph of generation 𝑛.
All vertices but 3 have valence 4.
INPUT:
• 𝑛 – an integer
OUTPUT:
a graph 𝑆𝑛 with 3(3𝑛−1 + 1)/2 vertices and 3𝑛 edges, closely related to the famous Sierpinski triangle fractal.
All these graphs have a triangular shape, and three special vertices at top, bottom left and bottom right. These
are the only vertices of valence 2, all the other ones having valence 4.
The graph 𝑆1 (generation 1) is a triangle.
The graph 𝑆𝑛+1 is obtained from the disjoint union of three copies A,B,C of 𝑆𝑛 by identifying pairs of vertices:
the top vertex of A with the bottom left vertex of B, the bottom right vertex of B with the top vertex of C, and
the bottom left vertex of C with the bottom right vertex of A.
See also:
• HanoiTowerGraph(). There is another family of graphs called Sierpinski graphs, where all vertices but 3
have valence 3. They are available using graphs.HanoiTowerGraph(3, n).
• GeneralizedSierpinskiGraph()
EXAMPLES:
sage: s4 = graphs.SierpinskiGasketGraph(4); s4
Graph on 42 vertices
sage: s4.size()
81
sage: s4.degree_histogram()
[0, 0, 3, 0, 39]
sage: s4.is_hamiltonian()
True
REFERENCES:
[LLWC2011]
sage.graphs.generators.families.SquaredSkewHadamardMatrixGraph(n)
Pseudo-𝑂𝐴(2𝑛, 4𝑛 − 1)-graph from a skew Hadamard matrix of order 4𝑛
A strongly regular graph with parameters of the orthogonal array graph OrthogonalArrayBlockGraph(), also
known as pseudo Latin squares graph 𝐿2𝑛 (4𝑛 − 1), constructed from a skew Hadamard matrix of order 4𝑛, due
to Goethals and Seidel, see [BL1984].
See also:
• is_orthogonal_array_block_graph()
EXAMPLES:
sage: graphs.SquaredSkewHadamardMatrixGraph(4).is_strongly_regular(parameters=True)
(225, 112, 55, 56)
sage: graphs.SquaredSkewHadamardMatrixGraph(5).is_strongly_regular(parameters=True)␣
˓→ # long time
sage.graphs.generators.families.SwitchedSquaredSkewHadamardMatrixGraph(n)
A strongly regular graph in Seidel switching class of 𝑆𝑞𝑢𝑎𝑟𝑒𝑑𝑆𝑘𝑒𝑤𝐻𝑎𝑑𝑎𝑚𝑎𝑟𝑑𝑀 𝑎𝑡𝑟𝑖𝑥𝐺𝑟𝑎𝑝ℎ
A strongly regular graph in the Seidel switching class of the disjoint union of a 1-vertex graph and the one
produced by Pseudo-L_{2n}(4n-1)
In this case, the other possible parameter set of a strongly regular graph in the Seidel switching class of the
latter graph (see [BH2012]) coincides with the set of parameters of the complement of the graph returned by this
function.
See also:
• is_switch_skewhad()
EXAMPLES:
sage: g=graphs.SwitchedSquaredSkewHadamardMatrixGraph(4)
sage: g.is_strongly_regular(parameters=True)
(226, 105, 48, 49)
sage: from sage.combinat.designs.twographs import twograph_descendant
sage: twograph_descendant(g,0).is_strongly_regular(parameters=True)
(225, 112, 55, 56)
sage: twograph_descendant(g.complement(),0).is_strongly_regular(parameters=True)
(225, 112, 55, 56)
sage.graphs.generators.families.TabacjnGraph(n, a, b, r)
Return a Tabačjn graph with 2𝑛 nodes.
The Tabačjn graphs is a family of pentavalent bicirculants graphs proposed in [AHKOS2014] as a generalization
of generalized Petersen graphs. The parameters 𝑛, 𝑎, 𝑏, 𝑟 are integers such that 𝑛 ≥ 3, 1 ≤ 𝑎, 𝑏, 𝑟 ≤ 𝑛 − 1, with
𝑎 ̸= 𝑏 and 𝑟 ̸= 𝑛/2.
INPUT:
• n – the number of nodes is 2 * 𝑛
• a – integer such that 0 < 𝑎 < 𝑛 and 𝑎 ̸= 𝑏, that determines a-spoke edges
• b – integer such that 0 < 𝑏 < 𝑛 and 𝑏 ̸= 𝑎, that determines b-spoke edges
• r – integer such that 0 < 𝑟 < 𝑛 and 𝑟 ̸= 𝑛/2 determining how inner vertices are connected
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the rose window graphs are displayed as an inner and outer cycle pair, with the first n nodes drawn
on the outer circle. The first (0) node is drawn at the top of the outer-circle, moving counterclockwise after that.
The inner circle is drawn with the (n)th node at the top, then counterclockwise as well. Vertices in the outer circle
are connected in the circular manner, vertices in the inner circle are connected when their label have difference
𝑟 (mod n). Vertices on the outer rim are connected with the vertices on the inner rim when they are at the same
position and when they are 𝑎 and 𝑏 apart.
EXAMPLES:
sage: G = graphs.TabacjnGraph(3, 1, 2, 1)
sage: G.degree()
[5, 5, 5, 5, 5, 5]
sage: G.is_isomorphic(graphs.CompleteGraph(6))
True
sage: G = graphs.TabacjnGraph(6, 1, 5, 2)
sage: I = graphs.IcosahedralGraph()
sage: G.is_isomorphic(I)
True
sage.graphs.generators.families.TadpoleGraph(n1, n2)
Return a tadpole graph with n1+n2 nodes.
A tadpole graph is a path graph (order n2) connected to a cycle graph (order n1).
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the cycle graph will be drawn in the lower-left corner with the (n1)th node at a 45 degree angle
above the right horizontal center of the cycle graph, leading directly into the path graph.
EXAMPLES:
Construct and show a tadpole graph Cycle = 13, Stick = 4:
sage.graphs.generators.families.TuranGraph(n, r)
Returns the Turan graph with parameters 𝑛, 𝑟.
Turan graphs are complete multipartite graphs with 𝑛 vertices and 𝑟 subsets, denoted 𝑇 (𝑛, 𝑟), with the property
that the sizes of the subsets are as close to equal as possible. The graph 𝑇 (𝑛, 𝑟) will have 𝑛 (mod 𝑟) subsets
of size ⌊𝑛/𝑟⌋ and 𝑟 − (𝑛 (mod 𝑟)) subsets of size ⌈𝑛/𝑟⌉. See the Wikipedia article Turan_graph for more
information.
INPUT:
• n – integer; the number of vertices in the graph
• r – integer; the number of partitions of the graph
EXAMPLES:
The Turan graph is a complete multipartite graph:
sage: g = graphs.TuranGraph(13, 4)
sage: k = graphs.CompleteMultipartiteGraph([3,3,3,4])
(continues on next page)
sage: n = 12
sage: r = 8
sage: g = graphs.TuranGraph(n, r)
sage: def count(n, r):
....: s = n % r
....: return (r - 1) * (n**2 - s**2) / (2*r) + s*(s - 1)/2
sage: g.size() == count(n, r)
True
sage: n = randint(3, 100)
sage: r = randint(2, n - 1)
sage: g = graphs.TuranGraph(n, r)
sage: g.size() == count(n, r)
True
sage.graphs.generators.families.WheelGraph(n)
Returns a Wheel graph with n nodes.
A Wheel graph is a basic structure where one node is connected to all other nodes and those (outer) nodes are
connected cyclically.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, each wheel graph will be displayed with the first (0) node in the center, the second node at the top,
and the rest following in a counterclockwise manner.
With the wheel graph, we see that it doesn’t take a very large n at all for the spring-layout to give a counter-intuitive
display. (See Graphics Array examples below).
EXAMPLES:
We view many wheel graphs with a Sage Graphics Array, first with this constructor (i.e., the position dictionary
filled):
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.WheelGraph(i+3)
....: g.append(k)
...
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
...
sage: G = graphics_array(j)
sage: G.show() # long time
sage: n = networkx.wheel_graph(23)
sage: spring23 = Graph(n)
sage: posdict23 = graphs.WheelGraph(23)
sage: spring23.show() # long time
sage: posdict23.show() # long time
sage.graphs.generators.families.WindmillGraph(k, n)
Return the Windmill graph 𝑊 𝑑(𝑘, 𝑛).
The windmill graph 𝑊 𝑑(𝑘, 𝑛) is an undirected graph constructed for 𝑘 ≥ 2 and 𝑛 ≥ 2 by joining 𝑛 copies of the
complete graph 𝐾𝑘 at a shared vertex. It has (𝑘 − 1)𝑛 + 1 vertices and 𝑛𝑘(𝑘 − 1)/2 edges, girth 3 (if 𝑘 > 2),
radius 1 and diameter 2. It has vertex connectivity 1 because its central vertex is an articulation point; however,
like the complete graphs from which it is formed, it is (𝑘 − 1)-edge-connected. It is trivially perfect and a block
graph.
See also:
EXAMPLES:
The Windmill graph 𝑊 𝑑(2, 𝑛) is a star graph:
sage: n = 5
sage: W = graphs.WindmillGraph(2, n)
sage: W.is_isomorphic( graphs.StarGraph(n) )
True
sage: n = 5
sage: W = graphs.WindmillGraph(3, n)
(continues on next page)
sage: W = graphs.WindmillGraph(3, 2)
sage: W.is_isomorphic( graphs.ButterflyGraph() )
True
sage.graphs.generators.families.chang_graphs()
Return the three Chang graphs.
Three of the four strongly regular graphs of parameters (28, 12, 6, 4) are called the Chang graphs. The fourth is
the line graph of 𝐾8 . For more information about the Chang graphs, see the Wikipedia article Chang_graphs or
https://www.win.tue.nl/~aeb/graphs/Chang.html.
EXAMPLES: check that we get 4 non-isomorphic s.r.g.’s with the same parameters:
sage: c3c5=graphs.CycleGraph(3).disjoint_union(graphs.CycleGraph(5))
sage: c8=graphs.CycleGraph(8)
sage: s=[K8.subgraph_search(c8).edges(sort=False),
....: [(0,1,None),(2,3,None),(4,5,None),(6,7,None)],
....: K8.subgraph_search(c3c5).edges(sort=False)]
sage: list(map(lambda x,G: T8.seidel_switching(x, inplace=False).is_isomorphic(G),
....: s, chang_graphs))
[True, True, True]
sage.graphs.generators.families.line_graph_forbidden_subgraphs()
Returns the 9 forbidden subgraphs of a line graph.
See the Wikipedia article Line_graph for more information.
The graphs are returned in the ordering given by the Wikipedia drawing, read from left to right and from top to
bottom.
EXAMPLES:
sage: graphs.line_graph_forbidden_subgraphs()
[Claw graph: Graph on 4 vertices,
Graph on 6 vertices,
Graph on 6 vertices,
Graph on 5 vertices,
Graph on 6 vertices,
Graph on 6 vertices,
Graph on 6 vertices,
Graph on 6 vertices,
Graph on 5 vertices]
sage.graphs.generators.families.nauty_gentreeg(options='', debug=False)
Return a generator which creates non-isomorphic trees from nauty’s gentreeg program.
INPUT:
• options – string (default: ""); a string passed to gentreeg as if it was run at a system command line.
At a minimum, you must pass the number of vertices you desire. Sage expects the graphs to be in nauty’s
“sparse6” format, do not set an option to change this default or results will be unpredictable.
• debug – boolean (default: False); if True the first line of gentreeg’s output to standard error is captured
and the first call to the generator’s next() function will return this line as a string. A line leading with
“>A” indicates a successful initiation of the program with some information on the arguments, while a line
beginning with “>E” indicates an error with the input.
The possible options, obtained as output of gentreeg -help:
Options which cause gentreeg to use an output format different than the sparse6 format are not listed above (-p,
-l, -u) as they will confuse the creation of a Sage graph. The res/mod option can be useful when using the output
in a routine run several times in parallel.
OUTPUT:
A generator which will produce the graphs as Sage graphs. These will be simple graphs: no loops, no multiple
edges, no directed edges.
See also:
trees() – another generator of trees
EXAMPLES:
The generator can be used to construct trees for testing, one at a time (usually inside a loop). Or it can be used
to create an entire list all at once if there is sufficient memory to contain it:
The number of trees on the first few vertex counts. This agrees with OEIS sequence A000055:
The debug switch can be used to examine gentreeg’s reaction to the input in the options string. We illustrate
success. (A failure will be a string beginning with “>E”.) Passing the “-q” switch to gentreeg will suppress the
indicator of a successful initiation, and so the first returned value might be an empty string if debug is True:
sage.graphs.generators.families.petersen_family(generate=False)
Returns the Petersen family
The Petersen family is a collection of 7 graphs which are the forbidden minors of the linklessly embeddable
graphs. For more information see the Wikipedia article Petersen_family.
INPUT:
• generate (boolean) – whether to generate the family from the ∆ − 𝑌 transformations. When set to False
(default) a hardcoded version of the graphs (with a prettier layout) is returned.
EXAMPLES:
sage: graphs.petersen_family()
[Petersen graph: Graph on 10 vertices,
Complete graph: Graph on 6 vertices,
Multipartite Graph with set sizes [3, 3, 1]: Graph on 7 vertices,
Graph on 8 vertices,
Graph on 9 vertices,
Graph on 7 vertices,
Graph on 8 vertices]
sage: F1 = graphs.petersen_family(generate=False)
sage: F2 = graphs.petersen_family(generate=True)
sage: F1 = [g.canonical_label().graph6_string() for g in F1]
sage: F2 = [g.canonical_label().graph6_string() for g in F2]
sage: set(F1) == set(F2)
True
sage.graphs.generators.families.trees(vertices)
Returns a generator of the distinct trees on a fixed number of vertices.
INPUT:
• vertices - the size of the trees created.
OUTPUT:
A generator which creates an exhaustive, duplicate-free listing of the connected free (unlabeled) trees with
vertices number of vertices. A tree is a graph with no cycles.
ALGORITHM:
Uses an algorithm that generates each new tree in constant time. See the documentation for, and implementation
of, the sage.graphs.trees module, including a citation.
EXAMPLES:
We create an iterator, then loop over its elements.
The number of trees on the first few vertex counts. This is sequence A000055 in Sloane’s OEIS.
sage: g = graphs.BullGraph(); g
Bull graph: Graph on 5 vertices
sage: g.show() # long time
The bull graph has 5 vertices and 5 edges. Its radius is 2, its diameter 3, and its girth 3. The bull graph is planar
with chromatic number 3 and chromatic index also 3:
The bull graph has chromatic polynomial 𝑥(𝑥−2)(𝑥−1)3 and Tutte polynomial 𝑥4 +𝑥3 +𝑥2 𝑦. Its characteristic
polynomial is 𝑥(𝑥2 − 𝑥 − 3)(𝑥2 + 𝑥 − 1), which follows from the definition of characteristic polynomials for
graphs, i.e. det(𝑥𝐼 − 𝐴), where 𝑥 is a variable, 𝐴 the adjacency matrix of the graph, and 𝐼 the identity matrix
of the same dimensions as 𝐴:
sage.graphs.generators.basic.ButterflyGraph()
Return the butterfly graph.
Let 𝐶3 be the cycle graph on 3 vertices. The butterfly or bowtie graph is obtained by joining two copies of 𝐶3 at
a common vertex, resulting in a graph that is isomorphic to the friendship graph 𝐹2 . See the Wikipedia article
Butterfly_graph for more information.
See also:
• GraphGenerators.FriendshipGraph()
EXAMPLES:
The butterfly graph is a planar graph on 5 vertices and having 6 edges:
sage: G = graphs.ButterflyGraph(); G
Butterfly graph: Graph on 5 vertices
sage: G.show() # long time
sage: G.is_planar()
True
sage: G.order()
5
sage: G.size()
6
sage: G.diameter()
2
sage: G.girth()
3
sage: G.radius()
1
sage: G.is_eulerian()
True
sage: G.chromatic_number()
3
sage.graphs.generators.basic.CircularLadderGraph(n)
Return a circular ladder graph with 2 * 𝑛 nodes.
A Circular ladder graph is a ladder graph that is connected at the ends, i.e.: a ladder bent around so that top meets
bottom. Thus it can be described as two parallel cycle graphs connected at each corresponding node pair.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the circular ladder graph is displayed as an inner and outer cycle pair, with the first 𝑛 nodes drawn
on the inner circle. The first (0) node is drawn at the top of the inner-circle, moving clockwise after that. The
outer circle is drawn with the (𝑛 + 1), we rotate the outer circle by an angle of 𝜋/8 to ensure that all edges are
visible (otherwise the 4 vertices of the graph would be placed on a single line).
EXAMPLES:
Construct and show a circular ladder graph with 26 nodes:
sage: g = graphs.CircularLadderGraph(13)
sage: g.show() # long time
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.CircularLadderGraph(i+3)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
(continues on next page)
sage.graphs.generators.basic.ClawGraph()
Return a claw graph.
A claw graph is named for its shape. It is actually a complete bipartite graph with (n1, n2) = (1, 3).
PLOTTING: See CompleteBipartiteGraph().
EXAMPLES:
Show a Claw graph:
sage: G = graphs.ClawGraph()
sage: G
Claw graph: Graph on 4 vertices
sage.graphs.generators.basic.CompleteBipartiteGraph(p, q, set_position=True)
Return a Complete Bipartite Graph on 𝑝 + 𝑞 vertices.
A Complete Bipartite Graph is a graph with its vertices partitioned into two groups, 𝑉1 = {0, ..., 𝑝 − 1} and
𝑉2 = {𝑝, ..., 𝑝 + 𝑞 − 1}. Each 𝑢 ∈ 𝑉1 is connected to every 𝑣 ∈ 𝑉2 .
INPUT:
• p,q – number of vertices in each side
• set_position – boolean (default True); if set to True, we assign positions to the vertices so that the set
of cardinality 𝑝 is on the line 𝑦 = 1 and the set of cardinality 𝑞 is on the line 𝑦 = 0.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, each complete bipartite graph will be displayed with the first 𝑝 nodes on the top row (at 𝑦 = 1) from
left to right. The remaining 𝑞 nodes appear at 𝑦 = 0, also from left to right. The shorter row (partition with
fewer nodes) is stretched to the same length as the longer row, unless the shorter row has 1 node; in which case
it is centered. The 𝑥 values in the plot are in domain [0, max(𝑝, 𝑞)].
In the Complete Bipartite graph, there is a visual difference in using the spring-layout algorithm vs. the position
dictionary used in this constructor. The position dictionary flattens the graph and separates the partitioned nodes,
making it clear which nodes an edge is connected to. The Complete Bipartite graph plotted with the spring-layout
algorithm tends to center the nodes in 𝑝 (see spring_med in examples below), thus overlapping its nodes and
edges, making it typically hard to decipher.
Filling the position dictionary in advance adds 𝑂(𝑛) to the constructor. Feel free to race the constructors below in
the examples section. The much larger difference is the time added by the spring-layout algorithm when plotting.
(Also shown in the example below). The spring model is typically described as 𝑂(𝑛3 ), as appears to be the case
in the NetworkX source code.
EXAMPLES:
Two ways of constructing the complete bipartite graph, using different layout algorithms:
Notice here how the spring-layout tends to center the nodes of 𝑛1:
View many complete bipartite graphs with a Sage Graphics Array, with this constructor (i.e., the position dictio-
nary filled):
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.CompleteBipartiteGraph(i+1,4)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
sage: g = []
sage: j = []
sage: for i in range(9):
....: spr = networkx.complete_bipartite_graph(i+1,4)
....: k = Graph(spr)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
sage: graphs.CompleteBipartiteGraph(5,6).complement()
complement(Complete bipartite graph of order 5+6): Graph on 11 vertices
sage.graphs.generators.basic.CompleteGraph(n)
Return a complete graph on 𝑛 nodes.
A Complete Graph is a graph in which all nodes are connected to all other nodes.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, each complete graph will be displayed with the first (0) node at the top, with the rest following in a
counterclockwise manner.
In the complete graph, there is a big difference visually in using the spring-layout algorithm vs. the position
dictionary used in this constructor. The position dictionary flattens the graph, making it clear which nodes
an edge is connected to. But the complete graph offers a good example of how the spring-layout works. The
edges push outward (everything is connected), causing the graph to appear as a 3-dimensional pointy ball. (See
examples below).
EXAMPLES:
We view many Complete graphs with a Sage Graphics Array, first with this constructor (i.e., the position dictio-
nary filled):
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.CompleteGraph(i+3)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
We compare plotting:
sage.graphs.generators.basic.CompleteMultipartiteGraph(L)
Return a complete multipartite graph.
INPUT:
• L – a list of integers; the respective sizes of the components
PLOTTING: Produce a layout of the vertices so that vertices in the same vertex set are adjacent and clearly
separated from vertices in other vertex sets.
This is done by calculating the vertices of an 𝑟-gon then calculating the slope between adjacent vertices. We then
‘walk’ around the 𝑟-gon placing graph vertices in regular intervals between adjacent vertices of the 𝑟-gon.
Makes a nicely organized graph like in this picture: https://commons.wikimedia.org/wiki/File:Turan_13-4.svg
EXAMPLES:
A complete tripartite graph with sets of sizes 5, 6, 8:
sage: g.chromatic_number()
3
sage.graphs.generators.basic.CycleGraph(n)
Return a cycle graph with 𝑛 nodes.
A cycle graph is a basic structure which is also typically called an 𝑛-gon.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, each cycle graph will be displayed with the first (0) node at the top, with the rest following in a
counterclockwise manner.
The cycle graph is a good opportunity to compare efficiency of filling a position dictionary vs. using the spring-
layout algorithm for plotting. Because the cycle graph is very symmetric, the resulting plots should be similar
(in cases of small 𝑛).
Filling the position dictionary in advance adds 𝑂(𝑛) to the constructor.
EXAMPLES:
Compare plotting using the predefined layout and networkx:
We next view many cycle graphs as a Sage graphics array. First we use the CycleGraph constructor, which fills
in the position dictionary:
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.CycleGraph(i+3)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
sage: g = []
sage: j = []
sage: for i in range(9):
....: spr = networkx.cycle_graph(i+3)
....: k = Graph(spr)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
sage.graphs.generators.basic.DartGraph()
Return a dart graph with 5 nodes.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the dart graph is drawn as a dart, with the sharp part on the bottom.
EXAMPLES:
Construct and show a dart graph:
sage: g = graphs.DartGraph()
sage: g.show() # long time
sage.graphs.generators.basic.DiamondGraph()
Return a diamond graph with 4 nodes.
A diamond graph is a square with one pair of diagonal nodes connected.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the diamond graph is drawn as a diamond, with the first node on top, second on the left, third on the
right, and fourth on the bottom; with the second and third node connected.
EXAMPLES:
Construct and show a diamond graph:
sage: g = graphs.DiamondGraph()
sage: g.show() # long time
sage.graphs.generators.basic.EmptyGraph()
Return an empty graph (0 nodes and 0 edges).
This is useful for constructing graphs by adding edges and vertices individually or in a loop.
PLOTTING: When plotting, this graph will use the default spring-layout algorithm, unless a position dictionary
is specified.
EXAMPLES:
Add one vertex to an empty graph and then show:
sage.graphs.generators.basic.ForkGraph()
Return a fork graph with 5 nodes.
A fork graph, sometimes also called chair graph, is 5 vertex tree.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the fork graph is drawn as a fork, with the sharp part on the bottom.
EXAMPLES:
Construct and show a fork graph:
sage: g = graphs.ForkGraph()
sage: g.show() # long time
sage.graphs.generators.basic.GemGraph()
Return a gem graph with 5 nodes.
A gem graph is a fan graph (4,1).
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the gem graph is drawn as a gem, with the sharp part on the bottom.
EXAMPLES:
Construct and show a gem graph:
sage: g = graphs.GemGraph()
sage: g.show() # long time
sage.graphs.generators.basic.Grid2dGraph(p, q, set_positions=True)
Return a 2-dimensional grid graph with 𝑝 × 𝑞 nodes (𝑝 rows and 𝑞 columns).
A 2d grid graph resembles a 2 dimensional grid. All inner nodes are connected to their 4 neighbors. Outer
(non-corner) nodes are connected to their 3 neighbors. Corner nodes are connected to their 2 neighbors.
INPUT:
• p and q – two positive integers
• set_positions – boolean (default: True); whether to set the position of the nodes
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, nodes are labelled in (row, column) pairs with (0, 0) in the top left corner. Edges will always be
horizontal and vertical - another advantage of filling the position dictionary.
EXAMPLES:
Construct and show a grid 2d graph Rows = 5, Columns = 7:
sage: g = graphs.Grid2dGraph(5,7)
sage: g.show() # long time
sage.graphs.generators.basic.GridGraph(dim_list)
Return an 𝑛-dimensional grid graph.
INPUT:
• dim_list – a list of integers representing the number of nodes to extend in each dimension
PLOTTING: When plotting, this graph will use the default spring-layout algorithm, unless a position dictionary
is specified.
EXAMPLES:
sage: G = graphs.GridGraph([2,3,4])
sage: G.show() # long time
sage: C = graphs.CubeGraph(4)
sage: G = graphs.GridGraph([2,2,2,2])
sage: C.show() # long time
sage: G.show() # long time
sage.graphs.generators.basic.HouseGraph()
Return a house graph with 5 nodes.
A house graph is named for its shape. It is a triangle (roof) over a square (walls).
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the house graph is drawn with the first node in the lower-left corner of the house, the second in the
lower-right corner of the house. The third node is in the upper-left corner connecting the roof to the wall, and the
fourth is in the upper-right corner connecting the roof to the wall. The fifth node is the top of the roof, connected
only to the third and fourth.
EXAMPLES:
Construct and show a house graph:
sage: g = graphs.HouseGraph()
sage: g.show() # long time
sage.graphs.generators.basic.HouseXGraph()
Return a house X graph with 5 nodes.
A house X graph is a house graph with two additional edges. The upper-right corner is connected to the lower-left.
And the upper-left corner is connected to the lower-right.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the house X graph is drawn with the first node in the lower-left corner of the house, the second in
the lower-right corner of the house. The third node is in the upper-left corner connecting the roof to the wall,
and the fourth is in the upper-right corner connecting the roof to the wall. The fifth node is the top of the roof,
connected only to the third and fourth.
EXAMPLES:
Construct and show a house X graph:
sage: g = graphs.HouseXGraph()
sage: g.show() # long time
sage.graphs.generators.basic.LadderGraph(n)
Return a ladder graph with 2 * 𝑛 nodes.
A ladder graph is a basic structure that is typically displayed as a ladder, i.e.: two parallel path graphs connected
at each corresponding node pair.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, each ladder graph will be displayed horizontally, with the first n nodes displayed left to right on the
top horizontal line.
EXAMPLES:
Construct and show a ladder graph with 14 nodes:
sage: g = graphs.LadderGraph(7)
sage: g.show() # long time
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.LadderGraph(i+2)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
(continues on next page)
sage.graphs.generators.basic.PathGraph(n, pos=None)
Return a path graph with 𝑛 nodes.
A path graph is a graph where all inner nodes are connected to their two neighbors and the two end-nodes are
connected to their one inner neighbors (i.e.: a cycle graph without the first and last node connected).
INPUT:
• n – number of nodes of the path graph
• pos – string (default: None); indicates the embedding to use between ‘circle’, ‘line’ or the default algorithm.
See the plotting section below for more detail.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the graph may be drawn in one of two ways: The ‘line’ argument will draw the graph in a horizontal
line (left to right) if there are less than 11 nodes. Otherwise the ‘line’ argument will append horizontal lines of
length 10 nodes below, alternating left to right and right to left. The ‘circle’ argument will cause the graph to be
drawn in a cycle-shape, with the first node at the top and then about the circle in a clockwise manner. By default
(without an appropriate string argument) the graph will be drawn as a ‘circle’ if 10 < 𝑛 < 41 and as a ‘line’ for
all other 𝑛.
EXAMPLES: Show default drawing by size: ‘line’: 𝑛 ≤ 10
sage: p = graphs.PathGraph(10)
sage: p.show() # long time
sage: q = graphs.PathGraph(25)
sage: q.show() # long time
‘line’: 𝑛 ≥ 41
sage: r = graphs.PathGraph(55)
sage: r.show() # long time
sage: s = graphs.PathGraph(5,'circle')
sage: s.show() # long time
sage.graphs.generators.basic.StarGraph(n)
Return a star graph with 𝑛 + 1 nodes.
A Star graph is a basic structure where one node is connected to all other nodes.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, each star graph will be displayed with the first (0) node in the center, the second node (1) at the top,
with the rest following in a counterclockwise manner. (0) is the node connected to all other nodes.
The star graph is a good opportunity to compare efficiency of filling a position dictionary vs. using the spring-
layout algorithm for plotting. As far as display, the spring-layout should push all other nodes away from the (0)
node, and thus look very similar to this constructor’s positioning.
EXAMPLES:
sage: n = networkx.star_graph(23)
sage: spring23 = Graph(n)
sage: posdict23 = graphs.StarGraph(23)
sage: spring23.show() # long time
sage: posdict23.show() # long time
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.StarGraph(i+3)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
sage: g = []
sage: j = []
sage: for i in range(9):
....: spr = networkx.star_graph(i+3)
....: k = Graph(spr)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
sage.graphs.generators.basic.Toroidal6RegularGrid2dGraph(p, q)
Return a toroidal 6-regular grid.
The toroidal 6-regular grid is a 6-regular graph on 𝑝 × 𝑞 vertices and its elements have coordinates (𝑖, 𝑗) for
𝑖 ∈ {0...𝑝 − 1} and 𝑗 ∈ {0...𝑞 − 1}.
Its edges are those of the ToroidalGrid2dGraph(), to which are added the edges between (𝑖, 𝑗) and ((𝑖 +
1)%𝑝, (𝑗 + 1)%𝑞).
INPUT:
• p, q – integers (see above)
EXAMPLES:
The toroidal 6-regular grid on 25 elements:
sage: g = graphs.Toroidal6RegularGrid2dGraph(5,5)
sage: g.is_regular(k=6)
True
sage: g.is_vertex_transitive()
True
sage: g.line_graph().is_vertex_transitive()
True
sage: g.automorphism_group().cardinality()
300
sage: g.is_hamiltonian()
True
sage.graphs.generators.basic.ToroidalGrid2dGraph(p, q)
Return a toroidal 2-dimensional grid graph with 𝑝 × 𝑞 nodes (𝑝 rows and 𝑞 columns).
The toroidal 2-dimensional grid with parameters 𝑝, 𝑞 is the 2-dimensional grid graph with identical parameters
to which are added the edges ((𝑖, 0), (𝑖, 𝑞 − 1)) and ((0, 𝑖), (𝑝 − 1, 𝑖)).
EXAMPLES:
The toroidal 2-dimensional grid is a regular graph, while the usual 2-dimensional grid is not
The 𝑑-dimensional Bishop Graph with 𝑑 >= 2 has for vertex set the cells of a 𝑑-dimensional grid with prescribed
dimensions, and each edge corresponds to a legal move by a bishop in any pairs of dimensions.
The Bishop Graph is not connected.
INPUT:
• dim_list – iterable (list, set, dict); provides the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1, of the chessboard
• radius – integer (default: None); by setting the radius to a positive integer, one may decrease the power
of the bishop to at most radius steps.
• relabel – boolean (default: False); indicates whether the vertices must be relabeled as integers
EXAMPLES:
The (n,m)-Bishop Graph is not connected:
sage.graphs.generators.chessboard.ChessboardGraphGenerator(dim_list, rook=True,
rook_radius=None, bishop=True,
bishop_radius=None, knight=True,
knight_x=1, knight_y=2,
relabel=False)
Return a Graph built on a 𝑑-dimensional chessboard with prescribed dimensions and interconnections.
This function allows to generate many kinds of graphs corresponding to legal movements on a 𝑑-dimensional
chessboard: Queen Graph, King Graph, Knight Graphs, Bishop Graph, and many generalizations. It also allows
to avoid redundant code.
INPUT:
• dim_list – iterable (list, set, dict); provides the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1, of the chessboard
• rook – boolean (default: True); indicates whether the chess piece is able to move as a rook, that is at any
distance along a dimension
• rook_radius – integer (default: None); restriction on the rook-like movements to distance at most
rook_radius
• bishop – boolean (default: True); indicates whether the chess piece is able to move like a bishop, that is
along diagonals
• bishop_radius – integer (default: None); restriction on the bishop-like movements to distance at most
bishop_radius
• knight – boolean (default: True); indicating whether the chess piece is able to move like a knight
• knight_x – integer (default: 1); indicates the number on steps the chess piece moves in one dimension
when moving like a knight
• knight_y – integer (default: 2); indicates the number on steps the chess piece moves in the second dimen-
sion when moving like a knight
• relabel – boolean (default: False); indicates whether the vertices must be relabeled as integers
OUTPUT:
• A Graph build on a 𝑑-dimensional chessboard with prescribed dimensions, and with edges according given
parameters.
• A string encoding the dimensions. This is mainly useful for providing names to graphs.
EXAMPLES:
A (2, 2)-King Graph is isomorphic to the complete graph on 4 vertices:
sage: H = (graphs.CompleteGraph(3)).cartesian_product(graphs.CompleteGraph(4))
sage: G.is_isomorphic(H)
True
The King Graph with large enough radius is isomorphic to a Queen Graph:
The 𝑑-dimensional Queen Graph with 𝑑 >= 2 has for vertex set the cells of a 𝑑-dimensional grid with prescribed
dimensions, and each edge corresponds to a legal move by a queen in either one or two dimensions.
All 2-dimensional Queen Graphs are Hamiltonian and biconnected. The chromatic number of a (𝑛, 𝑛)-Queen
Graph is at least 𝑛, and it is exactly 𝑛 when 𝑛 ≡ 1, 5 mod 6.
INPUT:
• dim_list – iterable (list, set, dict); provides the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1, of the chessboard
• radius – integer (default: None); by setting the radius to a positive integer, one may reduce the visibility
of the queen to at most radius steps. When radius is 1, the resulting graph is a King Graph.
• relabel – boolean (default: False); indicates whether the vertices must be relabeled as integers
EXAMPLES:
The (2, 2)-Queen Graph is isomorphic to the complete graph on 4 vertices:
The Queen Graph can be obtained from the Rook Graph and the Bishop Graph:
INPUT:
• dim_list – iterable (list, set, dict); provides the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1, of the chessboard
• radius – integer (default: None); by setting the radius to a positive integer, one may decrease the power
of the rook to at most radius steps. When the radius is 1, the resulting graph is a 𝑑-dimensional grid.
• relabel – boolean (default: False); indicates whether the vertices must be relabeled as integers
EXAMPLES:
The (𝑛, 𝑚)-Rook’s Graph is isomorphic to the Cartesian product of two complete graphs:
Note: The elements of 𝑆 must be finite, hashable, and the elements of any 𝑠 ∈ 𝑆 must be hashable
too.
EXAMPLES:
sage: graphs.IntersectionGraph([(1,2,3),(3,4,5),(5,6,7)])
Intersection Graph: Graph on 3 vertices
sage.graphs.generators.intersection.IntervalGraph(intervals, points_ordered=False)
Return the graph corresponding to the given intervals.
An interval graph is built from a list (𝑎𝑖 , 𝑏𝑖 )1≤𝑖≤𝑛 of intervals : to each interval of the list is associated one
vertex, two vertices being adjacent if the two corresponding (closed) intervals intersect.
INPUT:
• intervals – the list of pairs (𝑎𝑖 , 𝑏𝑖 ) defining the graph.
• points_ordered – states whether every interval (𝑎𝑖 , 𝑏𝑖 ) of 𝑖𝑛𝑡𝑒𝑟𝑣𝑎𝑙𝑠 satisfies 𝑎𝑖 < 𝑏𝑖 . If satisfied then
setting points_ordered to True will speed up the creation of the graph.
Note:
• The vertices are named 0, 1, 2, and so on. The intervals used to create the graph are saved with the graph
and can be recovered using get_vertex() or get_vertices().
EXAMPLES:
The following line creates the sequence of intervals (𝑖, 𝑖 + 2) for i in [0, ..., 8]:
sage: g = graphs.IntervalGraph(intervals)
sage: g.get_vertex(3)
(3, 5)
sage: neigh = g.neighbors(3)
sage: for v in neigh: print(g.get_vertex(v))
(1, 3)
(2, 4)
(4, 6)
(5, 7)
sage: g.is_interval()
True
The endpoints of the intervals are not ordered we get the same graph (except for the vertex labels).
sage.graphs.generators.intersection.OrthogonalArrayBlockGraph(k, n, OA=None)
Return the graph of an 𝑂𝐴(𝑘, 𝑛).
The intersection graph of the blocks of a transversal design with parameters (𝑘, 𝑛), or 𝑇 𝐷(𝑘, 𝑛) for short, is a
strongly regular graph (unless it is a complete graph). Its parameters (𝑣, 𝑘 ′ , 𝜆, 𝜇) are determined by the param-
eters 𝑘, 𝑛 via:
As transversal designs and orthogonal arrays (OA for short) are equivalent objects, this graph can also be built
from the blocks of an 𝑂𝐴(𝑘, 𝑛), two of them being adjacent if one of their coordinates match.
For more information on these graphs, see Andries Brouwer’s page on Orthogonal Array graphs.
Warning:
• Brouwer’s website uses the notation 𝑂𝐴(𝑛, 𝑘) instead of 𝑂𝐴(𝑘, 𝑛)
• For given parameters 𝑘 and 𝑛 there can be many 𝑂𝐴(𝑘, 𝑛) : the graphs returned are not uniquely
defined by their parameters (see the examples below).
• If the function is called only with the parameter k and n the results might be different with two versions
of Sage, or even worse : some could not be available anymore.
See also:
sage.combinat.designs.orthogonal_arrays
INPUT:
• k,n (integers)
• OA – An orthogonal array. If set to None (default) then orthogonal_array() is called to compute an
𝑂𝐴(𝑘, 𝑛).
EXAMPLES:
sage: G = graphs.OrthogonalArrayBlockGraph(5,5); G
OA(5,5): Graph on 25 vertices
sage: G.is_strongly_regular(parameters=True)
(25, 20, 15, 20)
sage: G = graphs.OrthogonalArrayBlockGraph(4,10); G
OA(4,10): Graph on 100 vertices
sage: G.is_strongly_regular(parameters=True)
(100, 36, 14, 12)
Two graphs built from different orthogonal arrays are also different:
sage: k=4;n=10
sage: OAa = designs.orthogonal_arrays.build(k,n)
sage: OAb = [[(x+1)%n for x in R] for R in OAa]
sage: set(map(tuple,OAa)) == set(map(tuple,OAb))
False
sage: Ga = graphs.OrthogonalArrayBlockGraph(k,n,OAa)
sage: Gb = graphs.OrthogonalArrayBlockGraph(k,n,OAb)
sage: Ga == Gb
False
As OAb was obtained from OAa by a relabelling the two graphs are isomorphic:
sage: Ga.is_isomorphic(Gb)
True
But there are examples of 𝑂𝐴(𝑘, 𝑛) for which the resulting graphs are not isomorphic:
sage: oa0 = [[0, 0, 1], [0, 1, 3], [0, 2, 0], [0, 3, 2],
....: [1, 0, 3], [1, 1, 1], [1, 2, 2], [1, 3, 0],
....: [2, 0, 0], [2, 1, 2], [2, 2, 1], [2, 3, 3],
....: [3, 0, 2], [3, 1, 0], [3, 2, 3], [3, 3, 1]]
sage: oa1 = [[0, 0, 1], [0, 1, 0], [0, 2, 3], [0, 3, 2],
....: [1, 0, 3], [1, 1, 2], [1, 2, 0], [1, 3, 1],
....: [2, 0, 0], [2, 1, 1], [2, 2, 2], [2, 3, 3],
....: [3, 0, 2], [3, 1, 3], [3, 2, 1], [3, 3, 0]]
sage: g0 = graphs.OrthogonalArrayBlockGraph(3,4,oa0)
sage: g1 = graphs.OrthogonalArrayBlockGraph(3,4,oa1)
sage: g0.is_isomorphic(g1)
False
sage: g0.spectrum()
[9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3]
sage: g1.spectrum()
[9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3]
Note that the graph g0 is actually isomorphic to the affine polar graph 𝑉 𝑂+ (4, 2):
sage: graphs.AffineOrthogonalPolarGraph(4,2,'+').is_isomorphic(g0)
True
sage.graphs.generators.intersection.PermutationGraph(second_permutation, first_permutation=None)
Build a permutation graph from one permutation or from two lists.
Definition:
If 𝜎 is a permutation of {1, 2, . . . , 𝑛}, then the permutation graph of 𝜎 is the graph on vertex set {1, 2, . . . , 𝑛} in
which two vertices 𝑖 and 𝑗 satisfying 𝑖 < 𝑗 are connected by an edge if and only if 𝜎 −1 (𝑖) > 𝜎 −1 (𝑗). A visual
way to construct this graph is as follows:
Take two horizontal lines in the euclidean plane, and mark points 1, ..., 𝑛 from left to right on the first
of them. On the second one, still from left to right, mark 𝑛 points 𝜎(1), 𝜎(2), . . . , 𝜎(𝑛). Now, link by
a segment the two points marked with 1, then link together the points marked with 2, and so on. The
permutation graph of 𝜎 is the intersection graph of those segments: there exists a vertex in this graph
for each element from 1 to 𝑛, two vertices 𝑖, 𝑗 being adjacent if the segments 𝑖 and 𝑗 cross each other.
The set of edges of the permutation graph can thus be identified with the set of inversions of the inverse of the
given permutation 𝜎.
A more general notion of permutation graph can be defined as follows: If 𝑆 is a set, and (𝑎1 , 𝑎2 , . . . , 𝑎𝑛 ) and
(𝑏1 , 𝑏2 , . . . , 𝑏𝑛 ) are two lists of elements of 𝑆, each of which lists contains every element of 𝑆 exactly once, then
the permutation graph defined by these two lists is the graph on the vertex set 𝑆 in which two vertices 𝑖 and 𝑗
are connected by an edge if and only if the order in which these vertices appear in the list (𝑎1 , 𝑎2 , . . . , 𝑎𝑛 ) is the
opposite of the order in which they appear in the list (𝑏1 , 𝑏2 , . . . , 𝑏𝑛 ). When (𝑎1 , 𝑎2 , . . . , 𝑎𝑛 ) = (1, 2, . . . , 𝑛),
this graph is the permutation graph of the permutation (𝑏1 , 𝑏2 , . . . , 𝑏𝑛 ) ∈ 𝑆𝑛 . Notice that 𝑆 does not have to
be a set of integers here, but can be a set of strings, tuples, or anything else. We can still use the above visual
description to construct the permutation graph, but now we have to mark points 𝑎1 , 𝑎2 , . . . , 𝑎𝑛 from left to right
on the first horizontal line and points 𝑏1 , 𝑏2 , . . . , 𝑏𝑛 from left to right on the second horizontal line.
INPUT:
• second_permutation – the unique permutation/list defining the graph, or the second of the two (if the
graph is to be built from two permutations/lists).
• first_permutation (optional) – the first of the two permutations/lists from which the graph should be
built, if it is to be built from two permutations/lists.
When first_permutation is None (default), it is set to be equal to sorted(second_permutation),
which yields the expected ordering when the elements of the graph are integers.
See also:
EXAMPLES:
sage: p = Permutations(5).random_element()
sage: PG = graphs.PermutationGraph(p)
sage: edges = PG.edges(sort=True, labels=False)
sage: set(edges) == set(p.inverse().inversions())
True
sage: PG = graphs.PermutationGraph([3,4,5,1,2])
sage: sorted(PG.edges(sort=True))
[(1, 3, None),
(1, 4, None),
(1, 5, None),
(2, 3, None),
(2, 4, None),
(2, 5, None)]
sage: PG = graphs.PermutationGraph([3,4,5,1,2], [1,4,2,5,3])
sage: sorted(PG.edges(sort=True))
[(1, 3, None),
(1, 4, None),
(1, 5, None),
(2, 3, None),
(2, 5, None),
(3, 4, None),
(3, 5, None)]
sage: PG = graphs.PermutationGraph([1,4,2,5,3], [3,4,5,1,2])
sage: sorted(PG.edges(sort=True))
[(1, 3, None),
(1, 4, None),
(1, 5, None),
(2, 3, None),
(2, 5, None),
(3, 4, None),
(3, 5, None)]
sage: graphs.PermutationGraph([]).edges(sort=True)
[]
sage: graphs.PermutationGraph([], []).edges(sort=True)
[]
sage.graphs.generators.intersection.ToleranceGraph(tolrep)
Return the graph generated by the tolerance representation tolrep.
The tolerance representation tolrep is described by the list ((𝑙0 , 𝑟0 , 𝑡0 ), (𝑙1 , 𝑟1 , 𝑡1 ), . . . , (𝑙𝑘 , 𝑟𝑘 , 𝑡𝑘 )) where 𝐼𝑖 =
(𝑙𝑖 , 𝑟𝑖 ) denotes a closed interval on the real line with 𝑙𝑖 < 𝑟𝑖 and 𝑡𝑖 a strictly positive value, called tolerance. This
representation generates the tolerance graph with the vertex set {0, 1, . . . , 𝑘} and the edge set {(𝑖, 𝑗) : |𝐼𝑖 ∩ 𝐼𝑗 | ≥
min{𝑡𝑖 , 𝑡𝑗 }} where |𝐼𝑖 ∩ 𝐼𝑗 | denotes the length of the intersection of 𝐼𝑖 and 𝐼𝑗 .
INPUT:
• tolrep – list of triples (𝑙𝑖 , 𝑟𝑖 , 𝑡𝑖 ) where (𝑙𝑖 , 𝑟𝑖 ) denotes a closed interval on the real line and 𝑡𝑖 a positive
value.
Note: The vertices are named 0, 1, . . . , 𝑘. The tolerance representation used to create the graph is saved with
the graph and can be recovered using get_vertex() or get_vertices().
EXAMPLES:
The following code creates a tolerance representation tolrep, generates its tolerance graph g, and applies some
checks:
sage: g = graphs.DodecahedralGraph()
sage: g.show() # long time
Create several dodecahedral graphs in a Sage graphics array They will be drawn differently due to the use of the
spring-layout algorithm:
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.DodecahedralGraph()
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
sage.graphs.generators.platonic_solids.HexahedralGraph()
Return a hexahedral graph (with 8 nodes).
A regular hexahedron is a 6-sided cube. The hexahedral graph corresponds to the connectivity of the vertices of
the hexahedron. This graph is equivalent to a 3-cube.
PLOTTING: The Hexahedral graph should be viewed in 3 dimensions. We choose to use a planar embedding
of the graph. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a argument will be
added to select the desired layout.
EXAMPLES:
Construct and show a Hexahedral graph:
sage: g = graphs.HexahedralGraph()
sage: g.show() # long time
Create several hexahedral graphs in a Sage graphics array. They will be drawn differently due to the use of the
spring-layout algorithm:
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.HexahedralGraph()
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
sage.graphs.generators.platonic_solids.IcosahedralGraph()
Return an Icosahedral graph (with 12 nodes).
The regular icosahedron is a 20-sided triangular polyhedron. The icosahedral graph corresponds to the connec-
tivity of the vertices of the icosahedron. It is dual to the dodecahedral graph. The icosahedron is symmetric, so
the spring-layout algorithm will be very effective for display.
PLOTTING: The Icosahedral graph should be viewed in 3 dimensions. We choose to use a planar embedding
of the graph. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a argument will be
added to select the desired layout.
EXAMPLES:
Construct and show an Octahedral graph:
sage: g = graphs.IcosahedralGraph()
sage: g.show() # long time
Create several icosahedral graphs in a Sage graphics array. They will be drawn differently due to the use of the
spring-layout algorithm:
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.IcosahedralGraph()
....: g.append(k)
sage: for i in range(3):
(continues on next page)
sage.graphs.generators.platonic_solids.OctahedralGraph()
Return an Octahedral graph (with 6 nodes).
The regular octahedron is an 8-sided polyhedron with triangular faces. The octahedral graph corresponds to the
connectivity of the vertices of the octahedron. It is the line graph of the tetrahedral graph. The octahedral is
symmetric, so the spring-layout algorithm will be very effective for display.
PLOTTING: The Octahedral graph should be viewed in 3 dimensions. We choose to use a planar embedding of
the graph. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a argument will be
added to select the desired layout.
EXAMPLES:
Construct and show an Octahedral graph:
sage: g = graphs.OctahedralGraph()
sage: g.show() # long time
Create several octahedral graphs in a Sage graphics array They will be drawn differently due to the use of the
spring-layout algorithm:
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.OctahedralGraph()
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
sage.graphs.generators.platonic_solids.TetrahedralGraph()
Return a tetrahedral graph (with 4 nodes).
A tetrahedron is a 4-sided triangular pyramid. The tetrahedral graph corresponds to the connectivity of the
vertices of the tetrahedron. This graph is equivalent to a wheel graph with 4 nodes and also a complete graph on
four nodes. (See examples below).
PLOTTING: The Tetrahedral graph should be viewed in 3 dimensions. We choose to use a planar embedding
of the graph. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a argument will be
added to select the desired layout.
EXAMPLES:
Construct and show a Tetrahedral graph:
sage: g = graphs.TetrahedralGraph()
sage: g.show() # long time
Compare this Tetrahedral, Wheel(4), Complete(4), and the Tetrahedral plotted with the spring-layout algorithm
below in a Sage graphics array:
sage: G = graphs.RandomBarabasiAlbert(6,2)
sage: G.order(), G.size()
(6, 8)
sage: G.degree_sequence() # random
[4, 3, 3, 2, 2, 2]
sage: ba = graphs.RandomBarabasiAlbert(12,3)
sage: ba.show() # long time
sage: g = []
sage: j = []
sage: for i in range(1,10):
....: k = graphs.RandomBarabasiAlbert(i+3, 3)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
sage.graphs.generators.random.RandomBicubicPlanar(n, seed=None)
Return the graph of a random bipartite cubic map with 3𝑛 edges.
INPUT:
𝑛 – an integer (at least 1)
• seed – a random.Random seed or a Python int for the random number generator (default: None)
OUTPUT:
a graph with multiple edges (no embedding is provided)
The algorithm used is described in [Sch1999]. This samples a random rooted bipartite cubic map, chosen uni-
formly at random.
First one creates a random binary tree with 𝑛 vertices. Next one turns this into a blossoming tree (at random)
and reads the contour word of this blossoming tree.
Then one performs a rotation on this word so that this becomes a balanced word. There are three ways to do that,
one is picked at random. Then a graph is build from the balanced word by iterated closure (adding edges).
In the returned graph, the three edges incident to any given vertex are colored by the integers 0, 1 and 2.
See also:
the auxiliary method blossoming_contour()
EXAMPLES:
INPUT:
• m – integer; number of blocks (at least one).
sage: B = graphs.RandomBlockGraph(1, 4)
sage: B.is_clique()
True
sage: B = graphs.RandomBlockGraph(10, 2)
sage: B.is_tree()
True
sage: m, k = 6, 4
sage: B = graphs.RandomBlockGraph(m, k)
sage: B.order() == m*(k-1)+1
True
sage: m, k = 6, 4
sage: IS = graphs.RandomBlockGraph(m, k, incidence_structure=True)
sage: from sage.combinat.designs.incidence_structures import IncidenceStructure
sage: IncidenceStructure(IS)
Incidence structure with 19 points and 6 blocks
(continues on next page)
sage.graphs.generators.random.RandomBoundedToleranceGraph(n, seed=None)
Return a random bounded tolerance graph.
The random tolerance graph is built from a random bounded tolerance representation by using the function
𝑇 𝑜𝑙𝑒𝑟𝑎𝑛𝑐𝑒𝐺𝑟𝑎𝑝ℎ. This representation is a list ((𝑙0 , 𝑟0 , 𝑡0 ), (𝑙1 , 𝑟1 , 𝑡1 ), ..., (𝑙𝑘 , 𝑟𝑘 , 𝑡𝑘 )) where 𝑘 = 𝑛 − 1 and
𝐼𝑖 = (𝑙𝑖 , 𝑟𝑖 ) denotes a random interval and 𝑡𝑖 a random positive value less than or equal to the length of the
interval 𝐼𝑖 . The width of the representation is limited to 𝑛2 * 2𝑛 .
Note: The tolerance representation used to create the graph can be recovered using get_vertex() or
get_vertices().
INPUT:
• n – number of vertices of the random graph.
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
Every (bounded) tolerance graph is perfect. Hence, the chromatic number is equal to the clique number
sage: g = graphs.RandomBoundedToleranceGraph(8)
sage: g.clique_number() == g.chromatic_number()
True
in total. Then, it determines the sizes of the 𝑙 + 1 subtrees and stores the distinct values. Finally, it
picks a random size 𝑘𝑖 from the set of largest 100(1 − 𝑠)% of distinct values, and randomly chooses a
subtree with size 𝑘𝑖 .
• k –√integer (default: None); maximum size of a subtree. If not specified (None), the maximum size is set
to 𝑛. This parameter is used only when algorithm="growing". See growing_subtrees() for more
details.
• l – a strictly positive real number (default: None); mean of a Poisson distribution. If not speci-
fied, the mean in set to log2 𝑛. This parameter is used only when algorithm="connecting". See
connecting_nodes() for more details.
• f – a rational number (default: None); the edge deletion fraction. This value must be chosen in [0..1]. If
not specified, this parameter is set to 𝑛−1
1
. This parameter is used only when algorithm="pruned". See
pruned_tree() for more details.
• s – a real number between 0 and 1 (default: None); selection barrier for the size of trees. If not specified, this
parameter is set to 0.5. This parameter is used only when algorithm="pruned". See pruned_tree()
for more details.
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
See also:
• growing_subtrees()
• connecting_nodes()
• pruned_tree()
• Wikipedia article Chordal_graph
• is_chordal()
• IntersectionGraph()
EXAMPLES:
We show the edge list of a random graph on 5 nodes with 10 edges:
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.RandomGNM(i+3, i^2-i)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
sage: set_random_seed(0)
sage: graphs.RandomGNP(6, .4).edges(sort=true, labels=False)
[(0, 3), (1, 2), (2, 3), (2, 4)]
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.RandomGNP(i+3,.43)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = graphics_array(j)
sage: G.show() # long time
sage: graphs.RandomGNP(4,1)
Complete graph: Graph on 4 vertices
sage.graphs.generators.random.RandomHolmeKim(n, m, p, seed=None)
Return a random graph generated by the Holme and Kim algorithm for graphs with power law degree distribution
and approximate average clustering.
INPUT:
• n – number of vertices
• m – number of random edges to add for each new node
• p – probability of adding a triangle after adding a random edge
• seed – a random.Random seed or a Python int for the random number generator (default: None)
From the NetworkX documentation: the average clustering has a hard time getting above a certain cutoff that
depends on 𝑚. This cutoff is often quite low. Note that the transitivity (fraction of triangles to possible triangles)
seems to go down with network size. It is essentially the Barabasi-Albert growth model with an extra step that
each random edge is followed by a chance of making an edge to one of its neighbors too (and thus a triangle).
This algorithm improves on B-A in the sense that it enables a higher average clustering to be attained if desired.
It seems possible to have a disconnected graph with this algorithm since the initial 𝑚 nodes may not be all linked
to a new node on the first iteration like the BA model.
EXAMPLES:
We check that a random graph on 8 nodes with 2 random edges per node and a probability 𝑝 = 0.5 of forming
triangles contains a triangle:
REFERENCE:
[HK2002a]
sage.graphs.generators.random.RandomIntervalGraph(n, seed=None)
Returns a random interval graph.
An interval graph is built from a list (𝑎𝑖 , 𝑏𝑖 )1≤𝑖≤𝑛 of intervals : to each interval of the list is associated one
vertex, two vertices being adjacent if the two corresponding intervals intersect.
A random interval graph of order 𝑛 is generated by picking random values for the (𝑎𝑖 , 𝑏𝑗 ), each of the two
coordinates being generated from the uniform distribution on the interval [0, 1].
This definitions follows [BF2001].
Note: The vertices are named 0, 1, 2, and so on. The intervals used to create the graph are saved with the graph
and can be recovered using get_vertex() or get_vertices().
INPUT:
• n – integer; the number of vertices in the random graph
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
As for any interval graph, the chromatic number is equal to the clique number
sage: g = graphs.RandomIntervalGraph(8)
sage: g.clique_number() == g.chromatic_number()
True
sage.graphs.generators.random.RandomLobster(n, p, q, seed=None)
Returns a random lobster.
A lobster is a tree that reduces to a caterpillar when pruning all leaf vertices. A caterpillar is a tree that reduces
to a path when pruning all leaf vertices (q=0).
INPUT:
• n - expected number of vertices in the backbone
• p - probability of adding an edge to the backbone
• q - probability of adding an edge (claw) to the arms
• seed - a random.Random seed or a Python int for the random number generator (default: None).
EXAMPLES:
We check a random graph with 12 backbone nodes and probabilities 𝑝 = 0.7 and 𝑞 = 0.3:
sage.graphs.generators.random.RandomNewmanWattsStrogatz(n, k, p, seed=None)
Return a Newman-Watts-Strogatz small world random graph on 𝑛 vertices.
From the NetworkX documentation: first create a ring over 𝑛 nodes. Then each node in the ring is connected
with its 𝑘 nearest neighbors. Then shortcuts are created by adding new edges as follows: for each edge 𝑢 − 𝑣 in
the underlying “𝑛-ring with 𝑘 nearest neighbors”; with probability 𝑝 add a new edge 𝑢−𝑤 with randomly-chosen
existing node 𝑤. In contrast with networkx.watts_strogatz_graph(), no edges are removed.
INPUT:
• n – number of vertices
• k – each vertex is connected to its 𝑘 nearest neighbors
• p – the probability of adding a new edge for each edge
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
We check that the generated graph contains a cycle of order 𝑛:
REFERENCE:
[NWS2002]
sage.graphs.generators.random.RandomRegular(d, n, seed=None)
Return a random 𝑑-regular graph on 𝑛 vertices, or False on failure.
Since every edge is incident to two vertices, 𝑛 × 𝑑 must be even.
INPUT:
• d – degree
• n – number of vertices
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
We check that a random graph with 8 nodes each of degree 3 is 3-regular:
sage: G = graphs.RandomRegular(3, 8)
sage: G.is_regular(k=3)
True
sage: G.degree_histogram()
[0, 0, 0, 8]
REFERENCES:
• [KV2003]
• [SW1999]
sage.graphs.generators.random.RandomRegularBipartite(n1, n2, d1, set_position=False, seed=None)
Return a random regular bipartite graph on 𝑛1 + 𝑛2 vertices.
The bipartite graph has 𝑛1 * 𝑑1 edges. Hence, 𝑛2 must divide 𝑛1 * 𝑑1. Each vertex of the set of cardinality 𝑛1
has degree 𝑑1 (which can be at most 𝑛2) and each vertex in the set of cardinality 𝑛2 has degree (𝑛1 * 𝑑1)/𝑛2.
The bipartite graph has no multiple edges.
This generator implements an algorithm inspired by that of [MW1990] for the uniform generation of random
regular bipartite graphs. It performs well when 𝑑1 = 𝑜(𝑛21/3 ) or (𝑛2 − 𝑑1 = 𝑜(𝑛21/3 )). In other cases, the
running time can be huge. Note that the currently implemented algorithm does not generate uniformly random
graphs.
INPUT:
• n1, n2 – number of vertices in each side
• d1 – degree of the vertices in the set of cardinality 𝑛1.
• set_position – boolean (default False); if set to True, we assign positions to the vertices so that the set
of cardinality 𝑛1 is on the line 𝑦 = 1 and the set of cardinality 𝑛2 is on the line 𝑦 = 0.
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
sage: g = graphs.RandomRegularBipartite(4, 6, 3)
sage: g.order(), g.size()
(10, 12)
sage: set(g.degree())
{2, 3}
sage.graphs.generators.random.RandomShell(constructor, seed=None)
Return a random shell graph for the constructor given.
INPUT:
• constructor – a list of 3-tuples (𝑛, 𝑚, 𝑑), each representing a shell, where:
– n – the number of vertices in the shell
– m – the number of edges in the shell
– d – the ratio of inter (next) shell edges to intra shell edges
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
sage: G = graphs.RandomShell([(10,20,0.8),(20,40,0.8)])
sage: G.order(), G.size()
(30, 52)
sage: G.show() # long time
sage.graphs.generators.random.RandomToleranceGraph(n, seed=None)
Return a random tolerance graph.
The random tolerance graph is built from a random tolerance representation by using the function
𝑇 𝑜𝑙𝑒𝑟𝑎𝑛𝑐𝑒𝐺𝑟𝑎𝑝ℎ. This representation is a list ((𝑙0 , 𝑟0 , 𝑡0 ), (𝑙1 , 𝑟1 , 𝑡1 ), ..., (𝑙𝑘 , 𝑟𝑘 , 𝑡𝑘 )) where 𝑘 = 𝑛 − 1 and
𝐼𝑖 = (𝑙𝑖 , 𝑟𝑖 ) denotes a random interval and 𝑡𝑖 a random positive value. The width of the representation is limited
to 𝑛2 * 2𝑛 .
Note: The vertices are named 0, 1, . . . , n-1. The tolerance representation used to create the graph is saved with
the graph and can be recovered using get_vertex() or get_vertices().
INPUT:
• n – number of vertices of the random graph
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
Every tolerance graph is perfect. Hence, the chromatic number is equal to the clique number
sage: g = graphs.RandomToleranceGraph(8)
sage: g.clique_number() == g.chromatic_number()
True
sage.graphs.generators.random.RandomTree(n, seed=None)
Returns a random tree on 𝑛 nodes numbered 0 through 𝑛 − 1.
By Cayley’s theorem, there are 𝑛𝑛−2 trees with vertex set {0, 1, ..., 𝑛 − 1}. This constructor chooses one of these
uniformly at random.
ALGORITHM:
The algorithm works by generating an (𝑛 − 2)-long random sequence of numbers chosen independently and
uniformly from {0, 1, . . . , 𝑛 − 1} and then applies an inverse Prufer transformation.
INPUT:
• n – number of vertices in the tree
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
sage: G = graphs.RandomTree(10)
sage: G.is_tree()
True
sage: G.show() # long time
sage: G = graphs.RandomTreePowerlaw(10, 3)
sage: G.is_tree()
True
sage: G.order(), G.size()
(10, 9)
sage: G = graphs.RandomTreePowerlaw(15, 2)
sage: if G:
....: G.show() # random output, long time
OUTPUT:
A random graph chosen uniformly among the inner triangulations of a rooted 𝑘-gon with 𝑛 vertices (including
the 𝑘 vertices from the outer face). This is a planar graph and comes with a combinatorial embedding. The
vertices of the root edge are labelled -1 and -2 and the outer face is the face returned by Graph.faces() in
which -1 and -2 are consecutive vertices in this order.
Because some triangulations have nontrivial automorphism groups, this may not be equal to the uniform distri-
bution among inner triangulations of unrooted 𝑘-gons.
ALGORITHM:
The algorithm is taken from [PS2006], Section 5.
Starting from a planar 𝑘-gonal forest (represented by its contour as a sequence of vertices), one performs local
closures, until no one is possible. A local closure amounts to replace in the cyclic contour word a sequence in1,
in2, in3, lf, in3 by in1, in3.
At every step of the algorithm, newly created edges are recorded in a graph, which will be returned at the end.
The combinatorial embedding is also computed and recorded in the output graph.
See also:
triangulations(), RandomTwoSphere().
EXAMPLES:
sage: t = BinaryTrees(2).random_element()
sage: print(blossoming_contour(t)) # random
[('i', 0), ('xb',), ('i', 0), ('n', 2), ('i', 1), ('xb',), ('i', 1),
('xb',), ('i', 1), ('n', 2), ('x',), ('n', 2), ('i', 0)]
sage.graphs.generators.random.connecting_nodes(T, l)
Return a list of the vertex sets of n randomly chosen subtrees of T.
This method is part of RandomChordalGraph().
ALGORITHM:
For each subtree 𝑇𝑖 , we first select 𝑘𝑖 nodes of 𝑇 , where 𝑘𝑖 is a random integer from a Poisson distribution
with mean 𝑙. 𝑇𝑖 is then generated to be the minimal subtree that contains the selected 𝑘𝑖 nodes. This implies
that a subtree will most likely have many more nodes than those selected initially, and this must be taken into
consideration when choosing 𝑙.
See [SHET2018] for more details.
INPUT:
• T – a tree
• l – a strictly positive real number; mean of a Poisson distribution
EXAMPLES:
sage.graphs.generators.random.growing_subtrees(T, k)
Return a list of the vertex sets of n randomly chosen subtrees of T.
For a tree of order 𝑛, the collection contains 𝑛 subtrees with maximum order 𝑘 and average order 2 .
𝑘+1
sage.graphs.generators.random.pruned_tree(T, f, s)
Return a list of the vertex sets of n randomly chosen subtrees of T.
This method is part of RandomChordalGraph().
ALGORITHM:
For each subtree 𝑇𝑖 , it randomly selects a fraction 𝑓 of the edges on the tree and removes them. The number of
edges to delete, say 𝑙, is calculated as ⌊((𝑛 − 1)𝑓 ⌋, which will leave 𝑙 + 1 subtrees in total. Then, it determines
the sizes of the 𝑙 + 1 subtrees and stores the distinct values. Finally, it picks a random size 𝑘𝑖 from the set of
largest 100(1 − 𝑠)% of distinct values, and randomly chooses a subtree with size 𝑘𝑖 .
See [SHET2018] for more details.
INPUT:
• T – a tree
• f – a rational number; the edge deletion fraction. This value must be chosen in [0..1].
• s – a real number between 0 and 1; selection barrier for the size of trees
EXAMPLES:
• embedding – integer (default: 1); two embeddings are available, and can be selected by setting embedding
to be either 1 or 2
EXAMPLES:
sage: g = graphs.Balaban10Cage()
sage: g.girth()
10
sage: g.chromatic_number()
2
sage: g.diameter()
6
sage: g.is_hamiltonian()
True
sage: g.show(figsize=[10,10]) # long time
sage.graphs.generators.smallgraphs.Balaban11Cage(embedding=1)
Return the Balaban 11-cage.
For more information, see the Wikipedia article Balaban_11-cage.
INPUT:
• embedding – integer (default: 1); three embeddings are available, and can be selected by setting
embedding to be 1, 2, or 3
– The first embedding is the one appearing on page 9 of the Fifth Annual Graph Drawing Contest report
[EMMN1998]. It separates vertices based on their eccentricity (see eccentricity()).
– The second embedding has been produced just for Sage and is meant to emphasize the automorphism
group’s 6 orbits.
– The last embedding is the default one produced by the LCFGraph() constructor.
EXAMPLES:
Basic properties:
sage: g = graphs.Balaban11Cage()
sage: g.order()
112
sage: g.size()
168
sage: g.girth()
11
sage: g.diameter()
8
sage: g.automorphism_group().cardinality()
64
sage: g1 = graphs.Balaban11Cage(embedding=1)
sage: g2 = graphs.Balaban11Cage(embedding=2)
sage: g3 = graphs.Balaban11Cage(embedding=3)
(continues on next page)
sage.graphs.generators.smallgraphs.BidiakisCube()
Return the Bidiakis cube.
For more information, see the Wikipedia article Bidiakis_cube.
EXAMPLES:
The Bidiakis cube is a 3-regular graph having 12 vertices and 18 edges. This means that each vertex has a degree
of 3:
sage: g = graphs.BidiakisCube(); g
Bidiakis cube: Graph on 12 vertices
sage: g.show() # long time
sage: g.order()
12
sage: g.size()
18
sage: g.is_regular(3)
True
sage: g.is_hamiltonian()
True
sage: g.diameter()
3
sage: g.girth()
4
It is a planar graph with characteristic polynomial (𝑥 − 3)(𝑥 − 2)(𝑥4 )(𝑥 + 1)(𝑥 + 2)(𝑥2 + 𝑥 − 4)2 and chromatic
number 3:
sage: g.is_planar()
True
sage: char_poly = g.characteristic_polynomial()
sage: x = char_poly.parent()('x')
sage: char_poly == (x - 3) * (x - 2) * (x^4) * (x + 1) * (x + 2) * (x^2 + x - 4)^2
True
sage: g.chromatic_number()
3
sage.graphs.generators.smallgraphs.BiggsSmithGraph(embedding=1)
Return the Biggs-Smith graph.
For more information, see the Wikipedia article Biggs-Smith_graph.
INPUT:
• embedding – integer (default: 1); two embeddings are available, and can be selected by setting embedding
to be 1 or 2
EXAMPLES:
Basic properties:
sage: g = graphs.BiggsSmithGraph()
sage: g.order()
102
sage: g.size()
153
sage: g.girth()
9
sage: g.diameter()
7
sage: g.automorphism_group().cardinality() # long time
2448
sage: g.show(figsize=[10, 10]) # long time
sage.graphs.generators.smallgraphs.BlanusaFirstSnarkGraph()
Return the first Blanusa Snark Graph.
The Blanusa graphs are two snarks on 18 vertices and 27 edges. For more information on them, see the Wikipedia
article Blanusa_snarks.
See also:
• BlanusaSecondSnarkGraph().
EXAMPLES:
sage: g = graphs.BlanusaFirstSnarkGraph()
sage: g.order()
18
sage: g.size()
27
sage: g.diameter()
4
sage: g.girth()
5
sage: g.automorphism_group().cardinality()
8
sage.graphs.generators.smallgraphs.BlanusaSecondSnarkGraph()
Return the second Blanusa Snark Graph.
The Blanusa graphs are two snarks on 18 vertices and 27 edges. For more information on them, see the Wikipedia
article Blanusa_snarks.
See also:
• BlanusaFirstSnarkGraph().
EXAMPLES:
sage: g = graphs.BlanusaSecondSnarkGraph()
sage: g.order()
18
sage: g.size()
27
sage: g.diameter()
4
sage: g.girth()
5
sage: g.automorphism_group().cardinality()
4
sage.graphs.generators.smallgraphs.BrinkmannGraph()
Return the Brinkmann graph.
For more information, see the Wikipedia article Brinkmann_graph.
EXAMPLES:
The Brinkmann graph is a 4-regular graph having 21 vertices and 42 edges. This means that each vertex has
degree 4:
sage: G = graphs.BrinkmannGraph(); G
Brinkmann graph: Graph on 21 vertices
sage: G.show() # long time
sage: G.order()
21
sage: G.size()
42
sage: G.is_regular(4)
True
sage: G.is_eulerian()
True
sage: G.radius()
3
sage: G.diameter()
3
sage: G.girth()
5
sage: G.is_hamiltonian()
True
sage: G.chromatic_number()
4
sage: ag = G.automorphism_group()
sage: ag.is_isomorphic(DihedralGroup(7))
True
sage.graphs.generators.smallgraphs.BrouwerHaemersGraph()
Return the Brouwer-Haemers Graph.
The Brouwer-Haemers is the only strongly regular graph of parameters (81, 20, 1, 6). It is build in Sage as the
Affine Orthogonal graph 𝑉 𝑂− (6, 3). For more information on this graph, see its corresponding page on Andries
Brouwer’s website.
EXAMPLES:
sage: g = graphs.BrouwerHaemersGraph()
sage: g
Brouwer-Haemers: Graph on 81 vertices
sage.graphs.generators.smallgraphs.BuckyBall()
Return the Bucky Ball graph.
This graph is a 3-regular 60-vertex planar graph. Its vertices and edges correspond precisely to the carbon atoms
and bonds in buckminsterfullerene. When embedded on a sphere, its 12 pentagon and 20 hexagon faces are
arranged exactly as the sections of a soccer ball.
EXAMPLES:
The Bucky Ball is planar:
sage: g = graphs.BuckyBall()
sage: g.is_planar()
True
The Bucky Ball can also be created by extracting the 1-skeleton of the Bucky Ball polyhedron, but this is much
slower:
sage: g = polytopes.buckyball().vertex_graph()
sage: g.remove_loops()
sage: h = graphs.BuckyBall()
sage: g.is_isomorphic(h)
True
sage.graphs.generators.smallgraphs.CameronGraph()
Return the Cameron graph.
The Cameron graph is strongly regular with parameters 𝑣 = 231, 𝑘 = 30, 𝜆 = 9, 𝜇 = 3.
For more information on the Cameron graph, see https://www.win.tue.nl/~aeb/graphs/Cameron.html.
EXAMPLES:
sage: g = graphs.CameronGraph()
sage: g.order()
231
sage: g.size()
3465
sage: g.is_strongly_regular(parameters = True) # long time
(231, 30, 9, 3)
sage.graphs.generators.smallgraphs.Cell120()
Return the 120-Cell graph.
This is the adjacency graph of the 120-cell. It has 600 vertices and 1200 edges. For more information, see the
Wikipedia article 120-cell.
EXAMPLES:
sage.graphs.generators.smallgraphs.Cell600(embedding=1)
Return the 600-Cell graph.
This is the adjacency graph of the 600-cell. It has 120 vertices and 720 edges. For more information, see the
Wikipedia article 600-cell.
INPUT:
• embedding – integer (default: 1); two different embeddings for a plot
EXAMPLES:
sage.graphs.generators.smallgraphs.ChvatalGraph()
Return the Chvatal graph.
Chvatal graph is one of the few known graphs to satisfy Grunbaum’s conjecture that for every 𝑚, 𝑛, there
is an 𝑚-regular, 𝑚-chromatic graph of girth at least 𝑛. For more information, see the Wikipedia article
Chv%C3%A1tal_graph.
EXAMPLES:
The Chvatal graph has 12 vertices and 24 edges. It is a 4-regular, 4-chromatic graph with radius 2, diameter 2,
and girth 4:
sage: G = graphs.ChvatalGraph(); G
Chvatal graph: Graph on 12 vertices
sage: G.order(); G.size()
12
24
sage: G.degree()
[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]
sage: G.chromatic_number()
4
sage: G.radius(); G.diameter(); G.girth()
2
2
4
sage.graphs.generators.smallgraphs.ClebschGraph()
Return the Clebsch graph.
See the Wikipedia article Clebsch_graph for more information.
EXAMPLES:
sage: g = graphs.ClebschGraph()
sage: g.automorphism_group().cardinality()
1920
sage: g.girth()
4
sage: g.chromatic_number()
4
sage: g.diameter()
2
sage: g.show(figsize=[10, 10]) # long time
sage.graphs.generators.smallgraphs.CoxeterGraph()
Return the Coxeter graph.
See the Wikipedia article Coxeter_graph.
EXAMPLES:
sage: g = graphs.CoxeterGraph()
sage: g.automorphism_group().cardinality()
336
sage: g.girth()
7
sage: g.chromatic_number()
3
sage: g.diameter()
4
sage: g.show(figsize=[10, 10]) # long time
sage.graphs.generators.smallgraphs.DejterGraph()
Return the Dejter graph.
The Dejter graph is obtained from the binary 7-cube by deleting a copy of the Hamming code of length 7. It is
6-regular, with 112 vertices and 336 edges. For more information, see the Wikipedia article Dejter_graph.
EXAMPLES:
sage: g = graphs.DejterGraph(); g
Dejter Graph: Graph on 112 vertices
sage: g.is_regular(k=6)
True
sage: g.girth()
4
sage.graphs.generators.smallgraphs.DesarguesGraph()
Return the Desargues graph.
PLOTTING: The layout chosen is the same as on the cover of [Har1994].
EXAMPLES:
sage: D = graphs.DesarguesGraph()
sage: L = graphs.LCFGraph(20,[5,-5,9,-9],5)
sage: D.is_isomorphic(L)
True
sage: D.show() # long time
sage.graphs.generators.smallgraphs.DoubleStarSnark()
Return the double star snark.
The double star snark is a 3-regular graph on 30 vertices. See the Wikipedia article Double-star_snark.
EXAMPLES:
sage: g = graphs.DoubleStarSnark()
sage: g.order()
30
sage: g.size()
45
sage: g.chromatic_number()
3
sage: g.is_hamiltonian()
False
sage: g.automorphism_group().cardinality()
80
sage: g.show()
sage.graphs.generators.smallgraphs.DurerGraph()
Return the Dürer graph.
For more information, see the Wikipedia article D%C3%BCrer_graph.
EXAMPLES:
The Dürer graph is named after Albrecht Dürer. It is a planar graph with 12 vertices and 18 edges:
sage: G = graphs.DurerGraph(); G
Durer graph: Graph on 12 vertices
sage: G.is_planar()
True
(continues on next page)
sage: G.chromatic_number()
3
sage: G.diameter()
4
sage: G.girth()
3
sage: ag = G.automorphism_group()
sage: ag.is_isomorphic(DihedralGroup(6))
True
sage.graphs.generators.smallgraphs.DyckGraph()
Return the Dyck graph.
For more information, see the MathWorld article on the Dyck graph or the Wikipedia article Dyck_graph.
EXAMPLES:
The Dyck graph was defined by Walther von Dyck in 1881. It has 32 vertices and 48 edges, and is a cubic graph
(regular of degree 3):
sage: G = graphs.DyckGraph(); G
Dyck graph: Graph on 32 vertices
sage: G.order()
32
sage: G.size()
48
sage: G.is_regular()
True
sage: G.is_regular(3)
True
sage: G.is_planar()
False
sage: G.is_hamiltonian()
True
sage: G.is_bipartite()
True
sage: G.radius()
5
(continues on next page)
sage: G.chromatic_number()
2
sage: G.automorphism_group().cardinality()
192
sage: G.characteristic_polynomial().factor()
(x - 3) * (x + 3) * (x - 1)^9 * (x + 1)^9 * (x^2 - 5)^6
It is a toroidal graph, and its embedding on a torus is dual to an embedding of the Shrikhande graph
(ShrikhandeGraph).
sage.graphs.generators.smallgraphs.EllinghamHorton54Graph()
Return the Ellingham-Horton 54-graph.
For more information, see the Wikipedia article Ellingham-Horton_graph.
EXAMPLES:
This graph is 3-regular:
sage: g = graphs.EllinghamHorton54Graph()
sage: g.is_regular(k=3)
True
It is not Hamiltonian:
sage.graphs.generators.smallgraphs.EllinghamHorton78Graph()
Return the Ellingham-Horton 78-graph.
For more information, see the Wikipedia article Ellingham%E2%80%93Horton_graph
EXAMPLES:
This graph is 3-regular:
sage: g = graphs.EllinghamHorton78Graph()
sage: g.is_regular(k=3)
True
It is not Hamiltonian:
sage.graphs.generators.smallgraphs.ErreraGraph()
Return the Errera graph.
For more information, see the Wikipedia article Errera_graph.
EXAMPLES:
The Errera graph is named after Alfred Errera. It is a planar graph on 17 vertices and having 45 edges:
sage: G = graphs.ErreraGraph(); G
Errera graph: Graph on 17 vertices
sage: G.is_planar()
True
sage: G.order()
17
sage: G.size()
45
The Errera graph is Hamiltonian with radius 3, diameter 4, girth 3, and chromatic number 4:
sage: G.is_hamiltonian()
True
sage: G.radius()
3
sage: G.diameter()
4
sage: G.girth()
3
sage: G.chromatic_number()
4
Each vertex degree is either 5 or 6. That is, if 𝑓 counts the number of vertices of degree 5 and 𝑠 counts the
number of vertices of degree 6, then 𝑓 + 𝑠 is equal to the order of the Errera graph:
sage: D = G.degree_sequence()
sage: D.count(5) + D.count(6) == G.order()
True
The automorphism group of the Errera graph is isomorphic to the dihedral group of order 20:
sage: ag = G.automorphism_group()
sage: ag.is_isomorphic(DihedralGroup(10))
True
sage.graphs.generators.smallgraphs.F26AGraph()
Return the F26A graph.
The F26A graph is a symmetric bipartite cubic graph with 26 vertices and 39 edges. For more information, see
the Wikipedia article F26A_graph.
EXAMPLES:
sage: g = graphs.F26AGraph(); g
F26A Graph: Graph on 26 vertices
sage: g.order(),g.size()
(26, 39)
sage: g.automorphism_group().cardinality()
78
sage: g.girth()
6
sage: g.is_bipartite()
True
sage: g.characteristic_polynomial().factor()
(x - 3) * (x + 3) * (x^4 - 5*x^2 + 3)^6
sage.graphs.generators.smallgraphs.FlowerSnark()
Return a Flower Snark.
A flower snark has 20 vertices. It is part of the class of biconnected cubic graphs with edge chromatic number
= 4, known as snarks. (i.e.: the Petersen graph). All snarks are not Hamiltonian, non-planar and have Petersen
graph graph minors. See the Wikipedia article Flower_snark.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the nodes are drawn 0-14 on the outer circle, and 15-19 in an inner pentagon.
EXAMPLES: Inspect a flower snark:
sage: F = graphs.FlowerSnark()
sage: F
Flower Snark: Graph on 20 vertices
sage: F.graph6_string()
'ShCGHC@?GGg@?@?Gp?K??C?CA?G?_G?Cc'
sage.graphs.generators.smallgraphs.FolkmanGraph()
Return the Folkman graph.
See the Wikipedia article Folkman_graph.
EXAMPLES:
sage: g = graphs.FolkmanGraph()
sage: g.order()
20
sage: g.size()
40
sage: g.diameter()
4
sage: g.girth()
4
sage: g.charpoly().factor()
(x - 4) * (x + 4) * x^10 * (x^2 - 6)^4
sage: g.chromatic_number()
2
sage: g.is_eulerian()
True
sage: g.is_hamiltonian()
True
sage: g.is_vertex_transitive()
False
sage: g.is_bipartite()
True
sage.graphs.generators.smallgraphs.FosterGraph()
Return the Foster graph.
See the Wikipedia article Foster_graph.
EXAMPLES:
sage: g = graphs.FosterGraph()
sage: g.order()
90
sage: g.size()
135
sage: g.diameter()
8
sage: g.girth()
10
sage: g.automorphism_group().cardinality()
4320
sage: g.is_hamiltonian()
True
sage.graphs.generators.smallgraphs.FranklinGraph()
Return the Franklin graph.
For more information, see the Wikipedia article Franklin_graph.
EXAMPLES:
The Franklin graph is named after Philip Franklin. It is a 3-regular graph on 12 vertices and having 18 edges:
sage: G = graphs.FranklinGraph(); G
Franklin graph: Graph on 12 vertices
(continues on next page)
The Franklin graph is a Hamiltonian, bipartite graph with radius 3, diameter 3, and girth 4:
sage: G.is_hamiltonian()
True
sage: G.is_bipartite()
True
sage: G.radius()
3
sage: G.diameter()
3
sage: G.girth()
4
sage: G.is_perfect()
True
sage: G.is_triangle_free()
True
sage: G.chromatic_number()
2
sage.graphs.generators.smallgraphs.FruchtGraph()
Return a Frucht Graph.
A Frucht graph has 12 nodes and 18 edges. It is the smallest cubic identity graph. It is planar and Hamiltonian.
See the Wikipedia article Frucht_graph.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the first seven nodes are on the outer circle, with the next four on an inner circle and the last in the
center.
EXAMPLES:
sage.graphs.generators.smallgraphs.GoldnerHararyGraph()
Return the Goldner-Harary graph.
For more information, see the Wikipedia article Goldner%E2%80%93Harary_graph.
EXAMPLES:
The Goldner-Harary graph is named after A. Goldner and Frank Harary. It is a planar graph having 11 vertices
and 27 edges:
sage: G = graphs.GoldnerHararyGraph(); G
Goldner-Harary graph: Graph on 11 vertices
sage: G.is_planar()
True
sage: G.order()
11
sage: G.size()
27
sage: G.is_chordal()
True
sage: G.radius()
2
sage: G.diameter()
2
sage: G.girth()
3
Its chromatic number is 4 and its automorphism group is isomorphic to the dihedral group 𝐷6 :
sage: G.chromatic_number()
4
sage: ag = G.automorphism_group()
sage: ag.is_isomorphic(DihedralGroup(6))
True
sage.graphs.generators.smallgraphs.GolombGraph()
Return the Golomb graph.
See the Wikipedia article Golomb_graph for more information.
EXAMPLES:
The Golomb graph is a planar and Hamiltonian graph with 10 vertices and 18 edges. It has chromatic number 4,
diameter 3, radius 2 and girth 3. It can be drawn in the plane as a unit distance graph:
sage: G = graphs.GolombGraph(); G
Golomb graph: Graph on 10 vertices
sage: pos = G.get_pos()
sage: dist2 = lambda u,v:(u[0]-v[0])**2 + (u[1]-v[1])**2
sage: all(dist2(pos[u], pos[v]) == 1 for u, v in G.edge_iterator(labels=None))
True
sage.graphs.generators.smallgraphs.GossetGraph()
Return the Gosset graph.
The Gosset graph is the skeleton of the Gosset_3_21() polytope. It has with 56 vertices and degree 27. For
more information, see the Wikipedia article Gosset_graph.
EXAMPLES:
sage: g = graphs.GossetGraph(); g
Gosset Graph: Graph on 56 vertices
sage: g.order(), g.size()
(56, 756)
sage.graphs.generators.smallgraphs.GrayGraph(embedding=1)
Return the Gray graph.
See the Wikipedia article Gray_graph.
INPUT:
• embedding – integer (default: 1); two embeddings are available, and can be selected by setting embedding
to 1 or 2
EXAMPLES:
sage: g = graphs.GrayGraph()
sage: g.order()
54
sage: g.size()
81
sage: g.girth()
8
sage: g.diameter()
6
sage: g.show(figsize=[10, 10]) # long time
sage: graphs.GrayGraph(embedding=2).show(figsize=[10, 10]) # long time
sage.graphs.generators.smallgraphs.GritsenkoGraph()
Return SRG(65, 32, 15, 16) constructed by Gritsenko.
We took the adjacency matrix from O.Gritsenko’s [Gri2021] and extracted orbits of the automorphism group on
the edges.
EXAMPLES:
sage: H = graphs.GritsenkoGraph(); H
Gritsenko strongly regular graph: Graph on 65 vertices
sage: H.is_strongly_regular(parameters=True)
(65, 32, 15, 16)
sage.graphs.generators.smallgraphs.GrotzschGraph()
Return the Grötzsch graph.
The Grötzsch graph is an example of a triangle-free graph with chromatic number equal to 4. For more informa-
tion, see the Wikipedia article Gr%C3%B6tzsch_graph.
EXAMPLES:
The Grötzsch graph is named after Herbert Grötzsch. It is a Hamiltonian graph with 11 vertices and 20 edges:
sage: G = graphs.GrotzschGraph(); G
Grotzsch graph: Graph on 11 vertices
sage: G.is_hamiltonian()
True
sage: G.order()
11
(continues on next page)
The Grötzsch graph is triangle-free and having radius 2, diameter 2, and girth 4:
sage: G.is_triangle_free()
True
sage: G.radius()
2
sage: G.diameter()
2
sage: G.girth()
4
Its chromatic number is 4 and its automorphism group is isomorphic to the dihedral group 𝐷5 :
sage: G.chromatic_number()
4
sage: ag = G.automorphism_group()
sage: ag.is_isomorphic(DihedralGroup(5))
True
sage.graphs.generators.smallgraphs.HallJankoGraph(from_string=True)
Return the Hall-Janko graph.
For more information on the Hall-Janko graph, see the Wikipedia article Hall-Janko_graph.
The construction used to generate this graph in Sage is by a 100-point permutation representation of the Janko
group 𝐽2 , as described in version 3 of the ATLAS of Finite Group representations, in particular on the page
ATLAS: J2 – Permutation representation on 100 points.
INPUT:
• from_string – boolean (default: True); whether to build the graph from its sparse6 string or through
GAP. The two methods return the same graph though doing it through GAP takes more time.
EXAMPLES:
sage: g = graphs.HallJankoGraph()
sage: g.is_regular(36)
True
sage: g.is_vertex_transitive()
True
sage: nu = set(g.neighbors(0))
sage: for v in range(1, 100):
....: if v in nu:
....: expected = 14
....: else:
....: expected = 12
....: nv = set(g.neighbors(v))
....: nv.discard(0)
....: if len(nu & nv) != expected:
(continues on next page)
sage: g.diameter()
2
sage: g.girth()
3
sage: factor(g.characteristic_polynomial())
(x - 36) * (x - 6)^36 * (x + 4)^63
sage.graphs.generators.smallgraphs.HarborthGraph()
Return the Harborth Graph.
The Harborth graph has 104 edges and 52 vertices, and is the smallest known example of a 4-regular matchstick
graph. For more information, see the Wikipedia article Harborth_graph.
EXAMPLES:
sage: g = graphs.HarborthGraph(); g
Harborth Graph: Graph on 52 vertices
sage: g.is_regular(4)
True
sage.graphs.generators.smallgraphs.HarriesGraph(embedding=1)
Return the Harries Graph.
The Harries graph is a Hamiltonian 3-regular graph on 70 vertices. See the Wikipedia article Harries_graph.
The default embedding here is to emphasize the graph’s 4 orbits. This graph actually has a funny construction.
The following procedure gives an idea of it, though not all the adjacencies are being properly defined.
1. Take two disjoint copies of a Petersen graph . Their vertices will form an orbit of the final graph.
2. Subdivide all the edges once, to create 15+15=30 new vertices, which together form another orbit.
3. Create 15 vertices, each of them linked to 2 corresponding vertices of the previous orbit, one in each of the
two subdivided Petersen graphs. At the end of this step all vertices from the previous orbit have degree 3,
and the only vertices of degree 2 in the graph are those that were just created.
4. Create 5 vertices connected only to the ones from the previous orbit so that the graph becomes 3-regular.
INPUT:
• embedding – integer (default: 1); two embeddings are available, and can be selected by setting embedding
to 1 or 2
EXAMPLES:
sage: g = graphs.HarriesGraph()
sage: g.order()
70
sage: g.size()
105
sage: g.girth()
10
sage: g.diameter()
(continues on next page)
sage.graphs.generators.smallgraphs.HarriesWongGraph(embedding=1)
Return the Harries-Wong Graph.
See the Wikipedia article Harries-Wong_graph.
About the default embedding:
The default embedding is an attempt to emphasize the graph’s 8 (!!!) different orbits. In order to understand this
better, one can picture the graph as being built in the following way.
1. One first creates a 3-dimensional cube (8 vertices, 12 edges), whose vertices define the first orbit of the
final graph.
2. The edges of this graph are subdivided once, to create 12 new vertices which define a second orbit.
3. The edges of the graph are subdivided once more, to create 24 new vertices giving a third orbit.
4. 4 vertices are created and made adjacent to the vertices of the second orbit so that they have degree 3. These
4 vertices also define a new orbit.
5. In order to make the vertices from the third orbit 3-regular (they all miss one edge), one creates a binary
tree on 1 + 3 + 6 + 12 vertices. The leaves of this new tree are made adjacent to the 12 vertices of the third
orbit, and the graph is now 3-regular. This binary tree contributes 4 new orbits to the Harries-Wong graph.
INPUT:
• embedding – integer (default: 1); two embeddings are available, and can be selected by setting embedding
to 1 or 2
EXAMPLES:
sage: g = graphs.HarriesWongGraph()
sage: g.order()
70
sage: g.size()
105
sage: g.girth()
10
sage: g.diameter()
6
sage: orbits = g.automorphism_group(orbits=True)[-1] # long time
sage: g.show(figsize=[15, 15], partition=orbits) # long time
Alternative embedding:
sage.graphs.generators.smallgraphs.HeawoodGraph()
Return a Heawood graph.
The Heawood graph is a cage graph that has 14 nodes. It is a cubic symmetric graph. (See also the Möbius-
Kantor graph, MobiusKantorGraph()). It is nonplanar and Hamiltonian. It has diameter 3, radius 3, girth 6,
and chromatic number 2. It is 4-transitive but not 5-transitive. See the Wikipedia article Heawood_graph.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By con-
vention, the nodes are positioned in a circular layout with the first node appearing at the top, and then continuing
counterclockwise.
EXAMPLES:
sage: H = graphs.HeawoodGraph()
sage: H
Heawood graph: Graph on 14 vertices
sage: H.graph6_string()
'MhEGHC@AI?_PC@_G_'
sage: (graphs.HeawoodGraph()).show() # long time
sage.graphs.generators.smallgraphs.HerschelGraph()
Return the Herschel graph.
For more information, see the Wikipedia article Herschel_graph.
EXAMPLES:
The Herschel graph is named after Alexander Stewart Herschel. It is a planar, bipartite graph with 11 vertices
and 18 edges:
sage: G = graphs.HerschelGraph(); G
Herschel graph: Graph on 11 vertices
sage: G.is_planar()
True
sage: G.is_bipartite()
True
sage: G.order()
11
sage: G.size()
18
The Herschel graph is a perfect graph with radius 3, diameter 4, and girth 4:
sage: G.is_perfect()
True
sage: G.radius()
3
sage: G.diameter()
4
sage: G.girth()
4
Its chromatic number is 2 and its automorphism group is isomorphic to the dihedral group 𝐷6 :
sage: G.chromatic_number()
2
sage: ag = G.automorphism_group()
sage: ag.is_isomorphic(DihedralGroup(6))
True
sage.graphs.generators.smallgraphs.HigmanSimsGraph(relabel=True)
Return the Higman-Sims graph.
The Higman-Sims graph is a remarkable strongly regular graph of degree 22 on 100 vertices. For example, it
can be split into two sets of 50 vertices each, so that each half induces a subgraph isomorphic to the Hoffman-
Singleton graph (HoffmanSingletonGraph()). This can be done in 352 ways (see Higman-Sims graph by
Andries E. Brouwer, accessed 24 October 2009.)
Its most famous property is that the automorphism group has an index 2 subgroup which is one of the 26 sporadic
groups [HS1968].
The construction used here follows [Haf2004].
See also the Wikipedia article Higman–Sims_graph.
INPUT:
• relabel – boolean (default: True); whether to relabel the vertices with consecutive integers. If False the
labels are strings that are three digits long. “xyz” means the vertex is in group 𝑥 (zero through three), pen-
tagon or pentagram 𝑦 (zero through four), and is vertex 𝑧 (zero through four) of that pentagon or pentagram.
See [Haf2004] for more.
OUTPUT:
The Higman-Sims graph.
EXAMPLES:
A split into the first 50 and last 50 vertices will induce two copies of the Hoffman-Singleton graph, and we
illustrate another such split, which is obvious based on the construction used:
sage: H = graphs.HigmanSimsGraph()
sage: A = H.subgraph(range(0,50))
sage: B = H.subgraph(range(50,100))
sage: K = graphs.HoffmanSingletonGraph()
sage: K.is_isomorphic(A) and K.is_isomorphic(B)
True
sage: C = H.subgraph(range(25,75))
sage: D = H.subgraph(list(range(0,25))+list(range(75,100)))
sage: K.is_isomorphic(C) and K.is_isomorphic(D)
True
The automorphism group contains only one nontrivial proper normal subgroup, which is of index 2 and is simple.
It is known as the Higman-Sims group:
sage: H = graphs.HigmanSimsGraph()
sage: G = H.automorphism_group()
sage: g=G.order(); g
88704000
sage: K = G.normal_subgroups()[1]
sage: K.is_simple()
True
sage: g//K.order()
2
AUTHOR:
• Rob Beezer (2009-10-24)
sage.graphs.generators.smallgraphs.HoffmanGraph()
Return the Hoffman Graph.
See the Wikipedia article Hoffman_graph.
EXAMPLES:
sage: g = graphs.HoffmanGraph()
sage: g.is_bipartite()
True
sage: g.is_hamiltonian() # long time
True
sage: g.radius()
3
sage: g.diameter()
4
sage: g.automorphism_group().cardinality()
48
sage.graphs.generators.smallgraphs.HoffmanSingletonGraph()
Return the Hoffman-Singleton graph.
The Hoffman-Singleton graph is the Moore graph of degree 7, diameter 2 and girth 5. The Hoffman-Singleton
theorem states that any Moore graph with girth 5 must have degree 2, 3, 7 or 57. The first three respectively are
the pentagon, the Petersen graph, and the Hoffman-Singleton graph. The existence of a Moore graph with girth
5 and degree 57 is still open.
A Moore graph is a graph with diameter 𝑑 and girth 2𝑑 + 1. This implies that the graph is regular, and distance
regular.
For more details, see [GR2001] and the Wikipedia article Hoffman–Singleton_graph.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. A novel
algorithm written by Tom Boothby gives a random layout which is pleasing to the eye.
EXAMPLES:
sage: HS = graphs.HoffmanSingletonGraph()
sage: Set(HS.degree())
{7}
sage: HS.girth()
5
sage: HS.diameter()
2
sage: HS.num_verts()
50
Note that you get a different layout each time you create the graph.
sage: HS.layout()[1] # random
(-0.844..., 0.535...)
sage: HS = graphs.HoffmanSingletonGraph()
sage: HS.layout()[1] # random
(-0.904..., 0.425...)
sage.graphs.generators.smallgraphs.HoltGraph()
Return the Holt graph (also called the Doyle graph).
See the Wikipedia article Holt_graph.
EXAMPLES:
sage: g = graphs.HoltGraph();g
Holt graph: Graph on 27 vertices
(continues on next page)
sage.graphs.generators.smallgraphs.HortonGraph()
Return the Horton Graph.
The Horton graph is a cubic 3-connected non-hamiltonian graph. For more information, see the Wikipedia article
Horton_graph.
EXAMPLES:
sage: g = graphs.HortonGraph()
sage: g.order()
96
sage: g.size()
144
sage: g.radius()
10
sage: g.diameter()
10
sage: g.girth()
6
sage: g.automorphism_group().cardinality()
96
sage: g.chromatic_number()
2
sage: g.is_hamiltonian() # not tested -- veeeery long
False
sage.graphs.generators.smallgraphs.IoninKharaghani765Graph()
Return a (765, 192, 48, 48)-strongly regular graph.
Existence of a strongly regular graph with these parameters was claimed in [IK2003]. Implementing the con-
struction in the latter did not work, however. This function implements the following instructions, shared by
Yury Ionin and Hadi Kharaghani.
Let 𝐴 be the affine plane over the field 𝐺𝐹 (3) = {−1, 0, 1}. Let
𝜑1 (𝑥, 𝑦) = 𝑥
𝜑2 (𝑥, 𝑦) = 𝑦
𝜑3 (𝑥, 𝑦) = 𝑥 + 𝑦
𝜑4 (𝑥, 𝑦) = 𝑥 − 𝑦
For 𝑖 = 1, 2, 3, 4 and 𝑗 ∈ 𝐺𝐹 (3), let 𝐿𝑖,𝑗 be the line in 𝐴 defined by 𝜑𝑖 (𝑥, 𝑦) = 𝑗. Let ℳ be the set
of all 12 lines 𝐿𝑖,𝑗 , plus the empty set. Let 𝜋 be the permutation defined on ℳ by 𝜋(𝐿𝑖,𝑗 ) = 𝐿𝑖,𝑗+1
and 𝜋(∅) = ∅, so that 𝜋 has three orbits of cardinality 3 and one of cardinality 1.
Let 𝐴 = (𝑝1 , ..., 𝑝9 ) with 𝑝1 = (−1, 1), 𝑝2 = (−1, 0), 𝑝3 = (−1, 1), 𝑝4 = (0, −1), 𝑝5 = (0, 0),
𝑝6 = (0, 1), 𝑝7 = (1, −1), 𝑝8 = (1, 0), 𝑝9 = (1, 1). Note that 𝑝𝑖 + 𝑝10−𝑖 = (0, 0). For any
subset 𝑋 of 𝐴, let 𝑀 (𝑋) be the (0, 1)-matrix of order 9 whose (𝑖, 𝑗)-entry equals 1 if and only if
𝑝10−𝑖 − 𝑝𝑗 ∈ 𝑋. Note that 𝑀 is a symmetric matrix.
An 𝑀 𝐹 -tuple is an ordered quintuple (𝑋1 , 𝑋2 , 𝑋3 , 𝑋4 , 𝑋5 ) of subsets of 𝐴, of which one is the
empty set and the other four are pairwise non-parallel lines. Such a quintuple generates the following
block matrix:
⎛ ⎞
𝑀 (𝑋1 ) 𝑀 (𝑋2 ) 𝑀 (𝑋3 ) 𝑀 (𝑋4 ) 𝑀 (𝑋5 )
⎜ 𝑀 (𝑋2 ) 𝑀 (𝑋3 ) 𝑀 (𝑋4 ) 𝑀 (𝑋5 ) 𝑀 (𝑋1 ) ⎟
⎜ ⎟
⎜ 𝑀 (𝑋3 ) 𝑀 (𝑋4 ) 𝑀 (𝑋5 ) 𝑀 (𝑋1 ) 𝑀 (𝑋2 ) ⎟
𝑁 (𝑋1 , 𝑋2 , 𝑋3 , 𝑋4 , 𝑋5 ) = ⎜ ⎟
⎝ 𝑀 (𝑋4 ) 𝑀 (𝑋5 ) 𝑀 (𝑋1 ) 𝑀 (𝑋2 ) 𝑀 (𝑋3 ) ⎠
𝑀 (𝑋5 ) 𝑀 (𝑋1 ) 𝑀 (𝑋2 ) 𝑀 (𝑋3 ) 𝑀 (𝑋4 )
𝜎(𝑋1 , 𝑋2 , 𝑋3 , 𝑋4 , 𝑋5 ) = (𝑋2 , 𝑋3 , 𝑋4 , 𝑋5 , 𝑋1 )
𝜋(𝑋1 , 𝑋2 , 𝑋3 , 𝑋4 , 𝑋5 ) = (𝜋(𝑋1 ), 𝜋(𝑋2 ), 𝜋(𝑋3 ), 𝜋(𝑋4 ), 𝜋(𝑋5 ))
Observe that 𝜎 and 𝜋 commute, and generate a (cyclic) group 𝐺 of order 15. We will from now
on identify 𝐺 with the (cyclic) multiplicative group of the field 𝐺𝐹 (16) equal to {𝜔 0 , ..., 𝜔 14 }. Let
𝑊 = [𝑤𝑖𝑗 ] be the following matrix of order 17 over 𝐺𝐹 (16) = {𝑎1 , ..., 𝑎1 6}:
⎪ 𝑎𝑖 + 𝑎𝑗 if 1 ≤ 𝑖 ≤ 16, 1 ≤ 𝑗 ≤ 16,
⎧
⎪
1 if 𝑖 = 17, 𝑗 ̸= 17,
⎨
𝑤𝑖𝑗 =
⎪ 1 if 𝑖 ̸= 17, 𝑗 = 17,
if 𝑖 = 𝑗 = 17
⎪
0
⎩
The diagonal entries of 𝑊 are equal to 0, each off-diagonal entry can be represented as 𝜔 𝑘 with
0 ≤ 𝑘 ≤ 14. Matrix 𝑊 is a symmetric 𝐵𝐺𝑊 (17, 16, 15; 𝐺).
Fix an 𝑀 𝐹 -tuple (𝑋1 , 𝑋2 , 𝑋3 , 𝑋4 , 𝑋5 ) and let 𝑆 be the block matrix obtained from 𝑊 by replacing
every diagonal entry of 𝑊 by the zero matrix of order 45, and every off-diagonal entry 𝜔 𝑘 by the
matrix 𝑁 (𝜎 𝑘 (𝑋1 , 𝑋2 , 𝑋3 , 𝑋4 , 𝑋5 )) (through the association of 𝜔 𝑘 with an element of 𝐺). Then 𝑆 is
a symmetric incidence matrix of a symmetric (765, 192, 48)-design with zero diagonal, and therefore
𝑆 is an adjacency matrix of a strongly regular graph with parameters (765, 192, 48, 48).
EXAMPLES:
sage: g = graphs.IoninKharaghani765Graph(); g
Ionin-Kharaghani: Graph on 765 vertices
Todo: An update to [IK2003] meant to fix the problem encountered became available 2016/02/24, see http:
//www.cs.uleth.ca/~hadi/research/IoninKharaghani.pdf
sage.graphs.generators.smallgraphs.JankoKharaghaniGraph(v)
Return a (936, 375, 150, 150)-srg or a (1800, 1029, 588, 588)-srg.
This functions returns a strongly regular graph for the two sets of parameters shown to be realizable in [JK2002].
The paper also uses a construction from [GM1987].
INPUT:
• v – integer; one of 936 or 1800
EXAMPLES:
sage.graphs.generators.smallgraphs.JankoKharaghaniTonchevGraph()
Return a (324, 153, 72, 72)-strongly regular graph from [JKT2001].
Build the graph using the description given in [JKT2001], taking sets B1 and B163 in the text as adjacencies of
vertices 1 and 163, respectively, and taking the edge orbits of the group 𝐺 provided.
EXAMPLES:
sage.graphs.generators.smallgraphs.KittellGraph()
Return the Kittell Graph.
For more information, see the Wolfram page about the Kittel Graph.
EXAMPLES:
sage: g = graphs.KittellGraph()
sage: g.order()
23
sage: g.size()
63
sage: g.radius()
3
sage: g.diameter()
4
sage: g.girth()
3
sage: g.chromatic_number()
4
sage.graphs.generators.smallgraphs.Klein3RegularGraph()
Return the Klein 3-regular graph.
The cubic Klein graph has 56 vertices and can be embedded on a surface of genus 3. It is the dual of
Klein7RegularGraph(). For more information, see the Wikipedia article Klein_graphs.
EXAMPLES:
sage: g = graphs.Klein3RegularGraph(); g
Klein 3-regular Graph: Graph on 56 vertices
sage: g.order(), g.size()
(56, 84)
sage: g.girth()
7
sage: g.automorphism_group().cardinality()
336
sage: g.chromatic_number()
3
sage.graphs.generators.smallgraphs.Klein7RegularGraph()
Return the Klein 7-regular graph.
The 7-valent Klein graph has 24 vertices and can be embedded on a surface of genus 3. It is the dual of
Klein3RegularGraph(). For more information, see the Wikipedia article Klein_graphs.
EXAMPLES:
sage: g = graphs.Klein7RegularGraph(); g
Klein 7-regular Graph: Graph on 24 vertices
sage: g.order(), g.size()
(24, 84)
sage: g.girth()
3
sage: g.automorphism_group().cardinality()
336
sage: g.chromatic_number()
4
sage.graphs.generators.smallgraphs.KrackhardtKiteGraph()
Return a Krackhardt kite graph with 10 nodes.
The Krackhardt kite graph was originally developed by David Krackhardt for the purpose of studying social
networks (see [Kre2002] and the Wikipedia article Krackhardt_kite_graph). It is used to show the distinction
between degree centrality, betweenness centrality, and closeness centrality. For more information read the plot-
ting section below in conjunction with the example.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the graph is drawn left to right, in top to bottom row sequence of [2, 3, 2, 1, 1, 1] nodes on each
row. This places the fourth node (3) in the center of the kite, with the highest degree. But the fourth node only
connects nodes that are otherwise connected, or those in its clique (i.e.: Degree Centrality). The eighth (7) node
is where the kite meets the tail. It has degree = 3, less than the average, but is the only connection between the
kite and tail (i.e.: Betweenness Centrality). The sixth and seventh nodes (5 and 6) are drawn in the third row and
have degree = 5. These nodes have the shortest path to all other nodes in the graph (i.e.: Closeness Centrality).
Please execute the example for visualization.
EXAMPLES:
Construct and show a Krackhardt kite graph
sage: g = graphs.KrackhardtKiteGraph()
sage: g.show() # long time
sage.graphs.generators.smallgraphs.LivingstoneGraph()
Return the Livingstone Graph.
The Livingstone graph is a distance-transitive graph on 266 vertices whose automorphism group is the J1 group.
For more information, see the Wikipedia article Livingstone_graph.
EXAMPLES:
sage.graphs.generators.smallgraphs.LjubljanaGraph(embedding=1)
Return the Ljubljana Graph.
The Ljubljana graph is a bipartite 3-regular graph on 112 vertices and 168 edges. It is not vertex-transitive as it
has two orbits which are also independent sets of size 56. See the Wikipedia article Ljubljana_graph.
The default embedding is obtained from the Heawood graph.
INPUT:
• embedding – integer (default: 1); two embeddings are available, and can be selected by setting embedding
to 1 or 2
EXAMPLES:
sage: g = graphs.LjubljanaGraph()
sage: g.order()
112
sage: g.size()
168
sage: g.girth()
10
sage: g.diameter()
8
sage: g.show(figsize=[10, 10]) # long time
sage: graphs.LjubljanaGraph(embedding=2).show(figsize=[10, 10]) # long time
sage.graphs.generators.smallgraphs.LocalMcLaughlinGraph()
Return the local McLaughlin graph.
The local McLaughlin graph is a strongly regular graph with parameters (162, 56, 10, 24). It can be obtained
from McLaughlinGraph() by considering the stabilizer of a point: one of its orbits has cardinality 162.
EXAMPLES:
sage.graphs.generators.smallgraphs.M22Graph()
Return the M22 graph.
The 𝑀22 graph is the unique strongly regular graph with parameters 𝑣 = 77, 𝑘 = 16, 𝜆 = 0, 𝜇 = 4.
For more information on the 𝑀22 graph, see https://www.win.tue.nl/~aeb/graphs/M22.html.
EXAMPLES:
sage: g = graphs.M22Graph()
sage: g.order()
77
sage: g.size()
616
sage: g.is_strongly_regular(parameters = True)
(77, 16, 0, 4)
sage.graphs.generators.smallgraphs.MarkstroemGraph()
Return the Markström Graph.
The Markström Graph is a cubic planar graph with no cycles of length 4 nor 8, but containing cycles of length
16. For more information, see the Wolfram page about the Markström Graph.
EXAMPLES:
sage: g = graphs.MarkstroemGraph()
sage: g.order()
24
sage: g.size()
36
sage: g.is_planar()
True
sage: g.is_regular(3)
True
sage: g.subgraph_search(graphs.CycleGraph(4)) is None
True
sage: g.subgraph_search(graphs.CycleGraph(8)) is None
True
sage: g.subgraph_search(graphs.CycleGraph(16))
Subgraph of (Markstroem Graph): Graph on 16 vertices
sage.graphs.generators.smallgraphs.MathonStronglyRegularGraph(t)
Return one of Mathon’s graphs on 784 vertices.
INPUT:
• t – integer; the number of the graph, from 0 to 2
EXAMPLES:
sage.graphs.generators.smallgraphs.McGeeGraph(embedding=2)
Return the McGee Graph.
See the Wikipedia article McGee_graph.
INPUT:
• embedding – integer (default: 2); two embeddings are available, and can be selected by setting embedding
to 1 or 2
EXAMPLES:
sage: g = graphs.McGeeGraph()
sage: g.order()
24
sage: g.size()
36
sage: g.girth()
7
sage: g.diameter()
4
sage: g.show()
sage: graphs.McGeeGraph(embedding=1).show() # long time
sage.graphs.generators.smallgraphs.McLaughlinGraph()
Return the McLaughlin Graph.
The McLaughlin Graph is the unique strongly regular graph of parameters (275, 112, 30, 56).
For more information on the McLaughlin Graph, see its web page on Andries Brouwer’s website which gives the
definition that this method implements.
Note: To create this graph you must have the gap_packages spkg installed.
EXAMPLES:
sage.graphs.generators.smallgraphs.MeredithGraph()
Return the Meredith Graph.
The Meredith Graph is a 4-regular 4-connected non-hamiltonian graph. For more information on the Meredith
Graph, see the Wikipedia article Meredith_graph.
EXAMPLES:
sage: g = graphs.MeredithGraph()
sage: g.is_regular(4)
(continues on next page)
sage.graphs.generators.smallgraphs.MoebiusKantorGraph()
Return a Möbius-Kantor Graph.
A Möbius-Kantor graph is a cubic symmetric graph. (See also the Heawood graph). It has 16 nodes and 24
edges. It is nonplanar and Hamiltonian. It has diameter 4, girth 6, and chromatic number 2. It is identical to the
Generalized Petersen graph, P[8, 3].
For more details, see Möbius-Kantor Graph - from Wolfram MathWorld.
PLOTTING: See the plotting section for the generalized Petersen graphs.
EXAMPLES:
sage: MK = graphs.MoebiusKantorGraph()
sage: MK
Moebius-Kantor Graph: Graph on 16 vertices
sage: MK.graph6_string()
'OhCGKE?O@?ACAC@I?Q_AS'
sage: (graphs.MoebiusKantorGraph()).show() # long time
sage.graphs.generators.smallgraphs.MoserSpindle()
Return the Moser spindle.
For more information, see the Wikipedia article Moser_spindle.
EXAMPLES:
The Moser spindle is a planar graph having 7 vertices and 11 edges:
sage: G = graphs.MoserSpindle(); G
Moser spindle: Graph on 7 vertices
sage: G.is_planar()
True
sage: G.order()
7
sage: G.size()
11
sage: G.is_hamiltonian()
True
sage: G.radius()
2
sage: G.diameter()
2
sage: G.girth()
3
The Moser spindle can be drawn in the plane as a unit distance graph, has chromatic number 4, and its automor-
phism group is isomorphic to the dihedral group 𝐷4 :
sage.graphs.generators.smallgraphs.NauruGraph(embedding=2)
Return the Nauru Graph.
See the Wikipedia article Nauru_graph.
INPUT:
• embedding – integer (default: 2); two embeddings are available, and can be selected by setting embedding
to 1 or 2
EXAMPLES:
sage: g = graphs.NauruGraph()
sage: g.order()
24
sage: g.size()
36
sage: g.girth()
6
sage: g.diameter()
4
sage: g.show()
sage: graphs.NauruGraph(embedding=1).show() # long time
sage.graphs.generators.smallgraphs.PappusGraph()
Return the Pappus graph, a graph on 18 vertices.
The Pappus graph is cubic, symmetric, and distance-regular.
EXAMPLES:
sage: G = graphs.PappusGraph()
sage: G.show() # long time
sage: L = graphs.LCFGraph(18, [5,7,-7,7,-7,-5], 3)
(continues on next page)
sage.graphs.generators.smallgraphs.PerkelGraph()
Return the Perkel Graph.
The Perkel Graph is a 6-regular graph with 57 vertices and 171 edges. It is the unique distance-regular graph
with intersection array (6, 5, 2; 1, 1, 3). For more information, see the Wikipedia article Perkel_graph or https:
//www.win.tue.nl/~aeb/graphs/Perkel.html.
EXAMPLES:
sage: g = graphs.PerkelGraph(); g
Perkel Graph: Graph on 57 vertices
sage: g.is_distance_regular(parameters=True)
([6, 5, 2, None], [None, 1, 1, 3])
sage.graphs.generators.smallgraphs.PetersenGraph()
Return the Petersen Graph.
The Petersen Graph is a named graph that consists of 10 vertices and 15 edges, usually drawn as a five-point star
embedded in a pentagon.
The Petersen Graph is a common counterexample. For example, it is not Hamiltonian.
PLOTTING: See the plotting section for the generalized Petersen graphs.
EXAMPLES: We compare below the Petersen graph with the default spring-layout versus a planned position
dictionary of (𝑥, 𝑦) tuples:
sage.graphs.generators.smallgraphs.PoussinGraph()
Return the Poussin Graph.
For more information on the Poussin Graph, see its corresponding Wolfram page.
EXAMPLES:
sage: g = graphs.PoussinGraph()
sage: g.order()
15
sage: g.is_planar()
True
sage.graphs.generators.smallgraphs.RobertsonGraph()
Return the Robertson graph.
See the Wikipedia article Robertson_graph.
EXAMPLES:
sage: g = graphs.RobertsonGraph()
sage: g.order()
19
sage: g.size()
38
sage: g.diameter()
3
sage: g.girth()
5
sage: g.charpoly().factor()
(x - 4) * (x - 1)^2 * (x^2 + x - 5) * (x^2 + x - 1) * (x^2 - 3)^2 * (x^2 + x - 4)^2␣
˓→* (x^2 + x - 3)^2
sage: g.chromatic_number()
3
sage: g.is_hamiltonian()
True
sage: g.is_vertex_transitive()
False
sage.graphs.generators.smallgraphs.SchlaefliGraph()
Return the Schläfli graph.
The Schläfli graph is the only strongly regular graphs of parameters (27, 16, 10, 8) (see [GR2001]).
For more information, see the Wikipedia article Schläfli_graph.
See also:
Graph.is_strongly_regular() – tests whether a graph is strongly regular and/or returns its parameters.
EXAMPLES:
Checking that the method actually returns the Schläfli graph:
sage: S = graphs.SchlaefliGraph()
sage: S.is_strongly_regular(parameters = True)
(27, 16, 10, 8)
sage: S.is_vertex_transitive()
True
The neighborhood of each vertex is isomorphic to the complement of the Clebsch graph:
sage.graphs.generators.smallgraphs.ShrikhandeGraph()
Return the Shrikhande graph.
For more information, see the MathWorld article on the Shrikhande graph or the Wikipedia article
Shrikhande_graph.
See also:
Graph.is_strongly_regular() – tests whether a graph is strongly regular and/or returns its parameters.
EXAMPLES:
The Shrikhande graph was defined by S. S. Shrikhande in 1959. It has 16 vertices and 48 edges, and is strongly
regular of degree 6 with parameters (2, 2):
sage: G = graphs.ShrikhandeGraph(); G
Shrikhande graph: Graph on 16 vertices
sage: G.order()
16
sage: G.size()
48
sage: G.is_regular(6)
True
sage: set([ len([x for x in G.neighbors(i) if x in G.neighbors(j)])
....: for i in range(G.order())
....: for j in range(i) ])
{2}
sage: G.is_planar()
False
sage: G.is_hamiltonian()
True
sage: G.is_eulerian()
True
sage: G.radius()
2
sage: G.diameter()
2
sage: G.girth()
3
sage: G.chromatic_number()
4
sage: G.automorphism_group().cardinality()
192
sage: G.characteristic_polynomial().factor()
(x - 6) * (x - 2)^6 * (x + 2)^9
It is a toroidal graph, and its embedding on a torus is dual to an embedding of the Dyck graph (DyckGraph).
sage.graphs.generators.smallgraphs.SimsGewirtzGraph()
Return the Sims-Gewirtz Graph.
This graph is obtained from the Higman Sims graph by considering the graph induced by the vertices at distance
two from the vertices of an (any) edge. It is the only strongly regular graph with parameters 𝑣 = 56, 𝑘 = 10,
𝜆 = 0, 𝜇 = 2
For more information on the Sylvester graph, see https://www.win.tue.nl/~aeb/graphs/Sims-Gewirtz.html or its
Wikipedia article Gewirtz_graph.
See also:
• HigmanSimsGraph().
EXAMPLES:
sage: g = graphs.SimsGewirtzGraph(); g
Sims-Gewirtz Graph: Graph on 56 vertices
sage: g.order()
56
sage: g.size()
280
sage: g.is_strongly_regular(parameters = True)
(56, 10, 0, 2)
sage.graphs.generators.smallgraphs.SousselierGraph()
Return the Sousselier Graph.
The Sousselier graph is a hypohamiltonian graph on 16 vertices and 27 edges. For more information, see
Wikipedia article Sousselier_graph or the corresponding French Wikipedia page.
EXAMPLES:
sage: g = graphs.SousselierGraph()
sage: g.order()
16
sage: g.size()
27
sage: g.radius()
2
sage: g.diameter()
3
sage: g.automorphism_group().cardinality()
2
sage: g.is_hamiltonian()
False
sage: g.delete_vertex(g.random_vertex())
sage: g.is_hamiltonian()
True
sage.graphs.generators.smallgraphs.SuzukiGraph()
Return the Suzuki Graph.
The Suzuki graph has 1782 vertices, and is strongly regular with parameters (1782, 416, 100, 96). Known as
S.15 in [Hub1975].
Note: It takes approximately 50 seconds to build this graph. Do not be too impatient.
EXAMPLES:
sage.graphs.generators.smallgraphs.SylvesterGraph()
Return the Sylvester Graph.
This graph is obtained from the Hoffman Singleton graph by considering the graph induced by the vertices at
distance two from the vertices of an (any) edge.
For more information on the Sylvester graph, see https://www.win.tue.nl/~aeb/graphs/Sylvester.html.
See also:
• HoffmanSingletonGraph().
EXAMPLES:
sage: g = graphs.SylvesterGraph(); g
Sylvester Graph: Graph on 36 vertices
sage: g.order()
36
sage: g.size()
90
sage: g.is_regular(k=5)
True
sage.graphs.generators.smallgraphs.SzekeresSnarkGraph()
Return the Szekeres Snark Graph.
The Szekeres graph is a snark with 50 vertices and 75 edges. For more information on this graph, see the
Wikipedia article Szekeres_snark.
EXAMPLES:
sage: g = graphs.SzekeresSnarkGraph()
sage: g.order()
50
sage: g.size()
75
sage: g.chromatic_number()
3
sage.graphs.generators.smallgraphs.ThomsenGraph()
Return the Thomsen Graph.
The Thomsen Graph is actually a complete bipartite graph with (𝑛1, 𝑛2) = (3, 3). It is also called the Utility
graph.
PLOTTING: See CompleteBipartiteGraph.
EXAMPLES:
sage: T = graphs.ThomsenGraph()
sage: T
Thomsen graph: Graph on 6 vertices
(continues on next page)
sage.graphs.generators.smallgraphs.TietzeGraph()
Return the Tietze Graph.
For more information on the Tietze Graph, see the Wikipedia article Tietze%27s_graph.
EXAMPLES:
sage: g = graphs.TietzeGraph()
sage: g.order()
12
sage: g.size()
18
sage: g.diameter()
3
sage: g.girth()
3
sage: g.automorphism_group().cardinality()
12
sage: g.automorphism_group().is_isomorphic(groups.permutation.Dihedral(6))
True
sage.graphs.generators.smallgraphs.TruncatedIcosidodecahedralGraph()
Return the truncated icosidodecahedron.
The truncated icosidodecahedron is an Archimedean solid with 30 square faces, 20 regular hexagonal faces, 12
regular decagonal faces, 120 vertices and 180 edges. For more information, see the Wikipedia article Trun-
cated_icosidodecahedron.
EXAMPLES:
Unfortunately, this graph can not be constructed currently, due to numerical issues:
sage: g = graphs.TruncatedIcosidodecahedralGraph(); g
Traceback (most recent call last):
...
ValueError: *Error: Numerical inconsistency is found. Use the GMP exact arithmetic.
sage: g.order(), g.size() # not tested
(120, 180)
sage.graphs.generators.smallgraphs.TruncatedTetrahedralGraph()
Return the truncated tetrahedron.
The truncated tetrahedron is an Archimedean solid with 12 vertices and 18 edges. For more information, see the
Wikipedia article Truncated_tetrahedron.
EXAMPLES:
sage: g = graphs.TruncatedTetrahedralGraph(); g
Truncated Tetrahedron: Graph on 12 vertices
sage: g.order(), g.size()
(12, 18)
(continues on next page)
sage.graphs.generators.smallgraphs.Tutte12Cage()
Return the Tutte 12-Cage.
See the Wikipedia article Tutte_12-cage.
EXAMPLES:
sage: g = graphs.Tutte12Cage()
sage: g.order()
126
sage: g.size()
189
sage: g.girth()
12
sage: g.diameter()
6
sage: g.show()
sage.graphs.generators.smallgraphs.TutteCoxeterGraph(embedding=2)
Return the Tutte-Coxeter graph.
See the Wikipedia article Tutte-Coxeter_graph.
INPUT:
• embedding – integer (default: 2); two embeddings are available, and can be selected by setting embedding
to 1 or 2
EXAMPLES:
sage: g = graphs.TutteCoxeterGraph()
sage: g.order()
30
sage: g.size()
45
sage: g.girth()
8
sage: g.diameter()
4
sage: g.show()
sage: graphs.TutteCoxeterGraph(embedding=1).show() # long time
sage.graphs.generators.smallgraphs.TutteGraph()
Return the Tutte Graph.
The Tutte graph is a 3-regular, 3-connected, and planar non-hamiltonian graph. For more information on the
Tutte Graph, see the Wikipedia article Tutte_graph.
EXAMPLES:
sage: g = graphs.TutteGraph()
sage: g.order()
46
(continues on next page)
sage.graphs.generators.smallgraphs.U42Graph216()
Return a (216,40,4,8)-strongly regular graph from [CRS2016].
Build the graph, interpreting the 𝑈4 (2)-action considered in [CRS2016] as the one on the hyperbolic lines of the
corresponding unitary polar space, and then doing the unique merging of the orbitals leading to a graph with the
parameters in question.
EXAMPLES:
sage.graphs.generators.smallgraphs.U42Graph540()
Return a (540,187,58,68)-strongly regular graph from [CRS2016].
Build the graph, interpreting the 𝑈4 (2)-action considered in [CRS2016] as the action of 𝑈4 (2) = 𝑆𝑝4 (3) <
𝑈4 (3) on the nonsingular, w.r.t. to the Hermitean form stabilised by 𝑈4 (3), points of the 3-dimensional projective
space over 𝐺𝐹 (9). There are several possible mergings of orbitals, some leading to non-isomorphic graphs with
the same parameters. We found the merging here using [FK1991].
EXAMPLES:
sage.graphs.generators.smallgraphs.WagnerGraph()
Return the Wagner Graph.
See the Wikipedia article Wagner_graph.
EXAMPLES:
sage: g = graphs.WagnerGraph()
sage: g.order()
8
sage: g.size()
12
sage: g.girth()
4
sage: g.diameter()
(continues on next page)
sage.graphs.generators.smallgraphs.WatkinsSnarkGraph()
Return the Watkins Snark Graph.
The Watkins Graph is a snark with 50 vertices and 75 edges. For more information, see the Wikipedia article
Watkins_snark.
EXAMPLES:
sage: g = graphs.WatkinsSnarkGraph()
sage: g.order()
50
sage: g.size()
75
sage: g.chromatic_number()
3
sage.graphs.generators.smallgraphs.WellsGraph()
Return the Wells graph.
For more information on the Wells graph (also called Armanios-Wells graph), see this page.
The implementation follows the construction given on page 266 of [BCN1989]. This requires to create inter-
mediate graphs and run a small isomorphism test, while everything could be replaced by a pre-computed list of
edges. I believe that it is better to keep “the recipe” in the code, however, as it is quite unlikely that this could
become the most time-consuming operation in any sensible algorithm, and . . . . “preserves knowledge”, which is
what open-source software is meant to do.
EXAMPLES:
sage: g = graphs.WellsGraph(); g
Wells graph: Graph on 32 vertices
sage: g.order()
32
sage: g.size()
80
sage: g.girth()
5
sage: g.diameter()
4
sage: g.chromatic_number()
4
sage: g.is_regular(k=5)
True
sage.graphs.generators.smallgraphs.WienerArayaGraph()
Return the Wiener-Araya Graph.
The Wiener-Araya Graph is a planar hypohamiltonian graph on 42 vertices and 67 edges. For more information,
see the Wolfram Page on the Wiener-Araya Graph or Wikipedia article Wiener-Araya_graph.
EXAMPLES:
sage: g = graphs.WienerArayaGraph()
sage: g.order()
42
sage: g.size()
67
sage: g.girth()
4
sage: g.is_planar()
True
sage: g.is_hamiltonian() # not tested -- around 30s long
False
sage: g.delete_vertex(g.random_vertex())
sage: g.is_hamiltonian()
True
sage.graphs.generators.world_map.EuropeMap(continental=False, year=2018)
Return European states as a graph of common border.
“European state” here is defined as an independent state having the capital city in Europe. The graph has an edge
between those countries that have common land border.
INPUT:
• continental – boolean (default: False); whether to only return states in the continental Europe or all
European states
sage.graphs.generators.world_map.USAMap(continental=False)
Return states of USA as a graph of common border.
The graph has an edge between those states that have common land border line or point. Hence for example
Colorado and Arizona are marked as neighbors, but Michigan and Minnesota are not.
INPUT:
• continental – boolean (default: False); whether to exclude Alaska and Hawaii
EXAMPLES:
How many states are neighbor’s neighbor for Pennsylvania:
sage.graphs.generators.world_map.WorldMap()
Return the Graph of all the countries, in which two countries are adjacent in the graph if they have a common
boundary.
This graph has been built from the data available in The CIA World Factbook [CIA] (2009-08-21).
The returned graph G has a member G.gps_coordinates equal to a dictionary containing the GPS coordinates
of each country’s capital city.
EXAMPLES:
sage: g = graphs.WorldMap()
sage: g.has_edge("France", "Italy")
True
sage: g.gps_coordinates["Bolivia"]
[[17, 'S'], [65, 'W']]
sage: sorted(g.connected_component_containing_vertex('Ireland'))
['Ireland', 'United Kingdom']
Presently, it is possible to use this database through the variables and methods present in the graph_classes object.
For instance:
Inclusions
It is then possible to check the inclusion of classes inside of others, if the information is available in the database:
Descriptions
Given a graph class, one can obtain its associated information in the ISGCI database with the description() method:
sage: Chordal.description()
Class of graphs : Chordal
-------------------------
id : gc_32
name : chordal
...
Problems :
-----------
3-Colourability : Linear
Clique : Polynomial
(continues on next page)
2.16. ISGCI: Information System on Graph Classes and their Inclusions 823
Graph Theory, Release 9.7
It is possible to obtain the complete list of the classes stored in ISGCI by calling the show_all() method (beware –
long output):
sage: graph_classes.show_all()
id | name | type | smallgraph
-----------------------------------------------------------------------------------------
˓→-----------------------------
Until a proper search method is implemented, this lets one find classes which do not appear in graph_classes.*.
To retrieve a class of graph from its ISGCI ID one may use the get_class() method:
sage: GC = graph_classes.get_class("gc_5")
sage: GC
$P_4$--bipartite graphs
Recognition of graphs
The graph classes represented by the ISGCI database can alternatively be used to access recognition algorithms. For
instance, in order to check that a given graph is a tree one has the following the options
or:
sage: graphs.PathGraph(5).is_tree()
True
Furthermore, all ISGCI graph classes which are defined by the exclusion of a finite sequence of induced subgraphs
benefit from a generic recognition algorithm. For instance
sage: g = graphs.PetersenGraph()
sage: g in graph_classes.ClawFree
False
sage: g.line_graph() in graph_classes.ClawFree
True
sage: gc = graph_classes.get_class("gc_441")
sage: gc
diamond--free graphs
sage: graphs.PetersenGraph() in gc
True
2.16. ISGCI: Information System on Graph Classes and their Inclusions 825
Graph Theory, Release 9.7
The class inclusion digraph: Sage remembers the class inclusions through the inclusion digraph (see
inclusion_digraph()). Its nodes are ID of ISGCI classes:
sage: d = graph_classes.inclusion_digraph()
sage: d.vertices(sort=True)[-10:]
['gc_990', 'gc_991', 'gc_992', 'gc_993', 'gc_994', 'gc_995', 'gc_996', 'gc_997', 'gc_998
˓→', 'gc_999']
An arc from gc1 to gc2 means that gc1 is a superclass of gc2. This being said, not all edges are stored ! To ensure
that a given class is included in another one, we have to check whether there is in the digraph a path from the first one
to the other:
Hence bipartite graphs are perfect graphs. We can see how ISGCI obtains this result
What ISGCI knows is that perfect graphs contain unimodular graph which contain bipartite graphs. Therefore bipartite
graphs are perfect !
Note: The inclusion digraph is NOT ACYCLIC. Indeed, several entries exist in the ISGCI database which represent
the same graph class, for instance Perfect graphs and Berge graphs:
sage: graph_classes.inclusion_digraph().is_directed_acyclic()
False
sage: Berge = graph_classes.get_class("gc_274"); Berge
(continues on next page)
• The database is loaded not so large, but it is still preferable to only load it on demand. This is achieved through
the cached methods classes() and inclusion_digraph().
• Upon the first access to the database, the information is extracted from the XML file and stored in the cache of
three methods:
– sage.graphs.isgci._classes (dictionary)
– sage.graphs.isgci._inclusions (list of dictionaries)
– sage.graphs.isgci._inclusion_digraph (DiGraph)
Note that the digraph is only built if necessary (for instance if the user tries to compare two classes).
2.16. ISGCI: Information System on Graph Classes and their Inclusions 827
Graph Theory, Release 9.7
2.16.5 AUTHORS:
2.16.6 Methods
description()
Print the information of ISGCI about the current class.
EXAMPLES:
sage: graph_classes.Chordal.description()
Class of graphs : Chordal
-------------------------
id : gc_32
name : chordal
...
Problems :
-----------
3-Colourability : Linear
Clique : Polynomial
Clique cover : Polynomial
...
Recognition : Linear
...
forbidden_subgraphs()
Return the list of forbidden induced subgraphs defining the class.
If the graph class is not defined by a finite list of forbidden induced subgraphs, None is returned instead.
EXAMPLES:
sage: graph_classes.Perfect.forbidden_subgraphs()
sage: gc = graph_classes.get_class('gc_62')
sage: gc
claw--free graphs
(continues on next page)
class sage.graphs.isgci.GraphClasses
Bases: sage.structure.unique_representation.UniqueRepresentation
classes()
Return the graph classes, as a dictionary.
Upon the first call, this loads the database from the local XML file. Subsequent calls are cached.
EXAMPLES:
sage: t = graph_classes.classes()
sage: type(t)
<... 'dict'>
sage: sorted(t["gc_151"].keys())
['id', 'name',... 'problem',... 'type']
sage: t["gc_151"]['name']
'cograph'
sage: t["gc_151"]['problem']['Clique']
{'complexity': 'Linear'}
get_class(id)
Return the class corresponding to the given id in the ISGCI database.
INPUT:
• id (string) – the desired class’ ID
See also:
show_all()
EXAMPLES:
With an existing id:
sage: graph_classes.get_class(-1)
Traceback (most recent call last):
...
ValueError: The given class id does not exist in the ISGCI database. Is the db␣
˓→too old ? You can update it with graph_classes.update_db().
inclusion_digraph()
Return the class inclusion digraph.
Upon the first call, this loads the database from the local XML file. Subsequent calls are cached.
EXAMPLES:
2.16. ISGCI: Information System on Graph Classes and their Inclusions 829
Graph Theory, Release 9.7
sage: g = graph_classes.inclusion_digraph(); g
Digraph on ... vertices
inclusions()
Return the graph class inclusions.
OUTPUT:
a list of dictionaries
Upon the first call, this loads the database from the local XML file. Subsequent calls are cached.
EXAMPLES:
sage: t = graph_classes.inclusions()
sage: type(t)
<... 'list'>
sage: t[0]
{'sub': 'gc_1', 'super': 'gc_2'}
show_all()
Prints all graph classes stored in ISGCI
EXAMPLES:
sage: graph_classes.show_all()
id | name | type |␣
˓→smallgraph
--------------------------------------------------------------------------------
˓→--------------------------------------
smallgraphs()
Return a dictionary associating a graph to a graph description string.
Upon the first call, this loads the database from the local XML files. Subsequent calls are cached.
EXAMPLES:
sage: t = graph_classes.smallgraphs()
sage: t['2C_4']
Graph on 8 vertices
sage: t['2K_3 + e']
Graph on 6 vertices
sage: t['fish']
Graph on 6 vertices
sage: t['bull']
Graph on 5 vertices
update_db()
Updates the ISGCI database by downloading the latest version from internet.
This method downloads the ISGCI database from the website GraphClasses.org. It then extracts the zip file
and parses its XML content.
Depending on the credentials of the user running Sage when this command is run, one attempt is made at
saving the result in Sage’s directory so that all users can benefit from it. If the credentials are not sufficient,
the XML file are saved instead in the user’s directory (in the SAGE_DB folder).
EXAMPLES:
2.16. ISGCI: Information System on Graph Classes and their Inclusions 831
Graph Theory, Release 9.7
THREE
LOW-LEVEL IMPLEMENTATION
This module contains no code, and describes Sage’s data structures for graphs and digraphs. They can be used directly
at Cython/C level, or through the Graph and DiGraph classes (except one)
833
Graph Theory, Release 9.7
The Graph and DiGraph objects delegate the storage of vertices and edges to other objects: the graph backends:
sage: Graph()._backend
<sage.graphs.base.sparse_graph.SparseGraphBackend object at ...>
A (di)graph backend is a simpler (di)graph class having only the most elementary methods (e.g.: add/remove ver-
tices/edges). Its vertices can be arbitrary hashable objects.
The only backend available in Sage is CGraphBackend.
CGraphBackend is the backend of all native data structures that can be used by Graph and DiGraph . It is extended
by:
• DenseGraphBackend
• SparseGraphBackend
• StaticSparseBackend
While a CGraphBackend deals with arbitrary (hashable) vertices, it contains a ._cg attribute of type CGraph which
only deals with integer vertices.
The CGraph data structures available in Sage are:
• DenseGraph
• SparseGraph
• StaticSparseCGraph
See the c_graph module for more information.
This is a Cython implementation of the base class for sparse and dense graphs in Sage. It is not intended for use on its
own. Specific graph types should extend this base class and implement missing functionalities. Whenever possible,
specific methods should also be overridden with implementations that suit the graph type under consideration.
For an overview of graph data structures in sage, see overview.
The bitset active_vertices is a list of all available vertices for use, but only the ones which are set are considered
to actually be in the graph. The variables num_verts and num_arcs are self-explanatory. Note that num_verts is the
number of bits set in active_vertices, not the full length of the bitset. The arrays in_degrees and out_degrees
are of the same length as the bitset.
For more information about active vertices, see the documentation for the method realloc.
class sage.graphs.base.c_graph.CGraph
Bases: object
Compiled sparse and dense graphs.
add_arc(u, v)
Add arc (u, v) to the graph.
INPUT:
• u, v – non-negative integers, must be in self
EXAMPLES:
On the CGraph level, this always produces an error, as there are no vertices:
add_vertex(k=- 1)
Adds vertex k to the graph.
INPUT:
• k – nonnegative integer or -1 (default: -1); if 𝑘 = −1, a new vertex is added and the integer used is
returned. That is, for 𝑘 = −1, this function will find the first available vertex that is not in self and
add that vertex to this graph.
OUTPUT:
• -1 – indicates that no vertex was added because the current allocation is already full or the vertex is
out of range.
• nonnegative integer – this vertex is now guaranteed to be in the graph.
See also:
• add_vertex_unsafe – add a vertex to a graph. This method is potentially unsafe. You should instead
use add_vertex().
• add_vertices – add a bunch of vertices to a graph
EXAMPLES:
Adding vertices to a sparse graph:
add_vertices(verts)
Add vertices from the iterable verts.
INPUT:
• verts – an iterable of vertices; value -1 has a special meaning – for each such value an unused vertex
name is found, used to create a new vertex and returned.
OUTPUT:
List of generated labels if there is any -1 in verts. None otherwise.
See also:
EXAMPLES:
Adding vertices for sparse graphs:
sage: from sage.graphs.base.sparse_graph import SparseGraph
sage: S = SparseGraph(nverts=4, extra_vertices=4)
sage: S.verts()
[0, 1, 2, 3]
sage: S.add_vertices([3, -1, 4, 9])
[5]
sage: S.verts()
[0, 1, 2, 3, 4, 5, 9]
sage: S.realloc(20)
sage: S.verts()
[0, 1, 2, 3, 4, 5, 9]
all_arcs(u, v)
Gives the labels of all arcs (u, v). An unlabeled arc is interpreted as having label 0.
EXAMPLES:
arc_label(u, v)
Retrieves the first label found associated with (u, v).
INPUT:
• u, v – non-negative integers, must be in self
OUTPUT: one of
• positive integer – indicates that there is a label on (u, v).
• 0 – either the arc (u, v) is unlabeled, or there is no arc at all.
EXAMPLES:
sage: G.add_arc_label(1,0)
sage: G.arc_label(1,0)
0
sage: G.arc_label(1,1)
0
sage: G.add_arc_label(1,2,1)
sage: G.add_arc_label(1,2,2)
sage: G.arc_label(1,2)
2
check_vertex(n)
Check that n is a vertex of self.
This method is different from has_vertex(). The current method raises an error if n is not a vertex of
this graph. On the other hand, has_vertex() returns a boolean to signify whether or not n is a vertex of
this graph.
INPUT:
• n – a nonnegative integer representing a vertex
OUTPUT:
• Raise an error if n is not a vertex of this graph
See also:
EXAMPLES:
current_allocation()
Report the number of vertices allocated.
OUTPUT:
• The number of vertices allocated. This number is usually different from the order of a graph. We may
have allocated enough memory for a graph to hold 𝑛 > 0 vertices, but the order (actual number of
vertices) of the graph could be less than 𝑛.
EXAMPLES:
The actual number of vertices in a graph might be less than the number of vertices allocated for the graph:
del_all_arcs(u, v)
Delete all arcs from u to v.
INPUT:
• u – integer; the tail of an arc.
• v – integer; the head of an arc.
EXAMPLES:
On the CGraph level, this always produces an error, as there are no vertices:
del_arc_label(u, v, l)
Delete an arc (u, v) with label l.
INPUT:
• u, v – non-negative integers, must be in self
• l – a positive integer label, or zero for no label
EXAMPLES:
del_vertex(v)
Delete the vertex v, along with all edges incident to it.
If v is not in self, fails silently.
INPUT:
• v – a nonnegative integer representing a vertex
See also:
• del_vertex_unsafe – delete a vertex from a graph. This method is potentially unsafe. Use
del_vertex() instead.
EXAMPLES:
Deleting vertices of sparse graphs:
has_arc(u, v)
Check if the arc (u, v) is in this graph.
INPUT:
• u – integer; the tail of an arc
• v – integer; the head of an arc
OUTPUT:
• Print a Not Implemented! message. This method is not implemented at the CGraph level. A child
class should provide a suitable implementation.
EXAMPLES:
On the CGraph this always returns False:
has_arc_label(u, v, l)
Indicates whether there is an arc (u, v) with label l.
INPUT:
• u, v – non-negative integers, must be in self
• l – a positive integer label, or zero for no label
EXAMPLES:
has_vertex(n)
Determine whether the vertex n is in self.
This method is different from check_vertex(). The current method returns a boolean to signify whether
or not n is a vertex of this graph. On the other hand, check_vertex() raises an error if n is not a vertex
of this graph.
INPUT:
• n – a nonnegative integer representing a vertex
OUTPUT:
• True if n is a vertex of this graph; False otherwise.
See also:
• check_vertex() – raise an error if this graph does not contain a specific vertex.
EXAMPLES:
Upon initialization, a SparseGraph or DenseGraph has the first nverts vertices:
in_neighbors(v)
Return the list of in-neighbors of the vertex v.
INPUT:
• v – integer representing a vertex of this graph
OUTPUT:
• Raise NotImplementedError. This method is not implemented at the CGraph level. A child class
should provide a suitable implementation.
Note: Due to the implementation of SparseGraph, this method is much more expensive than
out_neighbors_unsafe for SparseGraph’s.
EXAMPLES:
On the CGraph level, this always produces an error, as there are no vertices:
out_neighbors(u)
Return the list of out-neighbors of the vertex u.
INPUT:
• u – integer representing a vertex of this graph
EXAMPLES:
On the CGraph level, this always produces an error, as there are no vertices:
realloc(total)
Reallocate the number of vertices to use, without actually adding any.
INPUT:
• total – integer; the total size to make the array of vertices
OUTPUT:
• Raise a NotImplementedError. This method is not implemented in this base class. A child class
should provide a suitable implementation.
See also:
EXAMPLES:
First, note that realloc() is implemented for SparseGraph and DenseGraph differently, and is not
implemented at the CGraph level:
verts()
Return a list of the vertices in self.
OUTPUT:
class sage.graphs.base.c_graph.CGraphBackend
Bases: sage.graphs.base.graph_backends.GenericGraphBackend
Base class for sparse and dense graph backends.
This class is extended by SparseGraphBackend and DenseGraphBackend, which are fully functional back-
ends. This class is mainly just for vertex functions, which are the same for both. A CGraphBackend will not
work on its own:
sage: G = Graph(30)
sage: G.add_edges([(0,1), (0,3), (4,5), (9, 23)])
sage: G.edges(sort=True, labels=False)
[(0, 1), (0, 3), (4, 5), (9, 23)]
This class handles the labels of vertices and edges. For vertices it uses two dictionaries vertex_labels and
vertex_ints. They are just opposite of each other: vertex_ints makes a translation from label to integers
(that are internally used) and vertex_labels make the translation from internally used integers to actual labels.
This class tries hard to avoid translation if possible. This will work only if the graph is built on integers from 0
to 𝑛 − 1 and the vertices are basically added in increasing order.
See also:
add_edge(u, v, l, directed)
Add the edge (u,v) to self.
INPUT:
• u,v – the vertices of the edge
• l – the edge label
• directed – if False, also add (v,u)
Note: The input l is ignored if the backend does not support labels.
EXAMPLES:
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
sage: D.add_edge(0,1,None,False)
sage: list(D.iterator_edges(range(9), True))
[(0, 1, None)]
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
sage: D.add_edge(0, 1, None, False)
sage: list(D.iterator_edges(range(9), True))
[(0, 1, None)]
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
sage: D.add_edges([(0,1), (2,3), (4,5), (5,6)], False)
sage: list(D.iterator_edges(range(9), True))
[(0, 1, None),
(2, 3, None),
(4, 5, None),
(5, 6, None)]
add_vertex(name)
Add a vertex to self.
INPUT:
• name – the vertex to be added (must be hashable). If None, a new name is created.
OUTPUT:
• If name = None, the new vertex name is returned. None otherwise.
See also:
EXAMPLES:
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
sage: D.add_vertex(10)
sage: D.add_vertex([])
Traceback (most recent call last):
...
TypeError: unhashable type: 'list'
sage: S = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
sage: S.add_vertex(10)
sage: S.add_vertex([])
Traceback (most recent call last):
...
TypeError: unhashable type: 'list'
add_vertices(vertices)
Add vertices to self.
INPUT:
• vertices – iterator of vertex labels; a new name is created, used and returned in the output list for all
None values in vertices
OUTPUT:
Generated names of new vertices if there is at least one None value present in vertices. None otherwise.
See also:
EXAMPLES:
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(1)
sage: D.add_vertices([1, 2, 3])
sage: D.add_vertices([None] * 4)
[4, 5, 6, 7]
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(0)
sage: G.add_vertices([0, 1])
sage: list(G.iterator_verts(None))
[0, 1]
sage: list(G.iterator_edges([0, 1], True))
[]
sage: G = Graph(graphs.PetersenGraph())
sage: for (u, v) in G.edges(sort=True, labels=None):
....: G.set_edge_label(u, v, 1)
sage: G.shortest_path(0, 1, by_weight=True)
[0, 1]
sage: G.shortest_path_length(0, 1, by_weight=True)
1
sage: G = DiGraph([(1, 2, {'weight':1}), (1, 3, {'weight':5}), (2, 3, {'weight
˓→':1})])
• weight_function – function (default: None); a function that inputs an edge (u, v, l) and outputs
its weight. If None, we use the edge label l as a weight, if l is not None, else 1 as a weight.
• distance_flag – boolean (default: False); when set to True, the shortest path distance from x to y
is returned instead of the path.
• reduced_weight – dictionary (default: None); a dictionary that takes as input an edge (u, v) and
outputs its reduced weight.
OUTPUT:
• A list of vertices in the shortest path from x to y or distance from x to y is returned depending upon
the value of parameter distance_flag
EXAMPLES:
sage: G = Graph([(1, 2, 20), (2, 3, 10), (3, 4, 30), (1, 5, 20), (5, 6, 10), (6,
˓→ 4, 50), (4, 7, 5)])
[1, 2, 3, 4]
sage: G._backend.bidirectional_dijkstra_special(1, 4, weight_function=lambda␣
˓→e:e[2], exclude_vertices=[2], exclude_edges=[(3, 4)])
[1, 5, 6, 4]
sage: G._backend.bidirectional_dijkstra_special(1, 4, weight_function=lambda␣
˓→e:e[2], exclude_vertices=[2, 7])
[1, 5, 6, 4]
sage: G._backend.bidirectional_dijkstra_special(1, 4, weight_function=lambda␣
˓→e:e[2], exclude_edges=[(5, 6)])
[1, 2, 3, 4]
sage: G._backend.bidirectional_dijkstra_special(1, 4, weight_function=lambda␣
˓→e:e[2], include_vertices=[1, 5, 6, 4])
[1, 5, 6, 4]
See also:
EXAMPLES:
Breadth-first search of the Petersen graph starting at vertex 0:
sage: G = Graph(graphs.PetersenGraph())
sage: list(G.breadth_first_search(0))
[0, 1, 4, 5, 2, 6, 3, 9, 7, 8]
sage: G = graphs.EuropeMap(continental=True)
sage: list(G.breadth_first_search("Portugal"))
['Portugal', 'Spain', ..., 'Greece']
c_graph()
Return the ._cg and ._cg_rev attributes
Note: The ._cg_rev attribute has been removed and hence None is returned.
EXAMPLES:
degree(v, directed)
Return the degree of the vertex v.
INPUT:
• v – a vertex of the graph
• directed – boolean; whether to take into account the orientation of this graph in counting the degree
of v
OUTPUT:
• The degree of vertex v
EXAMPLES:
del_edge(u, v, l, directed)
Delete edge (u, v, l).
INPUT:
• u, v – the vertices of the edge
• l – the edge label
• directed – if False, also delete (v, u, l)
Note: The input l is ignored if the backend does not support labels.
EXAMPLES:
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
sage: D.add_edges([(0,1), (2,3), (4,5), (5,6)], False)
sage: list(D.iterator_edges(range(9), True))
[(0, 1, None),
(2, 3, None),
(4, 5, None),
(5, 6, None)]
sage: D.del_edge(0,1,None,True)
sage: list(D.iterator_out_edges(range(9), True))
[(1, 0, None),
(2, 3, None),
(3, 2, None),
(4, 5, None),
(5, 4, None),
(5, 6, None),
(6, 5, None)]
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
sage: D.add_edges([(0, 1), (2, 3), (4, 5), (5, 6)], False)
sage: list(D.iterator_edges(range(9), True))
[(0, 1, None),
(continues on next page)
del_edges(edges, directed)
Delete edges from a list.
INPUT:
• edges – the edges to be added; can either be of the form (u,v) or (u,v,l)
• directed – if False, remove``(v,u)`` as well as (u,v)
EXAMPLES:
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
sage: D.add_edges([(0,1), (2,3), (4,5), (5,6)], False)
sage: D.del_edges([(0,1), (2,3), (4,5), (5,6)], False)
sage: list(D.iterator_edges(range(9), True))
[]
del_vertex(v)
Delete a vertex in self, failing silently if the vertex is not in the graph.
INPUT:
• v – vertex to be deleted
See also:
EXAMPLES:
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
sage: D.del_vertex(0)
sage: D.has_vertex(0)
False
sage: S = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
sage: S.del_vertex(0)
sage: S.has_vertex(0)
False
del_vertices(vertices)
Delete vertices from an iterable container.
INPUT:
EXAMPLES:
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
sage: D.del_vertices([1, 2, 3])
sage: D.has_vertex(1)
False
sage: D.has_vertex(0)
True
1. if 𝐷[𝑤] = ∞ then
1. 𝐷[𝑤] ← 𝐷[𝑣] + 1
2. push(𝑆, 𝑤)
3. append(𝑇, 𝑣𝑤)
6. return (𝐷, 𝑇 )
See also:
EXAMPLES:
Traversing the Petersen graph using depth-first search:
sage: G = Graph(graphs.PetersenGraph())
sage: list(G.depth_first_search(0))
[0, 5, 8, 6, 9, 7, 2, 3, 4, 1]
has_vertex(v)
Check whether v is a vertex of self.
INPUT:
• v – any object
OUTPUT:
• True if v is a vertex of this graph; False otherwise
EXAMPLES:
in_degree(v)
Return the in-degree of v
INPUT:
• v – a vertex of the graph
EXAMPLES:
is_connected()
Check whether the graph is connected.
EXAMPLES:
Petersen’s graph is connected:
sage: DiGraph(graphs.PetersenGraph()).is_connected()
True
sage: DiGraph(2*graphs.PetersenGraph()).is_connected()
False
sage: Graph(graphs.CubeGraph(3)).is_connected()
True
is_directed_acyclic(certificate=False)
Check whether the graph is both directed and acyclic (possibly with a certificate)
INPUT:
• certificate – boolean (default: False); whether to return a certificate
OUTPUT:
When certificate=False, returns a boolean value. When certificate=True :
• If the graph is acyclic, returns a pair (True, ordering) where ordering is a list of the vertices
such that u appears before v in ordering if u, v is an edge.
• Else, returns a pair (False, cycle) where cycle is a list of vertices representing a circuit in the
graph.
ALGORITHM:
We pick a vertex at random, think hard and find out that if we are to remove the vertex from the graph we
must remove all of its out-neighbors in the first place. So we put all of its out-neighbours in a stack, and
repeat the same procedure with the vertex on top of the stack (when a vertex on top of the stack has no
out-neighbors, we remove it immediately). Of course, for each vertex we only add its outneighbors to the
end of the stack once : if for some reason the previous algorithm leads us to do it twice, it means we have
found a circuit.
We keep track of the vertices whose out-neighborhood has been added to the stack once with a variable
named tried.
There is no reason why the graph should be empty at the end of this procedure, so we run it again on the
remaining vertices until none are left or a circuit is found.
EXAMPLES:
At first, the following graph is acyclic:
sage: D.plot(layout='circular').show()
sage: D.is_directed_acyclic()
True
sage: D.add_edge(9,7)
sage: D.is_directed_acyclic()
True
We can obtain as a proof an ordering of the vertices such that 𝑢 appears before 𝑣 if 𝑢𝑣 is an edge of the
graph:
sage: D.add_edge(7,4)
sage: D.is_directed_acyclic()
False
....: return h
...
sage: all( random_acyclic(100, .2).is_directed_acyclic() # long time
....: for i in range(50)) # long time
True
is_strongly_connected()
Check whether the graph is strongly connected.
EXAMPLES:
iterator_edges(vertices, labels)
Iterate over the edges incident to a sequence of vertices.
Edges are assumed to be undirected.
Warning: This will try to sort the two ends of every edge.
INPUT:
• vertices – a list of vertex labels
• labels – boolean, whether to return labels as well
EXAMPLES:
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
sage: G.add_edge(1,2,3,False)
sage: list(G.iterator_edges(range(9), False))
[(1, 2)]
sage: list(G.iterator_edges(range(9), True))
[(1, 2, 3)]
iterator_in_edges(vertices, labels)
Iterate over the incoming edges incident to a sequence of vertices.
INPUT:
• vertices – a list of vertex labels
• labels – boolean, whether to return labels as well
EXAMPLES:
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
sage: G.add_edge(1,2,3,True)
sage: list(G.iterator_in_edges([1], False))
[]
sage: list(G.iterator_in_edges([2], False))
[(1, 2)]
sage: list(G.iterator_in_edges([2], True))
[(1, 2, 3)]
iterator_in_nbrs(v)
Iterate over the incoming neighbors of v.
INPUT:
• v – a vertex of this graph
OUTPUT:
• An iterator over the in-neighbors of the vertex v
See also:
EXAMPLES:
sage: P = DiGraph(graphs.PetersenGraph().to_directed())
sage: list(P._backend.iterator_in_nbrs(0))
[1, 4, 5]
iterator_nbrs(v)
Iterate over the neighbors of v.
INPUT:
• v – a vertex of this graph
OUTPUT:
• An iterator over the neighbors the vertex v
See also:
EXAMPLES:
sage: P = Graph(graphs.PetersenGraph())
sage: list(P._backend.iterator_nbrs(0))
[1, 4, 5]
sage: Q = DiGraph(P)
sage: list(Q._backend.iterator_nbrs(0))
[1, 4, 5]
iterator_out_edges(vertices, labels)
Iterate over the outbound edges incident to a sequence of vertices.
INPUT:
• vertices – a list of vertex labels
• labels – boolean, whether to return labels as well
EXAMPLES:
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
sage: G.add_edge(1,2,3,True)
sage: list(G.iterator_out_edges([2], False))
[]
sage: list(G.iterator_out_edges([1], False))
[(1, 2)]
sage: list(G.iterator_out_edges([1], True))
[(1, 2, 3)]
iterator_out_nbrs(v)
Iterate over the outgoing neighbors of v.
INPUT:
• v – a vertex of this graph
OUTPUT:
EXAMPLES:
sage: P = DiGraph(graphs.PetersenGraph().to_directed())
sage: list(P._backend.iterator_out_nbrs(0))
[1, 4, 5]
iterator_unsorted_edges(vertices, labels)
Iterate over the edges incident to a sequence of vertices.
Edges are assumed to be undirected.
This does not sort the ends of each edge.
INPUT:
• vertices – a list of vertex labels
• labels – boolean, whether to return labels as well
EXAMPLES:
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
sage: G.add_edge(1,2,3,False)
sage: list(G.iterator_unsorted_edges(range(9), False))
[(2, 1)]
sage: list(G.iterator_unsorted_edges(range(9), True))
[(2, 1, 3)]
iterator_verts(verts=None)
Iterate over the vertices of self intersected with verts.
INPUT:
• verts – an iterable container of objects (default: None)
OUTPUT:
• If verts=None, return an iterator over all vertices of this graph
• If verts is a single vertex of the graph, treat it as the container [verts]
• If verts is a iterable container of vertices, find the intersection of verts with the vertex set of this
graph and return an iterator over the resulting intersection
See also:
EXAMPLES:
sage: P = Graph(graphs.PetersenGraph())
sage: list(P._backend.iterator_verts(P))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
(continues on next page)
loops(new=None)
Check whether loops are allowed in this graph.
INPUT:
• new – boolean (default: None); to set or None to get
OUTPUT:
• If new=None, return True if this graph allows self-loops or False if self-loops are not allowed
• If new is a boolean, set the self-loop permission of this graph according to the boolean value of new
EXAMPLES:
sage: G = Graph()
sage: G._backend.loops()
False
sage: G._backend.loops(True)
sage: G._backend.loops()
True
num_edges(directed)
Return the number of edges in self.
INPUT:
• directed – boolean; whether to count (u, v) and (v, u) as one or two edges
OUTPUT:
• If directed=True, counts the number of directed edges in this graph. Otherwise, return the size of
this graph.
See also:
EXAMPLES:
sage: G = Graph(graphs.PetersenGraph())
sage: G._backend.num_edges(False)
15
num_verts()
Return the number of vertices in self.
OUTPUT:
• The order of this graph.
See also:
EXAMPLES:
sage: G = Graph(graphs.PetersenGraph())
sage: G._backend.num_verts()
10
out_degree(v)
Return the out-degree of v
INPUT:
• v – a vertex of the graph.
EXAMPLES:
relabel(perm, directed)
Relabel the graph according to perm.
INPUT:
• perm – anything which represents a permutation as v --> perm[v], for example a dict or a list
• directed – ignored (this is here for compatibility with other backends)
EXAMPLES:
sage: G = Graph(graphs.PetersenGraph())
sage: G._backend.relabel(range(9,-1,-1), False)
sage: G.edges(sort=True)
[(0, 2, None),
(0, 3, None),
(0, 5, None),
(1, 3, None),
(1, 4, None),
(1, 6, None),
(2, 4, None),
(2, 7, None),
(3, 8, None),
(4, 9, None),
(5, 6, None),
(5, 9, None),
(6, 7, None),
(7, 8, None),
(8, 9, None)]
shortest_path(x, y, distance_flag=False)
Return the shortest path or distance from x to y.
INPUT:
• x – the starting vertex in the shortest path from x to y
• y – the end vertex in the shortest path from x to y
• distance_flag – boolean (default: False); when set to True, the shortest path distance from x to y
is returned instead of the path
OUTPUT:
• A list of vertices in the shortest path from x to y or distance from x to y is returned depending upon
the value of parameter distance_flag
EXAMPLES:
sage: G = Graph(graphs.PetersenGraph())
sage: G.shortest_path(0, 1)
[0, 1]
sage: G.shortest_path_length(0, 1)
1
ALGORITHM:
This is just a breadth-first search.
EXAMPLES:
On the Petersen Graph:
sage: g = graphs.PetersenGraph()
sage: paths = g._backend.shortest_path_all_vertices(0)
sage: all((not paths[v] or len(paths[v])-1 == g.distance(0,v)) for v in g)
True
sage: g._backend.shortest_path_all_vertices(0, distance_flag=True)
{0: 0, 1: 1, 2: 2, 3: 2, 4: 1, 5: 1, 6: 2, 7: 2, 8: 2, 9: 2}
On a disconnected graph:
True
sage: G = Graph([(1, 2), (2, 3), (3, 4), (1, 5), (5, 6), (6, 7), (7, 4)])
sage: G._backend.shortest_path_special(1, 4)
[1, 2, 3, 4]
sage: G._backend.shortest_path_special(1, 4, exclude_vertices=[5,7])
[1, 2, 3, 4]
sage: G._backend.shortest_path_special(1, 4, exclude_vertices=[2, 3])
[1, 5, 6, 7, 4]
sage: G._backend.shortest_path_special(1, 4, exclude_vertices=[2], exclude_
˓→edges=[(5, 6)])
[]
sage: G._backend.shortest_path_special(1, 4, exclude_vertices=[2], exclude_
˓→edges=[(2, 3)])
[1, 5, 6, 7, 4]
strongly_connected_component_containing_vertex(v)
Return the strongly connected component containing the given vertex.
INPUT:
• v – a vertex
EXAMPLES:
The digraph obtained from the PetersenGraph has an unique strongly connected component:
sage: g = DiGraph(graphs.PetersenGraph())
sage: g.strongly_connected_component_containing_vertex(0)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sage: g = digraphs.ButterflyGraph(3)
sage: all([v] == g.strongly_connected_component_containing_vertex(v) for v in g)
True
subgraph_given_vertices(other, vertices)
Initialize other to be the subgraph of self with given vertices.
INPUT:
• other – a (mutable) subclass of CGraphBackend
• vertices – a list of vertex labels
EXAMPLES:
Make a dense copy:
True
True
Loops are removed, if the other graph does not allow loops:
Multiple edges are removed, if the other graph does not allow them:
Labels are removed, if the other graph does not allow them:
A directed subgraph of an undirected graph is taken by initializing with edges in both directions:
class sage.graphs.base.c_graph.Search_iterator
Bases: object
An iterator for traversing a (di)graph.
This class is commonly used to perform a depth-first or breadth-first search. The class does not build all at once
in memory the whole list of visited vertices. The class maintains the following variables:
• graph – a graph whose vertices are to be iterated over.
• direction – integer; this determines the position at which vertices to be visited are removed from the list.
For breadth-first search (BFS), element removal follow a first-in first-out (FIFO) protocol, as signified by
the value direction=0. We use a queue to maintain the list of vertices to visit in this case. For depth-
first search (DFS), element removal follow a last-in first-out (LIFO) protocol, as signified by the value
direction=-1. In this case, we use a stack to maintain the list of vertices to visit.
• stack – a list of vertices to visit, used only when direction=-1
• queue – a queue of vertices to visit, used only when direction=0
• seen – a list of vertices that are already visited
• test_out – boolean; whether we want to consider the out-neighbors of the graph to be traversed. For
undirected graphs, we consider both the in- and out-neighbors. However, for digraphs we only traverse
along out-neighbors.
• test_in – boolean; whether we want to consider the in-neighbors of the graph to be traversed. For undi-
rected graphs, we consider both the in- and out-neighbors.
EXAMPLES:
sage: g = graphs.PetersenGraph()
sage: list(g.breadth_first_search(0))
[0, 1, 4, 5, 2, 6, 3, 9, 7, 8]
This example initializes a sparse graph with room for twenty vertices, the first ten of which are in the graph. In general,
the first nverts are “active.” For example, see that 9 is already in the graph:
sage: S.verts()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sage: S.add_vertex(9)
9
sage: S.verts()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sage: S.add_vertex(10)
10
sage: S.verts()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
You can begin working with unlabeled arcs right away as follows:
sage: S.add_arc(0,1)
sage: S.add_arc(1,2)
sage: S.add_arc(1,0)
sage: S.has_arc(7,3)
False
sage: S.has_arc(0,1)
True
sage: S.in_neighbors(1)
[0]
sage: S.out_neighbors(1)
[0, 2]
sage: S.del_all_arcs(0,1)
sage: S.all_arcs(0,1)
[]
sage: S.all_arcs(1,2)
[0]
sage: S.del_vertex(7)
sage: S.all_arcs(7,3)
Traceback (most recent call last):
...
LookupError: vertex (7) is not a vertex of the graph
Sparse graphs support multiple edges and labeled edges, but requires that the labels be positive integers (the case label
= 0 is treated as no label).
sage: S.add_arc_label(0,1,-1)
Traceback (most recent call last):
...
ValueError: Label (-1) must be a nonnegative integer.
sage: S.add_arc(0,1)
sage: S.arc_label(0,1)
0
Note that arc_label only returns the first edge label found in the specified place, and this can be in any order (if you
want all arc labels, use all_arcs):
sage: S.add_arc_label(0,1,1)
sage: S.arc_label(0,1)
1
sage: S.all_arcs(0,1)
[0, 1]
sage: S.arc_label(1,2)
0
So do not be fooled:
sage: S.all_arcs(1,2)
[0]
sage: S.add_arc(1,2)
sage: S.arc_label(1,2)
0
Instead, if you work with unlabeled edges, be sure to use the right functions:
Sparse graphs are by their nature directed. As of this writing, you need to do operations in pairs to treat the undirected
case (or use a backend or a Sage graph):
sage: T.has_arc(1,0)
False
The curious developer is encouraged to check out the unsafe functions, which do not check input but which run in
pure C.
The class SparseGraph contains the following variables which are inherited from CGraph (for explanation, refer to
the documentation there):
For each vertex u, a hash table of length hash_length is instantiated. An arc (u, v) is stored at u * hash_length
+ hash(v) of the array vertices, where hash should be thought of as an arbitrary but fixed hash function which
takes values in 0 <= hash < hash_length. Each address may represent different arcs, say (u, v1) and (u, v2)
where hash(v1) == hash(v2). Thus, a binary tree structure is used at this step to speed access to individual arcs,
whose nodes (each of which represents a pair (u,v)) are instances of the following type:
Which range of the vertices array the root of the tree is in determines u, and vertex stores v. The integer number
stores only the number of unlabeled arcs from u to v.
Currently, labels are stored in a simple linked list, whose nodes are instances of the following type:
The int label must be a positive integer, since 0 indicates no label, and negative numbers indicate errors. The int
number is the number of arcs with the given label.
TODO: Optimally, edge labels would also be represented by a binary tree, which would help performance in graphs
with many overlapping edges. Also, a more efficient binary tree structure could be used, although in practice the
trees involved will usually have very small order, unless the degree of vertices becomes significantly larger than the
expected_degree given, because this is the size of each hash table. Indeed, the expected size of the binary trees
actual degree
is expected degree . Ryan Dingman, e.g., is working on a general-purpose Cython-based red black tree, which would be
optimal for both of these uses.
class sage.graphs.base.sparse_graph.SparseGraph
Bases: sage.graphs.base.c_graph.CGraph
Compiled sparse graphs.
INPUT:
• nverts – non-negative integer, the number of vertices.
• expected_degree – non-negative integer (default: 16), expected upper bound on degree of vertices.
• extra_vertices – non-negative integer (default: 0), how many extra vertices to allocate.
• verts – optional list of vertices to add
• arcs – optional list of arcs to add
The first nverts are created as vertices of the graph, and the next extra_vertices can be freely added without
reallocation. See top level documentation for more details. The input verts and arcs are mainly for use in
pickling.
add_arc_label(u, v, l=0)
Add arc (u, v) to the graph with label l.
INPUT:
• u, v – non-negative integers, must be in self
in_degree(v)
Returns the in-degree of v
INPUT:
• v – integer
EXAMPLES:
is_directed()
Return whether the graph is directed.
EXAMPLES:
out_degree(u)
Returns the out-degree of v
INPUT:
• u – integer
EXAMPLES:
realloc(total)
Reallocate the number of vertices to use, without actually adding any.
INPUT:
• total – integer, the total size to make the array
Returns -1 and fails if reallocation would destroy any active vertices.
EXAMPLES:
class sage.graphs.base.sparse_graph.SparseGraphBackend
Bases: sage.graphs.base.c_graph.CGraphBackend
Backend for Sage graphs using SparseGraphs.
This class is only intended for use by the Sage Graph and DiGraph class. If you are interested in using a SparseG-
raph, you probably want to do something like the following example, which creates a Sage Graph instance which
wraps a SparseGraph object:
Note that Sage graphs using the backend are more flexible than SparseGraphs themselves. This is because
SparseGraphs (by design) do not deal with Python objects:
sage: G.add_vertex((0,1,2))
sage: sorted(list(G),
....: key=lambda x: (isinstance(x, tuple), x))
[0,
...
29,
(0, 1, 2)]
sage: from sage.graphs.base.sparse_graph import SparseGraph
sage: SG = SparseGraph(30)
sage: SG.add_vertex((0,1,2))
Traceback (most recent call last):
...
TypeError: an integer is required
get_edge_label(u, v)
Return the edge label for (u, v).
INPUT:
• u,v – the vertices of the edge
EXAMPLES:
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
sage: D.add_edges([(0,1,1), (2,3,2), (4,5,3), (5,6,2)], False)
sage: list(D.iterator_edges(range(9), True))
[(0, 1, 1), (2, 3, 2), (4, 5, 3), (5, 6, 2)]
sage: D.get_edge_label(3,2)
2
has_edge(u, v, l)
Returns whether this graph has edge (u,v) with label l. If l is None, return whether this graph has an
edge (u,v) with any label.
INPUT:
• u, v – the vertices of the edge
• l – the edge label, or None
EXAMPLES:
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
sage: D.add_edges([(0,1), (2,3), (4,5), (5,6)], False)
sage: D.has_edge(0,1,None)
True
multiple_edges(new)
Get/set whether or not self allows multiple edges.
INPUT:
• new – boolean (to set) or None (to get)
EXAMPLES:
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
sage: G.multiple_edges(True)
sage: G.multiple_edges(None)
True
sage: G.multiple_edges(False)
sage: G.multiple_edges(None)
False
sage: G.add_edge(0,1,0,True)
sage: G.add_edge(0,1,0,True)
sage: list(G.iterator_out_edges(range(9), True))
[(0, 1, 0)]
set_edge_label(u, v, l, directed)
Label the edge (u,v) by l.
INPUT:
• u,v – the vertices of the edge
• l – the edge label
• directed – if False, also set (v,u) with label l
EXAMPLES:
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
sage: G.add_edge(1,2,None,True)
sage: G.set_edge_label(1,2,'a',True)
sage: list(G.iterator_out_edges(range(9), True))
[(1, 2, 'a')]
sage: G.set_edge_label(2,1,'b',True)
sage: list(G.iterator_out_edges(range(9), True))
[(1, 2, 'a')]
This example initializes a dense graph with room for twenty vertices, the first ten of which are in the graph. In general,
the first nverts are “active.” For example, see that 9 is already in the graph:
sage: D.verts()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sage: D.add_vertex(9)
9
sage: D.verts()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sage: D.add_vertex(10)
10
sage: D.verts()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
sage: D.add_arc(0, 1)
sage: D.add_arc(1, 2)
sage: D.add_arc(1, 0)
sage: D.has_arc(7, 3)
False
sage: D.has_arc(0, 1)
True
sage: D.in_neighbors(1)
[0]
sage: D.out_neighbors(1)
[0, 2]
sage: D.del_all_arcs(0, 1)
sage: D.has_arc(0, 1)
False
sage: D.has_arc(1, 2)
True
sage: D.del_vertex(7)
sage: D.has_arc(7, 3)
False
Dense graphs are by their nature directed. As of this writing, you need to do operations in pairs to treat the undirected
case (or use a backend or a Sage graph):
sage: T.has_arc(1, 0)
False
The curious developer is encouraged to check out the unsafe functions, which do not check input but which run in
pure C.
The class DenseGraph contains the following variables which are inherited from CGraph (for explanation, refer to the
documentation there):
class sage.graphs.base.dense_graph.DenseGraph
Bases: sage.graphs.base.c_graph.CGraph
Compiled dense graphs.
INPUT:
• nverts – non-negative integer; the number of vertices
• extra_vertices – non-negative integer (default: 10); how many extra vertices to allocate
• verts – list (default: None); optional list of vertices to add
• arcs – list (default: None); optional list of arcs to add
EXAMPLES:
realloc(total_verts)
Reallocate the number of vertices to use, without actually adding any.
INPUT:
• total – integer; the total size to make the array
Returns -1 and fails if reallocation would destroy any active vertices.
EXAMPLES:
sage: from sage.graphs.base.dense_graph import DenseGraph
sage: D = DenseGraph(nverts=4, extra_vertices=4)
sage: D.current_allocation()
8
sage: D.add_vertex(6)
6
sage: D.current_allocation()
8
sage: D.add_vertex(10)
10
sage: D.current_allocation()
16
sage: D.add_vertex(40)
Traceback (most recent call last):
...
RuntimeError: requested vertex is past twice the allocated range: use realloc
sage: D.realloc(50)
sage: D.add_vertex(40)
40
sage: D.current_allocation()
50
sage: D.realloc(30)
-1
(continues on next page)
class sage.graphs.base.dense_graph.DenseGraphBackend
Bases: sage.graphs.base.c_graph.CGraphBackend
Backend for Sage graphs using DenseGraphs.
This class is only intended for use by the Sage Graph and DiGraph class. If you are interested in using a DenseG-
raph, you probably want to do something like the following example, which creates a Sage Graph instance which
wraps a DenseGraph object:
Note that Sage graphs using the backend are more flexible than DenseGraphs themselves. This is because
DenseGraphs (by design) do not deal with Python objects:
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
sage: D.add_edges([(0, 1), (2, 3), (4, 5), (5, 6)], False)
(continues on next page)
get_edge_label(u, v)
Return the edge label for (u, v).
Always None, since dense graphs do not support edge labels.
INPUT:
• u, v – the vertices of the edge
EXAMPLES:
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
sage: D.add_edges([(0, 1), (2, 3, 7), (4, 5), (5, 6)], False)
sage: list(D.iterator_edges(range(9), True))
[(0, 1, None),
(2, 3, None),
(4, 5, None),
(5, 6, None)]
sage: D.del_edge(0, 1, None, True)
sage: list(D.iterator_out_edges(range(9), True))
[(1, 0, None),
(2, 3, None),
(3, 2, None),
(4, 5, None),
(5, 4, None),
(5, 6, None),
(6, 5, None)]
sage: D.get_edge_label(2, 3)
sage: D.get_edge_label(2, 4)
Traceback (most recent call last):
...
LookupError: (2, 4) is not an edge of the graph
has_edge(u, v, l)
Check whether this graph has edge (u, v).
INPUT:
• u, v – the vertices of the edge
• l – the edge label (ignored)
EXAMPLES:
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
sage: D.add_edges([(0, 1), (2, 3), (4, 5), (5, 6)], False)
(continues on next page)
multiple_edges(new)
Get/set whether or not self allows multiple edges.
INPUT:
• new – boolean (to set) or None (to get)
EXAMPLES:
set_edge_label(u, v, l, directed)
Label the edge (u, v) by l.
INPUT:
• u, v – the vertices of the edge
• l – the edge label
• directed – if False, also set (v, u) with label l
EXAMPLES:
This module gathers everything which is related to static dense graphs, i.e. :
• The vertices are integer from 0 to 𝑛 − 1
• No labels on vertices/edges
• No multiple edges
• No addition/removal of vertices
This being said, it is technically possible to add/remove edges. The data structure does not mind at all.
It is all based on the binary matrix data structure described in data_structures/binary_matrix.pxd, which is
almost a copy of the bitset data structure. The only difference is that it differentiates the rows (the vertices) instead of
storing the whole data in a long bitset, and we can use that.
3.5.1 Index
Cython functions
dense_graph_init Fill a binary matrix with the information from a Sage (di)graph.
Python functions
3.5.2 Functions
sage.graphs.base.static_dense_graph.connected_subgraph_iterator(G, k=None,
vertices_only=False)
Iterator over the induced connected subgraphs of order at most 𝑘.
This method implements a iterator over the induced connected subgraphs of the input (di)graph. An induced
subgraph of a graph is another graph, formed from a subset of the vertices of the graph and all of the edges
connecting pairs of vertices in that subset (Wikipedia article Induced_subgraph).
As for method sage.graphs.generic_graph.connected_components(), edge orientation is ignored.
Hence, the directed graph with a single arc 0 → 1 is considered connected.
INPUT:
• G – a Graph or a DiGraph ; loops and multiple edges are allowed
• k – (optional) integer; maximum order of the connected subgraphs to report; by default, the method iterates
over all connected subgraphs (equivalent to k == n)
• vertices_only – boolean (default: False); whether to return (Di)Graph or list of vertices
EXAMPLES:
sage.graphs.base.static_dense_graph.is_strongly_regular(g, parameters=False)
Check whether the graph is strongly regular.
A simple graph 𝐺 is said to be strongly regular with parameters (𝑛, 𝑘, 𝜆, 𝜇) if and only if:
• 𝐺 has 𝑛 vertices
• 𝐺 is 𝑘-regular
• Any two adjacent vertices of 𝐺 have 𝜆 common neighbors
• Any two non-adjacent vertices of 𝐺 have 𝜇 common neighbors
By convention, the complete graphs, the graphs with no edges and the empty graph are not strongly regular.
See the Wikipedia article Strongly regular graph.
INPUT:
• parameters – boolean (default: False); whether to return the quadruple (𝑛, 𝑘, 𝜆, 𝜇). If parameters =
False (default), this method only returns True and False answers. If parameters = True, the True
answers are replaced by quadruples (𝑛, 𝑘, 𝜆, 𝜇). See definition above.
EXAMPLES:
Petersen’s graph is strongly regular:
sage: g = graphs.PetersenGraph()
sage: g.is_strongly_regular()
True
sage: g.is_strongly_regular(parameters=True)
(10, 3, 0, 1)
sage: g = graphs.ClebschGraph()
sage: g.is_strongly_regular()
True
sage: g.is_strongly_regular(parameters=True)
(16, 5, 0, 2)
sage: g = graphs.ChvatalGraph()
sage: g.is_strongly_regular()
False
sage: g = graphs.CompleteGraph(5)
sage: g.is_strongly_regular()
False
sage: g = graphs.CompleteGraph(5).complement()
sage: g.is_strongly_regular()
False
sage: g = graphs.EmptyGraph()
sage: g.is_strongly_regular()
False
sage: Graph([(1,1),(2,2)],loops=True).is_strongly_regular()
Traceback (most recent call last):
...
ValueError: This method is not known to work on graphs with
loops. Perhaps this method can be updated to handle them, but in the
meantime if you want to use it please disallow loops using
allow_loops().
sage: Graph([(1,2),(1,2)],multiedges=True).is_strongly_regular()
Traceback (most recent call last):
...
ValueError: This method is not known to work on graphs with
multiedges. Perhaps this method can be updated to handle them, but in
the meantime if you want to use it please disallow multiedges using
allow_multiple_edges().
sage.graphs.base.static_dense_graph.is_triangle_free(G, certificate=False)
Check whether 𝐺 is triangle free.
INPUT:
• G – a Sage graph
• certificate – boolean (default: False); whether to return a triangle if one is found
EXAMPLES:
sage.graphs.base.static_dense_graph.triangles_count(G)
Return the number of triangles containing 𝑣, for every 𝑣.
INPUT:
• G – a simple Sage graph
EXAMPLES:
This class implements a Cython (di)graph structure made for efficiency. The graphs are static, i.e. no add/remove
vertex/edges methods are available, nor can they easily or efficiently be implemented within this data structure.
The data structure, however, is made to save the maximum amount of computations for graph algorithms whose main
operation is to list the out-neighbours of a vertex (which is precisely what BFS, DFS, distance computations and the
flow-related stuff waste their life on).
The code contained in this module is written C-style. The purpose is efficiency and simplicity.
For an overview of graph data structures in sage, see overview.
Author:
• Nathann Cohen (2011)
The data structure is actually pretty simple and compact. short_digraph has five fields
• n (int); the number of vertices in the graph
• m (int); the number of edges in the graph
• edges (uint32_t *); array whose length is the number of edges of the graph
• neighbors (uint32_t **); this array has size 𝑛 + 1, and describes how the data of edges should be read
: the neighbors of vertex 𝑖 are the elements of edges addressed by neighbors[i]...neighbors[i+1]-1.
The element neighbors[n], which corresponds to no vertex (they are numbered from 0 to 𝑛 − 1) is present so
that it remains easy to enumerate the neighbors of vertex 𝑛 − 1 : the last of them is the element addressed by
neighbors[n]-1.
• edge_labels (list); this cython list associates a label to each edge of the graph. If a given edge is represented
by edges[i], this its associated label can be found at edge_labels[i]. This object is usually NULL, unless
the call to init_short_digraph explicitly requires the labels to be stored in the data structure.
In the example given above, vertex 0 has 2,3,5,7,8 and 9 as out-neighbors, but not 4, which is an out-neighbour of
vertex 1. Vertex 𝑛 − 1 has 2, 5, 8 and 9 as out-neighbors. neighbors[n] points toward the cell immediately after the
end of edges, hence outside of the allocated memory. It is used to indicate the end of the outneighbors of vertex 𝑛 − 1
Iterating over the edges
This is the one thing to have in mind when working with this data structure:
Advantages
Two great points :
• The neighbors of a vertex are C types, and are contiguous in memory.
• Storing such graphs is incredibly cheaper than storing Python structures.
Well, I think it would be hard to have anything more efficient than that to enumerate out-neighbors in sparse graphs !
:-)
• When creating a short_digraph from a Graph or DiGraph named G, the 𝑖th vertex corresponds by default
to G.vertices(sort=True)[i]. Using optional parameter vertex_list, you can specify the order of the
vertices. Then 𝑖th vertex will corresponds to vertex_list[i].
• Some methods return bitset_t objects when lists could be expected. There is a very useful bitset_list
function for this kind of problems :-)
• When the edges are labelled, most of the space taken by this graph is taken by edge labels. If no edge is labelled
then this space is not allocated, but if any edge has a label then a (possibly empty) label is stored for each edge,
which can double the memory needs.
• The data structure stores the number of edges, even though it appears that this number can be reconstructed with
g.neighbors[n]-g.neighbors[0]. The trick is that not all elements of the g.edges array are necessarily
used : when an undirected graph contains loops, only one entry of the array of size 2𝑚 is used to store it, instead
of the expected two. Storing the number of edges is the only way to avoid an uselessly costly computation to
obtain the number of edges of an undirected, looped, AND labelled graph (think of several loops on the same
vertex with different labels).
• The codes of this module are well documented, and many answers can be found directly in the code.
Connectivity
can_be_reached_from(short_digraph g, int src, bitset_t reached)
Assuming bitset_t reached has size at least g.n, this method updates reached so that it represents
the set of vertices that can be reached from src in g.
strongly_connected_component_containing_vertex(short_digraph g, short_digraph g_reversed,
int v, bitset_t scc)
Assuming bitset_t reached has size at least g.n, this method updates scc so that it represents the
vertices of the strongly connected component containing v in g. The variable g_reversed is assumed to
represent the reverse of g.
These functions are available so that Python modules from Sage can call the Cython routines this module implements
(as they cannot directly call methods with C arguments).
sage.graphs.base.static_sparse_graph.spectral_radius(G, prec=1e-10)
Return an interval of floating point number that encloses the spectral radius of this graph
The input graph G must be strongly connected.
INPUT:
• prec – (default 1e-10) an upper bound for the relative precision of the interval
The algorithm is iterative and uses an inequality valid for non-negative matrices. Namely, if 𝐴 is a non-negative
square matrix with Perron-Frobenius eigenvalue 𝜆 then the following inequality is valid for any vector 𝑥
(𝐴𝑥)𝑖 (𝐴𝑥)𝑖
min ≤ 𝜆 ≤ max
𝑖 𝑥𝑖 𝑖 𝑥𝑖
Note: The speed of convergence of the algorithm is governed by the spectral gap (the distance to the second
largest modulus of other eigenvalues). If this gap is small, then this function might not be appropriate.
The algorithm is not smart and not parallel! It uses basic interval arithmetic and native floating point arithmetic.
EXAMPLES:
sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(2,4),(3,4)])
sage: e_min, e_max = spectral_radius(G, 1e-14)
sage: e = max(G.adjacency_matrix().charpoly().roots(AA, multiplicities=False))
sage: e_min < e < e_max
True
A larger example:
sage: G = DiGraph()
sage: G.add_edges((i,i+1) for i in range(200))
sage: G.add_edge(200,0)
sage: G.add_edge(1,0)
sage: e_min, e_max = spectral_radius(G, 0.00001)
sage: p = G.adjacency_matrix(sparse=True).charpoly()
sage: p
x^201 - x^199 - 1
sage: r = p.roots(AA, multiplicities=False)[0]
sage: e_min < r < e_max
True
sage: G = DiGraph(100000)
sage: r = list(range(100000))
sage: while not G.is_strongly_connected():
....: shuffle(r)
....: G.add_edges(enumerate(r), loops=False)
sage: spectral_radius(G, 1e-10) # random
(1.9997956006500042, 1.9998043797692782)
sage: G = DiGraph(2,loops=True,multiedges=True)
sage: G.add_edges([(0,0),(0,0),(0,1),(1,0)])
sage: spectral_radius(G, 1e-14) # abs tol 1e-14
(2.414213562373094, 2.414213562373095)
sage: max(G.adjacency_matrix().eigenvalues(AA))
2.414213562373095?
sage: G = Graph([(0,1),(0,3),(2,3)])
sage: G.spectral_radius() # abs tol 1e-10
(continues on next page)
sage: G = DiGraph([(0,1),(0,3),(2,3),(3,0),(1,0),(1,2)])
sage: G.spectral_radius() # abs tol 1e-10
(1.5537739740270458, 1.553773974033029)
sage: G = graphs.CompleteBipartiteGraph(1,3)
sage: G.spectral_radius() # abs tol 1e-10
(1.7320508075688772, 1.7320508075688774)
sage.graphs.base.static_sparse_graph.strongly_connected_components_digraph(G)
Return the digraph of the strongly connected components (SCCs).
This routine is used to test strongly_connected_components_digraph_C, but it is not used by the Sage
digraph. It outputs a pair [g_scc,scc], where g_scc is the SCC digraph of g, scc is a dictionary associating
to each vertex v the number of the SCC of v, as it appears in g_scc.
EXAMPLES:
sage: strongly_connected_components_digraph(digraphs.Path(3))
(Digraph on 3 vertices, {0: 2, 1: 1, 2: 0})
sage: strongly_connected_components_digraph(DiGraph(4))
(Digraph on 4 vertices, {0: 0, 1: 1, 2: 2, 3: 3})
sage.graphs.base.static_sparse_graph.tarjan_strongly_connected_components(G)
Return the lists of vertices in each strongly connected components (SCCs).
This method implements the Tarjan algorithm to compute the strongly connected components of the digraph. It
returns a list of lists of vertices, each list of vertices representing a strongly connected component.
The basic idea of the algorithm is this: a depth-first search (DFS) begins from an arbitrary start node (and
subsequent DFSes are conducted on any nodes that have not yet been found). As usual with DFSes, the search
visits every node of the graph exactly once, declining to revisit any node that has already been explored. Thus,
the collection of search trees is a spanning forest of the graph. The strongly connected components correspond
to the subtrees of this spanning forest that have no edge directed outside the subtree.
To recover these components, during the DFS, we keep the index of a node, that is, the position in the DFS tree,
and the lowlink: as soon as the subtree rooted at 𝑣 has been fully explored, the lowlink of 𝑣 is the smallest index
reachable from 𝑣 passing from descendants of 𝑣. If the subtree rooted at 𝑣 has been fully explored, and the index
of 𝑣 equals the lowlink of 𝑣, that whole subtree is a new SCC.
For more information, see the Wikipedia article Tarjan%27s_strongly_connected_components_algorithm.
EXAMPLES:
sage: tarjan_strongly_connected_components(digraphs.Path(3))
[[2], [1], [0]]
sage: D = DiGraph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )
sage: D.connected_components()
[[0, 1, 2, 3], [4, 5, 6]]
sage: D = DiGraph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )
sage: D.strongly_connected_components()
(continues on next page)
sage.graphs.base.static_sparse_graph.triangles_count(G)
Return the number of triangles containing 𝑣, for every 𝑣.
INPUT:
• 𝐺– a graph
EXAMPLES:
This module implement a immutable sparse graph backend using the data structure from sage.graphs.base.
static_sparse_graph . It supports both directed and undirected graphs, as well as vertex/edge labels, loops and
multiple edges. As it uses a very compact C structure it should be very small in memory.
As it is a sparse data structure, you can expect it to be very efficient when you need to list the graph’s edge, or those
incident to a vertex, but an adjacency test can be much longer than in a dense data structure (i.e. like in sage.graphs.
base.static_dense_graph )
For an overview of graph data structures in sage, see overview.
class sage.graphs.base.static_sparse_backend.StaticSparseBackend
Bases: sage.graphs.base.c_graph.CGraphBackend
A graph backend for static sparse graphs.
EXAMPLES:
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
sage: D.add_edge(0, 1, None, False)
sage: list(D.iterator_edges(range(9), True))
[(0, 1, None)]
sage: g = graphs.PetersenGraph()
sage: gi = Graph(g, data_structure="static_sparse")
sage: g == gi
True
sage: set(g.edges(sort=False)) == set(gi.edges(sort=False))
True
sage: gi = Graph({ 0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2}}, data_
˓→structure="static_sparse")
sage: G == GI
True
sage: G = graphs.OddGraph(4)
sage: d = G.diameter()
sage: H = G.distance_graph(list(range(d + 1)))
sage: HI = Graph(H, data_structure="static_sparse")
sage: HI.size() == len(HI.edges(sort=False))
True
True
add_edge(u, v, l, directed)
Set edge label. No way.
add_edges(edges, directed)
Set edge label. No way.
add_vertex(v)
Addition of vertices is not available on an immutable graph.
EXAMPLES:
sage: g.add_vertices([1,2,3])
Traceback (most recent call last):
...
ValueError: graph is immutable; please change a copy instead (use function␣
˓→copy())
add_vertices(vertices)
Set edge label. No way.
allows_loops(value=None)
Return whether the graph allows loops
INPUT:
• value – only useful for compatibility with other graph backends, where this method can be used to
define this boolean. This method raises an exception if value is not equal to None.
degree(v, directed)
Return the degree of a vertex
INPUT:
• v – a vertex
• directed – boolean; whether to take into account the orientation of this graph in counting the degree
of v
EXAMPLES:
del_edge(u, v, l, directed)
Set edge label. No way.
del_vertex(v)
Removal of vertices is not available on an immutable graph.
EXAMPLES:
sage: g.delete_vertices([1,2,3])
Traceback (most recent call last):
...
ValueError: graph is immutable; please change a copy instead (use function␣
˓→copy())
get_edge_label(u, v)
Return the edge label for (u, v).
INPUT:
• u,v – two vertices
has_edge(u, v, l)
Return whether this graph has edge (u, v) with label l.
If l is None, return whether this graph has an edge (u, v) with any label.
INPUT:
• u,v – two vertices
• l – a label
has_vertex(v)
Test if the vertex belongs to the graph
INPUT:
• v – a vertex (or not?)
in_degree(v)
Return the in-degree of a vertex
INPUT:
• v – a vertex
EXAMPLES:
iterator_edges(vertices, labels)
Iterate over the graph’s edges.
INPUT:
• vertices – list; only returns the edges incident to at least one vertex of vertices
• labels – boolean; whether to return edge labels too
iterator_in_edges(vertices, labels)
Iterate over the incoming edges incident to a sequence of vertices.
INPUT:
• vertices – a list of vertices
• labels – whether to return labels too
iterator_in_nbrs(v)
Iterate over the in-neighbors of a vertex
INPUT:
• v – a vertex
EXAMPLES:
iterator_nbrs(v)
Iterate over the neighbors of a vertex
INPUT:
• v – a vertex
EXAMPLES:
iterator_out_edges(vertices, labels)
Iterate over the outbound edges incident to a sequence of vertices.
INPUT:
• vertices – a list of vertices
• labels – whether to return labels too
iterator_out_nbrs(v)
Iterate over the out-neighbors of a vertex
INPUT:
• v – a vertex
EXAMPLES:
iterator_unsorted_edges(vertices, labels)
Iterate over the graph’s edges.
INPUT:
• vertices – list; only returns the edges incident to at least one vertex of vertices
• labels – boolean; whether to return edge labels too
iterator_verts(vertices)
Iterate over the vertices
INPUT:
• vertices – a list of objects; the method will only return the elements of the graph which are contained
in vertices. It’s not very efficient. If vertices is equal to None, all the vertices are returned.
multiple_edges(value=None)
Return whether the graph allows multiple edges
INPUT:
• value – only useful for compatibility with other graph backends, where this method can be used to
define this boolean. This method raises an exception if value is not equal to None.
num_edges(directed)
Return the number of edges
INPUT:
• directed – boolean; whether to consider the graph as directed or not.
num_verts()
Return the number of vertices
out_degree(v)
Return the out-degree of a vertex
INPUT:
• v – a vertex
EXAMPLES:
relabel(perm, directed)
Relabel the graphs’ vertices. No way.
set_edge_label(u, v, l, directed)
Set edge label. No way.
class sage.graphs.base.static_sparse_backend.StaticSparseCGraph
Bases: sage.graphs.base.c_graph.CGraph
CGraph class based on the sparse graph data structure static sparse graphs.
add_vertex(k)
Add a vertex to the graph. No way.
del_vertex(k)
Remove a vertex from the graph. No way.
has_arc(u, v)
Test if 𝑢𝑣 is an edge of the graph
INPUT:
• u,v – integers
has_vertex(v)
Test if a vertex belongs to the graph
INPUT:
• n – an integer
in_degree(u)
Return the in-degree of a vertex
INPUT:
• u – a vertex
in_neighbors(u)
Return the in-neighbors of a vertex
INPUT:
• u – a vertex
out_degree(u)
Return the out-degree of a vertex
INPUT:
• u – a vertex
out_neighbors(u)
List the out-neighbors of a vertex
INPUT:
• u – a vertex
verts()
Returns the list of vertices
class sage.graphs.base.graph_backends.GenericGraphBackend
Bases: sage.structure.sage_object.SageObject
A generic wrapper for the backend of a graph.
Various graph classes use extensions of this class. Note, this graph has a number of placeholder functions, so
the doctests are rather silly.
add_edge(u, v, l, directed)
Add an edge (𝑢, 𝑣) to self, with label 𝑙.
If directed is True, this is interpreted as an arc from 𝑢 to 𝑣.
INPUT:
• u,v – vertices
• l – edge label
• directed – boolean
add_edges(edges, directed)
Add a sequence of edges to self.
If directed is True, these are interpreted as arcs.
INPUT:
• edges – list/iterator of edges to be added
• directed – boolean
add_vertex(name)
Add a labelled vertex to self.
INPUT:
• name – vertex label
OUTPUT:
If name=None, the new vertex name is returned, None otherwise.
add_vertices(vertices)
Add labelled vertices to self.
INPUT:
• vertices – iterator of vertex labels; a new label is created, used and returned in the output list for all
None values in vertices
OUTPUT:
Generated names of new vertices if there is at least one None value present in vertices. None otherwise.
EXAMPLES:
sage: G = sage.graphs.base.graph_backends.GenericGraphBackend()
sage: G.add_vertices([1,2,3])
Traceback (most recent call last):
...
NotImplementedError
degree(v, directed)
Return the total number of vertices incident to 𝑣.
INPUT:
• v – a vertex label
• directed – boolean
OUTPUT:
degree of 𝑣
del_edge(u, v, l, directed)
Delete the edge (𝑢, 𝑣) with label 𝑙.
INPUT:
• u,v – vertices
• l – edge label
• directed – boolean
del_vertex(v)
Delete a labelled vertex in self.
INPUT:
• v – vertex label
del_vertices(vertices)
Delete labelled vertices in self.
INPUT:
• vertices – iterator of vertex labels
get_edge_label(u, v)
Return the edge label of (𝑢, 𝑣).
INPUT:
• u,v – vertex labels
OUTPUT:
label of (𝑢, 𝑣)
has_edge(u, v, l)
Check whether self has an edge (𝑢, 𝑣) with label 𝑙.
INPUT:
• u,v – vertex labels
• l – label
OUTPUT:
boolean
has_vertex(v)
Check whether self has a vertex with label 𝑣.
INPUT:
• v – vertex label
OUTPUT: boolean
in_degree(v)
Return the in-degree of 𝑣
INPUT:
• v – a vertex label
iterator_edges(vertices, labels)
Iterate over the edges incident to a sequence of vertices.
Edges are assumed to be undirected.
This method returns an iterator over the edges (𝑢, 𝑣) such that either 𝑢 or 𝑣 is in vertices and the edge
(𝑢, 𝑣) is in self.
INPUT:
OUTPUT: a generator which yields edges, with or without labels depending on the labels parameter.
iterator_in_nbrs(v)
Iterate over the in-neighbors of vertex 𝑣.
This method returns an iterator over the vertices 𝑢 such that the edge (𝑢, 𝑣) is in self (that is, predecessors
of 𝑣).
INPUT:
• v – vertex label
OUTPUT:
a generator which yields vertex labels
iterator_nbrs(v)
Iterate over the vertices adjacent to 𝑣.
This method returns an iterator over the vertices 𝑢 such that either the edge (𝑢, 𝑣) or the edge (𝑣, 𝑢) is in
self (that is, neighbors of 𝑣).
INPUT:
• v – vertex label
OUTPUT:
a generator which yields vertex labels
iterator_out_edges(vertices, labels)
Iterate over the outbound edges incident to a sequence of vertices.
This method returns an iterator over the edges (𝑣, 𝑢) such that 𝑣 is in vertices and the edge (𝑣, 𝑢) is in
self.
INPUT:
• vertices – a list of vertex labels
• labels – boolean
OUTPUT:
a generator which yields edges, with or without labels depending on the labels parameter.
iterator_out_nbrs(v)
Iterate over the out-neighbors of 𝑣.
This method returns an iterator over the vertices 𝑢 such that the edge (𝑣, 𝑢) is in self (that is, successors
of 𝑣).
INPUT:
• v – vertex label
OUTPUT:
a generator which yields vertex labels
iterator_verts(verts)
Iterate over the vertices 𝑣 with labels in verts.
INPUT:
• verts – vertex labels
OUTPUT:
a generator which yields vertices
loops(new=None)
Get/set whether or not self allows loops.
INPUT:
• new – can be a boolean (in which case it sets the value) or None, in which case the current value is
returned. It is set to None by default.
multiple_edges(new=None)
Get/set whether or not self allows multiple edges.
INPUT:
• new – can be a boolean (in which case it sets the value) or None, in which case the current value is
returned. It is set to None by default.
name(new=None)
Get/set name of self.
INPUT:
• new – can be a string (in which case it sets the value) or None, in which case the current value is
returned. It is set to None by default.
num_edges(directed)
Return the number of edges in self
INPUT:
• directed – boolean
num_verts()
Return the number of vertices in self
out_degree(v)
Return the out-degree of 𝑣
INPUT:
• v – a vertex label
relabel(perm, directed)
Relabel the vertices of self by a permutation.
INPUT:
• perm – permutation
• directed – boolean
set_edge_label(u, v, l, directed)
Label the edge (𝑢, 𝑣) by 𝑙.
INPUT:
• u,v – vertices
• l – edge label
• directed – boolean
sage.graphs.base.graph_backends.unpickle_graph_backend(directed, vertices, edges, kwds)
Return a backend from its pickled data
This methods is defined because Python’s pickling mechanism can only build objects from a pair (f,args)
by running f(*args). In particular, there is apparently no way to define a **kwargs (i.e. define the value of
keyword arguments of f), which means that one must know the order of all arguments of f (here, f is Graph or
DiGraph ).
As a consequence, this means that the order cannot change in the future, which is something we cannot swear.
INPUT:
• directed – boolean
• vertices – list of vertices
• edges – list of edges
• kwds – any dictionary whose keywords will be forwarded to the graph constructor
This function builds a Graph or DiGraph from its data, and returns the _backend attribute of this object.
EXAMPLES:
sage: b
<sage.graphs.base.sparse_graph.SparseGraphBackend object at ...>
sage: list(b.iterator_edges(range(4), True))
[(0, 0, 1), (0, 3, 'label')]
Wrapper for a Boost graph. The Boost graphs are Cython C++ variables, and they cannot be converted to Python
objects: as a consequence, only functions defined with cdef are able to create, read, modify, and delete these graphs.
A very important feature of Boost graph library is that all object are generic: for instance, adjacency lists can be stored
using different data structures, and (most of) the functions work with all implementations provided. This feature is
implemented in our interface using fused types: however, Cython’s support for fused types is still experimental, and
some features are missing. For instance, there cannot be nested generic function calls, and no variable can have a
generic type, apart from the arguments of a generic function.
All the input functions use pointers, because otherwise we might have problems with delete().
Basic Boost Graph operations:
3.9.1 Functions
sage.graphs.base.boost_graph.bandwidth_heuristics(g, algorithm='cuthill_mckee')
Use Boost heuristics to approximate the bandwidth of the input graph.
The bandwidth 𝑏𝑤(𝑀 ) of a matrix 𝑀 is the smallest integer 𝑘 such that all non-zero entries of 𝑀 are at distance
𝑘 from the diagonal. The bandwidth 𝑏𝑤(𝑔) of an undirected graph 𝑔 is the minimum bandwidth of the adjacency
matrix of 𝑔, over all possible relabellings of its vertices (for more information, see the bandwidth module).
Unfortunately, exactly computing the bandwidth is NP-hard (and an exponential algorithm is implemented in
Sagemath in routine bandwidth()). Here, we implement two heuristics to find good orderings: Cuthill-McKee,
and King.
This function works only in undirected graphs, and its running time is 𝑂(𝑚𝑑𝑚𝑎𝑥 log 𝑑𝑚𝑎𝑥 ) for the Cuthill-
McKee ordering, and 𝑂(𝑚𝑑2𝑚𝑎𝑥 log 𝑑𝑚𝑎𝑥 ) for the King ordering, where 𝑚 is the number of edges, and 𝑑𝑚𝑎𝑥 is
the maximum degree in the graph.
INPUT:
• g – the input Sage graph
• algorithm – string (default: 'cuthill_mckee'); the heuristic used to compute the ordering among
'cuthill_mckee' and 'king'
OUTPUT:
A pair [bandwidth, ordering], where ordering is the ordering of vertices, bandwidth is the bandwidth of
that specific ordering (which is not necessarily the bandwidth of the graph, because this is a heuristic).
EXAMPLES:
sage.graphs.base.boost_graph.blocks_and_cut_vertices(g)
Compute the blocks and cut vertices of the graph.
This method uses the implementation of Tarjan’s algorithm available in the Boost library .
INPUT:
• g – the input Sage graph
OUTPUT:
A 2-dimensional vector with m+1 rows (m is the number of biconnected components), where each of the first m
rows correspond to vertices in a block, and the last row is the list of cut vertices.
See also:
• sage.graphs.generic_graph.GenericGraph.blocks_and_cut_vertices()
EXAMPLES:
sage: blocks_and_cut_vertices(G)
([[0, 1, 2]], [])
sage.graphs.base.boost_graph.clustering_coeff(g, vertices=None)
Compute the clustering coefficient of the input graph, using Boost.
See also:
sage.graphs.generic_graph.GenericGraph.clustering_coeff()
INPUT:
• g – the input Sage Graph
• vertices – list (default: None); the list of vertices to analyze (if None, compute the clustering coefficient
of all vertices)
OUTPUT: a pair (average_clustering_coefficient, clust_of_v), where
average_clustering_coefficient is the average clustering of the vertices in variable vertices,
clust_of_v is a dictionary that associates to each vertex its clustering coefficient. If vertices is None, all
vertices are considered.
EXAMPLES:
Computing the clustering coefficient of a clique:
sage: g = graphs.IcosahedralGraph()
sage: clustering_coeff(g, vertices=[1,2,3])
(0.5, {1: 0.5, 2: 0.5, 3: 0.5})
With labels:
sage: g.relabel(list("abcdefghiklm"))
sage: clustering_coeff(g, vertices="abde")
(0.5, {'a': 0.5, 'b': 0.5, 'd': 0.5, 'e': 0.5})
This method computes the diameter of undirected graph using the algorithm proposed in [Dragan2018].
This method returns Infinity if graph is not connected.
INPUT:
• g – the input Sage graph
• weight_function – function (default: None); a function that associates a weight to each edge. If None
(default), the weights of g are used, if g.weighted()==True, otherwise all edges have weight 1.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs a number
for each edge
EXAMPLES:
sage: g = graphs.GridGraph([2,2]).dominator_tree((0,0))
sage: g.to_dictionary()
{(0, 0): [(0, 1), (1, 0), (1, 1)], (0, 1): [(0, 0)], (1, 0): [(0, 0)], (1, 1): [(0,␣
˓→0)]}
If the graph is made by two 3-cycles 𝐶1 , 𝐶2 connected by an edge (𝑣, 𝑤), with 𝑣 ∈ 𝐶1 , 𝑤 ∈ 𝐶2 , the cut vertices
are 𝑣 and 𝑤, the biconnected components are 𝐶1 , 𝐶2 , and the edge (𝑣, 𝑤). If the root is in 𝐶1 , the parent of each
vertex in 𝐶1 is the root, the parent of 𝑤 is 𝑣, and the parent of each vertex in 𝐶2 is 𝑤:
sage: G = 2 * graphs.CycleGraph(3)
sage: v = 0
sage: w = 3
sage: G.add_edge(v,w)
sage: G.dominator_tree(1, return_dict=True)
{0: 1, 1: None, 2: 1, 3: 0, 4: 3, 5: 3}
sage: g = digraphs.Circuit(10).dominator_tree(5)
sage: g.to_dictionary()
{0: [1], 1: [2], 2: [3], 3: [4], 4: [], 5: [6], 6: [7], 7: [8], 8: [9], 9: [0]}
sage: g = digraphs.Circuit(10).dominator_tree(5, reverse=True)
sage: g.to_dictionary()
{0: [9], 1: [0], 2: [1], 3: [2], 4: [3], 5: [4], 6: [], 7: [6], 8: [7], 9: [8]}
sage.graphs.base.boost_graph.edge_connectivity(g)
Compute the edge connectivity of the input graph, using Boost.
OUTPUT: a pair (ec, edges), where ec is the edge connectivity, edges is the list of edges in a minimum cut.
See also:
sage.graphs.generic_graph.GenericGraph.edge_connectivity()
EXAMPLES:
Computing the edge connectivity of a clique:
Vertex-labeled graphs:
sage.graphs.base.boost_graph.floyd_warshall_shortest_paths(g, weight_function=None,
distances=True, predecessors=False)
Use Floyd-Warshall algorithm to solve the all-pairs-shortest-paths.
This routine outputs the distance between each pair of vertices and the predecessors matrix (depending on the
values of boolean distances and predecessors) using a dictionary of dictionaries. This method should be
preferred only if the graph is dense. If the graph is sparse the much faster johnson_shortest_paths should be used.
The time-complexity is 𝑂(𝑛3 + 𝑛𝑚), where 𝑛 is the number of nodes and 𝑚 the number of edges. The factor
𝑛𝑚 in the complexity is added only when predecessors is set to True.
INPUT:
• g – the input Sage graph
• weight_function – function (default: None); a function that associates a weight to each edge. If None
(default), the weights of g are used, if g.weighted()==True, otherwise all edges have weight 1.
• distances – boolean (default: True); whether to return the dictionary of shortest distances
• predecessors – boolean (default: False); whether to return the predecessors matrix
OUTPUT:
Depending on the input, this function return the dictionary of predecessors, the dictionary of distances, or a pair
of dictionaries (distances, predecessors) where distance[u][v] denotes the distance of a shortest path
from 𝑢 to 𝑣 and predecessors[u][v] indicates the predecessor of 𝑤 on a shortest path from 𝑢 to 𝑣.
EXAMPLES:
Undirected graphs:
True
Directed graphs:
sage.graphs.base.boost_graph.johnson_closeness_centrality(g, weight_function=None)
Use Johnson algorithm to compute the closeness centrality of all vertices.
This routine is preferable to johnson_shortest_paths() because it does not create a doubly indexed dictio-
nary of distances, saving memory.
The time-complexity is 𝑂(𝑚𝑛 log 𝑛), where 𝑛 is the number of nodes and 𝑚 is the number of edges.
INPUT:
• g – the input Sage graph
• weight_function – function (default: None); a function that associates a weight to each edge. If None
(default), the weights of g are used, if g.weighted()==True, otherwise all edges have weight 1.
OUTPUT:
A dictionary associating each vertex v to its closeness centrality.
EXAMPLES:
Undirected graphs:
Directed graphs:
Directed graphs:
sage: g = Graph([(1, 2, 3), (2, 3, 5), (3, 4, 8), (4, 1, 13), (1, 3, 250), (5, 6,␣
˓→9), (6, 7, 17), (7, 5, 20)])
sage: sorted(g.minimum_cycle_basis(by_weight=True))
[[1, 2, 3], [1, 2, 3, 4], [5, 6, 7]]
sage: sorted(g.minimum_cycle_basis())
[[1, 2, 3], [1, 3, 4], [5, 6, 7]]
See also:
– if weight_function is None and g is not weighted, we set all weights to 1 (hence, the output can be
any spanning tree).
Note that, if the weight is not convertible to a number with function float(), an error is raised (see tests
below).
• algorithm – string (default: 'Kruskal'); the algorithm to use among 'Kruskal' and 'Prim'
OUTPUT:
The edges of a minimum spanning tree of g, if one exists, otherwise the empty list.
See also:
• sage.graphs.generic_graph.GenericGraph.min_spanning_tree()
EXAMPLES:
However, Dijkstra algorithm is more efficient: for this reason, we suggest to use Bellman-Ford only if necessary
(which is also the default option). Note that, if the graph is undirected, a negative edge automatically creates a
negative cycle: for this reason, in this case, Dijkstra algorithm is always better.
The running-time is 𝑂(𝑛 log 𝑛 + 𝑚) for Dijkstra algorithm and 𝑂(𝑚𝑛) for Bellman-Ford algorithm, where 𝑛 is
the number of nodes and 𝑚 is the number of edges.
INPUT:
• g – the input Sage graph
• start – the starting vertex to compute shortest paths
• weight_function – function (default: None); a function that associates a weight to each edge. If None
(default), the weights of g are used, if g.weighted()==True, otherwise all edges have weight 1.
• algorithm – string (default: None); one of the following algorithms:
– 'Dijkstra', 'Dijkstra_Boost': the Dijkstra algorithm implemented in Boost (works only with
positive weights)
– 'Bellman-Ford', 'Bellman-Ford_Boost': the Bellman-Ford algorithm implemented in Boost
(works also with negative weights, if there is no negative cycle)
OUTPUT:
A pair of dictionaries (distances, predecessors) such that, for each vertex v, distances[v] is the dis-
tance from start to v, predecessors[v] is the last vertex in a shortest path from start to v.
EXAMPLES:
Undirected graphs:
Directed graphs:
INPUT:
• g – the input Sage graph
• vertex_list – list (default: None); list of vertices to compute shortest paths from. By default (None),
compute shortest paths from all vertices.
• order – list (default: None); order of vertices of 𝑔
• weight_function – function (default: None); a function that associates a weight to each edge. If None
(default), the weights of g are used, if g.weighted()==True, otherwise all edges have weight 1.
• algorithm – string (default: None); one of the following algorithms:
– 'Dijkstra', 'Dijkstra_Boost' - the Dijkstra algorithm implemented in Boost (works only with
positive weights)
– 'Bellman-Ford', 'Bellman-Ford_Boost' - the Bellman-Ford algorithm implemented in Boost
(works also with negative weights, if there is no negative cycle)
OUTPUT:
The type of output depends on the input. More precisely -
• A pair of dictionaries of list (distances, predecessors), when order is not None, such that for
each vertex v in vertex_list, distances[v][i] store the shortest distance between v and order[i]
and predecessors[v][i] store the last vertex in the shortest path from v to order[i].
• A pair of dictionaries of dictionaries (distances, predecessors) such that for each vertex v
in vertex_list, distances[v] store the shortest distances of all the other vertices from v,
predecessors[v] store the last vertices in the shortest path from v to all the other vertices.
EXAMPLES:
Undirected graphs:
Directed graphs:
sage: n = 10
sage: g = digraphs.Circuit(n)
sage: w = lambda x: (x*x*(x-1))/2
sage: wiener_index(g) == w(n)
True
sage: wiener_index(Graph(1))
0
sage: wiener_index(Graph())
Traceback (most recent call last):
...
ValueError: Wiener index is not defined for the empty graph
FOUR
HYPERGRAPHS
This module implements generators of hypergraphs. All hypergraphs can be built through the hypergraphs object.
For instance, to build a complete 3-uniform hypergraph on 5 points, one can do:
sage: H = hypergraphs.CompleteUniform(5, 3)
To enumerate hypergraphs with certain properties up to isomorphism, one can use method nauty(), which calls
Brendan McKay’s Nauty (http://cs.anu.edu.au/~bdm/nauty/):
class sage.graphs.hypergraph_generators.HypergraphGenerators
Bases: object
A class consisting of constructors for common hypergraphs.
BinomialRandomUniform(n, k, p)
Return a random 𝑘-uniform hypergraph on 𝑛 points, in which each edge is inserted independently with
probability 𝑝.
• n – number of nodes of the graph
• k – uniformity
• p – probability of an edge
EXAMPLES:
921
Graph Theory, Release 9.7
CompleteUniform(n, k)
Return the complete 𝑘-uniform hypergraph on 𝑛 points.
INPUT:
• k,n – nonnegative integers with 𝑘 ≤ 𝑛
EXAMPLES:
UniformRandomUniform(n, k, m)
Return a uniformly sampled 𝑘-uniform hypergraph on 𝑛 points with 𝑚 hyperedges.
• n – number of nodes of the graph
• k – uniformity
• m – number of edges
EXAMPLES:
• max_intersection – integers (default: None); constraints the maximum cardinality of the intersec-
tion of two sets from the hypergraphs.
• connected – boolean (default: False); whether to require the hypergraphs to be connected.
• debug – boolean (default: False); if True the first line of genbgL’s output to standard error is captured
and the first call to the generator’s next() function will return this line as a string. A line leading with
“>A” indicates a successful initiation of the program with some information on the arguments, while
a line beginning with “>E” indicates an error with the input.
• options – string (default: "") – anything else that should be forwarded as input to Nauty’s genbgL.
See its documentation for more information : http://cs.anu.edu.au/~bdm/nauty/.
Note: For genbgL the first class elements are vertices, and second class elements are the hypergraph’s
sets.
OUTPUT:
A tuple of tuples.
EXAMPLES:
Small hypergraphs:
The Fano Plane, as the only 3-uniform hypergraph with 7 sets and 7 vertices:
The Fano Plane, as the only 3-regular hypergraph with 7 sets and 7 vertices:
automorphism_group() Return the subgroup of the automorphism group of the incidence graph which
respects the P B partition. It is (isomorphic to) the automorphism group of the
block design, although the degrees differ.
block_sizes() Return the set of block sizes.
blocks() Return the list of blocks.
canonical_label() Return a canonical label for the incidence structure.
coloring() Compute a (weak) 𝑘-coloring of the hypergraph
complement() Return the complement of the incidence structure.
copy() Return a copy of the incidence structure.
degree() Return the degree of a point p (or a set of points).
degrees() Return the degree of all sets of given size, or the degree of all points.
dual() Return the dual of the incidence structure.
edge_coloring() Compute a proper edge-coloring.
ground_set() Return the ground set (i.e the list of points).
incidence_graph() Return the incidence graph of the incidence structure
incidence_matrix() Return the incidence matrix 𝐴 of the design. A is a (𝑣 × 𝑏) matrix defined by:
A[i,j] = 1 if i is in block B_j and 0 otherwise.
induced_substructure() Return the substructure induced by a set of points.
intersection_graph() Return the intersection graph of the incidence structure.
is_berge_cyclic() Check whether self is a Berge-Cyclic uniform hypergraph.
is_connected() Test whether the design is connected.
is_generalized_quadrangle()Test if the incidence structure is a generalized quadrangle.
is_isomorphic() Return whether the two incidence structures are isomorphic.
is_regular() Test whether the incidence structure is 𝑟-regular.
is_resolvable() Test whether the hypergraph is resolvable
is_simple() Test whether this design is simple (i.e. no repeated block).
is_spread() Check whether the input is a spread for self.
is_t_design() Test whether self is a 𝑡 − (𝑣, 𝑘, 𝑙) design.
is_uniform() Test whether the incidence structure is 𝑘-uniform
Iterates over all copies of H2 contained in self.
isomorphic_substructures_iterator()
num_blocks() Return the number of blocks.
num_points() Return the size of the ground set.
packing() Return a maximum packing
rank() Return the rank of the hypergraph (the maximum size of a block).
relabel() Relabel the ground set
trace() Return the trace of a set of points.
REFERENCES:
AUTHORS:
• Peter Dobcsanyi and David Joyner (2007-2008)
This is a significantly modified form of part of the module block_design.py (version 0.6) written by Peter Dobc-
sanyi [email protected].
1 Block designs and incidence structures from wikipedia, Wikipedia article Block_design Wikipedia article Incidence_structure
2 E. Assmus, J. Key, Designs and their codes, CUP, 1992.
4.2.1 Methods
Note: The following syntax, where points is omitted, automatically defines the ground set as the union
of the blocks:
sage: H = IncidenceStructure([['a','b','c'],['c','d','e']])
sage: sorted(H.ground_set())
['a', 'b', 'c', 'd', 'e']
• blocks – (i.e. edges, i.e. sets) the blocks defining the incidence structure. Can be any iterable.
• incidence_matrix – a binary incidence matrix. Each column represents a set.
• name (a string, such as “Fano plane”).
• check – whether to check the input
• copy – (use with caution) if set to False then blocks must be a list of lists of integers. The list will not
be copied but will be modified in place (each block is sorted, and the whole list is sorted). Your blocks
object will become the IncidenceStructure instance’s internal data.
EXAMPLES:
An incidence structure can be constructed by giving the number of points and the list of blocks:
Only providing the set of blocks is sufficient. In this case, the ground set is defined as the union of the blocks:
sage: IncidenceStructure([[1,2,3],[2,3,4]])
Incidence structure with 4 points and 2 blocks
Or by its adjacency matrix (a {0, 1}-matrix in which rows are indexed by points and columns by blocks):
sage: m = matrix([[0,1,0],[0,0,1],[1,0,1],[1,1,1]])
sage: IncidenceStructure(m)
Incidence structure with 4 points and 3 blocks
sage: V = [(0,'a'),(0,'b'),(1,'a'),(1,'b')]
sage: B = [(V[0],V[1],V[2]), (V[1],V[2]), (V[0],V[2])]
sage: I = IncidenceStructure(V, B)
sage: I.ground_set()
[(0, 'a'), (0, 'b'), (1, 'a'), (1, 'b')]
sage: I.blocks()
[[(0, 'a'), (0, 'b'), (1, 'a')], [(0, 'a'), (1, 'a')], [(0, 'b'), (1, 'a')]]
The order of the points and blocks does not matter as they are sorted on input (see trac ticket #11333):
If you care for speed, you can set copy to False, but in that case, your input must be a list of lists and the ground
set must be 0, ..., 𝑣 − 1:
automorphism_group()
Return the subgroup of the automorphism group of the incidence graph which respects the P B partition.
It is (isomorphic to) the automorphism group of the block design, although the degrees differ.
EXAMPLES:
sage: P = designs.DesarguesianProjectivePlaneDesign(2); P
(7,3,1)-Balanced Incomplete Block Design
sage: G = P.automorphism_group()
sage: G.is_isomorphic(PGL(3,2))
True
sage: G
Permutation Group with generators [...]
sage: G.cardinality()
168
block_sizes()
Return the set of block sizes.
EXAMPLES:
sage: BD.block_sizes()
[3, 3, 3, 3, 3, 3, 3]
blocks()
Return the list of blocks.
EXAMPLES:
sage: BD = IncidenceStructure(7,[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,
˓→6],[2,4,5]])
sage: BD.blocks()
[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]]
canonical_label()
Return a canonical label for the incidence structure.
A canonical label is relabeling of the points into integers {0, ..., 𝑛 − 1} such that isomorphic incidence
structures are relabelled to equal objects.
EXAMPLES:
A weak coloring of a hypergraph ℋ is an assignment of colors to its vertices such that no set is monochro-
matic.
INPUT:
• k (integer) – compute a coloring with 𝑘 colors if an integer is provided, otherwise returns an optimal
coloring (i.e. with the minimum possible number of colors).
• solver – (default: None) Specify a Mixed Integer Linear Programming (MILP) solver to be used. If
set to None, the default one is used. For more information on MILP solvers and which default solver
is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – non-negative integer (default: 0). Set the level of verbosity you want from the linear
program solver. Since the problem is 𝑁 𝑃 -complete, its solving may take some time depending on the
graph. A value of 0 means that there will be no message printed by the solver.
• integrality_tolerance – parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
EXAMPLES:
The Fano plane has chromatic number 3:
sage: len(designs.steiner_triple_system(7).coloring())
3
The chromatic number of a graph is equal to the chromatic number of its 2-uniform corresponding hyper-
graph:
sage: g = graphs.PetersenGraph()
sage: H = IncidenceStructure(g.edges(sort=True, labels=False))
sage: len(g.coloring())
3
sage: len(H.coloring())
3
complement(uniform=False)
Return the complement of the incidence structure.
Two different definitions of “complement” are made available, according to the value of uniform.
INPUT:
• uniform (boolean) –
– if set to False (default), returns the incidence structure whose blocks are the complements of all
blocks of the incidence structure.
– If set to True and the incidence structure is 𝑘-uniform, returns the incidence structure whose
blocks are all 𝑘-sets of the ground set that do not appear in self.
EXAMPLES:
The complement of a BalancedIncompleteBlockDesign is also a 2-design:
sage: g = graphs.PetersenGraph()
sage: G = IncidenceStructure(g.edges(sort=True, labels=False))
sage: H = G.complement(uniform=True)
sage: h = Graph(H.blocks())
sage: g == h
False
sage: g == h.complement()
True
copy()
Return a copy of the incidence structure.
EXAMPLES:
sage: IS = IncidenceStructure([[1,2,3,"e"]],name="Test")
sage: IS
Incidence structure with 4 points and 1 blocks
sage: copy(IS)
Incidence structure with 4 points and 1 blocks
sage: [1, 2, 3, 'e'] in copy(IS)
True
sage: copy(IS)._name
'Test'
degree(p=None, subset=False)
Return the degree of a point p (or a set of points).
The degree of a point (or set of points) is the number of blocks that contain it.
INPUT:
• p – a point (or a set of points) of the incidence structure.
• subset (boolean) – whether to interpret the argument as a set of point (subset=True) or as a point
(subset=False, default).
EXAMPLES:
sage: designs.steiner_triple_system(9).degree(3)
4
sage: designs.steiner_triple_system(9).degree({1,2},subset=True)
1
degrees(size=None)
Return the degree of all sets of given size, or the degree of all points.
The degree of a point (or set of point) is the number of blocks that contain it.
INPUT:
• size (integer) – return the degree of all subsets of points of cardinality size. When size=None, the
function outputs the degree of all points.
Note: When size=None the output is indexed by the points. When size=1 it is indexed by tuples of
size 1. This is the same information, stored slightly differently.
OUTPUT:
A dictionary whose values are degrees and keys are either:
• the points of the incidence structure if size=None (default)
• the subsets of size size of the points stored as tuples
EXAMPLES:
sage: IncidenceStructure([[1,2,3],[1,4]]).degrees(2)
{(1, 2): 1, (1, 3): 1, (1, 4): 1, (2, 3): 1, (2, 4): 0, (3, 4): 0}
dual(algorithm=None)
Return the dual of the incidence structure.
INPUT:
• algorithm – whether to use Sage’s implementation (algorithm=None, default) or use GAP’s
(algorithm="gap").
Note: The algorithm="gap" option requires GAP’s Design package (included in the
gap_packages Sage spkg).
EXAMPLES:
The dual of a projective plane is a projective plane:
sage: PP = designs.DesarguesianProjectivePlaneDesign(4)
sage: PP.dual().is_t_design(return_parameters=True)
(True, (2, 21, 5, 1))
REFERENCE:
• Soicher, Leonard, Design package manual, available at https://www.gap-system.org/Manuals/pkg/
design/htm/CHAP003.htm
edge_coloring()
Compute a proper edge-coloring.
A proper edge-coloring is an assignment of colors to the sets of the incidence structure such that two sets
with non-empty intersection receive different colors. The coloring returned minimizes the number of colors.
OUTPUT:
A partition of the sets into color classes.
EXAMPLES:
sage: H = Hypergraph([{1,2,3},{2,3,4},{3,4,5},{4,5,6}]); H
Incidence structure with 6 points and 4 blocks
sage: C = H.edge_coloring()
sage: C # random
[[[3, 4, 5]], [[2, 3, 4]], [[4, 5, 6], [1, 2, 3]]]
sage: Set(map(Set,sum(C,[]))) == Set(map(Set,H.blocks()))
True
ground_set()
Return the ground set (i.e the list of points).
EXAMPLES:
incidence_graph(labels=False)
Return the incidence graph of the incidence structure
A point and a block are adjacent in this graph whenever they are incident.
INPUT:
• labels (boolean) – whether to return a graph whose vertices are integers, or labelled elements.
– labels is False (default) – in this case the first vertices of the graphs are the elements of
ground_set(), and appear in the same order. Similarly, the following vertices represent the
elements of blocks(), and appear in the same order.
– labels is True, the points keep their original labels, and the blocks are Set objects.
Note that the labelled incidence graph can be incorrect when blocks are repeated, and on some
(rare) occasions when the elements of ground_set() mix Set() and non-Set objects.
EXAMPLES:
sage: BD.incidence_graph()
Bipartite graph on 14 vertices
sage: A = BD.incidence_matrix()
sage: Graph(block_matrix([[A*0,A],[A.transpose(),A*0]])) == BD.incidence_graph()
True
incidence_matrix()
Return the incidence matrix 𝐴 of the design. A is a (𝑣 × 𝑏) matrix defined by: A[i,j] = 1 if i is in block
B_j and 0 otherwise.
EXAMPLES:
sage: BD.block_sizes()
[3, 3, 3, 3, 3, 3, 3]
sage: BD.incidence_matrix()
[1 1 1 0 0 0 0]
(continues on next page)
induced_substructure(points)
Return the substructure induced by a set of points.
The substructure induced in ℋ by a set 𝑋 ⊆ 𝑉 (ℋ) of points is the incidence structure ℋ𝑋 defined on 𝑋
whose sets are all 𝑆 ∈ ℋ such that 𝑆 ⊆ 𝑋.
INPUT:
• points – a set of points.
Note: This method goes over all sets of self before building a new IncidenceStructure (which
involves some relabelling and sorting). It probably should not be called in a performance-critical code.
EXAMPLES:
A Fano plane with one point removed:
sage: F = designs.steiner_triple_system(7)
sage: F.induced_substructure([0..5])
Incidence structure with 6 points and 4 blocks
intersection_graph(sizes=None)
Return the intersection graph of the incidence structure.
The vertices of this graph are the blocks() of the incidence structure. Two of them are adjacent if the size
of their intersection belongs to the set sizes.
INPUT:
• sizes – a list/set of integers. For convenience, setting sizes to 5 has the same effect as sizes=[5].
When set to None (default), behaves as sizes=PositiveIntegers().
EXAMPLES:
The intersection graph of a balanced_incomplete_block_design() is a strongly regular graph
(when it is not trivial):
is_berge_cyclic()
Check whether self is a Berge-Cyclic uniform hypergraph.
A 𝑘-uniform Berge cycle (named after Claude Berge) of length ℓ is a cyclic list of distinct 𝑘-sets 𝐹1 , . . . , 𝐹ℓ ,
ℓ > 1, and distinct vertices 𝐶 = {𝑣1 , . . . , 𝑣ℓ } such that for each 1 ≤ 𝑖 ≤ ℓ, 𝐹𝑖 contains 𝑣𝑖 and 𝑣𝑖+1 (where
𝑣𝑙+1 = 𝑣1 ).
A uniform hypergraph is Berge-cyclic if its incidence graph is cyclic. It is called “Berge-acyclic” otherwise.
For more information, see [Fag1983] and Wikipedia article Hypergraph.
EXAMPLES:
is_connected()
Test whether the design is connected.
EXAMPLES:
is_generalized_quadrangle(verbose=False, parameters=False)
Test if the incidence structure is a generalized quadrangle.
An incidence structure is a generalized quadrangle iff (see [BH2012], section 9.6):
• two blocks intersect on at most one point.
• For every point 𝑝 not in a block 𝐵, there is a unique block 𝐵 ′ intersecting both {𝑝} and 𝐵
It is a regular generalized quadrangle if furthermore:
• it is 𝑠 + 1-uniform for some positive integer 𝑠.
• it is 𝑡 + 1-regular for some positive integer 𝑡.
For more information, see the Wikipedia article Generalized_quadrangle.
Note: Some references (e.g. [PT2009] or Wikipedia article Generalized_quadrangle) only allow regular
generalized quadrangles. To use such a definition, see the parameters optional argument described below,
or the methods is_regular() and is_uniform().
INPUT:
• verbose (boolean) – whether to print an explanation when the instance is not a generalized quadrangle.
• parameters (boolean; False) – if set to True, the function returns a pair (s,t) instead of True
answers. In this case, 𝑠 and 𝑡 are the integers defined above if they exist (each can be set to False
otherwise).
EXAMPLES:
sage: h = designs.CremonaRichmondConfiguration()
sage: h.is_generalized_quadrangle()
True
sage: h.is_generalized_quadrangle(parameters=True)
(2, 2)
is_isomorphic(other, certificate=False)
Return whether the two incidence structures are isomorphic.
INPUT:
• other – an incidence structure.
• certificate (boolean) – whether to return an isomorphism from self to other instead of a boolean
answer.
EXAMPLES:
is_regular(r=None)
Test whether the incidence structure is 𝑟-regular.
An incidence structure is said to be 𝑟-regular if all its points are incident with exactly 𝑟 blocks.
INPUT:
• r (integer)
OUTPUT:
If r is defined, a boolean is returned. If r is set to None (default), the method returns either False or the
integer r such that the incidence structure is 𝑟-regular.
Warning: In case of 0-regular incidence structure, beware that if not H.is_regular() is a satis-
fied condition.
EXAMPLES:
sage: designs.balanced_incomplete_block_design(7,3).is_regular()
3
sage: designs.balanced_incomplete_block_design(7,3).is_regular(r=3)
True
sage: designs.balanced_incomplete_block_design(7,3).is_regular(r=4)
False
Note: This problem is solved using an Integer Linear Program, and GLPK (the default LP solver) has been
reported to be very slow on some instances. If you hit this wall, consider installing a more powerful MILP
INPUT:
• certificate (boolean) – whether to return the classes along with the binary answer (see examples
below).
• solver – (default: None) Specify a Mixed Integer Linear Programming (MILP) solver to be used. If
set to None, the default one is used. For more information on MILP solvers and which default solver
is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0). Sets the level of verbosity. Set to 0 by default, which means quiet.
• check (boolean) – whether to check that output is correct before returning it. As this is expected to be
useless (but we are cautious guys), you may want to disable it whenever you want speed. Set to True
by default.
• integrality_tolerance – parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
EXAMPLES:
Some resolvable designs:
sage: TD = designs.transversal_design(2,2,resolvable=True)
sage: TD.is_resolvable()
True
sage: AG = designs.AffineGeometryDesign(3,1,GF(2))
sage: AG.is_resolvable()
True
Their classes:
A non-resolvable design:
is_simple()
Test whether this design is simple (i.e. no repeated block).
EXAMPLES:
sage: V = [(0,'a'),(0,'b'),(1,'a'),(1,'b')]
sage: B = [[V[0],V[1]], [V[1],V[2]]]
sage: I = IncidenceStructure(V, B)
sage: I.is_simple()
True
sage: I2 = IncidenceStructure(V, B*2)
sage: I2.is_simple()
False
is_spread(spread)
Check whether the input is a spread for self.
A spread of an incidence structure (𝑃, 𝐵) is a subset of 𝐵 which forms a partition of 𝑃 .
INPUT:
• spread – iterable; defines the spread
EXAMPLES:
False
Steiner triple and quadruple systems are other names for 2 − (𝑣, 3, 1) and 3 − (𝑣, 4, 1) designs:
Further examples:
sage: D = IncidenceStructure(4,[[],[]])
sage: D.is_t_design(return_parameters=True)
(True, (0, 4, 0, 2))
sage: D = IncidenceStructure(4,[[0,1],[2,3]])
sage: D.is_t_design(return_parameters=True)
(True, (1, 4, 2, 1))
is_uniform(k=None)
Test whether the incidence structure is 𝑘-uniform
An incidence structure is said to be 𝑘-uniform if all its blocks have size 𝑘.
INPUT:
• k (integer)
OUTPUT:
If k is defined, a boolean is returned. If k is set to None (default), the method returns either False or the
integer k such that the incidence structure is 𝑘-uniform.
Warning: In case of 0-uniform incidence structure, beware that if not H.is_uniform() is a sat-
isfied condition.
EXAMPLES:
sage: designs.balanced_incomplete_block_design(7,3).is_uniform()
3
sage: designs.balanced_incomplete_block_design(7,3).is_uniform(k=3)
True
sage: designs.balanced_incomplete_block_design(7,3).is_uniform(k=4)
False
isomorphic_substructures_iterator(H2, induced=False)
Iterates over all copies of H2 contained in self.
A hypergraph 𝐻1 contains an isomorphic copy of a hypergraph 𝐻2 if there exists an injection 𝑓 : 𝑉 (𝐻2 ) ↦→
𝑉 (𝐻1 ) such that for any set 𝑆2 ∈ 𝐸(𝐻2 ) the set 𝑆1 = 𝑓 (𝑆2) belongs to 𝐸(𝐻1 ).
It is an induced copy if no other set of 𝐸(𝐻1 ) is contained in 𝑓 (𝑉 (𝐻2 )), i.e. |𝐸(𝐻2 )| = {𝑆 : 𝑆 ∈
𝐸(𝐻1 ) and 𝑓 (𝑉 (𝐻2 ))}.
This function lists all such injections. In particular, the number of copies of 𝐻 in itself is equal to the size
of its automorphism group.
See subhypergraph_search for more information.
INPUT:
• H2 an IncidenceStructure object.
• induced (boolean) – whether to require the copies to be induced. Set to False by default.
EXAMPLES:
How many distinct 𝐶5 in Petersen’s graph ?
sage: P = graphs.PetersenGraph()
sage: C = graphs.CycleGraph(5)
sage: IP = IncidenceStructure(P.edges(sort=True, labels=False))
sage: IC = IncidenceStructure(C.edges(sort=True, labels=False))
sage: sum(1 for _ in IP.isomorphic_substructures_iterator(IC))
120
As the automorphism group of 𝐶5 has size 10, the number of distinct unlabelled copies is 12. Let us check
that all functions returned correspond to an actual 𝐶5 subgraph:
sage: H = designs.projective_plane(3)
sage: sum(1 for _ in H.isomorphic_substructures_iterator(H))
5616
(continues on next page)
num_blocks()
Return the number of blocks.
EXAMPLES:
sage: designs.DesarguesianProjectivePlaneDesign(2).num_blocks()
7
sage: B = IncidenceStructure(4, [[0,1],[0,2],[0,3],[1,2], [1,2,3]])
sage: B.num_blocks()
5
num_points()
Return the size of the ground set.
EXAMPLES:
sage: designs.DesarguesianProjectivePlaneDesign(2).num_points()
7
sage: B = IncidenceStructure(4, [[0,1],[0,2],[0,3],[1,2], [1,2,3]])
sage: B.num_points()
4
sage: P = IncidenceStructure([[1,2],[3,4],[2,3]]).packing()
sage: sorted(sorted(b) for b in P)
[[1, 2], [3, 4]]
sage: len(designs.steiner_triple_system(9).packing())
3
rank()
Return the rank of the hypergraph (the maximum size of a block).
EXAMPLES:
relabel(perm=None, inplace=True)
Relabel the ground set
INPUT:
• perm – can be one of
– a dictionary – then each point p (which should be a key of d) is relabeled to d[p]
– a list or a tuple of length n – the first point returned by ground_set() is relabeled to l[0], the
second to l[1], . . .
– None – the incidence structure is relabeled to be on {0, 1, ..., 𝑛 − 1} in the ordering given by
ground_set().
• inplace – If True then return a relabeled graph and does not touch self (default is False).
EXAMPLES:
sage: TD=designs.transversal_design(5,5)
sage: TD.relabel({i:chr(97+i) for i in range(25)})
sage: TD.ground_set()
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
˓→ 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y']
sage: TD.blocks()[:3]
[['a', 'f', 'k', 'p', 'u'], ['a', 'g', 'm', 's', 'y'], ['a', 'h', 'o', 'q', 'x
˓→']]
sage: TD.relabel()
sage: TD.blocks()[:3]
[[0, 5, 10, 15, 20], [0, 6, 12, 18, 24], [0, 7, 14, 16, 23]]
Note: This method goes over all sets of self before building a new IncidenceStructure (which
involves some relabelling and sorting). It probably should not be called in a performance-critical code.
EXAMPLES:
A Baer subplane of order 2 (i.e. a Fano plane) in a projective plane of order 4:
sage: P4 = designs.projective_plane(4)
sage: F = designs.projective_plane(2)
sage: for x in Subsets(P4.ground_set(),7):
....: if P4.trace(x,min_size=2).is_isomorphic(F):
....: break
sage: subplane = P4.trace(x,min_size=2); subplane
Incidence structure with 7 points and 7 blocks
sage: subplane.is_isomorphic(F)
True
FIVE
LIBRARIES OF ALGORITHMS
This module gathers all methods related to graph coloring. Here is what it can do :
Proper vertex coloring
Fractional relaxations
Other colorings
AUTHORS:
• Tom Boothby (2008-02-21): Initial version
• Carlo Hamalainen (2009-03-28): minor change: switch to C++ DLX solver
• Nathann Cohen (2009-10-24): Coloring methods using linear programming
943
Graph Theory, Release 9.7
5.1.1 Methods
class sage.graphs.graph_coloring.Test
Bases: object
This class performs randomized testing for all_graph_colorings.
Since everything else in this file is derived from all_graph_colorings, this is a pretty good randomized tester for
the entire file. Note that for a graph 𝐺, G.chromatic_polynomial() uses an entirely different algorithm, so
we provide a good, independent test.
random(tests=1000)
Call self.random_all_graph_colorings().
In the future, if other methods are added, it should call them, too.
random_all_graph_colorings(tests=2)
Verify the results of all_graph_colorings() in three ways:
1. all colorings are unique
2. number of m-colorings is 𝑃 (𝑚) (where 𝑃 is the chromatic polynomial of the graph being tested)
3. colorings are valid – that is, that no two vertices of the same color share an edge.
sage.graphs.graph_coloring.acyclic_edge_coloring(g, hex_colors=False, value_only=False, k=0,
solver=None, verbose=0,
integrality_tolerance=0.001)
Compute an acyclic edge coloring of the current graph.
An edge coloring of a graph is a assignment of colors to the edges of a graph such that :
• the coloring is proper (no adjacent edges share a color)
• For any two colors 𝑖, 𝑗, the union of the edges colored with 𝑖 or 𝑗 is a forest.
The least number of colors such that such a coloring exists for a graph 𝐺 is written 𝜒′𝑎 (𝐺), also called the acyclic
chromatic index of 𝐺.
It is conjectured that this parameter cannot be too different from the obvious lower bound ∆(𝐺) ≤ 𝜒′𝑎 (𝐺), ∆(𝐺)
being the maximum degree of 𝐺, which is given by the first of the two constraints. Indeed, it is conjectured that
∆(𝐺) ≤ 𝜒′𝑎 (𝐺) ≤ ∆(𝐺) + 2.
INPUT:
• hex_colors – boolean (default: False):
– If hex_colors = True, the function returns a dictionary associating to each color a list of edges
(meant as an argument to the edge_colors keyword of the plot method).
– If hex_colors = False (default value), returns a list of graphs corresponding to each color class.
• value_only – boolean (default: False):
– If value_only = True, only returns the acyclic chromatic index as an integer value
– If value_only = False, returns the color classes according to the value of hex_colors
• k – integer; the number of colors to use.
– If k > 0, computes an acyclic edge coloring using 𝑘 colors.
– If k = 0 (default), computes a coloring of 𝐺 into ∆(𝐺) + 2 colors, which is the conjectured general
bound.
– If k = None, computes a decomposition using the least possible number of colors.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver is
used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
ALGORITHM:
Linear Programming
EXAMPLES:
The complete graph on 8 vertices cannot be acyclically edge-colored with less ∆ + 1 colors, but it can be colored
with ∆ + 2 = 9:
True
If one wants to acyclically color a cycle on 4 vertices, at least 3 colors will be necessary. The function raises an
exception when asked to color it with only 2:
sage: g = graphs.CycleGraph(4)
sage: acyclic_edge_coloring(g, k=2)
Traceback (most recent call last):
...
ValueError: this graph cannot be colored with the given number of colors
INPUT:
• G – a graph
• n – a positive integer; the number of colors
• count_only – boolean (default: False); when set to True, it returns 1 for each coloring
• hex_colors – boolean (default: False); when set to False, colors are labeled [0, 1, . . . , 𝑛 − 1], otherwise
the RGB Hex labeling is used
• vertex_color_dict – boolean (default: False); when set to True, it returns a dictionary {vertex:
color}, otherwise it returns a dictionary {color: [list of vertices]}
Warning: This method considers only colorings using exactly 𝑛 colors, even if a coloring using fewer colors
can be found.
Note: This method computes a b-coloring that uses at MOST 𝑘 colors. If this method returns a value equal to
𝑘, it cannot be assumed that 𝑘 is equal to 𝜒𝑏 (𝐺). Meanwhile, if it returns any value 𝑘 ′ < 𝑘, this is a certificate
that the Grundy number of the given graph is 𝑘 ′ .
As 𝜒𝑏 (𝐺) ≤ 𝑚(𝐺), it can be assumed that 𝜒𝑏 (𝐺) = 𝑘 if b_coloring(g, k) returns 𝑘 when 𝑘 = 𝑚(𝐺).
INPUT:
• k – integer; maximum number of colors
• value_only – boolean (default: True); when set to True, only the number of colors is returned. Other-
wise, the pair (nb_colors, coloring) is returned, where coloring is a dictionary associating its color
(integer) to each vertex of the graph.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver is
used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
ALGORITHM:
Integer Linear Program.
EXAMPLES:
The b-chromatic number of a 𝑃5 is equal to 3:
sage: g = graphs.PetersenGraph()
sage: b_coloring(g, 5)
3
It would have been sufficient to set the value of k to 4 in this case, as 4 = 𝑚(𝐺).
sage.graphs.graph_coloring.chromatic_number(G)
Return the chromatic number of the graph.
The chromatic number is the minimal number of colors needed to color the vertices of the graph 𝐺.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.chromatic_number()
3
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
OUTPUT:
In the following, ∆ is equal to the maximum degree in the graph g.
• If vizing=True and value_only=False, return a partition of the edge set into ∆ + 1 matchings.
• If vizing=False and value_only=True, return the chromatic index.
• If vizing=False and value_only=False, return a partition of the edge set into the minimum number
of matchings.
• If vizing=True and value_only=True, should return something, but mainly you are just trying to com-
pute the maximum degree of the graph, and this is not the easiest way. By Vizing’s theorem, a graph has a
chromatic index equal to ∆ or to ∆ + 1.
Note: In a few cases, it is possible to find very quickly the chromatic index of a graph, while it remains a tedious
job to compute a corresponding coloring. For this reason, value_only = True can sometimes be much faster,
and it is a bad idea to compute the whole coloring if you do not need it !
See also:
EXAMPLES:
The Petersen graph has chromatic index 4:
The chromatic index of a non connected graph is the maximum over its connected components:
Such that :
∑︁
∀𝑀 matching ⊆ 𝐺, 𝑟𝑣 ≤ 1
𝑒∈𝑀
INPUT:
• G – a graph
• solver – (default: "PPL"); specify a Linear Program (LP) solver to be used. If set to None, the default
one is used. For more information on LP solvers and which default solver is used, see the method solve
of the class MixedIntegerLinearProgram.
Note: The default solver used here is "PPL" which provides exact results, i.e. a rational number, although
this may be slower that using other solvers. Be aware that this method may loop endlessly when using some
non exact solvers as reported in trac ticket #23658 and trac ticket #23798.
• verbose_constraints – boolean (default: False); whether to display which constraints are being gen-
erated
• verbose – integer (default: 0); sets the level of verbosity of the LP solver
EXAMPLES:
The fractional chromatic index of a 𝐶5 is 5/2:
sage: g = graphs.CycleGraph(5)
sage: g.fractional_chromatic_index()
5/2
Such that :
∑︁
∀𝑣 ∈ 𝑉 (𝐺), 𝑥𝑣 ≥ 1
𝐼∈ℐ(𝐺), 𝑣∈𝐼
∀𝐼 ∈ ℐ(𝐺), 𝑥𝐼 ≥ 0
where ℐ(𝐺) is the set of maximal independent sets of 𝐺 (see Section 2.1 of [CFKPR2010] to know why it
is sufficient to consider maximal independent sets). As optional optimisations, we construct the LP on each
biconnected component of 𝐺 (and output the maximum value), and avoid using the LP if G is bipartite (as then
the output must be 1 or 2).
Note: Computing the fractional chromatic number can be very slow. Since the variables of the LP are indepen-
dent sets, in general the LP has size exponential in the order of the graph. In the current implementation a list of
all maximal independent sets is created and stored, which can be both slow and memory-hungry.
INPUT:
• G – a graph
• solver – (default: "PPL"); specify a Linear Program (LP) solver to be used. If set to None, the default
one is used. For more information on LP solvers and which default solver is used, see the method solve
of the class MixedIntegerLinearProgram.
Note: The default solver used here is "PPL" which provides exact results, i.e. a rational number, although
this may be slower that using other solvers.
• verbose – integer (default: 0); sets the level of verbosity of the LP solver
• check_components – boolean (default: True); whether the method is called on each biconnected com-
ponent of 𝐺
• check_bipartite – boolean (default: True); whether the graph is checked for bipartiteness. If the graph
is bipartite then we can avoid creating and solving the LP.
EXAMPLES:
The fractional chromatic number of a 𝐶5 is 5/2:
sage: g = graphs.CycleGraph(5)
sage: g.fractional_chromatic_number()
5/2
Note: This method computes a grundy coloring using at MOST 𝑘 colors. If this method returns a value equal
to 𝑘, it cannot be assumed that 𝑘 is equal to Γ(𝐺). Meanwhile, if it returns any value 𝑘 ′ < 𝑘, this is a certificate
that the Grundy number of the given graph is 𝑘 ′ .
As Γ(𝐺) ≤ ∆(𝐺) + 1, it can also be assumed that Γ(𝐺) = 𝑘 if grundy_coloring(g, k) returns 𝑘 when
𝑘 = ∆(𝐺) + 1.
INPUT:
• k – integer; maximum number of colors
• value_only – boolean (default: True); when set to True, only the number of colors is returned. Other-
wise, the pair (nb_colors, coloring) is returned, where coloring is a dictionary associating its color
(integer) to each vertex of the graph.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver is
used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
ALGORITHM:
Integer Linear Program.
EXAMPLES:
The Grundy number of a 𝑃4 is equal to 3:
sage: g = graphs.PetersenGraph()
sage: grundy_coloring(g, 5)
4
It would have been sufficient to set the value of k to 4 in this case, as 4 = ∆(𝐺) + 1.
sage.graphs.graph_coloring.linear_arboricity(g, plus_one=None, hex_colors=False, value_only=False,
solver=None, verbose=0, integrality_tolerance=0.001)
Compute the linear arboricity of the given graph.
The linear arboricity of a graph 𝐺 is the least number 𝑙𝑎(𝐺) such that the edges of 𝐺 can be partitioned into
linear forests (i.e. into forests of paths).
⌈︁ ⌉︁
Obviously, 𝑙𝑎(𝐺) ≥ Δ(𝐺) 2 .
⌈︁ ⌉︁
It is conjectured in [Aki1980] that 𝑙𝑎(𝐺) ≤ Δ(𝐺)+1
2 .
INPUT:
⌈︁ ⌉︁ ⌈︁ ⌉︁
• plus_one – integer (default: None); whether to use Δ(𝐺) 2 or Δ(𝐺)+1
2 colors.
⌈︁ ⌉︁
– If 0, computes a decomposition of 𝐺 into Δ(𝐺)2 forests of paths
⌈︁ ⌉︁
– If 1, computes a decomposition of 𝐺 into Δ(𝐺)+12 colors, which is the conjectured general bound.
– If plus_one = None (default), computes a decomposition using the least possible number of colors.
• hex_colors – boolean (default: False):
– If hex_colors = True, the function returns a dictionary associating to each color a list of edges
(meant as an argument to the edge_colors keyword of the plot method).
– If hex_colors = False (default value), returns a list of graphs corresponding to each color class.
• value_only – boolean (default: False):
– If value_only = True, only returns the linear arboricity as an integer value.
– If value_only = False, returns the color classes according to the value of hex_colors
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver is
used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
ALGORITHM:
Linear Programming
COMPLEXITY:
NP-Hard
EXAMPLES:
Obviously, a square grid has a linear arboricity of 2, as the set of horizontal lines and the set of vertical lines are
an admissible partition:
Of maximum degree 2:
sage.graphs.graph_coloring.number_of_n_colorings(G, n)
Compute the number of 𝑛-colorings of a graph
INPUT:
• G – a graph
• n – a positive integer; the number of colors
EXAMPLES:
sage.graphs.graph_coloring.numbers_of_colorings(G)
Compute the number of colorings of a graph.
Return the number of 𝑛-colorings of the graph 𝐺 for all 𝑛 from 0 to |𝑉 |.
EXAMPLES:
sage.graphs.graph_coloring.round_robin(n)
Compute a round-robin coloring of the complete graph on 𝑛 vertices.
A round-robin coloring of the complete graph 𝐺 on 2𝑛 vertices (𝑉 = [0, . . . , 2𝑛 − 1]) is a proper coloring of its
edges such that the edges with color 𝑖 are all the (𝑖 + 𝑗, 𝑖 − 𝑗) plus the edge (2𝑛 − 1, 𝑖).
If 𝑛 is odd, one obtain a round-robin coloring of the complete graph through the round-robin coloring of the
graph with 𝑛 + 1 vertices.
INPUT:
• n – the number of vertices in the complete graph
OUTPUT:
• A CompleteGraph() with labelled edges such that the label of each edge is its color.
EXAMPLES:
sage: round_robin(4).edges(sort=True)
[(0, 1, 2), (0, 2, 1), (0, 3, 0), (1, 2, 0), (1, 3, 1), (2, 3, 2)]
For higher orders, the coloring is still proper and uses the expected number of colors:
sage: g = round_robin(9)
sage: sum(Set(e[2] for e in g.edges_incident(v)).cardinality() for v in g) == 2 * g.
˓→size()
True
sage: Set(e[2] for e in g.edge_iterator()).cardinality()
9
sage: g = round_robin(10)
sage: sum(Set(e[2] for e in g.edges_incident(v)).cardinality() for v in g) == 2 * g.
˓→size()
True
sage: Set(e[2] for e in g.edge_iterator()).cardinality()
9
• k – integer (default: None); tests whether the graph is 𝑘-colorable. The function returns a partition of the
vertex set in 𝑘 independent sets if possible and False otherwise.
• value_only – boolean (default: False):
– When set to True, only the chromatic number is returned.
– When set to False (default), a partition of the vertex set into independent sets is returned if possible.
• hex_colors – boolean (default: False); when set to True, the partition returned is a dictionary whose
keys are colors and whose values are the color classes (ideal for plotting).
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver is
used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
OUTPUT:
• If k=None and value_only=False, then return a partition of the vertex set into the minimum possible of
independent sets.
• If k=None and value_only=True, return the chromatic number.
• If k is set and value_only=None, return False if the graph is not 𝑘-colorable, and a partition of the vertex
set into 𝑘 independent sets otherwise.
• If k is set and value_only=True, test whether the graph is 𝑘-colorable, and return True or False accord-
ingly.
EXAMPLES:
This module defines functions based on Cliquer, an exact branch-and-bound algorithm developed by Patric R. J. Os-
tergard and written by Sampo Niskanen.
AUTHORS:
• Nathann Cohen (2009-08-14): Initial version
• Jeroen Demeyer (2011-05-06): Make cliquer interruptible (trac ticket #11252)
• Nico Van Cleemput (2013-05-27): Handle the empty graph (trac ticket #14525)
REFERENCE:
[NO2003]
5.2.1 Methods
Note: Currently only implemented for undirected graphs. Use to_undirected() to convert a digraph to an
undirected graph.
INPUT:
• min_size – integer (default: 0); minimum size of reported cliques. When set to 0 (default), this method
searches for maximum cliques. In such case, parameter max_size must also be set to 0.
• max_size – integer (default: 0); maximum size of reported cliques. When set to 0 (default), the maximum
size of the cliques is unbounded. When min_size is set to 0, this parameter must be set to 0.
ALGORITHM:
This function is based on Cliquer [NO2003].
EXAMPLES:
sage: G = graphs.CompleteGraph(5)
sage: list(sage.graphs.cliquer.all_cliques(G))
[[0, 1, 2, 3, 4]]
sage: list(sage.graphs.cliquer.all_cliques(G, 2, 3))
[[3, 4],
[2, 3],
[2, 3, 4],
[2, 4],
[1, 2],
[1, 2, 3],
[1, 2, 4],
[1, 3],
[1, 3, 4],
[1, 4],
[0, 1],
[0, 1, 2],
[0, 1, 3],
[0, 1, 4],
[0, 2],
[0, 2, 3],
[0, 2, 4],
[0, 3],
[0, 3, 4],
[0, 4]]
sage: G.delete_edge([1,3])
sage: list(sage.graphs.cliquer.all_cliques(G))
[[0, 2, 3, 4], [0, 1, 2, 4]]
Todo: Use the re-entrant functionality of Cliquer [NO2003] to avoid storing all cliques.
sage.graphs.cliquer.all_max_clique(graph)
Return the vertex sets of ALL the maximum complete subgraphs.
Returns the list of all maximum cliques, with each clique represented by a list of vertices. A clique is an induced
complete subgraph, and a maximum clique is one of maximal order.
Note: Currently only implemented for undirected graphs. Use to_undirected() to convert a digraph to an
undirected graph.
ALGORITHM:
This function is based on Cliquer [NO2003].
EXAMPLES:
sage.graphs.cliquer.clique_number(graph)
Return the size of the largest clique of the graph (clique number).
Note: Currently only implemented for undirected graphs. Use to_undirected() to convert a digraph to an
undirected graph.
EXAMPLES:
sage: C = Graph('DJ{')
sage: C.clique_number()
4
sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
sage: G.show(figsize=[2,2])
sage: G.clique_number()
3
sage.graphs.cliquer.max_clique(graph)
Return the vertex set of a maximum complete subgraph.
Note: Currently only implemented for undirected graphs. Use to_undirected() to convert a digraph to an
undirected graph.
EXAMPLES:
sage: C = graphs.PetersenGraph()
sage: from sage.graphs.cliquer import max_clique
sage: max_clique(C)
[7, 9]
5.3 Centrality
5.3.1 Functions
ALGORITHM:
To compute 𝑐(𝑣), we fix 𝑠 and define 𝑐𝑠 (𝑣) as the
∑︀ centrality of 𝑣 due to 𝑠, obtained from the formula above by
running the sum over 𝑡 only. We obtain 𝑐(𝑣) = 𝑠̸=𝑣 𝑐𝑠 (𝑣).
For every vertex 𝑠, we compute the value of 𝑐𝑠 (𝑣) for all 𝑣, using the following remark (see [Brandes01]):
Let 𝑣1 , . . . , 𝑣𝑘 be the out-neighbors of 𝑣 such that 𝑑𝑖𝑠𝑡(𝑠, 𝑣𝑖 ) = 𝑑𝑖𝑠𝑡(𝑠, 𝑣) + 1. Then
∑︁ #{shortest 𝑠𝑣𝑖 − paths}
𝑐𝑠 (𝑣) = 𝑐𝑠 (𝑣𝑖 )
#{shortest 𝑠𝑣 − paths}
1≤𝑖≤𝑘
The number of shortest paths between 𝑠 and every other vertex can be computed with a slightly modified BFS.
While running this BFS we can also store the list of the vertices 𝑣1 , . . . , 𝑣𝑘 associated with each 𝑣.
EXAMPLES:
Exact computations:
sage: graphs.PetersenGraph().centrality_betweenness(exact=True)
{0: 1/12, 1: 1/12, 2: 1/12, 3: 1/12, 4: 1/12, 5: 1/12, 6: 1/12, 7: 1/12, 8: 1/12,␣
˓→9: 1/12}
sage.graphs.centrality.centrality_closeness_random_k(G, k=1)
Return an estimation of the closeness centrality of 𝐺.
The algorithm first randomly selects a set 𝑆 of 𝑘 vertices. Then it computes shortest path distances from each
vertex in 𝑆 (using Dijkstra for weighted graph and breadth-first-search (BFS) for unweighted graph) and uses
this knowledge to estimate the closeness centrality of all vertices.
For more information, see [EDI2014].
INPUT:
• G – an undirected connected Graph
• k – integer (default: 1); number of random nodes to choose
OUTPUT:
A dictionary associating to each vertex its estimated closeness centrality.
EXAMPLES:
Estimation of the closeness centrality of the Petersen Graph when 𝑘 == 𝑛:
5.4.1 Definition
Three independent vertices of a graph form an asteroidal triple if every two of them are connected by a path avoiding
the neighborhood of the third one. A graph is asteroidal triple-free (AT-free, for short) if it contains no asteroidal triple
[LB1962].
Use graph_classes.AT_free.description() to get some known properties of AT-free graphs, or visit this page.
5.4.2 Algorithm
This module implements the Straightforward algorithm recalled in [Koh2004] and due to [LB1962] for testing if a
graph is AT-free or not. This algorithm has time complexity in 𝑂(𝑛3 ) and space complexity in 𝑂(𝑛2 ).
This algorithm uses the connected structure of the graph, stored into a 𝑛 × 𝑛 matrix 𝑀 . This matrix is such that
𝑀 [𝑢][𝑣] == 0 if 𝑣 ∈ ({𝑢} ∪ 𝑁 (𝑢)), and otherwise 𝑀 [𝑢][𝑣] is the unique identifier (a strictly positive integer) of the
connected component of 𝐺 ∖ ({𝑢} ∪ 𝑁 (𝑢)) to which 𝑣 belongs. This connected structure can be computed in time
𝑂(𝑛(𝑛 + 𝑚)) using 𝑛 BFS.
Now, a triple 𝑢, 𝑣, 𝑤 ∈ 𝑉 is an asteroidal triple if and only if it satisfies 𝑀 [𝑢][𝑣] == 𝑀 [𝑢][𝑤] and 𝑀 [𝑣][𝑢] ==
𝑀 [𝑣][𝑤] and 𝑀 [𝑤][𝑢] == 𝑀 [𝑤][𝑣], assuming all these values are positive. Indeed, if 𝑀 [𝑢][𝑣] == 𝑀 [𝑢][𝑤], 𝑣 and
𝑤 are in the same connected component of 𝐺 ∖ ({𝑢} ∪ 𝑁 (𝑢)), and so there is a path between 𝑣 and 𝑤 avoiding the
neighborhood of 𝑢. The algorithm iterates over all triples.
5.4.3 Functions
sage.graphs.asteroidal_triples.is_asteroidal_triple_free(G, certificate=False)
Test if the input graph is asteroidal triple-free
An independent set of three vertices such that each pair is joined by a path that avoids the neighborhood of the
third one is called an asteroidal triple. A graph is asteroidal triple-free (AT-free) if it contains no asteroidal
triples. See the module's documentation for more details.
This method returns True is the graph is AT-free and False otherwise.
INPUT:
• G – a Graph
• certificate – boolean (default: False); by default, this method returns True if the graph is asteroidal
triple-free and False otherwise. When certificate==True, this method returns in addition a list of
three vertices forming an asteroidal triple if such a triple is found, and the empty list otherwise.
EXAMPLES:
The complete graph is AT-free, as well as its line graph:
sage: G = graphs.CompleteGraph(5)
sage: G.is_asteroidal_triple_free()
True
sage: G.is_asteroidal_triple_free(certificate=True)
(True, [])
sage: LG = G.line_graph()
sage: LG.is_asteroidal_triple_free()
True
sage: LLG = LG.line_graph()
sage: LLG.is_asteroidal_triple_free()
False
class sage.graphs.independent_sets.IndependentSets
Bases: object
The set of independent sets of a graph.
For more information on independent sets, see the Wikipedia article Independent_set_(graph_theory).
INPUT:
• G – a graph
• maximal – boolean (default: False); whether to only consider (inclusionwise) maximal independent sets.
• complement – boolean (default: False); whether to consider the graph’s complement (i.e. cliques instead
of independent sets).
ALGORITHM:
The enumeration of independent sets is done naively : given an independent set, this implementation considers
all ways to add a new vertex to it (while keeping it an independent set), and then creates new independent sets
from all those that were created this way.
The implementation, however, is not recursive.
Note: This implementation of the enumeration of maximal independent sets is not much faster than NetworkX’,
which is surprising as it is written in Cython. This being said, the algorithm from NetworkX appears to be slightly
different from this one, and that would be a good thing to explore if one wants to improve the implementation.
A simple generalization can also be done without too much modifications: iteration through independent sets
with given size bounds (minimum and maximum number of vertices allowed).
EXAMPLES:
Listing all independent sets of the Claw graph:
Count them:
sage: I.cardinality()
9
sage: Im.cardinality()
2
One can easily count the number of independent sets of each cardinality:
sage: g = graphs.PetersenGraph()
sage: number_of = [0] * g.order()
sage: for x in IndependentSets(g):
....: number_of[len(x)] += 1
sage: number_of
[1, 10, 30, 30, 5, 0, 0, 0, 0, 0]
It is also possible to define an iterator over all independent sets of a given cardinality. Note, however, that Sage
will generate them all, to return only those that satisfy the cardinality constraints. Getting the list of independent
sets of size 4 in this way can thus take a very long time:
sage: g = graphs.DurerGraph()
sage: I = IndependentSets(g)
sage: [0, 2] in I
True
sage: [0, 3, 5] in I
False
cardinality()
Compute and return the number of independent sets.
This module implements method related to Wikipedia article Comparability_graph and Wikipedia article Permuta-
tion_graph, that is, for the moment, only recognition algorithms.
Most of the information found here can also be found in [ST1994] or [Sha1997].
The following methods are implemented in this module
Author:
• Nathann Cohen 2012-04
Comparability graphs
A graph is a comparability graph if it can be obtained from a poset by adding an edge between any two elements that
are comparable. Co-comparability graph are complements of such graphs, i.e. graphs built from a poset by adding an
edge between any two incomparable elements.
For more information on comparability graphs, see the Wikipedia article Comparability_graph.
Permutation graphs
Definitions:
• A permutation 𝜋 = 𝜋1 𝜋2 . . . 𝜋𝑛 defines a graph on 𝑛 vertices such that 𝑖 ∼ 𝑗 when 𝜋 reverses 𝑖 and 𝑗 (i.e. when
𝑖 < 𝑗 and 𝜋𝑗 < 𝜋𝑖 . A graph is a permutation graph whenever it can be built through this construction.
• A graph is a permutation graph if it can be build from two parallel lines are the intersection graph of segments
intersecting both lines.
• A graph is a permutation graph if it is both a comparability graph and a co-comparability graph.
For more information on permutation graphs, see the Wikipedia article Permutation_graph.
Greedy algorithm
This algorithm attempts to build a transitive orientation of a given graph 𝐺, that is an orientation 𝐷 such that for any
directed 𝑢𝑣-path of 𝐷 there exists in 𝐷 an edge 𝑢𝑣. This already determines a notion of equivalence between some
edges of 𝐺 :
In 𝐺, two edges 𝑢𝑣 and 𝑢𝑣 ′ (incident to a common vertex 𝑢) such that 𝑣𝑣 ′ ̸∈ 𝐺 need necessarily be oriented
the same way (that is that they should either both leave or both enter 𝑢). Indeed, if one enters 𝐺 while the
other leaves it, these two edges form a path of length two, which is not possible in any transitive orientation
of 𝐺 as 𝑣𝑣 ′ ̸∈ 𝐺.
Hence, we can say that in this case a directed edge 𝑢𝑣 is equivalent to a directed edge 𝑢𝑣 ′ (to mean that if one belongs
to the transitive orientation, the other one must be present too) in the same way that 𝑣𝑢 is equivalent to 𝑣 ′ 𝑢. We can
thus define equivalence classes on oriented edges, to represent set of edges that imply each other. We can thus define
𝐺
𝐶𝑢𝑣 to be the equivalence class in 𝐺 of the oriented edge 𝑢𝑣.
Of course, if there exists a transitive orientation of a graph 𝐺, then no edge 𝑢𝑣 implies its contrary 𝑣𝑢, i.e. it is
necessary to ensure that ∀𝑢𝑣 ∈ 𝐺, 𝑣𝑢 ̸∈ 𝐶𝑢𝑣 𝐺
. The key result on which the greedy algorithm is built is the following
(see [ST1994]):
Theorem – The following statements are equivalent :
• 𝐺 is a comparability graph
• ∀𝑢𝑣 ∈ 𝐺, 𝑣𝑢 ̸∈ 𝐶𝑢𝑣
𝐺
• The edges of 𝐺 can be partitionned into 𝐵1 , ..., 𝐵𝑘 where 𝐵𝑖 is the equivalence class of some oriented
edge in 𝐺 − 𝐵1 − · · · − 𝐵𝑖−1
Hence, ensuring that a graph is a comparability graph can be done by checking that no equivalence class is contradictory.
Building the orientation, however, requires to build equivalence classes step by step until an orientation has been found
for all of them.
Mixed Integer Linear Program
A MILP formulation is available to check the other methods for correction. It is easily built :
To each edge are associated two binary variables (one for each possible direction). We then ensure that
each triangle is transitively oriented, and that each pair of incident edges 𝑢𝑣, 𝑢𝑣 ′ such that 𝑣𝑣 ′ ̸∈ 𝐺 do not
create a 2-path.
Here is the formulation:
Maximize : Nothing
Such that :
∀𝑢𝑣 ∈ 𝐺
· 𝑜𝑢𝑣 + 𝑜𝑣𝑢 = 1
∀𝑢 ∈ 𝐺, ∀𝑣, 𝑣 ′ ∈ 𝑁 (𝑣) such that 𝑣𝑣 ′ ̸∈ 𝐺
· 𝑜𝑢𝑣 + 𝑜𝑣′ 𝑢 − 𝑜𝑣′ 𝑣 ≤ 1
· 𝑜𝑢𝑣′ + 𝑜𝑣𝑢 − 𝑜𝑣𝑣′ ≤ 1
∀𝑢 ∈ 𝐺, ∀𝑣, 𝑣 ′ ∈ 𝑁 (𝑣) such that 𝑣𝑣 ′ ∈ 𝐺
· 𝑜𝑢𝑣 + 𝑜𝑣′ 𝑢 ≤ 1
· 𝑜𝑢𝑣′ + 𝑜𝑣𝑢 ≤ 1
𝑜𝑢𝑣 is a binary variable
Note: The MILP formulation is usually much slower than the greedy algorithm. This MILP has been implemented
to check the results of the greedy algorithm that has been implemented to check the results of a faster algorithm which
has not been implemented yet.
5.6.3 Certificates
Comparability graphs
The yes-certificates that a graph is a comparability graphs are transitive orientations of it. The no-certificates, on the
other hand, are odd cycles of such graph. These odd cycles have the property that around each vertex 𝑣 of the cycle its
two incident edges must have the same orientation (toward 𝑣, or outward 𝑣) in any transitive orientation of the graph.
This is impossible whenever the cycle has odd length. Explanations are given in the “Greedy algorithm” part of the
previous section.
Permutation graphs
Permutation graphs are precisely the intersection of comparability graphs and co-comparability graphs. Hence, nega-
tive certificates are precisely negative certificates of comparability or co-comparability. Positive certificates are a pair
of permutations that can be used through PermutationGraph() (whose documentation says more about what these
permutations represent).
Note: The greedy algorithm implemented here is just there to check the correction of more complicated ones, and it
is reaaaaaaaaaaaalllly bad whenever you look at it with performance in mind.
5.6.5 Methods
sage: g = graphs.PetersenGraph()
sage: is_comparability(g)
False
sage: is_comparability(g, no_certificate=True)
(False, [2, 1, 0, 4, 3, 2])
sage.graphs.comparability.greedy_is_comparability_with_certificate(g, certificate=False)
Tests whether the graph is a comparability graph and returns certificates(greedy algorithm).
This method can return certificates of both yes and no answers.
To understand how this method works, please consult the documentation of the comparability module.
INPUT:
• certificate (boolean) – whether to return a certificate. Yes-answers the certificate is a transitive orien-
tation of 𝐺, and a no certificates is an odd cycle of sequentially forcing edges.
EXAMPLES:
The 5-cycle or the Petersen Graph are not transitively orientable:
sage: from sage.graphs.comparability import greedy_is_comparability_with_
˓→certificate as is_comparability
sage: g = graphs.BullGraph()
sage: is_comparability(g)
True
sage: is_comparability(g, certificate = True)
(True, Digraph on 5 vertices)
sage: is_comparability(g, certificate = True)[1].is_transitive()
True
• solver – (default: None); Specify a Linear Program (LP) solver to be used. If set to None, the default one
is used. For more information on LP solvers and which default solver is used, see the method solve() of
the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
EXAMPLES:
sage: g = graphs.BullGraph()
sage: is_comparability(g)
True
sage: is_comparability(g, certificate = True)
(True, Digraph on 5 vertices)
sage: is_comparability(g, certificate = True)[1].is_transitive()
True
Note: As the True certificate is a Permutation object, the segment intersection model of the permutation
graph can be visualized through a call to Permutation.show.
EXAMPLES:
A permutation realizing the bull graph:
sage.graphs.comparability.is_transitive(g, certificate=False)
Tests whether the digraph is transitive.
A digraph is transitive if for any pair of vertices 𝑢, 𝑣 ∈ 𝐺 linked by a 𝑢𝑣-path the edge 𝑢𝑣 belongs to 𝐺.
INPUT:
• certificate – whether to return a certificate for negative answers.
– If certificate = False (default), this method returns True or False according to the graph.
– If certificate = True, this method either returns True answers or yield a pair of vertices 𝑢𝑣 such
that there exists a 𝑢𝑣-path in 𝐺 but 𝑢𝑣 ̸∈ 𝐺.
EXAMPLES:
sage: digraphs.Circuit(4).is_transitive()
False
sage: digraphs.Circuit(4).is_transitive(certificate=True)
(0, 2)
sage: digraphs.RandomDirectedGNP(30,.2).is_transitive()
False
sage: D = digraphs.DeBruijn(5, 2)
sage: D.is_transitive()
False
sage: cert = D.is_transitive(certificate=True)
sage: D.has_edge(*cert)
False
sage: bool(D.shortest_path(*cert))
True
sage: digraphs.RandomDirectedGNP(20,.2).transitive_closure().is_transitive()
True
This module gather everything which is related to line graphs. Right now, this amounts to the following functions :
Author:
• Nathann Cohen (01-2013), root_graph() method and module documentation. Written while listening to Nina
Simone “I wish I knew how it would feel to be free”. Crazy good song. And “Prendre ta douleur”, too.
• David Coudert (10-2018), use maximal cliques iterator in root_graph(), and use root_graph() instead of
forbidden subgraph search in is_line_graph() (trac ticket #26444).
5.7.1 Definition
Given a graph 𝐺, the line graph 𝐿(𝐺) of 𝐺 is the graph such that
𝑉 (𝐿(𝐺)) =𝐸(𝐺)
𝐸(𝐿(𝐺)) ={(𝑒, 𝑒′ ) : and 𝑒, 𝑒′ have a common endpoint in 𝐺}
The definition is extended to directed graphs. In this situation, there is an arc (𝑒, 𝑒′ ) in 𝐿(𝐺) if the destination of 𝑒 is
the origin of 𝑒′ .
For more information, see the Wikipedia article Line_graph.
A graph whose line graph is 𝐿𝐺 is called the root graph of 𝐿𝐺. The root graph of a (connected) graph is unique
([Whi1932], [Har1969]), except when 𝐿𝐺 = 𝐾3 , as both 𝐿(𝐾3 ) and 𝐿(𝐾1,3 ) are equal to 𝐾3 .
Here is how we can “see” 𝐺 by staring (very intently) at 𝐿𝐺 :
A graph 𝐿𝐺 is the line graph of 𝐺 if there exists a collection (𝑆𝑣 )𝑣∈𝐺 of subsets of 𝑉 (𝐿𝐺) such that :
• Every 𝑆𝑣 is a complete subgraph of 𝐿𝐺.
• Every 𝑣 ∈ 𝐿𝐺 belongs to exactly two sets of the family (𝑆𝑣 )𝑣∈𝐺 .
• Any two sets of (𝑆𝑣 )𝑣∈𝐺 have at most one common elements
• For any edge (𝑢, 𝑣) ∈ 𝐿𝐺 there exists a set of (𝑆𝑣 )𝑣∈𝐺 containing both 𝑢 and 𝑣.
In this family, each set 𝑆𝑣 represent a vertex of 𝐺, and contains “the set of edges incident to 𝑣 in 𝐺”. Two
elements 𝑆𝑣 , 𝑆𝑣′ have a nonempty intersection whenever 𝑣𝑣 ′ is an edge of 𝐺.
Hence, finding the root graph of 𝐿𝐺 is the job of finding this collection of sets.
In particular, what we know for sure is that a maximal clique 𝑆 of size 2 or ≥ 4 in 𝐿𝐺 corresponds to a vertex of degree
|𝑆| in 𝐺, whose incident edges are the elements of 𝑆 itself.
The main problem lies with maximal cliques of size 3, i.e. triangles. Those we have to split into two categories, even
and odd triangles :
A triangle {𝑒1 , 𝑒2 , 𝑒3 } ⊆ 𝑉 (𝐿𝐺) is said to be an odd triangle if there exists a vertex 𝑒 ∈ 𝑉 (𝐺) incident
to exactly one or all of {𝑒1 , 𝑒2 , 𝑒3 }, and it is said to be even otherwise.
The very good point of this definition is that an inclusionwise maximal clique which is an odd triangle will always
correspond to a vertex of degree 3 in 𝐺, while an even triangle could result from either a vertex of degree 3 in 𝐺 or a
triangle in 𝐺. And in order to build the root graph we obviously have to decide which.
Beineke proves in [Bei1970] that the collection of sets we are looking for can be easily found. Indeed it turns out that
it is the union of :
1. The family of all maximal cliques of 𝐿𝐺 of size 2 or ≥ 4, as well as all odd triangles.
2. The family of all pairs of adjacent vertices which appear in exactly one maximal clique which is an even triangle.
There are actually four special cases to which the decomposition above does not apply, i.e. graphs containing an edge
which belongs to exactly two even triangles. We deal with those independently.
• The Complete graph 𝐾3 .
• The Diamond graph – the line graph of 𝐾1,3 plus an edge.
• The Wheel graph on 4 + 1 vertices – the line graph of the Diamond graph
• The Octahedron – the line graph of 𝐾4 .
This decomposition turns out to be very easy to implement :-)
Warning: Even though the root graph is NOT UNIQUE for the triangle, this method returns 𝐾1,3 (and not 𝐾3 ) in
this case. Pay very close attention to that, for this answer is not theoretically correct : there is no unique answer in
this case, and we deal with it by returning one of the two possible answers.
5.7.3 Functions
sage.graphs.line_graph.is_line_graph(g, certificate=False)
Check whether the graph 𝑔 is a line graph.
INPUT:
• certificate (boolean) – whether to return a certificate along with the boolean result. Here is what
happens when certificate = True:
– If the graph is not a line graph, the method returns a pair (b, subgraph) where b is False and
subgraph is a subgraph isomorphic to one of the 9 forbidden induced subgraphs of a line graph.
– If the graph is a line graph, the method returns a triple (b,R,isom) where b is True, R is a graph
whose line graph is the graph given as input, and isom is a map associating an edge of R to each vertex
of the graph.
Note: This method wastes a bit of time when the input graph is not connected. If you have performance in mind,
it is probably better to only feed it with connected graphs only.
See also:
EXAMPLES:
sage: graphs.CompleteGraph(5).is_line_graph()
True
sage: graphs.PetersenGraph().is_line_graph()
False
sage: C = graphs.PetersenGraph().is_line_graph(certificate=True)[1]
sage: C.is_isomorphic(graphs.ClawGraph())
True
sage: g = graphs.HouseGraph()
sage: g.is_line_graph()
True
sage.graphs.line_graph.line_graph(g, labels=True)
Return the line graph of the (di)graph g.
INPUT:
• labels – boolean (default: True); whether edge labels should be taken in consideration. If labels=True,
the vertices of the line graph will be triples (u,v,label), and pairs of vertices otherwise.
The line graph of an undirected graph G is an undirected graph H such that the vertices of H are the edges of G
and two vertices e and f of H are adjacent if e and f share a common vertex in G. In other words, an edge in H
represents a path of length 2 in G.
The line graph of a directed graph G is a directed graph H such that the vertices of H are the edges of G and two
vertices e and f of H are adjacent if e and f share a common vertex in G and the terminal vertex of e is the initial
vertex of f. In other words, an edge in H represents a (directed) path of length 2 in G.
Note: As a Graph object only accepts hashable objects as vertices (and as the vertices of the line graph
are the edges of the graph), this code will fail if edge labels are not hashable. You can also set the argument
labels=False to ignore labels.
See also:
EXAMPLES:
sage: g = graphs.CompleteGraph(4)
sage: h = g.line_graph()
sage: h.vertices(sort=True)
[(0, 1, None),
(0, 2, None),
(0, 3, None),
(1, 2, None),
(1, 3, None),
(2, 3, None)]
sage: h.am()
[0 1 1 1 1 0]
[1 0 1 1 0 1]
[1 1 0 0 1 1]
[1 1 0 0 1 1]
[1 0 1 1 0 1]
[0 1 1 1 1 0]
sage: h2 = g.line_graph(labels=False)
sage: h2.vertices(sort=True)
[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
sage: h2.am() == h.am()
True
sage: g = DiGraph([[1..4], lambda i,j: i < j])
sage: h = g.line_graph()
sage: h.vertices(sort=True)
[(1, 2, None),
(1, 3, None),
(1, 4, None),
(2, 3, None),
(2, 4, None),
(3, 4, None)]
sage: h.edges(sort=True)
[((1, 2, None), (2, 3, None), None),
((1, 2, None), (2, 4, None), None),
((1, 3, None), (3, 4, None), None),
((2, 3, None), (3, 4, None), None)]
sage.graphs.line_graph.root_graph(g, verbose=False)
Return the root graph corresponding to the given graph g.
See the documentation of sage.graphs.line_graph to know how it works.
INPUT:
• g – a graph
• verbose – boolean (default: False); display some information about what is happening inside of the
algorithm.
Warning: This code assumes that 𝑔 is a line graph, and is a connected, undirected graph without multiple
edges.
This module is a collection of algorithms on spanning trees. Also included in the collection are algorithms for minimum
spanning trees. See the book [JNC2010] for descriptions of spanning tree algorithms, including minimum spanning
trees.
See also:
• GenericGraph.min_spanning_tree.
Todo:
• Parallel version of Boruvka’s algorithm.
5.8.1 Methods
• min_spanning_tree()
EXAMPLES:
An example from pages 727–728 in [Sah2000]:
sage: G.weighted(True)
sage: E = boruvka(G, check=True); E
[(1, 6, 10), (2, 7, 14), (3, 4, 12), (4, 5, 22), (5, 6, 25), (2, 3, 16)]
sage: boruvka(G, by_weight=True)
[(1, 6, 10), (2, 7, 14), (3, 4, 12), (4, 5, 22), (5, 6, 25), (2, 3, 16)]
sage: sorted(boruvka(G, by_weight=False))
[(1, 2, 28), (1, 6, 10), (2, 3, 16), (2, 7, 14), (3, 4, 12), (4, 5, 22)]
sage.graphs.spanning_tree.edge_disjoint_spanning_trees(G, k, by_weight=False,
weight_function=None, check_weight=True)
Return 𝑘 edge-disjoint spanning trees of minimum cost.
This method implements the Roskind-Tarjan algorithm for finding 𝑘 minimum-cost edge-disjoint spanning trees
in simple undirected graphs [RT1985]. When edge weights are taken into account, the algorithm ensures that
the sum of the weights of the returned spanning trees is minimized. The time complexity of the algorithm is in
𝑂(𝑘 2 𝑛2 ) for the unweighted case and otherwise in 𝑂(𝑚 log 𝑚 + 𝑘 2 𝑛2 ).
This method raises an error if the graph does not contain the requested number of spanning trees.
INPUT:
• G – a simple undirected graph
• k – the requested number of edge-disjoint spanning trees
• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise all edges
have weight 1
• weight_function – function (default: None); a function that takes as input an edge (u, v, l) and
outputs its weight. If not None, by_weight is automatically set to True. If None and by_weight is True,
we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs a number
for each edge
EXAMPLES:
sage: F = edge_disjoint_spanning_trees(G, 2)
sage: F
[Graph on 5 vertices, Graph on 5 vertices]
sage: [f.is_tree() for f in F]
[True, True]
This method raises an error if the graph does not contain the required number of trees:
sage: edge_disjoint_spanning_trees(G, 3)
Traceback (most recent call last):
...
EmptySetError: this graph does not contain the required number of trees/
˓→arborescences
sage: g = graphs.CompleteGraph(5)
sage: for u, v in g.edges(sort=True, labels=False):
....: g.set_edge_label(u, v, 1)
sage: g.set_edge_label(0, 1, 33)
sage: g.set_edge_label(1, 3, 33)
sage: F = edge_disjoint_spanning_trees(g, 2, by_weight=True)
sage: sum(F[0].edge_labels()) + sum(F[1].edge_labels())
8
• weight_function – function (default: None); a function that takes as input an edge (u, v, l) and
outputs its weight. If not None, by_weight is automatically set to True. If None and by_weight is True,
we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: False); whether to check that the weight_function outputs a number
for each edge
• check – boolean (default: False); whether to first perform sanity checks on the input graph G. Default:
check=False. If we toggle check=True, the following sanity checks are first performed on G prior to
running Kruskal’s algorithm on that input graph:
– Is G the null graph?
– Is G disconnected?
– Is G a tree?
– Does G have self-loops?
– Does G have multiple edges?
OUTPUT:
The edges of a minimum spanning tree of G, if one exists, otherwise returns the empty list.
See also:
• sage.graphs.generic_graph.GenericGraph.min_spanning_tree()
• Wikipedia article Kruskal%27s_algorithm
• kruskal()
• filter_kruskal_iterator()
EXAMPLES:
sage: G.weighted(True)
sage: filter_kruskal(G, check=True)
[(1, 6, 10), (3, 4, 12), (2, 7, 14), (2, 3, 16), (4, 5, 22), (5, 6, 25)]
• weight_function – function (default: None); a function that takes as input an edge (u, v, l) and
outputs its weight. If not None, by_weight is automatically set to True. If None and by_weight is True,
we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: False); whether to check that the weight_function outputs a number
for each edge
• check – boolean (default: False); whether to first perform sanity checks on the input graph G. Default:
check=False. If we toggle check=True, the following sanity checks are first performed on G prior to
running Kruskal’s algorithm on that input graph:
– Is G the null graph?
– Is G disconnected?
– Is G a tree?
– Does G have self-loops?
– Does G have multiple edges?
OUTPUT:
The edges of a minimum spanning tree of G, one by one.
See also:
• sage.graphs.generic_graph.GenericGraph.min_spanning_tree()
• Wikipedia article Kruskal%27s_algorithm
• kruskal()
• filter_kruskal()
EXAMPLES:
The edges of a minimum spanning tree of G, if one exists, otherwise returns the empty list.
sage: G.weighted(True)
sage: list(filter_kruskal_iterator(G, threshold=3, check=True))
[(1, 6, 10), (3, 4, 12), (2, 7, 14), (2, 3, 16), (4, 5, 22), (5, 6, 25)]
The weights of the spanning trees returned by kruskal_iterator() and filter_kruskal_iterator() are
the same:
True
This function assumes that we can only compute minimum spanning trees for undirected graphs. Such graphs can
be weighted or unweighted, and they can have multiple edges (since we are computing the minimum spanning
tree, only the minimum weight among all (𝑢, 𝑣)-edges is considered, for each pair of vertices 𝑢, 𝑣).
INPUT:
• G – an undirected graph
• by_weight – boolean (default: True); if True, the edges in the graph are weighted; if False, all edges
have weight 1.
• weight_function – function (default: None); a function that takes as input an edge (u, v, l) and
outputs its weight. If not None, by_weight is automatically set to True. If None and by_weight is True,
we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: False); whether to check that the weight_function outputs a number
for each edge
• check – boolean (default: False); whether to first perform sanity checks on the input graph G. Default:
check=False. If we toggle check=True, the following sanity checks are first performed on G prior to
running Kruskal’s algorithm on that input graph:
– Is G the null graph?
– Is G disconnected?
– Is G a tree?
– Does G have self-loops?
– Does G have multiple edges?
By default, we turn off the sanity checks for performance reasons. This means that by default the func-
tion assumes that its input graph is connected, and has at least one vertex. Otherwise, you should set
check=True to perform some sanity checks and preprocessing on the input graph. If G has multiple edges
or self-loops, the algorithm still works, but the running-time can be improved if these edges are removed.
To further improve the runtime of this function, you should call it directly instead of using it indirectly via
sage.graphs.generic_graph.GenericGraph.min_spanning_tree().
OUTPUT:
The edges of a minimum spanning tree of G, if one exists, otherwise returns the empty list.
See also:
• sage.graphs.generic_graph.GenericGraph.min_spanning_tree()
• kruskal_iterator()
• filter_kruskal() and filter_kruskal_iterator()
EXAMPLES:
An example from pages 727–728 in [Sah2000].
sage: G.weighted(True)
sage: E = kruskal(G, check=True); E
[(1, 6, 10), (3, 4, 12), (2, 7, 14), (2, 3, 16), (4, 5, 22), (5, 6, 25)]
True
See also:
kruskal()
EXAMPLES:
sage: G.weighted(True)
sage: next(kruskal_iterator(G, check=True))
(1, 6, 10)
• kruskal()
• filter_kruskal()
EXAMPLES:
sage: G.weighted(True)
sage: union_set = DisjointSet(G)
sage: next(kruskal_iterator_from_edges(G.edges(sort=False), union_set, by_weight=G.
˓→weighted()))
(1, 6, 10)
Start from any vertex. Perform a random walk by choosing at every step one neighbor uniformly at random.
Every time a new vertex 𝑗 is met, add the edge (𝑖, 𝑗) to the spanning tree, where 𝑖 is the previous vertex in the
random walk.
When by_weight is True or a weight function is given, the selection of the neighbor is done proportionaly to
the edge weights.
INPUT:
• G – an undirected graph
• output_as_graph – boolean (default: False); whether to return a list of edges or a graph
• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise all edges
have weight 1
• weight_function – function (default: None); a function that takes as input an edge (u, v, l) and
outputs its weight. If not None, by_weight is automatically set to True. If None and by_weight is True,
we use the edge label l , if l is not None, else 1 as a weight. The weight_function can be used to
transform the label into a weight (note that, if the weight returned is not convertible to a float, an error is
raised)
• check_weight – boolean (default: True); whether to check that the weight_function outputs a number
for each edge.
See also:
spanning_trees_count() and spanning_trees()
EXAMPLES:
sage: G = graphs.TietzeGraph()
sage: G.random_spanning_tree(output_as_graph=True)
Graph on 12 vertices
sage: rg = G.random_spanning_tree(); rg # random
[(0, 9),
(9, 11),
(0, 8),
(8, 7),
(7, 6),
(7, 2),
(2, 1),
(1, 5),
(9, 10),
(5, 4),
(2, 3)]
sage: Graph(rg).is_tree()
True
sage: G = graphs.Grid2dGraph(6, 6)
sage: pos = G.get_pos()
sage: T = G.random_spanning_tree(True)
sage: T.set_pos(pos)
sage: T.show(vertex_labels=False)
We can also use edge weights to change the probability of returning a spanning tree:
Check that the spanning tree returned when using weights is a tree:
sage: G = graphs.RandomBarabasiAlbert(50, 2)
sage: for u, v in G.edge_iterator(labels=False):
....: G.set_edge_label(u, v, randint(1, 10))
sage: T = G.random_spanning_tree(by_weight=True, output_as_graph=True)
sage: T.is_tree()
True
sage.graphs.spanning_tree.spanning_trees(g, labels=False)
Return an iterator over all spanning trees of the graph 𝑔.
A disconnected graph has no spanning tree.
Uses the Read-Tarjan backtracking algorithm [RT1975a].
INPUT:
• labels – boolean (default: False); whether to return edges labels in the spanning trees or not
EXAMPLES:
See also:
5.9 PQ-Trees
This module implements PQ-Trees, a data structure use to represent all permutations of the columns of a matrix which
satisfy the consecutive ones property:
A binary matrix satisfies the consecutive ones property if the 1s are contiguous in each of its rows (or
equivalently, if no row contains the regexp pattern 10+ 1).
Alternatively, one can say that a sequence of sets 𝑆1 , ..., 𝑆𝑛 satisfies the consecutive ones property if for
any 𝑥 the indices of the sets containing 𝑥 is an interval of [1, 𝑛].
This module is used for the recognition of Interval Graphs (see is_interval()).
P-tree and Q-tree
• A 𝑃 -tree with children 𝑐1 , ..., 𝑐𝑘 (which can be 𝑃 -trees, 𝑄-trees, or actual sets of points) indicates that all 𝑘!
permutations of the children are allowed.
Example: {1, 2}, {3, 4}, {5, 6} (disjoint sets can be permuted in any way)
• A 𝑄-tree with children 𝑐1 , ..., 𝑐𝑘 (which can be 𝑃 -trees, 𝑄-trees, or actual sets of points) indicates that only two
permutations of its children are allowed: 𝑐1 , ..., 𝑐𝑘 or 𝑐𝑘 , ..., 𝑐1 .
Example: {1, 2}, {2, 3}, {3, 4}, {4, 5}, {5, 6} (only two permutations of these sets have the consecutive ones
property).
Computation of all possible orderings
1. In order to compute all permutations of a sequence of sets 𝑆1 , ..., 𝑆𝑘 satisfying the consecutive ones property,
we initialize 𝑇 as a 𝑃 -tree whose children are all the 𝑆1 , ..., 𝑆𝑘 , thus representing the set of all 𝑘! permutations
of them.
2. We select some element 𝑥 and update the data structure 𝑇 to restrict the permutations it describes to those that
keep the occurrences of 𝑥 on an interval of [1, ..., 𝑘]. This will result in a new 𝑃 -tree whose children are:
• all 𝑐¯𝑥 sets 𝑆𝑖 which do not contain 𝑥.
• a new 𝑃 -tree whose children are the 𝑐𝑥 sets 𝑆𝑖 containing 𝑥.
This describes the set of all 𝑐𝑥 ! × 𝑐¯′𝑥 ! permutations of 𝑆1 , ..., 𝑆𝑘 that keep the sets containing 𝑥 on an interval.
3. We take a second element 𝑥′ and update the data structure 𝑇 to restrict the permutations it describes to those that
keep 𝑥′ on an interval of [1, ..., 𝑘]. The sets 𝑆1 , ..., 𝑆𝑘 belong to 4 categories:
• The family 𝑆00 of sets which do not contain any of 𝑥, 𝑥′ .
• The family 𝑆01 of sets which contain 𝑥′ but do not contain 𝑥.
• The family 𝑆10 of sets which contain 𝑥 but do not contain 𝑥′ .
• The family 𝑆11 of sets which contain 𝑥′ and 𝑥′ .
With these notations, the permutations of 𝑆1 , ..., 𝑆𝑘 which keep the occurrences of 𝑥 and 𝑥′ on an interval are
of two forms:
• <some sets 𝑆00 >, <sets from 𝑆10 >, <sets from 𝑆11 >, <sets from 𝑆01 >, <other sets from 𝑆00 >
• <some sets 𝑆00 >, <sets from 𝑆01 >, <sets from 𝑆11 >, <sets from 𝑆10 >, <other sets from 𝑆00 >
These permutations can be modeled with the following 𝑃 𝑄-tree:
• A 𝑃 -tree whose children are:
– All sets from 𝑆00
– A 𝑄-tree whose children are:
class sage.graphs.pq_trees.P(seq)
Bases: sage.graphs.pq_trees.PQ
A P-Tree is a PQ-Tree whose children can be permuted in any way.
For more information, see the documentation of sage.graphs.pq_trees.
cardinality()
Return the number of orderings allowed by the structure.
See also:
orderings() – iterate over all admissible orderings
EXAMPLES:
orderings()
Iterate over all orderings of the sets allowed by the structure.
See also:
cardinality() – return the number of orderings
EXAMPLES:
set_contiguous(v)
Updates self so that the sets containing v are contiguous for any admissible permutation of its subtrees.
INPUT:
• v – an element of the ground set
OUTPUT:
According to the cases :
• (EMPTY, ALIGNED) if no set of the tree contains an occurrence of v
• (FULL, ALIGNED) if all the sets of the tree contain v
• (PARTIAL, ALIGNED) if some (but not all) of the sets contain v, all of which are aligned to the right
of the ordering at the end when the function ends
• (PARTIAL, UNALIGNED) if some (but not all) of the sets contain v, though it is impossible to align
them all to the right
In any case, the sets containing v are contiguous when this function ends. If there is no possibility of doing
so, the function raises a ValueError exception.
EXAMPLES:
Ensuring the sets containing 0 are continuous:
Impossible situation:
class sage.graphs.pq_trees.PQ(seq)
Bases: object
PQ-Trees
This class should not be instantiated by itself: it is extended by P and Q . See the documentation of sage.graphs.
pq_trees for more information.
number_of_children()
Returns the number of children of self
EXAMPLES:
ordering()
Returns the current ordering given by listing the leaves from left to right.
EXAMPLES:
reverse()
Recursively reverses self and its children
EXAMPLES:
Note: This method is assumes that self is partial for v, and aligned to the side indicated by left, right.
EXAMPLES:
A 𝑃 -Tree
A 𝑄-Tree
class sage.graphs.pq_trees.Q(seq)
Bases: sage.graphs.pq_trees.PQ
A Q-Tree is a PQ-Tree whose children are ordered up to reversal
For more information, see the documentation of sage.graphs.pq_trees.
cardinality()
Return the number of orderings allowed by the structure.
See also:
orderings() – iterate over all admissible orderings
EXAMPLES:
orderings()
Iterates over all orderings of the sets allowed by the structure
See also:
cardinality() – return the number of orderings
EXAMPLES:
set_contiguous(v)
Updates self so that the sets containing v are contiguous for any admissible permutation of its subtrees.
INPUT:
• v – an element of the ground set
OUTPUT:
According to the cases :
• (EMPTY, ALIGNED) if no set of the tree contains an occurrence of v
• (FULL, ALIGNED) if all the sets of the tree contain v
• (PARTIAL, ALIGNED) if some (but not all) of the sets contain v, all of which are aligned to the right
of the ordering at the end when the function ends
• (PARTIAL, UNALIGNED) if some (but not all) of the sets contain v, though it is impossible to align
them all to the right
In any case, the sets containing v are contiguous when this function ends. If there is no possibility of doing
so, the function raises a ValueError exception.
EXAMPLES:
Ensuring the sets containing 0 are continuous:
Impossible situation:
sage.graphs.pq_trees.reorder_sets(sets)
Reorders a collection of sets such that each element appears on an interval.
Given a collection of sets 𝐶 = 𝑆1 , ..., 𝑆𝑘 on a ground set 𝑋, this function attempts to reorder them in such a
way that ∀𝑥 ∈ 𝑋 and 𝑖 < 𝑗 with 𝑥 ∈ 𝑆𝑖 , 𝑆𝑗 , then 𝑥 ∈ 𝑆𝑙 for every 𝑖 < 𝑙 < 𝑗 if it exists.
INPUT:
• sets - a list of instances of list, Set or set
ALGORITHM:
PQ-Trees
EXAMPLES:
There is only one way (up to reversal) to represent contiguously the sequence ofsets {𝑖 − 1, 𝑖, 𝑖 + 1}:
sage: p = Permutations(len(seq)).random_element()
sage: seq = [ seq[p(i+1)-1] for i in range(len(seq)) ]
sage: ordered = reorder_sets(seq)
sage: if not 0 in ordered[0]:
....: ordered = ordered.reverse()
sage: print(ordered)
[{0, 1, 2}, {1, 2, 3}, {2, 3, 4}, {3, 4, 5}, {4, 5, 6}, {5, 6, 7},
{8, 6, 7}, {8, 9, 7}, {8, 9, 10}, {9, 10, 11}, {10, 11, 12},
{11, 12, 13}, {12, 13, 14}, {13, 14, 15}]
This is an implementation of the algorithm for generating trees with 𝑛 vertices (up to isomorphism) in constant time
per tree described in [WROM1986].
AUTHORS:
• Ryan Dingman (2009-04-16): initial version
class sage.graphs.trees.TreeIterator
Bases: object
This class iterates over all trees with n vertices (up to isomorphism).
EXAMPLES:
AUTHORS:
• Robert Miller, Tom Boothby - original implementation
REFERENCE:
[God1993]
5.11.1 Methods
sage.graphs.matchpoly.complete_poly(n)
Compute the matching polynomial of the complete graph on 𝑛 vertices.
INPUT:
• n – order of the complete graph
Todo: This code could probably be made more efficient by using FLINT polynomials and being written in
Cython, using an array of fmpz_poly_t pointers or something. . . Right now just about the whole complement
optimization is written in Python, and could be easily sped up.
EXAMPLES:
If 𝑝(𝐺, 𝑘) denotes the number of 𝑘-matchings (matchings with 𝑘 edges) in 𝐺, then the matching polynomial is
defined as [God1993]:
∑︁
𝜇(𝑥) = (−1)𝑘 𝑝(𝐺, 𝑘)𝑥𝑛−2𝑘
𝑘≥0
INPUT:
• complement - (default: True) whether to use Godsil’s duality theorem to compute the matching polynomial
from that of the graphs complement (see ALGORITHM).
• name - optional string for the variable name in the polynomial
Note: The complement option uses matching polynomials of complete graphs, which are cached. So if you
are crazy enough to try computing the matching polynomial on a graph with millions of vertices, you might not
want to use this option, since it will end up caching millions of polynomials of degree in the millions.
ALGORITHM:
The algorithm used is a recursive one, based on the following observation [God1993]:
• If 𝑒 is an edge of 𝐺, 𝐺′ is the result of deleting the edge 𝑒, and 𝐺′′ is the result of deleting each vertex in 𝑒,
then the matching polynomial of 𝐺 is equal to that of 𝐺′ minus that of 𝐺′′ .
(the algorithm actually computes the signless matching polynomial, for which the recursion is the same
when one replaces the subtraction by an addition. It is then converted into the matching polynomial and
returned)
Depending on the value of complement, Godsil’s duality theorem [God1993] can also be used to compute 𝜇(𝑥)
:
∑︁
𝜇(𝐺, 𝑥) = 𝑝(𝐺, 𝑘)𝜇(𝐾𝑛−2𝑘 , 𝑥)
𝑘≥0
sage: g = graphs.PetersenGraph()
sage: g.matching_polynomial()
x^10 - 15*x^8 + 75*x^6 - 145*x^4 + 90*x^2 - 6
sage: g.matching_polynomial(complement=False)
x^10 - 15*x^8 + 75*x^6 - 145*x^4 + 90*x^2 - 6
sage: g.matching_polynomial(name='tom')
tom^10 - 15*tom^8 + 75*tom^6 - 145*tom^4 + 90*tom^2 - 6
sage: g = Graph()
sage: L = [graphs.RandomGNP(8, .3) for i in range(1, 6)]
sage: prod([h.matching_polynomial() for h in L]) == sum(L, g).matching_polynomial()␣
˓→ # long time (up to 10s on sage.math, 2011)
True
5.12 Genus
This file contains a moderately-optimized implementation to compute the genus of simple connected graph. It runs
about a thousand times faster than the previous version in Sage, not including asymptotic improvements.
The algorithm works by enumerating combinatorial embeddings of a graph, and computing the genus of these via the
Euler characteristic. We view a combinatorial embedding of a graph as a pair of permutations 𝑣, 𝑒 which act on a set 𝐵
of 2|𝐸(𝐺)| “darts”. The permutation 𝑒 is an involution, and its orbits correspond to edges in the graph. Similarly, The
orbits of 𝑣 correspond to the vertices of the graph, and those of 𝑓 = 𝑣𝑒 correspond to faces of the embedded graph.
The requirement that the group < 𝑣, 𝑒 > acts transitively on 𝐵 is equivalent to the graph being connected. We can
compute the genus of a graph by
2 − 2𝑔 = 𝑉 − 𝐸 + 𝐹
where 𝐸, 𝑉 , and 𝐹 denote the number of orbits of 𝑒, 𝑣, and 𝑓 respectively.
We make several optimizations to the naive algorithm, which are described throughout the file.
class sage.graphs.genus.simple_connected_genus_backtracker
Bases: object
A class which computes the genus of a DenseGraph through an extremely slow but relatively optimized algorithm.
This is “only” exponential for graphs of bounded degree, and feels pretty snappy for 3-regular graphs. The generic
runtime is
∏︀
|𝑉 (𝐺)| 𝑣∈𝑉 (𝐺) (𝑑𝑒𝑔(𝑣) − 1)!
which is 2|𝑉 (𝐺)| for 3-regular graphs, and can achieve 𝑛(𝑛 − 1)!𝑛 for the complete graph on 𝑛 vertices. We
can handily compute the genus of 𝐾6 in milliseconds on modern hardware, but 𝐾7 may take a few days. Don’t
bother with 𝐾8 , or any graph with more than one vertex of degree 10 or worse, unless you can find an a priori
lower bound on the genus and expect the graph to have that genus.
Warning:
THIS MAY SEGFAULT OR HANG ON:
• DISCONNECTED GRAPHS
• DIRECTED GRAPHS
• LOOPED GRAPHS
• MULTIGRAPHS
EXAMPLES:
sage: bt.genus()
1
sage: G = graphs.FlowerSnark()
sage: G = Graph(G, sparse=False)
sage: bt = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[0])
sage: bt.genus()
2
sage: gb.genus()
0
get_embedding()
Return an embedding for the graph.
If min_genus_backtrack has been called with record_embedding = True, then this will return the
first minimal embedding that we found. Otherwise, this returns the first embedding considered.
EXAMPLES:
sage: gb.genus(record_embedding=True)
1
sage: gb.get_embedding()
{0: [1, 2, 3, 4], 1: [0, 2, 3, 4], 2: [0, 1, 4, 3], 3: [0, 2, 1, 4], 4: [0, 3,␣
˓→1, 2]}
sage: G = Graph(sparse=False)
sage: G.add_edge(0,1)
sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[0])
sage: gb.get_embedding()
{0: [1], 1: [0]}
sage: G = Graph(sparse=False)
sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[0])
sage: gb.get_embedding()
{}
Warning:
THIS MAY SEGFAULT OR HANG ON:
• DISCONNECTED GRAPHS
• DIRECTED GRAPHS
• LOOPED GRAPHS
• MULTIGRAPHS
DO NOT CALL WITH check = False UNLESS YOU ARE CERTAIN.
EXAMPLES:
REFERENCES:
[1] http://www.springerlink.com/content/0776127h0r7548v7/
AUTHORS:
• Dima Pasechnik (2015-06-30): Initial version
REFERENCE:
[Lov1979]
5.13.1 Functions
sage.graphs.lovasz_theta.lovasz_theta(graph)
Return the value of Lovász theta-function of graph.
For a graph 𝐺 this function is denoted by 𝜃(𝐺), and it can be computed in polynomial time. Mathematically, its
most important property is the following:
with 𝛼(𝐺) and 𝜒(𝐺) being, respectively, the maximum size of an independent set set of 𝐺 and the
chromatic number of the complement 𝐺 of 𝐺.
For more information, see the Wikipedia article Lovász_number.
Note:
• Implemented for undirected graphs only. Use to_undirected to convert a digraph to an undirected graph.
• This function requires the optional package csdp, which you can install with sage -i csdp.
EXAMPLES:
sage: C = graphs.PetersenGraph()
sage: C.lovasz_theta() # optional csdp
4.0
sage: graphs.CycleGraph(5).lovasz_theta() # optional csdp
2.236068
A module for computing the (x,y) coordinates for a straight-line planar embedding of any connected planar graph with
at least three vertices. Uses Walter Schnyder’s Algorithm from [Sch1990].
AUTHORS:
• Jonathan Bober, Emily Kirkman (2008-02-09) – initial version
class sage.graphs.schnyder.TreeNode(parent=None, children=None, label=None)
Bases: object
A class to represent each node in the trees used by _realizer and _compute_coordinates when finding a
planar geometric embedding in the grid.
Each tree node is doubly linked to its parent and children.
INPUT:
• parent – the parent TreeNode of self
• children – a list of TreeNode children of self
• label – the associated realizer vertex label
EXAMPLES:
append_child(child)
Add a child to list of children.
EXAMPLES:
compute_depth_of_self_and_children()
Computes the depth of self and all descendants.
For each TreeNode, sets result as attribute self.depth
EXAMPLES:
compute_number_of_descendants()
Computes the number of descendants of self and all descendants.
For each TreeNode, sets result as attribute self.number_of_descendants
EXAMPLES:
A larger example:
sage: g = Graph([(0,-1),(0,2),(0,1),(0,-3),(-1,-3),(-1,2),
....: (-1,-2),(1,2),(1,-3),(2,-2),(1,-2),(-2,-3)], format='list_of_edges')
sage: g.set_embedding({-1:[-2,2,0,-3],-2:[-3,1,2,-1],
....: -3:[-1,0,1,-2],0:[-1,2,1,-3],1:[-2,-3,0,2],2:[-1,-2,1,0]})
sage: newg = minimal_schnyder_wood(g)
sage: newg.edges(sort=True, key=lambda e:(str(e[0]),str(e[1])))
[(0, -1, 'green'),
(0, -3, 'red'),
(0, 2, 'blue'),
(1, -2, 'blue'),
(1, -3, 'red'),
(1, 0, 'green'),
(2, -1, 'green'),
(2, -2, 'blue'),
(2, 1, 'red')]
(continues on next page)
sage: G = graphs.DodecahedralGraph()
sage: from sage.graphs.planarity import is_planar
sage: is_planar(G)
True
sage: Graph('@').is_planar()
True
5.16.1 Methods
sage.graphs.traversals.is_valid_lex_M_order(G, alpha, F)
Check whether the ordering alpha and the triangulation F are valid for G.
Given the graph 𝐺 = (𝑉, 𝐸) with vertex set 𝑉 and edge set 𝐸, and the set 𝐹 of edges of a triangulation of
𝐺, let 𝐻 = (𝑉, 𝐸 ∪ 𝐹 ). By induction one can see that for every 𝑖 ∈ {1, ..., 𝑛 − 1} the neighbors of 𝛼(𝑖) in
𝐻[{𝛼(𝑖), ..., 𝛼(𝑛)}] induce a clique. The ordering 𝛼 is a perfect elimination ordering of 𝐻, so 𝐻 is chordal. See
[RTL76] for more details.
INPUT:
• G – a Graph
• alpha – list; an ordering of the vertices of 𝐺
• F – an iterable of edges given either as (u, v) or (u, v, label), the edges of the triangulation of 𝐺
sage.graphs.traversals.lex_BFS(G, reverse=False, tree=False, initial_vertex=None, algorithm='fast')
Perform a lexicographic breadth first search (LexBFS) on the graph.
INPUT:
• G – a sage graph
• reverse – boolean (default: False); whether to return the vertices in discovery order, or the reverse
• tree – boolean (default: False); whether to return the discovery directed tree (each vertex being linked
to the one that saw it for the first time)
• initial_vertex – (default: None); the first vertex to consider
• algorithm – string (default: "fast"); algorithm to use among:
– "slow" – This algorithm maintains for each vertex left in the graph a code corresponding to the vertices
already removed. The vertex of maximal code (according to the lexicographic order) is then removed,
and the codes are updated. See for instance [CK2008] for more details. The time complexity of this
algorithm as described in [CK2008] is in 𝑂(𝑛 + 𝑚), where 𝑛 is the number of vertices and 𝑚 is the
number of edges, but our implementation is in 𝑂(𝑛2 ).
– "fast" – This algorithm uses the notion of slices to refine the position of the vertices in the ordering.
The time complexity of this algorithm is in 𝑂(𝑛+𝑚), and our implementation follows that complexity.
See [HMPV2000] and next section for more details.
ALGORITHM:
The "fast" algorithm is the 𝑂(𝑛 + 𝑚) time algorithm proposed in [HMPV2000], where 𝑛 is the number of
vertices and 𝑚 is the number of edges. It uses the notion of slices, i.e., subsets of consecutive vertices in the
ordering, and iteratively refines the slices by subdividing them into sub-slices to determine the exact position of
the vertices in the ordering.
Consider an ordering 𝜎 of the vertices. For a vertex 𝑣, we define 𝑁𝑖 (𝑣) = {𝑢|𝑢 ∈ 𝑁 (𝑣) and 𝜎(𝑢) < 𝑖}, that is
the subset of neighbors of 𝑣 appearing before the 𝑖-th vertex in the ordering 𝜎. Now, a slice of an ordering 𝜎 is a
set of consecutive vertices, 𝑆 = {𝑢|𝑖 ≤ 𝜎(𝑢) ≤ 𝑗}, such that for any 𝑢 ∈ 𝑆, we have 𝑁𝑖 (𝑢) = 𝑁𝑖 (𝜎 −1 (𝑖)) and
for any 𝑣 such that 𝑗 < 𝜎(𝑣), 𝑁𝑖 (𝑣) ̸= 𝑁𝑖 (𝜎 −1 (𝑖)). The head of a slice is the first position of its vertices.
The algorithm starts with a single slice containing all vertices. Then, when the position of the 𝑖-th vertex 𝑣 is
fixed, it explores the neighbors of 𝑣 that have not yet been ordered. Consider a slice 𝑆 such that 𝑁 (𝑥) ∩ 𝑆 ̸= ∅.
The algorithm will rearrange the ordering of the vertices in 𝑆 so that the first vertices are the neighbors of 𝑣. The
sub-slice containing the neighbors of 𝑣 is assigned a new slice name, and the head of slice 𝑆 is set to the position
of the first vertex of 𝑆 ∖ 𝑁 (𝑣) in the ordering 𝜎.
Observe that each arc of the graph can induce the subdivision of a slice. Hence, the algorithm can use up to
𝑚 + 1 different slices.
See also:
EXAMPLES:
A Lex BFS is obviously an ordering of the vertices:
sage: g = graphs.CompleteGraph(6)
sage: len(g.lex_BFS()) == g.order()
True
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4, 5), (5,
˓→ 6)])
sage: g.lex_BFS()
[1, 2, 3, 5, 4, 6]
sage: g = graphs.PathGraph(3).lexicographic_product(graphs.CompleteGraph(2))
sage: g.lex_BFS(reverse=True)
[(2, 1), (2, 0), (1, 1), (1, 0), (0, 1), (0, 0)]
And the vertices at the end of the tree of discovery are, for chordal graphs, simplicial vertices (their neighborhood
is a complete graph):
sage: g = graphs.ClawGraph().lexicographic_product(graphs.CompleteGraph(2))
sage: v = g.lex_BFS()[-1]
sage: peo, tree = g.lex_BFS(initial_vertex = v, tree=True)
sage: leaves = [v for v in tree if tree.in_degree(v) ==0]
sage: all(g.subgraph(g.neighbors(v)).is_clique() for v in leaves)
True
sage: G = digraphs.DeBruijn(2,3)
sage: G.lex_BFS(initial_vertex='000', algorithm="fast")
['000', '001', '100', '010', '011', '110', '101', '111']
sage: G.lex_BFS(initial_vertex='000', algorithm="slow")
['000', '001', '100', '010', '011', '110', '101', '111']
sage: G.lex_DFS(initial_vertex='000')
['000', '001', '100', '010', '101', '110', '011', '111']
sage: G.lex_UP(initial_vertex='000')
['000', '001', '010', '101', '110', '111', '011', '100']
sage: G.lex_DOWN(initial_vertex='000')
['000', '001', '100', '011', '010', '110', '111', '101']
EXAMPLES:
A Lex DFS is obviously an ordering of the vertices:
sage: g = graphs.CompleteGraph(6)
sage: len(g.lex_DFS()) == g.order()
True
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4, 5), (5,
˓→ 6)])
sage: g.lex_DFS()
[1, 2, 3, 5, 6, 4]
sage: G = digraphs.DeBruijn(2,3)
sage: G.lex_BFS(initial_vertex='000')
['000', '001', '100', '010', '011', '110', '101', '111']
sage: G.lex_DFS(initial_vertex='000')
['000', '001', '100', '010', '101', '110', '011', '111']
sage: G.lex_UP(initial_vertex='000')
['000', '001', '010', '101', '110', '111', '011', '100']
sage: G.lex_DOWN(initial_vertex='000')
['000', '001', '100', '011', '010', '110', '111', '101']
EXAMPLES:
A Lex DOWN is obviously an ordering of the vertices:
sage: g = graphs.CompleteGraph(6)
sage: len(g.lex_DOWN()) == g.order()
True
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4, 5), (5,
˓→ 6)])
sage: g.lex_DOWN()
[1, 2, 3, 4, 6, 5]
sage: G = digraphs.DeBruijn(2,3)
sage: G.lex_BFS(initial_vertex='000')
['000', '001', '100', '010', '011', '110', '101', '111']
sage: G.lex_DFS(initial_vertex='000')
['000', '001', '100', '010', '101', '110', '011', '111']
sage: G.lex_UP(initial_vertex='000')
['000', '001', '010', '101', '110', '111', '011', '100']
sage: G.lex_DOWN(initial_vertex='000')
['000', '001', '100', '011', '010', '110', '111', '101']
INPUT:
• triangulation – boolean (default: False); whether to return a list of edges that need to be added in
order to triangulate the graph
• labels – boolean (default: False); whether to return the labels assigned to each vertex
• initial_vertex – (default: None); the first vertex to consider
• algorithm – string (default: None); one of the following algorithms:
– 'lex_M_slow': slower implementation of LexM traversal
– 'lex_M_fast': faster implementation of LexM traversal (works only when labels is set to False)
– None: Sage chooses the best algorithm: 'lex_M_slow' if labels is set to True, 'lex_M_fast'
otherwise.
OUTPUT:
Depending on the values of the parameters triangulation and labels the method will return one or more of
the following (in that order):
• an ordering of vertices of the graph according to LexM ordering scheme
• the labels assigned to each vertex
• a list of edges that when added to the graph will triangulate it
EXAMPLES:
LexM produces an ordering of the vertices:
sage: g = graphs.CompleteGraph(6)
sage: ord = g.lex_M(algorithm='lex_M_fast')
sage: len(ord) == g.order()
True
sage: set(ord) == set(g.vertices(sort=False))
True
sage: ord = g.lex_M(algorithm='lex_M_slow')
sage: len(ord) == g.order()
True
sage: set(ord) == set(g.vertices(sort=False))
True
Both algorithms produce a valid LexM ordering 𝛼 (i.e the neighbors of 𝛼(𝑖) in 𝐺[{𝛼(𝑖), ..., 𝛼(𝑛)}] induce a
clique):
sage: G = graphs.PetersenGraph()
sage: _, F = G.lex_M(triangulation=True)
sage: H = Graph(F, format='list_of_edges')
sage: H.is_chordal()
True
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4, 5), (5,
˓→ 6)])
sage: g.lex_M()
[6, 4, 5, 3, 2, 1]
INPUT:
• G – a sage graph
• triangulation – boolean (default: False); whether to return the triangulation of given graph produced
by the method
• initial_vertex – (default: None); the first vertex to consider
OUTPUT:
This method will return an ordering of the vertices of G according to the LexM ordering scheme. Furthermore, if
triangulation is set to True the method also returns a list of edges F such that when added to G the resulting
graph is a triangulation of G.
EXAMPLES:
A LexM ordering is obviously an ordering of the vertices:
sage: lex_M_fast(g)
[6, 4, 5, 3, 2, 1]
During the search, the vertices are numbered from 𝑛 to 1. Let 𝛼(𝑖) denote the vertex numbered 𝑖 and let 𝛼−1 (𝑢)
denote the number assigned to 𝑢. Each vertex 𝑢 has also a label, denoted by 𝑙𝑎𝑏𝑒𝑙(𝑢), consisting of a list of
numbers selected from [1, 𝑛] and ordered in decreasing order. Given two labels 𝐿1 = [𝑝1 , 𝑝2 , . . . , 𝑝𝑘 ] and
𝐿1 = [𝑞1 , 𝑞2 , . . . , 𝑞𝑙 ], we define 𝐿1 < 𝐿2 if, for some 𝑗, 𝑝𝑖 == 𝑞𝑖 for 𝑖 = 1, . . . , 𝑗 − 1 and 𝑝𝑗 < 𝑞𝑗 , or if
𝑝𝑖 == 𝑞𝑖 for 𝑖 = 1, . . . , 𝑘 and 𝑘 < 𝑙. Observe that this is exactly how Python compares two lists.
INPUT:
• G – a sage graph
• triangulation – boolean (default: False); whether to return the triangulation of the graph produced by
the method
• labels – boolean (default: False); whether to return the labels assigned to each vertex
• initial_vertex – (default: None); the first vertex to consider. If not specified, an arbitrary vertex is
chosen.
OUTPUT:
Depending on the values of the parameters triangulation and labels the method will return one or more of
the following (in that order):
• the ordering of vertices of 𝐺
• the labels assigned to each vertex
• a list of edges that when added to 𝐺 will produce a triangulation of 𝐺
EXAMPLES:
A LexM ordering is obviously an ordering of the vertices:
LexM ordering and label assignments on the vertices of the 3-sun graph:
EXAMPLES:
A Lex UP is obviously an ordering of the vertices:
sage: g = graphs.CompleteGraph(6)
sage: len(g.lex_UP()) == g.order()
True
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4, 5), (5,
˓→ 6)])
sage: g.lex_UP()
[1, 2, 4, 5, 6, 3]
sage: G = digraphs.DeBruijn(2,3)
sage: G.lex_BFS(initial_vertex='000')
['000', '001', '100', '010', '011', '110', '101', '111']
sage: G.lex_DFS(initial_vertex='000')
(continues on next page)
INPUT:
• G – a Sage Graph
• reverse – boolean (default: False); whether to return the vertices in discovery order, or the reverse
• tree – boolean (default: False); whether to also return the discovery directed tree (each vertex being
linked to the one that saw it for the first time)
• initial_vertex – (default: None); the first vertex to consider
OUTPUT:
By default, return the ordering 𝛼 as a list. When tree is True, the method returns a tuple (𝛼, 𝑇 ), where 𝑇 is a
directed tree with the same set of vertices as 𝐺 to 𝑣 if 𝑢 was the first vertex to saw 𝑣.
EXAMPLES:
When specified, the initial_vertex is placed at the end of the ordering, unless parameter reverse is True,
in which case it is placed at the beginning:
sage: G = graphs.PathGraph(4)
sage: G.maximum_cardinality_search(initial_vertex=0)
[3, 2, 1, 0]
sage: G.maximum_cardinality_search(initial_vertex=1)
[0, 3, 2, 1]
sage: G.maximum_cardinality_search(initial_vertex=2)
[0, 1, 3, 2]
sage: G.maximum_cardinality_search(initial_vertex=3)
[0, 1, 2, 3]
sage: G.maximum_cardinality_search(initial_vertex=3, reverse=True)
[3, 2, 1, 0]
sage: G = graphs.PathGraph(4)
sage: _, T = G.maximum_cardinality_search(tree=True, initial_vertex=0)
sage: T.order(), T.size()
(4, 3)
sage: T.edges(labels=False, sort=True)
[(1, 0), (2, 1), (3, 2)]
sage: _, T = G.maximum_cardinality_search(tree=True, initial_vertex=3)
sage: T.edges(labels=False, sort=True)
[(0, 1), (1, 2), (2, 3)]
sage.graphs.traversals.maximum_cardinality_search_M(G, initial_vertex=None)
Return the ordering and the edges of the triangulation produced by MCS-M.
Maximum cardinality search M (MCS-M) is an extension of MCS (maximum_cardinality_search()) in the
same way that Lex-M (lex_M()) is an extension of Lex-BFS (lex_BFS()). That is, in MCS-M when 𝑢 receives
number 𝑖 at step 𝑛 − 𝑖 + 1, it increments the weight of all unnumbered vertices 𝑣 for which there exists a path
between 𝑢 and 𝑣 consisting only of unnumbered vertices with weight strictly less than 𝑤− (𝑢) and 𝑤− (𝑣), where
𝑤− is the number of times a vertex has been reached during previous iterations. See [BBHP2004] for the details
of this 𝑂(𝑛𝑚) time algorithm.
If 𝐺 is not connected, the orderings of each of its connected components are added consecutively. Furthermore,
if 𝐺 has 𝑘 connected components 𝐶𝑖 for 0 ≤ 𝑖 < 𝑘, 𝑋 contains at least one vertex of 𝐶𝑖 for each 𝑖 ≥ 1. Hence,
|𝑋| ≥ 𝑘 − 1. In particular, some isolated vertices (i.e., of degree 0) can appear in 𝑋 as for such a vertex 𝑥, we
have that 𝐺 ∖ 𝑁 (𝑥) = 𝐺 is not connected.
INPUT:
• G – a Sage graph
• initial_vertex – (default: None); the first vertex to consider
OUTPUT: a tuple (𝛼, 𝐹, 𝑋), where
• 𝛼 is the resulting ordering of the vertices. If an initial vertex is specified, it gets the last position in the
ordering 𝛼.
• 𝐹 is the list of edges of a minimal triangulation of 𝐺 according 𝛼
• 𝑋 is a list of vertices such that for each 𝑥 ∈ 𝑋, the neighborhood of 𝑥 in 𝐺 is a separator (i.e., 𝐺 ∖ 𝑁 (𝑥)
is not connected). Note that we may have 𝑁 (𝑥) = ∅ if 𝐺 is not connected and 𝑥 has degree 0.
EXAMPLES:
Chordal graphs have a perfect elimination ordering, and so the set 𝐹 of edges of the triangulation is empty:
sage: G = graphs.RandomChordalGraph(20)
sage: alpha, F, X = G.maximum_cardinality_search_M(); F
[]
The cycle of order 4 is not chordal and so the triangulation has one edge:
sage: G = graphs.CycleGraph(4)
sage: alpha, F, X = G.maximum_cardinality_search_M(); len(F)
1
The number of edges needed to triangulate of a cycle graph or order 𝑛 is 𝑛−3, independently of the initial vertex:
When an initial vertex is specified, it gets the last position in the ordering:
sage: G = graphs.PathGraph(4)
sage: G.maximum_cardinality_search_M(initial_vertex=0)
([3, 2, 1, 0], [], [2, 3])
sage: G.maximum_cardinality_search_M(initial_vertex=1)
([3, 2, 0, 1], [], [2, 3])
sage: G.maximum_cardinality_search_M(initial_vertex=2)
([0, 1, 3, 2], [], [0, 1])
sage: G.maximum_cardinality_search_M(initial_vertex=3)
([0, 1, 2, 3], [], [0, 1])
When 𝐺 is not connected, the orderings of each of its connected components are added consecutively, the vertices
of the component containing the initial vertex occupying the last positions:
sage: G = graphs.CycleGraph(4) * 2
sage: G.maximum_cardinality_search_M()[0]
[5, 4, 6, 7, 2, 3, 1, 0]
sage: G.maximum_cardinality_search_M(initial_vertex=7)[0]
[2, 1, 3, 0, 5, 6, 4, 7]
Furthermore, if 𝐺 has 𝑘 connected components, 𝑋 contains at least one vertex per connected component, except
for the first one, and so at least 𝑘 − 1 vertices:
sage: G = Graph({'a': ['b', 'k'], 'b': ['c'], 'c': ['d', 'j', 'k'],
....: 'd': ['e', 'f', 'j', 'k'], 'e': ['g'],
....: 'f': ['g', 'j', 'k'], 'g': ['j', 'k'], 'h': ['i', 'j'],
....: 'i': ['k'], 'j': ['k']})
sage: _, F, _ = G.maximum_cardinality_search_M(initial_vertex='a')
sage: len(F)
3
sage: G = graphs.WheelGraph(15)
sage: P = G.plot()
sage: P.show() # long time
1
2 14
3 13
4 12
5 11
6 10
7 9
8
When plotting a graph created using Sage’s Graph command, node positions are determined using the spring-layout
algorithm. Special graphs available from graphs.* have preset positions. For example, compare the two plots of the
Petersen graph, as obtained using Graph or as obtained from that database:
All constructors in this database (except some random graphs) prefill the position dictionary, bypassing the spring-
layout positioning algorithm.
Plot options
3
7
1
6 9
5 4
0
1 4
6 9
7 8
2 3
Here is the list of options accepted by plot() and the constructor of GraphPlot. Those two functions also accept all
options of sage.plot.graphics.Graphics.show().
layout A layout algorithm – one of : “acyclic”, “circular” (plots the graph with vertices
evenly distributed on a circle), “ranked”, “graphviz”, “planar”, “spring” (tradi-
tional spring layout, using the graph’s current positions as initial positions), or
“tree” (the tree will be plotted in levels, depending on minimum distance for the
root).
iterations The number of times to execute the spring layout algorithm.
heights A dictionary mapping heights to the list of vertices at this height.
spring Use spring layout to finalize the current layout.
tree_root A vertex designation for drawing trees. A vertex of the tree to be used as the
root for the layout='tree' option. If no root is specified, then one is chosen
close to the center of the tree. Ignored unless layout='tree'.
forest_roots An iterable specifying which vertices to use as roots for the layout='forest'
option. If no root is specified for a tree, then one is chosen close to the center of
the tree. Ignored unless layout='forest'.
tree_orientation The direction of tree branches – ‘up’, ‘down’, ‘left’ or ‘right’.
save_pos Whether or not to save the computed position for the graph.
dim The dimension of the layout – 2 or 3.
prog Which graphviz layout program to use – one of “circo”, “dot”, “fdp”, “neato”,
or “twopi”.
by_component Whether to do the spring layout by connected component – a boolean.
pos The position dictionary of vertices.
vertex_labels Vertex labels to draw. This can be True/False to indicate whether to print the
vertex string representation of not, a dictionary keyed by vertices and associating
to each vertex a label string, or a function taking as input a vertex and returning
a label string.
vertex_color Default color for vertices not listed in vertex_colors dictionary.
vertex_colors A dictionary specifying vertex colors: each key is a color recognizable by mat-
plotlib, and each corresponding value is a list of vertices.
vertex_size The size to draw the vertices.
vertex_shape The shape to draw the vertices. Currently unavailable for Multi-edged DiGraphs.
edge_labels Whether or not to draw edge labels.
edge_style The linestyle of the edges. It should be one of “solid”, “dashed”, “dotted”, dash-
dot”, or “-”, “–”, “:”, “-.”, respectively.
edge_thickness The thickness of the edges.
edge_color The default color for edges not listed in edge_colors.
edge_colors A dictionary specifying edge colors: each key is a color recognized by mat-
plotlib, and each corresponding value is a list of edges.
color_by_label Whether to color the edges according to their labels. This also accepts a function
or dictionary mapping labels to colors.
partition A partition of the vertex set. If specified, plot will show each cell in a different
color; vertex_colors takes precedence.
loop_size The radius of the smallest loop.
dist The distance between multiedges.
max_dist The max distance range to allow multiedges.
talk Whether to display the vertices in talk mode (larger and white).
graph_border Whether or not to draw a frame around the graph.
edge_labels_background The color of the background of the edge labels.
Default options
This module defines two dictionaries containing default options for the plot() and show() methods. These
two dictionaries are sage.graphs.graph_plot.DEFAULT_PLOT_OPTIONS and sage.graphs.graph_plot.
DEFAULT_SHOW_OPTIONS, respectively.
Obviously, these values are overruled when arguments are given explicitly.
Here is how to define the default size of a graph drawing to be (6, 6). The first two calls to show() use this option,
while the third does not (a value for figsize is explicitly given):
We can now reset the default to its initial value, and now display graphs as previously:
Note:
• While DEFAULT_PLOT_OPTIONS affects both G.show() and G.plot(), settings from
DEFAULT_SHOW_OPTIONS only affects G.show().
• In order to define a default value permanently, you can add a couple of lines to Sage’s startup scripts. Example:
layout_tree(root, orientation)
Compute a nice layout of a tree.
INPUT:
• root – the root vertex.
• orientation – whether to place the root at the top or at the bottom:
– orientation="down" – children are placed below their parent
– orientation="top" – children are placed above their parent
EXAMPLES:
plot(**kwds)
Return a graphics object representing the (di)graph.
INPUT:
The options accepted by this method are to be found in the documentation of the sage.graphs.
graph_plot module, and the show() method.
Note: See the module's documentation for information on default values of this method.
1 4
6 9
7 8
2 3
Here are some more common graphs with typical options:
sage: C = graphs.CubeGraph(8)
sage: P = C.graphplot(vertex_labels=False, vertex_size=0,
....: graph_border=True)
sage: P.show()
sage: G = graphs.HeawoodGraph().copy(sparse=True)
sage: for u, v, l in G.edges(sort=True):
....: G.set_edge_label(u, v, f'({u},{v})')
sage: G.graphplot(edge_labels=True).show()
0
(0,1) (0,13)
1 13
(1,2) (12,13)
2 12
4 (2,7) 10
(6,11)
(4,5) (4,9) (9,10)
5 9
(5,6) (8,9)
6 8
(6,7) (7,8)
7
The options for plotting also work with directed graphs:
sage: D = DiGraph({
....: 0: [1, 10, 19], 1: [8, 2], 2: [3, 6], 3: [19, 4],
....: 4: [17, 5], 5: [6, 15], 6: [7], 7: [8, 14], 8: [9],
....: 9: [10, 13], 10: [11], 11: [12, 18], 12: [16, 13],
....: 13: [14], 14: [15], 15: [16], 16: [17], 17: [18],
....: 18: [19], 19: []})
sage: for u, v, l in D.edges(sort=True):
....: D.set_edge_label(u, v, f'({u},{v})')
sage: D.graphplot(edge_labels=True, layout='circular').show()
0 (0,19)
1 (0,1) 19
(1,2) (18,19)
2 (3,19) 18
(2,3) (17,18)
3 17
(3,4) (4,17) (16,17)
4 16
(2,6)
(4,5) (15,16)
(1,8)
5 (0,10)
(5,15) 15
(11,18)
(5,6) (14,15)
(12,16)
6 14
(6,7) (7,14) (13,14)
7 13
(7,8) (12,13)
8 (9,13) 12
(8,9) (11,12)
9 (9,10) (10,11) 11
10
With the partition option, we can separate out same-color groups of vertices:
sage: D = graphs.DodecahedralGraph()
sage: Pi = [[6, 5, 15, 14, 7], [16, 13, 8, 2, 4],
....: [12, 17, 9, 3, 1], [0, 19, 18, 10, 11]]
sage: D.show(partition=Pi)
sage: G = graphs.PetersenGraph()
sage: G.allow_loops(True)
sage: G.add_edge(0,0)
sage: G.show()
10
9 11
1 19
8 13 12 18
14 16
7 17
15
6 5 4
2 3
1 4
6 9
7 8
2 3
More options:
sage: G = Graph()
sage: P = G.graphplot().plot()
sage: P.axes()
False
sage: G = DiGraph()
sage: P = G.graphplot().plot()
sage: P.axes()
False
sage: T = list(graphs.trees(7))
sage: t = T[3]
sage: t.graphplot(heights={0: [0], 1: [4, 5, 1],
....: 2: [2], 3: [3, 6]}
....: ).plot()
Graphics object consisting of 14 graphics primitives
0 3
6
sage: T = list(graphs.trees(7))
sage: t = T[3]
sage: t.graphplot(heights={0: [0], 1: [4, 5, 1],
....: 2: [2], 3: [3, 6]}
....: ).plot()
Graphics object consisting of 14 graphics primitives
4
1
2 3
1000 None 6
5
99
-7 0
1
None
4
None
sage: T = list(graphs.trees(7))
sage: t = T[3]
sage: t.graphplot(layout='tree').show()
sage: t = DiGraph('JCC???@A??GO??CO??GO??')
sage: t.graphplot(layout='tree', tree_root=0,
....: tree_orientation="up"
....: ).show()
More examples:
5 1
6 4 3 2
6 1 8 4
10 5 7 2
9 3
1
4
2
5
a
4
a
b
3
a
b
2
a
b
1
a
b
0
b
-1
sage: g.graphplot(edge_labels=True,
(continues on next page)
0
e
b f
a c
f
d
1
set_edges(**edge_options)
Set edge plotting parameters for the GraphPlot object.
This function is called by the constructor but can also be called to update the vertex options of an existing
GraphPlot object. Note that the changes are cumulative.
EXAMPLES:
0
b
a
c f e
d f
2
h
sage: GP.set_edges(edge_color='black')
sage: GP.plot()
Graphics object consisting of 22 graphics primitives
d
f
c
f
e
b
a
sage: d = DiGraph(loops=True, multiedges=True, sparse=True)
sage: d.add_edges([(0, 0, 'a'), (0, 0, 'b'), (0, 1, 'c'),
....: (0, 1, 'd'), (0, 1, 'e'), (0, 1, 'f'),
....: (0, 1, 'f'), (2, 1, 'g'), (2, 2, 'h')])
sage: GP = d.graphplot(vertex_size=100, edge_labels=True,
....: color_by_label=True, edge_style='dashed')
sage: GP.set_edges(edge_style='solid')
sage: GP.plot()
Graphics object consisting of 24 graphics primitives
sage: GP.set_edges(edge_color='black')
sage: GP.plot()
Graphics object consisting of 24 graphics primitives
set_pos()
Set the position plotting parameters for this GraphPlot.
EXAMPLES:
This function is called implicitly by the code below:
h
g
1
e
f
c
f
d
0
b
a
0
b
a
f c f e
d
2
h
The following illustrates the format of a position dictionary, but due to numerical noise we do not check
the values themselves:
sage: g.get_pos()
{0: (0.0, 1.0),
1: (-0.951..., 0.309...),
2: (-0.587..., -0.809...),
3: (0.587..., -0.809...),
4: (0.951..., 0.309...)}
sage: T = list(graphs.trees(7))
sage: t = T[3]
sage: t.plot(heights={0: [0], 1: [4, 5, 1], 2: [2], 3: [3, 6]})
Graphics object consisting of 14 graphics primitives
4
3
1
2
6
set_vertices(**vertex_options)
Set the vertex plotting parameters for this GraphPlot.
This function is called by the constructor but can also be called to make updates to the vertex options of an
existing GraphPlot object. Note that the changes are cumulative.
EXAMPLES:
2
h
df
c f
e
0
b
a
Vertex labels are flexible:
sage: g = graphs.PathGraph(4)
sage: g.plot(vertex_labels=False)
Graphics object consisting of 4 graphics primitives
sage: g = graphs.PathGraph(4)
sage: g.plot(vertex_labels=True)
(continues on next page)
0
b
a
d f c f
e
2
h
0 1 2 3
sage: g = graphs.PathGraph(4)
sage: g.plot(vertex_labels=dict(zip(g, ['+', '-', '/', '*'])))
Graphics object consisting of 8 graphics primitives
sage: g = graphs.PathGraph(4)
sage: g.plot(vertex_labels=lambda x: str(x % 2))
Graphics object consisting of 8 graphics primitives
show(**kwds)
Show the (di)graph associated with this GraphPlot object.
INPUT:
This method accepts all parameters of sage.plot.graphics.Graphics.show().
Note:
• See the module's documentation for information on default values of this method.
• Any options not used by plot will be passed on to the show() method.
+ - / *
0 1 0 1
EXAMPLES:
sage: C = graphs.CubeGraph(8)
sage: P = C.graphplot(vertex_labels=False, vertex_size=0,
....: graph_border=True)
sage: P.show()
This module implements everything that can be used to draw graphs with d3.js in Sage.
On Python’s side, this is mainly done by wrapping a graph’s edges and vertices in a structure that can then be used in
the javascript code. This javascript code is then inserted into a .html file to be opened by a browser.
In the browser, the displayed page contains at the bottom right a menu that allows to save the picture under the svg file
format.
What Sage feeds javascript with is a “graph” object with the following content:
• vertices – each vertex is a dictionary defining :
– name – The vertex’s label
– group – the vertex’ color (integer)
Warning: Since the d3js package is not standard yet, the javascript is fetched from d3js.org website by the browser.
If you want to avoid that (e.g. to protect your privacy or by lack of internet connection), you can install the d3js
package for offline use by running sage -i d3js from the command line.
Todo:
• Add tooltip like in http://bl.ocks.org/bentwonk/2514276.
• Add a zoom through scrolling (http://bl.ocks.org/mbostock/3681006).
Authors:
• Nathann Cohen, Brice Onfroy – July 2013 – Initial version of the Sage code, Javascript code, using examples
from d3.js.
• Thierry Monteil (June 2014): allow offline use of d3.js provided by d3js spkg.
5.18.1 Functions
• vertex_partition – list (default: []); a list of lists representing a partition of the vertex set. Vertices are
then colored in the graph according to the partition
• vertex_colors – dict (default: None); a dictionary representing a partition of the vertex set. Keys are
colors (ignored) and values are lists of vertices. Vertices are then colored in the graph according to the
partition
• edge_partition – list (default: []); same as vertex_partition, with edges instead
• force_spring_layout – boolean (default: False); whether to take previously computed position of
nodes into account if there is one, or to compute a spring layout
• vertex_size – integer (default: 7); the size of a vertex’ circle
• edge_thickness – integer (default: 4); thickness of an edge
• charge – integer (default: -120); the vertices’ charge. Defines how they repulse each other. See https:
//github.com/mbostock/d3/wiki/Force-Layout for more information
• link_distance – integer (default: 30); see https://github.com/mbostock/d3/wiki/Force-Layout for more
information
• link_strength – integer (default: 2); see https://github.com/mbostock/d3/wiki/Force-Layout for more
information
• gravity – float (default: 0.04); see https://github.com/mbostock/d3/wiki/Force-Layout for more infor-
mation
Warning: Since the d3js package is not standard yet, the javascript is fetched from d3js.org website by the
browser. If you want to avoid that (e.g. to protect your privacy or by lack of internet connection), you can
install the d3js package for offline use by running sage -i d3js from the command line.
EXAMPLES:
sage: g = graphs.PetersenGraph()
sage: g.show(method="js", vertex_partition=g.coloring()) # optional -- internet
sage: g = digraphs.DeBruijn(2, 2)
sage: g.allow_multiple_edges(True)
sage: g.add_edge("10", "10", "a")
sage: g.add_edge("10", "10", "b")
sage: g.add_edge("10", "10", "c")
sage: g.add_edge("10", "10", "d")
sage: g.add_edge("01", "11", "1")
sage: g.show(method="js", vertex_labels=True,edge_labels=True,
....: link_distance=200, gravity=.05, charge=-500,
....: edge_partition=[[("11", "12", "2"), ("21", "21", "a")]],
....: edge_thickness=4) # optional -- internet
sage: T = graphs.RandomTree(20)
sage: T.treewidth()
1
sage: T.treelength()
1
See also:
• Wikipedia article Tree_decomposition
• Wikipedia article Treewidth
This module contains the following methods
5.19.1 Methods
class sage.graphs.graph_decompositions.tree_decomposition.TreelengthConnected
Bases: object
Compute the treelength of a connected graph (and provide a decomposition).
This class implements an algorithm for computing the treelength of a connected graph that virtually explores the
graph of all pairs (vertex_cut, connected_component), where vertex_cut is a vertex cut of the graph of
length ≤ 𝑘, and connected_component is a connected component of the graph induced by G - vertex_cut.
We deduce that the pair (vertex_cut, connected_component) is feasible with treelength 𝑘 if
connected_component is empty, or if a vertex v from vertex_cut can be replaced with a vertex from
connected_component, such that the pair (vertex_cut + v, connected_component - v) is feasible.
INPUT:
• G – a sage Graph
• k – integer (default: None); indicates the length to be considered. When 𝑘 is an integer, the method checks
that the graph has treelength ≤ 𝑘. If 𝑘 is None (default), the method computes the optimal treelength.
• certificate – boolean (default: False); whether to also compute the tree-decomposition itself
OUTPUT:
TreelengthConnected(G) returns the treelength of 𝐺. When 𝑘 is specified, it returns False when no tree-
decomposition of length ≤ 𝑘 exists or True otherwise. When certificate=True, the tree-decomposition is
also returned.
EXAMPLES:
A clique has treelength 1:
sage: TreelengthConnected(graphs.CompleteGraph(3)).get_length()
1
sage: TC = TreelengthConnected(graphs.CompleteGraph(4), certificate=True)
sage: TC.get_length()
1
sage: TC.get_tree_decomposition()
Tree decomposition of Complete graph: Graph on 1 vertex
sage: TreelengthConnected(graphs.CycleGraph(6)).get_length()
2
sage: TreelengthConnected(graphs.CycleGraph(7)).get_length()
3
sage: TreelengthConnected(graphs.CycleGraph(7), k=3).is_less_than_k()
(continues on next page)
get_length()
Return the length of the tree decomposition.
EXAMPLES:
sage: G = graphs.CycleGraph(4)
sage: TreelengthConnected(G).get_length()
2
sage: TreelengthConnected(G, k=2).get_length()
2
sage: TreelengthConnected(G, k=1).get_length()
Traceback (most recent call last):
...
ValueError: no tree decomposition with length <= 1 was found
get_tree_decomposition()
Return the tree-decomposition.
EXAMPLES:
sage: G = graphs.CycleGraph(4)
sage: TreelengthConnected(G, certificate=True).get_tree_decomposition()
Tree decomposition of Cycle graph: Graph on 2 vertices
sage: G.diameter()
2
sage: TreelengthConnected(G, k=2, certificate=True).get_tree_decomposition()
Tree decomposition of Cycle graph: Graph on 1 vertex
sage: TreelengthConnected(G, k=1, certificate=True).get_tree_decomposition()
Traceback (most recent call last):
...
ValueError: no tree decomposition with length <= 1 was found
is_less_than_k()
Return whether a tree decomposition with length at most 𝑘 was found.
EXAMPLES:
sage: G = graphs.CycleGraph(4)
sage: TreelengthConnected(G, k=1).is_less_than_k()
False
sage: TreelengthConnected(G, k=2).is_less_than_k()
True
sage: TreelengthConnected(G).is_less_than_k()
Traceback (most recent call last):
(continues on next page)
sage.graphs.graph_decompositions.tree_decomposition.is_valid_tree_decomposition(G, T )
Check whether 𝑇 is a valid tree-decomposition for 𝐺.
INPUT:
• G – a sage Graph
• T – a tree decomposition, i.e., a tree whose vertices are the bags (subsets of vertices) of the decomposition
EXAMPLES:
sage: K = graphs.CompleteGraph(4)
sage: T = Graph()
sage: T.add_vertex(Set(K))
sage: is_valid_tree_decomposition(K, T)
True
sage: G = graphs.PathGraph(4)
sage: T = G.treewidth(certificate=True)
sage: _ = G.add_vertex()
sage: is_valid_tree_decomposition(G, T)
False
sage: G = graphs.PathGraph(4)
sage: T = G.treewidth(certificate=True)
sage: G.add_edge(0, 3)
sage: is_valid_tree_decomposition(G, T)
False
sage: G = graphs.PathGraph(4)
sage: X1, X2, X3 = Set([0, 1]), Set([1, 2]), Set([2, 3])
sage: T = Graph([(X1, X3), (X3, X2)])
sage: is_valid_tree_decomposition(G, T)
False
sage.graphs.graph_decompositions.tree_decomposition.reduced_tree_decomposition(T )
Return a reduced tree-decomposition of 𝑇 .
We merge all edges between two sets 𝑆 and 𝑆 ′ where 𝑆 is a subset of 𝑆 ′ . To do so, we use a simple union-find
data structure to record merge operations and the good sets.
Warning: This method assumes that the vertices of the input tree 𝑇 are hashable and have attribute
issuperset, e.g., frozenset or Set_object_enumerated.
INPUT:
• T – a tree-decomposition
EXAMPLES:
sage: G = graphs.PathGraph(3)
sage: T = Graph()
sage: T.add_path([Set([0]), Set([0, 1]), Set([1]), Set([1, 2]), Set([2])])
sage: T.order()
5
sage: is_valid_tree_decomposition(G, T)
True
sage: T2 = reduced_tree_decomposition(T)
sage: is_valid_tree_decomposition(G, T2)
True
sage: T2.order()
2
In practice, this method decomposes the graph by its clique minimal separators into atoms, computes the tree-
length of each of atom and returns the maximum value over all the atoms. Indeed, we have that 𝑡𝑙(𝐺) =
max𝑋∈𝐴 𝑡𝑙(𝐺[𝑋]) where 𝐴 is the set of atoms of the decomposition by clique separators of 𝐺. When
certificate == True, the tree-decompositions of the atoms are connected to each others by adding edges
with respect to the clique separators.
See also:
EXAMPLES:
The PetersenGraph has treelength 2:
sage: G = graphs.PetersenGraph()
sage: G.treelength()
2
sage: G = Graph(2)
sage: G.treelength()
+Infinity
sage: G.treelength(k=+Infinity)
True
sage: G.treelength(k=2)
False
sage: G.treelength(certificate=True)
Traceback (most recent call last):
...
ValueError: the tree decomposition of a disconnected graph is not defined
sage: G = graphs.RandomChordalGraph(30)
sage: while not G.is_connected():
....: G = graphs.RandomChordalGraph(30)
sage: G.treelength()
1
sage.graphs.graph_decompositions.tree_decomposition.treelength_lowerbound(G)
Return a lower bound on the treelength of 𝐺.
See [DG2006] for more details.
INPUT:
• G – a sage Graph
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: treelength_lowerbound(G)
1
sage: G.treelength()
2
sage: G = graphs.CycleGraph(5)
sage: treelength_lowerbound(G)
2
sage: G.treelength()
2
Note: The implementation would be much faster if cc, the argument of the recursive function, was a bitset.
It would also be very nice to not copy the graph in order to compute connected components, for this is really a
waste of time.
See also:
path_decomposition() computes the pathwidth of a graph. See also the vertex_separation module.
EXAMPLES:
sage: graphs.PetersenGraph().treewidth()
4
sage: graphs.PetersenGraph().treewidth(certificate=True)
Tree decomposition: Graph on 6 vertices
sage: graphs.Grid2dGraph(2,5).treewidth()
2
sage: graphs.Grid2dGraph(3,5).treewidth()
3
When parameter kmin is specified, the method search for a tree-decomposition of width at least kmin:
sage: g = graphs.PetersenGraph()
sage: g.treewidth()
4
sage: g.treewidth(kmin=2, algorithm='sage')
4
sage: g.treewidth(kmin=g.order(), certificate=True, algorithm='sage')
Tree decomposition: Graph on 1 vertex
sage.graphs.graph_decompositions.tree_decomposition.width_of_tree_decomposition(G, T,
check=True)
Return the width of the tree decomposition 𝑇 of 𝐺.
The width of a tree-decomposition is the size of the largest bag minus 1. The empty graph and a graph of order
1 have treewidth 0.
INPUT:
• G – a sage Graph
• T – a tree-decomposition for 𝐺
• check – boolean (default: True); whether to check that the tree-decomposition 𝑇 is valid for 𝐺
EXAMPLES:
sage: G = graphs.PathGraph(3)
sage: T = G.treewidth(certificate=True)
sage: width_of_tree_decomposition(G, T, check=True)
1
This module implements several algorithms to compute the vertex separation of a digraph and the corresponding or-
dering of the vertices. It also implements tests functions for evaluation the width of a linear ordering.
Given an ordering 𝑣1 , · · · , 𝑣𝑛 of the vertices of 𝑉 (𝐺), its cost is defined as:
Where
𝑐′ (𝑆) = |𝑁𝐺
+
(𝑆)∖𝑆|
The vertex separation of a digraph 𝐺 is equal to the minimum cost of an ordering of its vertices.
Vertex separation and pathwidth
The vertex separation is defined on a digraph, but one can obtain from a graph 𝐺 a digraph 𝐷 with the same vertex
set, and in which each edge 𝑢𝑣 of 𝐺 is replaced by two edges 𝑢𝑣 and 𝑣𝑢 in 𝐷. The vertex separation of 𝐷 is equal
to the pathwidth of 𝐺, and the corresponding ordering of the vertices of 𝐷, also called a layout, encodes an optimal
path-decomposition of 𝐺. This is a result of Kinnersley [Kin1992] and Bodlaender [Bod1998].
This module contains the following methods
In order to find an optimal ordering of the vertices for the vertex separation, this algorithm tries to save time by com-
puting the function 𝑐′ (𝑆) at most once once for each of the sets 𝑆 ⊆ 𝑉 (𝐺). These values are stored in an array of size
2𝑛 where reading the value of 𝑐′ (𝑆) or updating it can be done in constant (and small) time.
Assuming that we can compute the cost of a set 𝑆 and remember it, finding an optimal ordering is an easy task.
Indeed, we can think of the sequence 𝑣1 , ..., 𝑣𝑛 of vertices as a sequence of sets {𝑣1 }, {𝑣1 , 𝑣2 }, ..., {𝑣1 , ..., 𝑣𝑛 }, whose
cost is precisely max 𝑐′ ({𝑣1 }), 𝑐′ ({𝑣1 , 𝑣2 }), ..., 𝑐′ ({𝑣1 , ..., 𝑣𝑛 }). Hence, when considering the digraph on the 2𝑛 sets
𝑆 ⊆ 𝑉 (𝐺) where there is an arc from 𝑆 to 𝑆 ′ if 𝑆 ′ = 𝑆 ∩{𝑣} for some 𝑣 (that is, if the sets 𝑆 and 𝑆 ′ can be consecutive
in a sequence), an ordering of the vertices of 𝐺 corresponds to a path from ∅ to {𝑣1 , ..., 𝑣𝑛 }. In this setting, checking
whether there exists a ordering of cost less than 𝑘 can be achieved by checking whether there exists a directed path ∅
to {𝑣1 , ..., 𝑣𝑛 } using only sets of cost less than 𝑘. This is just a depth-first-search, for each 𝑘.
Lazy evaluation of 𝑐′
In the previous algorithm, most of the time is actually spent on the computation of 𝑐′ (𝑆) for each set 𝑆 ⊆ 𝑉 (𝐺) – i.e.
2𝑛 computations of neighborhoods. This can be seen as a huge waste of time when noticing that it is useless to know
that the value 𝑐′ (𝑆) for a set 𝑆 is less than 𝑘 if all the paths leading to 𝑆 have a cost greater than 𝑘. For this reason, the
value of 𝑐′ (𝑆) is computed lazily during the depth-first search. Explanation :
When the depth-first search discovers a set of size less than 𝑘, the costs of its out-neighbors (the potential sets that
could follow it in the optimal ordering) are evaluated. When an out-neighbor is found that has a cost smaller than 𝑘, the
depth-first search continues with this set, which is explored with the hope that it could lead to a path toward {𝑣1 , ..., 𝑣𝑛 }.
On the other hand, if an out-neighbour has a cost larger than 𝑘 it is useless to attempt to build a cheap sequence going
though this set, and the exploration stops there. This way, a large number of sets will never be evaluated and a lot of
computational time is saved this way.
Besides, some improvement is also made by “improving” the values found by 𝑐′ . Indeed, 𝑐′ (𝑆) is a lower bound on the
cost of a sequence containing the set 𝑆, but if all out-neighbors of 𝑆 have a cost of 𝑐′ (𝑆) + 5 then one knows that having
𝑆 in a sequence means a total cost of at least 𝑐′ (𝑆) + 5. For this reason, for each set 𝑆 we store the value of 𝑐′ (𝑆), and
replace it by max(𝑐′ (𝑆), minnext ) (where minnext is the minimum of the costs of the out-neighbors of 𝑆) once the costs
of these out-neighbors have been evaluated by the algorithm.
Note: Because of its current implementation, this algorithm only works on graphs on less than 32 vertices. This can
be changed to 64 if necessary, but 32 vertices already require 4GB of memory. Running it on 64 bits is not expected to
be doable by the computers of the next decade : −𝐷
max 𝑐′ ({𝑣1 }), 𝑐′ ({𝑣1 , 𝑣2 }), ..., 𝑐′ ({𝑣1 , ..., 𝑣𝑛 }) ≥ max 𝑐′1 , ..., 𝑐′𝑛
where 𝑐𝑖 is the minimum cost of a set 𝑆 on 𝑖 vertices. Evaluating the 𝑐𝑖 can take time (and in particular more than the
previous exact algorithm), but it does not need much memory to run.
We describe below a mixed integer linear program (MILP) for determining an optimal layout for the vertex separation
of 𝐺, which is an improved version of the formulation proposed in [SP2010]. It aims at building a sequence 𝑆𝑡 of sets
such that an ordering 𝑣1 , ..., 𝑣𝑛 of the vertices correspond to 𝑆0 = {𝑣1 }, 𝑆2 = {𝑣1 , 𝑣2 }, ..., 𝑆𝑛−1 = {𝑣1 , ..., 𝑣𝑛 }.
Variables:
• 𝑦𝑣𝑡 – Variable set to 1 if 𝑣 ∈ 𝑆𝑡 , and 0 otherwise. The order of 𝑣 in the layout is the smallest 𝑡 such that 𝑦𝑣𝑡 == 1.
• 𝑢𝑡𝑣 – Variable set to 1 if 𝑣 ̸∈ 𝑆𝑡 and 𝑣 has an in-neighbor in 𝑆𝑡 . It is set to 0 otherwise.
• 𝑥𝑡𝑣 – Variable set to 1 if either 𝑣 ∈ 𝑆𝑡 or if 𝑣 has an in-neighbor in 𝑆𝑡 . It is set to 0 otherwise.
• 𝑧 – Objective value to minimize. It is equal to the maximum over all step 𝑡 of the number of vertices such that
𝑢𝑡𝑣 == 1.
MILP formulation:
Minimize:𝑧 (5.1)
Such that:𝑥𝑡𝑣 ≤ 𝑥𝑡+1
𝑣 ∀𝑣 ∈ 𝑉, 0 ≤ 𝑡 ≤ 𝑛 − 2 (5.2)
𝑦𝑣𝑡 ≤ 𝑡+1
𝑦𝑣 ∀𝑣 ∈ 𝑉, 0 ≤ 𝑡 ≤ 𝑛 − 2 (5.3)
𝑦𝑣𝑡 ≤ 𝑥𝑡𝑤 +
∀𝑣 ∈ 𝑉, ∀𝑤 ∈ 𝑁 (𝑣), 0 ≤ 𝑡 ≤ 𝑛 − 1 (5.4)
∑︁
𝑦𝑣𝑡 =𝑡+1 0≤𝑡≤𝑛−1 (5.5)
𝑣∈𝑉
𝑥𝑡𝑣 − 𝑦𝑣𝑡 ≤ 𝑢𝑡𝑣 ∀𝑣 ∈ 𝑉, 0 ≤ 𝑡 ≤ 𝑛 − 1 (5.6)
∑︁
𝑢𝑡𝑣 ≤𝑧 0≤𝑡≤𝑛−1 (5.7)
𝑣∈𝑉
0 ≤ 𝑥𝑡𝑣 ≤ 1 ∀𝑣 ∈ 𝑉, 0 ≤ 𝑡 ≤ 𝑛 − 1 (5.8)
0≤ 𝑢𝑡𝑣 ≤1 ∀𝑣 ∈ 𝑉, 0 ≤ 𝑡 ≤ 𝑛 − 1 (5.9)
𝑦𝑣𝑡 ∈ {0, 1} ∀𝑣 ∈ 𝑉, 0 ≤ 𝑡 ≤ 𝑛 − 1 (5.10)
0≤𝑧≤𝑛 (5.11)
The vertex separation of 𝐺 is given by the value of 𝑧, and the order of vertex 𝑣 in the optimal layout is given by the
smallest 𝑡 for which 𝑦𝑣𝑡 == 1.
We describe below the principle of a branch and bound algorithm (BAB) for determining an optimal ordering for the
vertex separation of 𝐺, as proposed in [CMN2014].
Greedy steps:
Let us denote ℒ(𝑆) the set of all possible orderings of the vertices in 𝑆, and let ℒ𝑃 (𝑆) ⊆ ℒ(𝑆) be the orderings starting
with a prefix 𝑃 . Let also 𝑐(𝐿) be the cost of the ordering 𝐿 ∈ ℒ(𝑉 ) as defined above.
Given a digraph 𝐷 = (𝑉, 𝐴), a set 𝑆 ⊂ 𝑉 , and a prefix 𝑃 , it has been proved in [CMN2014] that min𝐿∈ℒ𝑃 (𝑉 ) 𝑐(𝐿) =
min𝐿∈ℒ𝑃 +𝑣 (𝑉 ) 𝑐(𝐿) holds in two (non exhaustive) cases:
{︃
𝑁 + (𝑣) ⊆ 𝑆 ∪ 𝑁 + (𝑆)
or
𝑣 ∈ 𝑁 + (𝑆) and 𝑁 + (𝑣) ∖ (𝑆 ∪ 𝑁 + (𝑆)) = {𝑤}
In other words, if we find a vertex 𝑣 satisfying the above conditions, the best possible ordering with prefix 𝑃 has the
same cost as the best possible ordering with prefix 𝑃 + 𝑣. So we can greedily extend the prefix with vertices satisfying
the conditions which results in a significant reduction of the search space.
The algorithm:
Given the current prefix 𝑃 and the current upper bound 𝑈 𝐵 (either an input upper bound or the cost of the best solution
found so far), apply the following steps:
• Extend the prefix 𝑃 into a prefix 𝑃 ′ using the greedy steps as described above.
• Sort the vertices 𝑣 ∈ 𝑉 ∖ 𝑃 ′ by increasing values of |𝑁 + (𝑃 + 𝑣)|, and prune the vertices with a value larger or
equal to 𝑈 𝐵. Let ∆ be the resulting sorted list.
• Repeat with prefix 𝑃 ′ + 𝑣 for all 𝑣 ∈ ∆ and keep the best found solution.
If a lower bound is passed to the algorithm, it will stop as soon as a solution with cost equal to that lower bound is
found.
Storing prefixes:
If for a prefix 𝑃 we have 𝑐(𝑃 ) < min𝐿∈ℒ𝑃 (𝑉 ) 𝑐(𝐿) = 𝐶, then for any permutation 𝑃 ′ of 𝑃 we have
min𝐿∈ℒ𝑃 ′ (𝑉 ) 𝑐(𝐿) ≥ 𝐶.
Thus, given such a prefix 𝑃 there is no need to explore any of the orderings starting with one of its permutations. To
do so, we store 𝑃 (as a set of vertices) to cut branches later. See [CMN2014] for more details.
Since the number of stored sets can get very large, one can control the maximum length and the maximum number of
stored prefixes.
5.20.4 Authors
5.20.5 Methods
sage.graphs.graph_decompositions.vertex_separation.is_valid_ordering(G, L)
Test if the linear vertex ordering 𝐿 is valid for (di)graph 𝐺.
A linear ordering 𝐿 of the vertices of a (di)graph 𝐺 is valid if all vertices of 𝐺 are in 𝐿, and if 𝐿 contains no
other vertex and no duplicated vertices.
INPUT:
• G – a Graph or a DiGraph.
• L – an ordered list of the vertices of G.
OUTPUT:
Returns True if 𝐿 is a valid vertex ordering for 𝐺, and False otherwise.
EXAMPLES:
Path decomposition of a cycle:
sage.graphs.graph_decompositions.vertex_separation.linear_ordering_to_path_decomposition(G,
L)
Return the path decomposition encoded in the ordering L
INPUT:
• G – a Graph
• L – a linear ordering for G
OUTPUT:
A path graph whose vertices are the bags of the path decomposition.
EXAMPLES:
The bags of an optimal path decomposition of a path-graph have two vertices each:
sage: g = graphs.PathGraph(5)
sage: pw, L = vertex_separation(g, algorithm = "BAB"); pw
1
sage: h = linear_ordering_to_path_decomposition(g, L)
sage: sorted(h, key=str)
[{0, 1}, {1, 2}, {2, 3}, {3, 4}]
sage: sorted(h.edge_iterator(labels=None), key=str)
[({0, 1}, {1, 2}), ({1, 2}, {2, 3}), ({2, 3}, {3, 4})]
sage: g = graphs.PathGraph(5)
sage: L = [1, 4, 0, 2, 3]
sage: from sage.graphs.graph_decompositions.vertex_separation import width_of_path_
˓→decomposition
sage: width_of_path_decomposition(g, L)
3
sage: h = linear_ordering_to_path_decomposition(g, L)
sage: h.vertices(sort=True)
[{0, 2, 3, 4}, {0, 1, 2}]
The bags of the path decomposition of a cycle have three vertices each:
sage: g = graphs.CycleGraph(6)
sage: pw, L = vertex_separation(g, algorithm = "BAB"); pw
2
sage: h = linear_ordering_to_path_decomposition(g, L)
sage: sorted(h, key=str)
[{0, 1, 5}, {1, 2, 5}, {2, 3, 4}, {2, 4, 5}]
sage: sorted(h.edge_iterator(labels=None), key=str)
[({0, 1, 5}, {1, 2, 5}), ({1, 2, 5}, {2, 4, 5}), ({2, 4, 5}, {2, 3, 4})]
sage.graphs.graph_decompositions.vertex_separation.lower_bound(G)
Return a lower bound on the vertex separation of 𝐺.
INPUT:
• G – a Graph or a DiGraph
OUTPUT:
A lower bound on the vertex separation of 𝐷 (see the module’s documentation).
Note: This method runs in exponential time but has no memory constraint.
EXAMPLES:
On a circuit:
sage.graphs.graph_decompositions.vertex_separation.path_decomposition(G, algorithm='BAB',
cut_off=None,
upper_bound=None,
verbose=False,
max_prefix_length=20,
max_prefix_number=1000000)
Return the pathwidth of the given graph and the ordering of the vertices resulting in a corresponding path de-
composition.
INPUT:
• G – a Graph
• algorithm – string (default: "BAB"); algorithm to use among:
– "BAB" – Use a branch-and-bound algorithm. This algorithm has no size restriction but could take a
very long time on large graphs. It can also be used to test is the input (di)graph has vertex separation
at most upper_bound or to return the first found solution with vertex separation less or equal to a
cut_off value.
– exponential – Use an exponential time and space algorithm. This algorithm only works of graphs
on less than 32 vertices.
– MILP – Use a mixed integer linear programming formulation. This algorithm has no size restriction
but could take a very long time.
• upper_bound – integer (default: None); parameter used by the "BAB" algorithm. If specified, the algorithm
searches for a solution with width < upper_bound. It helps cutting branches. However, if the given upper
bound is too low, the algorithm may not be able to find a solution.
• cut_off – integer (default: None); parameter used by the "BAB" algorithm. This bound allows us to stop
the search as soon as a solution with width at most cut_off is found, if any. If this bound cannot be
reached, the best solution found is returned, unless a too low upper_bound is given.
• verbose – boolean (default: False); whether to display information on the computations
• max_prefix_length – integer (default: 20); limits the length of the stored prefixes to prevent storing too
many prefixes. This parameter is used only when algorithm=="BAB".
• max_prefix_number – integer (default: 10**6); upper bound on the number of stored prefixes used to
prevent using too much memory. This parameter is used only when algorithm=="BAB".
OUTPUT:
A pair (cost, ordering) representing the optimal ordering of the vertices and its cost.
See also:
EXAMPLES:
The pathwidth of a cycle is equal to 2:
sage: g = graphs.CycleGraph(6)
sage: pw, L = path_decomposition(g, algorithm = "BAB"); pw
2
sage: pw, L = path_decomposition(g, algorithm = "exponential"); pw
2
sage: pw, L = path_decomposition(g, algorithm = "MILP"); pw
2
EXAMPLES:
The pathwidth of a cycle is equal to 2:
sage: g = graphs.CycleGraph(6)
sage: g.pathwidth()
(continues on next page)
sage: g = graphs.PetersenGraph()
sage: g.pathwidth()
5
sage: g.pathwidth(k=2)
False
sage: g.pathwidth(k=6)
True
sage: g.pathwidth(k=6, certificate=True)
(True, Graph on 5 vertices)
sage.graphs.graph_decompositions.vertex_separation.vertex_separation(G, algorithm='BAB',
cut_off=None,
upper_bound=None,
verbose=False,
max_prefix_length=20,
max_prefix_number=1000000,
solver=None, integral-
ity_tolerance=0.001)
Return an optimal ordering of the vertices and its cost for vertex-separation.
INPUT:
• G – a Graph or a DiGraph
• algorithm – string (default: "BAB"); algorithm to use among:
– "BAB" – Use a branch-and-bound algorithm. This algorithm has no size restriction but could take a
very long time on large graphs. It can also be used to test is the input (di)graph has vertex separation
at most upper_bound or to return the first found solution with vertex separation less or equal to a
cut_off value.
– exponential – Use an exponential time and space algorithm. This algorithm only works of graphs
on less than 32 vertices.
– MILP – Use a mixed integer linear programming formulation. This algorithm has no size restriction
but could take a very long time.
• upper_bound – integer (default: None); parameter used by the "BAB" algorithm. If specified, the algorithm
searches for a solution with width < upper_bound. It helps cutting branches. However, if the given upper
bound is too low, the algorithm may not be able to find a solution.
• cut_off – integer (default: None); parameter used by the "BAB" algorithm. This bound allows us to stop
the search as soon as a solution with width at most cut_off is found, if any. If this bound cannot be
reached, the best solution found is returned, unless a too low upper_bound is given.
• verbose – boolean (default: False); whether to display information on the computations
• max_prefix_length – integer (default: 20); limits the length of the stored prefixes to prevent storing too
many prefixes. This parameter is used only when algorithm=="BAB".
• max_prefix_number – integer (default: 10**6); upper bound on the number of stored prefixes used to
prevent using too much memory. This parameter is used only when algorithm=="BAB".
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver is
used, see the method solve of the class MixedIntegerLinearProgram.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
OUTPUT:
A pair (cost, ordering) representing the optimal ordering of the vertices and its cost.
EXAMPLES:
Comparison of methods:
sage: G = digraphs.DeBruijn(2,3)
sage: vs,L = vertex_separation(G, algorithm="BAB"); vs
2
sage: vs,L = vertex_separation(G, algorithm="exponential"); vs
2
sage: vs,L = vertex_separation(G, algorithm="MILP"); vs
2
sage: G = graphs.Grid2dGraph(3,3)
sage: vs,L = vertex_separation(G, algorithm="BAB"); vs
3
sage: vs,L = vertex_separation(G, algorithm="exponential"); vs
3
sage: vs,L = vertex_separation(G, algorithm="MILP"); vs
3
sage: D = digraphs.Path(8)
sage: print(vertex_separation(D))
(0, [7, 6, 5, 4, 3, 2, 1, 0])
sage: D = digraphs.RandomDirectedAcyclicGraph(10, .5)
sage: vs,L = vertex_separation(D); vs
0
sage: K4 = DiGraph( graphs.CompleteGraph(4) )
sage: D = K4+K4
sage: D.add_edge(0, 4)
sage: print(vertex_separation(D))
(3, [4, 5, 6, 7, 0, 1, 2, 3])
sage: D = K4+K4+K4
sage: D.add_edge(0, 4)
sage: D.add_edge(0, 8)
sage: print(vertex_separation(D))
(3, [10, 11, 8, 9, 4, 5, 6, 7, 0, 1, 2, 3])
sage.graphs.graph_decompositions.vertex_separation.vertex_separation_BAB(G, cut_off=None,
upper_bound=None,
max_prefix_length=20,
max_prefix_number=1000000,
verbose=False)
Branch and Bound algorithm for the vertex separation.
This method implements the branch and bound algorithm for the vertex separation of directed graphs and the
pathwidth of undirected graphs proposed in [CMN2014]. The implementation is valid for both Graph and Di-
Graph. See the documentation of the vertex_separation module.
INPUT:
• G – a Graph or a DiGraph.
• cut_off – integer (default: None); bound to consider in the branch and bound algorithm. This allows us
to stop the search as soon as a solution with width at most cut_off is found, if any. If this bound cannot
be reached, the best solution found is returned, unless a too low upper_bound is given.
• upper_bound – integer (default: None); if specified, the algorithm searches for a solution with width <
upper_bound. It helps cutting branches. However, if the given upper bound is too low, the algorithm may
not be able to find a solution.
• max_prefix_length – integer (default: 20); limits the length of the stored prefixes to prevent storing too
many prefixes
• max_prefix_number – integer (default: 10**6); upper bound on the number of stored prefixes used to
prevent using too much memory
• verbose – boolean (default: False); display some information when set to True
OUTPUT:
• width – the computed vertex separation
• seq – an ordering of the vertices of width width
EXAMPLES:
The algorithm is valid for the vertex separation:
Testing for the existence of a solution with width strictly less than upper_bound:
sage.graphs.graph_decompositions.vertex_separation.vertex_separation_MILP(G,
integrality=False,
solver=None,
verbose=0,
integral-
ity_tolerance=0.001)
Compute the vertex separation of 𝐺 and the optimal ordering of its vertices using an MILP formulation.
This function uses a mixed integer linear program (MILP) for determining an optimal layout for the vertex sep-
aration of 𝐺. This MILP is an improved version of the formulation proposed in [SP2010]. See the module's
documentation for more details on this MILP formulation.
INPUT:
• G – a Graph or a DiGraph
• integrality – boolean (default: False); specify if variables 𝑥𝑡𝑣 and 𝑢𝑡𝑣 must be integral or if they can be
relaxed. This has no impact on the validity of the solution, but it is sometimes faster to solve the problem
using binary variables only.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver is
used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
OUTPUT:
A pair (cost, ordering) representing the optimal ordering of the vertices and its cost.
EXAMPLES:
Vertex separation of a De Bruijn digraph:
sage.graphs.graph_decompositions.vertex_separation.vertex_separation_exp(G, verbose=False)
Return an optimal ordering of the vertices and its cost for vertex-separation.
INPUT:
• G – a Graph or a DiGraph
• verbose – boolean (default: False); whether to display information on the computations
OUTPUT:
A pair (cost, ordering) representing the optimal ordering of the vertices and its cost.
Note: Because of its current implementation, this algorithm only works on graphs on less than 32 vertices. This
can be changed to 54 if necessary, but 32 vertices already require 4GB of memory.
EXAMPLES:
The vertex separation of a circuit is equal to 1:
sage: g = digraphs.Circuit(6)
sage: vertex_separation_exp(g)
(1, [0, 1, 2, 3, 4, 5])
sage.graphs.graph_decompositions.vertex_separation.width_of_path_decomposition(G, L)
Return the width of the path decomposition induced by the linear ordering 𝐿 of the vertices of 𝐺.
If 𝐺 is an instance of Graph , this function returns the width 𝑝𝑤𝐿 (𝐺) of the path decomposition induced by the
linear ordering 𝐿 of the vertices of 𝐺. If 𝐺 is a DiGraph , it returns instead the width 𝑣𝑠𝐿 (𝐺) of the directed
path decomposition induced by the linear ordering 𝐿 of the vertices of 𝐺, where
INPUT:
• G – a Graph or a DiGraph
• L – a linear ordering of the vertices of G
EXAMPLES:
Path decomposition of a cycle:
This module wraps C code from Philipp Klaus Krause computing an optimal rank-decomposition.
Definitions :
Given a graph 𝐺 and a subset 𝑆 ⊆ 𝑉 (𝐺) of vertices, the rank-width of 𝑆 in 𝐺, denoted 𝑟𝑤𝐺 (𝑆), is equal to the rank in
𝐺𝐹 (2) of the |𝑆| × (|𝑉 | − |𝑆|) matrix of the adjacencies between the vertices of 𝑆 and 𝑉 ∖𝑆. By definition, 𝑟𝑤𝐺 (𝑆)
is equal to 𝑟𝑤𝐺 (𝑆) where 𝑆 is the complement of 𝑆 in 𝑉 (𝐺).
A rank-decomposition of 𝐺 is a tree whose 𝑛 leaves are the elements of 𝑉 (𝐺), and whose internal nodes have degree
3. In a tree, any edge naturally corresponds to a bipartition of the vertex set : indeed, the removal of any edge splits
the tree into two connected components, thus splitting the set of leaves (i.e. vertices of 𝐺) into two sets. Hence we can
define for any edge 𝑒 ∈ 𝐸(𝐺) a width equal to the value 𝑟𝑤𝐺 (𝑆) or 𝑟𝑤𝐺 (𝑆), where 𝑆, 𝑆 is the bipartition obtained
from 𝑒. The rank-width associated to the whole decomposition is then set to the maximum of the width of all the edges
it contains.
A rank-decomposition is said to be optimal for 𝐺 if it is the decomposition achieving the minimal rank-width.
RW – The original source code :
RW is a program that calculates rank-width and rank-decompositions. It is based on ideas from:
• “Computing rank-width exactly” by Sang-il Oum [Oum2009]
• “Sopra una formula numerica” by Ernesto Pascal
• “Generation of a Vector from the Lexicographical Index” by B.P. Buckles and M. Lybanon [BL1977]
• “Fast additions on masked integers” by Michael D. Adams and David S. Wise [AW2006]
OUTPUT:
The rank decomposition is returned as a tree whose vertices are subsets of 𝑉 (𝐺). Its leaves, corresponding to the
vertices of 𝐺 are sets of 1 elements, i.e. singletons.
sage: g = graphs.PetersenGraph()
sage: rw, tree = g.rank_decomposition()
sage: all(len(v)==1 for v in tree if tree.degree(v) == 1)
True
The internal nodes are sets of the decomposition. This way, it is easy to deduce the bipartition associated to an edge
from the tree. Indeed, two adjacent vertices of the tree are comparable sets : they yield the bipartition obtained from
the smaller of the two and its complement.
sage: g = graphs.PetersenGraph()
sage: rw, tree = g.rank_decomposition()
sage: u = Set([8, 9, 3, 7])
sage: v = Set([8, 9])
sage: tree.has_edge(u,v)
True
(continues on next page)
Warning:
• The current implementation cannot handle graphs of ≥ 32 vertices.
• A bug that has been reported upstream make the code crash immediately on instances of size 30. If you
experience this kind of bug please report it to us, what we need is some information on the hardware you run
to know where it comes from !
EXAMPLES:
sage: g = graphs.PetersenGraph()
sage: g.rank_decomposition()
(3, Graph on 19 vertices)
AUTHORS:
• Philipp Klaus Krause : Implementation of the C algorithm
• Nathann Cohen : Interface with Sage and documentation
5.21.1 Methods
sage.graphs.graph_decompositions.rankwidth.mkgraph(num_vertices)
Return the graph corresponding to the current rank-decomposition.
(This function is for internal use)
EXAMPLES:
sage.graphs.graph_decompositions.rankwidth.rank_decomposition(G, verbose=False)
Compute an optimal rank-decomposition of the given graph.
This function is available as a method of the Graph class. See rank_decomposition.
INPUT:
• verbose – boolean (default: False); whether to display progress information while computing the de-
composition
OUTPUT:
A pair (rankwidth, decomposition_tree), where rankwidth is a numerical value and
decomposition_tree is a ternary tree describing the decomposition (cf. the module’s documentation).
EXAMPLES:
sage: g = Graph()
sage: rank_decomposition(g)
(0, Graph on 0 vertices)
5.22.1 Definition
The bandwidth 𝑏𝑤(𝑀 ) of a matrix 𝑀 is the smallest integer 𝑘 such that all non-zero entries of 𝑀 are at distance 𝑘
from the diagonal. The bandwidth 𝑏𝑤(𝐺) of an undirected graph 𝐺 is the minimum bandwidth of the adjacency matrix
of 𝐺, over all possible relabellings of its vertices.
Path spanner: alternatively, the bandwidth measures how tightly a path represents the distance of a graph 𝐺. Indeed,
if the vertices of 𝐺 can be ordered as 𝑣1 , ..., 𝑣𝑛 in such a way that 𝑘 × 𝑑𝐺 (𝑣𝑖 , 𝑣𝑗 ) ≥ |𝑖 − 𝑗| then 𝑏𝑤(𝐺) ≤ 𝑘.
Proof: for all 𝑣𝑖 ∼ 𝑣𝑗 (i.e. 𝑑𝐺 (𝑣𝑖 , 𝑣𝑗 ) = 1), the constraint ensures that 𝑘 ≥ |𝑖 − 𝑗|, meaning that adjacent
vertices are at distance at most 𝑘 in the path ordering. That alone is sufficient to ensure that 𝑏𝑤(𝐺) ≤ 𝑘.
As a byproduct, we obtain that 𝑘 × 𝑑𝐺 (𝑣𝑖 , 𝑣𝑗 ) ≥ |𝑖 − 𝑗| in general: let 𝑣𝑠0 , ..., 𝑣𝑠𝑖 be the vertices of a
shortest (𝑣𝑖 , 𝑣𝑗 )-path. We have:
Let us suppose that the first 𝑖 vertices 𝑣1 , ..., 𝑣𝑖 of 𝐺 have already been assigned positions 𝑝1 , ..., 𝑝𝑖 in an ordering of
𝑉 (𝐺) of bandwidth ≤ 𝑘. Where can 𝑣𝑖+1 appear ?
Because of the previous definition, 𝑝𝑖+1 must be at distance at most 𝑘 ×𝑑𝐺 (𝑣1 , 𝑣𝑖+1 ) from 𝑝1 , and in general at distance
at most 𝑘 × 𝑑𝐺 (𝑣𝑗 , 𝑣𝑖+1 ) from 𝑝𝑗 . Each range is an interval of {1, ..., 𝑛}∖{𝑝1 , ..., 𝑝𝑖 }, and because the intersection of
two intervals is again an interval we deduce that in order to satisfy all these constraints simultaneously 𝑝𝑗 must belong
to an interval defined from this partial assignment.
Applying this rule to all non-assigned vertices, we deduce that each of them must be assigned to a given interval of
{1, ..., 𝑛}. Note that this can also be extended to the already assigned vertices, by saying that 𝑣𝑗 with 𝑗 < 𝑖 must be
assigned within the interval [𝑝𝑗 , 𝑝𝑗 ].
This problem is not always satisfiable, e.g. 5 vertices cannot all be assigned to the elements of [10, 13]. This is a
matching problem which, because all admissible sets are intervals, can be solved quickly.
Let 𝑛 points 𝑣1 , ..., 𝑣𝑛 be given, along with two functions 𝑚, 𝑀 : [𝑛] ↦→ [𝑛]. Is there an ordering 𝑝1 , ..., 𝑝𝑛 of them
such that 𝑚(𝑣𝑖 ) ≤ 𝑝𝑖 ≤ 𝑀 (𝑣𝑖 ) ? This is equivalent to Hall’s bipartite matching theorem, and can in this specific case
be solved by the following algorithm:
• Consider all vertices 𝑣 sorted increasingly according to 𝑀 (𝑣)
• For each of them, assign to 𝑣 the smallest position in [𝑚(𝑣), 𝑀 (𝑣)] which has not been assigned yet. If there is
none, the assignment problem is not satisfiable.
Note that the latest operation can be performed with very few bitset operations (provided that 𝑛 < 64).
This section contains totally subjective choices, that may be changed in the hope to get better performances.
• Try to find a satisfiable ordering by filling positions, one after the other (and not by trying to find each vertex’
position)
• Fill the positions in this order: 0, 𝑛 − 1, 1, 𝑛 − 2, 3, 𝑛 − 3, ...
Note: There is some symmetry to break as the reverse of a satisfiable ordering is also a satisfiable ordering.
5.22.6 Functions
sage.graphs.graph_decompositions.bandwidth.bandwidth(G, k=None)
Compute the bandwidth of an undirected graph.
For a definition of the bandwidth of a graph, see the documentation of the bandwidth module.
INPUT:
• G – a graph
• k – integer (default: None); set to an integer value to test whether 𝑏𝑤(𝐺) ≤ 𝑘, or to None (default) to
compute 𝑏𝑤(𝐺)
OUTPUT:
When 𝑘 is an integer value, the function returns either False or an ordering of cost ≤ 𝑘.
When 𝑘 is equal to None, the function returns a pair (bw, ordering).
See also:
sage.graphs.generic_graph.GenericGraph.adjacency_matrix() – return the adjacency matrix from
an ordering of the vertices.
EXAMPLES:
5.23 Cutwidth
This module implements several algorithms to compute the cutwidth of a graph and the corresponding ordering of the
vertices. It also implements tests functions for evaluation the width of a linear ordering (or layout).
Given an ordering 𝑣1 , · · · , 𝑣𝑛 of the vertices of 𝑉 (𝐺), its cost is defined as:
Where
The cutwidth of a graph 𝐺 is equal to the minimum cost of an ordering of its vertices.
This module contains the following methods
cutwidth() Return the cutwidth of the graph and the corresponding vertex ordering.
cutwidth_dyn() Compute the cutwidth of 𝐺 using an exponential time and space algorithm based
on dynamic programming
cutwidth_MILP() Compute the cutwidth of 𝐺 and the optimal ordering of its vertices using an
MILP formulation
Return the width of the cut decomposition induced by the linear ordering 𝐿 of
width_of_cut_decomposition()
the vertices of 𝐺
In order to find an optimal ordering of the vertices for the vertex separation, this algorithm tries to save time by com-
puting the function 𝑐′ (𝑆) at most once once for each of the sets 𝑆 ⊆ 𝑉 (𝐺). These values are stored in an array of size
2𝑛 where reading the value of 𝑐′ (𝑆) or updating it can be done in constant time.
Assuming that we can compute the cost of a set 𝑆 and remember it, finding an optimal ordering is an easy task.
Indeed, we can think of the sequence 𝑣1 , ..., 𝑣𝑛 of vertices as a sequence of sets {𝑣1 }, {𝑣1 , 𝑣2 }, ..., {𝑣1 , ..., 𝑣𝑛 }, whose
cost is precisely max 𝑐′ ({𝑣1 }), 𝑐′ ({𝑣1 , 𝑣2 }), ..., 𝑐′ ({𝑣1 , ..., 𝑣𝑛 }). Hence, when considering the digraph on the 2𝑛 sets
𝑆 ⊆ 𝑉 (𝐺) where there is an arc from 𝑆 to 𝑆 ′ if 𝑆 ′ = 𝑆 ∩{𝑣} for some 𝑣 (that is, if the sets 𝑆 and 𝑆 ′ can be consecutive
in a sequence), an ordering of the vertices of 𝐺 corresponds to a path from ∅ to {𝑣1 , ..., 𝑣𝑛 }. In this setting, checking
whether there exists a ordering of cost less than 𝑘 can be achieved by checking whether there exists a directed path ∅
to {𝑣1 , ..., 𝑣𝑛 } using only sets of cost less than 𝑘. This is just a depth-first-search, for each 𝑘.
Lazy evaluation of 𝑐′
In the previous algorithm, most of the time is actually spent on the computation of 𝑐′ (𝑆) for each set 𝑆 ⊆ 𝑉 (𝐺) – i.e.
2𝑛 computations of neighborhoods. This can be seen as a huge waste of time when noticing that it is useless to know
that the value 𝑐′ (𝑆) for a set 𝑆 is less than 𝑘 if all the paths leading to 𝑆 have a cost greater than 𝑘. For this reason, the
value of 𝑐′ (𝑆) is computed lazily during the depth-first search. Explanation :
When the depth-first search discovers a set of size less than 𝑘, the costs of its out-neighbors (the potential sets that
could follow it in the optimal ordering) are evaluated. When an out-neighbor is found that has a cost smaller than 𝑘, the
depth-first search continues with this set, which is explored with the hope that it could lead to a path toward {𝑣1 , ..., 𝑣𝑛 }.
On the other hand, if an out-neighbour has a cost larger than 𝑘 it is useless to attempt to build a cheap sequence going
though this set, and the exploration stops there. This way, a large number of sets will never be evaluated and a lot of
computational time is saved this way.
Besides, some improvement is also made by “improving” the values found by 𝑐′ . Indeed, 𝑐′ (𝑆) is a lower bound on the
cost of a sequence containing the set 𝑆, but if all out-neighbors of 𝑆 have a cost of 𝑐′ (𝑆) + 5 then one knows that having
𝑆 in a sequence means a total cost of at least 𝑐′ (𝑆) + 5. For this reason, for each set 𝑆 we store the value of 𝑐′ (𝑆), and
replace it by max(𝑐′ (𝑆), minnext ) (where minnext is the minimum of the costs of the out-neighbors of 𝑆) once the costs
of these out-neighbors have been evaluated by the algorithm.
This algorithm and its implementation are very similar to sage.graphs.graph_decompositions.
vertex_separation.vertex_separation_exp(). The main difference is in the computation of 𝑐′ (𝑆). See
the vertex separation module's documentation for more details on this algorithm.
Note: Because of its current implementation, this algorithm only works on graphs on strictly less than 32 vertices.
This can be changed to 64 if necessary, but 32 vertices already require 4GB of memory.
We describe a mixed integer linear program (MILP) for determining an optimal layout for the cutwidth of 𝐺.
Variables:
• 𝑥𝑘𝑣 – Variable set to 1 if vertex 𝑣 is placed in the ordering at position 𝑖 with 𝑖 ≤ 𝑘, and 0 otherwise.
• 𝑦𝑢,𝑣
𝑘
– Variable set to 1 if one of 𝑢 or 𝑣 is at a position 𝑖 ≤ 𝑘 and the other is at a position 𝑗 > 𝑘, and so we have
to count edge 𝑢𝑣 at position 𝑘. Otherwise, 𝑦𝑢,𝑣 𝑘
= 0. The value of 𝑦𝑢,𝑣
𝑘
is a xor of the values of 𝑥𝑘𝑢 and 𝑥𝑘𝑣 .
• 𝑧 – Objective value to minimize. It is equal to the maximum over all position 𝑘 of the ∑︀number𝑘of edges with one
extremity at position at most 𝑘 and the other at position strictly more than 𝑘, that is 𝑢𝑣∈𝐸 𝑦𝑢,𝑣 .
MILP formulation:
Minimize:
Subject to:
𝑘−1
∑︁
𝑥𝑖𝑣 ≤ 𝑘 * 𝑥𝑘𝑣 ∀𝑣 ∈ 𝑉, 𝑘 ∈ [1, 𝑛 − 1] (1)
𝑖=0
𝑥𝑛𝑣 = 1 ∀𝑣 ∈ 𝑉 (2)
∑︁
𝑥𝑘𝑣 =𝑘+1 ∀𝑘 ∈ [0, 𝑛 − 1] (3)
𝑣∈𝑉
𝑥𝑘𝑢 − 𝑥𝑘𝑣 𝑘
≤ 𝑦𝑢,𝑣 ∀𝑢𝑣 ∈ 𝐸, ∀𝑘 ∈ [0, 𝑛 − 1] (4)
𝑥𝑘𝑣 − 𝑥𝑘𝑢 ≤ 𝑘
𝑦𝑢,𝑣 ∀𝑢𝑣 ∈ 𝐸, ∀𝑘 ∈ [0, 𝑛 − 1] (5)
∑︁
𝑘
𝑦𝑢,𝑣 ≤𝑧 ∀𝑘 ∈ [0, 𝑛 − 1] (6)
𝑢𝑣∈𝐸
0 ≤ 𝑧 ≤ |𝐸|
Constraints (1)-(3) ensure that all vertices have a distinct position. Constraints (4)-(5) force variable 𝑦𝑢,𝑣
𝑘
to 1 if the
edge is in the cut. Constraint (6) count the number of edges starting at position at most 𝑘 and ending at a position
strictly larger than 𝑘.
This formulation corresponds to method cutwidth_MILP().
5.23.3 Authors
5.23.4 Methods
• lower_bound – integer (default: 0); the algorithm searches for a solution with cost larger or equal to
lower_bound. If the given bound is larger than the optimal solution the returned solution might not be
optimal. If the given bound is too high, the algorithm might not be able to find a feasible solution.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver is
used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
OUTPUT:
A pair (cost, ordering) representing the optimal ordering of the vertices and its cost.
EXAMPLES:
Cutwidth of a Cycle graph:
sage.graphs.graph_decompositions.cutwidth.cutwidth_dyn(G, lower_bound=0)
Dynamic programming algorithm for the cutwidth of a Graph.
This function uses dynamic programming algorithm for determining an optimal layout for the cutwidth of 𝐺.
See the module's documentation for more details on this method.
INPUT:
• G – a Graph
• lower_bound – integer (default: 0); the algorithm returns immediately if it finds a solution lower or equal
to lower_bound (in which case it may not be optimal).
OUTPUT:
A pair (cost, ordering) representing the optimal ordering of the vertices and its cost.
Note: Because of its current implementation, this algorithm only works on graphs on strictly less than 32
vertices. This can be changed to 63 if necessary, but 32 vertices already require 4GB of memory.
sage.graphs.graph_decompositions.cutwidth.width_of_cut_decomposition(G, L)
Return the width of the cut decomposition induced by the linear ordering 𝐿 of the vertices of 𝐺.
If 𝐺 is an instance of Graph , this function returns the width 𝑐𝑤𝐿 (𝐺) of the cut decomposition induced by the
linear ordering 𝐿 of the vertices of 𝐺.
𝑐𝑤𝐿 (𝐺) = max |{(𝑢, 𝑤) ∈ 𝐸(𝐺) | 𝑢 ∈ 𝐿[: 𝑖] and 𝑤 ∈ 𝑉 (𝐺) ∖ 𝐿[: 𝑖]}|
0≤𝑖<|𝑉 |−1
INPUT:
• G – a Graph
• L – a linear ordering of the vertices of G
EXAMPLES:
Cut decomposition of a Cycle graph:
This module gathers everything related to graph products. At the moment it contains an implementation of a recognition
algorithm for graphs that can be written as a Cartesian product of smaller ones.
Author:
• Nathann Cohen (May 2012 – coded while watching the election of Francois Hollande on TV)
First, a definition:
Definition The Cartesian product of two graphs 𝐺 and 𝐻, denoted 𝐺𝐻, is a graph defined on the pairs
(𝑔, ℎ) ∈ 𝑉 (𝐺) × 𝑉 (𝐻).
Two elements (𝑔, ℎ), (𝑔 ′ , ℎ′ ) ∈ 𝑉 (𝐺𝐻) are adjacent in 𝐺𝐻 if and only if :
• 𝑔 = 𝑔 ′ and ℎℎ′ ∈ 𝐻; or
• ℎ = ℎ′ and 𝑔𝑔 ′ ∈ 𝐺
Two remarks follow :
1. The Cartesian product is commutative
2. Any edge 𝑢𝑣 of a graph 𝐺1 · · · 𝐺𝑘 can be given a color 𝑖 corresponding to the unique index 𝑖 such that 𝑢𝑖
and 𝑣𝑖 differ.
The problem that is of interest to us in the present module is the following:
Recognition problem Given a graph 𝐺, can we guess whether there exist graphs 𝐺1 , ..., 𝐺𝑘 such that
𝐺 = 𝐺1 · · · 𝐺𝑘 ?
This problem can actually be solved, and the resulting factorization is unique. What is explained below can be found
in the book Handbook of Product Graphs [HIK2011].
Everything is actually based on simple observations. Given a graph 𝐺, finding out whether 𝐺 can be written as the
product of several graphs can be attempted by trying to color its edges according to some rules. Indeed, if we are to
color the edges of 𝐺 in such a way that each color class represents a factor of 𝐺, we must ensure several things.
Remark 1 In any cycle of 𝐺 no color can appear exactly once.
Indeed, if only one edge 𝑢𝑣 of a cycle were labelled with color 𝑖, it would mean that:
1. The only difference between 𝑢 and 𝑣 lies in their 𝑖 th coordinate
2. It is possible to go from 𝑢 to 𝑣 by changing only coordinates different from the 𝑖 th
A contradiction indeed.
That means that, for instance, the edges of a triangle necessarily have the same color.
Remark 2 If two consecutive edges 𝑢1 𝑢2 and 𝑢2 𝑢3 have different colors, there necessarily exists a unique
vertex 𝑢4 different from 𝑢2 and incident to both 𝑢1 and 𝑢3 .
In this situation, opposed edges necessarily have the same colors because of the previous remark.
The algorithm
The previous remarks tell us that some edges are in some way equivalent to some others, i.e. that their colors are equal.
In order to compute the coloring we are looking for, we therefore build a graph on the edges of a graph 𝐺, linking two
edges whenever they are found to be equivalent according to the previous remarks.
All that is left to do is to compute the connected components of this new graph, as each of them representing the edges
of a factor. Of course, only one connected component indicates that the graph has no factorization.
Then again, please refer to [HIK2011] for any technical question.
To Do
This implementation is made at Python level, and some parts of the algorithm could be rewritten in Cython to save
time. Especially when enumerating all pairs of edges and computing their distances. This can easily be done in C with
the functions from the sage.graphs.distances_all_pairs module.
5.24.2 Methods
sage.graphs.graph_decompositions.graph_products.is_cartesian_product(g, certificate=False,
relabeling=False)
Test whether the graph is a Cartesian product.
INPUT:
• certificate – boolean (default: False); if certificate = False (default) the method only returns
True or False answers. If certificate = True, the True answers are replaced by the list of the factors
of the graph.
• relabeling – boolean (default: False); if relabeling = True (implies certificate = True), the
method also returns a dictionary associating to each vertex its natural coordinates as a vertex of a product
graph. If 𝑔 is not a Cartesian product, None is returned instead.
See also:
• sage.graphs.generic_graph.GenericGraph.cartesian_product()
• graph_products – a module on graph products.
Note: This algorithm may run faster whenever the graph’s vertices are integers (see relabel()). Give it a try
if it is too slow !
EXAMPLES:
The Petersen graph is prime:
sage: g = graphs.PetersenGraph()
sage: is_cartesian_product(g)
False
sage: g = graphs.Grid2dGraph(5,5)
sage: p1, p2 = is_cartesian_product(g, certificate = True)
sage: p1.is_isomorphic(graphs.PathGraph(5))
True
sage: p2.is_isomorphic(graphs.PathGraph(5))
True
sage: g.relabel()
sage: b,D = g.is_cartesian_product(g, relabeling=True)
sage: b
True
sage: D # random isomorphism
{0: (20, 0), 1: (20, 1), 2: (20, 2), 3: (20, 3), 4: (20, 4),
5: (15, 0), 6: (15, 1), 7: (15, 2), 8: (15, 3), 9: (15, 4),
10: (10, 0), 11: (10, 1), 12: (10, 2), 13: (10, 3), 14: (10, 4),
(continues on next page)
And of course, we find the factors back when we build a graph from a product:
sage: g = graphs.PetersenGraph().cartesian_product(graphs.CycleGraph(3))
sage: g1, g2 = is_cartesian_product(g, certificate = True)
sage: any( x.is_isomorphic(graphs.PetersenGraph()) for x in [g1,g2])
True
sage: any( x.is_isomorphic(graphs.CycleGraph(3)) for x in [g1,g2])
True
This module implements the function for computing the modular decomposition of undirected graphs.
class sage.graphs.graph_decompositions.modular_decomposition.Node(node_type)
Bases: object
Node class stores information about the node type, node split and index of the node in the parent tree.
Node type can be PRIME, SERIES, PARALLEL, NORMAL or FOREST. Node split can be NO_SPLIT, LEFT_SPLIT,
RIGHT_SPLIT or BOTH_SPLIT. A node is split in the refinement phase and the split used is propagated to the
ancestors.
• node_type – is of type NodeType and specifies the type of node
• node_split – is of type NodeSplit and specifies the type of splits which have occurred in the node and its
descendants
• index_in_root – specifies the index of the node in the forest obtained after promotion phase
• comp_num – specifies the number given to nodes in a (co)component before refinement
• is_separated – specifies whether a split has occurred with the node as the root
has_left_split()
Check whether self has LEFT_SPLIT.
EXAMPLES:
has_right_split()
Check whether self has RIGHT_SPLIT.
EXAMPLES:
set_node_split(node_split)
Add node_split to the node split of self.
LEFT_SPLIT and RIGHT_SPLIT can exist together in self as BOTH_SPLIT.
INPUT:
• node_split – node_split to be added to self
EXAMPLES:
class sage.graphs.graph_decompositions.modular_decomposition.NodeSplit
Bases: enum.Enum
Enumeration class used to specify the split that has occurred at the node or at any of its descendants.
NodeSplit is defined for every node in modular decomposition tree and is required during the refinement and
promotion phase of modular decomposition tree computation. Various node splits defined are
• LEFT_SPLIT – indicates a left split has occurred
• RIGHT_SPLIT – indicates a right split has occurred
• BOTH_SPLIT – indicates both left and right split have occurred
• NO_SPLIT – indicates no split has occurred
class sage.graphs.graph_decompositions.modular_decomposition.NodeType
Bases: enum.Enum
NodeType is an enumeration class used to define the various types of nodes in modular decomposition tree.
The various node types defined are
• PARALLEL – indicates the node is a parallel module
• SERIES – indicates the node is a series module
• PRIME – indicates the node is a prime module
sage.graphs.graph_decompositions.modular_decomposition.create_normal_node(vertex)
Return a normal node with no children
INPUT:
• vertex – vertex number
OUTPUT:
A node object representing the vertex with node_type set as NodeType.NORMAL
EXAMPLES:
sage.graphs.graph_decompositions.modular_decomposition.create_parallel_node()
Return a parallel node with no children
OUTPUT:
A node object with node_type set as NodeType.PARALLEL
EXAMPLES:
sage.graphs.graph_decompositions.modular_decomposition.create_prime_node()
Return a prime node with no children
OUTPUT:
A node object with node_type set as NodeType.PRIME
EXAMPLES:
sage.graphs.graph_decompositions.modular_decomposition.create_series_node()
Return a series node with no children
OUTPUT:
A node object with node_type set as NodeType.SERIES
EXAMPLES:
sage.graphs.graph_decompositions.modular_decomposition.either_connected_or_not_connected(v,
ver-
tices_in_module,
graph)
Check whether v is connected or disconnected to all vertices in the module.
INPUT:
• v – vertex tested
• vertices_in_module – list containing vertices in the module
• graph – graph to which the vertices belong
EXAMPLES:
sage.graphs.graph_decompositions.modular_decomposition.equivalent_trees(root1, root2)
Check that two modular decomposition trees are the same.
Verify that the structure of the trees is the same. Two leaves are equivalent if they represent the same vertex, two
internal nodes are equivalent if they have the same nodes type and the same number of children and there is a
matching between the children such that each pair of children is a pair of equivalent subtrees.
EXAMPLES:
sage.graphs.graph_decompositions.modular_decomposition.gamma_classes(graph)
Partition the edges of the graph into Gamma classes.
Two distinct edges are Gamma related if they share a vertex but are not part of a triangle. A Gamma class of
edges is a collection of edges such that any edge in the class can be reached from any other by a chain of Gamma
related edges (that are also in the class).
The two important properties of the Gamma class
• The vertex set corresponding to a Gamma class is a module
• If the graph is not fragile (neither it or its complement is disconnected) then there is exactly one class that
visits all the vertices of the graph, and this class consists of just the edges that connect the maximal strong
modules of that graph.
EXAMPLES:
The gamma_classes of the octahedral graph are the three 4-cycles corresponding to the slices through the center
of the octahedron:
sage: g = graphs.OctahedralGraph()
sage: sorted(gamma_classes(g), key=str)
[frozenset({0, 1, 4, 5}), frozenset({0, 2, 3, 5}), frozenset({1, 2, 3, 4})]
sage.graphs.graph_decompositions.modular_decomposition.get_module_type(graph)
Return the module type of the root of the modular decomposition tree of graph.
INPUT:
• graph – input sage graph
OUTPUT:
PRIME if graph is PRIME, PARALLEL if graph is PARALLEL and SERIES if graph is of type SERIES
EXAMPLES:
sage: g = graphs.HexahedralGraph()
sage: get_module_type(g)
PRIME
sage.graphs.graph_decompositions.modular_decomposition.get_vertices(component_root)
Compute the list of vertices in the (co)component
INPUT:
• component_root – root of the (co)component whose vertices need to be returned as a list
OUTPUT:
list of vertices in the (co)component
EXAMPLES:
sage.graphs.graph_decompositions.modular_decomposition.habib_maurer_algorithm(graph,
g_classes=None)
Compute the modular decomposition by the algorithm of Habib and Maurer
Compute the modular decomposition of the given graph by the algorithm of Habib and Maurer [HM1979] . If
the graph is disconnected or its complement is disconnected return a tree with a PARALLEL or SERIES node at the
root and children being the modular decomposition of the subgraphs induced by the components. Otherwise, the
root is PRIME and the modules are identified by having identical neighborhoods in the gamma class that spans the
vertices of the subgraph (exactly one is guaranteed to exist). The gamma classes only need to be computed once,
as the algorithm computes the the classes for the current root and each of the submodules. See also [BM1983]
for an equivalent algorithm described in greater detail.
INPUT:
• graph – the graph for which modular decomposition tree needs to be computed
• g_classes – dictionary (default: None); a dictionary whose values are the gamma classes of the graph,
and whose keys are a frozenset of the vertices corresponding to the class. Used internally.
OUTPUT:
The modular decomposition tree of the graph.
EXAMPLES:
The Icosahedral graph is Prime:
sage: print_md_tree(habib_maurer_algorithm(graphs.OctahedralGraph()))
SERIES
PARALLEL
0
5
PARALLEL
1
4
PARALLEL
2
3
sage: print_md_tree(habib_maurer_algorithm(graphs.TetrahedralGraph()))
SERIES
0
1
2
3
sage: print_md_tree(habib_maurer_algorithm(graphs.TetrahedralGraph()))
SERIES
0
1
2
3
sage.graphs.graph_decompositions.modular_decomposition.md_tree_to_graph(root)
Create a graph having the given MD tree.
For the prime nodes we use that every path of length 4 or more is prime.
TODO: accept a function that generates prime graphs as a parameter and use that in the prime nodes.
EXAMPLES:
sage.graphs.graph_decompositions.modular_decomposition.modular_decomposition(graph,
g_classes=None)
Compute the modular decomposition by the algorithm of Habib and Maurer
Compute the modular decomposition of the given graph by the algorithm of Habib and Maurer [HM1979] . If
the graph is disconnected or its complement is disconnected return a tree with a PARALLEL or SERIES node at the
root and children being the modular decomposition of the subgraphs induced by the components. Otherwise, the
root is PRIME and the modules are identified by having identical neighborhoods in the gamma class that spans the
vertices of the subgraph (exactly one is guaranteed to exist). The gamma classes only need to be computed once,
as the algorithm computes the the classes for the current root and each of the submodules. See also [BM1983]
for an equivalent algorithm described in greater detail.
INPUT:
• graph – the graph for which modular decomposition tree needs to be computed
• g_classes – dictionary (default: None); a dictionary whose values are the gamma classes of the graph,
and whose keys are a frozenset of the vertices corresponding to the class. Used internally.
OUTPUT:
The modular decomposition tree of the graph.
EXAMPLES:
The Icosahedral graph is Prime:
sage: print_md_tree(habib_maurer_algorithm(graphs.OctahedralGraph()))
SERIES
PARALLEL
0
5
PARALLEL
1
4
PARALLEL
2
3
sage: print_md_tree(habib_maurer_algorithm(graphs.TetrahedralGraph()))
SERIES
0
1
2
3
sage: print_md_tree(habib_maurer_algorithm(graphs.TetrahedralGraph()))
SERIES
0
1
2
3
sage.graphs.graph_decompositions.modular_decomposition.nested_tuple_to_tree(nest)
Turn a tuple representing the modular decomposition into a tree.
INPUT:
• nest – a nested tuple of the form returned by tree_to_nested_tuple()
OUTPUT:
The root node of a modular decomposition tree.
EXAMPLES:
sage.graphs.graph_decompositions.modular_decomposition.permute_decomposition(*args,
**kwargs)
Check that a graph and its permuted relabeling have the same modular decomposition.
We generate a trials random graphs and then generate an isomorphic graph by relabeling the original graph.
We then verify
EXAMPLES:
sage.graphs.graph_decompositions.modular_decomposition.print_md_tree(root)
Print the modular decomposition tree
INPUT:
• root – root of the modular decomposition tree
EXAMPLES:
sage.graphs.graph_decompositions.modular_decomposition.random_md_tree(max_depth,
max_fan_out,
leaf_probability)
Create a random MD tree.
INPUT:
• max_depth – the maximum depth of the tree.
• max_fan_out – the maximum number of children a node can have (must be >=4 as a prime node must
have at least 4 vertices).
• leaf_probability – the probability that a subtree is a leaf
EXAMPLES:
sage.graphs.graph_decompositions.modular_decomposition.recreate_decomposition(*args,
**kwargs)
Verify that we can recreate a random MD tree.
We create a random MD tree, then create a graph having that decomposition, then find a modular decomposition
for that graph, and verify that the two modular decomposition trees are equivalent.
EXAMPLES:
sage.graphs.graph_decompositions.modular_decomposition.relabel_tree(root, perm)
Relabel the leaves of a tree according to a dictionary
INPUT:
• root – the root of the tree
• perm – a function, dictionary, list, permutation, or None representing the relabeling. See relabel() for
description of the permutation input.
EXAMPLES:
sage.graphs.graph_decompositions.modular_decomposition.test_gamma_modules(*args, **kwargs)
Verify that the vertices of each gamma class of a random graph are modules of that graph.
INPUT:
• trials – the number of trials to run
• vertices – the size of the graph to use
• prob – the probability that any given edge is in the graph. See RandomGNP() for more details.
• verbose – print information on each trial.
EXAMPLES:
sage.graphs.graph_decompositions.modular_decomposition.test_maximal_modules(tree_root, graph)
Test the maximal nature of modules in a modular decomposition tree.
Suppose the module 𝑀 = [𝑀1 , 𝑀2 , · · · , 𝑛] is the input modular decomposition tree. Algorithm forms pairs like
(𝑀1 , 𝑀2 ), (𝑀1 , 𝑀3 ), · · · , (𝑀1 , 𝑀𝑛 ); (𝑀2 , 𝑀3 ), (𝑀2 , 𝑀4 ), · · · , (𝑀2 , 𝑀𝑛 ); · · · and so on and tries to form a
module using the pair. If the module formed has same type as 𝑀 and is of type SERIES or PARALLEL then
the formed module is not considered maximal. Otherwise it is considered maximal and 𝑀 is not a modular
decomposition tree.
INPUT:
• tree_root – modular decomposition tree whose modules are tested for maximal nature
• graph – graph whose modular decomposition tree is tested
OUTPUT:
True if all modules at first level in the modular decomposition tree are maximal in nature
EXAMPLES:
sage.graphs.graph_decompositions.modular_decomposition.test_modular_decomposition(tree_root,
graph)
Test the input modular decomposition tree using recursion.
INPUT:
sage.graphs.graph_decompositions.modular_decomposition.test_module(module, graph)
Test whether input module is actually a module
INPUT:
• module – module which needs to be tested
• graph – input sage graph which contains the module
OUTPUT:
True if input module is a module by definition else False
EXAMPLES:
sage.graphs.graph_decompositions.modular_decomposition.tree_to_nested_tuple(root)
Convert a modular decomposition tree to a nested tuple.
INPUT:
• root – the root of the modular decomposition tree
OUTPUT:
A tuple whose first element is the type of the root of the tree and whose subsequent nodes are either vertex labels
in the case of leaves or tuples representing the child subtrees.
EXAMPLES:
This module implements methods related to the decomposition of a graph by clique minimal separators. See [TY1984]
and [BPS2010] for more details on the algorithms.
5.26.1 Methods
sage.graphs.graph_decompositions.clique_separators.atoms_and_clique_separators(G,
tree=False,
rooted_tree=False,
separa-
tors=False)
Return the atoms of the decomposition of 𝐺 by clique minimal separators.
Let 𝐺 = (𝑉, 𝐸) be a graph. A set 𝑆 ⊂ 𝑉 is a clique separator if 𝐺[𝑆] is a clique and the graph 𝐺 ∖ 𝑆 has at least
2 connected components. Let 𝐶 ⊂ 𝑉 be the vertices of a connected component of 𝐺 ∖ 𝑆. The graph 𝐺[𝐶 + 𝑆]
is an atom if it has no clique separator.
This method implements the algorithm proposed in [BPS2010], that improves upon the algorithm proposed in
[TY1984], for computing the atoms and the clique minimal separators of a graph. This algorithm is based on the
maximum_cardinality_search_M() graph traversal and has time complexity in 𝑂(|𝑉 | · |𝐸|).
If the graph is not connected, we insert empty separators between the lists of separators of each connected
components. See the examples below for more details.
INPUT:
• G – a Sage graph
• tree – boolean (default: False); whether to return the result as a directed tree in which internal nodes are
clique separators and leaves are the atoms of the decomposition. Since a clique separator is repeated when
its removal partition the graph into 3 or more connected components, vertices are labels by tuples (𝑖, 𝑆),
where 𝑆 is the set of vertices of the atom or the clique separator, and 0 ≤ 𝑖 ≤ |𝑇 |.
• rooted_tree – boolean (default: False); whether to return the result as a LabelledRootedTree. When
tree is True, this parameter is ignored.
• separators – boolean (default: False); whether to also return the complete list of separators considered
during the execution of the algorithm. When tree or rooted_tree is True, this parameter is ignored.
OUTPUT:
• By default, return a tuple (𝐴, 𝑆𝑐 ), where 𝐴 is the list of atoms of the graph in the order of discovery, and 𝑆𝑐
is the list of clique separators, with possible repetitions, in the order the separator has been considered. If
furthermore separators is True, return a tuple (𝐴, 𝑆ℎ , 𝑆𝑐 ), where 𝑆𝑐 is the list of considered separators
of the graph in the order they have been considered.
• When tree is True, format the result as a directed tree
• When rooted_tree is True and tree is False, format the output as a LabelledRootedTree
EXAMPLES:
Example of [BPS2010]:
sage: G = Graph({'a': ['b', 'k'], 'b': ['c'], 'c': ['d', 'j', 'k'],
....: 'd': ['e', 'f', 'j', 'k'], 'e': ['g'],
....: 'f': ['g', 'j', 'k'], 'g': ['j', 'k'], 'h': ['i', 'j'],
....: 'i': ['k'], 'j': ['k']})
(continues on next page)
sage: G = graphs.PathGraph(4)
sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
____{2}____
/ /
{2, 3} __{1}__
/ /
{1, 2} {0, 1}
sage: G = graphs.WindmillGraph(3, 4)
sage: G.atoms_and_clique_separators()
([{0, 1, 2}, {0, 3, 4}, {0, 5, 6}, {0, 8, 7}], [{0}, {0}, {0}])
sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
________{0}________
/ /
{0, 1, 2} _______{0}______
/ /
{0, 3, 4} ____{0}___
/ /
{0, 8, 7} {0, 5, 6}
When the removal of a clique separator results in 𝑘 > 2 connected components, this separator is repeated 𝑘 − 1
times, but the repetitions are not necessarily contiguous:
sage: G = Graph(2)
sage: for i in range(5):
(continues on next page)
sage: G = graphs.StarGraph(3)
sage: G.subdivide_edges(G.edges(sort=False), 2)
sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
______{5}______
/ /
{1, 5} ______{7}______
/ /
{2, 7} ______{9}______
/ /
{9, 3} ______{6}______
/ /
{6, 7} ______{4}_____
/ /
{4, 5} _____{0}_____
/ /
{0, 6} ____{8}____
/ /
{8, 9} __{0}__
/ /
{0, 8} {0, 4}
If the graph is not connected, we insert empty separators between the lists of separators of each connected
components. For instance, let 𝐺 be a graph with 3 connected components. The method returns the list
𝑆𝑐 = [𝑆0 , · · · , 𝑆𝑖 , . . . , 𝑆𝑗 , . . . , 𝑆𝑘−1 ] of 𝑘 clique separators, where 𝑖 and 𝑗 are the indexes of the inserted
empty separators and 0 ≤ 𝑖 < 𝑗 < 𝑘 − 1. The method also returns the list 𝐴 = [𝐴0 , . . . , 𝑆𝑘 ] of the 𝑘 + 1
atoms, with 𝑘 + 1 ≥ 3. The lists of atoms and clique separators of each of the connected components are
respectively [𝐴0 , . . . , 𝐴𝑖 ] and [𝑆0 , . . . , 𝑆𝑖−1 ], [𝐴𝑖+1 , . . . , 𝐴𝑗 ] and [𝑆𝑖+1 , . . . , 𝑆𝑗−1 ], and [𝐴𝑗+1 , . . . , 𝐴𝑘 ] and
[𝑆𝑗+1 , . . . , 𝑆𝑘−1 ]. One can check that for each connected component, we get one atom more than clique separa-
tors:
sage: G = graphs.PathGraph(3) * 3
sage: A, Sc = G.atoms_and_clique_separators()
sage: A
[{1, 2}, {0, 1}, {4, 5}, {3, 4}, {8, 7}, {6, 7}]
sage: Sc
[{1}, {}, {4}, {}, {7}]
sage: i , j = [i for i, s in enumerate(Sc) if not s]
sage: i, j
(1, 3)
sage: A[:i+1], Sc[:i]
(continues on next page)
sage: G.allow_loops(True)
sage: G.add_edges([(u, u) for u in G])
sage: G.allow_multiple_edges(True)
sage: G.add_edges(G.edges(sort=False))
sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
______{1}______
/ /
{1, 2} ______{}______
/ /
{0, 1} _____{4}_____
/ /
{4, 5} ____{}_____
/ /
{3, 4} __{7}__
/ /
{6, 7} {8, 7}
sage.graphs.graph_decompositions.clique_separators.make_labelled_rooted_tree(atoms, cliques)
Return a LabelledRootedTree of atoms and cliques.
The atoms are the leaves of the tree and the cliques are the internal vertices. The number of atoms is the number
of cliques plus one.
EXAMPLES:
sage: G = graphs.PathGraph(5)
sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
_____{3}_____
/ /
{3, 4} ____{2}____
/ /
{2, 3} __{1}__
/ /
{0, 1} {1, 2}
sage.graphs.graph_decompositions.clique_separators.make_tree(atoms, cliques)
Return a tree of atoms and cliques.
The atoms are the leaves of the tree and the cliques are the internal vertices. The number of atoms is the number
of cliques plus one.
As a clique may appear several times in the list cliques, vertices are numbered by pairs (𝑖, 𝑆), where 0 ≤ 𝑖 <
|𝑎𝑡𝑜𝑚𝑠| + |𝑐𝑙𝑖𝑞𝑢𝑒𝑠| and 𝑆 is either an atom or a clique.
The root of the tree is the only vertex with even or null degree, i.e., 0 if cliques is empty and 2 otherwise. When
cliques is not empty, other internal vertices (each of which is a clique) have degree 3, and the leaves (vertices
of degree 1) are the atoms.
INPUT:
• atoms – list of atoms
• cliques – list of cliques
EXAMPLES:
This class gathers the algorithms related to convexity in a graph. It implements the following methods:
These methods can be used through the ConvexityProperties object returned by Graph.
convexity_properties().
AUTHORS:
• Nathann Cohen
5.27.1 Methods
class sage.graphs.convexity_properties.ConvexityProperties
Bases: object
This class gathers the algorithms related to convexity in a graph.
Definitions
A set 𝑆 ⊆ 𝑉 (𝐺) of vertices is said to be convex if for all 𝑢, 𝑣 ∈ 𝑆 the set 𝑆 contains all the vertices located on a
shortest path between 𝑢 and 𝑣. Alternatively, a set 𝑆 is said to be convex if the distances satisfy ∀𝑢, 𝑣 ∈ 𝑆, ∀𝑤 ∈
𝑉 ∖𝑆 : 𝑑𝐺 (𝑢, 𝑤) + 𝑑𝐺 (𝑤, 𝑣) > 𝑑𝐺 (𝑢, 𝑣).
The convex hull ℎ(𝑆) of a set 𝑆 of vertices is defined as the smallest convex set containing 𝑆.
It is a closure operator, as trivially 𝑆 ⊆ ℎ(𝑆) and ℎ(ℎ(𝑆)) = ℎ(𝑆).
What this class contains
As operations on convex sets generally involve the computation of distances between vertices, this class’ purpose
is to cache that information so that computing the convex hulls of several different sets of vertices does not imply
recomputing several times the distances between the vertices.
In order to compute the convex hull of a set 𝑆 it is possible to write the following algorithm:
For any pair 𝑢, 𝑣 of elements in the set 𝑆, and for any vertex 𝑤 outside of it, add 𝑤 to 𝑆 if 𝑑𝐺 (𝑢, 𝑤) +
𝑑𝐺 (𝑤, 𝑣) = 𝑑𝐺 (𝑢, 𝑣). When no vertex can be added anymore, the set 𝑆 is convex
The distances are not actually that relevant. The same algorithm can be implemented by remembering for each
pair 𝑢, 𝑣 of vertices the list of elements 𝑤 satisfying the condition, and this is precisely what this class remembers,
encoded as bitsets to make storage and union operations more efficient.
Note:
• This class is useful if you compute the convex hulls of many sets in the same graph, or if you want to
compute the hull number itself as it involves many calls to hull()
• Using this class on non-connected graphs is a waste of space and efficiency ! If your graph is disconnected,
the best for you is to deal independently with each connected component, whatever you are doing.
Possible improvements
When computing a convex set, all the pairs of elements belonging to the set 𝑆 are enumerated several times.
• There should be a smart way to avoid enumerating pairs of vertices which have already been tested. The
cost of each of them is not very high, so keeping track of those which have been tested already may be too
expensive to gain any efficiency.
• The ordering in which they are visited is currently purely lexicographic, while there is a Poset structure to
exploit. In particular, when two vertices 𝑢, 𝑣 are far apart and generate a set ℎ({𝑢, 𝑣}) of vertices, all the
pairs of vertices 𝑢′ , 𝑣 ′ ∈ ℎ({𝑢, 𝑣}) satisfy ℎ({𝑢′ , 𝑣 ′ }) ⊆ ℎ({𝑢, 𝑣}), and so it is useless to test the pair 𝑢′ , 𝑣 ′
when both 𝑢 and 𝑣 where present.
• The information cached is for any pair 𝑢, 𝑣 of vertices the list of elements 𝑧 with 𝑑𝐺 (𝑢, 𝑤) + 𝑑𝐺 (𝑤, 𝑣) =
𝑑𝐺 (𝑢, 𝑣). This is not in general equal to ℎ({𝑢, 𝑣}) !
Nothing says these recommandations will actually lead to any actual improvements. There are just some ideas
remembered while writing this code. Trying to optimize may well lead to lost in efficiency on many instances.
EXAMPLES:
hull(vertices)
Return the convex hull of a set of vertices.
INPUT:
• vertices – A list of vertices.
EXAMPLES:
hull_number(value_only=True, verbose=False)
Compute the hull number and a corresponding generating set.
The hull number ℎ𝑛(𝐺) of a graph 𝐺 is the cardinality of a smallest set of vertices 𝑆 such that ℎ(𝑆) =
𝑉 (𝐺).
INPUT:
• value_only – boolean (default: True); whether to return only the hull number (default) or a minimum
set whose convex hull is the whole graph
• verbose – boolean (default: False); whether to display information on the LP
COMPLEXITY:
This problem is NP-Hard [HLT1993], but seems to be of the “nice” kind. Update this comment if you fall
on hard instances : −)
ALGORITHM:
This is solved by linear programming.
As the function ℎ(𝑆) associating to each set 𝑆 its convex hull is a closure operator, it is clear that any set
𝑆𝐺 of vertices such that ℎ(𝑆𝐺 ) = 𝑉 (𝐺) must satisfy 𝑆𝐺 ̸⊆ 𝐶 for any proper convex set 𝐶 ( 𝑉 (𝐺). The
following formulation is hence correct
∑︁
Minimize : 𝑏𝑣
𝑣∈𝐺
Such that :
∀𝐶 ( 𝑉 (𝐺) a proper convex set
∑︁
𝑏𝑣 ≥ 1
𝑣∈𝑉 (𝐺)∖𝐶
Of course, the number of convex sets – and so the number of constraints – can be huge, and hard to enumer-
ate, so at first an incomplete formulation is solved (it is missing some constraints). If the answer returned
by the LP solver is a set 𝑆 generating the whole graph, then it is optimal and so is returned. Otherwise, the
constraint corresponding to the set ℎ(𝑆) can be added to the LP, which makes the answer 𝑆 infeasible, and
another solution computed.
This being said, simply adding the constraint corresponding to ℎ(𝑆) is a bit slow, as these sets can be large
(and the corresponding constraint a bit weak). To improve it a bit, before being added, the set ℎ(𝑆) is
“greedily enriched” to a set 𝑆 ′ with vertices for as long as ℎ(𝑆 ′ ) ̸= 𝑉 (𝐺). This way, we obtain a set 𝑆 ′
with ℎ(𝑆) ⊆ ℎ(𝑆 ′ ) ( 𝑉 (𝐺), and the constraint corresponding to ℎ(𝑆 ′ ) – which is stronger than the one
corresponding to ℎ(𝑆) – is added.
This can actually be seen as a hitting set problem on the complement of convex sets.
EXAMPLES:
The Hull number of Petersen’s graph:
sage.graphs.convexity_properties.geodetic_closure(G, S)
Return the geodetic closure of the set of vertices 𝑆 in 𝐺.
The geodetic closure 𝑔(𝑆) of a subset of vertices 𝑆 of a graph 𝐺 is in [HLT1993] as the set of all vertices that
lie on a shortest 𝑢 − 𝑣 path for any pair of vertices 𝑢, 𝑣 ∈ 𝑆. We assume that 𝑔(∅) = ∅ and that 𝑔({𝑢}) = {𝑢}
for any 𝑢 in 𝐺.
Warning: This operation is not a closure function. Indeed, a closure function must satisfy the property
that 𝑓 (𝑓 (𝑋)) should be equal to 𝑓 (𝑋), which is not always the case here. The term closure is used here to
follow the terminology of the domain. See for instance [HLT1993].
Here, we implement a simple algorithm to determine this set. Roughly, for each vertex 𝑢 ∈ 𝑆, the algorithm first
performs a breadth first search from 𝑢 to get distances, and then identifies the vertices of 𝐺 lying on a shortest
path from 𝑢 to any 𝑣 ∈ 𝑆 using a reversal traversal from vertices in 𝑆. This algorithm has time complexity in
𝑂(|𝑆|(𝑛 + 𝑚)) and space complexity in 𝑂(𝑛 + 𝑚).
INPUT:
• G – a Sage graph
• S – a subset of vertices of 𝐺
EXAMPLES:
The vertices of the Petersen graph can be obtained by a geodetic closure of four of its vertices:
sage: G = graphs.Grid2dGraph(4, 4)
sage: c = G.geodetic_closure([(0, 0), (3, 3)])
sage: len(c) == G.order()
True
If two vertices belong to different connected components of a graph, their geodetic closure is trivial:
The geodetic closure does not satisfy the closure function property that 𝑓 (𝑓 (𝑋)) should be equal to 𝑓 (𝑋):
sage: G = graphs.DiamondGraph()
sage: G.subdivide_edge((1, 2), 1)
sage: geodetic_closure(G, [0, 3])
[0, 1, 2, 3]
sage: geodetic_closure(G, geodetic_closure(G, [0, 3]))
[0, 1, 2, 3, 4]
This module deals with everything related to weakly chordal graphs. It currently contains the following functions:
Author:
• Birk Eisermann (initial implementation)
• Nathann Cohen (some doc and optimization)
5.28.1 Methods
sage.graphs.weakly_chordal.is_long_antihole_free(g, certificate=False)
Tests whether the given graph contains an induced subgraph that is isomorphic to the complement of a cycle of
length at least 5.
INPUT:
• certificate – boolean (default: False)
Whether to return a certificate. When certificate = True, then the function returns
– (False, Antihole) if g contains an induced complement of a cycle of length at least 5 returned as
Antihole.
– (True, []) if g does not contain an induced complement of a cycle of length at least 5. For this case
it is not known how to provide a certificate.
When certificate = False, the function returns just True or False accordingly.
ALGORITHM:
This algorithm tries to find a cycle in the graph of all induced 𝑃4 of 𝑔, where two copies 𝑃 and 𝑃 ′ of 𝑃4 are
adjacent if there exists a (not necessarily induced) copy of 𝑃5 = 𝑢1 𝑢2 𝑢3 𝑢4 𝑢5 such that 𝑃 = 𝑢1 𝑢2 𝑢3 𝑢4 and
𝑃 ′ = 𝑢2 𝑢3 𝑢4 𝑢5 .
This is done through a depth-first-search. For efficiency, the auxiliary graph is constructed on-the-fly and never
stored in memory.
The run time of this algorithm is 𝑂(𝑚2 ) [NP2007] (where 𝑚 is the number of edges of the graph).
EXAMPLES:
The Petersen Graph contains an antihole:
sage: g = graphs.PetersenGraph()
sage: g.is_long_antihole_free()
False
sage: g = graphs.CycleGraph(6).complement()
sage: r,a = g.is_long_antihole_free(certificate=True)
sage: r
False
sage: a.complement().is_isomorphic(graphs.CycleGraph(6))
True
sage.graphs.weakly_chordal.is_long_hole_free(g, certificate=False)
Tests whether g contains an induced cycle of length at least 5.
INPUT:
• certificate – boolean (default: False)
Whether to return a certificate. When certificate = True, then the function returns
– (True, []) if g does not contain such a cycle. For this case, it is not known how to provide a
certificate.
– (False, Hole) if g contains an induced cycle of length at least 5. Hole returns this cycle.
If certificate = False, the function returns just True or False accordingly.
ALGORITHM:
This algorithm tries to find a cycle in the graph of all induced 𝑃4 of 𝑔, where two copies 𝑃 and 𝑃 ′ of 𝑃4 are
adjacent if there exists a (not necessarily induced) copy of 𝑃5 = 𝑢1 𝑢2 𝑢3 𝑢4 𝑢5 such that 𝑃 = 𝑢1 𝑢2 𝑢3 𝑢4 and
𝑃 ′ = 𝑢2 𝑢3 𝑢4 𝑢5 .
This is done through a depth-first-search. For efficiency, the auxiliary graph is constructed on-the-fly and never
stored in memory.
The run time of this algorithm is 𝑂(𝑚2 ) [NP2007] ( where 𝑚 is the number of edges of the graph ) .
EXAMPLES:
The Petersen Graph contains a hole:
sage: g = graphs.PetersenGraph()
sage: g.is_long_hole_free()
False
sage: g = graphs.FlowerSnark()
sage: r,h = g.is_long_hole_free(certificate=True)
sage: r
False
sage: Graph(h).is_isomorphic(graphs.CycleGraph(h.order()))
True
sage.graphs.weakly_chordal.is_weakly_chordal(g, certificate=False)
Tests whether the given graph is weakly chordal, i.e., the graph and its complement have no induced cycle of
length at least 5.
INPUT:
• certificate – Boolean value (default: False) whether to return a certificate. If certificate =
False, return True or False according to the graph. If certificate = True, return
– (False, forbidden_subgraph) when the graph contains a forbidden subgraph H, this graph is
returned.
– (True, []) when the graph is weakly chordal. For this case, it is not known how to provide a cer-
tificate.
ALGORITHM:
This algorithm checks whether the graph g or its complement contain an induced cycle of length at least 5.
Using is_long_hole_free() and is_long_antihole_free() yields a run time of 𝑂(𝑚2 ) (where 𝑚 is the number of
edges of the graph).
EXAMPLES:
The Petersen Graph is not weakly chordal and contains a hole:
sage: g = graphs.PetersenGraph()
sage: r,s = g.is_weakly_chordal(certificate=True)
sage: r
False
(continues on next page)
This module implements a few functions that deal with the computation of distances or shortest paths between all pairs
of vertices.
Efficiency : Because these functions involve listing many times the (out)-neighborhoods of (di)-graphs, it is useful in
terms of efficiency to build a temporary copy of the graph in a data structure that makes it easy to compute quickly.
These functions also work on large volume of data, typically dense matrices of size 𝑛2 , and are expected to return
corresponding dictionaries of size 𝑛2 , where the integers corresponding to the vertices have first been converted to the
vertices’ labels. Sadly, this last translating operation turns out to be the most time-consuming, and for this reason it is
also nice to have a Cython module, and version of these functions that return C arrays, in order to avoid these operations
when they are not necessary.
Memory cost : The methods implemented in the current module sometimes need large amounts of memory to return
their result. Storing the distances between all pairs of vertices in a graph on 1500 vertices as a dictionary of dictionaries
takes around 200MB, while storing the same information as a C array requires 4MB.
The C function all_pairs_shortest_path_BFS actually does all the computations, and all the others (except for
Floyd_Warshall) are just wrapping it. This function begins with copying the graph in a data structure that makes it
fast to query the out-neighbors of a vertex, then starts one Breadth First Search per vertex of the (di)graph.
What can this function compute ?
• The matrix of predecessors.
This matrix 𝑃 has size 𝑛2 , and is such that vertex 𝑃 [𝑢, 𝑣] is a predecessor of 𝑣 on a shortest 𝑢𝑣-path. Hence,
this matrix efficiently encodes the information of a shortest 𝑢𝑣-path for any 𝑢, 𝑣 ∈ 𝐺 : indeed, to go from 𝑢 to 𝑣
you should first find a shortest 𝑢𝑃 [𝑢, 𝑣]-path, then jump from 𝑃 [𝑢, 𝑣] to 𝑣 as it is one of its outneighbors. Apply
recursively and find out what the whole path is !.
• The matrix of distances.
This matrix has size 𝑛2 and associates to any 𝑢𝑣 the distance from 𝑢 to 𝑣.
• The vector of eccentricities.
This vector of size 𝑛 encodes for each vertex 𝑣 the distance to vertex which is furthest from 𝑣 in the graph. In
particular, the diameter of the graph is the maximum of these values.
What does it take as input ?
• gg a (Di)Graph.
• unsigned short * predecessors – a pointer toward an array of size 𝑛2 ·sizeof(unsigned short). Set to NULL
if you do not want to compute the predecessors.
• unsigned short * distances – a pointer toward an array of size 𝑛2 · sizeof(unsigned short). The computa-
tion of the distances is necessary for the algorithm, so this value can not be set to NULL.
• int * eccentricity – a pointer toward an array of size 𝑛 · sizeof(int). Set to NULL if you do not want to
compute the eccentricity.
Technical details
• The vertices are encoded as 1, ..., 𝑛 as they appear in the ordering of G.vertices(sort=True), unless another
ordering is specified by the user.
• Because this function works on matrices whose size is quadratic compared to the number of vertices when
computing all distances or predecessors, it uses short variables to store the vertices’ names instead of long ones
to divide by 2 the size in memory. This means that only the diameter/eccentricities can be computed on a graph
of more than 65536 nodes. For information, the current version of the algorithm on a graph with 65536 = 216
nodes creates in memory 2 tables on 232 short elements (2bytes each), for a total of 233 bytes or 8 gigabytes.
In order to support larger sizes, we would have to replace shorts by 32-bits int or 64-bits int, which would then
require respectively 16GB or 32GB.
• In the C version of these functions, infinite distances are represented with <unsigned short> -1 = 65535 for
unsigned short variables, and by INT32_MAX otherwise. These case happens when the input is a disconnected
graph, or a non-strongly-connected digraph.
• A memory error is raised when data structures allocation failed. This could happen with large graphs on com-
puters with low memory space.
Warning: The function all_pairs_shortest_path_BFS has no reason to be called by the user, even though
he would be writing his code in Cython and look for efficiency. This module contains wrappers for this function that
feed it with the good parameters. As the function is inlined, using those wrappers actually saves time as it should
avoid testing the parameters again and again in the main function’s body.
AUTHOR:
• Nathann Cohen (2011)
• David Coudert (2014) – 2sweep, multi-sweep and iFUB for diameter computation
5.29.2 Functions
sage.graphs.distances_all_pairs.antipodal_graph(G)
Return the antipodal graph of 𝐺.
The antipodal graph of a graph 𝐺 has the same vertex set of 𝐺 and two vertices are adjacent if their distance in
𝐺 is equal to the diameter of 𝐺.
This method first computes the eccentricity of all vertices and determines the diameter of the graph. Then, it for
each vertex 𝑢 with eccentricity the diameter, it computes BFS distances from 𝑢 and add an edge in the antipodal
graph for each vertex 𝑣 at diamter distance from 𝑢 (i.e., for each antipodal vertex).
The drawback of this method is that some BFS distances may be computed twice, one time to determine the
eccentricities and another time is the vertex has eccentricity equal to the diameter. However, in practive, this is
much more efficient. See the documentation of method c_eccentricity_DHV().
EXAMPLES:
The antipodal graph of a grid graph has only 2 edges:
𝑑(𝑣, 𝑎) ≤ 𝑖, ∀𝑎 ∈ 𝐴
𝑑(𝑣, 𝑏) ≥ 𝑖, ∀𝑏 ∈ 𝐵
As all vertices from 𝐴 are at distance ≤ 2𝑖 from each other, a vertex 𝑎 ∈ 𝐴 with eccentricity
𝑒𝑐𝑐(𝑎) > 2𝑖 is at distance 𝑒𝑐𝑐(𝑎) from some vertex 𝑏 ∈ 𝐵.
Consequently, if we have already computed the maximum eccentricity 𝑚 of all vertices in 𝐵
and if 𝑚 > 2𝑖, then we do not need to compute the eccentricity of the vertices in 𝐴.
Starting from a vertex 𝑣 obtained through a multi-sweep computation (which refines the 4sweep algo-
rithm used in [CGHLM2013]), we compute the diameter by computing the eccentricity of all vertices
sorted decreasingly according to their distance to 𝑣, and stop as allowed by the remark above. The
worst case time complexity of the iFUB algorithm is 𝑂(𝑛𝑚), but it can be very fast in practice.
– 'DiFUB' – The directed version of iFUB (iterative Fringe Upper Bound) algorithm. See the code’s
documentation and [CGLM2012] for more details. If the digraph is not strongly connected, the re-
turned value is infinity.
• source – (default: None) vertex from which to start the first BFS. If source==None, an arbitrary vertex
of the graph is chosen. Raise an error if the initial vertex is not in 𝐺. This parameter is not used when
algorithm=='standard'.
EXAMPLES:
Although max( ) is usually defined as -Infinity, since the diameter will never be negative, we define it to be zero:
sage: G = graphs.EmptyGraph()
sage: diameter(G, algorithm='iFUB')
0
sage: G = graphs.RandomBarabasiAlbert(100, 2)
sage: d1 = diameter(G, algorithm='standard')
sage: d2 = diameter(G, algorithm='iFUB')
sage: d3 = diameter(G, algorithm='iFUB', source=G.random_vertex())
sage: d4 = diameter(G, algorithm='DHV')
sage: if d1 != d2 or d1 != d3 or d1 != d4: print("Something goes wrong!")
sage.graphs.distances_all_pairs.distances_all_pairs(G)
Return the matrix of distances in G.
This function returns a double dictionary D of vertices, in which the distance between vertices u and v is D[u][v].
EXAMPLES:
sage.graphs.distances_all_pairs.distances_and_predecessors_all_pairs(G)
Return the matrix of distances in G and the matrix of predecessors.
Distances : the matrix 𝑀 returned is of length 𝑛2 , and the distance between vertices 𝑢 and 𝑣 is 𝑀 [𝑢, 𝑣]. The
integer corresponding to a vertex is its index in the list G.vertices(sort=True).
Predecessors : the matrix 𝑃 returned has size 𝑛2 , and is such that vertex 𝑃 [𝑢, 𝑣] is a predecessor of 𝑣 on a shortest
𝑢𝑣-path. Hence, this matrix efficiently encodes the information of a shortest 𝑢𝑣-path for any 𝑢, 𝑣 ∈ 𝐺 : indeed,
to go from 𝑢 to 𝑣 you should first find a shortest 𝑢𝑃 [𝑢, 𝑣]-path, then jump from 𝑃 [𝑢, 𝑣] to 𝑣 as it is one of its
outneighbors.
EXAMPLES:
sage: g = graphs.PetersenGraph()
sage: distances_and_predecessors_all_pairs(g)
({0: {0: 0, 1: 1, 2: 2, 3: 2, 4: 1, 5: 1, 6: 2, 7: 2, 8: 2, 9: 2},
1: {0: 1, 1: 0, 2: 1, 3: 2, 4: 2, 5: 2, 6: 1, 7: 2, 8: 2, 9: 2},
2: {0: 2, 1: 1, 2: 0, 3: 1, 4: 2, 5: 2, 6: 2, 7: 1, 8: 2, 9: 2},
3: {0: 2, 1: 2, 2: 1, 3: 0, 4: 1, 5: 2, 6: 2, 7: 2, 8: 1, 9: 2},
4: {0: 1, 1: 2, 2: 2, 3: 1, 4: 0, 5: 2, 6: 2, 7: 2, 8: 2, 9: 1},
5: {0: 1, 1: 2, 2: 2, 3: 2, 4: 2, 5: 0, 6: 2, 7: 1, 8: 1, 9: 2},
6: {0: 2, 1: 1, 2: 2, 3: 2, 4: 2, 5: 2, 6: 0, 7: 2, 8: 1, 9: 1},
7: {0: 2, 1: 2, 2: 1, 3: 2, 4: 2, 5: 1, 6: 2, 7: 0, 8: 2, 9: 1},
8: {0: 2, 1: 2, 2: 2, 3: 1, 4: 2, 5: 1, 6: 1, 7: 2, 8: 0, 9: 2},
9: {0: 2, 1: 2, 2: 2, 3: 2, 4: 1, 5: 2, 6: 1, 7: 1, 8: 2, 9: 0}},
(continues on next page)
sage.graphs.distances_all_pairs.distances_distribution(G)
Return the distances distribution of the (di)graph in a dictionary.
This method ignores all edge labels, so that the distance considered is the topological distance.
OUTPUT:
A dictionary d such that the number of pairs of vertices at distance k (if any) is equal to 𝑑[𝑘] · |𝑉 (𝐺)| ·
(|𝑉 (𝐺)| − 1).
Note: We consider that two vertices that do not belong to the same connected component are at infinite distance,
and we do not take the trivial pairs of vertices (𝑣, 𝑣) at distance 0 into account. Empty (di)graphs and (di)graphs
of order 1 have no paths and so we return the empty dictionary {}.
EXAMPLES:
An empty Graph:
sage: g = Graph()
sage: g.distances_distribution()
{}
A Graph of order 1:
sage: g = Graph()
sage: g.add_vertex(1)
sage: g.distances_distribution()
{}
sage: g = Graph()
sage: g.add_vertices([1,2])
sage: g.distances_distribution()
{+Infinity: 1}
sage: g = graphs.PetersenGraph()
sage: g.distances_distribution()
{1: 1/3, 2: 2/3}
sage: g = graphs.PetersenGraph()
sage: g.add_edge('good','wine')
sage: g.distances_distribution()
{1: 8/33, 2: 5/11, +Infinity: 10/33}
sage: D = digraphs.DeBruijn(2,3)
sage: D.distances_distribution()
{1: 1/4, 2: 11/28, 3: 5/14}
OUTPUT:
Depending on the input, this function return the dictionary of paths, the dictionary of distances, or a pair of
dictionaries (distances, paths) where distance[u][v] denotes the distance of a shortest path from 𝑢 to
𝑣 and paths[u][v] denotes an inneighbor 𝑤 of 𝑣 such that 𝑑𝑖𝑠𝑡(𝑢, 𝑣) = 1 + 𝑑𝑖𝑠𝑡(𝑢, 𝑤).
Warning: Because this function works on matrices whose size is quadratic compared to the number of
vertices, it uses short variables instead of long ones to divide by 2 the size in memory. This means that the
current implementation does not run on a graph of more than 65536 nodes (this can be easily changed if
necessary, but would require much more memory. It may be worth writing two versions). For information,
the current version of the algorithm on a graph with 65536 = 216 nodes creates in memory 2 tables on 232
short elements (2bytes each), for a total of 234 bytes or 16 gigabytes. Let us also remember that if the memory
size is quadratic, the algorithm runs in cubic time.
Note: When paths = False the algorithm saves roughly half of the memory as it does not have to maintain
the matrix of predecessors. However, setting distances=False produces no such effect as the algorithm can
not run without computing them. They will not be returned, but they will be stored while the method is running.
EXAMPLES:
Shortest paths in a small grid
sage: g = graphs.Grid2dGraph(2,2)
sage: from sage.graphs.distances_all_pairs import floyd_warshall
sage: print(floyd_warshall(g))
{(0, 0): {(0, 0): None, (0, 1): (0, 0), (1, 0): (0, 0), (1, 1): (0, 1)},
(0, 1): {(0, 1): None, (0, 0): (0, 1), (1, 0): (0, 0), (1, 1): (0, 1)},
(1, 0): {(1, 0): None, (0, 0): (1, 0), (0, 1): (0, 0), (1, 1): (1, 0)},
(1, 1): {(1, 1): None, (0, 0): (0, 1), (0, 1): (1, 1), (1, 0): (1, 1)}}
sage: g = graphs.Grid2dGraph(5,5)
sage: dist,path = floyd_warshall(g, distances=True)
sage: all(dist[u][v] == g.distance(u, v) for u in g for v in g)
True
sage: g = graphs.DiamondGraph()
sage: floyd_warshall(g, paths=False, distances=True)
{0: {0: 0, 1: 1, 2: 1, 3: 2},
1: {0: 1, 1: 0, 2: 1, 3: 1},
(continues on next page)
sage.graphs.distances_all_pairs.is_distance_regular(G, parameters=False)
Test if the graph is distance-regular
A graph 𝐺 is distance-regular if for any integers 𝑗, 𝑘 the value of |{𝑥 : 𝑑𝐺 (𝑥, 𝑢) = 𝑗, 𝑥 ∈ 𝑉 (𝐺)} ∩ {𝑦 :
𝑑𝐺 (𝑦, 𝑣) = 𝑗, 𝑦 ∈ 𝑉 (𝐺)}| is constant for any two vertices 𝑢, 𝑣 ∈ 𝑉 (𝐺) at distance 𝑖 from each other. In
particular 𝐺 is regular, of degree 𝑏0 (see below), as one can take 𝑢 = 𝑣.
Equivalently a graph is distance-regular if there exist integers 𝑏𝑖 , 𝑐𝑖 such that for any two vertices 𝑢, 𝑣 at distance
𝑖 we have
• 𝑏𝑖 = |{𝑥 : 𝑑𝐺 (𝑥, 𝑢) = 𝑖 + 1, 𝑥 ∈ 𝑉 (𝐺)} ∩ 𝑁𝐺 (𝑣)}|, 0 ≤ 𝑖 ≤ 𝑑 − 1
• 𝑐𝑖 = |{𝑥 : 𝑑𝐺 (𝑥, 𝑢) = 𝑖 − 1, 𝑥 ∈ 𝑉 (𝐺)} ∩ 𝑁𝐺 (𝑣)}|, 1 ≤ 𝑖 ≤ 𝑑,
where 𝑑 is the diameter of the graph. For more information on distance-regular graphs, see the Wikipedia article
Distance-regular_graph.
INPUT:
• parameters – boolean (default: False); if set to True, the function returns the pair (b, c) of lists of
integers instead of a boolean answer (see the definition above)
See also:
• is_regular()
• is_strongly_regular()
EXAMPLES:
sage: g = graphs.PetersenGraph()
sage: g.is_distance_regular()
True
sage: g.is_distance_regular(parameters = True)
([3, 2, None], [None, 1, 1])
Cube graphs, which are not strongly regular, are a bit more interesting:
sage: graphs.CubeGraph(4).is_distance_regular()
True
sage: graphs.OddGraph(5).is_distance_regular()
True
Disconnected graph:
sage: (2*graphs.CubeGraph(4)).is_distance_regular()
True
sage.graphs.distances_all_pairs.radius_DHV(G)
Return the radius of unweighted graph 𝐺.
This method computes the radius of unweighted undirected graph using the algorithm given in [Dragan2018].
This method returns Infinity if graph is not connected.
EXAMPLES:
sage.graphs.distances_all_pairs.shortest_path_all_pairs(G)
Return the matrix of predecessors in G.
The matrix 𝑃 returned has size 𝑛2 , and is such that vertex 𝑃 [𝑢, 𝑣] is a predecessor of 𝑣 on a shortest 𝑢𝑣-path.
Hence, this matrix efficiently encodes the information of a shortest 𝑢𝑣-path for any 𝑢, 𝑣 ∈ 𝐺 : indeed, to go from
𝑢 to 𝑣 you should first find a shortest 𝑢𝑃 [𝑢, 𝑣]-path, then jump from 𝑃 [𝑢, 𝑣] to 𝑣 as it is one of its outneighbors.
EXAMPLES:
sage.graphs.distances_all_pairs.szeged_index(G, algorithm=None)
Return the Szeged index of the graph 𝐺.
Let 𝐺 = (𝑉, 𝐸) be a connected graph, and for any 𝑢𝑣 ∈ 𝐸, let 𝑁𝑢 (𝑢𝑣) = {𝑤 ∈ 𝑉 : 𝑑(𝑢, 𝑤) < 𝑑(𝑣, 𝑤)} and
𝑛𝑢 (𝑢𝑣) = |𝑁𝑢 (𝑢𝑣)|. The Szeged index of 𝐺 is then defined as [KRG1996]
∑︁
‘ 𝑛𝑢 (𝑢𝑣) × 𝑛𝑣 (𝑢𝑣)‘
𝑢𝑣∈𝐸(𝐺)
sage: g = Graph()
sage: g.add_edges(graphs.CubeGraph(5).min_spanning_tree())
sage: g.wiener_index() == szeged_index(g)
True
sage.graphs.distances_all_pairs.wiener_index(G)
Return the Wiener index of the graph.
The Wiener index of an undirected graph 𝐺 is defined as 𝑊 (𝐺) = 1
𝑑(𝑢, 𝑣) where 𝑑(𝑢, 𝑣) denotes the
∑︀
2 𝑢,𝑣∈𝐺
distance between vertices 𝑢 and 𝑣 (see [KRG1996]).
The Wiener
∑︀ index of a directed graph 𝐺 is defined as the sum of the distances between each pairs of vertices,
𝑊 (𝐺) = 𝑢,𝑣∈𝐺 𝑑(𝑢, 𝑣).
EXAMPLES:
From [GYLL1993], cited in [KRG1996]:
sage: g=graphs.PathGraph(10)
sage: w=lambda x: (x*(x*x -1)/6)
sage: g.wiener_index()==w(10)
True
sage: n = 5
sage: g = graphs.CompleteGraph(n)
sage: g.wiener_index() == (n * (n - 1)) / 2
True
sage: g = digraphs.Complete(n)
sage: g.wiener_index() == n * (n - 1)
True
sage: Graph(1).wiener_index()
0
sage: Graph().wiener_index()
Traceback (most recent call last):
...
ValueError: Wiener index is not defined for the empty graph
This module provides a class to hold, manipulate and employ various options for rendering a graph in LaTeX, in addition
to providing the code that actually generates a LaTeX representation of a (combinatorial) graph.
AUTHORS:
• Rob Beezer (2009-05-20): GraphLatex class
• Fidel Barerra Cruz (2009-05-20): tkz-graph commands to render a graph
• Nicolas M. Thiéry (2010-02): dot2tex/graphviz interface
• Rob Beezer (2010-05-29): Extended range of tkz-graph options
Many mathematical objects in Sage have LaTeX representations, and graphs are no exception. For a graph g, the
command view(g), issued at the Sage command line or in the notebook, will create a graphic version of g. Similarly,
latex(g) will return a (long) string that is a representation of the graph in LaTeX. Other ways of employing LaTeX
in Sage, such as %latex in a notebook cell, or the Typeset checkbox in the notebook, will handle g appropriately.
Support through the tkz-graph package is by Alain Matthes, the author of tkz-graph, whose work can be found at
https://www.ctan.org/pkg/tkz-graph.
The range of possible options for customizing the appearance of a graph are carefully documented at sage.graphs.
graph_latex.GraphLatex.set_option(). As a broad overview, the following options are supported:
• Pre-built Styles: the pre-built styles of the tkz-graph package provide nice drawings quickly
• Dimensions: can be specified in natural units, then uniformly scaled after design work
• Vertex Colors: the perimeter and fill color for vertices can be specified, including on a per-vertex basis
• Vertex Shapes: may be circles, shaded spheres, rectangles or diamonds, including on a per-vertex basis
• Vertex Sizes: may be specified as minimums, and will automatically sized to contain vertex labels, including on
a per-vertex basis
• Vertex Labels: can use latex formatting, and may have their colors specified, including on a per-vertex basis
• Vertex Label Placement: can be interior to the vertex, or external at a configurable location
• Edge Colors: a solid color with or without a second color down the middle, on a per-edge basis
• Edge Thickness: can be set, including on a per-edge basis
• Edge Labels: can use latex formatting, and may have their colors specified, including on a per-edge basis
• Edge Label Placement: can be to the left, right, above, below, inline, and then sloped or horizontal
• Digraph Edges: are slightly curved, with arrowheads
• Loops: may be specified by their size, and with a direction equaling one of the four compass points
To use LaTeX in Sage you of course need a working TeX installation and it will work best if you have the dvipng and
convert utilities. For graphs you need the tkz-graph.sty and tkz-berge.sty style files of the tkz-graph package.
TeX, dvipng, and convert should be widely available through package managers or installers. You may need to install
the tkz-graph style files in the appropriate locations, a task beyond the scope of this introduction. Primary locations for
these programs are:
• TeX: http://ctan.org/
• dvipng: http://sourceforge.net/projects/dvipng/
• convert: http://www.imagemagick.org (the ImageMagick suite)
• tkz-graph: https://www.ctan.org/pkg/tkz-graph
Customizing the output is accomplished in several ways. Suppose g is a graph, then g.set_latex_options() can be
used to efficiently set or modify various options. Setting individual options, or querying options, can be accomplished
by first using a command like opts = g.latex_options() to obtain a sage.graphs.graph_latex.GraphLatex
object which has several methods to set and retrieve options.
Here is a minimal session demonstrating how to use these features. The following setup should work in the notebook
or at the command-line.:
sage: H = graphs.HeawoodGraph()
sage: H.set_latex_options(
....: graphic_size=(5,5),
....: vertex_size=0.2,
....: edge_thickness=0.04,
....: edge_color='green',
(continues on next page)
At this point, view(H) should call pdflatex to process the string created by latex(H) and then display the resulting
graphic.
To use this image in a LaTeX document, you could of course just copy and save the resulting graphic. However, the
latex() command will produce the underlying LaTeX code, which can be incorporated into a standalone LaTeX
document.:
sage: from sage.graphs.graph_latex import check_tkz_graph
sage: check_tkz_graph() # random - depends on TeX installation
sage: latex(H)
\begin{tikzpicture}
\definecolor{cv0}{rgb}{0.0,0.502,0.0}
\definecolor{cfv0}{rgb}{1.0,1.0,1.0}
\definecolor{clv0}{rgb}{1.0,0.0,0.0}
\definecolor{cv1}{rgb}{0.0,0.502,0.0}
\definecolor{cfv1}{rgb}{1.0,1.0,1.0}
\definecolor{clv1}{rgb}{1.0,0.0,0.0}
\definecolor{cv2}{rgb}{0.0,0.502,0.0}
\definecolor{cfv2}{rgb}{1.0,1.0,1.0}
\definecolor{clv2}{rgb}{1.0,0.0,0.0}
\definecolor{cv3}{rgb}{0.0,0.502,0.0}
\definecolor{cfv3}{rgb}{1.0,1.0,1.0}
\definecolor{clv3}{rgb}{1.0,0.0,0.0}
\definecolor{cv4}{rgb}{0.0,0.502,0.0}
\definecolor{cfv4}{rgb}{1.0,1.0,1.0}
\definecolor{clv4}{rgb}{1.0,0.0,0.0}
\definecolor{cv5}{rgb}{0.0,0.502,0.0}
\definecolor{cfv5}{rgb}{1.0,1.0,1.0}
\definecolor{clv5}{rgb}{1.0,0.0,0.0}
\definecolor{cv6}{rgb}{0.0,0.502,0.0}
\definecolor{cfv6}{rgb}{1.0,1.0,1.0}
\definecolor{clv6}{rgb}{1.0,0.0,0.0}
\definecolor{cv7}{rgb}{0.0,0.502,0.0}
\definecolor{cfv7}{rgb}{1.0,1.0,1.0}
\definecolor{clv7}{rgb}{1.0,0.0,0.0}
\definecolor{cv8}{rgb}{0.0,0.502,0.0}
\definecolor{cfv8}{rgb}{1.0,1.0,1.0}
\definecolor{clv8}{rgb}{1.0,0.0,0.0}
\definecolor{cv9}{rgb}{0.0,0.502,0.0}
\definecolor{cfv9}{rgb}{1.0,1.0,1.0}
\definecolor{clv9}{rgb}{1.0,0.0,0.0}
\definecolor{cv10}{rgb}{0.0,0.502,0.0}
\definecolor{cfv10}{rgb}{1.0,1.0,1.0}
\definecolor{clv10}{rgb}{1.0,0.0,0.0}
\definecolor{cv11}{rgb}{0.0,0.502,0.0}
\definecolor{cfv11}{rgb}{1.0,1.0,1.0}
\definecolor{clv11}{rgb}{1.0,0.0,0.0}
\definecolor{cv12}{rgb}{0.0,0.502,0.0}
\definecolor{cfv12}{rgb}{1.0,1.0,1.0}
(continues on next page)
\Vertex[style={minimum size=0.2cm,draw=cv1,fill=cfv1,text=clv1,shape=circle},
˓→LabelOut=false,L=\hbox{$1$},x=1.3874cm,y=4.7524cm]{v1}
\Vertex[style={minimum size=0.2cm,draw=cv2,fill=cfv2,text=clv2,shape=circle},
˓→LabelOut=false,L=\hbox{$2$},x=0.4952cm,y=4.0587cm]{v2}
\Vertex[style={minimum size=0.2cm,draw=cv3,fill=cfv3,text=clv3,shape=circle},
˓→LabelOut=false,L=\hbox{$3$},x=0.0cm,y=3.0563cm]{v3}
\Vertex[style={minimum size=0.2cm,draw=cv4,fill=cfv4,text=clv4,shape=circle},
˓→LabelOut=false,L=\hbox{$4$},x=0.0cm,y=1.9437cm]{v4}
\Vertex[style={minimum size=0.2cm,draw=cv5,fill=cfv5,text=clv5,shape=circle},
˓→LabelOut=false,L=\hbox{$5$},x=0.4952cm,y=0.9413cm]{v5}
\Vertex[style={minimum size=0.2cm,draw=cv6,fill=cfv6,text=clv6,shape=circle},
˓→LabelOut=false,L=\hbox{$6$},x=1.3874cm,y=0.2476cm]{v6}
\Vertex[style={minimum size=0.2cm,draw=cv7,fill=cfv7,text=clv7,shape=circle},
˓→LabelOut=false,L=\hbox{$7$},x=2.5cm,y=0.0cm]{v7}
\Vertex[style={minimum size=0.2cm,draw=cv8,fill=cfv8,text=clv8,shape=circle},
˓→LabelOut=false,L=\hbox{$8$},x=3.6126cm,y=0.2476cm]{v8}
\Vertex[style={minimum size=0.2cm,draw=cv9,fill=cfv9,text=clv9,shape=circle},
˓→LabelOut=false,L=\hbox{$9$},x=4.5048cm,y=0.9413cm]{v9}
\Vertex[style={minimum size=0.2cm,draw=cv10,fill=cfv10,text=clv10,shape=circle},
˓→LabelOut=false,L=\hbox{$10$},x=5.0cm,y=1.9437cm]{v10}
\Vertex[style={minimum size=0.2cm,draw=cv11,fill=cfv11,text=clv11,shape=circle},
˓→LabelOut=false,L=\hbox{$11$},x=5.0cm,y=3.0563cm]{v11}
\Vertex[style={minimum size=0.2cm,draw=cv12,fill=cfv12,text=clv12,shape=circle},
˓→LabelOut=false,L=\hbox{$12$},x=4.5048cm,y=4.0587cm]{v12}
%
\Edge[lw=0.04cm,style={color=cv0v1,},](v0)(v1)
\Edge[lw=0.04cm,style={color=cv0v5,},](v0)(v5)
\Edge[lw=0.04cm,style={color=cv0v13,},](v0)(v13)
\Edge[lw=0.04cm,style={color=cv1v2,},](v1)(v2)
\Edge[lw=0.04cm,style={color=cv1v10,},](v1)(v10)
\Edge[lw=0.04cm,style={color=cv2v3,},](v2)(v3)
\Edge[lw=0.04cm,style={color=cv2v7,},](v2)(v7)
\Edge[lw=0.04cm,style={color=cv3v4,},](v3)(v4)
\Edge[lw=0.04cm,style={color=cv3v12,},](v3)(v12)
\Edge[lw=0.04cm,style={color=cv4v5,},](v4)(v5)
\Edge[lw=0.04cm,style={color=cv4v9,},](v4)(v9)
\Edge[lw=0.04cm,style={color=cv5v6,},](v5)(v6)
\Edge[lw=0.04cm,style={color=cv6v7,},](v6)(v7)
\Edge[lw=0.04cm,style={color=cv6v11,},](v6)(v11)
\Edge[lw=0.04cm,style={color=cv7v8,},](v7)(v8)
\Edge[lw=0.04cm,style={color=cv8v9,},](v8)(v9)
\Edge[lw=0.04cm,style={color=cv8v13,},](v8)(v13)
\Edge[lw=0.04cm,style={color=cv9v10,},](v9)(v10)
\Edge[lw=0.04cm,style={color=cv10v11,},](v10)(v11)
\Edge[lw=0.04cm,style={color=cv11v12,},](v11)(v12)
\Edge[lw=0.04cm,style={color=cv12v13,},](v12)(v13)
%
\end{tikzpicture}
EXAMPLES:
This example illustrates switching between the built-in styles when using the tkz_graph format.:
sage: g = graphs.PetersenGraph()
sage: g.set_latex_options(tkz_style='Classic')
sage: from sage.graphs.graph_latex import check_tkz_graph
sage: check_tkz_graph() # random - depends on TeX installation
sage: latex(g)
\begin{tikzpicture}
\GraphInit[vstyle=Classic]
...
\end{tikzpicture}
sage: opts = g.latex_options()
sage: opts
LaTeX options for Petersen graph: {'tkz_style': 'Classic'}
sage: g.set_latex_options(tkz_style = 'Art')
sage: opts.get_option('tkz_style')
'Art'
sage: opts
LaTeX options for Petersen graph: {'tkz_style': 'Art'}
sage: latex(g)
\begin{tikzpicture}
\GraphInit[vstyle=Art]
...
\end{tikzpicture}
sage: g = graphs.PetersenGraph()
sage: g.set_latex_options(format='dot2tex', prog='neato')
sage: from sage.graphs.graph_latex import check_tkz_graph
sage: check_tkz_graph() # random - depends on TeX installation
sage: latex(g) # optional - dot2tex graphviz
\begin{tikzpicture}[>=latex,line join=bevel,]
...
\end{tikzpicture}
Among other things, this supports the flexible edge_options option (see sage.graphs.generic_graph.
GenericGraph.graphviz_string()); here we color in red all edges touching the vertex 0:
sage: g = graphs.PetersenGraph()
sage: g.set_latex_options(format="dot2tex", edge_options=lambda u_v_label: {"color": "red
˓→"} if u_v_label[0] == 0 else {})
dot2tex_picture()
Call dot2tex to construct a string of LaTeX commands representing a graph as a tikzpicture.
EXAMPLES:
sage: g = digraphs.ButterflyGraph(1)
sage: from sage.graphs.graph_latex import check_tkz_graph
sage: check_tkz_graph() # random - depends on TeX installation
sage: print(g.latex_options().dot2tex_picture()) # optional - dot2tex graphviz
\begin{tikzpicture}[>=latex,line join=bevel,]
(continues on next page)
%
\end{tikzpicture}
sage: G = DiGraph()
sage: G.add_edge(3333, 88, 'my_label')
sage: G.set_latex_options(edge_labels=True)
sage: print(G.latex_options().dot2tex_picture()) # optional - dot2tex graphviz
\begin{tikzpicture}[>=latex,line join=bevel,]
%%
\node (node_...) at (...bp,...bp) [draw,draw=none] {$...$};
\node (node_...) at (...bp,...bp) [draw,draw=none] {$...$};
\draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp) ..␣
˓→(node_...);
\definecolor{strokecol}{rgb}{0.0,0.0,0.0};
\pgfsetstrokecolor{strokecol}
\draw (...bp,...bp) node {$\text{\texttt{my{\char`\_}label}}$};
%
\end{tikzpicture}
sage: G = Graph([(0,1)])
sage: G.set_latex_options(edge_colors = {(0,1): 'red'})
sage: print(G.latex_options().dot2tex_picture()) # optional - dot2tex graphviz
\begin{tikzpicture}[>=latex,line join=bevel,]
...
\draw [red,] (node_0) ... (node_1);
...
\end{tikzpicture}
Note: There is a lot of overlap between what tkz_picture and dot2tex do. It would be best to merge
them! dot2tex probably can work without graphviz if layout information is provided.
get_option(option_name)
Return the current value of the named option.
INPUT:
sage: g = graphs.PetersenGraph()
sage: opts = g.latex_options()
sage: opts.set_option('tkz_style', 'Art')
sage: opts.get_option('tkz_style')
'Art'
sage: opts.set_option('tkz_style')
sage: opts.get_option('tkz_style') == "Custom"
True
sage: opts.get_option('bad_name')
Traceback (most recent call last):
...
ValueError: bad_name is not a Latex option for a graph.
latex()
Return a string in LaTeX representing a graph.
This is the command that is invoked by sage.graphs.generic_graph.GenericGraph._latex_ for a
graph, so it returns a string of LaTeX commands that can be incorporated into a LaTeX document unmod-
ified. The exact contents of this string are influenced by the options set via the methods sage.graphs.
generic_graph.GenericGraph.set_latex_options(), set_option(), and set_options().
By setting the format option different packages can be used to create the latex version of a graph. Supported
packages are tkz-graph and dot2tex.
EXAMPLES:
\Vertex[style={minimum size=1.0cm,draw=cv1,fill=cfv1,text=clv1,shape=circle},
˓→LabelOut=false,L=\hbox{$1$},x=2.5cm,y=0.0cm]{v1}
%
\Edge[lw=0.1cm,style={color=cv0v1,},](v0)(v1)
%
\end{tikzpicture}
set_option(option_name, option_value=None)
Set, modify, clear a LaTeX option for controlling the rendering of a graph.
The possible options are documented here, because ultimately it is this routine that sets the values. However,
the sage.graphs.generic_graph.GenericGraph.set_latex_options() method is the easiest way
to set options, and allows several to be set at once.
INPUT:
• option_name – a string for a latex option contained in the list sage.graphs.graph_latex.
GraphLatex.__graphlatex_options. A ValueError is raised if the option is not allowed.
• option_value – a value for the option. If omitted, or set to None, the option will use the default
value.
The output can be either handled internally by Sage, or delegated to the external software dot2tex and
graphviz. This is controlled by the option format:
• format – string (default: 'tkz_graph'); either 'dot2tex' or 'tkz_graph'.
If format is 'dot2tex', then all the LaTeX generation will be delegated to dot2tex (which must be
installed).
For tkz_graph, the possible option names, and associated values are given below. This first group allows
you to set a style for a graph and specify some sizes related to the eventual image. (For more information
consult the documentation for the tkz-graph package.)
• tkz_style – string (default: 'Custom'); the name of a pre-defined tkz-graph style such as
'Shade', 'Art', 'Normal', 'Dijkstra', 'Welsh', 'Classic', and 'Simple', or the string
'Custom'. Using one of these styles alone will often give a reasonably good drawing with mini-
mal effort. For a custom appearance set this to 'Custom' and use the options described below to
override the default values.
• units – string (default: 'cm') – a natural unit of measurement used for all dimensions. Possible
values are: 'in', 'mm', 'cm', 'pt', 'em', 'ex'.
• scale – float (default: 1.0); a dimensionless number that multiplies every linear dimension. So you
can design at sizes you are accustomed to, then shrink or expand to meet other needs. Though fonts
do not scale.
• graphic_size – tuple (default: (5, 5)); overall dimensions (width, length) of the bounding box
around the entire graphic image.
• margins – 4-tuple (default: (0, 0, 0, 0)); portion of graphic given over to a plain border as a tuple
of four numbers: (left, right, top, bottom). These are subtracted from the graphic_size to create the
area left for the vertices of the graph itself. Note that the processing done by Sage will trim the graphic
down to the minimum possible size, removing any border. So this is only useful if you use the latex
string in a latex document.
If not using a pre-built style the following options are used, so the following defaults will apply. It is not
possible to begin with a pre-built style and modify it (other than editing the latex string by hand after the
fact).
• vertex_color – (default: 'black'); a single color to use as the default for outline of vertices. For the
sphere shape this color is used for the entire vertex, which is drawn with a 3D shading. Colors must
be specified as a string recognized by the matplotlib library: a standard color name like 'red', or a hex
string like '#2D87A7', or a single character from the choices 'rgbcmykw'. Additionally, a number
between 0 and 1 will create a grayscale value. These color specifications are consistent throughout the
options for a tikzpicture.
• vertex_colors – a dictionary whose keys are vertices of the graph and whose values are colors.
These will be used to color the outline of vertices. See the explanation above for the vertex_color
option to see possible values. These values need only be specified for a proper subset of the vertices.
Specified values will supersede a default value.
• vertex_fill_color – (default: 'white'); a single color to use as the default for the fill color of
vertices. See the explanation above for the vertex_color option to see possible values. This color is
ignored for the sphere vertex shape.
• vertex_fill_colors – a dictionary whose keys are vertices of the graph and whose values are colors.
These will be used to fill the interior of vertices. See the explanation above for the vertex_color
option to see possible values. These values need only be specified for a proper subset of the vertices.
Specified values will supersede a default value.
• vertex_shape – string (default: 'circle'); specifies the shape of the vertices. Allowable values are
'circle', 'sphere', 'rectangle', 'diamond'. The sphere shape has a 3D look to its coloring
and is uses only one color, that specified by vertex_color and vertex_colors, which are normally
used for the outline of the vertex.
• vertex_shapes – a dictionary whose keys are vertices of the graph and whose values are shapes. See
vertex_shape for the allowable possibilities.
• vertex_size – float (default: 1.0); the minimum size of a vertex as a number. Vertices will expand
to contain their labels if the labels are placed inside the vertices. If you set this value to zero the vertex
will be as small as possible (up to tkz-graph’s “inner sep” parameter), while still containing labels.
However, if labels are not of a uniform size, then the vertices will not be either.
• edge_label_colors – a dictionary whose keys are edges of the graph and whose values are colors.
These will be used for the text of the labels of edges. See the explanation above for the vertex_color
option to see possible values. These values need only be specified for a proper subset of the vertices.
Specified values will supersede a default value. Note that labels must be used for this to have any
effect, and no care is taken to ensure that label and fill colors work well together.
• edge_label_sloped – boolean (default: True); specifies how edge labels are place. False results
in a horizontal label, while True means the label is rotated to follow the direction of the edge it labels.
• edge_label_slopes – a dictionary of booleans, indexed by some subset of the edges. See the
edge_label_sloped option for a description of sloped edge labels.
• edge_label_placement – (default: 0.50); either a number between 0.0 and 1.0, or one of: 'above',
'below', 'left', 'right'. These adjust the location of an edge label along an edge. A number
specifies how far along the edge the label is located. 'left' and 'right' are conveniences. 'above'
and 'below' move the label off the edge itself while leaving it near the midpoint of the edge. The
default value of 0.50 places the label on the midpoint of the edge.
• edge_label_placements – a dictionary of edge placements, indexed by the edges. See the
edge_label_placement option for a description of the allowable values.
• loop_placement – (default: (3.0, 'NO')); determine how loops are rendered. the first element
of the pair is a distance, which determines how big the loop is and the second element is a string
specifying a compass point (North, South, East, West) as one of 'NO', 'SO', 'EA', 'WE'.
• loop_placements – a dictionary of loop placements. See the loop_placements option for the
allowable values. While loops are technically edges, this dictionary is indexed by vertices.
For the 'dot2tex' format, the possible option names and associated values are given below:
• prog – string; the program used for the layout. It must be a string corresponding to one of the software
of the graphviz suite: 'dot', 'neato', 'twopi', 'circo' or 'fdp'.
• edge_labels – boolean (default: False); whether to display the labels on edges.
• edge_colors – a color; can be used to set a global color to the edge of the graph.
• color_by_label – boolean (default: False); colors the edges according to their labels
• subgraph_clusters – (default: []) a list of lists of vertices, if supported by the layout engine, nodes
belonging to the same cluster subgraph are drawn together, with the entire drawing of the cluster
contained within a bounding rectangle.
OUTPUT:
There are none. Success happens silently.
EXAMPLES:
Set, then modify, then clear the tkz_style option, and finally show an error for an unrecognized option
name:
sage: g = graphs.PetersenGraph()
sage: opts = g.latex_options()
sage: opts
LaTeX options for Petersen graph: {}
sage: opts.set_option('tkz_style', 'Art')
sage: opts
LaTeX options for Petersen graph: {'tkz_style': 'Art'}
sage: opts.set_option('tkz_style', 'Simple')
sage: opts
(continues on next page)
sage: g = graphs.PetersenGraph()
sage: opts = g.latex_options()
sage: opts.set_options(tkz_style='Welsh')
sage: opts.get_option('tkz_style')
'Welsh'
tkz_picture()
Return a string of LaTeX commands representing a graph as a tikzpicture.
This routine interprets the graph’s properties and the options in _options to render the graph with com-
mands from the tkz-graph LaTeX package.
This requires that the LaTeX optional packages tkz-graph and tkz-berge be installed. You may also
need a current version of the pgf package. If the tkz-graph and tkz-berge packages are present in
the system’s TeX installation, the appropriate \\usepackage{} commands will be added to the LaTeX
preamble as part of the initialization of the graph. If these two packages are not present, then this command
will return a warning on its first use, but will return a string that could be used elsewhere, such as a LaTeX
document.
For more information about tkz-graph you can visit https://www.ctan.org/pkg/tkz-graph.
EXAMPLES:
With a pre-built tkz-graph style specified, the latex representation will be relatively simple.
Setting the style to “Custom” results in various configurable aspects set to the defaults, so the string is more
involved.
sage: from sage.graphs.graph_latex import check_tkz_graph
sage: check_tkz_graph() # random - depends on TeX installation
sage: g = graphs.CompleteGraph(3)
sage: opts = g.latex_options()
sage: g.set_latex_options(tkz_style='Custom')
sage: print(opts.tkz_picture())
\begin{tikzpicture}
\definecolor{cv0}{rgb}{0.0,0.0,0.0}
\definecolor{cfv0}{rgb}{1.0,1.0,1.0}
\definecolor{clv0}{rgb}{0.0,0.0,0.0}
\definecolor{cv1}{rgb}{0.0,0.0,0.0}
\definecolor{cfv1}{rgb}{1.0,1.0,1.0}
\definecolor{clv1}{rgb}{0.0,0.0,0.0}
\definecolor{cv2}{rgb}{0.0,0.0,0.0}
\definecolor{cfv2}{rgb}{1.0,1.0,1.0}
\definecolor{clv2}{rgb}{0.0,0.0,0.0}
\definecolor{cv0v1}{rgb}{0.0,0.0,0.0}
\definecolor{cv0v2}{rgb}{0.0,0.0,0.0}
\definecolor{cv1v2}{rgb}{0.0,0.0,0.0}
%
\Vertex[style={minimum size=1.0cm,draw=cv0,fill=cfv0,text=clv0,shape=circle},
˓→LabelOut=false,L=\hbox{$0$},x=2.5cm,y=5.0cm]{v0}
\Vertex[style={minimum size=1.0cm,draw=cv1,fill=cfv1,text=clv1,shape=circle},
˓→LabelOut=false,L=\hbox{$1$},x=0.0cm,y=0.0cm]{v1}
\Vertex[style={minimum size=1.0cm,draw=cv2,fill=cfv2,text=clv2,shape=circle},
˓→LabelOut=false,L=\hbox{$2$},x=5.0cm,y=0.0cm]{v2}
%
\Edge[lw=0.1cm,style={color=cv0v1,},](v0)(v1)
\Edge[lw=0.1cm,style={color=cv0v2,},](v0)(v2)
\Edge[lw=0.1cm,style={color=cv1v2,},](v1)(v2)
%
(continues on next page)
See the introduction to the graph_latex module for more information on the use of this routine.
sage.graphs.graph_latex.check_tkz_graph()
Check if the proper LaTeX packages for the tikzpicture environment are installed in the user’s environment,
and issue a warning otherwise.
The warning is only issued on the first call to this function. So any doctest that illustrates the use of the tkz-graph
packages should call this once as having random output to exhaust the warnings before testing output.
See also sage.misc.latex.Latex.check_file()
sage.graphs.graph_latex.have_tkz_graph()
Return True if the proper LaTeX packages for the tikzpicture environment are installed in the user’s envi-
ronment, namely tikz, tkz-graph and tkz-berge.
The result is cached.
See also sage.misc.latex.Latex.has_file()
sage.graphs.graph_latex.setup_latex_preamble()
Add appropriate \usepackage{...}, and other instructions to the latex preamble for the packages that are
needed for processing graphs(tikz, tkz-graph, tkz-berge), if available in the LaTeX installation.
See also sage.misc.latex.Latex.add_package_to_preamble_if_available().
EXAMPLES:
sage: sage.graphs.graph_latex.setup_latex_preamble()
This module adds an interface to phitigra, a graph editor widget for Jupyter and JupyterLab. The phitigra optional
package should be installed on your Sage installation.
AUTHORS:
• Radoslav Kirov (2009): initial editor for use with the old sage notebook
• Jean-Florent Raymond (2022-04-12): replacement with the phitigra package
sage.graphs.graph_editor.graph_editor(graph=None, **display_options)
Return a graph editor widget.
The graph editor widget can be displayed with Jupyter or JupyterLab. It is provided by the phitigra op-
tional package, see https://github.com/jfraymond/phitigra for details about the possible options (changing the
width/height of the canvas, the default size and color of vertices, etc.).
INPUT:
• graph – a graph to edit (default: None)
• display_options – options for the widget
EXAMPLES:
AUTHORS:
• Robert L. Miller (2007-02-10): initial version
• Emily A. Kirkman (2007-02-13): added show functions (to_graphics_array and show_graphs)
sage.graphs.graph_list.from_graph6(data)
Return a list of Sage Graphs, given a list of graph6 data.
INPUT:
• data – can be a string, a list of strings, or a file stream
EXAMPLES:
sage: graphs_list.from_graph6(l)
[Graph on 15 vertices, Graph on 25 vertices]
sage.graphs.graph_list.from_sparse6(data)
Return a list of Sage Graphs, given a list of sparse6 data.
INPUT:
• data – can be a string, a list of strings, or a file stream
EXAMPLES:
sage: g1 = ':P_`cBaC_ACd`C_@BC`ABDHaEH_@BF_@CHIK_@BCEHKL_BIKM_BFGHI'
sage: g2 = ':f`??KO?B_OOSCGE_?OWONDBO?GOJBDO?_SSJdApcOIG`?og_UKEbg?_SKF'
sage: g2 += 'q@[CCBA`p?oYMFp@gw]Qaa@xEMHDb@hMCBCbQ@ECHEcAKKQKFPOwo[PIDQ'
sage: g2 += '{KIHEcQPOkVKEW_WMNKqPWwcRKOOWSKIGCqhWt??___WMJFCahWzEBa`xO'
sage: g2 += 'u[MpPPKqYNoOOOKHHDBPs|??__gWMKEcAHKgTLErqA?A@a@G{kVLErs?GD'
sage: g2 += 'BA@XCs\NggWSOJIDbHh@?A@aF'
sage: graphs_list.from_sparse6([g1, g2])
[Looped multi-graph on 17 vertices, Looped multi-graph on 39 vertices]
sage.graphs.graph_list.from_whatever(data)
Return a list of Sage Graphs, given a list of whatever kind of data.
INPUT:
• data – can be a string, a list/iterable of strings, or a readable file-like object
EXAMPLES:
sage: l = ['N@@?N@UGAGG?gGlKCMO', ':P_`cBaC_ACd`C_@BC`ABDHaEH_@BF_@CHIK_@BCEHKL_
˓→BIKM_BFGHI']
sage: graphs_list.from_whatever(l)
[Graph on 15 vertices, Looped multi-graph on 17 vertices]
sage: graphs_list.from_whatever('\n'.join(l))
[Graph on 15 vertices, Looped multi-graph on 17 vertices]
This example happens to be a mix a sparse and non-sparse graphs, so we don’t explicitly put a .g6 or .s6
extension, which implies just one or the other:
sage: filename = tmp_filename()
sage: with open(filename, 'w') as fobj:
....: _ = fobj.write('\n'.join(l))
sage: with open(filename) as fobj:
....: graphs_list.from_whatever(fobj)
[Graph on 15 vertices, Looped multi-graph on 17 vertices]
sage.graphs.graph_list.show_graphs(graph_list, **kwds)
Show a maximum of 20 graphs from graph_list in a sage graphics array.
If more than 20 graphs are given in the list argument, then it will display one graphics array after another with
each containing at most 20 graphs.
Note that to save the image output from the notebook, you must save each graphics array individually. (There
will be a small space between graphics arrays).
INPUT:
• graph_list – a Python list of Sage Graphs
GRAPH PLOTTING: Defaults to circular layout for graphs. This allows for a nicer display in a small area and
takes much less time to compute than the spring-layout algorithm for many graphs.
EXAMPLES: Create a list of graphs:
sage: glist = []
sage: glist.append(graphs.CompleteGraph(6))
sage: glist.append(graphs.CompleteBipartiteGraph(4, 5))
sage: glist.append(graphs.BarbellGraph(7, 4))
sage: glist.append(graphs.CycleGraph(15))
(continues on next page)
sage: len(glist)
17
sage: graphs_list.show_graphs(glist)
See the .plot() or .show() documentation for an individual graph for options, all of which are available from
to_graphics_array():
sage: glist = []
sage: for _ in range(10):
....: glist.append(graphs.RandomLobster(41, .3, .4))
sage: graphs_list.show_graphs(glist, layout='spring', vertex_size=20)
sage.graphs.graph_list.to_graphics_array(graph_list, **kwds)
Draw all graphs in a graphics array
INPUT:
• graph_list – a Python list of Sage Graphs
GRAPH PLOTTING:
Defaults to circular layout for graphs. This allows for a nicer display in a small area and takes much less time to
compute than the spring- layout algorithm for many graphs.
EXAMPLES:
sage: glist = []
sage: for i in range(999):
....: glist.append(graphs.RandomGNP(6, .45))
sage: garray = graphs_list.to_graphics_array(glist)
sage: garray.nrows(), garray.ncols()
(250, 4)
See the .plot() or .show() documentation for an individual graph for options, all of which are available from
to_graphics_array():
sage: glist = []
sage: for _ in range(10):
....: glist.append(graphs.RandomLobster(41, .3, .4))
sage: graphs_list.to_graphics_array(glist, layout='spring', vertex_size=20)
Graphics Array of size 3 x 4
This module gathers functions needed to build a graph from any other data.
Note: This is an internal module of Sage. All features implemented here are made available to end-users through the
constructors of Graph and DiGraph .
Note that because they are called by the constructors of Graph and DiGraph , most of these functions modify a graph
inplace.
5.33.1 Functions
sage.graphs.graph_input.from_dig6(G, dig6_string)
Fill G with the data of a dig6 string.
INPUT:
• G – a graph
• dig6_string – a dig6 string
EXAMPLES:
sage.graphs.graph_input.from_graph6(G, g6_string)
Fill G with the data of a graph6 string.
INPUT:
• G – a graph
• g6_string – a graph6 string
EXAMPLES:
sage: G = Graph()
sage: gnx = networkx.MultiGraph()
sage: _ = gnx.add_edge(0, 1)
sage: _ = gnx.add_edge(0, 1)
sage: from_networkx_graph(G, gnx)
sage: G.edges(sort=True, labels=False)
[(0, 1), (0, 1)]
sage: G = Graph()
sage: from_networkx_graph(G, gnx, multiedges=False)
sage: G.edges(sort=True, labels=False)
[(0, 1)]
When feeding a Graph 𝐺 with a NetworkX DiGraph 𝐷, 𝐺 has one edge (𝑢, 𝑣) whenever 𝐷 has arc (𝑢, 𝑣) or
(𝑣, 𝑢) or both:
sage: G = Graph()
sage: D = networkx.DiGraph()
sage: _ = D.add_edge(0, 1)
sage: from_networkx_graph(G, D)
sage: G.edges(sort=True, labels=False)
[(0, 1)]
sage: G = Graph()
sage: _ = D.add_edge(1, 0)
sage: from_networkx_graph(G, D)
sage: G.edges(sort=True, labels=False)
[(0, 1)]
When feeding a Graph 𝐺 with a NetworkX MultiDiGraph 𝐷, the number of edges between 𝑢 and 𝑣 in 𝐺 is the
maximum between the number of arcs (𝑢, 𝑣) and the number of arcs (𝑣, 𝑢) in D`:
sage: G = Graph()
sage: D = networkx.MultiDiGraph()
sage: _ = D.add_edge(0, 1)
sage: _ = D.add_edge(1, 0)
sage: _ = D.add_edge(1, 0)
sage: D.edges()
OutMultiEdgeDataView([(0, 1), (1, 0), (1, 0)])
sage: from_networkx_graph(G, D)
sage: G.edges(sort=True, labels=False)
[(0, 1), (0, 1)]
sage: G = DiGraph()
sage: gnx = networkx.MultiDiGraph()
sage: _ = gnx.add_edge(0, 1)
sage: _ = gnx.add_edge(0, 1)
sage: from_networkx_graph(G, gnx)
sage: G.edges(sort=True, labels=False)
[(0, 1), (0, 1)]
sage: G = DiGraph()
sage: from_networkx_graph(G, gnx, multiedges=False)
sage: G.edges(sort=True, labels=False)
[(0, 1)]
When feeding a DiGraph 𝐺 with a NetworkX Graph 𝐻, 𝐺 has both arcs (𝑢, 𝑣) and (𝑣, 𝑢) if 𝐺 has edge (𝑢, 𝑣):
sage: G = DiGraph()
sage: H = networkx.Graph()
sage: _ = H.add_edge(0, 1)
sage: from_networkx_graph(G, H)
sage: G.edges(labels=False, sort=True)
[(0, 1), (1, 0)]
When feeding a DiGraph 𝐺 with a NetworkX MultiGraph 𝐻, 𝐺 has 𝑘 arcs (𝑢, 𝑣) and 𝑘 arcs (𝑣, 𝑢) if 𝐻 has 𝑘
edges (𝑢, 𝑣), unless parameter multiedges is set to False:
sage: G = DiGraph()
sage: H = networkx.MultiGraph()
sage: _ = H.add_edge(0, 1)
sage: _ = H.add_edge(0, 1)
sage: _ = H.add_edge(0, 1)
sage: H.edges()
MultiEdgeDataView([(0, 1), (0, 1), (0, 1)])
sage: from_networkx_graph(G, H)
sage: G.edges(labels=False, sort=True)
[(0, 1), (0, 1), (0, 1), (1, 0), (1, 0), (1, 0)]
sage: G = DiGraph()
sage: from_networkx_graph(G, H, multiedges=False)
sage: G.edges(labels=False, sort=True)
[(0, 1), (1, 0)]
sage.graphs.graph_input.from_seidel_adjacency_matrix(G, M)
Fill G with the data of a Seidel adjacency matrix.
INPUT:
• G – a graph
• M – a Seidel adjacency matrix
EXAMPLES:
sage: g.is_isomorphic(graphs.PetersenGraph())
True
sage.graphs.graph_input.from_sparse6(G, g6_string)
Fill G with the data of a sparse6 string.
INPUT:
• G – a graph
• g6_string – a sparse6 string
EXAMPLES:
5.34 Hyperbolicity
Definition :
The hyperbolicity 𝛿 of a graph 𝐺 has been defined by Gromov [Gro1987] as follows (we give here the
so-called 4-points condition):
Let 𝑎, 𝑏, 𝑐, 𝑑 be vertices of the graph, let 𝑆1 , 𝑆2 and 𝑆3 be defined by
𝑆1 = 𝑑𝑖𝑠𝑡(𝑎, 𝑏) + 𝑑𝑖𝑠𝑡(𝑑, 𝑐)
𝑆2 = 𝑑𝑖𝑠𝑡(𝑎, 𝑐) + 𝑑𝑖𝑠𝑡(𝑏, 𝑑)
𝑆3 = 𝑑𝑖𝑠𝑡(𝑎, 𝑑) + 𝑑𝑖𝑠𝑡(𝑏, 𝑐)
and let 𝑀1 and 𝑀2 be the two largest values among 𝑆1 , 𝑆2 , and 𝑆3 . We define ℎ𝑦𝑝(𝑎, 𝑏, 𝑐, 𝑑) =
𝑀1 − 𝑀2 , and the hyperbolicity 𝛿(𝐺) of the graph is the maximum of ℎ𝑦𝑝 over all possible
4-tuples (𝑎, 𝑏, 𝑐, 𝑑) divided by 2. That is, the graph is said 𝛿-hyperbolic when
1
𝛿(𝐺) = max ℎ𝑦𝑝(𝑎, 𝑏, 𝑐, 𝑑)
2 𝑎,𝑏,𝑐,𝑑∈𝑉 (𝐺)
(note that ℎ𝑦𝑝(𝑎, 𝑏, 𝑐, 𝑑) = 0 whenever two elements among 𝑎, 𝑏, 𝑐, 𝑑 are equal)
Some known results :
• Trees and cliques are 0-hyperbolic
• 𝑛 × 𝑛 grids are 𝑛 − 1-hyperbolic
• Cycles are approximately 𝑛/4-hyperbolic
• Chordal graphs are ≤ 1-hyperbolic
Besides, the hyperbolicity of a graph is the maximum over all its biconnected components.
Algorithms and complexity :
The time complexity of the naive implementation (i.e. testing all 4-tuples) is 𝑂(𝑛4 ), and an algorithm
with time complexity 𝑂(𝑛3.69 ) has been proposed in [FIV2012]. This remains very long for large-scale
graphs, and much harder to implement.
Several improvements over the naive algorithm have been proposed and are implemented in the current
module.
• Another upper bound on ℎ𝑦𝑝(𝑎, 𝑏, 𝑐, 𝑑) has been proved in [CCL2015]. It is used to design an algo-
rithm with worse case time complexity in 𝑂(𝑛4 ) but that behaves much better in practice.
Assume that 𝑆1 = 𝑑𝑖𝑠𝑡(𝑎, 𝑏) + 𝑑𝑖𝑠𝑡(𝑐, 𝑑) is the largest sum among 𝑆1 , 𝑆2 , 𝑆3 . We have
We obtain similarly that ℎ𝑦𝑝(𝑎, 𝑏, 𝑐, 𝑑) ≤ 𝑑𝑖𝑠𝑡(𝑎, 𝑏). Consequently, in the implementation of the
‘CCL’ algorithm, we ensure that 𝑆1 is larger than 𝑆2 and 𝑆3 using an ordering of the pairs by decreas-
ing lengths. Then, we use the best value ℎ found so far to stop exploration as soon as 𝑑𝑖𝑠𝑡(𝑎, 𝑏) ≤ ℎ.
The worst case time complexity of this algorithm is 𝑂(𝑛4 ), but it performs very well in practice since
it cuts the search space. This algorithm can be turned into an approximation algorithm since at any
step of its execution we maintain an upper and a lower bound. We can thus stop execution as soon as
a multiplicative approximation factor or an additive one is proven.
• The notion of ‘’far-apart pairs” has been introduced in [Sot2011] to further reduce the number of
4-tuples to consider. We say that the pair (𝑎, 𝑏) is far-apart if for every 𝑤 in 𝑉 ∖ {𝑎, 𝑏} we have
Determining the set of far-apart pairs can be done in time 𝑂(𝑛𝑚) using BFS. Now, it is proved in
[Sot2011] that there exists two far-apart pairs (𝑎, 𝑏) and (𝑐, 𝑑) satisfying 𝛿(𝐺) = ℎ𝑦𝑝(𝑎, 𝑏, 𝑐, 𝑑)/2.
For instance, the 𝑛 × 𝑚-grid has only two far-apart pairs, and so computing its hyperbolicity is
immediate once the far-apart pairs are found. The ‘CCL+FA’ or ‘CCL+’ algorithm improves the
‘CCL’ algorithm since it uses far-apart pairs.
• This algorithm was further improved in [BCCM2015]: instead of iterating twice over all pairs of
vertices, in the “inner” loop, we cut several pairs by exploiting properties of the underlying graph.
Todo:
• Add exact methods for the hyperbolicity of chordal graphs
• Add method for partitioning the graph with clique separators
AUTHORS:
• David Coudert (2012): initial version, exact and approximate algorithm, distribution, sampling
• David Coudert (2014): improved exact algorithm using far-apart pairs
• Michele Borassi (2015): cleaned the code and implemented the new algorithm
• Karan Desai (2016): fixed minor typo in documentation
5.34.1 Methods
Hyperbolicity of a PetersenGraph:
Comparison of results:
sage: from sage.graphs.hyperbolicity import hyperbolicity
sage: for i in range(10): # long time
....: G = graphs.RandomBarabasiAlbert(100,2)
....: d1,_,_ = hyperbolicity(G, algorithm='basic')
....: d2,_,_ = hyperbolicity(G, algorithm='CCL')
....: d3,_,_ = hyperbolicity(G, algorithm='CCL+')
....: d4,_,_ = hyperbolicity(G, algorithm='CCL+FA')
....: d5,_,_ = hyperbolicity(G, algorithm='BCCM')
....: l3,_,u3 = hyperbolicity(G, approximation_factor=2)
....: if (not d1==d2==d3==d4==d5) or l3>d1 or u3<d1:
....: print("That's not good!")
The hyperbolicity of a graph is the maximum value over all its biconnected components:
sage.graphs.hyperbolicity.hyperbolicity_distribution(G, algorithm='sampling',
sampling_size=1000000)
Return the hyperbolicity distribution of the graph or a sampling of it.
The hyperbolicity of a graph has been defined by Gromov [Gro1987] as follows: Let 𝑎, 𝑏, 𝑐, 𝑑 be vertices of the
graph, let 𝑆1 = 𝑑𝑖𝑠𝑡(𝑎, 𝑏) + 𝑑𝑖𝑠𝑡(𝑏, 𝑐), 𝑆2 = 𝑑𝑖𝑠𝑡(𝑎, 𝑐) + 𝑑𝑖𝑠𝑡(𝑏, 𝑑), and 𝑆3 = 𝑑𝑖𝑠𝑡(𝑎, 𝑑) + 𝑑𝑖𝑠𝑡(𝑏, 𝑐), and let
𝑀1 and 𝑀2 be the two largest values among 𝑆1 , 𝑆2 , and 𝑆3 . We have ℎ𝑦𝑝(𝑎, 𝑏, 𝑐, 𝑑) = |𝑀1 − 𝑀2 |, and the
hyperbolicity of the graph is the maximum over all possible 4-tuples (𝑎, 𝑏, 𝑐, 𝑑) divided by 2.
The computation of the hyperbolicity of each 4-tuple, and so the hyperbolicity distribution, takes time in 𝑂(𝑛4 ).
INPUT:
• G – a Graph.
• algorithm – (default: ‘sampling’) When algorithm is ‘sampling’, it returns the distribution of the hyper-
bolicity over a sample of sampling_size 4-tuples. When algorithm is ‘exact’, it computes the distribution
of the hyperbolicity over all 4-tuples. Be aware that the computation time can be HUGE.
• sampling_size – (default: 106 ) number of 4-tuples considered in the sampling. Used only when
algorithm == 'sampling'.
OUTPUT:
• hdict – A dictionary such that hdict[i] is the number of 4-tuples of hyperbolicity i.
EXAMPLES:
Exact hyperbolicity distribution of the Petersen Graph:
This module implements a deletion-contraction algorithm for computing the Tutte polynomial as described in the paper
[HPR2010].
Authors:
• Mike Hansen (06-2013), Implemented the algorithm.
• Jernej Azarija (06-2013), Tweaked the code, added documentation
5.35.1 Definition
Given a graph 𝐺, with 𝑛 vertices and 𝑚 edges and 𝑘(𝐺) connected components we define the Tutte polynomial of 𝐺
as
∑︁
(𝑥 − 1)𝑘(𝐻)−𝑐 (𝑦 − 1)𝑘(𝐻)−|𝐸(𝐻)|−𝑛
𝐻
5.35.2 Functions
sage: G = graphs.PathGraph(4)
sage: G.add_edges([(0,4),(0,5),(3,6),(3,7)])
sage: from sage.graphs.tutte_polynomial import Ear
sage: E = Ear.find_ear(G)
sage: E.s
3
(continues on next page)
removed_from(*args, **kwds)
A context manager which removes the ear from the graph 𝐺.
EXAMPLES:
sage: G = graphs.PathGraph(4)
sage: G.add_edges([(0,4),(0,5),(3,6),(3,7)])
sage: len(G.edges(sort=True))
7
sage: from sage.graphs.tutte_polynomial import Ear
sage: E = Ear.find_ear(G)
sage: with E.removed_from(G) as Y:
....: G.edges(sort=True)
[(0, 4, None), (0, 5, None), (3, 6, None), (3, 7, None)]
sage: len(G.edges(sort=True))
7
s
Returns the number of distinct edges in this ear.
EXAMPLES:
sage: G = graphs.PathGraph(4)
sage: G.add_edges([(0,4),(0,5),(3,6),(3,7)])
sage: from sage.graphs.tutte_polynomial import Ear
sage: E = Ear(G,[0,3],[1,2],False)
sage: E.s
3
unlabeled_edges()
Returns the edges in this ear.
EXAMPLES:
sage: G = graphs.PathGraph(4)
sage: G.add_edges([(0,4),(0,5),(3,6),(3,7)])
sage: from sage.graphs.tutte_polynomial import Ear
sage: E = Ear(G,[0,3],[1,2],False)
sage: E.unlabeled_edges
[(0, 1), (1, 2), (2, 3)]
vertices
Returns the vertices of this ear.
EXAMPLES:
sage: G = graphs.PathGraph(4)
sage: G.add_edges([(0,4),(0,5),(3,6),(3,7)])
sage: from sage.graphs.tutte_polynomial import Ear
sage: E = Ear(G,[0,3],[1,2],False)
(continues on next page)
class sage.graphs.tutte_polynomial.EdgeSelection
Bases: object
class sage.graphs.tutte_polynomial.MaximizeDegree
Bases: sage.graphs.tutte_polynomial.EdgeSelection
class sage.graphs.tutte_polynomial.MinimizeDegree
Bases: sage.graphs.tutte_polynomial.EdgeSelection
class sage.graphs.tutte_polynomial.MinimizeSingleDegree
Bases: sage.graphs.tutte_polynomial.EdgeSelection
class sage.graphs.tutte_polynomial.VertexOrder(order)
Bases: sage.graphs.tutte_polynomial.EdgeSelection
EXAMPLES:
sage.graphs.tutte_polynomial.contracted_edge(*args, **kwds)
Delete the first vertex in the edge, and make all the edges that went from it go to the second vertex.
EXAMPLES:
sage.graphs.tutte_polynomial.edge_multiplicities(G)
Return the dictionary of multiplicities of the edges in the graph 𝐺.
EXAMPLES:
sage.graphs.tutte_polynomial.removed_edge(*args, **kwds)
A context manager which removes an edge from the graph 𝐺 and restores it upon exiting.
EXAMPLES:
sage.graphs.tutte_polynomial.removed_loops(*args, **kwds)
A context manager which removes all the loops in the graph 𝐺. It yields a list of the loops, and restores the loops
upon exiting.
EXAMPLES:
sage.graphs.tutte_polynomial.removed_multiedge(*args, **kwds)
A context manager which removes an edge with multiplicity from the graph 𝐺 and restores it upon exiting.
EXAMPLES:
• cache – (optional; dict) a dictionary to cache the Tutte polynomials generated in the recursive process. One
will be created automatically if not provided.
EXAMPLES:
The Tutte polynomial of any tree of order 𝑛 is 𝑥𝑛−1 :
sage: P = graphs.PetersenGraph()
sage: P.tutte_polynomial()
x^9 + 6*x^8 + 21*x^7 + 56*x^6 + 12*x^5*y + y^6 + 114*x^5 + 70*x^4*y
+ 30*x^3*y^2 + 15*x^2*y^3 + 10*x*y^4 + 9*y^5 + 170*x^4 + 170*x^3*y
+ 105*x^2*y^2 + 65*x*y^3 + 35*y^4 + 180*x^3 + 240*x^2*y + 171*x*y^2
+ 75*y^3 + 120*x^2 + 168*x*y + 84*y^2 + 36*x + 36*y
The Tutte polynomial of a connected graph 𝐺 evaluated at (1,1) is the number of spanning trees of 𝐺:
sage: G = graphs.RandomGNP(10,0.6)
sage: while not G.is_connected():
....: G = graphs.RandomGNP(10,0.6)
sage: G.tutte_polynomial()(1,1) == G.spanning_trees_count()
True
Given that 𝑇 (𝑥, 𝑦) is the Tutte polynomial of a graph 𝐺 with 𝑛 vertices and 𝑐 connected components, then
(−1)𝑛−𝑐 𝑥𝑘 𝑇 (1 − 𝑥, 0) is the chromatic polynomial of 𝐺.
sage: G = graphs.OctahedralGraph()
sage: T = G.tutte_polynomial()
sage: R = PolynomialRing(ZZ, 'x')
sage: R((-1)^5*x*T(1-x,0)).factor()
(x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32)
sage: G.chromatic_polynomial().factor()
(x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32)
sage.graphs.tutte_polynomial.underlying_graph(G)
Given a graph 𝐺 with multi-edges, returns a graph where all the multi-edges are replaced with a single edge.
EXAMPLES:
The code in this module that recognizes partial cubes is originally from the PADS library by David Eppstein, which is
available at http://www.ics.uci.edu/~eppstein/PADS/ under the MIT license. It has a quadratic runtime and has been
described in [Epp2008].
For more information on partial cubes, see the Wikipedia article Partial cube.
Definitions
A partial cube is an isometric subgraph 𝐺 of a CubeGraph() (of possibly high dimension). Consequently, the vertices
of 𝐺 can be labelled with binary sequences in such a way that the distance between two vertices 𝑢, 𝑣 ∈ 𝐺 is the Hamming
distance between their labels.
Tokens and their action: in the terminology of [Epp2008], a token represents a transition of the form:
switch the k-th bit of the binary string from 0 to 1
Each token can be matched with a ‘reversed’ token that performs the same switch in the opposite direction. Alterna-
tively, a token can be seen as a set of disjoint (directed) edges of 𝐺, corresponding to the transitions. When a vertex
𝑣 ∈ 𝐺 is the source of such an edge, it is said that the token acts on 𝑣.
Observations
Shortest paths: in a hypercube, a shortest path between two vertices uses each token at most once. Furthermore, it
cannot use both a token and it reverse.
Cycles: a cycle in a partial cube is necessarily even, as hypercubes are bipartite. If an edge 𝑒 of a cycle 𝐶 belongs to a
token 𝑇 , then the edge opposite to 𝑒 in 𝐶 belongs to the reverse of 𝑇 .
Incident edges: all 2𝑑𝐺 (𝑣) arcs incident to a given vertex belong to as many different tokens.
Algorithm
Labeling: Iteratively, the algorithm selects a vertex 𝑣 ∈ 𝐺, which is naturally associated to 2𝑑(𝑣) tokens. It then
performs a breadth-first search from 𝑣, applying the previous observation on cycles to attribute a token to some of the
edges it meets. None of the edges whose token remains undecided after this step can belong to one of those 2𝑑(𝑣)
tokens, by virtue of the observation on shortest paths.
The labeled edges can then be simplified (contracted) if the previous step did not lead to a contradiction, and the
procedure is applied again until the graph is contracted to a single vertex and all edges are labeled.
A partial cube is correctly labeled at this step, but some other graphs can also satisfy the procedure.
Checking the labeling: once all tokens are defined and the vertices are labeled with a binary string, we check that they
define an isometric subgraph of the hypercube. To ensure that the distance 𝑑(𝑣0 , 𝑢) is what we expect for any vertex
𝑢, it is sufficient to find, for any vertex 𝑢, a neighbor 𝑛𝑢 of 𝑢 whose Hamming distance with 𝑣0 is strictly less than the
Hamming distance between 𝑢 and 𝑣0 . Here is the algorithm used to check the labeling:
• For an initial vertex 𝑣, run a BFS starting from 𝑣, and associate to every other vertex 𝑢 a token that brings 𝑢
closer to 𝑣. This yields shortest paths from every vertex to 𝑣.
• Assuming that the information is computed (and correct) for 𝑣, it is easy to update it for a neighbor 𝑣 ′ of 𝑣.
Indeed, if we write 𝑇 the token that turns 𝑣 into 𝑣 ′ , only the vertices which were associated with the reverse of
𝑇 need to select a new neighbour. All others can remain as they were previously.
With this second observation, one can efficiently check that the distance between all pairs of vertices are what
they should be. In the implementation, the sequence of the sources (𝑣, 𝑣 ′ , ...) is given by a depth-first search.
5.36.2 Functions
sage.graphs.partial_cube.breadth_first_level_search(G, start)
Generate a sequence of dictionaries, each mapping the vertices at distance i from start to the set of their
neighbours at distance i+1.
Originally written by D. Eppstein for the PADS library (http://www.ics.uci.edu/~eppstein/PADS/).
INPUT:
• G – a graph to perform the search on.
• start – vertex or list of vertices from which to start the traversal.
EXAMPLES:
sage: H = digraphs.DeBruijn(3,2)
sage: list(sage.graphs.partial_cube.breadth_first_level_search(H, '00'))
[{'00': {'01', '02'}},
{'01': {'10', '11', '12'}, '02': {'20', '21', '22'}},
{'10': set(),
'11': set(),
'12': set(),
'20': set(),
'21': set(),
'22': set()}]
sage.graphs.partial_cube.depth_first_traversal(G, start)
Generate a sequence of triples (v,w,edgetype) for DFS of graph G.
Originally written by D. Eppstein for the PADS library (http://www.ics.uci.edu/~eppstein/PADS/).
INPUT:
• G – a graph to perform the search on.
• start – vertex or list of vertices from which to start the traversal.
OUTPUT:
• a generator of triples (v,w,edgetype), where edgetype is True if the algorithm is progressing via the
edge vw, or False if the algorithm is backtracking via the edge wv.
EXAMPLES:
sage: H = digraphs.DeBruijn(3,2)
sage: t = list(sage.graphs.partial_cube.depth_first_traversal(H, '00'))
sage: len(t)
16
sage.graphs.partial_cube.is_partial_cube(G, certificate=False)
Test whether the given graph is a partial cube.
A partial cube is a graph that can be isometrically embedded into a hypercube, i.e., its vertices can be labelled
with (0,1)-vectors of some fixed length such that the distance between any two vertices in the graph equals the
Hamming distance of their labels.
Originally written by D. Eppstein for the PADS library (http://www.ics.uci.edu/~eppstein/PADS/), see also
[Epp2008]. The algorithm runs in 𝑂(𝑛2 ) time, where 𝑛 is the number of vertices. See the documentation
of partial_cube for an overview of the algorithm.
INPUT:
• certificate – boolean (default: False); this function returns True or False according to the graph,
when certificate = False. When certificate = True and the graph is a partial cube, the function
returns (True, mapping), where mapping is an isometric mapping of the vertices of the graph to the
vertices of a hypercube ((0, 1)-strings of a fixed length). When certificate = True and the graph is
not a partial cube, (False, None) is returned.
EXAMPLES:
The Petersen graph is not a partial cube:
sage: g = graphs.PetersenGraph()
sage: g.is_partial_cube()
False
sage: g = graphs.CycleGraph(10).cartesian_product(graphs.CompleteGraph(2))
sage: g.is_partial_cube()
True
This module is meant for all functions related to path enumeration in graphs.
5.37.1 Functions
sage: g = Graph([(0, 1), (0, 1), (1, 2), (1, 2)], multiedges=True)
sage: g.all_paths(0, 2, use_multiedges=True)
[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]
sage: g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']}, loops=True)
sage: pi = g.all_paths_iterator(starting_vertices=['a'], ending_vertices=['d'],␣
˓→report_edges=True, simple=True)
sage: list(pi)
[[('a', 'b'), ('b', 'c'), ('c', 'd')]]
sage: g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']}, loops=True)
sage: pi = g.all_paths_iterator()
sage: [len(next(pi)) - 1 for _ in range(7)]
[1, 1, 1, 1, 1, 2, 2]
sage: pi = g.all_paths_iterator(starting_vertices=['a'])
sage: [len(next(pi)) - 1 for _ in range(5)]
[1, 1, 2, 2, 2]
sage: pi = g.all_paths_iterator(starting_vertices=['a'], ending_vertices=['b'])
sage: for _ in range(5):
....: print(next(pi))
['a', 'b']
['a', 'a', 'b']
['a', 'a', 'a', 'b']
['a', 'a', 'a', 'a', 'b']
['a', 'a', 'a', 'a', 'a', 'b']
sage: pi = g.all_paths_iterator(simple=True)
sage: sorted(list(pi), key=lambda x:(len(x), x))
[['a', 'a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'c'],
['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'], ['d', 'c', 'd'],
['a', 'b', 'c', 'd']]
sage: pi = g.all_paths_iterator(simple=True)
sage: [len(p) - 1 for p in pi]
[1, 1, 1, 1, 1, 2, 2, 2, 2, 3]
• trivial - boolean (default: False); if set to True, then the empty paths are also enumerated.
• use_multiedges – boolean (default: False); this parameter is used only if the graph has multiple edges.
– If False, the graph is considered as simple and an edge label is arbitrarily selected for each edge as
in sage.graphs.generic_graph.GenericGraph.to_simple() if report_edges is True
– If True, a path will be reported as many times as the edges multiplicities along that path (when
report_edges = False or labels = False), or with all possible combinations of edge labels
(when report_edges = True and labels = True)
• report_edges – boolean (default: False); whether to report paths as list of vertices (default) or list of
edges, if False then labels parameter is ignored
• labels – boolean (default: False); if False, each edge is simply a pair (u, v) of vertices. Otherwise a
list of edges along with its edge labels are used to represent the path.
OUTPUT:
list
Note: Although the number of simple paths of a finite graph is always finite, computing all its paths may take
a very long time.
EXAMPLES:
[[0, 1, 2]]
sage: g.all_simple_paths(starting_vertices=[0], ending_vertices=[2], use_
˓→multiedges=True)
[[(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)]]
sage: g.all_simple_paths(starting_vertices=[0], ending_vertices=[2], use_
˓→multiedges=True, report_edges=True, labels=True)
One may compute all paths having specific starting and/or ending vertices:
sage: g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']}, loops=True)
sage: g.all_simple_paths(starting_vertices=['a'])
[['a', 'a'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'd']]
sage: g.all_simple_paths(starting_vertices=['a'], ending_vertices=['c'])
[['a', 'b', 'c']]
sage: g.all_simple_paths(starting_vertices=['a'], ending_vertices=['b', 'c'])
[['a', 'b'], ['a', 'b', 'c']]
By default, empty paths are not enumerated, but this can be parametrized:
sage: g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']}, loops=True)
sage: g.all_simple_paths(starting_vertices=['a'], trivial=True)
[['a'], ['a', 'a'], ['a', 'b'], ['a', 'b', 'c'],
['a', 'b', 'c', 'd']]
sage: g.all_simple_paths(starting_vertices=['a'], trivial=False)
[['a', 'a'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'd']]
For unweighted graphs, paths are returned in order of increasing number of edges.
In case of weighted graphs, negative weights are not allowed.
If source is the same vertex as target, then [[source]] is returned – a list containing the 1-vertex, 0-edge
path source.
The loops and the multiedges if present in the given graph are ignored and only minimum of the edge labels is
kept in case of multiedges.
INPUT:
• source – a vertex of the graph, where to start
• target – a vertex of the graph, where to end
• weight_function – function (default: None); a function that takes as input an edge (u, v, l) and
outputs its weight. If not None, by_weight is automatically set to True. If None and by_weight is True,
we use the edge label l as a weight.
• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise all edges
have weight 1
• check_weight – boolean (default: True); whether to check that the weight_function outputs a number
for each edge
• report_edges – boolean (default: False); whether to report paths as list of vertices (default) or list of
edges, if False then labels parameter is ignored
• labels – boolean (default: False); if False, each edge is simply a pair (u, v) of vertices. Otherwise a
list of edges along with its edge labels are used to represent the path.
• report_weight – boolean (default: False); if False, just the path between source and target is
returned. Otherwise a tuple of path length and path is returned.
ALGORITHM:
This algorithm can be divided into two parts. Firstly, it determines the shortest path from source to target.
Then, it determines all the other 𝑘-shortest paths. This algorithm finds the deviations of previous shortest paths
to determine the next shortest paths. This algorithm finds the candidate paths more efficiently using a node
classification technique. At first the candidate path is separated by its deviation node as prefix and suffix. Then
the algorithm classify the nodes as red, yellow and green. A node on the prefix is assigned a red color, a node that
can reach t (the destination node) through a shortest path without visiting a red node is assigned a green color,
and all other nodes are assigned a yellow color. When searching for the suffix of a candidate path, all green nodes
are bypassed, and Dijkstra’s algorithm is applied to find an all-yellow-node subpath. Since on average the
number of yellow nodes is much smaller than n, this algorithm has a much lower average-case running time.
Time complexity is 𝑂(𝑘𝑛(𝑚 + 𝑛 log 𝑛)) where 𝑛 is the number of vertices and 𝑚 is the number of edges and 𝑘
is the number of shortest paths needed to find. Its average running time is much smaller as compared to 𝑌 𝑒𝑛′ 𝑠
algorithm.
See [Feng2014] for more details on this algorithm.
EXAMPLES:
[[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]]
sage: list(feng_k_shortest_simple_paths(g, 1, 5, report_edges=True, labels=True, by_
˓→weight=True, report_weight=True))
[(2, [(1, 2), (2, 3)]), (3, [(1, 4), (4, 5), (5, 3)])]
sage: list(feng_k_shortest_simple_paths(g, 1, 3, report_weight=True, report_
˓→edges=True, by_weight=True))
[(3, [(1, 4), (4, 5), (5, 3)]), (5, [(1, 2), (2, 3)])]
sage: list(feng_k_shortest_simple_paths(g, 1, 3, report_weight=True, report_
˓→edges=True, by_weight=True, labels=True))
[(3, [(1, 4, 2), (4, 5, 1), (5, 3, 0)]), (5, [(1, 2, 5), (2, 3, 0)])]
sage: g = DiGraph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), (3, 5, 10), (4,␣
˓→5, 30)])
[(20, [(1, 3), (3, 5)]), (40, [(1, 2), (2, 5)]), (60, [(1, 4), (4, 5)])]
sage: list(g.shortest_simple_paths(1, 5, report_edges=True, report_weight=True))
[(2, [(1, 4), (4, 5)]), (2, [(1, 3), (3, 5)]), (2, [(1, 2), (2, 5)])]
sage: list(g.shortest_simple_paths(1, 5, by_weight=True, report_edges=True))
[[(1, 3), (3, 5)], [(1, 2), (2, 5)], [(1, 4), (4, 5)]]
sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Feng", report_
˓→edges=True, labels=True))
[[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]]
sage: g = Graph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), (3, 5, 10), (4, 5,␣
˓→30), (1, 6, 100), (5, 6, 5)])
[(2, [(1, 2), (2, 5)]), (2, [(1, 3), (3, 5)]), (2, [(1, 4), (4, 5)])]
sage: list(yen_k_shortest_simple_paths(g, 1, 5, by_weight=True, report_edges=True))
[[(1, 3), (3, 5)], [(1, 2), (2, 5)], [(1, 4), (4, 5)]]
sage: list(yen_k_shortest_simple_paths(g, 1, 5, by_weight=True, report_edges=True,␣
˓→labels=True))
[[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]]
sage: from sage.graphs.path_enumeration import yen_k_shortest_simple_paths
sage: g = Graph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), (3, 5, 10), (4, 5,␣
˓→30), (1, 6, 100), (5, 6, 5)])
AUTHORS:
• Robert L. Miller (2007-02-13): initial version
• Robert W. Bradshaw (2007-03-31): fast spring layout algorithms
• Nathann Cohen : exhaustive search
class sage.graphs.generic_graph_pyx.GenericGraph_pyx
Bases: sage.structure.sage_object.SageObject
class sage.graphs.generic_graph_pyx.SubgraphSearch
Bases: object
This class implements methods to exhaustively search for copies of a graph 𝐻 in a larger graph 𝐺.
It is possible to look for induced subgraphs instead, and to iterate or count the number of their occurrences.
ALGORITHM:
The algorithm is a brute-force search. Let 𝑉 (𝐻) = {ℎ1 , . . . , ℎ𝑘 }. It first tries to find in 𝐺 a possible represen-
tative of ℎ1 , then a representative of ℎ2 compatible with ℎ1 , then a representative of ℎ3 compatible with the first
two, etc.
This way, most of the time we need to test far less than 𝑘! |𝑉 (𝐺)| subsets, and hope this brute-force technique
(︀ )︀
𝑘
can sometimes be useful.
Note: This algorithm does not take vertex/edge labels into account.
cardinality()
Returns the number of labelled subgraphs of 𝐺 isomorphic to 𝐻.
Note: This method counts the subgraphs by enumerating them all ! Hence it probably is not a good idea
to count their number before enumerating them :-)
EXAMPLES:
Counting the number of labelled 𝑃3 in 𝑃5 :
sage: from sage.graphs.generic_graph_pyx import SubgraphSearch
sage: g = graphs.PathGraph(5)
sage: h = graphs.PathGraph(3)
sage: S = SubgraphSearch(g, h)
sage: S.cardinality()
6
sage.graphs.generic_graph_pyx.binary_string_from_dig6(s, n)
A helper function for the dig6 format.
INPUT:
• s – a graph6 string
• n – the length of the binary string encoded by s.
EXAMPLES:
sage: from sage.graphs.generic_graph_pyx import binary_string_from_dig6
sage: d6 = '?????_@?CG??B??@OG?C?G???GO??W@a???CO???OACC?OA?P@G??O?????'
sage: d6 += '?G??C????c?G?CC?_?@???C_??_?C????PO?C_??AA?OOAHCA___?CC?A?'
sage: d6 += 'CAOGO??????A??G?GR?C?_o`???g???A_C?OG??O?G_IA????_QO@EG???'
sage: d6 += 'O??C?_?C@?G???@?_??AC?AO?a???O?????A?_Dw?H???__O@AAOAACd?_'
sage: d6 += 'C??G?G@??GO?_???O@?_O??W??@P???AG??B?????G??GG???A??@?aC_G'
sage: d6 += '@A??O??_?A?????O@Z?_@M????GQ@_G@?C?'
sage: binary_string_from_dig6(d6, 63)
˓→'000000000000000000000000000000100000000001000000000100001000000000000000000011000000000000000001
˓→..
(continues on next page)
˓→1000000000000000000000000000000001000000000101101100000010000000000100111000000000000000000000000
˓→'
˓→'0000000000000000000001000000000000010000100000100000001000000000000000100000000100000.
˓→..
˓→0100000000000001000100000010000000000000000000000000000010100000000010110000000000000100100000000
˓→'
sage.graphs.generic_graph_pyx.binary_string_from_graph6(s, n)
Decode a binary string from its graph6 representation
This helper function is the inverse of 𝑅 from [McK2015].
INPUT:
• s – a graph6 string
• n – the length of the binary string encoded by s.
EXAMPLES:
˓→ '000000000000000000000000000000100000000001000000000100001000000000000000000011000000000000000001
˓→ ..
˓→1000000000000000000000000000000001000000000101101100000010000000000100111000000000000000000000000
˓→'
sage: g6 = '???C?@AA?_?A?O?C??S??O?q_?P?CHD??@?C?GC???C??GG?C_??O?COG??'
sage: g6 += '??I?J??Q??O?_@@??@??????'
sage: binary_string_from_graph6(g6, 32)
˓→'0000000000000000000001000000000000010000100000100000001000000000000000100000000100000.
˓→..
˓→0100000000000001000100000010000000000000000000000000000010100000000010110000000000000100100000000
˓→'
sage.graphs.generic_graph_pyx.binary_string_to_graph6(x)
Transform a binary string into its graph6 representation.
This helper function is named 𝑅 in [McK2015].
INPUT:
• x – a binary string.
EXAMPLES:
Warning: May loop endlessly when run on a graph with vertices of degree 1.
EXAMPLES:
For demonstration purposes we fix a random seed:
sage: set_random_seed(0)
First we try the algorithm in the Dodecahedral graph, which is Hamiltonian, so we are able to find a Hamiltonian
cycle and a Hamiltonian path:
Another test, now in the Möbius-Kantor graph which is also Hamiltonian, as in our previous example, we are
able to find a Hamiltonian cycle and path:
sage: G=graphs.MoebiusKantorGraph()
sage: fh(G)
(True, [15, 10, 2, 3, 4, 5, 13, 8, 11, 14, 6, 7, 0, 1, 9, 12])
sage: fh(G,find_path=True)
(True, [10, 15, 7, 6, 5, 4, 12, 9, 14, 11, 3, 2, 1, 0, 8, 13])
Now, we try the algorithm on a non Hamiltonian graph, the Petersen graph. This graph is known to be hypo-
hamiltonian, so a Hamiltonian path can be found:
sage: G=graphs.PetersenGraph()
sage: fh(G)
(False, [9, 4, 0, 1, 6, 8, 5, 7, 2, 3])
sage: fh(G,find_path=True)
(True, [7, 2, 1, 0, 5, 8, 6, 9, 4, 3])
We now show the algorithm working on another known hypohamiltonian graph, the generalized Petersen graph
with parameters 11 and 2:
sage: G=graphs.GeneralizedPetersenGraph(11,2)
sage: fh(G)
(False, [7, 8, 9, 10, 0, 1, 2, 3, 14, 12, 21, 19, 17, 6, 5, 4, 15, 13, 11, 20, 18,␣
˓→16])
sage: fh(G,find_path=True)
(True, [2, 1, 12, 21, 10, 0, 11, 13, 15, 17, 19, 8, 7, 6, 5, 4, 3, 14, 16, 18, 20,␣
˓→9])
sage: G=graphs.HyperStarGraph(5,2)
sage: fh(G,find_path=False)
(False, ['00110', '10100', '01100', '11000', '01010', '10010', '00011', '10001',
˓→'00101'])
sage: fh(G,find_path=True)
(False, ['01001', '10001', '00101', '10100', '00110', '10010', '01010', '11000',
˓→'01100'])
sage.graphs.generic_graph_pyx.int_to_binary_string(n)
A quick python int to binary string conversion.
INPUT:
• n (integer)
EXAMPLES:
sage: sage.graphs.generic_graph_pyx.int_to_binary_string(389)
'110000101'
sage: Integer(389).binary()
'110000101'
sage: sage.graphs.generic_graph_pyx.int_to_binary_string(2007)
'11111010111'
sage.graphs.generic_graph_pyx.layout_split(layout_function, G, **options)
Graph each component of G separately with layout_function, placing them adjacent to each other.
This is done because several layout methods need the input graph to be connected. For instance, on a disconnected
graph, the spring layout will push components further and further from each other without bound, resulting in
very tight clumps for each component.
Note: If the axis are scaled to fit the plot in a square, the horizontal distance may end up being “squished” due
to the several adjacent components.
EXAMPLES:
sage: G = graphs.DodecahedralGraph()
sage: for i in range(10): G.add_cycle(list(range(100*i, 100*i+3)))
sage: from sage.graphs.generic_graph_pyx import layout_split, spring_layout_fast
sage: D = layout_split(spring_layout_fast, G); D # random
{0: [0.77..., 0.06...],
...
902: [3.13..., 0.22...]}
AUTHOR:
Robert Bradshaw
sage.graphs.generic_graph_pyx.length_and_string_from_graph6(s)
Return a pair (length, graph6_string) from a graph6 string of unknown length.
This helper function is the inverse of 𝑁 from [McK2015].
INPUT:
• s – a graph6 string describing an binary vector (and encoding its length).
EXAMPLES:
˓→G_IA????_QO@EG???O??C?_?C@?G???@?_??AC?AO?a???O?????A?_Dw?H???__O@AAOAACd?_C??G?
˓→G@??GO?_???O@?_O??W??@P???AG??B?????G??GG???A??@?aC_G@A??O??_?A?????O@Z?_@M????
˓→GQ@_G@?C?')
sage: g6 = '_???C?@AA?_?A?O?C??S??O?q_?P?CHD??@?C?GC???C??GG?C_??O?COG?'
sage: g6 += '???I?J??Q??O?_@@??@??????'
sage: length_and_string_from_graph6(g6)
(32, '???C?@AA?_?A?O?C??S??O?q_?P?CHD??@?C?GC???C??GG?C_??O?COG????I?J??Q??O?_@@??@?
˓→?????')
sage.graphs.generic_graph_pyx.small_integer_to_graph6(n)
Encode a small integer (i.e. a number of vertices) as a graph6 string.
This helper function is named 𝑁 [McK2015].
INPUT:
• n (integer)
EXAMPLES:
sage: G = graphs.DodecahedralGraph()
sage: for i in range(10): G.add_cycle(list(range(100*i, 100*i+3)))
sage: from sage.graphs.generic_graph_pyx import spring_layout_fast
sage: pos = spring_layout_fast(G)
sage: pos[0] # random
[0.00..., 0.03...]
sage: sorted(pos.keys()) == sorted(G)
True
With split=True, each component of G is laid out separately, placing them adjacent to each other. This is done
because on a disconnected graph, the spring layout will push components further and further from each other
without bound, resulting in very tight clumps for each component.
If the axis are scaled to fit the plot in a square, the horizontal distance may end up being “squished” due to the
several adjacent components.
sage: G = graphs.DodecahedralGraph()
sage: for i in range(10): G.add_cycle(list(range(100*i, 100*i+3)))
sage: from sage.graphs.generic_graph_pyx import spring_layout_fast
sage: pos = spring_layout_fast(G, by_component = True)
sage: pos[0] # random
[2.21..., -0.00...]
sage: len(pos) == G.order()
True
sage.graphs.generic_graph_pyx.spring_layout_fast_split(G, **options)
Graph each component of G separately, placing them adjacent to each other.
In ticket trac ticket #29522 the function was modified so that it can work with any layout method and renamed
layout_split. Please use layout_split() from now on.
sage.graphs.generic_graph_pyx.transitive_reduction_acyclic(G)
Return the transitive reduction of an acyclic digraph.
INPUT:
• G – an acyclic digraph.
EXAMPLES:
5.39 Orientations
This module implements several methods to compute orientations of undirected graphs subject to specific constraints
(e.g., acyclic, strongly connected, etc.). It also implements some iterators over all these orientations.
This module contains the following methods
5.39.1 Authors
5.39.2 Methods
sage.graphs.orientations.random_orientation(G)
Return a random orientation of a graph 𝐺.
An orientation of an undirected graph is a directed graph such that every edge is assigned a direction. Hence
there are 2𝑚 oriented digraphs for a simple graph with 𝑚 edges.
INPUT:
• G – a Graph.
EXAMPLES:
See also:
• orientations()
• strong_orientation()
• strong_orientations_iterator()
• nauty_directg()
sage.graphs.orientations.strong_orientations_iterator(G)
Returns an iterator over all strong orientations of a graph 𝐺.
A strong orientation of a graph is an orientation of its edges such that the obtained digraph is strongly connected
(i.e. there exist a directed path between each pair of vertices).
ALGORITHM:
It is an adaptation of the algorithm published in [CGMRV16]. It runs in 𝑂(𝑚𝑛) amortized time, where 𝑚 is
the number of edges and 𝑛 is the number of vertices. The amortized time can be improved to 𝑂(𝑚) with a
more involved method. In this function, first the graph is preprocessed and a spanning tree is generated. Then
every orientation of the non-tree edges of the graph can be extended to at least one new strong orientation by
orienting properly the edges of the spanning tree (this property is proved in [CGMRV16]). Therefore, this func-
tion generates all partial orientations of the non-tree edges and then launches a helper function corresponding to
the generation algorithm described in [CGMRV16]. In order to avoid trivial symmetries, the orientation of an
arbitrary edge is fixed before the start of the enumeration process.
INPUT:
• G – an undirected graph.
OUTPUT:
• an iterator which will produce all strong orientations of this graph.
Note: Works only for simple graphs (no multiple edges). To avoid symmetries an orientation of an arbitrary
edge is fixed.
See also:
• orientations()
• strong_orientation()
• nauty_directg()
• random_orientation()
EXAMPLES:
A cycle has one possible (non-symmetric) strong orientation:
sage: g = graphs.CycleGraph(4)
sage: it = g.strong_orientations_iterator()
sage: len(list(it))
1
sage: g = graphs.RandomTree(100)
sage: len(list(g.strong_orientations_iterator()))
0
sage: g = graphs.CompleteGraph(6)
sage: g.add_vertex(7)
sage: len(list(g.strong_orientations_iterator()))
0
This module implements the connectivity based functions for graphs and digraphs. The methods in this module are also
available as part of GenericGraph, DiGraph or Graph classes as aliases, and these methods can be accessed through
this module or as class methods. Here is what the module can do:
For both directed and undirected graphs:
For DiGraph:
bridges() Returns an iterator over the bridges (or cut edges) of given undirected graph.
cleave() Return the connected subgraphs separated by the input vertex cut.
is_triconnected() Check whether the graph is triconnected.
spqr_tree() Return a SPQR-tree representing the triconnected components of the graph.
spqr_tree_to_graph() Return the graph represented by the SPQR-tree 𝑇 .
5.40.1 Methods
class sage.graphs.connectivity.TriconnectivitySPQR
Bases: object
Decompose a graph into triconnected components and build SPQR-tree.
This class implements the algorithm proposed by Hopcroft and Tarjan in [Hopcroft1973], and later corrected by
Gutwenger and Mutzel in [Gut2001], for finding the triconnected components of a biconnected graph. It then
organizes these components into a SPQR-tree. See the:wikipedia:𝑆𝑃 𝑄𝑅𝑡 𝑟𝑒𝑒.
A SPQR-tree is a tree data structure used to represent the triconnected components of a biconnected (multi)graph
and the 2-vertex cuts separating them. A node of a SPQR-tree, and the graph associated with it, can be one of
the following four types:
• "S" – the associated graph is a cycle with at least three vertices. "S" stands for series and is also called
a polygon.
• "P" – the associated graph is a dipole graph, a multigraph with two vertices and three or more edges. "P"
stands for parallel and the node is called a bond.
• "Q" – the associated graph has a single real edge. This trivial case is necessary to handle the graph that has
only one edge.
• "R" – the associated graph is a 3-vertex-connected graph that is not a cycle or dipole. "R" stands for rigid.
The edges of the tree indicate the 2-vertex cuts of the graph.
INPUT:
• G – graph; if G is a DiGraph , the computation is done on the underlying Graph (i.e., ignoring edge orien-
tation)
• check – boolean (default: True); indicates whether G needs to be tested for biconnectivity
See also:
• sage.graphs.connectivity.spqr_tree()
• is_biconnected()
• Wikipedia article SPQR_tree
EXAMPLES:
Example from the Wikipedia article SPQR_tree:
sage: G = Graph([(1, 2), (1, 4), (1, 8), (1, 12), (1, 13), (2, 3),
....: (2, 13), (3, 4), (3, 13), (4, 5), (4, 7), (5, 6), (5, 7), (5, 8),
....: (6, 7), (8, 9), (8, 11), (8, 12), (9, 10), (9, 11), (9, 12),
....: (10, 11), (10, 12)])
sage: tric = TriconnectivitySPQR(G)
sage: T = tric.get_spqr_tree()
sage: G.is_isomorphic(spqr_tree_to_graph(T))
True
sage: tric.print_triconnected_components()
Triconnected: [(8, 9, None), (9, 12, None), (9, 11, None), (8, 11, None), (10, 11,␣
˓→None), (9, 10, None), (10, 12, None), (8, 12, 'newVEdge0')]
Bond: [(8, 12, None), (8, 12, 'newVEdge0'), (8, 12, 'newVEdge1')]
Polygon: [(6, 7, None), (5, 6, None), (7, 5, 'newVEdge2')]
Bond: [(7, 5, 'newVEdge2'), (5, 7, 'newVEdge3'), (5, 7, None)]
Polygon: [(5, 7, 'newVEdge3'), (4, 7, None), (5, 4, 'newVEdge4')]
(continues on next page)
Triconnected: [(1, 2, None), (2, 13, None), (1, 13, None), (3, 13, None), (2, 3,␣
˓→None), (1, 3, 'newVEdge7')]
sage: G = Graph([(1, 2), (1, 4), (2, 3), (2, 5), (3, 4), (3, 5), (4, 5),
....: (4, 6), (5, 7), (5, 8), (5, 14), (6, 8), (7, 14), (8, 9), (8, 10),
....: (8, 11), (8, 12), (9, 10), (10, 13), (10, 14), (10, 15), (10, 16),
....: (11, 12), (11, 13), (12, 13), (14, 15), (14, 16), (15, 16)])
sage: T = TriconnectivitySPQR(G).get_spqr_tree()
sage: G.is_isomorphic(spqr_tree_to_graph(T))
True
sage: G = Graph([(1, 2), (1, 5), (1, 5), (2, 3), (2, 3), (3, 4), (4, 5)],␣
˓→multiedges=True)
sage: G = Graph([('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c',
˓→'d')])
sage: T = TriconnectivitySPQR(G).get_spqr_tree()
sage: print(T.vertices(sort=True))
[('R', Multi-graph on 4 vertices)]
sage: G.is_isomorphic(spqr_tree_to_graph(T))
True
sage: G = DiGraph([(1, 2), (2, 3), (3, 4), (4, 5), (1, 5), (5, 1)])
sage: tric = TriconnectivitySPQR(G)
sage: tric.print_triconnected_components()
Bond: [(1, 5, None), (5, 1, None), (1, 5, 'newVEdge0')]
Polygon: [(4, 5, None), (1, 5, 'newVEdge0'), (3, 4, None), (2, 3, None), (1, 2,␣
˓→None)]
get_spqr_tree()
Return an SPQR-tree representing the triconnected components of the graph.
An SPQR-tree is a tree data structure used to represent the triconnected components of a biconnected
(multi)graph and the 2-vertex cuts separating them. A node of a SPQR-tree, and the graph associated with
it, can be one of the following four types:
• "S" – the associated graph is a cycle with at least three vertices. "S" stands for series.
• "P" – the associated graph is a dipole graph, a multigraph with two vertices and three or more edges.
"P" stands for parallel.
• "Q" – the associated graph has a single real edge. This trivial case is necessary to handle the graph
that has only one edge.
• "R" – the associated graph is a 3-connected graph that is not a cycle or dipole. "R" stands for rigid.
The edges of the tree indicate the 2-vertex cuts of the graph.
OUTPUT:
SPQR-tree a tree whose vertices are labeled with the block’s type and the subgraph of three-blocks in the
decomposition.
EXAMPLES:
sage: G = Graph(2)
sage: for i in range(3):
....: G.add_path([0, G.add_vertex(), G.add_vertex(), 1])
sage: tric = TriconnectivitySPQR(G)
sage: Tree = tric.get_spqr_tree()
sage: C4 = graphs.CycleGraph(4)
sage: all(u[1].is_isomorphic(C4) for u in Tree if u[0] == 'S')
True
(continues on next page)
sage: G.allow_multiple_edges(True)
sage: G.add_edges(G.edge_iterator())
sage: tric = TriconnectivitySPQR(G)
sage: Tree = tric.get_spqr_tree()
sage: all(u[1].is_isomorphic(C4) for u in Tree if u[0] == 'S')
True
sage: G.is_isomorphic(spqr_tree_to_graph(Tree))
True
sage: G = graphs.CycleGraph(6)
sage: tric = TriconnectivitySPQR(G)
sage: Tree = tric.get_spqr_tree()
sage: Tree.order()
1
sage: G.is_isomorphic(spqr_tree_to_graph(Tree))
True
sage: G.add_edge(0, 3)
sage: tric = TriconnectivitySPQR(G)
sage: Tree = tric.get_spqr_tree()
sage: Tree.order()
3
sage: G.is_isomorphic(spqr_tree_to_graph(Tree))
True
get_triconnected_components()
Return the triconnected components as a list of tuples.
Each component is represented as a tuple of the type of the component and the list of edges of the compo-
nent.
EXAMPLES:
print_triconnected_components()
Print the type and list of edges of each component.
EXAMPLES:
An example from [Hopcroft1973]:
Bond: [(8, 12, None), (8, 12, 'newVEdge0'), (8, 12, 'newVEdge1')]
Polygon: [(6, 7, None), (5, 6, None), (7, 5, 'newVEdge2')]
Bond: [(7, 5, 'newVEdge2'), (5, 7, 'newVEdge3'), (5, 7, None)]
Polygon: [(5, 7, 'newVEdge3'), (4, 7, None), (5, 4, 'newVEdge4')]
Bond: [(5, 4, 'newVEdge4'), (4, 5, 'newVEdge5'), (4, 5, None)]
Polygon: [(4, 5, 'newVEdge5'), (5, 8, None), (1, 4, 'newVEdge9'), (1, 8,
˓→'newVEdge10')]
Triconnected: [(1, 2, None), (2, 13, None), (1, 13, None), (3, 13, None), (2, 3,
˓→ None), (1, 3, 'newVEdge7')]
ALGORITHM:
We implement the algorithm proposed by Tarjan in [Tarjan72]. The original version is recursive. We
emulate the recursion using a stack.
See also:
• blocks_and_cuts_tree()
• sage.graphs.base.boost_graph.blocks_and_cut_vertices()
• is_biconnected()
• bridges()
EXAMPLES:
We construct a trivial example of a graph with one cut vertex:
sage: blocks_and_cut_vertices(graphs.PetersenGraph())
([[0, 1, 4, 5, 2, 6, 3, 7, 8, 9]], [])
A disconnected graph:
sage: g = Graph({1: {2: 28, 3: 10}, 2: {1: 10, 3: 16}, 4: {}, 5: {6: 3, 7: 10, 8: 4}
˓→})
sage: blocks_and_cut_vertices(g)
([[1, 2, 3], [5, 6], [5, 7], [5, 8], [4]], [5])
sage.graphs.connectivity.blocks_and_cuts_tree(G)
Return the blocks-and-cuts tree of self.
This new graph has two different kinds of vertices, some representing the blocks (type B) and some other the cut
vertices of the graph (type C).
There is an edge between a vertex 𝑢 of type B and a vertex 𝑣 of type C if the cut-vertex corresponding to 𝑣 is in
the block corresponding to 𝑢.
The resulting graph is a tree, with the additional characteristic property that the distance between two leaves is
even. When self is not connected, the resulting graph is a forest.
When self is biconnected, the tree is reduced to a single node of type 𝐵.
We referred to [HarPri] and [Gallai] for blocks and cuts tree.
See also:
• blocks_and_cut_vertices()
• is_biconnected()
EXAMPLES:
sage: T = blocks_and_cuts_tree(graphs.RandomTree(40))
sage: T.is_tree()
True
sage: leaves = [v for v in T if T.degree(v) == 1]
sage: all(T.distance(u,v) % 2 == 0 for u in leaves for v in leaves)
True
sage: T = blocks_and_cuts_tree(graphs.PetersenGraph())
sage: T.vertices(sort=True)
[('B', (0, 1, 4, 5, 2, 6, 3, 7, 8, 9))]
sage.graphs.connectivity.bridges(G, labels=True)
Return an iterator over the bridges (or cut edges).
A bridge is an edge whose deletion disconnects the undirected graph. A disconnected graph has no bridge.
INPUT:
• labels – boolean (default: True); if False, each bridge is a tuple (𝑢, 𝑣) of vertices
EXAMPLES:
sage: g = graphs.RandomTree(100)
sage: sum(1 for _ in g.bridges()) == 99
True
sage: G.delete_edge(0, 1)
sage: S1,C1,f1 = cleave(G, cut_vertices=[0, 1])
sage: [g.order() for g in S1]
[4, 4, 4]
sage: C1.order(), C1.size()
(2, 3)
sage: f1.vertices(sort=True), f1.edges(sort=True)
([0, 1], [(0, 1, None)])
If virtual_edges == False and the cut vertices are not connected by an edge:
If 𝐺 is a biconnected multigraph:
sage: G = graphs.CompleteBipartiteGraph(2, 3)
sage: G.add_edge(2, 3)
sage: G.allow_multiple_edges(True)
sage: G.add_edges(G.edge_iterator())
sage: G.add_edges([(0, 1), (0, 1), (0, 1)])
sage: S,C,f = cleave(G, cut_vertices=[0, 1])
(continues on next page)
[(0, 1), (0, 1), (0, 1), (0, 4), (0, 4), (1, 4), (1, 4)]
sage.graphs.connectivity.connected_components(G, sort=True)
Return the list of connected components.
This returns a list of lists of vertices, each list representing a connected component. The list is ordered from
largest to smallest component.
INPUT:
• G – the input graph
• sort – boolean (default True); whether to sort vertices inside each component
EXAMPLES:
sage.graphs.connectivity.connected_components_number(G)
Return the number of connected components.
INPUT:
• G – the input graph
EXAMPLES:
sage.graphs.connectivity.connected_components_sizes(G)
Return the sizes of the connected components as a list.
The list is sorted from largest to lower values.
EXAMPLES:
sage.graphs.connectivity.connected_components_subgraphs(G)
Return a list of connected components as graph objects.
EXAMPLES:
Note: When the graph is a directed graph, this method actually computes the strong connectivity, (i.e. a directed
graph is strongly 𝑘-connected if there are 𝑘 disjoint paths between any two vertices 𝑢, 𝑣). If you do not want to
consider strong connectivity, the best is probably to convert your DiGraph object to a Graph object, and compute
the connectivity of this other graph.
INPUT:
• G – the input Sage (Di)Graph
• value_only – boolean (default: True)
– When set to True (default), only the value is returned.
– When set to False, both the value and a minimum vertex cut are returned.
• implementation – string (default: None); selects an implementation:
– None (default) – selects the best implementation available
– "boost" – use the Boost graph library (which is much more efficient). It is not available when
edge_labels=True, and it is unreliable for directed graphs (see trac ticket #18753).
The edge connectivity of a complete graph is its minimum degree, and one of the two parts of the bipartition is
reduced to only one vertex. The graph of the cut edges is isomorphic to a Star graph:
sage: g = graphs.CompleteGraph(5)
sage: [ value, edges, [ setA, setB ]] = edge_connectivity(g,vertices=True)
sage: value
(continues on next page)
Even if obviously in any graph we know that the edge connectivity is less than the minimum degree of the graph:
sage: g = graphs.RandomGNP(10,.3)
sage: min(g.degree()) >= edge_connectivity(g)
True
If we build a tree then assign to its edges a random value, the minimum cut will be the edge with minimum value:
sage: l == minimum
True
When value_only=True and implementation="sage", this function is optimized for small connectivity
values and does not need to build a linear program.
It is the case for graphs which are not connected
sage: g = 2 * graphs.PetersenGraph()
sage: edge_connectivity(g, implementation="sage")
0.0
For directed graphs, the strong connectivity is tested through the dedicated function:
sage: g = digraphs.ButterflyGraph(3)
sage: edge_connectivity(g, implementation="sage")
0.0
We check that the result with Boost is the same as the result without Boost:
True
However, the Boost algorithm is not reliable if the input is directed (see trac ticket #18753):
sage: g = digraphs.Path(3)
sage: edge_connectivity(g)
0.0
sage: edge_connectivity(g, implementation="boost")
1
sage: g.add_edge(1, 0)
sage: edge_connectivity(g)
0.0
sage: edge_connectivity(g, implementation="boost")
0
sage.graphs.connectivity.is_connected(G)
Check whether the (di)graph is connected.
Note that in a graph, path connected is equivalent to connected.
INPUT:
• G – the input graph
See also:
• is_biconnected()
EXAMPLES:
• is_cut_edge(G, 1, 2, ‘label’ )
• is_cut_edge(G, (1, 2, ‘label’) )
OUTPUT:
• Returns True if (u,v) is a cut edge, False otherwise
EXAMPLES:
sage: G = graphs.CompleteGraph(4)
sage: G.add_edge((0,5,'silly'))
sage: is_cut_edge(G,(0,5,'silly'))
True
sage: G = Graph([[0,1],[0,2],[3,4],[4,5],[3,5]])
sage: is_cut_edge(G,(0,1))
True
sage: G = digraphs.Circuit(5)
sage: is_cut_edge(G,(0,1))
False
sage: G = graphs.CompleteGraph(6)
sage: is_cut_edge(G,(0,7))
Traceback (most recent call last):
...
ValueError: edge not in graph
sage.graphs.connectivity.is_cut_vertex(G, u, weak=False)
Check whether the input vertex is a cut-vertex.
A vertex is a cut-vertex if its removal from the (di)graph increases the number of (strongly) connected compo-
nents. Isolated vertices or leafs are not cut-vertices. This function works with simple graphs as well as graphs
with loops and multiple edges.
INPUT:
• G – a Sage (Di)Graph
• u – a vertex
• weak – boolean (default: False); whether the connectivity of directed graphs is to be taken in the weak
sense, that is ignoring edges orientations
OUTPUT:
Return True if u is a cut-vertex, and False otherwise.
EXAMPLES:
Giving a LollipopGraph(4,2), that is a complete graph with 4 vertices with a pending edge:
sage: G = graphs.CompleteGraph(4)
sage: is_cut_vertex(G, 7)
Traceback (most recent call last):
...
ValueError: vertex (7) is not a vertex of the graph
sage.graphs.connectivity.is_strongly_connected(G)
Check whether the current DiGraph is strongly connected.
EXAMPLES:
The circuit is obviously strongly connected:
sage.graphs.connectivity.is_triconnected(G)
Check whether the graph is triconnected.
A triconnected graph is a connected graph on 3 or more vertices that is not broken into disconnected pieces by
deleting any pair of vertices.
EXAMPLES:
The Petersen graph is triconnected:
sage: G = graphs.PetersenGraph()
sage: G.is_triconnected()
True
sage: G = graphs.Grid2dGraph(3, 3)
sage: G.is_triconnected()
False
sage: G = graphs.CycleGraph(3)
sage: G.is_triconnected()
True
Comparing different methods on random graphs that are not always triconnected:
sage: G = graphs.RandomBarabasiAlbert(50, 3)
sage: G.is_triconnected() == G.vertex_connectivity(k=3)
True
See also:
• is_connected()
• is_biconnected()
• spqr_tree()
• Wikipedia article SPQR_tree
This method decomposes a biconnected graph into cycles, cocycles, and 3-connected blocks summed over co-
cycles, and arranges them as a SPQR-tree. More precisely, it splits the graph at each of its 2-vertex cuts, giving
a unique decomposition into 3-connected blocks, cycles and cocycles. The cocycles are dipole graphs with one
edge per real edge between the included vertices and one additional (virtual) edge per connected component
resulting from deletion of the vertices in the cut. See the Wikipedia article SPQR_tree.
INPUT:
• G – the input graph
• algorithm – string (default: "Hopcroft_Tarjan"); the algorithm to use among:
– "Hopcroft_Tarjan" (default) – use the algorithm proposed by Hopcroft and Tarjan
in [Hopcroft1973] and later corrected by Gutwenger and Mutzel in [Gut2001]. See
TriconnectivitySPQR.
– "cleave" – using method cleave()
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver is
used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
OUTPUT: SPQR-tree a tree whose vertices are labeled with the block’s type and the subgraph of three-blocks
in the decomposition.
EXAMPLES:
sage: G = Graph(2)
sage: for i in range(3):
....: G.add_path([0, G.add_vertex(), G.add_vertex(), 1])
sage: Tree = spqr_tree(G)
sage: Tree.order()
4
sage: C4 = graphs.CycleGraph(4)
sage: all(u[1].is_isomorphic(C4) for u in Tree if u[0] == 'S')
True
sage: G.is_isomorphic(spqr_tree_to_graph(Tree))
True
sage: G = graphs.CycleGraph(6)
sage: Tree = spqr_tree(G)
sage: Tree.order()
1
sage: G.is_isomorphic(spqr_tree_to_graph(Tree))
True
sage: G.add_edge(0, 3)
sage: Tree = spqr_tree(G)
sage: Tree.order()
3
sage: G.is_isomorphic(spqr_tree_to_graph(Tree))
True
sage: G = Graph('LlCG{O@?GBoMw?')
sage: T = spqr_tree(G, algorithm="Hopcroft_Tarjan")
sage: G.is_isomorphic(spqr_tree_to_graph(T))
True
sage: T2 = spqr_tree(G, algorithm='cleave')
sage: G.is_isomorphic(spqr_tree_to_graph(T2))
True
sage.graphs.connectivity.spqr_tree_to_graph(T )
Return the graph represented by the SPQR-tree 𝑇 .
The main purpose of this method is to test spqr_tree().
INPUT:
• T – a SPQR tree as returned by spqr_tree().
OUTPUT: a (multi) graph
EXAMPLES:
Wikipedia article SPQR_tree reference paper example:
A small multigraph
sage: G = Graph([(0, 2), (0, 2), (1, 3), (2, 3)], multiedges=True)
sage: for i in range(3):
....: G.add_clique([0, 1, G.add_vertex(), G.add_vertex()])
sage: for i in range(3):
....: G.add_clique([2, 3, G.add_vertex(), G.add_vertex()])
sage: T = spqr_tree(G)
sage: H = spqr_tree_to_graph(T)
sage: H.is_isomorphic(G)
True
sage.graphs.connectivity.strong_articulation_points(G)
Return the strong articulation points of this digraph.
A vertex is a strong articulation point if its deletion increases the number of strongly connected components.
This method implements the algorithm described in [ILS2012]. The time complexity is dominated by the time
complexity of the immediate dominators finding algorithm.
OUTPUT: The list of strong articulation points.
EXAMPLES:
Two cliques sharing a vertex:
sage: D = digraphs.Complete(4) * 2
sage: D.add_edges([(0, 4), (7, 3)])
sage: sorted(strong_articulation_points(D))
[0, 3, 4, 7]
sage: D.add_edge(1, 5)
sage: sorted(strong_articulation_points(D))
[3, 7]
sage: D.add_edge(6, 2)
sage: strong_articulation_points(D)
[]
See also:
• strongly_connected_components()
• dominator_tree()
sage.graphs.connectivity.strongly_connected_component_containing_vertex(G, v)
Return the strongly connected component containing a given vertex
INPUT:
• G – the input DiGraph
• v – a vertex
EXAMPLES:
In the symmetric digraph of a graph, the strongly connected components are the connected components:
sage: g = graphs.PetersenGraph()
sage: d = DiGraph(g)
sage: strongly_connected_component_containing_vertex(d, 0)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sage: d.strongly_connected_component_containing_vertex(0)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sage: g = DiGraph([(0, 1), (1, 0), (1, 2), (2, 3), (3, 2)])
sage: strongly_connected_component_containing_vertex(g, 0)
[0, 1]
sage.graphs.connectivity.strongly_connected_components_digraph(G, keep_labels=False)
Return the digraph of the strongly connected components
The digraph of the strongly connected components of a graph 𝐺 has a vertex per strongly connected component
included in 𝐺. There is an edge from a component 𝐶1 to a component 𝐶2 if there is an edge in 𝐺 from a vertex
𝑢1 ∈ 𝐶1 to a vertex 𝑢2 ∈ 𝐶2 .
INPUT:
• G – the input DiGraph
• keep_labels – boolean (default: False); when keep_labels=True, the resulting digraph has an edge
from a component 𝐶𝑖 to a component 𝐶𝑗 for each edge in 𝐺 from a vertex 𝑢𝑖 ∈ 𝐶𝑖 to a vertex 𝑢𝑗 ∈ 𝐶𝑗 .
Hence the resulting digraph may have loops and multiple edges. However, edges in the result with same
source, target, and label are not duplicated (see examples below). When keep_labels=False, the return
digraph is simple, so without loops nor multiple edges, and edges are unlabelled.
EXAMPLES:
Such a digraph is always acyclic:
The vertices of the digraph of strongly connected components are exactly the strongly connected components:
sage: g = digraphs.ButterflyGraph(2)
sage: scc_digraph = strongly_connected_components_digraph(g)
sage: g.is_directed_acyclic()
True
sage: V_scc = list(scc_digraph)
sage: all(Set(scc) in V_scc for scc in g.strongly_connected_components())
True
The following digraph has three strongly connected components, and the digraph of those is a
TransitiveTournament():
sage: g = DiGraph({0: {1: "01", 2: "02", 3: "03"}, 1: {2: "12"}, 2:{1: "21", 3: "23
˓→"}})
By default, the labels are discarded, and the result has no loops nor multiple edges. If keep_labels is True,
then the labels are kept, and the result is a multi digraph, possibly with multiple edges and loops. However, edges
in the result with same source, target, and label are not duplicated (see the edges from 0 to the strongly connected
component {1, 2} below):
sage.graphs.connectivity.strongly_connected_components_subgraphs(G)
Return the strongly connected components as a list of subgraphs.
EXAMPLES:
In the symmetric digraph of a graph, the strongly connected components are the connected components:
sage: g = DiGraph([(0, 1), (1, 0), (1, 2), (2, 3), (3, 2)])
sage: strongly_connected_components_subgraphs(g)
[Subgraph of (): Digraph on 2 vertices, Subgraph of (): Digraph on 2 vertices]
Note:
• When the graph is directed, this method actually computes the strong connectivity, (i.e. a directed graph is
strongly 𝑘-connected if there are 𝑘 vertex disjoint paths between any two vertices 𝑢, 𝑣). If you do not want
to consider strong connectivity, the best is probably to convert your DiGraph object to a Graph object, and
compute the connectivity of this other graph.
• By convention, a complete graph on 𝑛 vertices is 𝑛 − 1 connected. In this case, no certificate can be given
as there is no pair of vertices split by a cut of order 𝑘 − 1. For this reason, the certificates returned in this
situation are empty.
INPUT:
• G – the input Sage (Di)Graph
• value_only – boolean (default: True)
– When set to True (default), only the value is returned.
– When set to False, both the value and a minimum vertex cut are returned.
• sets – boolean (default: False); whether to also return the two sets of vertices that are disconnected
by the cut (implies value_only=False)
• k – integer (default: None); when specified, check if the vertex connectivity of the (di)graph is larger or
equal to 𝑘. The method thus outputs a boolean only.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver is
used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
EXAMPLES:
A basic application on a PappusGraph:
In a grid, the vertex connectivity is equal to the minimum degree, in which case one of the two sets is of cardinality
1:
When value_only = True, this function is optimized for small connectivity values and does not need to build
a linear program.
It is the case for connected graphs which are not connected:
sage: g = 2 * graphs.PetersenGraph()
sage: vertex_connectivity(g)
0
sage: g = graphs.PathGraph(10)
sage: vertex_connectivity(g)
1
For directed graphs, the strong connectivity is tested through the dedicated function:
sage: g = digraphs.ButterflyGraph(3)
sage: vertex_connectivity(g)
0
sage: g = graphs.CompleteGraph(10)
sage: vertex_connectivity(g)
9
sage: g = DiGraph(graphs.CompleteGraph(10))
sage: vertex_connectivity(g)
9
When parameter k is set, we only check for the existence of a vertex cut of order at least k:
sage: g = graphs.PappusGraph()
sage: vertex_connectivity(g, k=3)
True
sage: vertex_connectivity(g, k=4)
False
This module implements methods for computing the edge-connectivity of graphs and digraphs. It also implements
methods to extract 𝑘 edge-disjoint spanning trees from a 2𝑘 edge-connected graph or a 𝑘 edge-connected digraph.
Todo:
• Add speedup methods proposed in [GKLP2021] for the edge connectivity
• Implement the tree-packing algorithms proposed in [Gabow1995] and [BHKP2008]
• Extend to digraphs with multiple edges
• Extend to weighted digraphs
class sage.graphs.edge_connectivity.GabowEdgeConnectivity
Bases: object
Gabow’s algorithm for finding the edge connectivity of digraphs.
This class implements the algorithm proposed in [Gabow1995] for finding the edge connectivity of a directed
graph and 𝑘 edge disjoint spanning trees if the digraph is 𝑘 edge connected.
Warning: Multiple edges are currently not supported. The current implementation act as if the digraph is
simple and so the return results might not be correct. We therefore raise an error if the digraph has multiple
edges.
INPUT:
• D – a DiGraph
EXAMPLES:
A random 𝑑-regular digraph is 𝑑-edge-connected:
G
edge_connectivity()
Return the edge connectivity of the digraph.
EXAMPLES:
edge_disjoint_spanning_trees()
Iterator over the edge disjoint spanning trees.
EXAMPLES:
5.42 Domination
This module implements methods related to the notion of domination in graphs, and more precisely:
EXAMPLES:
We compute the size of a minimum dominating set of the Petersen graph:
sage: g = graphs.PetersenGraph()
sage: g.dominating_set(value_only=True)
3
sage: g = graphs.StarGraph(5)
sage: list(g.minimal_dominating_sets())
[{0}, {1, 2, 3, 4, 5}]
sage: list(g.minimal_dominating_sets([0]))
[{0}, {1}, {2}, {3}, {4}, {5}]
sage: g = graphs.PathGraph(5)
sage: list(g.minimal_dominating_sets())
[{0, 2, 4}, {1, 4}, {0, 3}, {1, 3}]
5.42.1 Methods
∀𝑥 ∈ 𝐺, 𝑏𝑥 is a binary variable
INPUT:
• k – a non-negative integer (default: 1); the domination distance
• independent – boolean (default: False); when True, computes a minimum independent dominating set,
that is a minimum dominating set that is also an independent set (see also independent_set())
• total – boolean (default: False); when True, computes a total dominating set (see the See the Wikipedia
article Dominating_set)
• value_only – boolean (default: False); whether to only return the cardinality of the computed dominating
set, or to return its list of vertices (default)
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver is
used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
EXAMPLES:
A basic illustration on a PappusGraph:
sage: g = graphs.PappusGraph()
sage: g.dominating_set(value_only=True)
5
If we build a graph from two disjoint stars, then link their centers we will find a difference between the cardinality
of an independent set and a stable independent set:
sage: g = 2 * graphs.StarGraph(5)
sage: g.add_edge(0, 6)
sage: len(g.dominating_set())
2
sage: len(g.dominating_set(independent=True))
6
sage: G = graphs.PetersenGraph()
sage: G.dominating_set(total=True, value_only=True)
4
The dominating set is calculated for both the directed and undirected graphs (modification introduced in trac
ticket #17905):
sage: g = digraphs.Path(3)
sage: g.dominating_set(value_only=True)
2
sage: g = graphs.PathGraph(3)
sage: g.dominating_set(value_only=True)
1
sage: G = graphs.PetersenGraph()
sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)]
[10, 3, 1]
sage: G = graphs.PathGraph(5)
sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)]
[5, 2, 1]
sage: g = graphs.CycleGraph(5)
sage: g.is_dominating([0,1], [4, 2])
True
sage: g.is_dominating([0,1])
False
For a graph 𝐺 and sets 𝐷 and 𝑆 of vertices, we say that a vertex 𝑣 ∈ 𝐷 is redundant in 𝑆 if 𝑣 has no private
neighbor with respect to 𝐷 in 𝑆. In other words, there is no vertex in 𝑆 that is dominated by 𝑣 but not by 𝐷 ∖ {𝑣}.
INPUT:
• dom – iterable of vertices of G; where we look for redundant vertices.
• focus – iterable of vertices of G (default: None); if specified, this method checks instead whether dom has
a redundant vertex in focus.
Warning: The assumption is made that focus (if provided) does not contain repeated vertices.
EXAMPLES:
sage: G = graphs.CubeGraph(3)
sage: G.is_redundant(['000', '101'], ['011'])
True
sage: G.is_redundant(['000', '101'])
False
sage: G = graphs.ButterflyGraph()
sage: ll = list(G.minimal_dominating_sets())
sage: pp = [{0, 1}, {1, 3}, {0, 2}, {2, 3}, {4}]
sage: len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in pp)
True
sage: ll = list(G.minimal_dominating_sets([0,3]))
sage: pp = [{0}, {3}, {4}]
sage: len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in pp)
True
sage: ll = list(G.minimal_dominating_sets([4]))
sage: pp = [{4}, {0}, {1}, {2}, {3}]
sage: len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in pp)
True
sage: ll = list(graphs.PetersenGraph().minimal_dominating_sets())
sage: pp = [{0, 2, 6},
....: {0, 9, 3},
....: {0, 8, 7},
....: {1, 3, 7},
....: {1, 4, 5},
....: {8, 1, 9},
....: {8, 2, 4},
....: {9, 2, 5},
....: {3, 5, 6},
....: {4, 6, 7},
....: {0, 8, 2, 9},
....: {0, 3, 6, 7},
....: {1, 3, 5, 9},
....: {8, 1, 4, 7},
....: {2, 4, 5, 6},
....: {0, 1, 2, 3, 4},
....: {0, 1, 2, 5, 7},
....: {0, 1, 4, 6, 9},
....: {0, 1, 5, 6, 8},
....: {0, 8, 3, 4, 5},
....: {0, 9, 4, 5, 7},
....: {8, 1, 2, 3, 6},
....: {1, 2, 9, 6, 7},
....: {9, 2, 3, 4, 7},
....: {8, 2, 3, 5, 7},
....: {8, 9, 3, 4, 6},
....: {8, 9, 5, 6, 7}]
sage: len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in pp)
True
sage: g = graphs.PathGraph(5)
sage: list(g.private_neighbors(1, [1, 3, 4]))
[1, 0]
SIX
• Index
• Module Index
• Search Page
1219
Graph Theory, Release 9.7
[Lein] Tom Leinster, The magnitude of metric spaces. Doc. Math. 18 (2013), 857-905.
1221
Graph Theory, Release 9.7
1222 Bibliography
PYTHON MODULE INDEX
c sage.graphs.graph_database, 639
sage.combinat.designs.incidence_structures, sage.graphs.graph_decompositions.bandwidth,
924 1077
sage.graphs.graph_decompositions.clique_separators,
g 1103
sage.graphs.asteroidal_triples, 961 sage.graphs.graph_decompositions.cutwidth,
sage.graphs.base.boost_graph, 906 1079
sage.graphs.base.c_graph, 834 sage.graphs.graph_decompositions.graph_products,
sage.graphs.base.dense_graph, 879 1084
sage.graphs.base.graph_backends, 901 sage.graphs.graph_decompositions.modular_decomposition,
sage.graphs.base.overview, 833 1088
sage.graphs.base.sparse_graph, 871 sage.graphs.graph_decompositions.rankwidth,
sage.graphs.base.static_dense_graph, 884 1075
sage.graphs.base.static_sparse_backend, 894 sage.graphs.graph_decompositions.tree_decomposition,
sage.graphs.base.static_sparse_graph, 888 1054
sage.graphs.bipartite_graph, 433 sage.graphs.graph_decompositions.vertex_separation,
sage.graphs.centrality, 959 1062
sage.graphs.cliquer, 956 sage.graphs.graph_editor, 1139
sage.graphs.comparability, 965 sage.graphs.graph_generators, 457
sage.graphs.connectivity, 1184 sage.graphs.graph_generators_pyx, 639
sage.graphs.convexity_properties, 1108 sage.graphs.graph_input, 1144
sage.graphs.digraph, 385 sage.graphs.graph_latex, 1125
sage.graphs.digraph_generators, 624 sage.graphs.graph_list, 1140
sage.graphs.distances_all_pairs, 1114 sage.graphs.graph_plot, 1017
sage.graphs.domination, 1210 sage.graphs.graph_plot_js, 1051
sage.graphs.edge_connectivity, 1209 sage.graphs.hyperbolicity, 1149
sage.graphs.generators.basic, 737 sage.graphs.hypergraph_generators, 921
sage.graphs.generators.chessboard, 750 sage.graphs.independent_sets, 963
sage.graphs.generators.classical_geometries, sage.graphs.isgci, 823
690 sage.graphs.line_graph, 972
sage.graphs.generators.distance_regular, 676 sage.graphs.lovasz_theta, 1000
sage.graphs.generators.families, 700 sage.graphs.matchpoly, 994
sage.graphs.generators.intersection, 755 sage.graphs.orientations, 1182
sage.graphs.generators.platonic_solids, 761 sage.graphs.partial_cube, 1160
sage.graphs.generators.random, 764 sage.graphs.path_enumeration, 1162
sage.graphs.generators.smallgraphs, 780 sage.graphs.planarity, 1004
sage.graphs.generators.world_map, 821 sage.graphs.pq_trees, 987
sage.graphs.generic_graph, 1 sage.graphs.schnyder, 1001
sage.graphs.generic_graph_pyx, 1175 sage.graphs.spanning_tree, 976
sage.graphs.genus, 997 sage.graphs.strongly_regular_db, 653
sage.graphs.graph, 245 sage.graphs.traversals, 1005
sage.graphs.graph_coloring, 943 sage.graphs.trees, 993
1223
Graph Theory, Release 9.7
sage.graphs.tutte_polynomial, 1155
sage.graphs.views, 451
sage.graphs.weakly_chordal, 1111
1225
Graph Theory, Release 9.7
1226 Index
Graph Theory, Release 9.7
Index 1227
Graph Theory, Release 9.7
1228 Index
Graph Theory, Release 9.7
Index 1229
Graph Theory, Release 9.7
1230 Index
Graph Theory, Release 9.7
Index 1231
Graph Theory, Release 9.7
1232 Index
Graph Theory, Release 9.7
Index 1233
Graph Theory, Release 9.7
1234 Index
Graph Theory, Release 9.7
Index 1235
Graph Theory, Release 9.7
1236 Index
Graph Theory, Release 9.7
Index 1237
Graph Theory, Release 9.7
has_right_split() (sage.graphs.graph_decompositions.modular_decomposition.Node
HortonGraph() (sage.graphs.graph_generators.GraphGenerators
method), 1088 static method), 529
has_vertex() (sage.graphs.base.c_graph.CGraph HouseGraph() (in module
method), 844 sage.graphs.generators.basic), 746
has_vertex() (sage.graphs.base.c_graph.CGraphBackendHouseGraph() (sage.graphs.graph_generators.GraphGenerators
method), 858 static method), 530
has_vertex() (sage.graphs.base.graph_backends.GenericGraphBackend
HouseXGraph() (in module
method), 903 sage.graphs.generators.basic), 747
has_vertex() (sage.graphs.base.static_sparse_backend.StaticSparseBackend
HouseXGraph() (sage.graphs.graph_generators.GraphGenerators
method), 897 static method), 530
has_vertex() (sage.graphs.base.static_sparse_backend.StaticSparseCGraph
hull() (sage.graphs.convexity_properties.ConvexityProperties
method), 900 method), 1109
has_vertex() (sage.graphs.generic_graph.GenericGraph hull_number() (sage.graphs.convexity_properties.ConvexityProperties
method), 108 method), 1109
have_tkz_graph() (in module hyperbolicity() (in module
sage.graphs.graph_latex), 1139 sage.graphs.hyperbolicity), 1151
HeawoodGraph() (in module hyperbolicity() (sage.graphs.graph.Graph method),
sage.graphs.generators.smallgraphs), 799 311
HeawoodGraph() (sage.graphs.graph_generators.GraphGenerators
hyperbolicity_distribution() (in module
static method), 525 sage.graphs.hyperbolicity), 1154
HermitianFormsGraph() (in module HypergraphGenerators (class in
sage.graphs.generators.distance_regular), sage.graphs.hypergraph_generators), 921
681 HyperStarGraph() (in module
HermitianFormsGraph() sage.graphs.generators.families), 719
(sage.graphs.graph_generators.GraphGenerators HyperStarGraph() (sage.graphs.graph_generators.GraphGenerators
static method), 525 static method), 530
HerschelGraph() (in module
sage.graphs.generators.smallgraphs), 800 I
HerschelGraph() (sage.graphs.graph_generators.GraphGenerators
IcosahedralGraph() (in module
static method), 526 sage.graphs.generators.platonic_solids),
HexahedralGraph() (in module 762
sage.graphs.generators.platonic_solids), IcosahedralGraph() (sage.graphs.graph_generators.GraphGenerators
761 static method), 531
HexahedralGraph() (sage.graphs.graph_generators.GraphGenerators
IGraph() (in module sage.graphs.generators.families),
static method), 526 719
HigmanSimsGraph() (in module IGraph() (sage.graphs.graph_generators.GraphGenerators
sage.graphs.generators.smallgraphs), 800 static method), 531
HigmanSimsGraph() (sage.graphs.graph_generators.GraphGenerators
igraph_graph() (sage.graphs.generic_graph.GenericGraph
static method), 527 method), 109
HoffmanGraph() (in module ihara_zeta_function_inverse()
sage.graphs.generators.smallgraphs), 801 (sage.graphs.graph.Graph method), 314
HoffmanGraph() (sage.graphs.graph_generators.GraphGenerators
ImaseItoh() (sage.graphs.digraph_generators.DiGraphGenerators
static method), 528 method), 630
HoffmanSingletonGraph() (in module in_branchings() (sage.graphs.digraph.DiGraph
sage.graphs.generators.smallgraphs), 802 method), 409
HoffmanSingletonGraph() in_degree() (sage.graphs.base.c_graph.CGraphBackend
(sage.graphs.graph_generators.GraphGenerators method), 858
static method), 528 in_degree() (sage.graphs.base.graph_backends.GenericGraphBackend
HoltGraph() (in module method), 903
sage.graphs.generators.smallgraphs), 802 in_degree() (sage.graphs.base.sparse_graph.SparseGraph
HoltGraph() (sage.graphs.graph_generators.GraphGenerators method), 875
static method), 529 in_degree() (sage.graphs.base.static_sparse_backend.StaticSparseBacken
HortonGraph() (in module method), 898
sage.graphs.generators.smallgraphs), 803
1238 Index
Graph Theory, Release 9.7
in_degree() (sage.graphs.base.static_sparse_backend.StaticSparseCGraph
sage.graphs.generators.intersection), 755
method), 900 IntervalGraph() (sage.graphs.graph_generators.GraphGenerators
in_degree() (sage.graphs.digraph.DiGraph method), static method), 532
410 IoninKharaghani765Graph() (in module
in_degree_iterator() (sage.graphs.digraph.DiGraph sage.graphs.generators.smallgraphs), 803
method), 411 IoninKharaghani765Graph()
in_degree_sequence() (sage.graphs.digraph.DiGraph (sage.graphs.graph_generators.GraphGenerators
method), 411 static method), 533
in_neighbors() (sage.graphs.base.c_graph.CGraph is_affine_polar() (in module
method), 845 sage.graphs.strongly_regular_db), 665
in_neighbors() (sage.graphs.base.static_sparse_backend.StaticSparseCGraph
is_antipodal() (sage.graphs.graph.Graph method),
method), 900 317
incidence_graph() (sage.combinat.designs.incidence_structures.IncidenceStructure
is_aperiodic() (sage.graphs.digraph.DiGraph
method), 931 method), 412
incidence_matrix() (sage.combinat.designs.incidence_structures.IncidenceStructure
is_apex() (sage.graphs.graph.Graph method), 318
method), 931 is_arc_transitive() (sage.graphs.graph.Graph
incidence_matrix() (sage.graphs.generic_graph.GenericGraph method), 318
method), 111 is_asteroidal_triple_free() (in module
IncidenceStructure (class in sage.graphs.asteroidal_triples), 962
sage.combinat.designs.incidence_structures), is_asteroidal_triple_free()
925 (sage.graphs.graph.Graph method), 319
inclusion_digraph() is_berge_cyclic() (sage.combinat.designs.incidence_structures.Inciden
(sage.graphs.isgci.GraphClasses method), method), 932
829 is_biconnected() (sage.graphs.graph.Graph method),
inclusions() (sage.graphs.isgci.GraphClasses 320
method), 830 is_bipartite() (sage.graphs.bipartite_graph.BipartiteGraph
incoming_edge_iterator() method), 443
(sage.graphs.digraph.DiGraph method), is_bipartite() (sage.graphs.generic_graph.GenericGraph
411 method), 113
incoming_edges() (sage.graphs.digraph.DiGraph is_block_graph() (sage.graphs.graph.Graph method),
method), 412 320
independent_set() (sage.graphs.graph.Graph is_cactus() (sage.graphs.graph.Graph method), 321
method), 315 is_cartesian_product() (in module
independent_set_of_representatives() sage.graphs.graph_decompositions.graph_products),
(sage.graphs.graph.Graph method), 316 1087
IndependentSets (class in is_cartesian_product() (sage.graphs.graph.Graph
sage.graphs.independent_sets), 963 method), 321
induced_substructure() is_cayley() (sage.graphs.generic_graph.GenericGraph
(sage.combinat.designs.incidence_structures.IncidenceStructure
method), 114
method), 932 is_chordal() (sage.graphs.generic_graph.GenericGraph
int_to_binary_string() (in module method), 115
sage.graphs.generic_graph_pyx), 1179 is_circulant() (sage.graphs.generic_graph.GenericGraph
interactive_query() method), 117
(sage.graphs.graph_database.GraphDatabase is_circular_planar()
method), 644 (sage.graphs.generic_graph.GenericGraph
intersection_graph() method), 118
(sage.combinat.designs.incidence_structures.IncidenceStructure
is_circumscribable() (sage.graphs.graph.Graph
method), 932 method), 322
IntersectionGraph() (in module is_classical_parameters_graph() (in module
sage.graphs.generators.intersection), 755 sage.graphs.generators.distance_regular), 685
IntersectionGraph() is_clique() (sage.graphs.generic_graph.GenericGraph
(sage.graphs.graph_generators.GraphGenerators method), 119
static method), 532 is_cograph() (sage.graphs.graph.Graph method), 323
IntervalGraph() (in module is_comparability() (in module
Index 1239
Graph Theory, Release 9.7
1240 Index
Graph Theory, Release 9.7
Index 1241
Graph Theory, Release 9.7
1242 Index
Graph Theory, Release 9.7
Index 1243
Graph Theory, Release 9.7
1244 Index
Graph Theory, Release 9.7
Index 1245
Graph Theory, Release 9.7
1246 Index
Graph Theory, Release 9.7
Index 1247
Graph Theory, Release 9.7
1248 Index
Graph Theory, Release 9.7
sage.graphs.graph_decompositions.vertex_separation), (sage.graphs.connectivity.TriconnectivitySPQR
1068 method), 1189
pathwidth() (sage.graphs.graph.Graph method), 364 private_neighbors() (in module
perfect_matchings() sage.graphs.domination), 1216
(sage.graphs.bipartite_graph.BipartiteGraph private_neighbors() (sage.graphs.graph.Graph
method), 446 method), 366
perfect_matchings() (sage.graphs.graph.Graph project_left() (sage.graphs.bipartite_graph.BipartiteGraph
method), 365 method), 447
period() (sage.graphs.digraph.DiGraph method), 421 project_right() (sage.graphs.bipartite_graph.BipartiteGraph
periphery() (sage.graphs.digraph.DiGraph method), method), 447
422 pruned_tree() (in module
periphery() (sage.graphs.graph.Graph method), 366 sage.graphs.generators.random), 780
PerkelGraph() (in module pseudo_partition_graph() (in module
sage.graphs.generators.smallgraphs), 812 sage.graphs.generators.distance_regular),
PerkelGraph() (sage.graphs.graph_generators.GraphGenerators 688
static method), 558
PermutationGraph() (in module Q
sage.graphs.generators.intersection), 758 Q (class in sage.graphs.pq_trees), 991
PermutationGraph() (sage.graphs.graph_generators.GraphGenerators
quadrangulations() (sage.graphs.graph_generators.GraphGenerators
static method), 558 method), 615
permute_decomposition() (in module QueenGraph() (in module
sage.graphs.graph_decompositions.modular_decomposition), sage.graphs.generators.chessboard), 753
1099 QueenGraph() (sage.graphs.graph_generators.GraphGenerators
petersen_family() (in module static method), 561
sage.graphs.generators.families), 736 query() (sage.graphs.graph_database.GraphDatabase
petersen_family() (sage.graphs.graph_generators.GraphGenerators method), 645
static method), 610 query_iterator() (sage.graphs.graph_database.GraphQuery
PetersenGraph() (in module method), 649
sage.graphs.generators.smallgraphs), 812
R
PetersenGraph() (sage.graphs.graph_generators.GraphGenerators
static method), 560 radius() (sage.graphs.digraph.DiGraph method), 422
planar_dual() (sage.graphs.generic_graph.GenericGraphradius() (sage.graphs.graph.Graph method), 367
method), 179 radius_DHV() (in module
planar_graphs() (sage.graphs.graph_generators.GraphGenerators sage.graphs.base.boost_graph), 916
method), 611 radius_DHV() (in module
plantri_gen() (sage.graphs.graph_generators.GraphGenerators sage.graphs.distances_all_pairs), 1122
method), 613 random() (sage.graphs.graph_coloring.Test method),
plot() (sage.graphs.bipartite_graph.BipartiteGraph 944
method), 447 random_all_graph_colorings()
plot() (sage.graphs.generic_graph.GenericGraph (sage.graphs.graph_coloring.Test method),
method), 179 944
plot() (sage.graphs.graph_plot.GraphPlot method), random_edge() (sage.graphs.generic_graph.GenericGraph
1022 method), 186
plot3d() (sage.graphs.generic_graph.GenericGraph random_edge_iterator()
method), 184 (sage.graphs.generic_graph.GenericGraph
PoussinGraph() (in module method), 186
sage.graphs.generators.smallgraphs), 812 random_md_tree() (in module
PoussinGraph() (sage.graphs.graph_generators.GraphGenerators sage.graphs.graph_decompositions.modular_decomposition),
static method), 561 1100
PQ (class in sage.graphs.pq_trees), 989 random_orientation() (in module
print_md_tree() (in module sage.graphs.orientations), 1182
sage.graphs.graph_decompositions.modular_decomposition),
random_orientation() (sage.graphs.graph.Graph
1099 method), 368
print_triconnected_components()
Index 1249
Graph Theory, Release 9.7
1250 Index
Graph Theory, Release 9.7
Index 1251
Graph Theory, Release 9.7
1252 Index
Graph Theory, Release 9.7
Index 1253
Graph Theory, Release 9.7
1254 Index
Graph Theory, Release 9.7
Index 1255
Graph Theory, Release 9.7
1256 Index
Graph Theory, Release 9.7
Index 1257
Graph Theory, Release 9.7
1258 Index
Graph Theory, Release 9.7
W Y
WagnerGraph() (in module yen_k_shortest_simple_paths() (in module
sage.graphs.generators.smallgraphs), 819 sage.graphs.path_enumeration), 1173
WagnerGraph() (sage.graphs.graph_generators.GraphGenerators
static method), 596
WatkinsSnarkGraph() (in module
sage.graphs.generators.smallgraphs), 820
WatkinsSnarkGraph()
(sage.graphs.graph_generators.GraphGenerators
static method), 596
weighted() (sage.graphs.generic_graph.GenericGraph
method), 239
weighted_adjacency_matrix()
(sage.graphs.generic_graph.GenericGraph
method), 240
WellsGraph() (in module
sage.graphs.generators.smallgraphs), 820
WellsGraph() (sage.graphs.graph_generators.GraphGenerators
static method), 596
WheelGraph() (in module
sage.graphs.generators.families), 732
WheelGraph() (sage.graphs.graph_generators.GraphGenerators
static method), 597
width_of_cut_decomposition() (in module
sage.graphs.graph_decompositions.cutwidth),
1084
width_of_path_decomposition() (in module
sage.graphs.graph_decompositions.vertex_separation),
1074
width_of_tree_decomposition() (in module
sage.graphs.graph_decompositions.tree_decomposition),
1061
wiener_index() (in module
sage.graphs.base.boost_graph), 918
wiener_index() (in module
sage.graphs.distances_all_pairs), 1124
wiener_index() (sage.graphs.generic_graph.GenericGraph
method), 241
WienerArayaGraph() (in module
sage.graphs.generators.smallgraphs), 820
WienerArayaGraph() (sage.graphs.graph_generators.GraphGenerators
static method), 598
WindmillGraph() (in module
sage.graphs.generators.families), 733
Index 1259