Graphs in Sage Math
Graphs in Sage Math
Release 8.4
4 Hypergraphs 623
Bibliography 835
Index 845
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
Sage Reference Manual: Graph Theory, Release 8.4
Graph products:
Linear algebra:
Some metrics:
cluster_triangles() Return the number of triangles for 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.
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() Test whether the graph is planar.
is_circular_planar() Test whether the graph is circular planar (outerplanar)
is_regular() Return True if this graph is (𝑘-)regular.
is_chordal() Test whether the given graph is chordal.
is_bipartite() Test whether the given graph is bipartite.
is_circulant() Test 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() Test whether a set of vertices is a clique
is_cycle() Test whether self is a (directed) cycle graph.
is_independent_set() Test whether a set of vertices is an independent set
Test whether the digraph is transitively reduced.
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
subgraph_search() Return a copy of G in self.
subgraph_search_count() Return the number of labelled occurrences of G in self.
Return an iterator over the labelled copies of G in self.
subgraph_search_iterator()
Return the characteristic polynomial of the adjacency matrix of the (di)graph.
characteristic_polynomial()
genus() Return the minimal genus of the graph.
crossing_number() Return the minimum number of edge crossings needed to draw the graph.
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 # 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)
sage: G == H
False
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 with 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])
sage: G.edges()
[(1, 1, None)]
sage: G = Graph(loops=True)
sage: G.add_clique([1], loops=True)
sage: G.edges()
[(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 – a list of indices for 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()
[(0, 1, None), (1, 2, None), (2, 3, None), (3, 0, None)]
sage: G = Graph()
sage: G.add_edge((1,2), 'label')
sage: G.networkx_graph().adj # random output order
{'label': {(1, 2): None}, (1, 2): {'label': None}}
sage: G = Graph()
sage: G.add_edge((1,2), label="label")
sage: G.networkx_graph().adj # random output order
{1: {2: 'label'}, 2: {1: 'label'}}
sage: G = Graph()
sage: G.add_edge(1,2,'label')
sage: G.networkx_graph().adj # random output order
{1: {2: 'label'}, 2: {1: 'label'}}
The following syntax is supported, but note that you must use the label keyword:
sage: G = Graph()
sage: G.add_edge((1,2), label='label')
sage: G.edges()
[(1, 2, 'label')]
sage: G = Graph()
sage: G.add_edge((1,2), 'label')
sage: G.edges()
[('label', (1, 2), None)]
sage: G = Graph()
sage: G.add_edge(None, 4)
sage: G.vertices()
[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 – (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()
[(0, 1, None), (0, 2, 'label')]
sage: H = Graph()
sage: H.add_edges([(0,0)], loops=False); H.edges()
[]
sage: H.add_edges([(0,0)], loops=None); H.edges()
[]
sage: H.add_edges([(0,0)]); H.edges()
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()
[]
sage: H.add_edges([(0,0)], loops=None); H.edges()
(continues on next page)
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 - a list of indices for 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()
[(0, 1, None), (1, 2, None), (2, 3, None)]
add_vertex(name=None)
Creates an isolated vertex. If the vertex already exists, then nothing is done.
INPUT:
• name - Name of the new vertex. If no name is specified, then the vertex will be represented by the
least integer not already representing a vertex. Name must be an immutable object, and cannot be
None.
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 is 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 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 other-
wise.
EXAMPLES:
sage: G = Graph(d)
sage: G.add_vertices([10,11,12])
sage: G.vertices()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
sage: G.add_vertices(graphs.CycleGraph(25).vertices())
sage: G.vertices()
[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]
adjacency_matrix(sparse=None, vertices=None)
Returns the adjacency matrix of the (di)graph.
The matrix returned is over the integers. If a different ring is desired, use either the sage.matrix.
matrix0.Matrix.change_ring() method or the matrix() function.
INPUT:
• sparse - whether to represent with a sparse matrix
• vertices (list) – the ordering of the vertices defining how they should appear in the matrix. By
default, the ordering given by GenericGraph.vertices() is used.
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.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(vertices=[2,4,1,3,0])
[0 0 1 1 0]
[0 0 0 1 0]
[1 0 0 0 1]
[1 1 0 0 0]
[0 0 1 0 0]
all_paths(start, end)
Return the list of all paths between a pair of vertices.
If start is the same vertex as end, then [[start]] is returned – a list containing the 1-vertex, 0-edge
path “start”.
INPUT:
• start, a vertex of a graph – where to start
• end, a vertex of a graph – where to end
EXAMPLES:
allow_loops(new, check=True)
Change whether loops are permitted in the (di)graph
INPUT:
• new - boolean.
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
(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()
[]
sage: G = Graph(multiedges=True,sparse=True); G
Multi-graph on 0 vertices
sage: G.has_multiple_edges()
False
sage: G.allows_multiple_edges()
True
sage: G.add_edges([(0,1,1), (0,1,2), (0,1,3)])
sage: G.has_multiple_edges()
True
sage: G.multiple_edges(sort=True)
[(0, 1, 1), (0, 1, 2), (0, 1, 3)]
sage: G.allow_multiple_edges(False); G
Graph on 2 vertices
sage: G.has_multiple_edges()
False
sage: G.edges()
[(0, 1, 1)]
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()
[]
sage: D = DiGraph(loops=True); D
(continues on next page)
allows_multiple_edges()
Returns whether multiple edges are permitted in the (di)graph.
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()
True
sage: G.add_edges([(0,1)]*3)
sage: G.has_multiple_edges()
True
sage: G.multiple_edges()
[(0, 1, None), (0, 1, None), (0, 1, None)]
sage: G.allow_multiple_edges(False); G
Graph on 2 vertices
sage: G.has_multiple_edges()
False
sage: G.edges()
[(0, 1, None)]
sage: D = DiGraph(multiedges=True,sparse=True); D
Multi-digraph on 0 vertices
sage: D.has_multiple_edges()
False
sage: D.allows_multiple_edges()
True
sage: D.add_edges([(0,1)]*3)
sage: D.has_multiple_edges()
True
sage: D.multiple_edges()
[(0, 1, None), (0, 1, None), (0, 1, None)]
sage: D.allow_multiple_edges(False); D
Digraph on 2 vertices
sage: D.has_multiple_edges()
False
sage: D.edges()
[(0, 1, None)]
am(sparse=None, vertices=None)
Returns the adjacency matrix of the (di)graph.
The matrix returned is over the integers. If a different ring is desired, use either the sage.matrix.
matrix0.Matrix.change_ring() method or the matrix() function.
INPUT:
• sparse - whether to represent with a sparse matrix
• vertices (list) – the ordering of the vertices defining how they should appear in the matrix. By
default, the ordering given by GenericGraph.vertices() is used.
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.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]
(continues on next page)
sage: graphs.PathGraph(5).adjacency_matrix(vertices=[2,4,1,3,0])
[0 0 1 1 0]
[0 0 0 1 0]
[1 0 0 0 1]
[1 1 0 0 0]
[0 0 1 0 0]
antisymmetric()
Tests whether the graph is antisymmetric.
A graph represents an antisymmetric relation if there being a path from a vertex x to a vertex y implies that
there is not a path from y to x unless x=y.
A directed acyclic graph is antisymmetric. An undirected graph is never antisymmetric unless it is just a
union of isolated vertices.
sage: graphs.RandomGNP(20,0.5).antisymmetric()
False
sage: digraphs.RandomDirectedGNR(20,0.5).antisymmetric()
True
sage: D = graphs.DodecahedralGraph()
sage: G = D.automorphism_group()
sage: A5 = AlternatingGroup(5)
sage: Z2 = CyclicPermutationGroup(2)
sage: H = A5.direct_product(Z2)[0] #see documentation for direct_product to
˓→explain the [0]
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: 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()
Returns the average degree of the graph.
The average degree of a graph 𝐺 = (𝑉, 𝐸) is equal to \frac {2|E|}{|V|}.
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
sage: g = graphs.RandomGNP(20,.5)
sage: tree = Graph()
sage: tree.add_edges(g.min_spanning_tree())
sage: tree.average_degree() < 2
True
sage: g = graphs.RandomGNP(50,.8)
sage: g.average_degree() == 2*g.size()/g.order()
True
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
REFERENCE:
blocks_and_cut_vertices(G, algorithm=’Tarjan_Boost’)
Compute the blocks and cut vertices of the graph.
In the case of a digraph, this computation is done on the underlying graph.
A cut vertex is one whose deletion increases the number of connected components. A block is a maximal
induced subgraph which itself has no cut vertices. Two distinct blocks cannot overlap in more than a single
cut vertex.
INPUT:
• algorithm – The algorithm to use in computing the blocks and cut vertices of G. The following
algorithms are supported:
OUTPUT: (B, C), where B is a list of blocks - each is a list of vertices and the blocks are the corre-
sponding induced subgraphs - and C is a list of cut vertices.
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:
blocks_and_cuts_tree(G)
Returns 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 self (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]
(continues on next page)
sage: T = blocks_and_cuts_tree(graphs.PetersenGraph())
sage: T.vertices()
[('B', (0, 1, 4, 5, 2, 6, 3, 7, 8, 9))]
EXAMPLES:
By default, the edge direction of a digraph is respected, but this can be overridden by the
ignore_direction parameter:
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: list(D.breadth_first_search(0,distance=0))
[0]
sage: list(D.breadth_first_search(0,distance=1))
[0, 1, 2, 3]
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 back-
wards by setting neighbors to be the neighbors_in() function of the graph:
It is possible (trac ticket #16470) using the keyword report_distance to get pairs (vertex, distance)
encoding the distance to 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)]
A canonical graph is the representative graph of an isomorphism class by some canonization function 𝑐. If
𝐺 and 𝐻 are graphs, then 𝐺 ∼ = 𝑐(𝐺), and 𝑐(𝐺) == 𝑐(𝐻) if and only if 𝐺 ∼ = 𝐻.
See the Wikipedia article Graph_canonization for more information.
INPUT:
• partition – if given, the canonical label with respect to this set partition will be computed. The
default is the unit set partition.
• certificate – boolean (default: False). When set to True, a dictionary mapping from the
vertices of the (di)graph to its canonical label will also be returned.
• edge_labels – boolean (default: False). When set to True, allows only permutations respecting
edge labels.
• algorithm – a string (default: None). The algorithm to use; currently available:
– 'bliss': use the optional package bliss (http://www.tcs.tkk.fi/Software/bliss/index.html);
– 'sage': always use Sage’s implementation.
– None (default): use bliss when available and possible
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
the canonical graph instead of the canonical graph; only available when 'bliss' is explicitly set as
algorithm.
• verbosity – deprecated, does nothing
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()
(continues on next page)
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]
[1 0 0 0 0 1 1 0 0 0]
[1 0 1 0 1 0 0 0 0 0]
[1 1 0 1 0 0 0 0 0 0]
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)
Returns 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)
Returns 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 (refering 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
• weight_function (function) - 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.
• check_weight (boolean) - 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()
• 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,
4: 0.06969696969696969, 5: 0.06969696969696969,
6: 0.0606060606060606, 7: 0.0606060606060606,
8: 0.0606060606060606, 9: 0.0606060606060606,
10: 0.0606060606060606, 11: 0.0606060606060606}
sage: g.centrality_betweenness(normalized=False) # abs tol 1e-10
{0: 3.833333333333333, 1: 3.833333333333333, 2: 3.333333333333333,
3: 3.333333333333333, 4: 3.833333333333333, 5: 3.833333333333333,
6: 3.333333333333333, 7: 3.333333333333333, 8: 3.333333333333333,
9: 3.333333333333333, 10: 3.333333333333333,
11: 3.333333333333333}
sage: D = DiGraph({0:[1,2,3], 1:[2], 3:[0,1]})
sage: D.show(figsize=[2,2])
sage: D = D.to_undirected()
sage: D.show(figsize=[2,2])
sage: D.centrality_betweenness() # abs tol abs 1e-10
{0: 0.16666666666666666, 1: 0.16666666666666666, 2: 0.0, 3: 0.0}
𝑟(𝑣) − 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,’ [Borgatti95].
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) - if True, the edges in the graph are weighted; if False, all edges have
weight 1.
• algorithm (string) - 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.
• centrality_closeness_top_k()
• centrality_degree()
• centrality_betweenness()
REFERENCES:
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()
(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)
Returns 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 – (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)
Returns 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 – (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:
cluster_transitivity()
Returns the transitivity (fraction of transitive triangles) of the graph.
Transitivity is the fraction of all existing triangles and all connected triples (triads), 𝑇 = 3 ×
triangles/triads.
See also section “Clustering” in chapter “Algorithms” of [HSSNX].
EXAMPLES:
sage: (graphs.FruchtGraph()).cluster_transitivity()
0.25
cluster_triangles(nbunch=None, with_labels=False)
Returns the number of triangles for the set 𝑛𝑏𝑢𝑛𝑐ℎ of vertices as a dictionary keyed by vertex.
See also section “Clustering” in chapter “Algorithms” of [HSSNX].
INPUT:
• nbunch - The vertices to inspect. If nbunch=None, returns data for all vertices in the graph.
REFERENCE:
EXAMPLES:
sage: list((graphs.FruchtGraph()).cluster_triangles().values())
[1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0]
sage: (graphs.FruchtGraph()).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: (graphs.FruchtGraph()).cluster_triangles(nbunch=[0,1,2])
{0: 1, 1: 1, 2: 0}
clustering_average(implementation=None)
Returns the average clustering coefficient.
The clustering coefficient of a node(︀ 𝑖 )︀is the fraction of existing triangles containing node 𝑖 and 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 [HSSNX].
INPUT:
• implementation - 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}
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)
Returns 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 C1, C2 of the partition, the number
of edges from a vertex of C1 to C2 is the same, over all vertices in C1.
A partition P1 is finer than P2 (P2 is coarser than P1) if every cell of P1 is a subset of a cell of P2.
INPUT:
• partition - a list of lists
• sparse - (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()
sage: Pi = [verts[:1], verts[1:]]
sage: Pi
[['000'], ['001', '010', '011', '100', '101', '110', '111']]
sage: 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, 2), (0, 4)], [(2, 3), (3, 4)]]
sage: graphs.TetrahedralGraph().complement().size()
0
(continues on next page)
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 (generic_graph) – the input graph.
• sort – boolean (default True) whether to sort vertices inside each component
EXAMPLES:
connected_components_number(G)
Return the number of connected components.
INPUT:
• G (generic_graph) – 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:
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 – (default: False) boolean; whether to return (Di)Graph or list of vertices
EXAMPLES:
• G.contract_edge( 1, 2 )
• G.contract_edge( (1, 2) )
• G.contract_edge( [ (1, 2) ] )
• G.contract_edge( 1, 2, ‘label’ )
• G.contract_edge( (1, 2, ‘label’) )
• G.contract_edge( [ (1, 2, ‘label’) ] )
EXAMPLES:
sage: G = graphs.CompleteGraph(4)
sage: G.contract_edge((0,1)); G.edges()
[(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()
[(0, 2, None), (0, 2, None), (0, 3, None), (0, 3, None), (2, 3, None)]
sage: G.contract_edge((0,2)); G.edges()
[(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()
[(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()
[(0, 3, None), (0, 3, None), (0, 3, None)]
sage: G.contract_edges([(1,3),(2,3)]); G.edges()
[(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()
[(0, 0, None)]
sage: D = graphs.CompleteGraph(4).to_directed()
sage: D.allow_loops(True); D.allow_multiple_edges(True)
sage: D.contract_edges([(0,1),(1,0),(0,2)]); D.edges()
(continues on next page)
sage: G = graphs.CompleteGraph(4)
sage: G.allow_loops(True); G.allow_multiple_edges(True)
sage: for e in G.edges():
....: G.set_edge_label(e[0], e[1], (e[0] + e[1]))
sage: H = G.copy()
sage: G.contract_edges([(0,1), (0,2)]); G.edges()
[(0, 0, 3), (0, 3, 3), (0, 3, 4), (0, 3, 5)]
sage: H.contract_edges([(0,1,1), (0,2,3)]); H.edges()
[(0, 2, 2), (0, 2, 3), (0, 3, 3), (0, 3, 4), (2, 3, 5)]
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 implementation
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=Graph({0:[0,1,1,2]},loops=True,multiedges=True,sparse=True)
sage: g==copy(g)
True
sage: g=DiGraph({0:[0,1,1,2],1:[0,1]},loops=True,multiedges=True,sparse=True)
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(19)
sage: H = G.copy(implementation='c_graph')
sage: H == G; H is G
True
False
sage: G1 = G.copy(sparse=True)
sage: G1==G
True
sage: G1 is G
False
sage: G2 = copy(G)
sage: G2 is G
False
sage: G = graphs.CompleteGraph(5)
sage: H1 = G.copy(weighted=False)
(continues on next page)
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’)
Returns 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.
INPUT:
• output ('vertex' (default) or 'edge') – whether every cycle is given as a list of vertices or a
list of edges.
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, 2, 7, 5, 0], [8, 3, 2, 7, 5], [4, 3, 2, 7, 5, 0], [4, 9, 7, 5, 0], [8, 6,
˓→ 9, 7, 5], [1, 6, 9, 7, 5, 0]]
sage: g.cycle_basis(output='edge')
[[(1, 2, None), (2, 7, None), (7, 5, None), (5, 0, None),
(0, 1, None)], [(8, 3, None), (3, 2, None), (2, 7, None),
(7, 5, None), (5, 8, None)], [(4, 3, None), (3, 2, None),
(2, 7, None), (7, 5, None), (5, 0, None), (0, 4, None)],
[(4, 9, None), (9, 7, None), (7, 5, None), (5, 0, None),
(0, 4, None)], [(8, 6, None), (6, 9, None), (9, 7, None),
(7, 5, None), (5, 8, None)], [(1, 6, None), (6, 9, None),
(9, 7, None), (7, 5, None), (5, 0, None), (0, 1, None)]]
sage: g = graphs.RandomGNP(30,.4)
sage: basis = g.cycle_basis()
Building the space of (directed) edges over 𝑍/2𝑍. On the way, building a dictionary associating an 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), edge_space.basis() ) )
sage: for (u,v),vec in list(edge_vector.items()):
....: edge_vector[(v,u)] = vec
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)
Gives the degree (in + out for digraphs) of a vertex or of vertices.
INPUT:
• vertices - If vertices is a single vertex, returns the number of neighbors of vertex. If vertices is an
iterable container of vertices, returns a list of degrees. If vertices is None, same as listing all vertices.
• labels - see OUTPUT
OUTPUT: Single vertex- an integer. Multiple vertices- a list of integers. If labels is True, then returns a
dictionary mapping each vertex 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]
degree_histogram()
Return a list, whose ith entry is the frequency of degree i.
EXAMPLES:
sage: G = graphs.Grid2dGraph(9,12)
sage: G.degree_histogram()
[0, 0, 4, 34, 70]
sage: G = graphs.Grid2dGraph(9,12).to_directed()
sage: G.degree_histogram()
[0, 0, 0, 0, 4, 0, 34, 0, 70]
degree_iterator(vertices=None, labels=False)
Returns 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:
• labels (boolean) – if set to False (default) the method returns an iterator over degrees. Otherwise
it returns an iterator over tuples (vertex, degree).
• vertices - if specified, restrict to this subset.
EXAMPLES:
sage: G = graphs.Grid2dGraph(3,4)
sage: for i in G.degree_iterator():
....: print(i)
3
4
2
...
2
4
sage: for i in G.degree_iterator(labels=True):
....: print(i)
((0, 1), 3)
((1, 2), 4)
((0, 0), 2)
...
((0, 3), 2)
((1, 1), 4)
sage: D = graphs.Grid2dGraph(2,4).to_directed()
sage: for i in D.degree_iterator():
....: print(i)
6
6
...
4
6
sage: for i in D.degree_iterator(labels=True):
....: print(i)
((0, 1), 6)
((1, 2), 6)
...
((1, 0), 4)
((0, 2), 6)
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]
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()[:3]
sage: G.degree_to_cell('011', cell)
2
sage: G.degree_to_cell('111', cell)
0
sage: C = graphs.CompleteGraph(19).to_directed(sparse=True)
sage: C.size()
342
sage: C.delete_edge( 1, 2 )
sage: C.delete_edge( (3, 4) )
sage: C.delete_edges( [ (5, 6), (7, 8) ] )
delete_edges(edges)
Delete edges from an iterable container.
EXAMPLES:
delete_multiedge(u, v)
Deletes all edges from u and v.
EXAMPLES:
sage: G = Graph(multiedges=True,sparse=True)
sage: G.add_edges([(0,1), (0,1), (0,1), (1,2), (2,3)])
sage: G.edges()
[(0, 1, None), (0, 1, None), (0, 1, None), (1, 2, None), (2, 3, None)]
sage: G.delete_multiedge( 0, 1 )
(continues on next page)
sage: D = DiGraph(multiedges=True,sparse=True)
sage: D.add_edges([(0,1,1), (0,1,2), (0,1,3), (1,0,None), (1,2,None), (2,3,
˓→None)])
sage: D.edges()
[(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()
[(1, 0, None), (1, 2, None), (2, 3, None)]
delete_vertex(vertex, in_order=False)
Deletes vertex, removing all incident edges. Deleting a non-existent vertex will raise an exception.
INPUT:
• in_order - (default False) If True, this deletes the ith vertex in the sorted list of vertices, i.e.
G.vertices()[i]
EXAMPLES:
sage: G = Graph(graphs.WheelGraph(9))
sage: G.delete_vertex(0); G.show()
sage: D = DiGraph({0:[1,2,3,4,5],1:[2],2:[3],3:[4],4:[5],5:[1]})
sage: D.delete_vertex(0); D
Digraph on 5 vertices
sage: D.vertices()
[1, 2, 3, 4, 5]
sage: D.delete_vertex(0)
Traceback (most recent call last):
...
RuntimeError: Vertex (0) not in the graph.
sage: G = graphs.CompleteGraph(4).line_graph(labels=False)
sage: G.vertices()
[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
sage: G.delete_vertex(0, in_order=True)
sage: G.vertices()
[(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)
Remove vertices from the (di)graph taken from an iterable container of vertices. Deleting a non-existent
vertex will raise an exception.
EXAMPLES:
sage: D = DiGraph({0:[1,2,3,4,5],1:[2],2:[3],3:[4],4:[5],5:[1]})
sage: D.delete_vertices([1,2,3,4,5]); D
Digraph on 1 vertex
sage: D.vertices()
[0]
sage: D.delete_vertices([1])
Traceback (most recent call last):
...
RuntimeError: Vertex (1) not in the graph.
density()
Returns the density (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: 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: 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 back-
wards 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]
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
sage: g = graphs.GridGraph([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.GridGraph([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.
• 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()
[(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()
[0, 1, 2, 3, 4, 5, 6]
sage: (G+H).vertices() # '+'-operator is a shortcut
[0, 1, 2, 3, 4, 5, 6]
disjunctive_product(other)
Returns 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
distance(u, v, by_weight=False)
Returns the (directed) distance from u to v in the (di)graph, i.e. the length of the shortest path from u to v.
This method simply calls shortest_path_length(), with default arguments. For more information,
and for more option, we refer to that method.
INPUT:
• by_weight - if False, the graph is considered unweighted, and the distance is the number of edges
in a shortest path. If True, the distance is the sum of edge labels (which are assumed to be numbers).
EXAMPLES:
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)
– 'BFS' - the computation is done through a BFS centered on each vertex successively. Works
only if by_weight==False.
– 'Floyd-Warshall-Cython' - the Cython implementation of the Floyd-Warshall algorithm.
Works only if by_weight==False.
– 'Floyd-Warshall-Python' - the Python implementation of the Floyd-Warshall algorithm.
Works also with weighted graphs, even with negative weights (but no negative cycle is allowed).
– '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).
– None (default): Sage chooses the best algorithm: 'BFS' if by_weight is False,
'Dijkstra_Boost' if all weights are positive, 'Floyd-Warshall-Cython' otherwise.
• weight_function (function) - 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.
• check_weight (boolean) - if True, we check that the weight_function outputs a number for each
edge.
OUTPUT:
A doubly indexed dictionary
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: 1, 4: 2, 5: 2, 6: 2, 7: 1, 8: 2, 9: 2}, 3: {0: 2, 1: 2, 2: 1, 3: 0, 4:
˓→ 8: 1, 9: 2}, 6: {0: 2, 1: 1, 2: 2, 3: 2, 4: 2, 5: 2, 6: 0, 7: 2, 8: 1, 9:
˓→2: 2, 3: 2, 4: 1, 5: 2, 6: 1, 7: 1, 8: 2, 9: 0}}
sage: g = graphs.RandomGNP(20,.3)
sage: distances = g.distance_all_pairs()
sage: all([g.distance(0,v) == distances[0][v] for v in g])
True
See also:
• distance_matrix()
• shortest_path_all_pairs()
distance_graph(dist)
Returns 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 is a nonnegative integer or a list of nonnegative integers. 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)))
sage: H.is_isomorphic(graphs.CompleteGraph(n))
True
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]
AUTHOR:
Rob Beezer, 2009-11-25
distance_matrix()
Return the distance matrix of (di)graph.
The (di)graph is expected to be (strongly) connected.
The distance matrix of a (strongly) connected (di)graph is a matrix whose rows and columns are indexed
with the positions of the vertices of the (di)graph in the ordering G.vertices(). The intersection of a
row and a column contains the respective distance between the vertices indexed at these positions.
Note that even when the vertices are consecutive integers starting from one, usually the vertex is not equal
to it’s index.
EXAMPLES:
sage: G = graphs.CubeGraph(3)
(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 n is (−1)𝑛−1 (𝑛 − 1)2𝑛−2 :
True
See also:
distances_distribution(G)
Returns 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}
∀𝑥 ∈ 𝐺, 𝑏𝑥 is a binary variable
INPUT:
• independent – boolean (default: False). If independent=True, computes a minimum inde-
pendent dominating set.
• total – boolean (default: False). If total=True, computes a total dominating set.
• value_only – boolean (default: False)
– If True, only the cardinality of a minimum dominating set is returned.
– If False (default), a minimum dominating set is returned as the list of its 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.
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
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 = graphs.KrackhardtKiteGraph()
sage: G.eccentricity()
[4, 4, 4, 4, 4, 3, 3, 2, 3, 4]
sage: G.vertices()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sage: G.eccentricity(7)
2
sage: G.eccentricity([7,8,9])
[3, 4, 2]
sage: G.eccentricity([7,8,9], with_labels=True) == {8: 3, 9: 4, 7: 2}
True
sage: G = Graph( { 0 : [], 1 : [], 2 : [1] } )
sage: G.eccentricity()
[+Infinity, +Infinity, +Infinity]
sage: G = Graph({0:[]})
sage: G.eccentricity(with_labels=True)
{0: 0}
sage: G = Graph({0:[], 1:[]})
sage: G.eccentricity(with_labels=True)
{0: +Infinity, 1: +Infinity}
sage: G = Graph([(0,1,1), (1,2,1), (0,2,3)])
sage: G.eccentricity(algorithm = 'BFS')
[1, 1, 1]
sage: G.eccentricity(algorithm = 'Floyd-Warshall-Cython')
[1, 1, 1]
sage: G.eccentricity(by_weight = True, algorithm = 'Dijkstra_NetworkX')
[2, 1, 2]
sage: G.eccentricity(by_weight = True, algorithm = 'Dijkstra_Boost')
[2, 1, 2]
sage: G.eccentricity(by_weight = True, algorithm = 'Johnson_Boost')
[2, 1, 2]
(continues on next page)
[2, 1, 2]
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
sage: K = graphs.CompleteBipartiteGraph(9,3).to_directed()
sage: len(K.edge_boundary( [0,1,2,3,4,5,6,7,8], [9,10,11] ))
27
sage: K.size()
54
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 (generic_graph) - the input 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 edge cut are returned.
• implementation – selects an implementation:
– When set to None (default): selects the best implementation available.
– When set to "boost", we 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).
– When set to "Sage", we use Sage’s implementation.
• use_edge_labels – boolean (default: False)
– When set to True, computes a weighted minimum cut where each edge has a weight defined by
its label. (If an edge has no label, 1 is assumed.). Implies boost = False.
– When set to False, each edge has weight 1.
• vertices – boolean (default: False)
– When set to True, also returns the two sets of vertices that are disconnected by the cut. Implies
value_only=False.
• solver – (default: None) Specify a Linear Program (LP) solver to be used (ignored if
implementation='boost'). If set to None, the default one is used. For more infor-
mation 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:
A basic application on the PappusGraph:
The edge connectivity of a complete graph ( and of a random graph ) is its minimum degree, and one of
the two parts of the bipartition is reduced to only one vertex. The cutedges 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: g = graphs.RandomGNP(15,.5)
sage: tree = Graph()
sage: tree.add_edges(g.min_spanning_tree())
sage: for u,v in tree.edge_iterator(labels=None):
....: tree.set_edge_label(u,v,random())
sage: minimum = min([l for u,v,l in tree.edge_iterator()])
sage: [value, [(u,v,l)]] = edge_connectivity(tree, value_only=False, use_edge_
˓→labels=True)
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
sage: g = graphs.RandomGNP(15,.3)
sage: edge_connectivity(g) == edge_connectivity(g, implementation="sage")
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
A minimum edge cut between two vertices 𝑠 and 𝑡 of self is a set 𝐴 of edges of minimum weight such
that 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). When set to True, only the weight of a minimum cut is
returned. Otherwise, a list of edges of a minimum cut is also returned.
• use_edge_labels – boolean (default: False). When set to True, computes a weighted mini-
mum cut where each edge has a weight defined by its label (if an edge has no label, 1 is assumed).
Otherwise, each edge has weight 1.
• vertices – boolean (default: False). When set to True, returns 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 – algorithm to use:
– If algorithm = "FF", a Python implementation of the Ford-Fulkerson algorithm is used
– If algorithm = "LP", the flow 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 (default), we use LP if vertex_bound = True, otherwise, we use
igraph if it is available, FF if it is not available.
• 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: 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.PetersenGraph()
sage: g.edge_cut(0, 3, vertices=True)
[3, [(0, 1, None), (0, 4, None), (0, 5, None)], [[0], [1, 2, 3, 4, 5, 6, 7, 8,
˓→ 9]]]
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]]
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: g = digraphs.RandomDirectedGNP(28,.3) # reduced from 30 to 28, cf. #9584
sage: k = Integer(g.edge_connectivity())
sage: arborescences = g.edge_disjoint_spanning_trees(k) # long time (up to
˓→15s on sage.math, 2011)
sage: all([a.is_directed_acyclic() for a in arborescences]) # long time
True
sage: all([a.is_connected() for a in arborescences]) # long time
True
REFERENCES:
edge_iterator(vertices=None, labels=True, ignore_direction=False)
Returns an iterator over edges.
The iterator returned is over the edges incident with any vertex given in the parameter vertices. If the
graph is directed, iterates over edges going out only. If vertices is None, then returns an iterator over all
edges. If self is directed, returns outgoing edges only.
INPUT:
• vertices - (default: None) a vertex, a list of vertices or None
• labels - if False, each edge is a tuple (u,v) of vertices.
• ignore_direction - bool (default: False) - only applies to directed graphs. If True, searches
across edges in either direction.
EXAMPLES:
sage: G = graphs.TetrahedralGraph()
sage: list(G.edge_iterator(labels=False))
[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
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 edge labels.
EXAMPLES:
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: graphs.DodecahedralGraph().edges()
[(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)]
sage: graphs.DodecahedralGraph().edges(labels=False)
[(0, 1), (0, 10), (0, 19), (1, 2), (1, 8), (2, 3), (2, 6), (3, 4), (3, 19),
˓→(4, 5), (4, 17), (5, 6), (5, 15), (6, 7), (7, 8), (7, 14), (8, 9), (9, 10),
˓→(9, 13), (10, 11), (11, 12), (11, 18), (12, 13), (12, 16), (13, 14), (14,
sage: D = graphs.DodecahedralGraph().to_directed()
sage: D.edges()
[(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, None), (19, 0, None), (19, 3,
˓→2), (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(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():
....: 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')]
sage: G.edges(key=lambda x: x[2])
[(0, 1, 'F'), (1, 2, 'L'), (2, 3, 'R'), (0, 4, 'U'), (3, 4, 'X')]
eigenspaces(laplacian=False)
Returns the right eigenspaces of the adjacency matrix of the graph.
INPUT:
• laplacian - 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:
(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)
Returns the right eigenvectors of the adjacency matrix of the graph.
INPUT:
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), (-2, [
(1, -1, 1, -1, 1, -1, 1, -1)
], 1), (0, [
(1, 0, -1, 0, 1, 0, -1, 0),
(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:
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()
Returns 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()
[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]
sage: o=g.eulerian_orientation()
sage: o.in_degree()
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
sage: o.out_degree()
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
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.
INPUT:
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)],
[(3, 2), (2, 1), (1, 3)],
[(3, 0), (0, 2), (2, 3)],
[(3, 1), (1, 0), (0, 3)]]
sage: graphs.TetrahedralGraph().faces()
[[(0, 1), (1, 2), (2, 0)],
[(3, 2), (2, 1), (1, 3)],
[(3, 0), (0, 2), (2, 3)],
[(3, 1), (1, 0), (0, 3)]]
sage: graphs.PetersenGraph().faces()
Traceback (most recent call last):
...
ValueError: No embedding is provided and the graph is not planar.
• 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.
• constraint_generation (boolean) – whether to use constraint generation when solving the
Mixed Integer Linear Program (default: True).
ALGORITHMS:
(Constraints generation)
When the parameter constraint_generation is enabled (default) the following MILP formulation
is used to solve the problem:
∑︁
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 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
INPUT:
• x – Source vertex
• y – Sink vertex
• value_only – boolean (default: True)
– When set to True, only the value of a maximal flow is returned.
– When set to False, is returned a pair whose first element is the value of the maximum flow, and
whose second value is 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)
– When set to True, computes an optimal solution under the constraint that the flow going through
an edge has to be an integer.
• use_edge_labels – boolean (default: True)
– When set to True, computes a maximum flow where each edge has a capacity defined by its
label. (If an edge has no label, 1 is assumed.)
– When set to False, each edge has capacity 1.
Note: Even though the three different implementations are meant to return the same Flow values, they
can not 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: len(flow_graph.edges())
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: len(flow_graph.edges())
4
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
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 ulti-
mately 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.
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: K5 = graphs.CompleteGraph(5)
sage: G = K5.copy()
sage: s = 4
sage: for i in range(1,100):
....: k = K5.relabel(list(range(s,s+5)),inplace=False)
....: G.add_edges(k.edges())
....: s += 4
sage: G.genus()
100
get_embedding()
Returns the attribute _embedding if it exists.
_embedding is a dictionary organized with vertex labels as keys and a list of each vertex’s neighbors in
clockwise order.
Error-checked to insure valid embedding is returned.
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]}
get_pos(dim=2)
Returns the position dictionary, a dictionary specifying the coordinates of each vertex.
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),
...
9: (0.475..., 0.154...)}
get_vertex(vertex)
Retrieve the object associated with a given vertex.
INPUT:
• vertex - the given vertex
EXAMPLES:
sage: d[2]
Moebius-Kantor Graph: Graph on 16 vertices
sage: T = graphs.TetrahedralGraph()
sage: T.vertices()
[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()
Computes the girth of the graph. For directed graphs, computes the girth of the undirected graph.
The girth is the length of the shortest cycle in the graph. Graphs without cycles have infinite girth.
EXAMPLES:
sage: graphs.TetrahedralGraph().girth()
3
sage: graphs.CubeGraph(3).girth()
4
sage: graphs.PetersenGraph().girth()
5
sage: graphs.HeawoodGraph().girth()
6
sage: next(graphs.trees(9)).girth()
+Infinity
See also:
graphplot(**options)
Returns a GraphPlot object.
EXAMPLES:
Creating a graphplot object uses the same options as graph.plot():
sage: GP.plot()
Graphics object consisting of 26 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 26 graphics primitives
sage: GP.set_vertices(talk=True)
sage: GP.plot()
Graphics object consisting of 26 graphics primitives
the entire drawing of the cluster contained within a bounding rectangle. Note that, for good and bad,
cluster subgraphs are not part of the DOT language, but solely a syntactic convention adhered to by
certain of the layout engines.”
EXAMPLES:
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;
node_1 -- node_2;
node_2 -- node_3 [label="foo"];
}
node_0 -- node_1;
node_0 -- node_2;
node_1 -- node_2;
node_2 -- node_3 [label=" ", texlbl="$\text{\texttt{foo}}$"];
}
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;
}
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:
sage: D = DiGraph([[1,2]])
sage: print(D.graphviz_string(rankdir="up"))
digraph {
rankdir=BT
node_0 [label="1"];
node_1 [label="2"];
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”, “backward” (a boolean), “dot” (a string containing
a sequence of options in dot format), “label” (a string), “label_style” (“string” or “latex”), “edge_string”
(“–” or “->”). 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):
REFERENCES:
graphviz_to_file_named(filename, **options)
Write a representation in the dot 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:
node_0 -- node_1;
node_0 -- node_2;
node_1 -- node_2;
node_2 -- node_3 [label="foo"];
}
A graph (resp. digraph) is said to be Hamiltonian if it contains as a subgraph a cycle (resp. a circuit) going
through all the vertices.
Computing a Hamiltonian cycle/circuit being NP-Complete, this algorithm could run for some time de-
pending on the instance.
ALGORITHM:
See traveling_salesman_problem() for ‘tsp’ algorithm and find_hamiltonian() from
sage.graphs.generic_graph_pyx for ‘backtrack’ algorithm.
INPUT:
• algorithm – one of ‘tsp’ or ‘backtrack’.
• 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.
• constraint_generation (boolean) – 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 – whether to display which constraints are being generated.
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):
(continues on next page)
sage: G=graphs.HeawoodGraph()
sage: G.hamiltonian_cycle(algorithm='backtrack')
(True, [11, 10, 1, 2, 3, 4, 9, 8, 7, 6, 5, 0, 13, 12])
sage: G=graphs.PetersenGraph()
sage: G.hamiltonian_cycle(algorithm='backtrack')
(False, [6, 8, 5, 0, 1, 2, 7, 9, 4, 3])
sage: G=graphs.CubeGraph(3)
sage: G.hamiltonian_cycle(algorithm='backtrack')
(True, ['010', '110', '100', '000', '001', '101', '111', '011'])
• longest_path()
• hamiltonian_cycle()
INPUT:
• s – vertex (optional); if specified, then forces the source of the path (the method then returns a Hamil-
tonian path starting at s)
• t – vertex (optional); 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 the labels on the edges are to be consid-
ered as weights (a label set to None or {} being considered as a weight of 1)
• maximize – boolean (default: False); whether to compute a minimum (default) of a maxi-
mum (when maximize == True) weight hamiltonian path. This parameter is considered only
if use_edge_labels == True.
• algorithm – one of "MILP" (default) or "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 – (default: None) specify the 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
• verbose – integer (default: 0); sets the level of verbosity with 0 meaning quiet
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)
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()
(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()
[]
has_multiple_edges(to_undirected=False)
Returns 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()
True
sage: G.add_edges([(0,1)]*3)
sage: G.has_multiple_edges()
True
sage: G.multiple_edges()
[(0, 1, None), (0, 1, None), (0, 1, None)]
sage: G.allow_multiple_edges(False); G
Graph on 2 vertices
sage: G.has_multiple_edges()
(continues on next page)
sage: D = DiGraph(multiedges=True,sparse=True); D
Multi-digraph on 0 vertices
sage: D.has_multiple_edges()
False
sage: D.allows_multiple_edges()
True
sage: D.add_edges([(0,1)]*3)
sage: D.has_multiple_edges()
True
sage: D.multiple_edges()
[(0, 1, None), (0, 1, None), (0, 1, None)]
sage: D.allow_multiple_edges(False); D
Digraph on 2 vertices
sage: D.has_multiple_edges()
False
sage: D.edges()
[(0, 1, None)]
sage: g = Graph(loops=True,multiedges=True)
sage: g.add_edge(0,0)
sage: g.has_multiple_edges()
False
has_vertex(vertex)
Return True if vertex is one of the vertices of this graph.
INPUT:
• vertex - an integer
OUTPUT:
• bool - True or False
EXAMPLES:
igraph_graph(vertex_attrs={}, edge_attrs={})
Converts the graph into an igraph graph.
Optionally, it is possible to add vertex attributes and edge attributes to the output graph.
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_attrs (dictionary) - a dictionary where the key is a string (the attribute name), and the
value is an iterable containing in position i the label of the ith vertex returned by vertices() (see
http://igraph.org/python/doc/igraph.Graph-class.html#__init__ for more information).
• edge_attrs (dictionary) - a dictionary where the key is a string (the attribute name), and the
value is an iterable containing in position i the label of the ith 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 = Graph([(1,2,'a'),(2,3,'b')]) #
˓→optional - python_igraph
sage: H.es['label'] #
˓→optional - python_igraph
['a', 'b']
sage: G = Graph([(1,2,{'weight':1}),(2,3,{'weight':2})])
˓→ # optional - python_igraph
sage: H = G.igraph_graph(edge_attrs = {'weight':[e[2]['weight'] for e in G.
˓→edges()]}) # optional - python_igraph
sage: H.is_weighted()
˓→ # optional - python_igraph
True
sage: H.es['weight']
˓→ # optional - python_igraph
[1, 2]
sage: G = Graph([(0,1,2)])
˓→# optional - python_igraph
1.0
sage: H = G.igraph_graph(edge_attrs = {'capacity':[float(e[2]) for e in G.
˓→edges()]}) # optional - python_igraph
incidence_matrix(oriented=None, sparse=True)
Return the incidence matrix of the (di)graph.
Each row is a vertex, and each column is an edge. The vertices as ordered as obtained by the method
vertices() and the edges as obtained by the method edge_iterator().
If the graph is not directed, then return a matrix with entries in {0, 1, 2}. Each column will either contain
two 1 (at the position of the endpoint of the edge), or one 2 (if the corresponding edge is a loop).
If the graph is directed return a matrix in {−1, 0, 1} where −1 and +1 correspond respectively to the
source and the target of the edge. A loop will correspond to a zero column. In particular, it is not possible
to recover the loops of an oriented graph from its incidence matrix.
See the Wikipedia article Incidence_matrix for more information.
INPUT:
• oriented – an optional boolean. If set to True, the matrix will be oriented (i.e. with entries in −1,
0, 1) and if set to False the matrix will be not oriented (i.e. with entries in 0, 1, 2). By default, this
argument is inferred from the graph type. Note that in the case the graph is not directed and with the
option directed=True, a somewhat random direction is chosen for each edge.
• sparse – default to True, whether to use a sparse or a dense matrix.
EXAMPLES:
sage: G = graphs.CubeGraph(3)
sage: G.incidence_matrix()
[0 1 0 0 0 1 0 1 0 0 0 0]
[0 0 0 1 0 1 1 0 0 0 0 0]
[1 1 1 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 0 1 0 0 1 1]
[0 0 0 0 0 0 1 0 0 1 0 1]
[0 0 1 0 0 0 0 0 1 0 1 0]
[0 0 0 0 1 0 0 0 1 1 0 0]
sage: G.incidence_matrix(oriented=True)
[ 0 -1 0 0 0 -1 0 -1 0 0 0 0]
[ 0 0 0 -1 0 1 -1 0 0 0 0 0]
[-1 1 -1 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 0 1 0 0 -1 -1]
[ 0 0 0 0 0 0 1 0 0 -1 0 1]
[ 0 0 1 0 0 0 0 0 -1 0 1 0]
[ 0 0 0 0 1 0 0 0 1 1 0 0]
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
is_bipartite(certificate=False)
Returns True if graph 𝐺 is bipartite, False if not.
sage: graphs.CycleGraph(4).is_bipartite()
True
sage: graphs.CycleGraph(5).is_bipartite()
False
sage: graphs.RandomBipartite(100,100,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 packages gap_packages and
database_gap need to be installed: to do so, it is enough to run sage -i gap_packages
database_gap.
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.
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’)
Tests 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) [Fulkerson65].
(It can be seen that if 𝐺 contains an induced hole, then it can not 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) – 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 – Two algorithms are available for this method (see next section), which can be se-
lected by setting algorithm = "A" or algorithm = "B" (default). While they will agree on
whether the given graph is chordal, they can not 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 𝑂(𝑚) [Rose75] ( 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 = graphs.RandomLobster(10,.5,.5).lexicographic_product(graphs.
˓→CompleteGraph(3))
sage: g.is_chordal()
True
Let us check the certificate given by Sage is indeed a perfect elimination order:
sage: (_, peo) = g.is_chordal(certificate = True)
sage: for v in peo:
....: if not g.subgraph(g.neighbors(v)).is_clique():
....: print("This should never happen !")
....: g.delete_vertex(v)
REFERENCES:
is_circulant(certificate=False)
Tests whether the graph is circulant.
For more information, see Wikipedia article Circulant_graph.
INPUT:
• certificate (boolean) – whether to return a certificate for yes-answers. See OUTPUT section.
Set to False by default.
OUTPUT:
When certificate is set to False (default) this method only returns True or False answers.
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])])
With this information, it is very easy to create (and plot) all possible drawings of a circulant graph:
sage: g = graphs.CirculantGraph(13, [2, 3, 10, 11])
sage: for param in g.is_circulant(certificate = True)[1]:
....: graphs.CirculantGraph(*param)
Circulant graph ([2, 3, 10, 11]): Graph on 13 vertices
Circulant graph ([1, 5, 8, 12]): Graph on 13 vertices
Circulant graph ([4, 6, 7, 9]): Graph on 13 vertices
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
(continues on next page)
is_connected(G)
Test whether the (di)graph is connected.
Note that in a graph, path connected is equivalent to connected.
INPUT:
• G (generic_graph) – the input graph.
See also:
• is_biconnected()
EXAMPLES:
sage: from sage.graphs.connectivity import is_connected
sage: G = Graph( { 0 : [1, 2], 1 : [2], 3 : [4, 5], 4 : [5] } )
sage: is_connected(G)
False
sage: G.is_connected()
False
sage: G.add_edge(0,3)
sage: is_connected(G)
True
sage: D = DiGraph( { 0 : [1, 2], 1 : [2], 3 : [4, 5], 4 : [5] } )
sage: is_connected(D)
False
sage: D.add_edge(0,3)
sage: is_connected(D)
True
sage: D = DiGraph({1:[0], 2:[0]})
sage: is_connected(D)
True
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)
Returns True if 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 (generic_graph) - the input graph.
• u – a vertex
• weak – (default: False) boolean set to 𝑇 𝑟𝑢𝑒 if the connectivity of directed graphs is to be taken in
the weak sense, that is ignoring edges orientations.
OUTPUT:
Returns 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(6)
sage: is_cut_vertex(G,7)
Traceback (most recent call last):
...
ValueError: The input vertex is not in the vertex set.
is_cycle(directed_cycle=True)
Test 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 – (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()
(continues on next page)
is_drawn_free_of_edge_crossings()
Returns True is the position dictionary for this graph is set and that position dictionary gives a planar
embedding.
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: D.set_planar_positions()
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
of edges from a vertex of C1 to C2 is the same, over all vertices in C1.
INPUT:
• partition - a list of lists
• quotient_matrix - (default False) if True, and the partition is equitable, returns a matrix over the
integers whose rows and columns represent cells of the partition, and whose i,j entry is the number of
vertices in cell j adjacent to each vertex in cell i (since the partition is equitable, this is well defined)
EXAMPLES:
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)
(continues on next page)
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)
Return true if the graph has a (closed) tour that visits each edge exactly once.
INPUT:
• path – 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
sage: graphs.CycleGraph(4).is_eulerian()
True
sage: g = DiGraph({0:[1,2], 1:[2]}); g.is_eulerian()
False
sage: g = DiGraph({0:[2], 1:[3], 2:[0,1], 3:[2]}); g.is_eulerian()
True
sage: g = DiGraph({0:[1], 1:[2], 2:[0], 3:[]}); g.is_eulerian()
True
sage: g = Graph([(1,2), (2,3), (3,1), (4,5), (5,6), (6,4)]); g.is_eulerian()
False
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 [erdos1978choos].
REFERENCES:
EXAMPLES:
A complete graph is, or course, a Gallai Tree:
sage: g = graphs.CompleteGraph(15)
sage: g.is_gallai_tree()
True
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()
Returns 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)
Returns True if the set vertices is an independent set, False if not. An independent set is a set of
vertices such that there is no edge between any two vertices.
INPUT:
• vertices - Vertices can be a single vertex or an iterable container of vertices, e.g. a list, set, graph,
file or numeric array. If not passed, defaults to the entire graph.
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) – The function returns True or False according to the graph when
certificate=False (default). When certificate=True it 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:
• either a boolean or, if certificate is True, a tuple consisting of a boolean and a map or None
EXAMPLES:
Graphs:
sage: D = graphs.DodecahedralGraph()
sage: S = SymmetricGroup(20)
sage: gamma = S.random_element()
sage: E = copy(D)
sage: E.relabel(gamma)
sage: a,b = D.is_isomorphic(E, certificate=True); a
True
sage: from sage.plot.graphics import GraphicsArray
sage: from sage.graphs.generic_graph_pyx import spring_layout_fast
sage: position_D = spring_layout_fast(D)
sage: position_E = {}
sage: for vert in position_D:
....: position_E[b[vert]] = position_D[vert]
sage: GraphicsArray([D.plot(pos=position_D), E.plot(pos=position_E)]).show()
˓→# long time
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:
See also:
INPUT:
• kuratowski - returns 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.
• on_embedding - the embedding dictionary to test planarity on. (i.e.: will return True or False
only for the given embedding.)
• set_embedding - whether or not 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 - whether or not 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()
[0, 1, 2, 3, 4]
is_regular(k=None)
Return True if this graph is (𝑘-)regular.
INPUT:
• k (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:
The only self-complementary path graph is 𝑃4 :
sage: graphs.PathGraph(4).is_self_complementary()
True
sage: graphs.PathGraph(5).is_self_complementary()
False
is_subgraph(other, induced=True)
Return True if the graph is a subgraph of other, and False otherwise.
Warning: Please note that this method does not check whether self contains a subgraph isomorphic
to other, but only if it directly contains it as a subgraph !
By default induced is True for backwards compatibility.
INPUT:
• induced - boolean (default: True) If set to True tests 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.
OUTPUT:
boolean – True iff the graph is a (possibly induced) subgraph of other.
See also:
If you are interested in the (possibly induced) subgraphs isomorphic to the graph in other, you are
looking for 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() – Iterate over all the copies of other contained in the graph.
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: G = P.subgraph(list(range(6)))
sage: G.is_subgraph(P)
True
sage: H = graphs.CycleGraph(5)
sage: G = graphs.PathGraph(5)
(continues on next page)
is_transitively_reduced()
Tests whether the digraph is transitively reduced.
A digraph is transitively reduced if it is equal to its transitive reduction.
EXAMPLES:
sage: d = DiGraph({0:[1],1:[2],2:[3]})
sage: d.is_transitively_reduced()
True
sage: d = DiGraph({0:[1,2],1:[2]})
sage: d.is_transitively_reduced()
False
sage: d = DiGraph({0:[1,2],1:[2],2:[]})
sage: d.is_transitively_reduced()
False
sage: G = Graph({0:[1],1:[2]})
sage: G.is_vertex_transitive()
False
sage: P = graphs.PetersenGraph()
sage: P.is_vertex_transitive()
True
sage: D = graphs.DodecahedralGraph()
sage: D.is_vertex_transitive()
True
sage: R = graphs.RandomGNP(2000, .01)
sage: R.is_vertex_transitive()
False
– If True, the weighted adjacency matrix is used for 𝑀 , and the diagonal matrix 𝐷 takes into
account the weight of edges (replace in the definition “degree” by “sum of the incident edges”
).
– Else, each edge is assumed to have weight 1.
Default is to take weights into consideration if and only if the graph is weighted.
• indegree – Binary variable :
– If True, each diagonal entry of 𝐷 is equal to the in-degree of the corresponding vertex.
– Else, each diagonal entry of 𝐷 is equal to the out-degree of the corresponding vertex.
By default, indegree is set to True
( This variable only matters when the graph is a digraph )
• normalized – Binary variable :
– If True, the returned matrix is 𝐷−1/2 (𝐷 − 𝑀 )𝐷−1/2 , a normalized version of the Laplacian
matrix. (More accurately, the normalizing matrix used is equal to 𝐷−1/2 only for non-isolated
vertices. If vertex 𝑖 is isolated, then diagonal entry 𝑖 in the matrix is 1, rather than a division by
zero.)
– Else, the matrix 𝐷 − 𝑀 is returned
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
[ 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: Graph({0:[],1:[2]}).laplacian_matrix(normalized=True)
[ 0 0 0]
(continues on next page)
kronecker_product(other)
Returns 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 (refering 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
– If True, the weighted adjacency matrix is used for 𝑀 , and the diagonal matrix 𝐷 takes into
account the weight of edges (replace in the definition “degree” by “sum of the incident edges”
).
– Else, each edge is assumed to have weight 1.
Default is to take weights into consideration if and only if the graph is weighted.
• indegree – Binary variable :
– If True, each diagonal entry of 𝐷 is equal to the in-degree of the corresponding vertex.
– Else, each diagonal entry of 𝐷 is equal to the out-degree of the corresponding vertex.
By default, indegree is set to True
( This variable only matters when the graph is a digraph )
• normalized – Binary variable :
– If True, the returned matrix is 𝐷−1/2 (𝐷 − 𝑀 )𝐷−1/2 , a normalized version of the Laplacian
matrix. (More accurately, the normalizing matrix used is equal to 𝐷−1/2 only for non-isolated
vertices. If vertex 𝑖 is isolated, then diagonal entry 𝑖 in the matrix is 1, rather than a division by
zero.)
– Else, the matrix 𝐷 − 𝑀 is returned
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
[ 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: Graph({0:[],1:[2]}).laplacian_matrix(normalized=True)
[ 0 0 0]
(continues on next page)
latex_options()
Returns 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: g.layout()
{('0', 0): [2.69..., 0.43...],
('0', 1): [1.35..., 0.86...],
(continues on next page)
sage: g.layout(dim = 3)
{('0', 0): [0.68..., 0.50..., -0.24...],
('0', 1): [1.02..., -0.02..., 0.93...],
('1', 0): [2.06..., -0.49..., 0.23...],
('1', 1): [1.74..., 0.01..., -0.92...]}
˓→", "planar", "spring" (traditional spring layout, using the graph's current
option prog : Which graphviz layout program to use -- one of "circo", "dot",
˓→"fdp", "neato", or "twopi".
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'.
˓→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 𝑏𝑙𝑎ℎ, by implementing a method .layout_blah.
It may override the default layout by overriding layout_default(), and similarly override the prede-
fined 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_circular(dim=2, **options)
Computes a circular layout for this graph
OUTPUT: a dictionary mapping vertices to positions
EXAMPLES:
layout_default(by_component=True, **options)
Computes a spring layout for this graph
INPUT:
• iterations – a positive integer
• dim – 2 or 3 (default: 2)
OUTPUT: a dictionary mapping vertices to positions
Returns a layout computed by randomly arranging the vertices along the given heights
EXAMPLES:
layout_extend_randomly(pos, dim=2)
Extends randomly a partial layout
INPUT:
• pos: a dictionary mapping vertices to positions
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: H.layout_extend_randomly({('0',0): (0,0), ('1',1): (1,1)})
{('0', 0): (0, 0),
('0', 1): [0.0446..., 0.332...],
('1', 0): [0.111..., 0.514...],
('1', 1): (1, 1)}
sage: g = digraphs.ButterflyGraph(2)
sage: g.layout_graphviz() # optional - dot2tex graphviz
{('...', ...): [...,...],
('...', ...): [...,...],
('...', ...): [...,...],
('...', ...): [...,...],
('...', ...): [...,...],
('...', ...): [...,...],
('...', ...): [...,...],
('...', ...): [...,...],
('...', ...): [...,...],
('...', ...): [...,...],
('...', ...): [...,...],
('...', ...): [...,...]}
sage: g.plot(layout = "graphviz") # optional - dot2tex graphviz
Graphics object consisting of 29 graphics primitives
This requires graphviz and the dot2tex spkg. Here are some installation tips:
• Install graphviz >= 2.14 so that the programs dot, neato, . . . 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.
layout_spring(by_component=True, **options)
Computes a spring layout for this graph
INPUT:
• iterations – a positive integer
• dim – 2 or 3 (default: 2)
OUTPUT: a dictionary mapping vertices to positions
Returns a layout computed by randomly arranging the vertices along the given heights
EXAMPLES:
sage: G = graphs.HoffmanSingletonGraph()
sage: T = Graph()
(continues on next page)
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: G = graphs.RandomTree(80)
sage: G.plot(layout="tree", tree_orientation = "right")
Graphics object consisting of 160 graphics primitives
sage: T = Graph([[0,1],[0,6],[0,3],[1,2],[1,5],[3,4],[3,7],[3,8]])
sage: T.set_embedding({0:[1,6,3],1:[2,5,0],2:[1],3:[4,7,8,0],
....: 4:[3],5:[1],6:[0],7:[3],8:[3]})
sage: T.layout_tree()
{0: (2.166..., 0),
1: (3.5, -1),
2: (4.0, -2),
3: (1.0, -1),
4: (2.0, -2),
5: (3.0, -2),
6: (2.0, -1),
7: (1.0, -2),
8: (0.0, -2)}
sage: T.plot(layout="tree", tree_root=3)
Graphics object consisting of 18 graphics primitives
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.
This algorithm runs in time 𝑂(𝑛2 ) ( where 𝑛 is the number of vertices in the graph ), which is not optimal.
An optimal algorithm would run in time 𝑂(𝑚) ( where 𝑚 is the number of edges in the graph ), and require
the use of a doubly-linked list which are not available in python and can not really be written efficiently.
This could be done in Cython, though.
EXAMPLES:
A Lex BFS is obviously an ordering of the vertices:
sage: g = graphs.PetersenGraph()
sage: len(g.lex_BFS()) == g.order()
True
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
lexicographic_product(other)
Returns 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(labels=True)
Returns the line graph of the (di)graph.
INPUT:
• labels (boolean) – 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.
This is set to True by default.
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()
[(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()
[(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()
[(1, 2, None),
(1, 3, None),
(continues on next page)
Note: The length of a path is assumed to be the number of its edges, or the sum of their labels.
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: g.longest_path(algorithm="backtrack").edges(labels=False)
[(0, 1), (1, 2), (2, 3), (3, 4), (4, 9), (5, 7), (5, 8), (6, 8), (6, 9)]
Let us compute longest paths on random graphs with random weights. Each time, we ensure the resulting
graph is indeed a path:
loop_edges(labels=True)
Return a list of all loops in the (di)graph
INPUT:
• labels – 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()
[(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
Digraph on 1 vertex
sage: D.has_loops()
False
sage: D.edges()
[]
sage: G = graphs.PetersenGraph()
sage: G.loops()
[]
loop_vertices()
Return a list of vertices with loops
EXAMPLES:
sage: G = Graph({0 : [0], 1: [1,2,3], 2: [3]}, loops=True)
sage: G.loop_vertices()
[0, 1]
loops(labels=True)
Return a list of all loops in the (di)graph
INPUT:
• labels – 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()
[(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
Digraph on 1 vertex
sage: D.has_loops()
(continues on next page)
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
(continues on next page)
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()
[(0, 2, None)]
sage: P=graphs.PetersenGraph()
sage: P.merge_vertices([5,7])
sage: P.vertices()
[0, 1, 2, 3, 4, 5, 6, 8, 9]
sage: g=graphs.CycleGraph(5)
sage: g.vertices()
[0, 1, 2, 3, 4]
sage: g.merge_vertices([None, 1, 3])
sage: g.edges(labels=False)
[(0, 4), (0, 5), (2, 5), (4, 5)]
• sage.graphs.spanning_tree.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: g.min_spanning_tree(weight_function=weight)
[(0, 4, None), (1, 4, None), (2, 4, None), (3, 4, None)]
sage: g.min_spanning_tree(weight_function=weight, algorithm='Kruskal_Boost')
[(0, 4, None), (1, 4, None), (2, 4, None), (3, 4, None)]
sage: g = graphs.PetersenGraph()
sage: g.allow_multiple_edges(True)
sage: g.add_edges(g.edges())
sage: g.min_spanning_tree()
[(0, 1, None), (0, 4, None), (0, 5, None), (1, 2, None), (1, 6, None), (3, 8,
˓→None), (5, 7, None), (5, 8, None), (6, 9, None)]
Boruvka’s algorithm:
sage: g.min_spanning_tree(algorithm='Boruvka')
[(0, 1, None), (1, 2, None), (2, 3, None), (0, 4, None), (0, 5, None), (1, 6,
˓→None), (2, 7, None), (3, 8, None), (4, 9, None)]
Prim’s algorithm:
sage: g = graphs.CompleteGraph(5)
sage: g.min_spanning_tree(algorithm='Prim_edge', starting_vertex=2, weight_
˓→function=weight)
NetworkX algorithm:
sage: 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:
sage: g.weighted(True)
sage: g.min_spanning_tree()
[(1, 2, 1), (2, 3, 1)]
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 multiflow 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
INPUT:
• to_undirected – boolean (default False)
• labels – boolean (default True) whether to include labels
• sort - boolean (default False) whether to sort the result
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()
True
sage: G.add_edges([(0,1)]*3)
sage: G.has_multiple_edges()
True
sage: G.multiple_edges(sort=True)
[(0, 1, None), (0, 1, None), (0, 1, None)]
sage: G.allow_multiple_edges(False); G
Graph on 2 vertices
sage: G.has_multiple_edges()
False
sage: G.edges()
[(0, 1, None)]
sage: D = DiGraph(multiedges=True,sparse=True); D
Multi-digraph on 0 vertices
sage: D.has_multiple_edges()
False
sage: D.allows_multiple_edges()
True
sage: D.add_edges([(0,1)]*3)
sage: D.has_multiple_edges()
True
sage: D.multiple_edges(sort=True)
[(0, 1, None), (0, 1, None), (0, 1, None)]
sage: D.allow_multiple_edges(False); D
Digraph on 2 vertices
sage: D.has_multiple_edges()
False
sage: D.edges()
[(0, 1, None)]
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())
sage: set(C) == set(g.edges())
True
name(new=None)
Returns or sets the graph’s name.
INPUT:
• new - if not None, then this becomes the new name of the (di)graph. (if 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()
''
neighbor_iterator(vertex)
Return an iterator over neighbors of vertex.
EXAMPLES:
sage: G = graphs.CubeGraph(3)
sage: for i in G.neighbor_iterator('010'):
....: print(i)
011
000
110
sage: D = G.to_directed()
sage: for i in D.neighbor_iterator('010'):
....: print(i)
011
000
110
neighbors(vertex)
Return a list of neighbors (in and out if directed) of vertex.
G[vertex] also works.
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: sorted(P.neighbors(3))
[2, 4, 8]
sage: sorted(P[4])
[0, 3, 9]
networkx_graph(copy=True)
Creates a new NetworkX graph from the Sage graph.
INPUT:
• copy - if False, and the underlying implementation is a NetworkX graph, then the actual object itself
is returned.
EXAMPLES:
sage: G = graphs.TetrahedralGraph()
sage: N = G.networkx_graph()
sage: type(N)
<class 'networkx.classes.graph.Graph'>
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 – (default: None); Specify a Linear Program 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 of the LP solver, where 0 means quiet.
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]
(continues on next page)
num_edges()
Returns the number of edges.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.size()
15
num_faces(embedding=None)
Returns the number of faces of an embedded graph.
EXAMPLES:
sage: T = graphs.TetrahedralGraph()
sage: T.num_faces()
4
num_verts()
Returns the number of vertices. Note that len(G) returns the number of vertices in G also.
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:
sage: G = Graph(4, loops=True)
sage: G.add_edges( [ (0,0), (1,1), (2,2), (3,3), (2,3) ] )
sage: G.edges(labels=False)
[(0, 0), (1, 1), (2, 2), (2, 3), (3, 3)]
sage: G.number_of_loops()
4
order()
Returns the number of vertices. Note that len(G) returns the number of vertices in G also.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.order()
10
sage: G = graphs.TetrahedralGraph()
sage: len(G)
4
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]
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 - 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-
plot(**options)
Returns a graphics object representing the (di)graph.
INPUT:
• pos - an optional positioning dictionary
• layout - what 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 positions
– ‘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 - whether to print vertex labels
• edge_labels - whether to print edge labels. By default, False, but if True, the result of str(l) is
printed on the edge for each label l. 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 - whether to include a box around the graph
• vertex_colors - 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 - 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. if specified, plot will show each cell in a different color.
vertex_colors takes precedence.
• talk - if true, prints large vertices with white backgrounds so that labels are legible on slides
• iterations - 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 specified by a function or dictionary mapping labels to colors; this option is incompatible with
edge_color and edge_colors.
• heights - 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 of the tree to be used as the root for the layout=”tree” option. If no root is
specified, then one is chosen at random. Ignored unless layout=’tree’.
• tree_orientation - “up” or “down” (default is “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 - 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 mech-
anism. 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: pos_dict = {}
sage: for i in range(5):
....: x = float(cos(pi/2 + ((2*pi)/5)*i))
....: y = float(sin(pi/2 + ((2*pi)/5)*i))
....: pos_dict[i] = [x,y]
...
sage: for i in range(5, 10):
....: x = float(0.5*cos(pi/2 + ((2*pi)/5)*i))
....: y = float(0.5*sin(pi/2 + ((2*pi)/5)*i))
....: pos_dict[i] = [x,y]
...
sage: pl = P.plot(pos=pos_dict, vertex_colors=d)
sage: pl.show()
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():
....: 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:
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...),
5: (0.0..., 0.5...),
(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)
Graphics object consisting of 20 graphics primitives
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()
Graphics object consisting of 16 graphics primitives
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'))
(continues on next page)
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]})
– 'tachyon'
• xres - resolution
• yres - resolution
• **kwds - passed on to the rendering engine
EXAMPLES:
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):G.
˓→vertices()}, 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):G.vertices()}).show()
˓→# long time
sage: C = graphs.CubeGraph(4)
sage: C.plot3d(engine='tachyon', edge_colors={(0,1,0):C.edges()}, vertex_
˓→colors={(1,1,1):C.vertices()}, 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], 17: [18], 18:
sage: P = graphs.PetersenGraph().to_directed()
sage: from sage.plot.colors import rainbow
sage: edges = P.edges()
sage: R = rainbow(len(edges), 'rgbtuple')
sage: edge_colors = {}
sage: for i in range(len(edges)):
....: edge_colors[R[i]] = [edges[i]]
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()
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_edge(**kwds)
Returns 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 (𝑢, 𝑣):
sage: g.random_edge()
(3, 4, None)
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 that contains each vertex with prob. p.
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.random_subgraph(.25)
Subgraph of (Petersen graph): Graph on 4 vertices
random_vertex(**kwds)
Returns 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
sage: S = SymmetricGroup(3)
sage: gamma = S('(1,2)')
sage: G.relabel(gamma, inplace=False).am()
[0 0 1]
[0 0 1]
[1 1 0]
sage: G.edges()
[(0, 1, None), (1, 2, None)]
sage: H = G.relabel(lambda i: i+10, inplace=False)
sage: H.vertices()
[10, 11, 12]
sage: H.edges()
[(10, 11, None), (11, 12, None)]
sage: G.edges()
[(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()
[(0, 1, None), (1, 2, None)]
sage: G.relabel(lambda i: 0, check_input = False)
sage: G.edges()
[]
sage: G = graphs.CubeGraph(3)
sage: G.vertices()
['000', '001', '010', '011', '100', '101', '110', '111']
sage: G.relabel()
sage: G.vertices()
[0, 1, 2, 3, 4, 5, 6, 7]
sage: G = graphs.CubeGraph(3)
sage: expecting = {'000': 0, '001': 1, '010': 2, '011': 3, '100': 4, '101': 5,
˓→ '110': 6, '111': 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)
Removes loops on vertices in vertices. If vertices is None, removes all loops.
EXAMPLE
sage: G = Graph(4, loops=True)
sage: G.add_edges( [ (0,0), (1,1), (2,2), (3,3), (2,3) ] )
sage: G.edges(labels=False)
[(0, 0), (1, 1), (2, 2), (2, 3), (3, 3)]
sage: G.remove_loops()
sage: G.edges(labels=False)
[(2, 3)]
sage: G.allows_loops()
True
sage: G.has_loops()
False
remove_multiple_edges()
Removes all multiple edges, retaining one edge for each.
EXAMPLES:
sage: G = Graph(multiedges=True, sparse=True)
sage: G.add_edges( [ (0,1), (0,1), (0,1), (0,1), (1,2) ] )
sage: G.edges(labels=False)
[(0, 1), (0, 1), (0, 1), (0, 1), (1, 2)]
sage: G.remove_multiple_edges()
sage: G.edges(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():
....: G.set_edge_label(u,v,'(' + str(u) + ',' + str(v) + ')')
sage: G.edges()
[(0, 1, '(0,1)'),
(0, 5, '(0,5)'),
(0, 13, '(0,13)'),
...
(11, 12, '(11,12)'),
(12, 13, '(12,13)')]
set_embedding(embedding)
Sets a combinatorial embedding dictionary to _embedding attribute.
Dictionary is organized with vertex labels as keys and a list of each vertex’s neighbors in clockwise order.
Dictionary is error-checked for validity.
INPUT:
• embedding - a dictionary
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]})
set_latex_options(**kwds)
Sets 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_planar_positions(test=False, **layout_options)
Compute a planar layout for self using Schnyder’s algorithm, and save it as default layout.
EXAMPLES:
sage: g = graphs.CycleGraph(7)
sage: g.set_planar_positions(test=True)
True
sage: G = graphs.PetersenGraph()
sage: G.get_pos()
{0: (..., ...),
...
9: (..., ...)}
sage: G.set_pos('spam')
sage: P = G.plot()
Traceback (most recent call last):
...
TypeError: string indices must be integers...
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()
[0, 1, 2, 3]
sage: T.set_vertex(1, graphs.FlowerSnark())
sage: T.get_vertex(1)
Flower Snark: Graph on 20 vertices
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()
[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) - 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.
• check_weight (boolean) - if True, we check that the weight_function outputs a number 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)
– '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, 'Floyd-Warshall-Cython' otherwise.
• weight_function (function) - 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.
• check_weight (boolean) - if True, we check that the weight_function outputs a number for each
edge.
OUTPUT:
A tuple (dist, pred). They are both dicts of dicts. The first indicates the length dist[u][v]
of the shortest weighted path from 𝑢 to 𝑣. The second is a compact representation of all the paths - it
indicates the predecessor pred[u][v] of 𝑣 in the shortest path from 𝑢 to 𝑣. If the algorithm used is
Johnson_Boost, predecessors are not computed.
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 vari-
ables):
sage: G = Graph( { 0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2} },
˓→sparse=True)
˓→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},
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},
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.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)
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: d1 == d2 == d3 == d4 == d5 == d6
True
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: d1 == d2 == d3 == d4 == d5 == d6
True
Checking that weighted distances are equal regardless of the algorithm used:
sage: g = Graph()
sage: import random
sage: for v in range(5):
....: for w in range(5):
....: if v != w:
....: 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: d1 == d2 == d3 == d4
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}})
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
(continues on next page)
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) - 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.
• check_weight (boolean) - if True, we check that the weight_function outputs a number 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
sage: G = Graph({0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2}},
˓→sparse = True)
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
from u.
For more information on the input variables and more examples, we refer to shortest_paths() which
has the same input variables.
INPUT:
• u (vertex) - the starting vertex.
• by_weight (boolean) - if True, the edges in the graph are weighted; if False, all edges have
weight 1.
• algorithm (string) - one of the following algorithms:
– 'BFS': performs a BFS from u. Does not work with edge weights.
– 'Dijkstra_NetworkX': the Dijkstra algorithm, implemented in NetworkX (works only with
positive 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) - 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.
• check_weight (boolean) - if True, we check that the weight_function outputs a number 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)
{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):
...
ValueError: the graph contains a negative cycle
sage: g = graphs.Grid2dGraph(5,5)
sage: d1 = g.shortest_path_lengths((0,0), algorithm="BFS")
sage: d2 = g.shortest_path_lengths((0,0), algorithm="Dijkstra_NetworkX")
sage: d3 = g.shortest_path_lengths((0,0), algorithm="Dijkstra_Boost")
sage: d4 = g.shortest_path_lengths((0,0), algorithm="Bellman-Ford_Boost")
sage: d1 == d2 == d3 == d4
True
EXAMPLES:
Standard example:
sage: D = graphs.DodecahedralGraph()
sage: D.shortest_paths(0)
{0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 19, 3], 4: [0, 19, 3, 4], 5: [0, 1,
˓→2, 6, 5], 6: [0, 1, 2, 6], 7: [0, 1, 8, 7], 8: [0, 1, 8], 9: [0, 10, 9],
˓→10: [0, 10], 11: [0, 10, 11], 12: [0, 10, 11, 12], 13: [0, 10, 9, 13], 14:
˓→[0, 1, 8, 7, 14], 15: [0, 19, 18, 17, 16, 15], 16: [0, 19, 18, 17, 16], 17:
˓→[0, 19, 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)
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
show(method=’matplotlib’, **kwds)
Shows the (di)graph.
INPUT:
• method – set to "matplotlib" (default) to display the graph using matplotlib, or to "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)
• yres - resolution
• **kwds - passed on to the Tachyon command
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):G.vertices()}, bgcolor=(0,0,0), color_by_label=True,
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):G.vertices()}) # long
˓→time
sage: C = graphs.CubeGraph(4)
sage: C.show3d(engine='tachyon', edge_colors={(0,1,0):C.edges()}, vertex_
˓→colors={(1,1,1):C.vertices()}, 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()
Returns the number of edges.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.size()
15
spanning_trees_count(root_vertex=None)
Returns 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 – integer (default: the first vertex) This is the vertex that will be used as root for
all spanning out-trees if the graph is a directed graph. 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
sage: M=matrix(3,3,[0,1,0,0,0,1,1,1,0])
sage: D=DiGraph(M)
sage: D.spanning_trees_count()
1
sage: D.spanning_trees_count(0)
1
sage: D.spanning_trees_count(2)
2
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 sec-
ond 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)
(continues on next page)
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)
Returns a list of the eigenvalues of the adjacency matrix.
INPUT:
• laplacian - 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:
Definition :
Computing a minimum spanning tree in a graph can be done in 𝑛 log(𝑛) time (and in linear time if all
weights are equal) where 𝑛 = 𝑉 + 𝐸. On the other hand, if one is given a large (possibly weighted) graph
and a subset of its vertices, it is NP-Hard to find a tree of minimum weight connecting the given set of
vertices, which is then called a Steiner Tree.
See the Wikipedia article Steiner_tree_problem for more information.
INPUT:
• vertices – the vertices to be connected by the Steiner Tree.
• weighted (boolean) – Whether to consider the graph as weighted, and use each edge’s label as a
weight, considering None as a weight of 1. If weighted=False (default) all edges are considered
to have a weight of 1.
• 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:
• 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
sage: g = graphs.RandomGNP(30,.5)
sage: st = g.steiner_tree(g.vertices()[:5])
sage: st.is_tree()
True
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):
(continues on next page)
strong_product(other)
Returns 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)
Subdivides 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 = g.edges()[0]
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(sorted(g.edges()))
[(0, 1, 'label1'), (1, 2, 'label2')]
sage: g.subdivide_edge(0,1,"label1", 3)
sage: print(sorted(g.edges()))
[(0, 3, 'label1'), (1, 2, 'label2'), (1, 5, 'label1'), (3, 4, 'label1'), (4,
˓→5, 'label1')]
sage: g.subdivide_edge(1,2,"label2", 5)
sage: print(sorted(g.edges()))
[(0, 3, 'label1'), (1, 5, 'label1'), (1, 6, 'label2'), (2, 10, 'label2'), (3,
˓→4, 'label1'), (4, 5, 'label1'), (6, 7, 'label2'), (7, 8, 'label2'), (8, 9,
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:
sage: g.subdivide_edge(0,1,"fake_label",5)
Traceback (most recent call last):
...
ValueError: The given edge does not exist.
See also:
subdivide_edges(edges, k)
Subdivides k 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:
Let us check this by creating the graph we expect to have built through subdivision:
See also:
sage: D = graphs.CompleteGraph(9).to_directed()
sage: H = D.subgraph([0,1,2]); H
Subgraph of (Complete graph): Digraph on 3 vertices
sage: H = D.subgraph(edges=[(0,1), (0,2)])
sage: H.edges(labels=False)
[(0, 1), (0, 2)]
sage: H.vertices()==D.vertices()
True
sage: D
Complete graph: Digraph on 9 vertices
sage: D.subgraph([0,1,2], inplace=True); D
Subgraph of (Complete graph): Digraph on 3 vertices
sage: D.subgraph()==D
True
sage: P = graphs.PetersenGraph()
sage: S = P.subgraph(vertex_property = lambda v : v%2 == 0)
sage: S.vertices()
[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()
[('00', '01', None), ('00', '10', None), ('01', '11', None), ('10', '11',
˓→None)]
sage: S.edges()
[('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
sage: g = graphs.PathGraph(10)
sage: g.is_planar(set_embedding=True)
True
sage: g.set_vertices(dict((v, 'v%d'%v) for v in g.vertices()))
sage: h = g.subgraph([3..5])
sage: sorted(h.get_pos().keys())
[3, 4, 5]
sage: h.get_vertices()
{3: 'v3', 4: 'v4', 5: 'v5'}
subgraph_search(G, induced=False)
Returns 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: This method does not take vertex/edge labels into account.
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(); h1.edges(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(); I1.edges(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(); h2.edges(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(); I2.edges(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: This method does not take vertex/edge labels into account.
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
𝑖𝑗 ∈ 𝑇𝑘 iif 𝑖 < 𝑗, how many directed triangles can be found in 𝑇5 ? The answer is of course 0
sage: T5 = DiGraph()
sage: T5.add_edges([(i,j) for i in range(5) for j in range(i+1, 5)])
sage: T5.subgraph_search_count(digraphs.Circuit(3))
0
(︀5)︀
If we count instead the number of 𝑇3 in 𝑇5 , we expect the answer to be 3 :
sage: T3 = T5.subgraph([0,1,2])
sage: T5.subgraph_search_count(T3)
10
sage: binomial(5,3)
10
subgraph_search_iterator(G, induced=False)
Returns an iterator over the labelled copies of G in self.
INPUT:
• G – the graph whose copies we are looking for in self.
• induced – boolean (default: False). Whether or not to iterate over the induced copies of G in
self.
Note: This method does not take vertex/edge labels into account.
ALGORITHM:
See the documentation of SubgraphSearch.
OUTPUT:
Iterator over the labelled copies of G in self, as lists. 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: for p in g.subgraph_search_iterator(graphs.PathGraph(3)):
....: print(p)
[0, 1, 2]
[1, 2, 3]
[2, 1, 0]
(continues on next page)
szeged_index()
Returns the Szeged index of the graph.
For any 𝑢𝑣 ∈ 𝐸(𝐺), let 𝑁𝑢 (𝑢𝑣) = {𝑤 ∈ 𝐺 : 𝑑(𝑢, 𝑤) < 𝑑(𝑣, 𝑤)}, 𝑛𝑢 (𝑢𝑣) = |𝑁𝑢 (𝑢𝑣)|
∑︀
The Szeged index of a graph is then defined as [1]: 𝑢𝑣∈𝐸(𝐺) 𝑛𝑢 (𝑢𝑣) × 𝑛𝑣 (𝑢𝑣)
EXAMPLES:
True for any connected graph [1]:
sage: g=graphs.PetersenGraph()
sage: g.wiener_index()<= g.szeged_index()
True
sage: g=Graph()
sage: g.add_edges(graphs.CubeGraph(5).min_spanning_tree())
sage: g.wiener_index() == g.szeged_index()
True
REFERENCE:
[1] Klavzar S., Rajapakse A., Gutman I. (1996). The Szeged and the Wiener index of graphs. Applied
Mathematics Letters, 9 (5), pp. 45-49.
tensor_product(other)
Returns 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 (refering 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)
to_dictionary(edge_labels=False, multiple_edges=False)
Returns the graph as a dictionary.
INPUT:
• edge_labels (boolean) – whether to include edge labels in the output.
• multiple_edges (boolean) – 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 as-
sociating 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 as-
sociating 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 asso-
ciating 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},
(continues on next page)
sage: G = DiGraph(loops=True,multiedges=True,sparse=True)
sage: G.add_edges( [ (0,0,None), (1,1,None), (2,2,None), (2,3,1), (2,3,2), (3,
˓→2,None) ] )
sage: G.edges(labels=False)
[(0, 0), (1, 1), (2, 2), (2, 3), (2, 3), (3, 2)]
sage: H=G.to_simple()
sage: H.edges(labels=False)
[(2, 3)]
sage: H.is_directed()
False
sage: H.allows_loops()
False
sage: H.allows_multiple_edges()
False
sage: G.to_simple(to_undirected=False, keep_label='min').edges()
[(2, 3, 1), (3, 2, None)]
sage: G.to_simple(to_undirected=False, keep_label='max').edges()
[(2, 3, 2), (3, 2, None)]
transitive_closure()
Computes the transitive closure of a graph and returns it. The original graph is not modified.
The transitive closure of a graph G has an edge (x,y) if and only if there is a path between x and y in G.
The transitive closure of any strongly connected component of a graph is a complete graph. In particular,
the transitive closure of a connected undirected graph is a complete graph. The transitive closure of a
directed acyclic graph is a directed acyclic graph representing the full partial order.
EXAMPLES:
sage: g=graphs.PathGraph(4)
sage: g.transitive_closure()
Transitive closure of Path graph: Graph on 4 vertices
sage: g.transitive_closure()==graphs.CompleteGraph(4)
True
sage: g=DiGraph({0:[1,2], 1:[3], 2:[4,5]})
sage: g.transitive_closure().edges(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
transitive_reduction()
Returns a transitive reduction of a graph. The original graph is not modified.
A transitive reduction H of G has a path from x to y if and only if there was a path from x to y in G.
Deleting any edge of H 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: edges = g.transitive_reduction().edges(); len(edges)
4
sage: g = DiGraph({0:[1,2], 1:[2,3,4,5], 2:[4,5]})
sage: g.transitive_reduction().size()
5
• maximize – boolean (default: False). When set to True search for a Hamiltonian cycle
(res. circuit) of maximum weight instead of minimum weight. This parameter is used only when
use_edge_labels is 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.
• constraint_generation (boolean) – 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 – whether to display which constraints are being generated.
OUTPUT:
A solution to the TSP, as a Graph object whose vertex set is 𝑉 (𝐺), and whose edges are only those of the
solution.
ALGORITHM:
This optimization problem is solved through the use of Linear Programming.
Note: This function is correctly defined for both graph and digraphs. In the second case, the returned
cycle is a circuit of optimal cost.
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):
(continues on next page)
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)
Returns the number of triangles in the (di)graph.
For digraphs, we count the number of directed circuit of length 3.
INPUT:
• algorithm – (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
sage: G = graphs.PetersenGraph()
sage: G.triangles_count()
0
sage: G = graphs.CompleteGraph(150)
sage: G.triangles_count() == binomial(150,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)
Returns 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) – whether to create a mutable/immutable union. immutable=None (de-
fault) 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()
[0, 1, 2, 3]
(continues on next page)
vertex_boundary(vertices1, vertices2=None)
Returns 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 v are those vertices u with an arc (v, u).
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 (generic_graph) - the input 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)
– When set to True, also returns 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 – (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, see the method solve of
the class MixedIntegerLinearProgram. Use method sage.numerical.backends.
generic_backend.default_mip_solver() to know which default solver is used or to set
the default solver.
• verbose – integer (default: 0). Sets the level of verbosity. Set to 0 by default, which means quiet.
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
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]]
vertex_iterator(vertices=None)
Returns an iterator over the given vertices.
Returns False if not given a vertex, sequence, iterator or None. None is equivalent to a list of every vertex.
Note that for v in G syntax is allowed.
INPUT:
• vertices - iterated vertices are these intersected with the vertices of the (di)graph
EXAMPLES:
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
(continues on next page)
Note that since the intersection option is available, the vertex_iterator() function is sub-optimal, speed-
wise, but note the following optimization:
In other words, if you want a fast vertex iterator, call the dictionary directly.
vertices(key=None)
Return a list of the vertices.
INPUT:
• key - default: None - a function that takes a vertex as its one argument and returns a value that can
be used for comparisons in the sorting algorithm.
OUTPUT:
The vertices of the list.
Warning: There is always an attempt to sort the list before returning the result. However, since any
object may be a vertex, there is no guarantee that any two vertices will be comparable. 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 sort, use the key argument, as illustrated in the examples below.
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.vertices()
[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 alternatives. The moral is: if you want a fast vertex iterator, call the dictionary directly.
sage: H=graphs.HanoiTowerGraph(3,3,labels=False)
sage: H.vertices()
[0, 1, 2, 3, 4, ... 22, 23, 24, 25, 26]
(continues on next page)
sage: G=graphs.HanoiTowerGraph(3,3)
sage: G.vertices()
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), ... (2, 2, 1), (2, 2, 2)]
sage: G.vertices(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 (optional bool): 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
immutable 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()
False
sage: G == H
False
sage: H.weighted(True)
sage: G == H
False
weighted_adjacency_matrix(sparse=True)
Returns the weighted adjacency matrix of the graph.
Each vertex is represented by its position in the list returned by the vertices() function.
EXAMPLES:
* 'BFS' - the computation is done through a BFS centered on each vertex successively.
* 'Floyd-Warshall-Cython' - the Cython implementation of the Floyd-Warshall algo-
rithm. Usually slower than 'BFS'.
– For graphs without negative weights:
• weight_function (function) - 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.
• check_weight (boolean) - if True, we check that the weight_function outputs a number for each
edge.
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='Johnson_Boost')
15
sage: G.wiener_index(algorithm='Dijkstra_NetworkX')
15
sage.graphs.generic_graph.graph_isom_equivalent_non_edge_labeled_graph(g,
par-
ti-
tion=None,
stan-
dard_label=None,
re-
turn_relabeling=False,
re-
turn_edge_labels=False,
in-
place=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 la-
beled 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 edge is labeled with a dictionary
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 (bipartite) graph, whose left vertices are the original
vertices of the graph, and whose right vertices represent the edges. 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 bipartite graph.
INPUT:
• g – Graph or DiGraph
• partition – (default:None) if given, the partition of the vertices is as well relabeled
• standard_label – (default:None) the standard label is not considered to be changed
• return_relabeling – (default: False) if True, a dictionary containing the relabeling is returned
• return_edge_labels – (default: False) if True, the different edge_labels are returned (useful if in-
place is True)
• inplace – (default:False) if True, g is modified, otherwise the result is returned. Note that attributes of
g are not copied for speed issues, only edges and vertices.
OUTPUT:
• if not inplace: the unlabeled graph without multiple edges
• the partition of the vertices
• if return_relabeling: a dictionary containing the relabeling
• if return_edge_labels: the list of (former) edge labels is returned
EXAMPLES:
sage: from sage.graphs.generic_graph import graph_isom_equivalent_non_edge_
˓→labeled_graph
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: g = graph_isom_equivalent_non_edge_labeled_graph(G, partition=[[0,123],[1,
˓→2]]); g
sage: g = graph_isom_equivalent_non_edge_labeled_graph(G); g
[Graph on 6 vertices, [[0, 1, 2, 3], [4], [5]]]
sage: g[0].edges()
[(0, 4, None), (1, 4, None), (1, 5, None), (2, 3, None), (2, 5, None)]
sage: g = graph_isom_equivalent_non_edge_labeled_graph(G,standard_label='string',
˓→return_edge_labels=True); g
[Graph on 6 vertices, [[0, 1, 2, 3], [5], [4]], [[[None, 1]], [[0, 1], [1, 1], [2,
˓→ 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 1], [8, 1], [9, 1]], [['string', 1]]]]
sage: g[0].edges()
[(0, 4, None), (1, 2, None), (1, 4, None), (2, 5, None), (3, 5, None)]
sage: graph_isom_equivalent_non_edge_labeled_graph(G,inplace=True)
[[[0, 1, 2, 3], [4], [5]]]
sage: G.edges()
[(0, 4, None), (1, 4, None), (1, 5, None), (2, 3, None), (2, 5, None)]
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_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
Computes an orientation of self such that every vertex 𝑣 has out-degree less
bounded_outdegree_orientation()
than 𝑏(𝑣)
bridges() Returns a list of 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.
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() Returns a list of all spanning trees.
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
Graph properties
Leftovers
cores() Return the core number for each vertex in an ordered list.
Return the fractional chromatic index of the graph.
fractional_chromatic_index()
has_perfect_matching() Return whether this graph has a perfect matching.
Compute the inverse of the Ihara zeta function of the graph.
ihara_zeta_function_inverse()
Return the Kirchhoff-Symanzik polynomial of a graph.
kirchhoff_symanzik_polynomial()
lovasz_theta() Return the value of Lovász theta-function of graph
magnitude_function() Return the magnitude function of the graph as a rational function.
matching() Return a maximum weighted matching of the graph represented by the list of
its edges.
maximum_average_degree()Return the Maximum Average Degree (MAD) of the current graph.
modular_decomposition() Return the modular decomposition of the current graph.
perfect_matchings() Return an iterator over all perfect matchings of the graph.
Return the Seidel adjacency matrix of self.
seidel_adjacency_matrix()
seidel_switching() Return the Seidel switching of self w.r.t. subset of vertices s.
two_factor_petersen() Return a decomposition of the graph into 2-factors.
twograph() Return the two-graph of self
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
• Michael W. Hansen (2007-06-09): Topological sort generation
• Emily Kirkman, Robert L. Miller Sage Days 4: Finished wrapping NetworkX
• Emily Kirkman (2007-07-21): Genus (including circular planar, all embeddings and all planar embeddings), all
paths, interior paths
• Bobby Moretti (2007-08-12): fixed up plotting of graphs with edge colors differentiated by label
• Jason Grout (2007-09-25): Added functions, bug fixes, and general enhancements
• Robert L. Miller (Sage Days 7): Edge labeled graph isomorphism
• Tom Boothby (Sage Days 7): Miscellaneous awesomeness
• Tom Boothby (2008-01-09): Added graphviz output
• David Joyner (2009-2): Fixed docstring bug related to GAP.
• Stephen Hartke (2009-07-26): Fixed bug in blocks_and_cut_vertices() that caused an incorrect result when the
vertex 0 was a cut vertex.
• Stephen Hartke (2009-08-22): Fixed bug in blocks_and_cut_vertices() where the list of cut_vertices is not
treated as a set.
• Anders Jonsson (2009-10-10): Counting of spanning trees and out-trees added.
• Nathann Cohen (2009-09) [Cliquer, Connectivity, Flows] and everything that uses Linear Programming and
class numerical.MIP
• Nicolas M. Thiery (2010-02): graph layout code refactoring, dot2tex/graphviz interface
• David Coudert (2012-04) : Reduction rules in vertex_cover.
• Birk Eisermann (2012-06): added recognition of weakly chordal graphs and long-hole-free / long-
antihole-free graphs
• Alexandre P. Zuge (2013-07): added join operation.
• Amritanshu Prasad (2014-08): added clique polynomial
• Julian Rüth (2018-06-21): upgrade to NetworkX 2
Supported formats
Sage Graphs can be created from a wide range of inputs. A few examples are covered here.
• 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
Graph on 10 vertices
sage: G.plot().show() # or G.show()
• 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:
sage: import igraph # optional - python_igraph
sage: g = Graph(igraph.Graph([(1,3),(3,2),(0,2)])) # optional - python_igraph
sage: g # optional - python_igraph
Graph on 4 vertices
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
INPUT:
By default, a Graph object is simple (i.e. no loops nor multiple edges) and unweighted. This can be easily
tuned with the appropriate flags (see below).
• data – can be any of the following (see the format argument):
• pos - a positioning dictionary (cf. documentation of layout()). For example, to draw 4 vertices on a
square:
{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, whether to allow loops (ignored if data is an instance of the Graph class)
• multiedges - boolean, whether to allow multiple edges (ignored if data is an instance of the Graph
class).
• weighted - 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 possi-
bly 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) – 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) – 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 - 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()
[0, 1, 2, 3, 4]
sage: g.edges()
[]
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.
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(labels=false), \
lambda i,j: len(set(i).intersection(set(j)))>0], \
loops=False)
sage: line_graph.vertices()
[(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):
(continues on next page)
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
adjacency 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]
sage: Graph(M,sparse=True)
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]
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 = Graph([(1,3),(3,8),(5,2)])
sage: g
Graph on 5 vertices
sage: g.loops()
[(3, 3, '2')]
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() #
˓→optional - python_igraph
sage: Graph(g).vertices() #
˓→optional - python_igraph
[0, 1, 2]
If the igraph Graph has edge attributes, they are used as edge labels:
sage: Graph(g).edges()
˓→ # 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)`
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 – 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]
A 4 × 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: G.apex_vertices() == G.vertices()
True
sage: G.add_edges([('universal',v) for v in G.vertex_iterator()])
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: G.add_path([(1,1),'x',(3,3)])
sage: G.is_planar()
False
sage: G.degree('x')
2
sage: G.apex_vertices()
['x', (2, 2), (3, 3), (1, 1)]
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_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 – (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.
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(ceil(mad/2))
sage: try:
....: g.bounded_outdegree_orientation(ceil(mad/2-1))
....: print("Error")
....: except ValueError:
....: pass
bridges(G, labels=True)
Returns a list of the bridges (or cut edges).
A bridge is an edge whose deletion disconnects the undirected graph. A disconnected graph has no bridge.
INPUT:
• labels – (default: True) if False, each bridge is a tuple (𝑢, 𝑣) of vertices
EXAMPLES:
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. 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
chromatic_index(solver=None, verbose=0)
Return the chromatic index of the graph.
The chromatic index is the minimal number of colors needed to properly color the edges of the graph.
INPUT:
• solver (default: None) Specify the 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.
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
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 n. Namely its chromatic
number is n:
The Kneser graph with parameters (n,2) for n > 3 has chromatic number n-2:
True
A snark has chromatic index 4 hence its line graph has chromatic number 4:
sage: graphs.FlowerSnark().line_graph().chromatic_number()
4
chromatic_polynomial(G, return_tree_basis=False)
Compute the chromatic polynomial of the graph G.
The algorithm used is a recursive one, based on the following observations of Read:
• The chromatic polynomial of a tree on n vertices is x(x-1)^(n-1).
• If e is an edge of G, G’ is the result of deleting the edge e, and G” is the result of contracting e, then
the chromatic polynomial of G is equal to that of G’ minus that of G’‘.
EXAMPLES:
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()
(continues on next page)
sage: G = graphs.RandomGNP(10,0.7)
sage: P = G.chromatic_polynomial()
sage: min(i for i in range(11) if P(i) > 0) == G.chromatic_number()
True
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 [SW12]. We use the equivalent definition given in [BC15]:
∑︁
𝑋𝐺 (𝑡) = 𝑡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: G = Graph([[1,2,3], [[1,3], [2,3]]])
sage: G.chromatic_quasisymmetric_function()
(2*t^2+2*t+2)*M[1, 1, 1] + M[1, 2] + t^2*M[2, 1]
sage: G = graphs.PathGraph(4)
sage: XG = G.chromatic_quasisymmetric_function(); XG
(t^3+11*t^2+11*t+1)*M[1, 1, 1, 1] + (3*t^2+3*t)*M[1, 1, 2]
+ (3*t^2+3*t)*M[1, 2, 1] + (3*t^2+3*t)*M[2, 1, 1]
+ (t^2+t)*M[2, 2]
sage: XG.to_symmetric_function()
(t^3+11*t^2+11*t+1)*m[1, 1, 1, 1] + (3*t^2+3*t)*m[2, 1, 1]
+ (t^2+t)*m[2, 2]
sage: G = graphs.CompleteGraph(4)
sage: G.chromatic_quasisymmetric_function()
(t^6+3*t^5+5*t^4+6*t^3+5*t^2+3*t+1)*M[1, 1, 1, 1]
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]
REFERENCES:
chromatic_symmetric_function(R=None)
Return the chromatic symmetric function of self.
Let 𝐺 be a graph. The chromatic symmetric function 𝑋𝐺 was described in [Stanley95], 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)
sage: G1.delete_edge([1,2])
sage: XG1 = G1.chromatic_symmetric_function()
sage: G2 = copy(G)
sage: G2.delete_edge([1,3])
sage: XG2 = G2.chromatic_symmetric_function()
sage: G3 = copy(G1)
(continues on next page)
REFERENCES:
cleave(G, cut_vertices=None, virtual_edges=True, solver=None, verbose=0)
Return the connected subgraphs separated by the input vertex cut.
Given a connected (multi)graph 𝐺 and a vertex cut 𝑋, this method computes the list of subgraphs of 𝐺
induced by each connected component 𝑐 of 𝐺 ∖ 𝑋 plus 𝑋, i.e., 𝐺[𝑐 ∪ 𝑋].
INPUT:
• G – a Graph.
• cut_vertices – (default: None) a set of vertices representing a vertex cut of G. If no vertex cut is
given, the method will compute one via a call to vertex_connectivity().
• virtual_edges – boolean (default: True); whether to add virtual edges to the sides of the cut or
not. A virtual edge is an edge between a pair of vertices of the cut that are not connected by an edge
in G.
• 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 sage.numerical.mip.MixedIntegerLinearProgram.solve() of the class
sage.numerical.mip.MixedIntegerLinearProgram.
• verbose – integer (default: 0). Sets the level of verbosity. Set to 0 by default, which means quiet.
OUTPUT: A triple (𝑆, 𝐶, 𝑓 ), where
• 𝑆 is a list of the graphs that are sides of the vertex cut.
• 𝐶 is the graph of the cocycles. For each pair of vertices of the cut, if there exists an edge between
them, 𝐶 has one copy of each edge connecting them in G per sides of the cut plus one extra copy.
Furthermore, when virtual_edges == True, if a pair of vertices of the cut is not connected by
an edge in G, then it has one virtual edge between them per sides of the cut.
• 𝑓 is the complement of the subgraph of G induced by the vertex cut. Hence, its vertex set is the vertex
cut, and its edge set is the set of virtual edges (i.e., edges between pairs of vertices of the cut that are
not connected by an edge in G). When virtual_edges == False, the edge set is empty.
EXAMPLES:
If there is an edge between cut vertices:
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(), f1.edges()
([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.edges())
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(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: i = x.graph()
sage: i==h
True
sage: x==i.clique_complex()
True
clique_maximum(algorithm=’Cliquer’)
Return the vertex set of a maximal order complete subgraph.
INPUT:
• algorithm – the algorithm to be used :
– If algorithm = "Cliquer" (default) - This wraps the C program Cliquer [NisOst2003].
– If algorithm = "MILP", the problem is solved through a Mixed Integer Linear Program.
(see MixedIntegerLinearProgram)
– If algorithm = "mcqd" - Uses the MCQD solver (http://www.sicmm.org/~konc/
maxclique/). Note that the MCQD package must be installed.
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 [NisOst2003].
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]
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" - This wraps the C program Cliquer [NisOst2003].
– If algorithm = "networkx" - This function is based on NetworkX’s implementation of
the Bron and Kerbosch Algorithm [BroKer1973].
– If algorithm = "MILP", the problem is solved through a Mixed Integer Linear Program.
(see MixedIntegerLinearProgram)
– If algorithm = "mcqd" - Uses the MCQD solver (http://www.sicmm.org/~konc/
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 – (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.
ALGORITHM:
This function is based on Cliquer [NisOst2003] and [BroKer1973].
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
True
sage: all((i*graphs.CompleteMultipartiteGraph(i*[5])).clique_number() == i
˓→for i in range(1,6))
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()
{0: [[4, 0]], 1: [[4, 1, 2, 3]], 2: [[4, 1, 2, 3]], 3: [[4, 1, 2, 3]], 4: [[4,
˓→ 0], [4, 1, 2, 3]]}
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]]}
sage: F = graphs.Grid2dGraph(2,3)
sage: X = F.cliques_containing_vertex()
sage: for v in sorted(X):
....: print("{} {}".format(v, X[v]))
(0, 0) [[(0, 1), (0, 0)], [(1, 0), (0, 0)]]
(0, 1) [[(0, 1), (0, 0)], [(0, 1), (0, 2)], [(0, 1), (1, 1)]]
(0, 2) [[(0, 1), (0, 2)], [(1, 2), (0, 2)]]
(1, 0) [[(1, 0), (0, 0)], [(1, 0), (1, 1)]]
(1, 1) [[(0, 1), (1, 1)], [(1, 2), (1, 1)], [(1, 0), (1, 1)]]
(1, 2) [[(1, 2), (0, 2)], [(1, 2), (1, 1)]]
sage: F.cliques_containing_vertex(vertices=[(0, 1), (1, 2)])
{(0, 1): [[(0, 1), (0, 0)], [(0, 1), (0, 2)], [(0, 1), (1, 1)]], (1, 2): [[(1,
˓→ 2), (0, 2)], [(1, 2), (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.
For more information, see the Wikipedia article Clique_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)
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
[BroKer1973].
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 sligthly 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 [BroKer1973].
REFERENCE:
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],
[3, 8], [4, 9], [5, 7], [5, 8], [6, 8], [6, 9], [7, 9]]
sage: C = Graph('DJ{')
sage: C.cliques_maximal()
[[0, 4], [1, 2, 3, 4]]
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)
Returns 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 [NisOst2003].
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:
• vertices - the vertices to inspect (default is entire graph)
• cliques - list of cliques (if already computed)
EXAMPLES:
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: X = F.cliques_number_of()
sage: for v in sorted(X):
....: print("{} {}".format(v, X[v]))
(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 [NisOst2003].
– networkx - This function is based on NetworkX’s implementation of the Bron and Kerbosch
Algorithm [BroKer1973].
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}
sage: F = graphs.Grid2dGraph(2,3)
sage: X = F.cliques_vertex_clique_number(algorithm="networkx")
sage: for v in sorted(X):
....: print("{} {}".format(v, X[v]))
(0, 0) 2
(0, 1) 2
(0, 2) 2
(1, 0) 2
(1, 1) 2
(1, 2) 2
sage: F.cliques_vertex_clique_number(vertices=[(0, 1), (1, 2)])
{(0, 1): 2, (1, 2): 2}
sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
sage: G.show(figsize=[2,2])
sage: G.cliques_vertex_clique_number()
{0: 3, 1: 3, 2: 3, 3: 3}
• verbose – integer (default: 0). Sets the level of verbosity for the MILP algorithm. Its default value
is 0, which means quiet.
See also:
For more functions related to graph coloring, see the module sage.graphs.graph_coloring.
EXAMPLES:
sage: G = Graph("Fooba")
sage: P = G.coloring(algorithm="MILP"); P
[[2, 1, 3], [0, 6, 5], [4]]
sage: P = G.coloring(algorithm="DLX"); P
[[1, 2, 3], [0, 5, 6], [4]]
sage: G.plot(partition=P)
Graphics object consisting of 16 graphics primitives
sage: H = G.coloring(hex_colors=True, algorithm="MILP")
sage: for c in sorted(H.keys()):
....: print("{} {}".format(c, H[c]))
#0000ff [4]
#00ff00 [0, 6, 5]
#ff0000 [2, 1, 3]
sage: H = G.coloring(hex_colors=True, algorithm="DLX")
sage: for c in sorted(H.keys()):
....: print("{} {}".format(c, H[c]))
#0000ff [4]
#00ff00 [1, 2, 3]
#ff0000 [0, 5, 6]
sage: G.plot(vertex_colors=H)
Graphics object consisting of 16 graphics primitives
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]
(continues on next page)
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 𝑘.
• Core number of a vertex
The core number of a vertex 𝑣 is the largest integer 𝑘 such that 𝑣 belongs to the 𝑘-core of 𝐺.
• Degeneracy
The degeneracy of a graph 𝐺, usually denoted 𝛿 * (𝐺), is the smallest integer 𝑘 such that the graph
𝐺 can be reduced to the empty graph by iteratively removing vertices of degree ≤ 𝑘. Equivalently,
𝛿 * (𝐺) = 𝑘 if 𝑘 is the smallest integer such that the 𝑘-core of 𝐺 is empty.
IMPLEMENTATION
This implementation is based on the NetworkX implementation of the algorithm described in [BZ].
INPUT
• k (integer)
– If k = None (default), returns the core number for each vertex.
– If k is an integer, returns a pair (ordering, core), where core is the list of vertices in
the 𝑘-core of self, and ordering is an elimination order for the other vertices such that each
vertex is of degree strictly less than 𝑘 when it is to be eliminated from the graph.
• with_labels (boolean)
– When set to False, and k = None, the method returns a list whose 𝑖 th element is the core
number of the 𝑖 th vertex. When set to True, the method returns a dictionary whose keys are
vertices, and whose values are the corresponding core numbers.
By default, with_labels = False.
See also:
• Graph cores is also a notion related to graph homomorphisms. For this second meaning, see Graph.
has_homomorphism_to().
REFERENCE:
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: 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.RandomLobster(20,.5,.5)
sage: ordering, core = g.cores(2)
sage: len(core) == 0
True
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:
sage: g = graphs.CycleGraph(6)
sage: bounds = lambda x: [1,1]
sage: m = g.degree_constrained_subgraph(bounds=bounds)
sage: m.size()
3
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 P 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.
This method implements the linear time algorithm presented in [Sch2013].
INPUT:
• self – The undirected graph for which ear decomposition needs to be computed.
OUTPUT:
• A nested list representing the cycles and chains of the ear decomposition of the graph.
EXAMPLES:
Ear decomposition of an outer planar graph of order 13:
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.CubeGraph(2)
sage: g.ear_decomposition()
[['00', '01', '11', '10', '00']]
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())
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
Such that :
∑︁
∀𝑀 matching ⊆ 𝐺, 𝑟𝑣 ≤ 1
𝑒∈𝑀
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.
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.
sage: g = graphs.CycleGraph(5)
sage: g.fractional_chromatic_index()
5/2
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 maxi-
mum 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 [SchrijverCombOpt].
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'
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
otherwise 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")
(continues on next page)
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
[ScottStorm] and Def. 4.1 in [Terras].
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
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:
independent_set(algorithm=’Cliquer’, value_only=False, reduction_rules=True, solver=None,
verbosity=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
• 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
applied 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 – (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.
• verbosity – non-negative integer (default: 0). Set the level of verbosity you want from the linear
program solver. Since the problem of computing an independent set 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. This option is only useful if algorithm="MILP".
Note: While Cliquer/MCAD are usually (and by far) the most efficient implementations, the MILP
formulation 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
• 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.
OUTPUT:
• A list whose 𝑖th element is the representative of the 𝑖th element of the family list. If there is no
ISR, None is returned.
EXAMPLES:
For a bipartite graph missing one edge, the solution is as expected:
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 prob-
lem : 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 = [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
REFERENCE:
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()
Returns true 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 – (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
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
• certificate (boolean) – 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) – 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.
This is set to False by default.
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: from sage.graphs.graph_decompositions.graph_products import is_
˓→cartesian_product
sage: g = graphs.PetersenGraph()
sage: is_cartesian_product(g)
False
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].
is_directed()
Since graph is undirected, returns False.
EXAMPLES:
sage: Graph().is_directed()
False
is_distance_regular(G, parameters=False)
Tests 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) – if set to True, the function returns the pair (b,c) of lists of integers
instead of True (see the definition above). Set to False by default.
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
is_edge_transitive()
Returns true 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 [ABCHRS08].
INPUT:
• certificate (boolean) – 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:
REFERENCE:
is_forest(certificate=False, output=’vertex’)
Tests if the graph is a forest, i.e. a disjoint union of trees.
INPUT:
• certificate (boolean) – whether to return a certificate. The method only returns boolean an-
swers when certificate = False (default). When it is set to True, it either answers (True,
None) when the graph is a forest and (False, cycle) when it contains a cycle.
• output ('vertex' (default) or 'edge') – whether the certificate is given as a list of vertices or a
list of edges.
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, [62, 63, 68, 66, 61])
is_half_transitive()
Returns true 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)
Tests wether 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.
Todo: This method sequentially tests each of the forbidden subgraphs in order to know whether the graph
is a line graph, which is a very slow method. It could eventually be replaced by root_graph() when
this method will not require an exponential time to run on general graphs anymore (see its documentation
for more information on this problem). . . and if it can be improved to return negative certificates !
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: 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 ) [NikolopoulosPalios07] ( 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 ) [NikolopoulosPalios07] ( 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
antihole [CRST06], it is not known whether testing for one of these two cases independently is polynomial
too.
INPUT:
• certificate (boolean) – 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
REFERENCES:
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:
...
sage: check_overfull_Kn_even(100) # long time
Complete graphs of even order up to 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 [Eppstein2008]. The algorithm runs in 𝑂(𝑛2 ) time, where 𝑛 is the number of vertices. See the
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_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 [SPGT] 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) – whether to return a certificate (default : False)
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:
A Bipartite Graph is always perfect
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
REFERENCES:
is_polyhedral()
Test 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()
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().
EXAMPLES:
The Petersen Graph and the Bull Graph are both prime:
sage: graphs.PetersenGraph().is_prime()
True
sage: graphs.BullGraph().is_prime()
True
is_semi_symmetric()
Returns true 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
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” [GraphClasses] 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 caracterisation of split graph states that a graph is a split graph if and only if does not contain the
4-cycle, 5-cycle or 2K_2 as an induced subgraph. Hence for the above graph we have:
REFERENCES:
is_strongly_regular(g, parameters=False)
Tests whether self 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) – 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)]).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)]).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) – whether to return a certificate. The method only returns boolean an-
swers when certificate = False (default). When it is set to True, it either answers (True,
None) when the graph is a tree and (False, cycle) when it contains a cycle. It returns
(False, None) when the graph is empty or not connected.
• output ('vertex' (default) or 'edge') – whether the certificate is given as a list of vertices or a
list of edges.
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)
sage: g.add_edge(10,-1)
sage: g.add_edge(11,-1)
sage: isit, cycle = g.is_tree(certificate=True)
sage: isit
False
sage: -1 in cycle
True
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=’bitset’)
Returns whether self is triangle-free
INPUT:
• algorithm – (default: 'bitset') 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.
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 = (3 * graphs.CompleteGraph(5)).complement()
sage: G.is_triangle_free(algorithm='matrix')
False
sage: G.is_triangle_free(algorithm='bitset')
False
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 = len(s.vertices())
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()
[(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()
[0, 1, 2, 3, 4]
sage: J.edges()
[(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()
[(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()
[(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 [Marcolli2009].
As an intermediate step, one computes a cycle basis 𝒞 of 𝐺 and a rectangular |𝒞| × |𝐸(𝐺)| matrix
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 = Graph([(0,1,'a'),(0,1,'b'),(0,1,'c')],multiedges=True)
sage: G.kirchhoff_symanzik_polynomial()
t0*t1 + t0*t2 + t1*t2
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:
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. Mathemati-
cally, 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')
sage: m(exp(-t))
6/(2*e^(-t) + 2*e^(-2*t) + e^(-3*t) + 1)
REFERENCES:
matching(value_only=False, algorithm=’Edmonds’, use_edge_labels=False, solver=None, ver-
bose=0)
Return a maximum weighted matching of the graph represented by the list of its edges.
For more information, see the Wikipedia article Matching_(graph_theory).
Given a graph 𝐺 such that each edge 𝑒 has a weight 𝑤𝑒 , a maximum matching is a subset 𝑆 of the edges
of 𝐺 of maximum weight such that no two edges of 𝑆 are incident with each other.
∀𝑥 ∈ 𝐺, 𝑏𝑥 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 – (default: None) specify a Linear Program (LP) solver to be used; if set to None, the
default one is used
• verbose – integer (default: 0); sets the level of verbosity: set to 0 by default, which means quiet
(only useful when algorithm == "LP")
For more information on LP solvers and which default solver is used, see the method solve of the class
MixedIntegerLinearProgram.
ALGORITHM:
The problem is solved using Edmond’s algorithm implemented in NetworkX, or using Linear Program-
ming depending on the value of algorithm.
EXAMPLES:
Maximum matching in a Pappus Graph:
sage: g = graphs.PappusGraph()
sage: g.matching(value_only=True)
9
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 [Godsil93]:
• 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 substraction by an addition. It is then converted into the matching poly-
nomial and returned)
Depending on the value of complement, Godsil’s duality theorem [Godsil93] can also be used to com-
pute 𝜇(𝑥) :
∑︁
𝜇(𝐺, 𝑥) = 𝑝(𝐺, 𝑘)𝜇(𝐾𝑛−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
sage: g = graphs.CompleteBipartiteGraph(3,4)
sage: o = g.minimum_outdegree_orientation()
sage: max(o.out_degree()) == ceil((4*3)/(3+4))
True
REFERENCES:
minor(H, solver=None, verbose=0)
Return the vertices of a minor isomorphic to 𝐻 in the current graph.
We say that a graph 𝐺 has a 𝐻-minor (or that it has a graph isomorphic to 𝐻 as a minor), if for all ℎ ∈ 𝐻,
there exist disjoint sets 𝑆ℎ ⊆ 𝑉 (𝐺) such that once the vertices of each 𝑆ℎ have been merged to create a
new graph 𝐺′ , this new graph contains 𝐻 as a subgraph.
For more information, see the Wikipedia article Minor_(graph_theory).
INPUT:
• H – The minor to find for in the current graph.
• 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.
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 algo-
rithms 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()
Return the modular decomposition of the current graph.
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” [HabPau10].
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.
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, 3, 7, 2, 8, 9, 6])
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, [4, 3, 2, 1]), 5, 6]), 0])
ALGORITHM:
This function uses python implementation of algorithm published by Marc Tedder, Derek Corneil, Michel
Habib and Christophe Paul [TedCorHabPaul08]
See also:
REFERENCE:
odd_girth()
Returns the odd girth of self.
The odd girth of a graph is defined as the smallest cycle of odd length.
OUTPUT:
The odd girth of self.
EXAMPLES:
The McGee graph has girth 7 and therefore its odd girth is 7 as well.
sage: G = graphs.McGeeGraph()
sage: G.odd_girth()
7
Any complete graph on more than 2 vertices contains a triangle and has thus odd girth 3.
sage: G = graphs.CompleteGraph(10)
sage: G.odd_girth()
3
Every bipartite graph has no odd cycles and consequently odd girth of infinity.
sage: G = graphs.CompleteBipartiteGraph(100,100)
sage: G.odd_girth()
+Infinity
See also:
REFERENCES:
The property relating the odd girth to the coefficients of the characteristic polynomial is an old result from
algebraic graph theory see
orientations(implementation=’c_graph’, 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 documenta-
tion of Graph or DiGraph; default is the data structure of self
• sparse – (optional) boolean; sparse=True is an alias for data_structure="sparse", and
sparse=False is an alias for data_structure="dense"
Warning: This always considers multiple edges of graphs as distinguishable, and hence, may have
repeated digraphs.
EXAMPLES:
sage: it = G.orientations()
sage: D = next(it)
sage: D.edges()
[(1, 2, 'a'), (1, 3, 'b')]
sage: D = next(it)
sage: D.edges()
[(1, 2, 'a'), (3, 1, 'b')]
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)
(continues on next page)
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
(containing the label as the third element), otherwise the edges are pairs
See also:
matching()
EXAMPLES:
sage: G=graphs.GridGraph([2,3])
sage: list(G.perfect_matchings())
[[((0, 0), (0, 1)), ((0, 2), (1, 2)), ((1, 0), (1, 1))],
[((0, 1), (0, 2)), ((1, 1), (1, 2)), ((0, 0), (1, 0))],
[((0, 1), (1, 1)), ((0, 2), (1, 2)), ((0, 0), (1, 0))]]
sage: G = graphs.CompleteGraph(4)
sage: list(G.perfect_matchings(labels=True))
[[(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: list(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())
[]
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:
sage: from sage.graphs.orientations import random_orientation
sage: G = graphs.PetersenGraph()
sage: D = random_orientation(G)
sage: D.order() == G.order(), D.size() == G.size()
(True, True)
See also:
• orientations()
random_spanning_tree(output_as_graph=False)
Return a random spanning tree of the graph.
This uses the Aldous-Broder algorithm ([Broder89], [Aldous90]) to generate a random spanning tree with
the uniform distribution, as follows.
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.
INPUT:
• output_as_graph – boolean (default: False) whether to return a list of edges or a graph.
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),
(continues on next page)
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)
rank_decomposition(G, verbose=False)
Computes 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) – 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 = graphs.PetersenGraph()
sage: rank_decomposition(g)
(3, Graph on 19 vertices)
sage: g = Graph()
sage: rank_decomposition(g)
(0, Graph on 0 vertices)
seidel_adjacency_matrix(vertices=None)
Return the Seidel adjacency matrix of self.
Returns 𝐽 − 𝐼 − 2𝐴, for 𝐴 the (ordinary) adjacency matrix of self, 𝐼 the identity matrix, and 𝐽
the all-1 matrix. It is closely related to twograph().
The matrix returned is over the integers. If a different ring is desired, use either the sage.matrix.
matrix0.Matrix.change_ring() method or the matrix() function.
INPUT:
• vertices (list) – the ordering of the vertices defining how they should appear in the matrix. By
default, the ordering given by vertices() is used.
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) – 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()
Returns a list of all spanning trees.
If the graph is disconnected, returns the empty list.
Uses the Read-Tarjan backtracking algorithm [RT75].
EXAMPLES:
sage: G = Graph([(1,2),(1,2),(1,3),(1,3),(2,3),(1,4)],multiedges=True)
sage: len(G.spanning_trees())
8
sage: G.spanning_trees_count()
8
sage: G = Graph([(1,2),(2,3),(3,1),(3,4),(4,5),(4,5),(4,6)],multiedges=True)
sage: len(G.spanning_trees())
(continues on next page)
See also:
REFERENCES:
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'
• algorithm – The algorithm to use in computing the SPQR tree of G. The following algorithms
are supported:
• 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 sage.numerical.mip.MixedIntegerLinearProgram.solve() of the class
sage.numerical.mip.MixedIntegerLinearProgram.
• verbose – integer (default: 0). Sets the level of verbosity. Set to 0 by default, which means quiet.
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.vertices() 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.edges())
sage: Tree = spqr_tree(G)
sage: Tree.order()
13
sage: all(u[1].is_isomorphic(C4) for u in Tree.vertices() if u[0] == 'S')
True
sage: G.is_isomorphic(spqr_tree_to_graph(Tree))
True
sage: G = graphs.CycleGraph(6)
(continues on next page)
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).
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
sage: g = Graph([(1,2),(1,2)],multiedges=True)
sage: g.strong_orientation()
Multi-digraph on 2 vertices
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 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
symetries, 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). In order to avoid symetries an orientation of an
arbitrary edge is fixed.
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
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
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
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
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
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
sage: 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)
two_factor_petersen(solver=None, verbose=0)
Return a decomposition of the graph into 2-factors.
Petersen’s 2-factor decomposition theorem asserts that any 2𝑟-regular graph 𝐺 can be decomposed into
2-factors. Equivalently, it means that the edges of any 2𝑟-regular graphs can be partitionned in 𝑟 sets
𝐶1 , . . . , 𝐶𝑟 such that for all 𝑖, the set 𝐶𝑖 is a disjoint union of cycles ( a 2-regular graph ).
As any graph of maximal degree ∆ can be completed into a regular graph of degree 2⌈ Δ 2 ⌉, this result also
Δ
means that the edges of any graph of degree ∆ can be partitionned in 𝑟 = 2⌈ 2 ⌉ sets 𝐶1 , . . . , 𝐶𝑟 such that
for all 𝑖, the set 𝐶𝑖 is a graph of maximal degree 2 ( a disjoint union of paths and cycles ).
INPUT:
• 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:
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 𝑇 = {𝑡 ∈ 3 :
⃒
2 ∩ 𝐸 odd} where 𝑉 and 𝐸 are vertices and
⃒
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)
sage: T8.twograph()==C.twograph()
True
sage: T8.is_isomorphic(C)
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.
– If algorithm = "mcqd" - Uses 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
applied 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 – (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.
• verbosity – non-negative integer (default: 0). Set the level of verbosity you want from the linear
program solver. Since the problem of computing a vertex cover 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. This option is only useful if algorithm="MILP".
EXAMPLES:
On the Pappus graph:
sage: g = graphs.PappusGraph()
sage: g.vertex_cover(value_only=True)
9
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'))
This module implements functions and operations involving directed graphs. Here is what they can do
Graph basic operations:
layout_acyclic_dummy() Computes a (dummy) ranked layout so that all edges point upward.
layout_acyclic() Computes a ranked layout so that all edges point upward.
reverse() Returns a copy of digraph with edges reversed in direction.
reverse_edge() Reverses an edge.
reverse_edges() Reverses 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() Returns the list of the out-neighbors of a given vertex.
neighbor_out_iterator() Returns an iterator over the out-neighbors of a given vertex.
neighbors_in() Returns the list of the in-neighbors of a given vertex.
neighbor_in_iterator() Returns an iterator over the in-neighbors of vertex.
outgoing_edges() Returns a list of edges departing from vertices.
outgoing_edge_iterator()Return an iterator over all departing edges from vertices
incoming_edges() Returns a list of edges arriving at vertices.
incoming_edge_iterator()Return an iterator over all arriving edges from vertices
sources() Returns the list of all sources (vertices without incoming edges) of this digraph.
sinks() Returns the list of all sinks (vertices without outgoing edges) of this digraph.
to_undirected() Returns 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() Returns the dig6 representation of the digraph as an ASCII string.
all_paths_iterator() Returns an iterator over the paths of self. The paths are
all_simple_paths() Returns a list of all the simple paths of self starting
all_cycles_iterator() Returns an iterator over all the cycles of self starting
all_simple_cycles() Returns a list of all simple cycles of self.
Representation theory:
path_semigroup() Returns the (partial) semigroup formed by the paths of the digraph.
Connectivity:
Acyclicity:
Hard stuff:
Miscellanous:
1.3.1 Methods
• pos - a positioning dictionary: for example, the spring layout from NetworkX for the 5-cycle is:
• name - (must be an explicitly named parameter, i.e., name=”complete”) gives the graph a name
• loops - boolean, whether to allow loops (ignored if data is an instance of the DiGraph class)
• multiedges - boolean, whether to allow multiple edges (ignored if data is an instance of the DiGraph
class)
• weighted - whether digraph thinks of itself as weighted or not. See self.weighted()
• format - if set to None (default), DiGraph tries to guess input’s format. To avoid this pos-
sibly 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) – 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) – whether to create a immutable digraph. Note that immutable=True is actu-
ally a shortcut for data_structure='static_sparse'.
• vertex_labels - 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:
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 i to j if and only
if i divides j.
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:
sage: M = 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]]); M
[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:
sage: M = Matrix(6, [-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]); M
[-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. (continues on next page)
sage: D = DiGraph("IRAaDCI'OWEOKcPWAo")
Traceback (most recent call last):
...
RuntimeError: The string seems corrupt: valid characters are
?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
6. A NetworkX XDiGraph:
7. A NetworkX digraph:
Digraph on 3 vertices
If vertex_labels is True, the names of the vertices are given by the vertex attribute 'name', if
available:
sage: DiGraph(g).vertices()
˓→ # optional - python_igraph
[0, 1, 2]
If the igraph Graph has edge attributes, they are used as edge labels:
sage: DiGraph(g).edges()
˓→ # optional - python_igraph
[(0, 1, {'name': 'a', 'weight': 1}), (0, 2, {'name': 'b', 'weight': 3})]
INPUT:
• starting_vertices - iterable (default: None) on vertices from which the cycles must start. If
None, then all vertices of the graph can be starting points.
• simple - boolean (default: False). If set to True, then only simple cycles are considered. A cycle is
simple if the only vertex occuring twice in it is the starting and ending one.
• rooted - boolean (default: False). If set to False, then cycles differing only by their starting ver-
tex are considered the same (e.g. ['a', 'b', 'c', 'a'] and ['b', 'c', 'a', 'b']).
Otherwise, all cycles are enumerated.
• max_length - non negative integer (default: None). The maximum length of the enumerated cycles.
If set to None, then all lengths are allowed.
• trivial - boolean (default: False). If set to True, then the empty cycles are also enumerated.
OUTPUT:
iterator
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 occuring 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]]
EXAMPLES:
sage: g = DiGraph({'a' : ['a', 'b'], 'b' : ['c'], 'c' : ['d'], 'd' : ['c']},
˓→loops=True)
sage: pi = g.all_paths_iterator()
sage: for _ in range(7): print(next(pi))
['a', 'a']
['a', 'b']
['b', 'c']
['c', 'd']
['d', 'c']
['a', 'a', 'a']
['a', 'a', 'b']
sage: pi = g.all_paths_iterator(starting_vertices=['a'])
sage: for _ in range(5): print(next(pi))
['a', 'a']
['a', 'b']
['a', 'a', 'a']
['a', 'a', 'b']
['a', 'b', 'c']
sage: pi = g.all_paths_iterator(starting_vertices=['a'], ending_vertices=['b
˓→'])
sage: pi = g.all_paths_iterator(simple=True)
sage: list(pi)
[['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: list(pi)
[['a', 'b'], ['a', 'a', 'b'], ['a', 'b', 'c'],
['a', 'a', 'a', 'b'], ['a', 'a', 'b', 'c'],
['a', 'a', 'a', 'a', 'b'], ['a', 'a', 'a', 'b', 'c'],
['a', 'b', 'c', 'd', 'c'], ['a', 'a', 'a', 'a', 'a', 'b'],
['a', 'a', 'a', 'a', 'b', 'c'], ['a', 'a', 'b', 'c', 'd', 'c'],
['a', 'a', 'a', 'a', 'a', 'a', 'b'],
['a', 'a', 'a', 'a', 'a', 'b', 'c'],
['a', 'a', 'a', 'b', 'c', 'd', 'c'],
['a', 'b', 'c', 'd', 'c', 'd', 'c']]
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.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],
[0, 17, 0], [0, 18, 0], [0, 19, 0], [1, 2, 1], [1, 3, 1],
[1, 4, 1], [1, 5, 1], [1, 6, 1], [1, 7, 1], [1, 8, 1], [1, 9, 1],
[1, 10, 1], [1, 11, 1], [1, 12, 1], [1, 13, 1], [1, 14, 1],
[1, 15, 1], [1, 16, 1], [1, 17, 1], [1, 18, 1], [1, 19, 1],
[2, 3, 2], [2, 4, 2], [2, 5, 2], [2, 6, 2], [2, 7, 2], [2, 8, 2],
[2, 9, 2], [2, 10, 2], [2, 11, 2], [2, 12, 2], [2, 13, 2],
[2, 14, 2], [2, 15, 2], [2, 16, 2], [2, 17, 2], [2, 18, 2],
[2, 19, 2], [3, 4, 3], [3, 5, 3], [3, 6, 3], [3, 7, 3], [3, 8, 3],
[3, 9, 3], [3, 10, 3], [3, 11, 3], [3, 12, 3], [3, 13, 3],
[3, 14, 3], [3, 15, 3], [3, 16, 3], [3, 17, 3], [3, 18, 3],
[3, 19, 3], [4, 5, 4], [4, 6, 4], [4, 7, 4], [4, 8, 4], [4, 9, 4],
[4, 10, 4], [4, 11, 4], [4, 12, 4], [4, 13, 4], [4, 14, 4],
[4, 15, 4], [4, 16, 4], [4, 17, 4], [4, 18, 4], [4, 19, 4],
[5, 6, 5], [5, 7, 5], [5, 8, 5], [5, 9, 5], [5, 10, 5],
[5, 11, 5], [5, 12, 5], [5, 13, 5], [5, 14, 5], [5, 15, 5],
[5, 16, 5], [5, 17, 5], [5, 18, 5], [5, 19, 5], [6, 7, 6],
[6, 8, 6], [6, 9, 6], [6, 10, 6], [6, 11, 6], [6, 12, 6],
[6, 13, 6], [6, 14, 6], [6, 15, 6], [6, 16, 6], [6, 17, 6],
[6, 18, 6], [6, 19, 6], [7, 8, 7], [7, 9, 7], [7, 10, 7],
[7, 11, 7], [7, 12, 7], [7, 13, 7], [7, 14, 7], [7, 15, 7],
[7, 16, 7], [7, 17, 7], [7, 18, 7], [7, 19, 7], [8, 9, 8],
[8, 10, 8], [8, 11, 8], [8, 12, 8], [8, 13, 8], [8, 14, 8],
[8, 15, 8], [8, 16, 8], [8, 17, 8], [8, 18, 8], [8, 19, 8],
(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],
[2, 0, 2], [2, 1, 2], [2, 3, 2], [3, 0, 3], [3, 1, 3], [3, 2, 3]]
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({'a' : ['a', 'b'], 'b' : ['c'], 'c' : ['d'], 'd' : ['c']},
˓→loops=True)
sage: g.all_simple_paths()
[['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']]
One may compute all paths having specific starting and/or ending vertices:
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']]
sage: g.all_simple_paths(max_length=2)
[['a', 'a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'c'],
['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'],
['d', 'c', 'd']]
By default, empty paths are not enumerated, but this can be parametrized:
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
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:
sage: D = DiGraph({0: [1, 2], 1: [2], 2: [3], 3: [0]})
sage: D.dig6_string()
'CW`_'
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: 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
flow_polytope(edges=None, ends=None)
Return the flow polytope of a digraph.
The flow polytope of a directed graph is the polytope consisting of all nonnegative flows on the graph with
a given set 𝑆 of sources and a given set 𝑇 of sinks.
A flow on a directed graph 𝐺 with a given set 𝑆 of sources and a given set 𝑇 of sinks means an assignment
of a nonnegative real to each edge of 𝐺 such that the flow is conserved in each vertex outside of 𝑆 and
𝑇 , and there is a unit of flow entering each vertex in 𝑆 and a unit of flow leaving each vertex in 𝑇 . These
flows clearly form a polytope in the space of all assignments of reals to the edges of 𝐺.
The polytope is empty unless the sets 𝑆 and 𝑇 are equinumerous.
By default, 𝑆 is taken to be the set of all sources (i.e., vertices of indegree 0) of 𝐺, and 𝑇 is taken to be
the set of all sinks (i.e., vertices of outdegree 0) of 𝐺. If a different choice of 𝑆 and 𝑇 is desired, it can be
specified using the optional ends parameter.
The polytope is returned as a polytope in R𝑚 , where 𝑚 is the number of edges of the digraph self. The
𝑘-th coordinate of a point in the polytope is the real assigned to the 𝑘-th edge of self. The order of the
edges is the one returned by self.edges(). If a different order is desired, it can be specified using the
optional edges parameter.
The faces and volume of these polytopes are of interest. Examples of these polytopes are the Chan-
Robbins-Yuen polytope and the Pitman-Stanley polytope [PitSta].
INPUT:
• edges – (optional, default: self.edges()) a list or tuple of all edges of self (each only once).
This determines which coordinate of a point in the polytope will correspond to which edge of self.
It is also possible to specify a list which contains not all edges of self; this results in a polytope
corresponding to the flows which are 0 on all remaining edges. Notice that the edges entered here
must be in the precisely same format as outputted by self.edges(); so, if self.edges()
outputs an edge in the form (1, 3, None), then (1, 3) will not do!
• ends – (optional, default: (self.sources(), self.sinks())) a pair (𝑆, 𝑇 ) of an iterable
𝑆 and an iterable 𝑇 .
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))
REFERENCES:
immediate_dominators(r, reverse=False)
Return the immediate dominators of all vertices reachable from 𝑟.
A flowgraph 𝐺 = (𝑉, 𝐴, 𝑟) is a digraph where every vertex in 𝑉 is reachable from a distinguished root
vertex 𝑟 ∈ 𝑉 . In such digraph, a vertex 𝑤 dominates a vertex 𝑣 if every path from 𝑟 to 𝑣 includes 𝑤.
Let 𝑑𝑜𝑚(𝑣) be the set of the vertices that dominate 𝑣. Obviously, 𝑟 and 𝑣, the trivial dominators of 𝑣,
are in 𝑑𝑜𝑚(𝑣). For 𝑣 ̸= 𝑟, the immediate dominator of 𝑣, denoted by 𝑑(𝑣), is the unique vertex 𝑤 ̸= 𝑣
that dominates 𝑣 and is dominated by all the vertices in 𝑑𝑜𝑚(𝑣) ∖ {𝑣}. The (immediate) dominator tree
is a directed tree (or arborescence) rooted at 𝑟 that is formed by the arcs {(𝑑(𝑣), 𝑣) | 𝑣 ∈ 𝑉 ∖ {𝑟}}. See
[Ge2005] for more details.
This method implements the algorithm proposed in [CHK2001] which performs very well in practice,
sage: D = digraphs.Complete(4) * 2
sage: D.add_edges([(0, 4), (7, 3)])
sage: d = D.immediate_dominators(0)
doctest:...: DeprecationWarning: immediate_dominators is now deprecated.
˓→Please use method dominator_tree instead.
sage: D = digraphs.Circuit(5)
sage: D.immediate_dominators(0)
{0: 0, 1: 0, 2: 1, 3: 2, 4: 3}
sage: D.immediate_dominators(1)
{0: 4, 1: 1, 2: 1, 3: 2, 4: 3}
sage: P = digraphs.Path(5)
sage: P.immediate_dominators(0)
{0: 0, 1: 0, 2: 1, 3: 2, 4: 3}
sage: P.immediate_dominators(3)
{3: 3, 4: 3}
sage: D = digraphs.Complete(5)+digraphs.Complete(4)
sage: D.add_edges([(0, 5), (1, 6), (7, 2)])
sage: idom = D.immediate_dominators(0, reverse=True)
sage: idom
{0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 7, 6: 7, 7: 2, 8: 7}
sage: D_reverse = D.reverse()
sage: D_reverse.immediate_dominators(0) == idom
True
See also:
• strongly_connected_components()
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: for i in D.in_degree_iterator():
....: print(i)
3
3
2
2
3
2
2
3
sage: for i in D.in_degree_iterator(labels=True):
....: print(i)
((0, 1), 3)
((1, 2), 3)
((0, 0), 2)
((0, 3), 2)
((1, 1), 3)
((1, 3), 2)
((1, 0), 2)
((0, 2), 3)
in_degree_sequence()
Return the indegree sequence.
EXAMPLES:
The indegree 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) – whether to return edges as pairs of vertices, or as triples containing the labels.
EXAMPLES:
incoming_edges(vertices, labels=True)
Returns a list of edges arriving at vertices.
INPUT:
• vertices – a vertex or a list of vertices
• labels (boolean) – whether to return edges as pairs of vertices, or as triples containing the labels.
EXAMPLES:
sage: D.incoming_edges([0])
[(1, 0, None), (4, 0, None)]
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, returns True.
EXAMPLES:
sage: DiGraph().is_directed()
True
is_directed_acyclic(certificate=False)
Returns 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 – whether to return a certificate (False by default).
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.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
is_strongly_connected(G)
Returns 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: digraphs.DeBruijn(5,2).is_transitive()
False
sage: digraphs.DeBruijn(5,2).is_transitive(certificate=True)
('00', '10')
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 – ‘up’, ‘down’, ‘left’, or ‘right’ (default: ‘up’): which direction the edges should point
toward
• **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]})
sage: pos = H.layout_acyclic(rankdir='up')
(continues on next page)
sage: H = DiGraph({0:[1,2],1:[3],2:[3],3:[],5:[1,6],6:[2,3]})
sage: H.layout_acyclic_dummy()
{0: [1.00..., 0], 1: [1.00..., 1], 2: [1.51..., 2], 3: [1.50..., 3], 5: [2.01.
˓→.., 0], 6: [2.00..., 1]}
sage: H = DiGraph({0:[1]})
sage: H.layout_acyclic_dummy(rankdir='up')
{0: [0.5..., 0], 1: [0.5..., 1]}
sage: H.layout_acyclic_dummy(rankdir='down')
{0: [0.5..., 1], 1: [0.5..., 0]}
sage: H.layout_acyclic_dummy(rankdir='left')
{0: [1, 0.5...], 1: [0, 0.5...]}
sage: H.layout_acyclic_dummy(rankdir='right')
{0: [0, 0.5...], 1: [1, 0.5...]}
sage: H = DiGraph({0:[1,2],1:[3],2:[3],3:[1],5:[1,6],6:[2,3]})
sage: H.layout_acyclic_dummy()
Traceback (most recent call last):
...
ValueError: `self` should be an acyclic graph
level_sets()
Returns 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 occuring 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
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)
Returns 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)
Returns an iterator over the out-neighbors of a given vertex.
An vertex 𝑢 is an out-neighbor of a vertex 𝑣 if 𝑣𝑢 in an edge.
EXAMPLES:
neighbors_in(vertex)
Returns the list of the in-neighbors of a given vertex.
sage: D.neighbors_in(0)
[1, 4]
neighbors_out(vertex)
Returns the list of the out-neighbors of a given vertex.
An vertex 𝑢 is an out-neighbor of a vertex 𝑣 if 𝑣𝑢 in an edge.
EXAMPLES:
sage: D.neighbors_out(0)
[1, 2, 3]
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: for i in D.out_degree_iterator():
....: print(i)
3
3
2
2
3
2
2
3
sage: for i in D.out_degree_iterator(labels=True):
....: print(i)
((0, 1), 3)
((1, 2), 3)
((0, 0), 2)
((0, 3), 2)
((1, 1), 3)
((1, 3), 2)
(continues on next page)
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) – whether to return edges as pairs of vertices, or as triples containing the labels.
EXAMPLES:
outgoing_edges(vertices, labels=True)
Returns a list of edges departing from vertices.
INPUT:
• vertices – a vertex or a list of vertices
• labels (boolean) – whether to return edges as pairs of vertices, or as triples containing the labels.
EXAMPLES:
sage: D.outgoing_edges([0])
[(0, 1, None), (0, 2, None), (0, 3, None)]
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()
reverse()
Returns a copy of digraph with edges reversed in direction.
EXAMPLES:
• multiedges – (default: None) how to decide what should be done in case of doubt (for instance
when edge (1, 2) is to be reversed in a graph while (2, 1) already exists):
– If set to True, input graph will be forced to allow parallel edges if necessary and edge (1, 2) will
appear twice in the graph.
– If set to False, only one edge (1, 2) will remain in the graph after (2, 1) is reversed. Besides,
the label of edge (1, 2) will be overwritten with the label of edge (2, 1).
The default behaviour (multiedges = None) will raise an exception each time a subjective deci-
sion (setting multiedges to True or False) is necessary to perform the operation.
The following forms are all accepted:
• D.reverse_edge( 1, 2 )
• D.reverse_edge( (1, 2) )
• D.reverse_edge( [1, 2] )
• D.reverse_edge( 1, 2, ‘label’ )
• D.reverse_edge( ( 1, 2, ‘label’) )
• D.reverse_edge( [1, 2, ‘label’] )
• D.reverse_edge( ( 1, 2), label=’label’) )
EXAMPLES:
If inplace is True (default value), self is modified:
sage: D = DiGraph([(0,1,2)])
sage: D.reverse_edge(0,1)
sage: D.edges()
[(1, 0, 2)]
If multiedges is True, self will be forced to allow parallel edges when and only when it is necessary:
sage: D = DiGraph( [(1, 2, 'A'), (2, 1, 'A'), (2, 3, None)] )
sage: D.reverse_edge(1,2, multiedges=True)
sage: D.edges()
[(2, 1, 'A'), (2, 1, 'A'), (2, 3, None)]
sage: D.allows_multiple_edges()
True
Even if multiedges is True, self will not be forced to allow parallel edges when it is not necessary:
sage: D = DiGraph( [(1,2,'A'), (2,1,'A'), (2, 3, None)] )
sage: D.reverse_edge(2,3, multiedges=True)
sage: D.edges()
[(1, 2, 'A'), (2, 1, 'A'), (3, 2, None)]
sage: D.allows_multiple_edges()
False
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:
sage: re = D.reverse_edge([0,1,'01'],inplace=False)
sage: re.edges()
[(0, 1, '01'), (0, 1, 'cat'), (1, 0, '01'), (1, 2, '12')]
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()
[(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:
sage: D = DiGraph([(0,1,'A'),(1,0,'B')])
sage: D.reverse_edge(0,1)
Traceback (most recent call last):
(continues on next page)
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()
[(1, 2, 'label')]
sage: D.reverse_edge((1,2),label ='label')
sage: D.edges()
[(2, 1, 'label')]
sage: D.add_edge((1,2),'label')
sage: D.edges()
[(2, 1, 'label'), ((1, 2), 'label', None)]
sage: D.reverse_edge((1,2), 'label')
sage: D.edges()
[(2, 1, 'label'), ('label', (1, 2), None)]
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()
Returns a list of sinks of the digraph.
OUTPUT:
• list, the vertices of the digraph that have no edges beginning at them
EXAMPLES:
sources()
Returns a list of sources of the digraph.
OUTPUT:
• list, 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 compo-
nents. 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()
strongly_connected_component_containing_vertex(G, v)
Returns the strongly connected component containing a given vertex
INPUT:
• G (DiGraph) - the input graph.
• 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]
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’s_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: D.strongly_connected_components()
[['e'], ['b', 'c', 'd'], ['a']]
strongly_connected_components_digraph(G, keep_labels=False)
Returns the digraph of the strongly connected components
INPUT:
• G (DiGraph) - the input graph.
• keep_labels – boolean (default: False)
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
from one to the other in 𝐺.
EXAMPLES:
Such a digraph is always acyclic
sage: g = digraphs.RandomDirectedGNP(15,.1)
sage: scc_digraph = strongly_connected_components_digraph(g)
sage: scc_digraph.is_directed_acyclic()
True
sage: scc_digraph = g.strongly_connected_components_digraph()
sage: scc_digraph.is_directed_acyclic()
True
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: all([ Set(scc) in scc_digraph.vertices() for scc in g.strongly_
˓→connected_components()])
True
The following digraph has three strongly connected components, and the digraph of those is a chain:
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: scc_digraph.vertices(key=sorted)
[{0}, {1, 2}, {3}]
sage: scc_digraph.edges()
[({0}, {1, 2}, '0-12'),
({0}, {3}, '0-3'),
({1, 2}, {1, 2}, '1-2'),
({1, 2}, {1, 2}, '2-1'),
({1, 2}, {3}, '1-3'),
({1, 2}, {3}, '2-3')]
strongly_connected_components_subgraphs(G)
Returns 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: from sage.graphs.connectivity import strongly_connected_components_
˓→subgraphs
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]
to_directed()
Since the graph is already directed, simply returns a copy of itself.
EXAMPLES:
sage: DiGraph({0:[1,2,3],4:[5,1]}).to_directed()
Digraph on 6 vertices
topological_sort(implementation=’default’)
Returns a topological sort of the digraph if it is acyclic, and raises a TypeError if the digraph contains
a directed cycle. 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 – Use the default Cython implementation (implementation = default),
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 graph1).
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()
Returns a list of all topological sorts of the digraph if it is acyclic, and raises a TypeError if the digraph
contains a directed cycle.
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 Graph.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:
sage: B = BipartiteGraph(graphs.CycleGraph(4))
sage: B == B.copy()
True
sage: type(B.copy())
<class 'sage.graphs.bipartite_graph.BipartiteGraph'>
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
(continues on next page)
sage: B = BipartiteGraph(graphs.CycleGraph(4))
sage: B = BipartiteGraph(graphs.CycleGraph(5))
Traceback (most recent call last):
...
TypeError: 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: 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(multiedges=True)
sage: B.allows_multiple_edges()
True
Ensure that we can construct a BipartiteGraph with isolated vertices via the reduced adjacency matrix
(trac ticket #10356):
sage: a=BipartiteGraph(matrix(2,2,[1,0,1,0]))
sage: a
Bipartite graph on 4 vertices
sage: a.vertices()
[0, 1, 2, 3]
sage: g = BipartiteGraph(matrix(4,4,[1]*4+[0]*12))
sage: g.vertices()
[0, 1, 2, 3, 4, 5, 6, 7]
sage: sorted(g.left.union(g.right))
[0, 1, 2, 3, 4, 5, 6, 7]
Make sure that loops are not allowed (trac ticket #23275):
sage: B = BipartiteGraph(loops=True)
Traceback (most recent call last):
...
ValueError: loops are not allowed in bipartite graphs
sage: B = BipartiteGraph(loops=None)
sage: B.allows_loops()
False
sage: B.add_edge(0,0)
Traceback (most recent call last):
...
ValueError: cannot add edge from 0 to 0 in graph without loops
sage: G = BipartiteGraph()
sage: G.add_vertex(left=True)
0
sage: G.add_vertex(right=True)
1
sage: G.vertices()
[0, 1]
sage: G.left
{0}
sage: G.right
{1}
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()
Returns the underlying bipartition of the bipartite graph.
EXAMPLES:
sage: B = BipartiteGraph(graphs.CycleGraph(4))
sage: B.bipartition()
({0, 2}, {1, 3})
complement()
Return a complement of this graph.
EXAMPLES:
delete_vertex(vertex, in_order=False)
Deletes vertex, removing all incident edges. Deleting a non-existent vertex will raise an exception.
INPUT:
• vertex – a vertex to delete.
• in_order – (default False) if True, this deletes the 𝑖-th vertex in the sorted list of vertices, i.e.
G.vertices()[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()
[(1, 2, None), (2, 3, None)]
sage: B.delete_vertex(3)
sage: B.right
{1}
sage: B.edges()
[(1, 2, None)]
sage: B.delete_vertex(0)
Traceback (most recent call last):
...
RuntimeError: 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()
[(1, 2, None)]
sage: B.delete_vertices([0])
Traceback (most recent call last):
...
RuntimeError: Vertex (0) not in the graph.
load_afile(fname)
Loads 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 exam-
ples and definition of the format.
EXAMPLES:
sage: file_name = os.path.join(SAGE_TMP, 'deleteme.alist.txt')
sage: fi = open(file_name, 'w')
sage: _ = fi.write("7 4 \n 3 4 \n 3 3 1 3 1 1 1 \n 3 3 3 4 \n\
1 2 4 \n 1 3 4 \n 1 0 0 \n 2 3 4 \n\
2 0 0 \n 3 0 0 \n 4 0 0 \n\
1 2 3 0 \n 1 4 5 0 \n 2 4 6 0 \n 1 2 4 7 \n")
sage: fi.close()
sage: B = BipartiteGraph()
sage: B.load_afile(file_name)
Bipartite graph on 11 vertices
sage: B.edges()
[(0, 7, None),
(0, 8, None),
(0, 10, None),
(1, 7, None),
(1, 9, None),
(1, 10, None),
(continues on next page)
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)
Computes the matching polynomial.
If 𝑝(𝐺, 𝑘) denotes the number of 𝑘-matchings (matchings with 𝑘 edges) in 𝐺, then the matching polyno-
mial is defined as [Godsil93]:
∑︁
𝜇(𝑥) = (−1)𝑘 𝑝(𝐺, 𝑘)𝑥𝑛−2𝑘
𝑘≥0
INPUT:
• algorithm - a string which must be either “Godsil” (default) or “rook”; “rook” is usually faster for
larger graphs.
• name - optional string for the variable name in the polynomial.
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'))
True
True
sage: g = graphs.RandomTree(20)
sage: p = g.characteristic_polynomial()
sage: p == BipartiteGraph(g).matching_polynomial(algorithm='rook')
True
plot(*args, **kwds)
Overrides 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()
Projects 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()
Projects 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)
reduced_adjacency_matrix(sparse=True)
Return the reduced adjacency matrix for the given graph.
A reduced adjacency matrix contains only the non-redundant portion of the full adjacency matrix for the
bipartite graph. Specifically, for zero matrices of the appropriate size, for the reduced adjacency matrix H,
the full adjacency matrix is [[0, H'], [H, 0]].
This method supports the named argument ‘sparse’ which defaults to True. When enabled, the returned
matrix will be sparse.
EXAMPLES:
Bipartite graphs that are not weighted will return a matrix over ZZ:
Weighted graphs will return a matrix over the ring given by their (first) weights:
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"). Indicating which algorithm to use. It can be one of those
values.
– "Konig" will compute a minimum vertex cover using Konig’s algorithm (Wikipedia article
Kőnig’s_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.
– If algorithm = "mcqd" - Uses 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
applied 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 – (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 sage.numerical.mip.MixedIntegerLinearProgram.solve() of the class
sage.numerical.mip.MixedIntegerLinearProgram.
• verbosity – non-negative integer (default: 0). Set the level of verbosity you want from the linear
program solver. Since the problem of computing a vertex cover 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. This option is only useful if algorithm="MILP".
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
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.
349
Sage Reference Manual: Graph Theory, Release 8.4
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 . . . )
AffineOrthogonalPolarGraphSymplecticDualPolarGraph Nowhere0WordsTwoWeightCodeGraph
AhrensSzekeresGeneralizedQuadrangleGraph
SymplecticPolarGraph HaemersGraph
NonisotropicOrthogonalPolarGraph
TaylorTwographDescendantSRG
CossidentePenttilaGraph
NonisotropicUnitaryPolarGraph
TaylorTwographSRG UnitaryDualPolarGraph
OrthogonalPolarGraph T2starGeneralizedQuadrangleGraph
UnitaryPolarGraph
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
• Nico Van Cleemput (2013-05-26): added fullerenes
• Nico Van Cleemput (2013-07-01): added benzenoids
• Birk Eisermann (2013-07-29): new section ‘intersection graphs’, added (random, bounded) tolerance graphs
• Marco Cognetta (2016-03-03): added TuranGraph
class sage.graphs.graph_generators.GraphGenerators
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 avail-
able 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 posi-
tion dictionary is filled to override the spring-layout algorithm.
ORDERLY GENERATION:
This syntax accesses the generator of isomorphism class representatives. Iterates over distinct, exhaustive rep-
resentatives.
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
generated 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.
• implementation – (default: 'c_graph') which underlying implementation to use (see Graph?).
• sparse – (default: True) ignored if implementation is not 'c_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:
Note that we can also get graphs with underlying Cython implementation:
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=’+’)
Returns 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 – must be equal to "+", "-", or None to compute (respectively) 𝑉 𝑂+ (𝑑, 𝑞), 𝑉 𝑂− (𝑑, 𝑞) or
𝑉 𝑂(𝑑, 𝑞). By default sign="+".
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)
REFERENCE:
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 – 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
static Balaban11Cage(embedding=1)
Return the Balaban 11-cage.
For more information, see the Wikipedia article Balaban_11-cage.
INPUT:
• embedding – 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:
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: n1 = randint(2, 2*10^2)
sage: n2 = randint(0, 2*10^2)
sage: g = graphs.BarbellGraph(n1, n2)
sage: v = 2*n1 + n2
sage: g.order() == v
True
sage: K_n1 = graphs.CompleteGraph(n1)
(continues on next page)
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: bool(g.characteristic_polynomial() == expand((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 – 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 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()
(continues on next page)
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()
Create 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: g = graphs.BuckyBall()
sage: g.plot(vertex_labels=False, vertex_size=10).show() # long time
static BullGraph()
Returns 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()
Returns 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
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: CFI.vertices()
[(0, ()), (0, (0, 1)), (0, (0, 'a')), (0, (0, 'b')),
(0, (1, 'a')), (0, (1, 'b')), (1, ()), (1, (0, 1)),
(1, (0, 'a')), (1, (0, 'b')), (1, (1, 'a')), (1, (1, 'b')),
(2, ()), (2, (0, 1)), (2, (0, 'a')), (2, (0, 'b')),
(2, (1, 'a')), (2, (1, 'b')), (3, ()), (3, (0, 1)),
(3, (0, 'a')), (3, (0, 'b')), (3, (1, 'a')), (3, (1, 'b'))]
sage: CFI.edges()
[((0, ()), (0, (0, 'b')), None),
((0, ()), (0, (1, 'b')), None),
((0, (0, 1)), (0, (0, 'a')), None),
((0, (0, 1)), (0, (1, 'a')), None),
((0, (0, 'a')), (1, (0, 'a')), None),
((0, (0, 'b')), (1, (0, 'b')), 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),
((1, (0, 1)), (1, (0, 'a')), None),
((1, (0, 1)), (1, (1, 'a')), None),
((1, (1, 'a')), (2, (0, 'a')), None),
((1, (1, 'b')), (2, (0, 'b')), None),
((2, ()), (2, (0, 'b')), None),
((2, ()), (2, (1, 'b')), None),
((2, (0, 1)), (2, (0, 'a')), None),
((2, (0, 1)), (2, (1, 'a')), None),
((2, (1, 'a')), (3, (1, 'a')), None),
((2, (1, 'b')), (3, (1, 'b')), None),
((3, ()), (3, (0, 'b')), None),
((3, ()), (3, (1, 'b')), None),
((3, (0, 1)), (3, (0, 'a')), None),
((3, (0, 1)), (3, (1, 'a')), None)]
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 (1 (default) or 2) – two different embeddings for a plot.
EXAMPLES:
INPUT:
• dim_list – an iterable object (list, set, dict) providing the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1,
of the chessboard.
• rook – (default: True) boolean value indicating if the chess piece is able to move as a rook, that is
at any distance along a dimension.
• rook_radius – (default: None) integer value restricting the rook-like movements to distance at
most 𝑟𝑜𝑜𝑘𝑟 𝑎𝑑𝑖𝑢𝑠.
• bishop – (default: True) boolean value indicating if the chess piece is able to move like a bishop,
that is along diagonals.
• bishop_radius – (default: None) integer value restricting the bishop-like movements to distance
at most 𝑏𝑖𝑠ℎ𝑜𝑝𝑟 𝑎𝑑𝑖𝑢𝑠.
• knight – (default: True) boolean value indicating if the chess piece is able to move like a knight.
• knight_x – (default: 1) integer indicating the number on steps the chess piece moves in one dimen-
sion when moving like a knight.
• knight_y – (default: 2) integer indicating the number on steps the chess piece moves in the second
dimension when moving like a knight.
• relabel – (default: False) a boolean set to True if 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: 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 m, n, there
is an m-regular, m-chromatic graph of girth at least n. 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 construc-
tor, 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)
(continues on next page)
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 = sage.plot.graphics.GraphicsArray(j)
sage: G.show() # long time
sage: graphs.CirculantGraph(6,1)==graphs.CycleGraph(6)
True
sage: graphs.CirculantGraph(7,[1,3]).edges(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)]
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 al-
gorithm. 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)‘𝑡ℎ𝑛𝑜𝑑𝑒𝑎𝑡𝑡ℎ𝑒𝑡𝑜𝑝, 𝑡ℎ𝑒𝑛𝑐𝑜𝑢𝑛𝑡𝑒𝑟𝑐𝑙𝑜𝑐𝑘𝑤𝑖𝑠𝑒𝑎𝑠𝑤𝑒𝑙𝑙.𝑊 ℎ𝑒𝑛‘𝑛 == 2, 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 = sage.plot.graphics.GraphicsArray(j)
sage: G.show() # long time
static ClawGraph()
Returns 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:
sage: spring_med.show() # long time
sage: posdict_med.show() # long time
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 = sage.plot.graphics.GraphicsArray(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 = sage.plot.graphics.GraphicsArray(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 n 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 = sage.plot.graphics.GraphicsArray(j)
sage: G.show() # long time
We compare plotting:
static CompleteMultipartiteGraph(l)
Returns a complete multipartite graph.
INPUT:
• l – a list of integers : the respective sizes of the components.
EXAMPLES:
A complete tripartite graph with sets of sizes 5, 6, 8:
sage: g.chromatic_number()
3
static CossidentePenttilaGraph(q)
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 quadrange 𝐺𝑄(𝑞, 𝑞 2 )
into two parts, so that on any of them the induced subgraph of the point graph of the GQ has parameters
as above [CP05].
Directly following the construction in [CP05] 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.
REFERENCES:
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 CubeGraph(n)
Returns 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.
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 = sage.plot.graphics.GraphicsArray(j)
sage: G.show(figsize=[6,4]) # long time
sage: g = graphs.CubeGraph(9)
sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20) # long time
AUTHORS:
• Robert Miller
static CycleGraph(n)
Return a cycle graph with n 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 = []
(continues on next page)
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 = sage.plot.graphics.GraphicsArray(j)
sage: G.show() # long time
static DegreeSequence(deg_sequence)
Returns a graph with the given degree sequence. 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 [CharLes1996].
INPUT:
• deg_sequence - a 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(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
REFERENCE:
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]
Note: as of this writing, plotting of loops and multiple edges is not supported, and the output is allowed to
contain both types of edges.
sage: G = graphs.DegreeSequenceConfigurationModel([3,3,3,3,3,3,3,3,3,3,3,3,3,
˓→3,3,3,3,3,3,3])
sage: len(G.edges())
30
sage: G.show() # long time
REFERENCE:
static DegreeSequenceExpected(deg_sequence, seed=None)
Returns a random graph with expected given degree sequence. 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 - a list of integers with each entry corresponding to the expected degree of a differ-
ent vertex.
• seed - for the random number generator.
EXAMPLES:
sage: G = graphs.DegreeSequenceExpected([1,2,3,2,3])
sage: G.edges(labels=False)
[(0, 2), (0, 3), (1, 1), (1, 4), (2, 3), (2, 4), (3, 4), (4, 4)]
sage: G.show() # long time
REFERENCE:
static DegreeSequenceTree(deg_sequence)
Returns a tree with the given degree sequence. 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 - a list of integers with each entry corresponding to the expected degree of a differ-
ent vertex.
EXAMPLES:
sage: G = graphs.DegreeSequenceTree([3,1,3,3,1,1,1,2,1])
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
(continues on next page)
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()
Returns 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()
Returns 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 chose to use the default
spring-layout algorithm here, so that multiple iterations might yield a different point of reference for the
user. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a string argument will
be added to select the flat spring-layout over a future implementation.
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 = sage.plot.graphics.GraphicsArray(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 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 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
(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).
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()
Returns 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.
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
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
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)
Returns the graph of the Fibonacci Tree 𝐹𝑖 of order 𝑛. 𝐹𝑖 is recursively defined as the a 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.
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 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)
(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
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):
....: g = graphs.FriendshipGraph(i + 1)
....: A.append(g)
sage: for i in range(3):
....: n = []
(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 𝑛 ≥ 1, 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 it is
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:
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: graphs.FuzzyBallGraph([3,1],2).adjacency_matrix()
[0 1 1 1 1 1 1 0]
[1 0 1 1 1 1 1 0]
[1 1 0 1 1 1 1 0]
[1 1 1 0 1 1 0 1]
[1 1 1 1 0 1 0 0]
[1 1 1 1 1 0 0 0]
[1 1 1 0 0 0 0 0]
[0 0 0 1 0 0 0 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 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
AUTHORS:
• Anders Jonsson (2009-10-15)
static GoethalsSeidelGraph(k, r)
Returns the graph Goethals-Seidel(𝑘, 𝑟).
The graph Goethals-Seidel(𝑘, 𝑟) comes from a construction presented in Theorem 2.4 of [GS70]. It re-
lies 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
(continues on next page)
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 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
static GrayGraph(embedding=1)
Return the Gray graph.
See the Wikipedia article Gray_graph.
INPUT:
• embedding – 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
(continues on next page)
sage: g = graphs.Grid2dGraph(5,7)
sage: g.show() # long time
static GridGraph(dim_list)
Returns an n-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
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()
(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: 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 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) – 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. It is set to True
by default.
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
[ARETT-DOREE].
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.
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.
sage: H = graphs.HanoiTowerGraph(3,4,labels=False,positions=False)
sage: H.automorphism_group().is_isomorphic(SymmetricGroup(3))
True
sage: H.chromatic_number()
3
sage: len(H.independent_set()) == 3^(4-1)
True
Citations
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 Har-
ries_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 – 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 – 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.HarriesWongGraph(embedding=2).show()
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). It is nonplanar and Hamiltonian. It has diameter = 3, radius = 3, girth = 6, 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 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()
Returns 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 chose to use the default spring-
layout algorithm here, so that multiple iterations might yield a different point of reference for the user. We
hope to add rotatable, 3-dimensional viewing in the future. In such a case, a string argument will be added
to select the flat spring-layout over a future implementation.
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))
(continues on next page)
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 ex-
ample, 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 - default: True. If True the vertices will be labeled with consecutive integers. If False
the labels are strings that are three digits long. “xyz” means the vertex is in group x (zero through
three), pentagon or pentagram y (zero through four), and is vertex z (zero through four) of that pen-
tagon 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:
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.
sage: HS.layout()[1]
(-0.844..., 0.535...)
sage: graphs.HoffmanSingletonGraph().layout()[1]
(-0.904..., 0.425...)
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()
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
static HouseGraph()
Returns 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()
Returns 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)
Returns the hyper-star graph HS(n,k).
The vertices of the hyper-star graph are the set of binary strings of length n which contain k 1s. Two
vertices, u and v, are adjacent only if u can be obtained from v by swapping the first bit with a different
symbol in another position.
INPUT:
• n
• k
EXAMPLES:
sage: g = graphs.HyperStarGraph(6,3)
sage: g.plot() # long time
Graphics object consisting of 51 graphics primitives
REFERENCES:
• Lee, Hyeong-Ok, Jong-Seok Kim, Eunseuk Oh, and Hyeong-Seok Lim. “Hyper-Star Graph: A New
Interconnection Network Improving the Network Cost of the Hypercube.” In Proceedings of the First
EurAsian Conference on Information and Communication Technology, 858-865. Springer-Verlag,
2002.
AUTHORS:
• Michael Yurko (2009-09-01)
static IcosahedralGraph()
Returns 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 chose to use the default spring-
layout algorithm here, so that multiple iterations might yield a different point of reference for the user. We
hope to add rotatable, 3-dimensional viewing in the future. In such a case, a string argument will be added
to select the flat spring-layout over a future implementation.
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 = sage.plot.graphics.GraphicsArray(j)
sage: G.show() # long time
static IntersectionGraph(S)
Returns 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
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,
⎪
1 if 𝑖 = 17, 𝑗 ̸= 17,
⎨
𝑤𝑖𝑗 =
⎪
⎪ 1 if 𝑖 ̸= 17, 𝑗 = 17,
0 if 𝑖 = 𝑗 = 17
⎩
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
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:
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 adjacen-
cies 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
All 2-dimensional King Graphs are Hamiltonian, biconnected, and have chromatic number 4 as soon as
both dimensions are larger or equal to 2.
INPUT:
• dim_list – an iterable object (list, set, dict) providing the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1,
of the chessboard.
• radius – (default: None) by setting the radius to a positive integer, one may increase the power
of the king to at least radius steps. When the radius equals the higher size of the dimensions, the
resulting graph is a Queen Graph.
• relabel – (default: False) a boolean set to True if vertices must be relabeled as integers.
EXAMPLES:
The (2, 2)-King Graph is isomorphic to the complete graph on 4 vertices:
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
sage: g.chromatic_number()
3
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: print(KG.vertices())
[{4, 5}, {1, 3}, {2, 5}, {2, 3}, {3, 4}, {3, 5}, {1, 4}, {1, 5}, {1, 2}, {2,
˓→4}]
sage: P=graphs.PetersenGraph()
sage: P.is_isomorphic(KG)
True
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 so-
cial networks (see [Kre2002] and the Wikipedia article Krackhardt_kite_graph). It is used to show the
distinction between: degree centrality, betweeness centrality, and closeness centrality. For more informa-
tion 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
LCF (Lederberg-Coxeter-Fruchte) notation is a concise way of describing cubic Hamiltonian graphs. The
way a graph is constructed is as follows. Since there is a Hamiltonian cycle, we first create a cycle
on n nodes. The 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.
static LadderGraph(n)
Returns a ladder graph with 2*n 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
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 = sage.plot.graphics.GraphicsArray(j)
sage: G.show() # long time
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 – 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()
(continues on next page)
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 ob-
tained from McLaughlinGraph() by considering the stabilizer of a point: one of its orbits has cardi-
nality 162.
EXAMPLES:
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 [BvL84].
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()
See also:
• 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()
sage: r=list(map(lambda z: matrix(libgap.PermutationMat(libgap(z),9).sage()),
....: filter(lambda x: x.order()==9, a.normal_
˓→subgroups())[0]))
REFERENCES:
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 – 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()
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
(continues on next page)
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 this MathWorld article on the 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
The Moser spindle has chromatic number 4 and its automorphism group is isomorphic to the dihedral
group 𝐷4 .
sage: G.chromatic_number()
4
sage: ag = G.automorphism_group()
sage: ag.is_isomorphic(DihedralGroup(4))
True
• is_muzychuk_S6()
Todo: Implement the possibility to explicitly supply the parameter Σ of the construction.
EXAMPLES:
REFERENCE:
static 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
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.” Informa-
tion 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 – 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()
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
(continues on next page)
𝑁 𝑂+ (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
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)
Returns the Graph 𝑁 𝑈 (𝑚, 𝑞).
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 [BH12] and series C14 in [Hu75].
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)
REFERENCE:
static 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
𝐶 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
[AB16], and leads to graphs with parameters also given by a construction in [HHL09]. According to
[AB16], 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 – (default: True) if True, check hyperoval for correctness.
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)
REFERENCES:
static OctahedralGraph()
Returns 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 chose to use the default spring-
layout algorithm here, so that multiple iterations might yield a different point of reference for the user. We
hope to add rotatable, 3-dimensional viewing in the future. In such a case, a string argument will be added
to select the flat spring-layout over a future implementation.
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 = sage.plot.graphics.GraphicsArray(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. Equiva-
lently, 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: print(OG.vertices())
[{4, 5}, {1, 3}, {2, 5}, {2, 3}, {3, 4}, {3, 5}, {1, 4}, {1, 5}, {1, 2}, {2,
˓→4}]
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:
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 com-
pute 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)
(continues on next page)
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 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
(continues on next page)
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 [Pa92].
See also:
• is_orthogonal_array_block_graph()
EXAMPLES:
sage: graphs.PasechnikGraph(4).is_strongly_regular(parameters=True)
(225, 98, 43, 42)
sage: graphs.PasechnikGraph(9).is_strongly_regular(parameters=True) # long
˓→time
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])
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(labels=False)
sage: set(edges) == set(p.inverse().inversions())
True
sage: PG = graphs.PermutationGraph([3,4,5,1,2])
sage: sorted(PG.edges())
[(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())
[(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())
[(1, 3, None),
(1, 4, None),
(1, 5, None),
(continues on next page)
sage: graphs.PermutationGraph([]).edges()
[]
sage: graphs.PermutationGraph([], []).edges()
[]
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 [x,y] 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 2-dimensional Queen 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 queen.
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 dimen-
sions.
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 – an iterable object (list, set, dict) providing the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1,
of the chessboard.
• radius – (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 – (default: False) a boolean set to True if 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:
sage: graphs.RandomBarabasiAlbert(6,2).edges(labels=False)
[(0, 2), (0, 3), (0, 4), (1, 2), (2, 3), (2, 4), (2, 5), (3, 5)]
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 = sage.plot.graphics.GraphicsArray(j)
sage: G.show() # long time
static RandomBicubicPlanar(n)
Return the graph of a random bipartite cubic map with 3𝑛 edges.
INPUT:
𝑛 – an integer (at least 1)
OUTPUT:
a graph with multiple edges (no embedding is provided)
The algorithm used is described in [Schaeffer99]. This samples a random rooted bipartite cubic map,
chosen uniformly 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:
REFERENCES:
static RandomBipartite(n1, n2, p, set_position=False)
Returns a bipartite graph with 𝑛1 + 𝑛2 vertices such that any edge from [𝑛1] to [𝑛2] exists with probability
𝑝.
INPUT:
• n1, n2 – Cardinalities of the two sets
• p – Probability for an edge to exist
• 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.
EXAMPLES:
• blocks_and_cut_vertices()
• blocks_and_cuts_tree()
• IncidenceStructure()
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.
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
static RandomBoundedToleranceGraph(n)
Returns 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 then or equal to the length
of the interval 𝐼𝑖 . The width of the representation is limited to n**2 * 2**n.
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.
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
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 = sage.plot.graphics.GraphicsArray(j)
sage: G.show() # long time
REFERENCE:
static RandomIntervalGraph(n)
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 [boucheron2001].
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.
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:
static 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 – integer seed for random number generator (default None).
EXAMPLES: We show the edge list of a random graph with 3 backbone nodes and probabilities 𝑝 = 0.7
and 𝑞 = 0.3:
REFERENCE:
static RandomRegular(d, n, seed=None)
Return a random d-regular graph on n vertices, or returns False on failure.
Since every edge is incident to two vertices, n*d must be even.
INPUT:
• n - number of vertices
• d - degree
• seed – integer seed for random number generator (default None).
EXAMPLES: We show the edge list of a random graph with 8 nodes each of degree 3.
REFERENCES:
static RandomRegularBipartite(n1, n2, d1, set_position=False)
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.
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.edges(labels=False)
[(0, 3), (0, 7), (0, 8), (1, 2), (1, 5), (1, 8), (1, 9), (3, 6), (3, 11), (4,
˓→6), (4, 7), (4, 8), (4, 21), (5, 8), (5, 9), (6, 9), (6, 10), (7, 8), (7,
˓→9), (8, 18), (10, 11), (10, 13), (10, 19), (10, 22), (10, 26), (11, 18),
˓→(11, 26), (11, 28), (12, 13), (12, 14), (12, 28), (12, 29), (13, 16), (13,
˓→21), (13, 29), (14, 18), (16, 20), (17, 18), (17, 26), (17, 28), (18, 19),
˓→(18, 22), (18, 27), (18, 28), (19, 23), (19, 25), (19, 28), (20, 22), (24,
static RandomToleranceGraph(n)
Returns 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 n**2 * 2**n.
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.
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
static RandomTree(n)
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
EXAMPLES:
sage: G = graphs.RandomTree(10)
sage: G.is_tree()
True
sage: G.show() # long time
sage: G = graphs.RandomTreePowerlaw(15, 2)
sage: if G:
....: G.show() # random output, long time
in1,in2,in3,lf,in3 by in1,in3. After all local closures are done, one has reached the partial
closure, as in [PS2006], figure 5 (a).
Then one has to perform complete closure by adding two more vertices, in order to reach the situation of
[PS2006], figure 5 (b). For this, it is necessary to find inside the final contour one of the two subsequences
lf,in,lf.
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:
REFERENCES:
static 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 𝑣 = ‘2𝑖+1 − 1.
Ringed trees are defined in [CFHM12].
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()
['', '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']
REFERENCES:
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
sage: G.is_isomorphic( H )
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 pa-
rameters.
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 pa-
rameters.
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())
(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:
There is another familly of graphs called Sierpinski graphs, where all vertices but 3 have valence 3. They
are available using graphs.HanoiTowerGraph(3, n).
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:
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
the corresponding Wikipedia page (in French).
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()
(continues on next page)
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 [BvL84].
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 = sage.plot.graphics.GraphicsArray(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 = sage.plot.graphics.GraphicsArray(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 [Hu75].
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 [BH12]) 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)
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)
Returns the Symplectic Dual Polar Graph 𝐷𝑆𝑝(𝑚, 𝑞).
For more information on Symplectic Dual Polar graphs, see [BCN1989] and Sect. 2.3.1 of [Co81].
INPUT:
• m,q (integers) – 𝑞 must be a prime power, and 𝑚 must be even.
EXAMPLES:
REFERENCE:
static SymplecticPolarGraph(d, q, algorithm=None)
Returns 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 – 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)
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
• q – a power of two
• dual – if False (default), return the graph of 𝑇2* (𝑂). Otherwise return the graph of the dual 𝑇2* (𝑂).
• 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 – (default: True) if True, check hyperoval for correctness.
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]
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 [BvL84].
INPUT:
• q – a power of an odd prime number
• clique_partition – if 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)
static TaylorTwographSRG(q)
constructing 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 [BvL84].
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()
Returns 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 chose to use the default spring-
layout algorithm here, so that multiple iterations might yield a different point of reference for the user. We
hope to add rotatable, 3-dimensional viewing in the future. In such a case, a string argument will be added
to select the flat spring-layout over a future implementation.
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 al-
gorithm 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’s_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)
Returns 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 positive value, called toler-
ance. This representation generates the tolerance graph with the vertex set {0,1, . . . , k} 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, . . . , k. 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:
INPUT:
• n1, n2 (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 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 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
2
The Turan graph 𝑇 (𝑛, 𝑟) has ⌊ (𝑟−1)(𝑛
2𝑟
)
⌋ edges.
sage: n = 13
sage: r = 4
sage: g = graphs.TuranGraph(n,r)
sage: g.size() == floor((r-1)*(n**2)/(2*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()
6
sage: g.show()
static TutteCoxeterGraph(embedding=2)
Return the Tutte-Coxeter graph.
See the Wikipedia article Tutte-Coxeter_graph.
INPUT:
• embedding – 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()
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 [COCO].
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, a Boolean – if set, exclude Alaska and Hawaii
EXAMPLES:
How many states are neighbor’s neighbor for Pennsylvania:
static UnitaryDualPolarGraph(m, q)
Returns the Dual Unitary Polar Graph 𝑈 (𝑚, 𝑞).
For more information on Unitary Dual Polar graphs, see [BCN1989] and Sect. 2.3.1 of [Co81].
INPUT:
• m,q (integers) – 𝑞 must be a prime power.
EXAMPLES:
The point graph of a generalized quadrangle (see [GQwiki], [PT09]) 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.UnitaryDualPolarGraph(6,2); G # not tested (long time)
Unitary Dual Polar Graph DU(6, 2): Graph on 891 vertices
sage: G.is_distance_regular(parameters=True) # not tested (long time)
([42, 40, 32, None], [None, 1, 5, 21])
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()
(continues on next page)
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 in-
termediate 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
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 = []
(continues on next page)
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 its (french) Wikipedia page.
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
static WorldMap()
Returns 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
(continues on next page)
REFERENCE:
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(),
....: [(0,1,None),(2,3,None),(4,5,None),(6,7,None)],
....: K8.subgraph_search(c3c5).edges()]
sage: list(map(lambda x,G: T8.seidel_switching(x, inplace=False).is_
˓→isomorphic(G),
....: s, chang_graphs))
[True, True, 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 pa-
rameters.
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:
True
fullerenes(order, ipr=False)
Returns a generator which creates fullerene graphs using the buckygen generator (see [buckygen]).
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:
REFERENCE:
fusenes(hexagon_count, benzenoids=False)
Returns a generator which creates fusenes and benzenoids using the benzene generator (see [benzene]).
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 naphtalene (C10 H8 ). In the fusene graph the H-atoms are not stored, so this is a graph on
just 10 vertices:
REFERENCE:
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]
nauty_geng(options=”, debug=False)
Returns a generator which creates graphs from nauty’s geng program.
INPUT:
• options - 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 - 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:
n : the number of vertices
mine:maxe : a range for the number of edges
#:0 means '# or more' except in the case 0:0
res/mod : only generate subset res out of subsets 0..mod-1
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 pa-
rameters.
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
supress the indicator of a successful initiation.
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,
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
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 con-
nectivity will be generated. This option cannot be used with minimum_connectivity=3, or if
the minimum connectivity is not explicitely set.
• 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:
sage: gen = graphs.planar_graphs(4) # optional plantri
sage: len(list(gen)) # optional plantri
6
The cycle of length 4 is the only 2-connected bipartite planar graph on 4 vertices:
sage: l = list(graphs.planar_graphs(4, minimum_connectivity=2, only_
˓→bipartite=True)) # optional plantri
sage: l[0].get_embedding() # optional plantri
{1: [2, 3],
2: [1, 4],
3: [1, 4],
4: [2, 3]}
There is one planar graph with one vertex. This graph obviously has minimum degree equal to 0:
sage: list(graphs.planar_graphs(1)) # optional plantri
[Graph on 1 vertex]
sage: list(graphs.planar_graphs(1, minimum_degree=1)) # optional plantri
[]
REFERENCE:
quadrangulations(order, minimum_degree=None, minimum_connectivity=None,
no_nonfacial_quadrangles=False, dual=False)
An iterator over planar quadrangulations using the plantri generator.
This uses the plantri generator (see [plantri]) which is available through the optional package plantri.
INPUT:
• order - a positive integer smaller than or equal to 64. This specifies the number of vertices in the
generated quadrangulations.
• minimum_degree - default: None - a value ≥ 2 and ≤ 3, or None. This specifies the minimum
degree of the generated quadrangulations. 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 2.
• minimum_connectivity - default: None - a value ≥ 2 and ≤ 3, or None. This speci-
fies the minimum connectivity of the generated quadrangulations. If this is None and the option
no_nonfacial_quadrangles is set to True, then this is set to 3. Otherwise if this is None
and the minimum degree is specified, then this is set to the minimum degree. If the minimum degree
is also equal to None, then this is set to 3.
• no_nonfacial_quadrangles - default: False - if True only quadrangulations with no non-
facial quadrangles are generated. This option cannot be used if minimum_connectivity is set to
2.
• dual - default: False - if True return instead the planar duals of the generated graphs.
OUTPUT:
An iterator which will produce all planar quadrangulations 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).
See also:
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:
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> and <a
href="srgtabrefs.html#KaskiOstergard07">Kaski & stergrd</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.
See also:
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
The best way to access this function is through the graphs() iterator:
Print graphs on 3 or less vertices.
INPUT:
• g - current position on the tree.
• aut_gens - list of generators of Aut(g), in list notation.
• max_verts - when to retreat.
• property - check before traversing below g.
• degree_sequence - specify a degree sequence to try to obtain.
EXAMPLES:
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:
At the start, check_aut_edge 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_edge to {i, j}, 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)
class sage.graphs.digraph_generators.DiGraphGenerators
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
will generate all digraphs with that property. If this does not hold, then all the digraphs generated will
satisfy the property, but there will be some missing.
• implementation - which underlying implementation to use (see DiGraph?)
• sparse - ignored if implementation is not c_graph
EXAMPLES: Print digraphs on 2 or less vertices.
Note that we can also get digraphs with underlying Cython implementation:
REFERENCE:
• Brendan D. McKay, Isomorph-Free Exhaustive generation. Journal of Algorithms Volume 26, Issue 2,
February 1998, pages 306-324.
ButterflyGraph(n, vertices=’strings’)
Returns a n-dimensional butterfly graph. The vertices consist of pairs (v,i), where v is an n-dimensional
tuple (vector) with binary entries (or a string representation of such) and i is an integer in [0..n]. A directed
edge goes from (v,i) to (w,i+1) if v and w are identical except for possibly v[i] != w[i].
A butterfly graph has (2𝑛 )(𝑛 + 1) vertices and 𝑛2𝑛+1 edges.
INPUT:
• vertices - ‘strings’ (default) or ‘vectors’, specifying whether the vertices are zero-one strings or
actually tuples over GF(2).
EXAMPLES:
sage: digraphs.ButterflyGraph(2).edges(labels=False)
[(('00', 0), ('00', 1)),
(('00', 0), ('10', 1)),
(('00', 1), ('00', 2)),
(('00', 1), ('01', 2)),
(('01', 0), ('01', 1)),
(('01', 0), ('11', 1)),
(('01', 1), ('00', 2)),
(('01', 1), ('01', 2)),
(('10', 0), ('00', 1)),
(('10', 0), ('10', 1)),
(('10', 1), ('10', 2)),
(('10', 1), ('11', 2)),
(('11', 0), ('01', 1)),
(('11', 0), ('11', 1)),
(('11', 1), ('10', 2)),
(('11', 1), ('11', 2))]
sage: digraphs.ButterflyGraph(2,vertices='vectors').edges(labels=False)
[(((0, 0), 0), ((0, 0), 1)),
(((0, 0), 0), ((1, 0), 1)),
(((0, 0), 1), ((0, 0), 2)),
(((0, 0), 1), ((0, 1), 2)),
(((0, 1), 0), ((0, 1), 1)),
(((0, 1), 0), ((1, 1), 1)),
(((0, 1), 1), ((0, 0), 2)),
(((0, 1), 1), ((0, 1), 2)),
(((1, 0), 0), ((0, 0), 1)),
(((1, 0), 0), ((1, 0), 1)),
(((1, 0), 1), ((1, 0), 2)),
(((1, 0), 1), ((1, 1), 2)),
(((1, 1), 0), ((0, 1), 1)),
(((1, 1), 0), ((1, 1), 1)),
(continues on next page)
Circuit(n)
Returns the circuit on 𝑛 vertices
The circuit is an oriented CycleGraph
EXAMPLES:
A circuit is the smallest strongly connected digraph:
sage: circuit = digraphs.Circuit(15)
sage: len(circuit.strongly_connected_components()) == 1
True
Circulant(n, integers)
Returns a circulant digraph on 𝑛 vertices from a set of integers.
INPUT:
• n (integer) – number of vertices.
• integers – the list of integers such that there is an edge from 𝑖 to 𝑗 if and only if (j-i)%n in
integers.
EXAMPLES:
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) – 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’)
Returns 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 – An integer equal to the length of words in the De Bruijn digraph when vertices ==
'strings', and also to the diameter of the digraph.
• vertices – ‘strings’ (default) or ‘integers’, specifying whether the vertices are words build upon
an alphabet or integers.
EXAMPLES:
de Bruijn digraph of degree 2 and diameter 2:
GeneralizedDeBruijn(n, d)
Returns the generalized de Bruijn digraph of order 𝑛 and degree 𝑑.
The generalized de Bruijn digraph has been defined in [RPK80] [RPK83]. 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 – is the number of vertices of the digraph
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'})
REFERENCES:
ImaseItoh(n, d)
Returns the digraph of Imase and Itoh of order 𝑛 and degree 𝑑.
The digraph of Imase and Itoh has been defined in [II83]. 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 digraph of Imase and Itoh is isomorphic to the de Bruijn digraph of degree 𝑑 and
diameter 𝐷. When 𝑛 = 𝑑𝐷−1 (𝑑 + 1), the digraph of Imase and Itoh is isomorphic to the Kautz digraph
[Kautz68] of degree 𝑑 and diameter 𝐷.
INPUT:
• n – is the number of vertices of the digraph
• d – is the degree of the digraph
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: II.is_isomorphic(digraphs.Kautz(2, 3), certificate = True)
(True, {0: '010', 1: '012', 2: '021', 3: '020', 4: '202', 5: '201', 6: '210',
˓→7: '212', 8: '121', 9: '120', 10: '102', 11: '101'})
REFERENCE:
Kautz(k, D, vertices=’strings’)
Returns the Kautz digraph of degree 𝑑 and diameter 𝐷.
The Kautz digraph has been defined in [Kautz68]. The Kautz digraph of degree 𝑑 and diameter 𝐷 has
𝑑𝐷−1 (𝑑 + 1) vertices. This digraph is build upon a set of vertices equal to the set of words of length 𝐷
from an alphabet of 𝑑 + 1 letters such that consecutive letters are differents. 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 digraph of Imase and Itoh [II83] of
degree 𝑑 and order 𝑑𝐷−1 (𝑑 + 1).
See the Wikipedia article Kautz_graph for more information.
INPUT:
sage: K = digraphs.Kautz(2, 3)
sage: K.is_isomorphic(digraphs.ImaseItoh(12, 2), certificate = True)
(True,
{'010': 0,
'012': 1,
'020': 3,
'021': 2,
'101': 11,
'102': 10,
'120': 9,
'121': 8,
'201': 5,
'202': 4,
'210': 6,
'212': 7})
sage: K = digraphs.Kautz([1,'a','B'], 2)
sage: K.edges()
[('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()
[('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',
REFERENCE:
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)
Returns a directed path on 𝑛 vertices.
INPUT:
• n (integer) – number of vertices in the path.
EXAMPLES:
sage: g = digraphs.Path(5)
sage: g.vertices()
[0, 1, 2, 3, 4]
sage: g.size()
4
sage: g.automorphism_group().cardinality()
1
sage: D = digraphs.RandomDirectedGN(25)
sage: D.edges(labels=False)
[(1, 0), (2, 0), (3, 1), (4, 0), (5, 0), (6, 1), (7, 0), (8, 3), (9, 0), (10,
˓→8), (11, 3), (12, 9), (13, 8), (14, 0), (15, 11), (16, 11), (17, 5), (18,
˓→11), (19, 6), (20, 5), (21, 14), (22, 5), (23, 18), (24, 11)]
REFERENCE:
• [1] Krapivsky, P.L. and Redner, S. Organization of Growing Random Networks, Phys. Rev. E vol. 63
(2001), p. 066123.
RandomDirectedGNC(n, seed=None)
Returns a random GNC (growing network with copying) digraph with n 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.
INPUT:
• n - number of vertices.
• seed - for the random number generator
EXAMPLES:
sage: D = digraphs.RandomDirectedGNC(25)
sage: D.edges(labels=False)
[(1, 0), (2, 0), (2, 1), (3, 0), (4, 0), (4, 1), (5, 0), (5, 1), (5, 2), (6,
˓→0), (6, 1), (7, 0), (7, 1), (7, 4), (8, 0), (9, 0), (9, 8), (10, 0), (10,
˓→1), (10, 2), (10, 5), (11, 0), (11, 8), (11, 9), (12, 0), (12, 8), (12, 9),
˓→(13, 0), (13, 1), (14, 0), (14, 8), (14, 9), (14, 12), (15, 0), (15, 8),
˓→(15, 9), (15, 12), (16, 0), (16, 1), (16, 4), (16, 7), (17, 0), (17, 8),
˓→(17, 9), (17, 12), (18, 0), (18, 8), (19, 0), (19, 1), (19, 4), (19, 7),
˓→(20, 0), (20, 1), (20, 4), (20, 7), (20, 16), (21, 0), (21, 8), (22, 0),
˓→(22, 1), (22, 4), (22, 7), (22, 19), (23, 0), (23, 8), (23, 9), (23, 12),
˓→(23, 14), (24, 0), (24, 8), (24, 9), (24, 12), (24, 15)]
REFERENCE:
• [1] Krapivsky, P.L. and Redner, S. Network Growth by Copying, Phys. Rev. E vol. 71 (2005), p.
036118.
RandomDirectedGNM(n, m, loops=False)
Returns a random labelled digraph on 𝑛 nodes and 𝑚 arcs.
INPUT:
• n (integer) – number of vertices.
• m (integer) – number of edges.
• loops (boolean) – whether to allow loops (set to False by default).
PLOTTING: When plotting, this graph will use the default spring-layout algorithm, unless a position
dictionary is specified.
EXAMPLES:
sage: D = digraphs.RandomDirectedGNM(10, 5)
sage: D.num_verts()
10
sage: D.edges(labels=False)
[(0, 3), (1, 5), (5, 1), (7, 0), (8, 5)]
With loops:
sage: set_random_seed(0)
sage: D = digraphs.RandomDirectedGNP(10, .2)
sage: D.num_verts()
10
sage: D.edges(labels=False)
[(1, 0), (1, 2), (3, 6), (3, 7), (4, 5), (4, 7), (4, 8), (5, 2), (6, 0), (7,
˓→2), (8, 1), (8, 9), (9, 4)]
RandomDirectedGNR(n, p, seed=None)
Returns a random GNR (growing network with redirection) digraph with n vertices and redirection proba-
bility p.
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.
INPUT:
• n - number of vertices.
• p - redirection probability
• seed - for the random number generator.
EXAMPLES:
˓→1), (10, 2), (10, 5), (11, 0), (11, 8), (11, 9), (12, 0), (12, 8), (12, 9),
˓→(13, 0), (13, 1), (14, 0), (14, 8), (14, 9), (14, 12), (15, 0), (15, 8),
˓→(15, 9), (15, 12), (16, 0), (16, 1), (16, 4), (16, 7), (17, 0), (17, 8),
˓→(17, 9), (17, 12), (18, 0), (18, 8), (19, 0), (19, 1), (19, 4), (19, 7),
˓→(20, 0), (20, 1), (20, 4), (20, 7), (20, 16), (21, 0), (21, 8), (22, 0),
˓→(22, 1), (22, 4), (22, 7), (22, 19), (23, 0), (23, 8), (23, 9), (23, 12),
˓→(23, 14), (24, 0), (24, 8), (24, 9), (24, 12), (24, 15)]
REFERENCE:
• [1] Krapivsky, P.L. and Redner, S. Organization of Growing Random Networks, Phys. Rev. E vol. 63
(2001), p. 066123.
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)
Returns 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:
• TransitiveTournament()
• Complete()
• RandomSemiComplete()
TransitiveTournament(n)
Returns 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()
[0, 1, 2, 3, 4]
sage: g.size()
10
sage: g.automorphism_group().cardinality()
1
See also:
Note: To use this method you must first install the Nauty spkg.
EXAMPLES:
AUTHORS:
• David Coudert (2012)
sage.graphs.graph_generators_pyx.RandomGNP(n, p, directed=False, loops=False)
Returns 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 – is a boolean indicating whether the random graph is directed or undirected (default).
• loops – is a boolean set to True if the random digraph may have loops, and False (default) otherwise.
This value is used only when directed == True.
REFERENCES:
EXAMPLES:
INFO:
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.database.py).
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_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.database.py
• Emily A. Kirkman (2007-07-23): inherits GenericSQLDatabase, also added classes: GraphQuery and Generic-
GraphQuery
• Emily A. Kirkman (2007-05-11): initial sqlite version
• Emily A. Kirkman (2007-02-13): initial version (non-sqlite)
REFERENCES:
• Data provided by Jason Grout (Brigham Young University). [Online] Available: http://artsci.drake.edu/grout/
graphs/
class sage.graphs.graph_database.GenericGraphQuery(query_string, database=None,
param_tuple=None)
Bases: sage.databases.sql_db.SQLQuery
A query for a GraphDatabase.
INPUT:
• database - the GraphDatabase instance to query (if None then a new instance is created)
• query_string - a string representing the SQL query
• param_tuple - a tuple of strings - what to replace question marks in query_string with (optional, but a
good idea)
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.
to see the underlying structure of the database. Also see SQLQuery in sage.databases.database 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
INFO:
This class interfaces with the sqlite database graphs.db. It is an immutable database that inherits from SQL-
Database (see sage.databases.database.py). 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.
USE: 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 initial-
izing one of 1. 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. 2. GraphQuery - is 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()
{u'aut_grp': {u'aut_grp_size': {'index': True,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
u'edge_transitive': {'index': True,
'primary_key': False,
'sql': u'BOOLEAN',
'unique': False},
u'graph_id': {'index': False,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
u'num_fixed_points': {'index': True,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
u'num_orbits': {'index': True,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
u'vertex_transitive': {'index': True,
'primary_key': False,
(continues on next page)
interactive_query(display_cols, **kwds)
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.
Generates an interact shell (in the notebook only) that allows the user to manipulate query parameters and
see the updated results.
EXAMPLES:
sage: D = GraphDatabase()
sage: D.interactive_query(display_cols=['graph6','num_vertices','degree_
˓→sequence'],num_edges=5,max_degree=3)
<html>...</html>
sage: D = GraphDatabase()
sage: q = D.query(display_cols=['graph6','num_vertices','degree_sequence'],
˓→num_edges=['<=',5])
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]
DK[ 5 [1, 2, 2, 2, 3]
DLo 5 [2, 2, 2, 2, 2]
D_K 5 [1, 1, 1, 1, 2]
D`K 5 [1, 1, 2, 2, 2]
E??? 6 [0, 0, 0, 0, 0, 0]
E??G 6 [0, 0, 0, 0, 1, 1]
E??W 6 [0, 0, 0, 1, 1, 2]
E??w 6 [0, 0, 1, 1, 1, 3]
E?@w 6 [0, 1, 1, 1, 1, 4]
E?Bw 6 [1, 1, 1, 1, 1, 5]
E?CW 6 [0, 0, 0, 2, 2, 2]
E?C_ 6 [0, 0, 1, 1, 1, 1]
E?Cg 6 [0, 0, 1, 1, 2, 2]
E?Cw 6 [0, 0, 1, 2, 2, 3]
E?Dg 6 [0, 1, 1, 1, 2, 3]
E?Dw 6 [0, 1, 1, 2, 2, 4]
E?Fg 6 [1, 1, 1, 1, 2, 4]
E?Ko 6 [0, 0, 2, 2, 2, 2]
(continues on next page)
Note: SQLQuery functions are available for GraphQuery. See sage.dataabases.database.py for more details.
INPUT:
• graph_db - The GraphDatabase instance to apply the query to. (If None, then a new instance is created).
• query_dict - A dictionary specifying the query itself. Format is: ‘table_name’: ‘tblname’, ‘dis-
play_cols’: [‘col1’, ‘col2’], ‘expression’:[col, operator, value] If not None, query_dict will take precedence
over all other arguments.
• display_cols - 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: 1.
[‘one_of’,String,. . . ,String] Will search for graphs containing a subgraph isomorphic to any of the graph6
strings in the list. 2. [‘all_of’,String,. . . ,String] Will search for graphs containing a subgraph isomorphic
to each of the graph6 strings in the list.
EXAMPLES:
sage: Q = GraphQuery(display_cols=['graph6','num_vertices','degree_sequence'],num_
˓→edges=['<=',5],min_degree=1)
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]
(continues on next page)
get_graphs_list()
Return a list of Sage Graph objects that satisfy the query.
EXAMPLES:
sage: Q = GraphQuery(display_cols=['graph6','num_vertices','degree_sequence'],
˓→num_edges=['<=',5],min_degree=1)
sage: L = Q.get_graphs_list()
sage: L[0]
Graph on 2 vertices
sage: len(L)
35
number_of()
Returns the number of graphs in the database that satisfy the query.
EXAMPLES:
sage: Q = GraphQuery(display_cols=['graph6','num_vertices','degree_sequence'],
˓→num_edges=['<=',5],min_degree=1)
sage: Q.number_of()
35
query_iterator()
Returns an iterator over the results list of the GraphQuery.
EXAMPLES:
show(max_field_size=20, with_picture=False)
Displays the results of a query in table format.
INPUT:
• max_field_size - width of fields in command prompt version
• with_picture - whether or not to display results with a picture of the graph (available only in the
notebook)
EXAMPLES:
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]
sage: S.show(with_picture=True)
Traceback (most recent call last):
...
NotImplementedError: Cannot display plot on command line.
sage: S.show(with_picture=False)
Graph6 Aut Grp Size
----------------------------------------
C? 24
C@ 4
CB 2
CF 6
CJ 6
CK 8
CL 2
CN 2
C] 8
C^ 4
C~ 24
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)
Takes the database integer data type (one digit per vertex representing its degree, sorted high to low) and converts
it to degree sequence list. The graph6 identifier is required for all graphs with no edges, so that the correct
number of zeros will be returned.
EXAMPLES:
sage.graphs.graph_database.degseq_to_data(degree_sequence)
Takes a degree sequence list (of Integers) and converts to a sorted (max-min) integer data type, as used for faster
access in the underlying database.
EXAMPLES:
sage.graphs.graph_database.graph6_to_plot(graph6)
Constructs a graph from a graph6 string and returns a Graphics object with arguments preset for show function.
EXAMPLES:
sage.graphs.graph_database.graph_db_info(tablename=None)
Returns 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)
Constructs and returns a GraphQuery object respecting the special input required for the induced_subgraphs
parameter. This input can be an individual graph6 string (in which case it is evaluated without the use of
this method) or a list of strings. In the latter case, the list should be of one of the following two formats:
1. [‘one_of’,String,. . . ,String] Will search for graphs containing a subgraph isomorphic to any of the graph6
strings in the list. 2. [‘all_of’,String,. . . ,String] Will search for graphs containing a subgraph isomorphic to each
of the graph6 strings in the list.
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 [CP16].
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:
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
[JK03]
EXAMPLES:
REFERENCES:
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
[JK03].
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 [GS70], and [Co06].
EXAMPLES:
REFERENCES:
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 [BvL84].
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 [BvE92]).
See also:
strongly_regular_from_two_weight_code() – build a strongly regular graph from a two-weight
code.
EXAMPLES:
REFERENCE:
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
[BvL84] 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 [Hu75].
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 [BrouwerPolarities82], 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:
REFERENCE:
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 [BvL84].
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 [IS06].
EXAMPLES:
REFERENCE:
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 [KPRWZ10]. 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 [COCO] found a megring of them, explicitly de-
scribed in [KPRWZ10], resulting in this graph.
EXAMPLES:
REFERENCES:
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 ap-
pears 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 [GS75].
Note: A strongly regular graph with the same parameters is also obtained from the database of 2-weight codes.
EXAMPLES:
REFERENCE:
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 [Hu75].
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. [HT96].
EXAMPLES:
sage: from sage.graphs.strongly_regular_db import SRG_276_140_58_84
sage: g=SRG_276_140_58_84() # long time # optional - gap_packages
sage: g.is_strongly_regular(parameters=True) # long time # optional - gap_packages
(276, 140, 58, 84)
REFERENCE:
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 [MR85]:
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: from sage.graphs.strongly_regular_db import SRG_280_117_44_52
sage: g=SRG_280_117_44_52()
sage: g.is_strongly_regular(parameters=True)
(280, 117, 44, 52)
REFERENCE:
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: from sage.graphs.strongly_regular_db import SRG_280_135_70_60
sage: g=SRG_280_135_70_60() # long time # optional - gap_packages
sage: g.is_strongly_regular(parameters=True) # long time # optional - gap_packages
(280, 135, 70, 60)
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 [Hu75].
EXAMPLES:
sage: from sage.graphs.strongly_regular_db import SRG_416_100_36_20
sage: g = SRG_416_100_36_20() # optional - gap_packages # long time
sage: g.is_strongly_regular(parameters=True) # optional - gap_packages # long time
(416, 100, 36, 20)
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 [BvL84].
EXAMPLES:
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 1st eigenmatrix of a (𝑣, 𝑘, 𝑙, 𝑚𝑢)-strongly regular graph.
The adjacency matrix 𝐴 of an s.r.g. commutes with the adacency 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 [BH12] and [BI84] 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: from sage.graphs.strongly_regular_db import eigenmatrix
sage: P=eigenmatrix(10,3,0,1); P
[ 1 3 6]
[ 1 1 -2]
[ 1 -2 1]
sage: 10*P^-1
[ 1 5 4]
[ 1 5/3 -8/3]
[ 1 -5/3 2/3]
A strongly regular graph with a non-isomorphic dual coming from another strongly regular graph:
sage: graphs.strongly_regular_graph(243,220,199,200, existence=True)
True
sage: graphs.strongly_regular_graph(243,110,37,60, existence=True)
True
sage: P=eigenmatrix(243,220,199,200); P
[ 1 220 22]
[ 1 4 -5]
[ 1 -5 4]
sage: 243*P^-1
[ 1 110 132]
[ 1 2 -3]
[ 1 -25 24]
sage: 243*P^-1==eigenmatrix(243,110,37,60)
True
REFERENCE:
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: from sage.graphs.strongly_regular_db import is_GQqmqp
sage: t = is_GQqmqp(27,10,1,5); t
(continues on next page)
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 [BvL84].
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 [BvL84].
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 [Hu75].
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.
For more information, see HaemersGraph().
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_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 parame-
ters 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 [BvL84], and in the latter case
due to Pasechnik [Pa92].
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
REFERENCE:
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 [Polhill09] is (1024, 𝑘, 𝜆, 𝜇)-strongly regular.
Note: This function does not actually explore all strongly regular graphs produced in [Polhill09], 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:
REFERENCE:
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 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_taylor_twograph_srg(v, k, l, mu)
Test whether some Taylor two-graph SRG is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
For more information, see §7E of [BvL84].
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:
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 [BH12] 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. [CDB13] 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:
REFERENCES:
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 [vLintSchrijver81] or [Delsarte72].
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)
REFERENCES:
sage.graphs.strongly_regular_db.strongly_regular_graph(v, k, l, mu=-1, exis-
tence=False, check=True)
Return a (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular graph.
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> and <a
href="srgtabrefs.html#KaskiOstergard07">Kaski & stergrd</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
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
type : base
Problems :
-----------
3-Colourability : Linear
Clique : Polynomial
Clique cover : Polynomial
Cliquewidth : Unbounded
Cliquewidth expression : NP-complete
Colourability : Linear
Cutwidth : NP-complete
Domination : NP-complete
Feedback vertex set : Polynomial
Hamiltonian cycle : NP-complete
Hamiltonian path : NP-complete
Independent set : Linear
Maximum bisection : Unknown
Maximum cut : NP-complete
Minimum bisection : Unknown
Recognition : Linear
Treewidth : Polynomial
Weighted clique : Polynomial
Weighted feedback vertex set : Unknown
Weighted independent set : Linear
It is possible to obtain the complete list of the classes stored in ISGCI by calling the show_all() method (beware
– long output):
2.6. ISGCI: Information System on Graph Classes and their Inclusions 535
Sage Reference Manual: Graph Theory, Release 8.4
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.6. ISGCI: Information System on Graph Classes and their Inclusions 537
Sage Reference Manual: Graph Theory, Release 8.4
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()[-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:
sage: bip_id = graph_classes.Bipartite._gc_id
sage: perfect_id = graph_classes.Perfect._gc_id
sage: d.has_edge(perfect_id, bip_id)
False
sage: d.distance(perfect_id, bip_id)
2
Hence bipartite graphs are perfect graphs. We can see how ISGCI obtains this result
sage: p = d.shortest_path(perfect_id, bip_id)
sage: len(p) - 1
2
sage: print(p) # random
['gc_56', 'gc_76', 'gc_69']
sage: for c in p:
....: print(graph_classes.get_class(c))
perfect graphs
...
bipartite graphs
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
Berge graphs
sage: Perfect = graph_classes.get_class("gc_56"); Perfect
perfect graphs
sage: Berge <= Perfect
True
sage: Perfect <= Berge
True
sage: Perfect == Berge
True
• 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.6.5 AUTHORS:
2.6.6 Methods
2.6. ISGCI: Information System on Graph Classes and their Inclusions 539
Sage Reference Manual: Graph Theory, Release 8.4
description()
Prints the information of ISGCI about the current class.
EXAMPLES:
sage: graph_classes.Chordal.description()
Class of graphs : Chordal
-------------------------
id : gc_32
name : chordal
type : base
Problems :
-----------
3-Colourability : Linear
Clique : Polynomial
Clique cover : Polynomial
Cliquewidth : Unbounded
Cliquewidth expression : NP-complete
Colourability : Linear
Cutwidth : NP-complete
Domination : NP-complete
Feedback vertex set : Polynomial
Hamiltonian cycle : NP-complete
Hamiltonian path : NP-complete
Independent set : Linear
Maximum bisection : Unknown
Maximum cut : NP-complete
Minimum bisection : Unknown
Recognition : Linear
Treewidth : Polynomial
Weighted clique : Polynomial
Weighted feedback vertex set : Unknown
Weighted independent set : Linear
forbidden_subgraphs()
Returns 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
sage: gc.forbidden_subgraphs()
[Graph on 4 vertices]
sage: gc.forbidden_subgraphs()[0].is_isomorphic(graphs.ClawGraph())
True
class sage.graphs.isgci.GraphClasses
Bases: sage.structure.unique_representation.UniqueRepresentation
classes()
Returns 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)
Returns 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()
Returns the class inclusion digraph
Upon the first call, this loads the database from the local XML file. Subsequent calls are cached.
EXAMPLES:
sage: g = graph_classes.inclusion_digraph(); g
Digraph on ... vertices
inclusions()
Returns the graph class inclusions
OUTPUT:
a list of dictionaries
2.6. ISGCI: Information System on Graph Classes and their Inclusions 541
Sage Reference Manual: Graph Theory, Release 8.4
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()
Returns 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,
'2K_2': Graph on 4 vertices,
'2K_3': Graph on 6 vertices,
'2K_3 + e': Graph on 6 vertices,
'2K_4': Graph on 8 vertices,
'2P_3': Graph on 6 vertices,
...
sage: t['fish']
Graph on 6 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.6. ISGCI: Information System on Graph Classes and their Inclusions 543
Sage Reference Manual: Graph Theory, Release 8.4
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)
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 ...>
545
Sage Reference Manual: Graph Theory, Release 8.4
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.
class sage.graphs.base.c_graph.CGraph
Bases: object
Compiled sparse and dense graphs.
add_arc(u, v)
Add the given arc to this graph.
INPUT:
• u – integer; the tail of an arc.
• v – integer; the head of an arc.
OUTPUT:
• Raise NotImplementedError. This method is not implemented at the CGraph level. A child
class should provide a suitable implementation.
See also:
EXAMPLES:
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)
Adds 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:
all_arcs(u, v)
Return the labels of all arcs from u to v.
INPUT:
• u – integer; the tail of an arc.
• v – integer; the head of an arc.
OUTPUT:
• Raise NotImplementedError. This method is not implemented at the CGraph level. A child
class should provide a suitable implementation.
See also:
EXAMPLES:
check_vertex(n)
Checks 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.
INPUT:
• None.
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.
OUTPUT:
• Raise NotImplementedError. This method is not implemented at the CGraph level. A child
class should provide a suitable implementation.
See also:
EXAMPLES:
del_vertex(v)
Deletes 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.
OUTPUT:
• None.
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)
Determine whether or not the given arc 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.
See also:
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)
Gives the 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.
See also:
EXAMPLES:
out_neighbors(u)
Gives the out-neighbors of the vertex u.
INPUT:
• u – 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.
See also:
EXAMPLES:
sage: from sage.graphs.base.c_graph import CGraph
sage: G = CGraph()
sage: G.out_neighbors(0)
Traceback (most recent call last):
...
NotImplementedError
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:
sage: from sage.graphs.base.c_graph import CGraph
sage: G = CGraph()
sage: G.realloc(20)
Traceback (most recent call last):
...
NotImplementedError
verts()
Returns a list of the vertices in self.
INPUT:
• None.
OUTPUT:
• A list of all vertices in this graph.
EXAMPLES:
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
backends. This class is mainly just for vertex functions, which are the same for both. A CGraphBackend will
not work on its own:
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_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 other-
wise.
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))
(continues on next page)
• Input: A directed or undirected graph 𝐺 = (𝑉, 𝐸) of order 𝑛 > 0. A vertex 𝑠 from which to start the
search. The vertices are numbered from 1 to 𝑛 = |𝑉 |, i.e. 𝑉 = {1, 2, . . . , 𝑛}.
• Output: A list 𝐷 of distances of all vertices from 𝑠. A tree 𝑇 rooted at 𝑠.
See also:
EXAMPLES:
Breadth-first search of the Petersen graph starting at vertex 0:
c_graph()
Return the ._cg and ._cg_rev attributes
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_vertex(v)
Delete a vertex in self, failing silently if the vertex is not in the graph.
INPUT:
• v – vertex to be deleted.
OUTPUT:
• None.
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:
• vertices – iterator of vertex labels.
OUTPUT:
• Same as for del_vertex().
See also:
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
i. if 𝐷[𝑤] = ∞ then
A. 𝐷[𝑤] ← 𝐷[𝑣] + 1
B. push(𝑆, 𝑤)
C. append(𝑇, 𝑣𝑤)
6. return (𝐷, 𝑇 )
See also:
EXAMPLES:
Traversing the Petersen graph using depth-first search:
has_vertex(v)
Returns 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)
Returns the in-degree of v
INPUT:
• v – a vertex of the graph.
EXAMPLES:
sage: D.out_degree(1)
2
is_connected()
Returns whether the graph is connected.
EXAMPLES:
Petersen’s graph is connected:
sage: DiGraph(graphs.PetersenGraph(),implementation="c_graph").is_connected()
True
sage: DiGraph(2*graphs.PetersenGraph(),implementation="c_graph").is_
˓→connected()
False
is_directed_acyclic(certificate=False)
Returns whether the graph is both directed and acylic (possibly with a certificate)
INPUT:
• certificate – whether to return a certificate (False by default).
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 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
is_strongly_connected()
Returns whether the graph is strongly connected.
EXAMPLES:
The circuit on 3 vertices is obviously strongly connected:
iterator_in_nbrs(v)
Returns an iterator 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: list(P._backend.iterator_in_nbrs(0))
[1, 4, 5]
iterator_nbrs(v)
Returns an iterator over the neighbors of v.
INPUT:
• v – a vertex of this graph.
OUTPUT:
• An iterator over the neighbors the vertex v.
See also:
EXAMPLES:
iterator_out_nbrs(v)
Returns an iterator over the outgoing neighbors of v.
INPUT:
• v – a vertex of this graph.
OUTPUT:
• An iterator over the out-neighbors of the vertex v.
See also:
EXAMPLES:
sage: list(P._backend.iterator_out_nbrs(0))
[1, 4, 5]
iterator_verts(verts=None)
Returns an iterator 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:
loops(new=None)
Returns whether loops are allowed in this graph.
INPUT:
• new – (default: None); boolean (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(implementation='c_graph')
sage: G._backend.loops()
False
sage: G._backend.loops(True)
sage: G._backend.loops()
True
num_edges(directed)
Returns 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:
num_verts()
Returns the number of vertices in self.
INPUT:
• None.
OUTPUT:
• The order of this graph.
See also:
EXAMPLES:
out_degree(v)
Returns the out-degree of v
INPUT:
• v – a vertex of the graph.
EXAMPLES:
sage: D.out_degree(1)
2
relabel(perm, directed)
Relabels 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(), implementation="c_graph")
sage: G._backend.relabel(range(9,-1,-1), False)
sage: G.edges()
[(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)
Returns 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(), implementation="c_graph")
sage: G.shortest_path(0, 1)
[0, 1]
sage: G.shortest_path_length(0, 1)
1
INPUT:
• v – a starting vertex in the shortest path.
• cutoff – maximal distance. Longer paths will not be returned.
• distance_flag – boolean (default: False). When set to True, each vertex u connected to v is
mapped to shortest path distance from v to u instead of the shortest path in the output dictionary.
OUTPUT:
• A dictionary which maps each vertex u connected to v to the shortest path list or distance from v to
u depending upon the value of parameter distance_flag
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([ len(paths[v]) == 0 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
sage: g = 2*graphs.RandomGNP(20,.3)
sage: paths = g._backend.shortest_path_all_vertices(0)
sage: all([ (v not in paths and g.distance(0,v) == +Infinity) or
˓→len(paths[v])-1 == g.distance(0,v) for v in g])
True
strongly_connected_component_containing_vertex(v)
Returns 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
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 stack. For breadth-first search (BFS), element removal occurs at the start of the list, as signified
by the value direction=0. This is because in implementations of BFS, the list of vertices to visit
are usually maintained by a queue, so element insertion and removal follow a first-in first-out (FIFO)
protocol. For depth-first search (DFS), element removal occurs at the end of the list, as signified by the
value direction=-1. The reason is that DFS is usually implemented using a stack to maintain the list
of vertices to visit. Hence, element insertion and removal follow a last-in first-out (LIFO) protocol.
• stack – a list of vertices to visit.
• 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
undirected 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]
next()
x.next() -> the next value, or raise StopIteration
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)
(continues on next page)
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 ver-
tices.
• 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(u, v)
Adds arc (u, v) to the graph with no label.
INPUT:
add_arc_label(u, v, l=0)
Adds arc (u, v) to the graph with label l.
INPUT:
• u, v - non-negative integers, must be in self
• l - a positive integer label, or zero for no label
EXAMPLES:
sage: from sage.graphs.base.sparse_graph import SparseGraph
sage: G = SparseGraph(5)
sage: G.add_arc_label(0,1)
sage: G.add_arc_label(4,7)
Traceback (most recent call last):
...
LookupError: Vertex (7) is not a vertex of the graph.
sage: G.has_arc(1,0)
False
sage: G.has_arc(0,1)
True
sage: G.add_arc_label(1,2,2)
sage: G.arc_label(1,2)
2
all_arcs(u, v)
Gives the labels of all arcs (u, v). An unlabeled arc is interpreted as having label 0.
EXAMPLES:
sage: from sage.graphs.base.sparse_graph import SparseGraph
sage: G = SparseGraph(5)
sage: G.add_arc_label(1,2,1)
sage: G.add_arc_label(1,2,2)
sage: G.add_arc_label(1,2,2)
sage: G.add_arc_label(1,2,2)
sage: G.add_arc_label(1,2,3)
sage: G.add_arc_label(1,2,3)
sage: G.add_arc_label(1,2,4)
sage: G.all_arcs(1,2)
[4, 3, 3, 2, 2, 2, 1]
arc_label(u, v)
Retrieves the first label found associated with (u, v).
INPUT:
• u, v - non-negative integers, must be in self
OUTPUT:
• 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
del_all_arcs(u, v)
Deletes all arcs from u to v.
INPUT:
• u, v - integers
EXAMPLES:
del_arc_label(u, v, l)
Delete an arc (u, v) with label l.
INPUT:
• u, v - non-negative integers, must be in self
has_arc(u, v)
Checks whether arc (u, v) is in the graph.
INPUT:
• u, v - integers
EXAMPLES:
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:
in_degree(u)
Returns the in-degree of v
INPUT:
• u - integer
EXAMPLES:
in_neighbors(v)
Gives all u such that (u, v) is an arc of the graph.
INPUT:
• v - integer
EXAMPLES:
NOTE: Due to the implementation of SparseGraph, this method is much more expensive than neigh-
bors_unsafe.
out_degree(u)
Returns the out-degree of v
INPUT:
• u - integer
EXAMPLES:
out_neighbors(u)
Gives all v such that (u, v) is an arc of the graph.
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
SparseGraph, 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(G.vertices(),
....: 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
add_edge(u, v, l, directed)
Adds 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)
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)]
add_edges(edges, directed)
Add 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, add (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: list(D.iterator_edges(range(9), True))
(continues on next page)
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)
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)]
get_edge_label(u, v)
Returns 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
iterator_edges(vertices, labels)
Iterate over the edges incident to a sequence of vertices. Edges are assumed to be undirected.
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_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)]
(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:
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_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_edges(range(9), True))
[(1, 2, 'a')]
sage: G.set_edge_label(2,1,'b',True)
sage: list(G.iterator_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):
The array edges is a series of bits which are turned on or off, and due to this, dense graphs only support graphs
without edge labels and with no multiple edges. num_longs stores the length of the edges array. Recall that this
length reflects the number of available vertices, not the number of “actual” vertices. For more details about this, refer
to the documentation for CGraph.
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: 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(u, v)
Adds arc (u, v) to the graph.
INPUT:
• u, v – non-negative integers, must be in self
EXAMPLES:
complement()
Replaces the graph with its complement
EXAMPLES:
del_all_arcs(u, v)
Deletes the arc from u to v.
INPUT:
• u, v - integers
NOTE: The naming of this function is for consistency with SparseGraph. Of course, there can be at
most one arc for a DenseGraph.
EXAMPLES:
has_arc(u, v)
Checks whether arc (u, v) is in the graph.
INPUT: u, v – integers
EXAMPLES:
in_neighbors(v)
Gives all u such that (u, v) is an arc of the graph.
INPUT:
• v - integer
EXAMPLES:
out_neighbors(u)
Gives all v such that (u, v) is an arc of the graph.
INPUT:
• u - integer
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:
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
DenseGraph, 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: G.add_vertex((0,1,2))
sage: G.vertices()
[0,
...
29,
(0, 1, 2)]
sage: from sage.graphs.base.dense_graph import DenseGraph
sage: DG = DenseGraph(30)
(continues on next page)
add_edge(u, v, l, directed)
Adds the edge (u,v) to self.
INPUT:
• u,v - the vertices of the edge
• l - the edge label (ignored)
• directed - if False, also add (v,u)
NOTE: The input l is for consistency with other backends.
EXAMPLES:
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)]
add_edges(edges, directed)
Add 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, add (v,u) as well as (u,v)
EXAMPLES:
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),
(2, 3, None),
(4, 5, None),
(5, 6, None)]
del_edge(u, v, l, directed)
Delete edge (u,v).
INPUT:
• u,v - the vertices of the edge
• l - the edge label (ignored)
• directed - if False, also delete (v,u,l)
NOTE: The input l is for consistency with other backends.
EXAMPLES:
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))
(continues on next page)
get_edge_label(u, v)
Returns 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)
Returns whether this graph has edge (u,v).
NOTE: The input l is for consistency with other backends.
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)
sage: D.has_edge(0,1,None)
True
iterator_edges(vertices, labels)
Iterate over the edges incident to a sequence of vertices. Edges are assumed to be undirected.
INPUT:
• vertices - a list of vertex labels
• labels - boolean, whether to return labels as well
EXAMPLES:
sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9)
sage: G.add_edge(1,2,None,False)
sage: list(G.iterator_edges(range(9), False))
[(1, 2)]
sage: list(G.iterator_edges(range(9), True))
[(1, 2, None)]
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.dense_graph.DenseGraphBackend(9)
sage: G.add_edge(1,2,None,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, None)]
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.dense_graph.DenseGraphBackend(9)
sage: G.add_edge(1,2,None,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, None)]
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 misc/binary_matrix.pxi, 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.
For an overview of graph data structures in sage, see overview.
3.5.1 Index
Cython functions
Python functions
3.5.2 Functions
sage.graphs.base.static_dense_graph.connected_subgraph_iterator
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 ig-
nored. 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 – (default: False) boolean; whether to return (Di)Graph or list of vertices
EXAMPLES:
sage: G = DiGraph([(1, 2), (2, 3), (3, 4), (4, 2)])
sage: list(G.connected_subgraph_iterator())
[Subgraph of (): Digraph on 1 vertex,
Subgraph of (): Digraph on 2 vertices,
Subgraph of (): Digraph on 3 vertices,
Subgraph of (): Digraph on 4 vertices,
Subgraph of (): Digraph on 3 vertices,
Subgraph of (): Digraph on 1 vertex,
Subgraph of (): Digraph on 2 vertices,
Subgraph of (): Digraph on 3 vertices,
Subgraph of (): Digraph on 2 vertices,
Subgraph of (): Digraph on 1 vertex,
Subgraph of (): Digraph on 2 vertices,
Subgraph of (): Digraph on 1 vertex]
sage: list(G.connected_subgraph_iterator(vertices_only=True))
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 4],
[2], [2, 3], [2, 3, 4], [2, 4], [3], [3, 4], [4]]
sage: list(G.connected_subgraph_iterator(k=2))
[Subgraph of (): Digraph on 1 vertex,
Subgraph of (): Digraph on 2 vertices,
Subgraph of (): Digraph on 1 vertex,
Subgraph of (): Digraph on 2 vertices,
(continues on next page)
sage.graphs.base.static_dense_graph.is_strongly_regular
Tests whether self 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) – whether to return the quadruple (𝑛, 𝑘, 𝜆, 𝜇). If parameters = False (de-
fault), 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.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)]).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)]).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.triangles_count
Return the number of triangles containing 𝑣, for every 𝑣.
INPUT:
• G– a simple 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 – 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 fast_digraph from a Graph or DiGraph named G, the 𝑖th vertex corresponds to G.
vertices()[i]
• Some methods return bitset_t objets 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 repre-
sents 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.
tarjan_strongly_connected_components_C(short_digraph g, int *scc)
Assuming scc is already allocated and has size at least g.n, this method computes the strongly connected
components of g, and outputs in scc[v] the number of the strongly connected component containing v.
It returns the number of strongly connected components.
strongly_connected_components_digraph_C(short_digraph g, int nscc, int *scc,
short_digraph output):
Assuming nscc and scc are the outputs of tarjan_strongly_connected_components_C on
g, this routine sets output to the strongly connected component digraph of g, that is, the vertices of
output are the strongly connected components of g (numbers are provided by scc), and output
contains an arc (C1,C2) if g has an arc from a vertex in C1 to a vertex in C2.
These functions are available so that Python modules from Sage can call the Cython routines this module implements
(as they can not directly call methods with C arguments).
sage.graphs.base.static_sparse_graph.spectral_radius
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
Returns 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
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’s_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])
(continues on next page)
sage.graphs.base.static_sparse_graph.triangles_count
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=DiGraph(digraphs.DeBruijn(4,3),data_structure="static_sparse")
sage: gi=DiGraph(g,data_structure="static_sparse")
sage: gi.edges()[0]
('000', '000', '0')
sage: gi.edges_incident('111')
[('111', '110', '0'), ('111', '111', '1'), ('111', '112', '2'), ('111', '113', '3
˓→')]
sage: g = graphs.PetersenGraph()
sage: gi=Graph(g,data_structure="static_sparse")
sage: g == gi
True
sage: sorted(g.edges()) == sorted(gi.edges())
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())
True
True
add_vertex(v)
Addition of vertices is not available on an immutable graph.
EXAMPLES:
allows_loops(value=None)
Returns 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)
Returns 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:
sage: Graph({0:[0]},immutable=True).degree(0)
2
sage: Graph({0:[0],1:[0,1,1,1]},immutable=True).degree(1)
7
del_vertex(v)
Removal of vertices is not available on an immutable graph.
EXAMPLES:
get_edge_label(u, v)
Returns the edge label for (u,v).
INPUT:
• u,v – two vertices
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 – two vertices
• l – a label
has_vertex(v)
Tests if the vertex belongs to the graph
INPUT:
• v – a vertex (or not?)
in_degree(v)
Returns the in-degree of a vertex
INPUT:
• v – a vertex
EXAMPLES:
iterator_edges(vertices, labels)
Returns an iterator over the graph’s edges.
INPUT:
• vertices – only returns the edges incident to at least one vertex of vertices.
• labels – 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
sage: DiGraph(digraphs.Path(5),immutable=False).incoming_edges([2])
[(1, 2, None)]
sage: DiGraph(digraphs.Path(5),immutable=True).incoming_edges([2])
[(1, 2, None)]
iterator_in_nbrs(v)
Returns the in-neighbors of a vertex
INPUT:
• v – a vertex
EXAMPLES:
iterator_nbrs(v)
Returns 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)
Returns the out-neighbors of a vertex
INPUT:
• v – a vertex
EXAMPLES:
iterator_verts(vertices)
Returns an iterator 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)
Returns 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)
Returns the number of edges
INPUT:
• directed (boolean) – whether to consider the graph as directed or not.
num_verts()
Returns the number of vertices
out_degree(v)
Returns the out-degree of a vertex
INPUT:
• v – a vertex
EXAMPLES:
relabel(perm, directed)
Relabel the graphs’ vertices. 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)
Adds a vertex to the graph. No way.
del_vertex(k)
Removes a vertex from the graph. No way.
has_arc(u, v)
Tests if uv is an edge of the graph
INPUT:
• u,v – integers
has_vertex(n)
Tests if a vertex belongs to the graph
INPUT:
• n – an integer
in_degree(u)
Returns the in-degree of a vertex
INPUT:
• u – a vertex
in_neighbors(u)
Returns the in-neighbors of a vertex
INPUT:
• u – a vertex
out_degree(u)
Returns 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 (u,v) to self, with label l. If directed is True, this is interpreted as an arc from u to v.
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:
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 v
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)
True if self has an edge (u,v) with label l.
INPUT:
• u,v – vertex labels
• l – label
OUTPUT:
boolean
has_vertex(v)
True if self has a vertex with label v.
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.
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_in_edges(vertices, labels)
Iterate over the incoming edges incident to a sequence of vertices.
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_in_nbrs(v)
Iterate over the vertices u such that the edge (u,v) is in self (that is, predecessors of v).
INPUT:
• v – vertex label
OUTPUT:
a generator which yields vertex labels
iterator_nbrs(v)
Iterate over the vertices adjacent to v.
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.
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 vertices u such that the edge (v,u) is in self (that is, successors of v).
INPUT:
• v – vertex label
OUTPUT:
a generator which yields vertex labels
iterator_verts(verts)
Iterate over the vertices v with labels in verts.
INPUT:
• vertex – 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)
The number of edges in self
INPUT:
• directed – boolean
num_verts()
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 (u,v) by l.
INPUT:
• u,v – vertices
• l – edge label
• directed – boolean
class sage.graphs.base.graph_backends.NetworkXDiGraphDeprecated
Bases: sage.structure.sage_object.SageObject
Class for unpickling old networkx.XDiGraph formats
mutate()
Change the old networkx XDiGraph format into the new one.
OUTPUT:
• The networkx.DiGraph or networkx.MultiDiGraph corresponding to the unpickled data.
EXAMPLES:
sage: X = NXDGD()
sage: X.adj = {1:{2:7}, 2:{1:[7,8], 3:[4,5,6,7]}}
sage: X.multiedges = True
sage: G = X.mutate()
sage: G.edges()
OutMultiEdgeDataView([(1, 2), (2, 1), (2, 3)])
sage: G.edges(data=True)
OutMultiEdgeDataView([(1, 2, {'weight': 7}),
(2, 1, {8: {}, 7: {}}),
(2, 3, {4: {}, 5: {}, 6: {}, 7: {}})])
class sage.graphs.base.graph_backends.NetworkXGraphDeprecated
Bases: sage.structure.sage_object.SageObject
Class for unpickling old networkx.XGraph formats
mutate()
Change the old networkx XGraph format into the new one.
OUTPUT:
• The networkx.Graph or networkx.MultiGraph corresponding to the unpickled data.
EXAMPLES:
sage: X = NXGD()
sage: X.adj = {1:{2:7}, 2:{1:7}, 3:{2:[4,5,6,7]}, 2:{3:[4,5,6,7]}}
sage: X.multiedges = True
sage: G = X.mutate()
sage: G.edges()
MultiEdgeDataView([(1, 2), (2, 3)])
sage: G.edges(data=True)
MultiEdgeDataView([(1, 2, {'weight': 7}), (2, 3, {4: {}, 5: {}, 6: {}, 7: {}}
˓→)])
sage: b
<sage.graphs.base.sparse_graph.SparseGraphBackend object at ...>
sage: list(b.iterator_edges(range(4),1))
[(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’)
Uses 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 (Graph) - the input graph.
• algorithm ('cuthill_mckee' or 'king') - the heuristic used to compute the ordering: Cuthill-
McKee, or King.
OUTPUT:
A pair [bandwidth, ordering], where ordering is the ordering of vertices, bandwidth is the band-
width 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)
Computes the blocks and cut vertices of the graph.
This method uses the implementation of Tarjan’s algorithm available in the Boost library .
INPUT:
• g (Graph) - the input 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)
Computes the clustering coefficient of the input graph, using Boost.
See also:
sage.graphs.generic_graph.GenericGraph.clustering_coeff()
INPUT:
• g (Graph) - the input graph.
• vertices (list) - the list of vertices we need to analyze (if None, we will compute the clustering coeffi-
cient of all vertices).
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})
sage.graphs.base.boost_graph.dominator_tree
Uses Boost to compute the dominator tree of g, rooted at root.
A node 𝑑 dominates a node 𝑛 if every path from the entry node root to 𝑛 must go through 𝑑. The immediate
dominator of a node 𝑛 is the unique node that strictly dominates 𝑛 but does not dominate any other node that
dominates 𝑛. A dominator tree is a tree where each node’s children are those nodes it immediately dominates.
For more information, see the Wikipedia article Dominator_(graph_theory).
If the graph is connected and undirected, the parent of a vertex 𝑣 is:
• the root if 𝑣 is in the same biconnected component as the root;
• the first cut vertex in a path from 𝑣 to the root, otherwise.
If the graph is not connected, the dominator tree of the whole graph is equal to the dominator tree of the
connected component of the root.
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 (generic_graph) - the input graph.
• root (vertex) - the root of the dominator tree.
• return_dict (boolean) - 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.graphs.base.boost_graph.edge_connectivity(g)
Computes 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.johnson_closeness_centrality(g,
weight_function=None)
Uses Johnson algorithm to compute the closeness centrality of all vertices.
This routine is preferrable to johnson_shortest_paths() because it does not create a doubly indexed
dictionary of distances, saving memory.
The time-complexity is 𝑂(𝑚𝑛 log 𝑛), where 𝑛 is the number of nodes and 𝑚 is the number of edges.
INPUT:
• g (generic_graph) - the input graph.
• weight_function (function) - a function that inputs 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.
OUTPUT:
A dictionary associating each vertex v to its closeness centrality.
EXAMPLES:
Undirected graphs:
Directed graphs:
sage.graphs.base.boost_graph.johnson_shortest_paths(g, weight_function=None)
Uses Johnson algorithm to solve the all-pairs-shortest-paths.
This routine outputs the distance between each pair of vertices, using a dictionary of dictionaries. It works on
all kinds of graphs, but it is designed specifically for graphs with negative weights (otherwise there are more
efficient algorithms, like Dijkstra).
The time-complexity is 𝑂(𝑚𝑛 log 𝑛), where 𝑛 is the number of nodes and 𝑚 is the number of edges.
INPUT:
• g (generic_graph) - the input graph.
• weight_function (function) - a function that inputs 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.
OUTPUT:
A dictionary of dictionary distances such that distances[v][w] is the distance between vertex v and
vertex w.
EXAMPLES:
Undirected graphs:
Directed graphs:
• sage.graphs.generic_graph.GenericGraph.min_spanning_tree()
EXAMPLES:
Directed graphs:
FOUR
HYPERGRAPHS
At the moment this module only implement one method, which calls Brendan McKay’s Nauty (http://cs.anu.edu.au/
~bdm/nauty/) to enumerate hypergraphs up to isomorphism.
class sage.graphs.hypergraph_generators.HypergraphGenerators
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:
CompleteUniform(n, k)
Return the complete 𝑘-uniform hypergraph on 𝑛 points.
INPUT:
• k,n – nonnegative integers with 𝑘 ≤ 𝑛
EXAMPLES:
sage: h = hypergraphs.CompleteUniform(5,2); h
Incidence structure with 5 points and 10 blocks
sage: len(h.packing())
2
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
623
Sage Reference Manual: Graph Theory, Release 8.4
EXAMPLES:
Note: For genbg the first class elements are vertices, and second class elements are the hypergraph’s
sets.
OUTPUT:
A tuple of tuples.
EXAMPLES:
Small hypergraphs:
sage: list(hypergraphs.nauty(4,2))
[((), (0,), (1,), (0, 1))]
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_connected() Test whether the design is connected.
Test if the incidence structure is a generalized quadrangle.
is_generalized_quadrangle()
is_isomorphic() Return whether the two incidence structures are isomorphic.
Continued on next page
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.
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
Dobcsanyi peter@designtheory.org.
• Vincent Delecroix (2014): major rewrite
4.2.1 Methods
class sage.combinat.designs.incidence_structures.IncidenceStructure(points=None,
blocks=None,
inci-
dence_matrix=None,
name=None,
check=True,
copy=True)
Bases: object
A base class for incidence structures (i.e. hypergraphs, i.e. set systems)
An incidence structure (i.e. hypergraph, i.e. set system) can be defined from a collection of blocks (i.e. sets, i.e.
edges), optionally with an explicit ground set (i.e. point set, i.e. vertex set). Alternatively they can be defined
from a binary incidence matrix.
INPUT:
• points – (i.e. ground set, i.e. vertex set) the underlying set. If points is an integer 𝑣, then the set is
considered to be {0, ..., 𝑣 − 1}.
Note: The following syntax, where points is ommitted, automatically defines the ground set as the
union of the blocks:
sage: H = IncidenceStructure([['a','b','c'],['c','d','e']])
sage: 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.
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 = IncidenceStructure(8, [[0,1,3],[1,4,5,6],[1,2],[5,6,7]])
sage: BD.block_sizes()
[3, 2, 4, 3]
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.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:
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(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(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 http://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]
[1 0 0 1 1 0 0]
[1 0 0 0 0 1 1]
[0 1 0 1 0 1 0]
[0 1 0 0 1 0 1]
[0 0 1 1 0 0 1]
[0 0 1 0 1 1 0]
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_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 [BH12], 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. [PT09] or [GQwiki]) 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 quad-
rangle.
• 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.
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.
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
LP solver (CPLEX, Gurobi, . . . ).
INPUT:
• certificate (boolean) – whether to return the classes along with the binary answer (see examples
below).
• 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.
• 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:
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:
sage: b,cls = TD.is_resolvable(True)
sage: b
True
sage: cls # random
[[[0, 3], [1, 2]], [[1, 3], [0, 2]]]
A non-resolvable design:
sage: Fano = designs.balanced_incomplete_block_design(7,3)
sage: Fano.is_resolvable()
False
sage: Fano.is_resolvable(True)
(False, [])
is_simple()
Test whether this design is simple (i.e. no repeated block).
EXAMPLES:
sage: IncidenceStructure(3, [[0,1],[1,2],[0,2]]).is_simple()
True
sage: IncidenceStructure(3, [[0],[0]]).is_simple()
False
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
(continues on next page)
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.
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(labels=False))
sage: IC = IncidenceStructure(C.edges(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
sage: H.automorphism_group().cardinality()
5616
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
packing(solver=None, verbose=0)
Return a maximum packing
A maximum packing in a hypergraph is collection of disjoint sets/blocks of maximal cardinality. This
problem is NP-complete in general, and in particular on 3-uniform hypergraphs. It is solved here with an
Integer Linear Program.
For more information, see the Wikipedia article Packing_in_a_hypergraph.
INPUT:
• 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: 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
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
5.1.1 Methods
class sage.graphs.graph_coloring.Test
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)
Calls self.random_all_graph_colorings(). In the future, if other methods are added, it should
call them, too.
643
Sage Reference Manual: Graph Theory, Release 8.4
random_all_graph_colorings(tests=1000)
Verifies 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)
Computes 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 can not 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)
– 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)
– 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 – (default: None) Specify a Linear Program (LP) solver to be used. If set to None, the de-
fault 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 of the LP solver. Set to 0 by default, which
means quiet.
ALGORITHM:
Linear Programming
EXAMPLES:
The complete graph on 8 vertices can not 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 can not be colored with the given number of colors.
sage.graphs.graph_coloring.all_graph_colorings(G, n, count_only=False,
hex_colors=False, ver-
tex_color_dict=False)
Computes all 𝑛-colorings of a graph.
This method casts the graph coloring problem into an exact cover problem, and passes this into an implementa-
tion of the Dancing Links algorithm described by Knuth (who attributes the idea to Hitotumatu and Noshita).
INPUT:
• G - a graph
• n - a positive integer the number of colors
• 𝑐𝑜𝑢𝑛𝑡𝑜 𝑛𝑙𝑦 – (default: False) when set to True, it returns 1 for each coloring
• ℎ𝑒𝑥𝑐 𝑜𝑙𝑜𝑟𝑠 – (default: False) when set to False, it labels the colors [0,1,.., n - 1], otherwise it uses the
RGB Hex labeling
• 𝑣𝑒𝑟𝑡𝑒𝑥𝑐 𝑜𝑙𝑜𝑟𝑑 𝑖𝑐𝑡 – (default: False) when set to True, it returns a dictionary {vertex:color}, otherwise it
returns a dictionary {color:[list of vertices]}
The construction works as follows. Columns:
• The first |𝑉 | columns correspond to a vertex – a 1 in this column indicates that that vertex has a color.
• After those |𝑉 | columns, we add 𝑛 * |𝐸| columns – a 1 in these columns indicate that a particular edge is
incident to a vertex with a certain color.
Rows:
• For each vertex, add 𝑛 rows; one for each color 𝑐. Place a 1 in the column corresponding to the vertex, and
a 1 in the appropriate column for each edge incident to the vertex, indicating that that edge is incident to
the color 𝑐.
• If 𝑛 > 2, the above construction cannot be exactly covered since each edge will be incident to only two
vertices (and hence two colors) - so we add 𝑛 * |𝐸| rows, each one containing a 1 for each of the 𝑛 * |𝐸|
columns. These get added to the cover solutions “for free” during the backtracking.
Note that this construction results in 𝑛 * |𝑉 | + 2 * 𝑛 * |𝐸| + 𝑛 * |𝐸| entries in the matrix. The Dancing Links
algorithm uses a sparse representation, so if the graph is simple, |𝐸| ≤ |𝑉 |2 and 𝑛 <= |𝑉 |, this construction
runs in 𝑂(|𝑉 |3 ) time. Back-conversion to a coloring solution is a simple scan of the solutions, which will
contain |𝑉 | + (𝑛 − 2) * |𝐸| entries, so runs in 𝑂(|𝑉 |3 ) time also. For most graphs, the conversion will be much
faster – for example, a planar graph will be transformed for 4-coloring in linear time since |𝐸| = 𝑂(|𝑉 |).
REFERENCES:
http://www-cs-staff.stanford.edu/~uno/papers/dancing-color.ps.gz
EXAMPLES:
Note: This method computes a b-coloring that uses at MOST 𝑘 colors. If this method returns a value equal to
𝑘, it can not 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
• 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.
• value_only – boolean (default: True). When set to True, only the number of colors is returned. Oth-
erwise, the pair (nb_colors, coloring) is returned, where coloring is a dictionary associating
its color (integer) to each vertex of the graph.
• verbose – integer (default: 0). Sets the level of verbosity. Set to 0 by default, which means quiet.
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)
Returns the minimal number of colors needed to color the vertices of the graph 𝐺.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.chromatic_number()
3
• g – a graph.
• value_only – (default: False):
– When set to True, only the chromatic index is returned.
– When set to False, a partition of the edge set into matchings is returned if possible.
• vizing – (default: False):
– When set to True, tries to find a ∆ + 1-edge-coloring, where ∆ is equal to the maximum degree in
the graph.
– When set to False, tries to find a ∆-edge-coloring, where ∆ is equal to the maximum degree
in the graph. If impossible, tries to find and returns a ∆ + 1-edge-coloring. This implies that
value_only=False.
• hex_colors – (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 – (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.
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
compute 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:
number of a graph.
Note: This method computes a grundy coloring using at MOST 𝑘 colors. If this method returns a value equal
to 𝑘, it can not 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
• 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.
• value_only – boolean (default: True). When set to True, only the number of colors is returned. Oth-
erwise, the pair (nb_colors, coloring) is returned, where coloring is a dictionary associating
its color (integer) to each vertex of the graph.
• verbose – integer (default: 0). Sets the level of verbosity. Set to 0 by default, which means quiet.
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, ver-
bose=0)
Computes 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 ⌉.
– If hex_colors = False (default value), returns a list of graphs corresponding to each color class.
• value_only (boolean)
– 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
• plus_one (integer) – whether to use ⌈ Δ(𝐺)
2 ⌉ or ⌈
Δ(𝐺)+1
2 ⌉ colors.
Of maximum degree 2:
sage.graphs.graph_coloring.number_of_n_colorings(G, n)
Computes the number of 𝑛-colorings of a graph
EXAMPLES:
sage.graphs.graph_coloring.numbers_of_colorings(G)
Returns the number of 𝑛-colorings of the graph 𝐺 for 𝑛 from 0 to |𝑉 |.
EXAMPLES:
sage.graphs.graph_coloring.round_robin(n)
Computes 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()
[(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
See the Wikipedia article Graph_coloring for further details on graph coloring.
INPUT:
• g – a graph.
• k – (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 – (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 – (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 – (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.
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
accordingly.
EXAMPLES:
This module defines functions based on Cliquer, an exact branch-and-bound algorithm developed by Patric R. J.
Ostergard 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:
5.2.1 Methods
sage.graphs.cliquer.all_max_clique
Returns 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 undi-
rected graph.
ALGORITHM:
This function is based on Cliquer [NisOst2003].
EXAMPLES:
sage.graphs.cliquer.clique_number
Returns the size of the largest clique of the graph (clique number).
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
Returns the vertex set of a maximum complete subgraph.
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
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:
sage: from sage.graphs.centrality import centrality_betweenness
sage: centrality_betweenness(digraphs.Circuit(6)) # abs tol 1e-10
{0: 0.5, 1: 0.5, 2: 0.5, 3: 0.5, 4: 0.5, 5: 0.5}
sage: centrality_betweenness(graphs.CycleGraph(6)) # abs tol 1e-10
{0: 0.2, 1: 0.2, 2: 0.2, 3: 0.2, 4: 0.2, 5: 0.2}
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) – The number of random nodes to choose
OUTPUT:
A dictionary indexed by vertices and values are estimated closeness centrality.
EXAMPLES:
Estimation of the closeness centrality of the Petersen Graph when 𝑘 == 𝑛:
• verbose (integer, default: 0): an integer defining how “verbose” the algorithm should be. If 0, nothing
is printed, if 1, we print only the performance ratio at the end of the algorithm, if 2, we print partial results
every 1000 visits, if 3, we print partial results after every visit.
OUTPUT:
An ordered list of k pairs (closv, v), where v is one of the k most central vertices, and closv is its
closeness centrality. If k is bigger than the number of vertices with positive (out)degree, the list might be
smaller.
EXAMPLES:
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
[LB62].
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 [Koh04] and due to [LB62] 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 References
5.4.4 Functions
sage.graphs.asteroidal_triples.is_asteroidal_triple_free
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 – (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) – whether to only consider (inclusionwise) maximal independent sets. Set to False
by default.
• complement (boolean) – whether to consider the graph’s complement (i.e. cliques instead of indepen-
dent sets). Set to False by default.
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 Net-
workX’, which is surprising as it is written in Cython. This being said, the algorithm from NetworkX appears
to be sligthly 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()
Computes and returns 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 alo be found in [Cleanup] or [ATGA].
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 [Cleanup]):
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 References
5.6.6 Methods
sage.graphs.comparability.greedy_is_comparability
Tests whether the graph is a comparability graph (greedy algorithm)
This method only returns no-certificates.
To understand how this method works, please consult the documentation of the comparability module.
INPUT:
• no_certificate – whether to return a no-certificate when the graph is not a comparability graph. This
certificate is an odd cycle of edges, each of which implies the next. It is set to False by default.
• equivalence_class – whether to return an equivalence class if the graph is a comparability graph.
OUTPUT:
• If the graph is a comparability graph and no_certificate = False, this method returns True or
(True, an_equivalence_class) according to the value of equivalence_class.
• If the graph is not a comparability graph, this method returns False or (False, odd_cycle) ac-
cording to the value of no_certificate.
EXAMPLES:
The Petersen Graph is not transitively orientable:
sage: g = graphs.PetersenGraph()
sage: is_comparability(g)
False
(continues on next page)
sage: g = graphs.BullGraph()
sage: is_comparability(g)
True
sage.graphs.comparability.greedy_is_comparability_with_certificate
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
orientation 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: 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
sage.graphs.comparability.is_comparability
Tests whether the graph is a comparability graph
INPUT:
• algorithm – choose the implementation used to do the test.
– "greedy" – a greedy algorithm (see the documentation of the comparability module).
– "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 de-
fault 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.graphs.comparability.is_comparability_MILP
Tests whether the graph is a comparability graph (MILP)
INPUT:
• certificate (boolean) – whether to return a certificate for yes instances. This method can not return
negative certificates.
• solver – (default: None); Specify a Linear Program (LP) solver to be used. If set to None, the de-
fault 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
sage.graphs.comparability.is_permutation
Tests whether the graph is a permutation graph.
For more information on permutation graphs, refer to the documentation of the comparability module.
INPUT:
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
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: digraphs.DeBruijn(5,2).is_transitive()
False
sage: digraphs.DeBruijn(5,2).is_transitive(certificate=True)
('00', '10')
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.
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
([Whitney32], [Harary69]), 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 [Beineke70] 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)
Tests wether 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.
Todo: This method sequentially tests each of the forbidden subgraphs in order to know whether the graph
is a line graph, which is a very slow method. It could eventually be replaced by root_graph() when this
method will not require an exponential time to run on general graphs anymore (see its documentation for more
information on this problem). . . and if it can be improved to return negative certificates !
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: g = graphs.HouseGraph()
sage: g.is_line_graph()
True
sage.graphs.line_graph.line_graph(self, labels=True)
Returns the line graph of the (di)graph.
INPUT:
• labels (boolean) – 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.
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()
[(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()
[(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()
[(1, 2, None),
(1, 3, None),
(1, 4, None),
(2, 3, None),
(2, 4, None),
(3, 4, None)]
sage: h.edges()
[((1, 2, None), (2, 3, None), None),
((1, 2, None), (2, 4, None), None),
(continues on next page)
sage.graphs.line_graph.root_graph(g, verbose=False)
Computes the root graph corresponding to the given graph
See the documentation of sage.graphs.line_graph to know how it works.
INPUT:
• g – a graph
• verbose (boolean) – display some information about what is happening inside of the algorithm.
Note: It is best to use this code through is_line_graph(), which first checks that the graph is indeed a
line graph, and deals with the disconnected case. But if you are sure of yourself, dig in !
Warning:
• This code assumes that the graph is connected.
• If the graph is not a line graph, this implementation will take a loooooong time to run. Its first step is
to enumerate all maximal cliques, and that can take a while for general graphs. As soon as there is a
way to iterate over maximal cliques without first building the (long) list of them this implementation
can be updated, and will deal reasonably with non-line graphs too !
This module is a collection of algorithms on spanning trees. Also included in the collection are algorithms for mini-
mum spanning trees. See the book [JoynerNguyenCohen2010] for descriptions of spanning tree algorithms, including
minimum spanning trees.
See also:
• GenericGraph.min_spanning_tree.
Todo
• Rewrite kruskal() to use priority queues. Once Cython has support for generators and the yield statement,
rewrite kruskal() to use yield.
• Parallel version of Boruvka’s algorithm.
• Randomized spanning tree construction.
REFERENCES:
5.8.1 Methods
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 span-
ning tree, only the minimum weight among all (𝑢, 𝑣)-edges is considered, for each pair of vertices 𝑢, 𝑣).
INPUT:
• G – an undirected graph.
• wfunction (weight function) - a function that inputs an edge e and outputs its weight. An edge has the
form (u,v,l), where u and v are vertices, l is a label (that can be of any kind). The wfunction can
be used to transform the label into a weight. In particular:
– if wfunction is not None, the weight of an edge e is wfunction(e);
– if wfunction is None (default) and g is weighted (that is, g.weighted()==True), the weight
of an edge e=(u,v,l) is l, independently on which kind of object l is: the ordering of labels relies
on Python’s operator <;
– if wfunction is None and g is not weighted, we set all weights to 1 (hence, the output can be any
spanning tree).
• check – 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 Boruvka’s
algorithm on that input graph:
– Is G the null graph or graph on one vertex?
– Is G disconnected?
– Is G a tree?
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.
• by_weight – Whether to find MST by using weights of edges provided. Default: by_weight=True.
If wfunction is given, MST is calculated using the weights of edges as per the function. If wfunction
is None, the weight of an edge e=(u,v,l) is l if graph is weighted, or all edge weights are considered
1 if graph is unweighted. If we toggle by_weight=False, all weights are considered as 1 and MST is
calculated.
OUTPUT:
The edges of a minimum spanning tree of G, if one exists, otherwise returns the empty list.
See also:
• min_spanning_tree()
EXAMPLES:
An example from pages 727–728 in [Sahni2000].
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)]
(continues on next page)
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()
EXAMPLES:
An example from pages 727–728 in [Sahni2000].
sage: G.weighted(True)
sage: E = kruskal(G, check=True); E
[(1, 6, 10), (2, 3, 16), (2, 7, 14), (3, 4, 12), (4, 5, 22), (5, 6, 25)]
sage: H = Graph(G.edges(labels=False))
sage: kruskal(H, check=True)
[(1, 2, None), (1, 6, None), (2, 3, None), (2, 7, None), (3, 4, None), (4, 5,
˓→None)]
sage: G.allow_loops(True)
sage: G.allow_multiple_edges(True)
sage: G
Looped multi-graph on 7 vertices
sage: for i in range(20):
....: u = randint(1, 7)
....: v = randint(1, 7)
....: w = randint(0, 20)
....: G.add_edge(u, v, w)
sage: H = copy(G)
sage: H
Looped multi-graph on 7 vertices
sage: def sanitize(G):
....: G.allow_loops(False)
....: E = {}
....: for u, v, _ in G.multiple_edges():
....: E.setdefault(u, v)
....: for u in E:
....: W = sorted(G.edge_label(u, E[u]))
....: for w in W[1:]:
....: G.delete_edge(u, E[u], w)
....: G.allow_multiple_edges(False)
sage: sanitize(H)
sage: H
Graph on 7 vertices
sage: kruskal(G, check=True) == kruskal(H, check=True)
True
˓→'SFO', 337)]
sage.graphs.spanning_tree.random_spanning_tree
Return a random spanning tree of the graph.
This uses the Aldous-Broder algorithm ([Broder89], [Aldous90]) to generate a random spanning tree with the
uniform distribution, as follows.
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.
INPUT:
• output_as_graph – boolean (default: False) whether to return a list of edges or a graph.
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
(continues on next page)
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)
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 𝑥.
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)
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.
AUTHOR : Nathann Cohen
flatten()
Returns a flattened copy of self
If self has only one child, we may as well consider its child’s children, as self encodes no information.
This method recursively “flattens” trees having only on PQ-tree child, and returns it.
EXAMPLES:
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.flatten(x)
sage.graphs.pq_trees.new_P(liste)
sage.graphs.pq_trees.new_Q(liste)
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}]
sage.graphs.pq_trees.set_contiguous(tree, x)
This is an implementation of the algorithm for generating trees with 𝑛 vertices (up to isomorphism) in constant time
per tree described in [WRIGHT-ETAL].
AUTHORS:
• Ryan Dingman (2009-04-16): initial version
REFERENCES:
class sage.graphs.trees.TreeIterator
Bases: object
This class iterates over all trees with n vertices (up to isomorphism).
EXAMPLES:
next()
x.next() -> the next value, or raise StopIteration
AUTHORS:
• Robert Miller, Tom Boothby - original implementation
REFERENCE:
5.11.1 Methods
sage.graphs.matchpoly.complete_poly
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:
sage.graphs.matchpoly.matching_polynomial
Computes the matching polynomial of the graph 𝐺.
If 𝑝(𝐺, 𝑘) denotes the number of 𝑘-matchings (matchings with 𝑘 edges) in 𝐺, then the matching polynomial is
defined as [Godsil93]:
∑︁
𝜇(𝑥) = (−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 [Godsil93]:
• 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 substraction by an addition. It is then converted into the matching polynomial and
returned)
Depending on the value of complement, Godsil’s duality theorem [Godsil93] 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 algo-
rithm. 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:
EXAMPLES:
sage: bt.genus()
1
sage: G = graphs.FlowerSnark()
sage: G = Graph(G, implementation='c_graph', sparse=False)
sage: bt = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[0])
sage: bt.genus()
2
OUTPUT:
the minimal or maximal genus for self’s graph.
EXAMPLES:
sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[0])
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 = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[0])
sage: gb.get_embedding()
{0: [1], 1: [0]}
sage: G = Graph(implementation='c_graph', sparse=False)
sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[0])
sage: gb.get_embedding()
{}
EXAMPLES:
REFERENCES:
[1] http://www.springerlink.com/content/0776127h0r7548v7/
AUTHORS:
• Dima Pasechnik (2015-06-30): Initial version
REFERENCE:
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 linear extension of a directed acyclic graph is a total (linear) ordering on the vertices that is compatible with the
graph in the following sense: if there is a path from x to y in the graph, the x appears before y in the linear extension.
The algorithm implemented in this module is from “Generating Linear Extensions Fast” by Preusse and Ruskey,
which can be found at http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.52.3057 . The algorithm generates
the extensions in constant amortized time (CAT) – a constant amount of time per extension generated, or linear in the
number of extensions generated.
EXAMPLES:
Here we generate the 5 linear extensions of the following directed acyclic graph:
Notice how all of the total orders are compatible with the ordering induced from the graph.
We can also get at the linear extensions directly from the graph. From the graph, the linear extensions are known as
topological sorts
sage: D.topological_sort_generator()
[[0, 1, 2, 3, 4],
[0, 1, 2, 4, 3],
[0, 2, 1, 3, 4],
[0, 2, 1, 4, 3],
[0, 2, 4, 1, 3]]
class sage.graphs.linearextensions.LinearExtensions(dag)
Bases: sage.combinat.combinat.CombinatorialClass
Creates an object representing the class of all linear extensions of the directed acyclic graph code{dag}.
Note that upon construction of this object some pre-computation is done. This is the “preprocessing routine”
found in Figure 7 of “Generating Linear Extensions Fast” by Preusse and Ruskey.
This is an in-place algorithm and the list self.le keeps track of the current linear extensions. The boolean variable
self.is_plus keeps track of the “sign”.
EXAMPLES:
generate_linear_extensions(i)
This a Python version of the GenLE routine found in Figure 8 of “Generating Linear Extensions Fast” by
Pruesse and Ruskey.
Note that this is meant to be called by the list method and is not meant to be used directly.
EXAMPLES:
incomparable(x, y)
Returns True if vertices x and y are incomparable in the directed acyclic graph when thought of as a poset.
EXAMPLES:
list()
Returns a list of the linear extensions of the directed acyclic graph.
Note that once they are computed, the linear extensions are cached in this object.
EXAMPLES:
move(element, direction)
This implements the Move procedure described on page 7 of “Generating Linear Extensions Fast” by
Pruesse and Ruskey.
If direction is “left”, then this transposes element with the element on its left. If the direction is “right”,
then this transposes element with the element on its right.
Note that this is meant to be called by the generate_linear_extensions method and is not meant to be used
directly.
EXAMPLES:
right(i, letter)
If letter ==”b”, then this returns True if and only if self.b[i] is incomparable with the elements to its right
in self.le. If letter == “a”, then it returns True if and only if self.a[i] is incomparable with the element to its
right in self.le and the element to the right is not self.b[i]
This is the Right function described on page 8 of “Generating Linear Extensions Fast” by Pruesse and
Ruskey.
Note that this is meant to be called by the generate_linear_extensions method and is not meant to be used
directly.
EXAMPLES:
switch(i)
This implements the Switch procedure described on page 7 of “Generating Linear Extensions Fast” by
Pruesse and Ruskey.
If i == -1, then the sign is changed. If i > 0, then self.a[i] and self.b[i] are transposed.
Note that this meant to be called by the generate_linear_extensions method and is not meant to be used
directly.
EXAMPLES:
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.
AUTHORS:
• Jonathan Bober, Emily Kirkman (2008-02-09) – initial version
REFERENCE:
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,'a'),(0,2),(0,1),(0,'c'),('a','c'),('a',2),
....: ('a','b'),(1,2),(1,'c'),(2,'b'),(1,'b'),('b','c')], format='list_of_edges')
sage: g.set_embedding({'a':['b',2,0,'c'],'b':['c',1,2,'a'],
....: 'c':['a',0,1,'b'],0:['a',2,1,'c'],1:['b','c',0,2],2:['a','b',1,0]})
sage: newg = minimal_schnyder_wood(g)
sage: sorted(newg.edges(), key=lambda e:(str(e[0]),str(e[1])))
[(0, 2, 'blue'),
(0, 'a', 'green'),
(0, 'c', 'red'),
(continues on next page)
REFERENCES:
sage: G = graphs.DodecahedralGraph()
sage: from sage.graphs.planarity import is_planar
sage: is_planar(G)
True
sage: Graph('@').is_planar()
True
sage: G = graphs.WheelGraph(15)
sage: P = G.plot()
sage: P.show() # long time
If you create a graph in Sage using the Graph command, then plot that graph, the positioning of nodes is determined
using the spring-layout algorithm. For the special graph constructors, which you get using graphs.[tab], the
positions are preset. For example, consider the Petersen graph with default node positioning vs. the Petersen graph
constructed by this database:
For all the constructors in this database (except some random graphs), the position dictionary is filled in, instead of
using the spring-layout algorithm.
Plot options
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().
partition A partition of the vertex set. If specified, plot will show each cell in a different
color. vertex_colors takes precedence.
dist The distance between multiedges.
vertex_labels Whether or not to draw vertex labels.
edge_color The default color for edges not listed in edge_colors.
spring Use spring layout to finalize the current layout.
pos The position dictionary of vertices
loop_size The radius of the smallest loop.
color_by_label Whether to color the edges according to their labels. This also accepts a function
or dictionary mapping labels to colors.
iterations The number of times to execute the spring layout algorithm.
talk Whether to display the vertices in talk mode (larger and white).
edge_labels Whether or not to draw edge labels.
vertex_size The size to draw the vertices.
edge_thickness The thickness of the edges.
dim The dimension of the layout – 2 or 3.
edge_style The linestyle of the edges. It should be one of “solid”, “dashed”, “dotted”,
dashdot”, or “-“, “–”, “:”, “-.”, respectively.
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).
vertex_shape The shape to draw the vertices. Currently unavailable for Multi-edged Di-
Graphs.
vertex_colors Dictionary of vertex coloring : each key is a color recognizable by matplotlib,
and each corresponding entry is a list of vertices.
by_component Whether to do the spring layout by connected component – a boolean.
heights A dictionary mapping heights to the list of vertices at this height.
graph_border Whether or not to draw a frame around the graph.
max_dist The max distance range to allow multiedges.
prog Which graphviz layout program to use – one of “circo”, “dot”, “fdp”, “neato”,
or “twopi”.
edge_colors a dictionary specifying edge colors: each key is a color recognized by mat-
plotlib, and each entry is a list of edges.
vertex_color Default color for vertices not listed in vertex_colors dictionary.
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.
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'
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 dic-
tionaries 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:
sage: T = graphs.RandomLobster(25,0.3,0.3)
sage: T.show(layout='tree',tree_orientation='up') # indirect doctest
plot(**kwds)
Returns 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.
sage: G = graphs.HeawoodGraph().copy(sparse=True)
sage: for u,v,l in G.edges():
....: G.set_edge_label(u,v,'(' + str(u) + ',' + str(v) + ')')
sage: G.graphplot(edge_labels=True).show()
With the partition option, we can separate out same-color groups of vertices:
sage: D = graphs.DodecahedralGraph()
(continues on next page)
sage: G = graphs.PetersenGraph()
sage: G.allow_loops(True)
sage: G.add_edge(0,0)
sage: G.show()
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
sage: t.set_edge_label(0,1,-7)
sage: t.set_edge_label(0,5,3)
(continues on next page)
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:
set_edges(**edge_options)
Sets the edge (or arrow) plotting parameters for the GraphPlot object.
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:
sage: GP.set_edges(edge_color='black')
sage: GP.plot()
Graphics object consisting of 26 graphics primitives
sage: GP.set_edges(edge_color='black')
sage: GP.plot()
Graphics object consisting of 28 graphics primitives
set_pos()
Sets the position plotting parameters for this GraphPlot.
EXAMPLES:
This function is called implicitly by the code below:
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
set_vertices(**vertex_options)
Sets 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:
sage: g = Graph({}, loops=True, multiedges=True, sparse=True)
sage: g.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 = g.graphplot(vertex_size=100, edge_labels=True, color_by_label=True,
....: edge_style='dashed')
sage: GP.set_vertices(talk=True)
sage: GP.plot()
Graphics object consisting of 26 graphics primitives
sage: GP.set_vertices(vertex_color='green', vertex_shape='^')
sage: GP.plot()
Graphics object consisting of 26 graphics primitives
show(**kwds)
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.
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.
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)
The ID of a vertex is its index in the vertex list.
• edges – each edge is a dictionary defining :
– source – the ID (int) of the edge’s source
– target – the ID (int) of the edge’s destination
– color – the edge’s color (integer)
– value – thickness of the edge
– strength – the edge’s strength in the automatic layout
– color – color (hexadecimal code)
– curve – distance from the barycenter of the two endpoints and the center of the edge. It defines the curve
of the edge, which can be useful for multigraphs.
• pos – a list whose 𝑖 th element is a dictionary defining the position of the 𝑖 th vertex.
It also contains the definition of some numerical/boolean variables whose definition can be found in the documen-
tation of show() : directed, charge, link_distance, link_strength, gravity, vertex_size,
edge_thickness.
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
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
This module implements several algorithms to compute the vertex separation of a digraph and the corresponding
ordering 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 [Kin92] and Bodlaender [Bod98].
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
computing 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 [SP10]. 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 [CMN14].
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 [CMN14] 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 [CMN14] 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.19.4 REFERENCES
5.19.5 Authors
5.19.6 Methods
sage.graphs.graph_decompositions.vertex_separation.is_valid_ordering
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
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: h.vertices()
[{0, 1}, {3, 4}, {2, 3}, {1, 2}]
sage: h.edges(labels=None)
[({0, 1}, {1, 2}), ({2, 3}, {3, 4}), ({1, 2}, {2, 3})]
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()
[{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: h.vertices()
[{1, 2, 5}, {2, 3, 4}, {0, 1, 5}, {2, 4, 5}]
sage: h.edges(labels=None)
[({1, 2, 5}, {2, 4, 5}), ({0, 1, 5}, {1, 2, 5}), ({2, 4, 5}, {2, 3, 4})]
sage.graphs.graph_decompositions.vertex_separation.lower_bound
Returns a lower bound on the vertex separation of 𝐺
INPUT:
• G – a Graph or a DiGraph
OUTPUT:
Note: This method runs in exponential time but has no memory constraint.
EXAMPLES:
On a circuit:
sage.graphs.graph_decompositions.vertex_separation.path_decomposition
Returns the pathwidth of the given graph and the ordering of the vertices resulting in a corresponding path
decomposition.
INPUT:
• G – a Graph
• algorithm – (default: "BAB") Specify the 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 – (default: None) This is parameter is 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 – (default: None) This is parameter is 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) – whether to display information on the computations.
• max_prefix_length – (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 – (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
sage.graphs.graph_decompositions.vertex_separation.pathwidth
Computes the pathwidth of self (and provides a decomposition)
INPUT:
• k (integer) – the width to be considered. When k is an integer, the method checks that the graph has
pathwidth ≤ 𝑘. If k is None (default), the method computes the optimal pathwidth.
• certificate – whether to return the path-decomposition itself.
• algorithm – (default: "BAB") Specify the 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 graph has pathwidth ≤ 𝑘, in
which cas it will return the first found solution with width ≤ 𝑘 is certificate==True.
– 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.
• verbose (boolean) – whether to display information on the computations.
• max_prefix_length – (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 – (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:
Return the pathwidth of self. When k is specified, it returns False when no path-decomposition of width
≤ 𝑘 exists or True otherwise. When certificate=True, the path-decomposition is also returned.
See also:
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: decomp.vertices()
[{1, 2, 5}, {2, 3, 4}, {0, 1, 5}, {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)
sage.graphs.graph_decompositions.vertex_separation.vertex_separation
Returns an optimal ordering of the vertices and its cost for vertex-separation.
INPUT:
• G – a Graph or a DiGraph
• algorithm – (default: "BAB") Specify the 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 – (default: None) This is parameter is 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 – (default: None) This is parameter is 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) – whether to display information on the computations.
• max_prefix_length – (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 – (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.
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
(continues on next page)
sage: D = digraphs.Path(8)
sage: print(vertex_separation(D))
(0, [7, 6, 5, 4, 3, 2, 1, 0])
sage: D = DiGraph( random_DAG(30) )
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, [8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3])
sage.graphs.graph_decompositions.vertex_separation.vertex_separation_BAB
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 [CMN14]. The implementation is valid for both Graph and DiGraph.
See the documentation of the vertex_separation module.
INPUT:
• G – a Graph or a DiGraph.
• cut_off – (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 – (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 – (default: 20) limits the length of the stored prefixes to prevent storing too many
prefixes.
• max_prefix_number – (default: 10**6) upper bound on the number of stored prefixes used to prevent
using too much memory.
• verbose – (default: False) display some information when set to True.
OUTPUT:
Testing for the existence of a solution with width strictly less than upper_bound:
sage.graphs.graph_decompositions.vertex_separation.vertex_separation_MILP
Computes 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
separation of 𝐺. This MILP is an improved version of the formulation proposed in [SP10]. See the module's
documentation for more details on this MILP formulation.
INPUT:
• G – a Graph or a DiGraph
• integrality – (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 – (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.
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
Returns an optimal ordering of the vertices and its cost for vertex-separation.
INPUT:
• G – a Graph or a DiGraph.
• verbose (boolean) – 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
Returns 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 modules wraps a C code from Philipp Klaus Krause computing a an optimal rank-decomposition [RWKlause].
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 qual 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 [RWKlause] is a program that calculates rank-width and rank-decompositions. It is based on ideas from :
• “Computing rank-width exactly” by Sang-il Oum [Oum]
• “Sopra una formula numerica” by Ernesto Pascal
• “Generation of a Vector from the Lexicographical Index” by B.P. Buckles and M. Lybanon [BL]
• “Fast additions on masked integers” by Michael D. Adams and David S. Wise [AW]
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 comarable 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
sage: m = min(u,v)
sage: bipartition = (m, Set(g.vertices()) - m)
sage: bipartition
({8, 9}, {0, 1, 2, 3, 4, 5, 6, 7})
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 [RWKlause].
• Nathann Cohen : Interface with Sage and documentation.
REFERENCES:
5.20.1 Methods
sage.graphs.graph_decompositions.rankwidth.mkgraph
Return the graph corresponding to the current rank-decomposition.
(This function is for internal use)
EXAMPLES:
sage: from sage.graphs.graph_decompositions.rankwidth import rank_decomposition
sage: g = graphs.PetersenGraph()
sage: rank_decomposition(g)
(3, Graph on 19 vertices)
sage.graphs.graph_decompositions.rankwidth.rank_decomposition
Computes 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) – 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 documentation).
EXAMPLES:
sage: g = Graph()
sage: rank_decomposition(g)
(0, Graph on 0 vertices)
5.21.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.21.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 – 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:
sage: from sage.graphs.graph_decompositions.bandwidth import bandwidth
sage: G = graphs.PetersenGraph()
sage: bandwidth(G,3)
False
sage: bandwidth(G)
(5, [0, 4, 5, 8, 1, 9, 3, 7, 6, 2])
sage: G.adjacency_matrix(vertices=[0, 4, 5, 8, 1, 9, 3, 7, 6, 2])
[0 1 1 0 1 0 0 0 0 0]
[1 0 0 0 0 1 1 0 0 0]
[1 0 0 1 0 0 0 1 0 0]
[0 0 1 0 0 0 1 0 1 0]
[1 0 0 0 0 0 0 0 1 1]
[0 1 0 0 0 0 0 1 1 0]
[0 1 0 1 0 0 0 0 0 1]
[0 0 1 0 0 1 0 0 0 1]
[0 0 0 1 1 1 0 0 0 0]
[0 0 0 0 1 0 1 1 0 0]
sage: G = graphs.ChvatalGraph()
sage: bandwidth(G)
(6, [0, 5, 9, 4, 10, 1, 6, 11, 3, 8, 7, 2])
sage: G.adjacency_matrix(vertices=[0, 5, 9, 4, 10, 1, 6, 11, 3, 8, 7, 2])
[0 0 1 1 0 1 1 0 0 0 0 0]
[0 0 0 1 1 1 0 1 0 0 0 0]
[1 0 0 0 1 0 0 1 1 0 0 0]
[1 1 0 0 0 0 0 0 1 1 0 0]
[0 1 1 0 0 0 1 0 0 1 0 0]
[1 1 0 0 0 0 0 0 0 0 1 1]
[1 0 0 0 1 0 0 1 0 0 0 1]
[0 1 1 0 0 0 1 0 0 0 1 0]
[0 0 1 1 0 0 0 0 0 0 1 1]
[0 0 0 1 1 0 0 0 0 0 1 1]
[0 0 0 0 0 1 0 1 1 1 0 0]
[0 0 0 0 0 1 1 0 1 1 0 0]
5.22 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:
𝑐(𝑣1 , ..., 𝑣𝑛 ) = max 𝑐′ ({𝑣1 , ..., 𝑣𝑖 })
1≤𝑖≤𝑛−1
Where
𝑐′ (𝑆) = |{(𝑢, 𝑤) ∈ 𝐸(𝐺) | 𝑢 ∈ 𝑆 and 𝑤 ∈ 𝑉 (𝐺)∖𝑆}|
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
computing 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 stricly 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
stricly larger than 𝑘.
This formulation corresponds to method cutwidth_MILP().
5.22.3 Authors
5.22.4 Methods
sage.graphs.graph_decompositions.cutwidth.cutwidth(G, algorithm=’exponential’,
cut_off=0, solver=None, ver-
bose=False)
Return the cutwidth of the graph and the corresponding vertex ordering.
INPUT:
• G – a Graph or a DiGraph
sage.graphs.graph_decompositions.cutwidth.cutwidth_MILP(G, lower_bound=0,
solver=None, verbose=0)
MILP formulation for the cutwidth of a Graph.
This method uses a mixed integer linear program (MILP) for determining an optimal layout for the cutwidth of
𝐺. See the module's documentation for more details on this MILP formulation.
INPUT:
• G – a Graph
• lower_bound – (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 – (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.
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 – (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)
Returns 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 recogni-
tion algorithm for graphs that can be written as a Cartesian product of smaller ones.
References:
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 [HIK11].
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 [HIK11] 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.23.2 Methods
sage.graphs.graph_decompositions.graph_products.is_cartesian_product
Tests whether the graph is a Cartesian product.
INPUT:
• certificate (boolean) – 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) – 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.
This is set to False by default.
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: g.is_cartesian_product(g, relabeling = True)
(True, {0: (0, 0), 1: (0, 1), 2: (0, 2), 3: (0, 3),
4: (0, 4), 5: (5, 0), 6: (5, 1), 7: (5, 2),
8: (5, 3), 9: (5, 4), 10: (10, 0), 11: (10, 1),
12: (10, 2), 13: (10, 3), 14: (10, 4), 15: (15, 0),
16: (15, 1), 17: (15, 2), 18: (15, 3), 19: (15, 4),
20: (20, 0), 21: (20, 1), 22: (20, 2), 23: (20, 3),
24: (20, 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
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.24.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 ‘u,v‘ of elements in the set ‘S‘, and for any vertex ‘w‘ outside of it, add ‘w‘ to ‘S‘ if ‘d_{G}(u,w) +
d_{G}(w,v) = d_{G}(u,v)‘. When no vertex can be added anymore, the set ‘S‘ 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)
Returns the convex hull of a set of vertices.
INPUT:
• vertices – A list of vertices.
EXAMPLES:
hull_number(value_only=True, verbose=False)
Computes 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) – whether to return only the hull number (default) or a minimum set whose
convex hull is the whole graph.
• verbose (boolean) – whether to display information on the LP.
COMPLEXITY:
This problem is NP-Hard [CHZ02], 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
enumerate, 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:
REFERENCE:
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)
REFERENCES:
5.25.1 Methods
sage.graphs.weakly_chordal.is_long_antihole_free
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 ) [NikolopoulosPalios07] ( 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
Tests whether g contains an induced cycle of length at least 5.
INPUT:
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
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 = len(s.vertices())
sage: s.is_isomorphic( graphs.CycleGraph(l) )
True
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
computation 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().
• 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 in-
stead 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 hap-
pens 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 computers with low memory space.
AUTHOR:
• Nathann Cohen (2011)
• David Coudert (2014) – 2sweep, multi-sweep and iFUB for diameter computation
REFERENCE:
5.26.2 Functions
sage.graphs.distances_all_pairs.diameter
Returns the diameter of 𝐺.
This algorithm returns Infinity if the (di)graph is not connected. It can also quickly return a lower bound on the
diameter using the 2sweep and multi-sweep schemes.
INPUT:
• algorithm – (default: ‘iFUB’) specifies the algorithm to use among:
– 'standard' – Computes the diameter of the input (di)graph as the largest eccentricity of its ver-
tices. This is the classical algorithm with time complexity in 𝑂(𝑛𝑚).
– '2sweep' – Computes a lower bound on the diameter of an unweighted undirected graph using 2
BFS, as proposed in [MLH08]. It first selects a vertex 𝑣 that is at largest distance from an initial vertex
source using BFS. Then it performs a second BFS from 𝑣. The largest distance from 𝑣 is returned as
a lower bound on the diameter of 𝐺. The time complexity of this algorithm is linear in the size of 𝐺.
𝑑(𝑣, 𝑎) <= 𝑖, ∀𝑎 ∈ 𝐴
𝑑(𝑣, 𝑏) >= 𝑖, ∀𝑏 ∈ 𝐵
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 al-
gorithm used in [CGH+13]), 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.
• 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: if d1!=d2 or d1!=d3: print("Something goes wrong!")
sage.graphs.distances_all_pairs.distances_all_pairs
Returns 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: from sage.graphs.distances_all_pairs import distances_all_pairs
sage: g = graphs.PetersenGraph()
sage: distances_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}}
sage.graphs.distances_all_pairs.distances_and_predecessors_all_pairs
Returns 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().
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.
The integer corresponding to a vertex is its index in the list G.vertices().
EXAMPLES:
sage: from sage.graphs.distances_all_pairs import distances_and_predecessors_all_
˓→pairs
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}},
{0: {0: None, 1: 0, 2: 1, 3: 4, 4: 0, 5: 0, 6: 1, 7: 5, 8: 5, 9: 4},
1: {0: 1, 1: None, 2: 1, 3: 2, 4: 0, 5: 0, 6: 1, 7: 2, 8: 6, 9: 6},
2: {0: 1, 1: 2, 2: None, 3: 2, 4: 3, 5: 7, 6: 1, 7: 2, 8: 3, 9: 7},
3: {0: 4, 1: 2, 2: 3, 3: None, 4: 3, 5: 8, 6: 8, 7: 2, 8: 3, 9: 4},
(continues on next page)
sage.graphs.distances_all_pairs.distances_distribution
Returns 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}
sage.graphs.distances_all_pairs.eccentricity
Return the vector of eccentricities in G.
The array returned is of length 𝑛, and its 𝑖-th component is the eccentricity of the ith vertex in G.vertices().
INPUT:
• G – a Graph or a DiGraph.
• algorithm – (default: 'standard') name of the method used to compute the eccentricity of the
vertices. Available algorithms are 'standard' which performs a BFS from each vertex and 'bounds'
which uses the fast algorithm proposed in [TK13] for undirected graphs.
EXAMPLES:
sage.graphs.distances_all_pairs.floyd_warshall
Computes the shortest path/distances between all pairs of vertices.
For more information on the Floyd-Warshall algorithm, see the Wikipedia article Floyd-Warshall_algorithm.
INPUT:
• gg – the graph on which to work.
• paths (boolean) – whether to return the dictionary of shortest paths. Set to True by default.
• distances (boolean) – whether to return the dictionary of distances. Set to False by default.
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, 1): {(0, 1): None, (1, 0): (0, 0), (0, 0): (0, 1), (1, 1): (0, 1)},
(1, 0): {(0, 1): (0, 0), (1, 0): None, (0, 0): (1, 0), (1, 1): (1, 0)},
(0, 0): {(0, 1): (0, 0), (1, 0): (0, 0), (0, 0): None, (1, 1): (0, 1)},
(1, 1): {(0, 1): (1, 1), (1, 0): (1, 1), (0, 0): (0, 1), (1, 1): None}}
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},
2: {0: 1, 1: 1, 2: 0, 3: 1},
3: {0: 2, 1: 1, 2: 1, 3: 0}}
sage.graphs.distances_all_pairs.is_distance_regular
Tests 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) – if set to True, the function returns the pair (b,c) of lists of integers instead
of True (see the definition above). Set to False by default.
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.shortest_path_all_pairs
Returns 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.
The integer corresponding to a vertex is its index in the list G.vertices().
EXAMPLES:
sage.graphs.distances_all_pairs.wiener_index
Returns the Wiener index of the graph.
The Wiener index of a graph 𝐺 can be defined in two equivalent ways [KRG96b] :
• 𝑊 (𝐺) = 21 𝑢,𝑣∈𝐺 𝑑(𝑢, 𝑣) where 𝑑(𝑢, 𝑣) denotes the distance between vertices 𝑢 and 𝑣.
∑︀
EXAMPLES:
From [GYLL93c], cited in [KRG96b]:
sage: g=graphs.PathGraph(10)
sage: w=lambda x: (x*(x*x -1)/6)
sage: g.wiener_index()==w(10)
True
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 his Altermundus.com site.
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: http://altermundus.com/pages/tkz/
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',
....: vertex_color='green',
....: vertex_label_color='red'
....: )
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}
(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}
\Vertex[style={minimum size=0.2cm,draw=cv13,fill=cfv13,text=clv13,shape=circle},
˓→LabelOut=false,L=\hbox{$13$},x=3.6126cm,y=4.7524cm]{v13}
%
\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 {})
EXAMPLES:
dot2tex_picture()
Calls 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,]
%%
\node (node_3) at (...bp,...bp) [draw,draw=none] {$\left(1, 1\right)$};
\node (node_2) at (...bp,...bp) [draw,draw=none] {$\left(1, 0\right)$};
\node (node_1) at (...bp,...bp) [draw,draw=none] {$\left(0, 1\right)$};
\node (node_0) at (...bp,...bp) [draw,draw=none] {$\left(0, 0\right)$};
\draw [black,->] (node_0) ..controls (...bp,...bp) and (...bp,...bp) ..
˓→(node_3);
%
\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_1) at (...bp,...bp) [draw,draw=none] {$3333$};
\node (node_0) at (...bp,...bp) [draw,draw=none] {$88$};
\draw [black,->] (node_1) ..controls (...bp,...bp) and (...bp,...bp) ..
˓→(node_0);
\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)
Returns the current value of the named option.
INPUT:
• option_name – the name of an option
OUTPUT:
If the name is not present in __graphlatex_options it is an error to ask for it. If an option has not
been set then the default value is returned. Otherwise, the value of the option is returned.
EXAMPLES:
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()
Returns 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 unmodified. 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)
Sets, modifies, clears 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. How-
ever, 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 – 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 in-
stalled).
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 – 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 minimal effort. For a custom
appearance set this to ‘Custom’ and use the options described below to override the default values.
• units – default: ‘cm’ – a natural unit of measurement used for all dimensions. Possible values are:
‘in’,’mm’,’cm’,’pt’, ‘em’, ‘ex’
• scale – 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 – default: (5,5) – overall dimensions (width, length) of the bounding box around
the entire graphic image
• margins – 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 tkzpicture.
• 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 – default: ‘circle’ – a string for 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– 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.
• vertex_sizes – a dictionary of sizes for some of the vertices.
• vertex_labels – default: True – a boolean to determine whether or not to display the vertex
labels. If False subsequent options about vertex labels are ignored.
• vertex_labels_math – default: True – when true, if a label is a string that begins and ends with
dollar signs, then the string will be rendered as a latex string. Otherwise, the label will be automat-
ically subjected to the latex() method and rendered accordingly. If False the label is rendered
as its textual representation according to the _repr method. Support for arbitrarily-complicated
mathematics is not especially robust.
• vertex_label_color – default: ‘black’ – a single color to use as the default for labels of vertices.
See the explanation above for the vertex_color option to see possible values.
• vertex_label_colors – a dictionary whose keys are vertices of the graph and whose values
are colors. These will be used for the text of the labels 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_label_placement – default: ‘center’ – if ‘center’ the label is centered in the interior
of the vertex and the vertex will expand to contain the label. Giving instead a pair of numbers will
place the label exterior to the vertex at a certain distance from the edge, and at an angle to the positive
x-axis, similar in spirit to polar coordinates.
• vertex_label_placements – a dictionary of placements indexed by the vertices. See the ex-
planation for vertex_label_placement for the possible values.
• edge_color – default: ‘black’ – a single color to use as the default for an edge. See the explanation
above for the vertex_color option to see possible values.
• edge_colors – a dictionary whose keys are edges of the graph and whose values are colors. These
will be used to color the 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.
• edge_fills – default: False – a boolean that determines if an edge has a second color running
down the middle. This can be a useful effect for highlighting edge crossings.
• edge_fill_color – default: ‘black’ – a single color to use as the default for the fill color of
an edge. The boolean switch edge_fills must be set to True for this to have an effect. See the
explanation above for the vertex_color option to see possible values.
• edge_fill_colors – a dictionary whose keys are edges of the graph and whose values are colors.
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.
• edge_thickness – default: 0.1 - a number specifying the width of the edges. Note that tkz-graph
does not interpret this number for loops.
• edge_thicknesses – a dictionary of thicknesses for some of the edges of a graph. These values
need only be specified for a proper subset of the vertices. Specified values will supersede a default
value.
• edge_labels – default: False – a boolean that determines if edge labels are shown. If False
subsequent options about edge labels are ignored.
• edge_labels_math – default: True – a boolean that controls how edge labels are rendered.
Read the explanation for the vertex_labels_math option, which behaves identically. Support
for arbitrarily-complicated mathematics is not especially robust.
• edge_label_color – default: ‘black’ – a single color to use as the default for labels of edges.
See the explanation above for the vertex_color option to see possible values.
• 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 – default: True a boolean that 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 – 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’) – a pair, that determines 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 – 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 – a 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 - a 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
LaTeX options for Petersen graph: {'tkz_style': 'Simple'}
sage: opts.set_option('tkz_style')
sage: opts
LaTeX options for Petersen graph: {}
sage: opts.set_option('bad_name', 'nonsense')
Traceback (most recent call last):
...
ValueError: bad_name is not a LaTeX option for a graph.
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
commands 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 Altermundus.com
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.
\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)
%
\end{tikzpicture}
See the introduction to the graph_latex module for more information on the use of this routine.
sage.graphs.graph_latex.check_tkz_graph()
Checks if the proper LaTeX packages for the tikzpicture environment are installed in the user’s environ-
ment, 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()
Returns True if the proper LaTeX packages for the tikzpicture environment are installed in the user’s
environment, 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()
Adds 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()
sage: g = graphs.CompleteGraph(3)
sage: graph_editor(g) # not tested
sage: graph_editor(graphs.HouseGraph()) # not tested
sage: graph_editor(graph_name='my_graph') # not tested
sage: h = graphs.StarGraph(6)
sage: graph_editor(h, replace_input=False) # not tested
sage.graphs.graph_editor.graph_to_js(g)
Returns a string representation of a Graph instance usable by the graph_editor(). The encoded informa-
tion is the number of vertices, their 2D positions, and a list of edges.
INPUT:
• g - a Graph instance
OUTPUT:
• a string
EXAMPLES:
sage: graph_to_js(graphs.StarGraph(2))
'num_vertices=3;edges=[[0,1],[0,2]];pos=[[0.0,0.5],[0.0,0.0],[0.0,1.0]];'
AUTHORS:
• Robert L. Miller (2007-02-10): initial version
sage: l = ['N@@?N@UGAGG?gGlKCMO','XsGGWOW?CC?C@HQKHqOjYKC_uHWGX?P?~
˓→TqIKA`OA@SAOEcEA??']
sage: graphs_list.from_graph6(l)
[Graph on 15 vertices, Graph on 25 vertices]
sage.graphs.graph_list.from_sparse6(data)
Returns 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: l = [':P_`cBaC_ACd`C_@BC`ABDHaEH_@BF_@CHIK_@BCEHKL_BIKM_BFGHI',':f`??KO?B_
˓→OOSCGE_?OWONDBO?GOJBDO?_SSJdApcOIG`?og_UKEbg?_SKFq@[CCBA`p?
˓→oYMFp@gw]Qaa@xEMHDb@hMCBCbQ@ECHEcAKKQKFPOwo[PIDQ{KIHEcQPOkVKEW_
˓→WMNKqPWwcRKOOWSKIGCqhWt??___WMJFCahWzEBa`xOu[MpPPKqYNoOOOKHHDBPs|??__
˓→gWMKEcAHKgTLErqA?A@a@G{kVLErs?GDBA@XCs\NggWSOJIDbHh@?A@aF']
sage: graphs_list.from_sparse6(l)
[Looped multi-graph on 17 vertices, Looped multi-graph on 39 vertices]
sage.graphs.graph_list.from_whatever(data)
Returns 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.graphs.graph_list.show_graphs(graph_list, **kwds)
Shows a maximum of 20 graphs from 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 if 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:
• list – a 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))
sage: glist.append(graphs.DiamondGraph())
sage: glist.append(graphs.HouseGraph())
sage: glist.append(graphs.HouseXGraph())
sage: glist.append(graphs.KrackhardtKiteGraph())
sage: glist.append(graphs.LadderGraph(5))
sage: glist.append(graphs.LollipopGraph(5,6))
sage: glist.append(graphs.PathGraph(15))
sage: glist.append(graphs.PetersenGraph())
sage: glist.append(graphs.StarGraph(17))
sage: glist.append(graphs.WheelGraph(9))
sage: len(glist)
14
sage: graphs_list.show_graphs(glist)
sage: gq = GraphQuery(display_cols=['graph6'],num_vertices=5)
sage: g = gq.get_graphs_list()
sage: len(g)
34
sage: graphs_list.show_graphs(g)
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 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.30.1 Functions
sage: g.is_isomorphic(graphs.PetersenGraph())
True
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.graphs.graph_input.from_oriented_incidence_matrix(G, M, loops=False,
multiedges=False,
weighted=False)
Fill G with the data of an oriented incidence matrix.
An oriented incidence matrix is the incidence matrix of a directed graph, in which each non-loop edge corre-
sponds to a +1 and a −1, indicating its source and destination.
INPUT:
• G – a DiGraph
• M – an incidence matrix
• loops, multiedges, weighted (booleans) – whether to consider the graph as having loops, multiple
edges, or weights. Set to False by default.
EXAMPLES:
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.31 Hyperbolicity
Definition :
The hyperbolicity 𝛿 of a graph 𝐺 has been defined by Gromov [Gromov87] 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 𝑎,𝑏,𝑐,𝑑∈𝑉 (𝐺)
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 [FIV12]. 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 [CCL15]. 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
decreasing 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 [Soto11] 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
[Soto11] 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 [BCCM15]: 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
REFERENCES:
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.31.1 Methods
• 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
optimal. Otherwise, the approximation factor if delta_UB/delta.
EXAMPLES:
Hyperbolicity of a 3 × 3 grid:
Hyperbolicity of a PetersenGraph:
Comparison of results:
The hyperbolicity of a graph is the maximum value over all its biconnected components:
This module implements a deletion-contraction algorithm for computing the Tutte polynomial as described in the
paper [Gordon10].
Authors:
• Mike Hansen (06-2013), Implemented the algorithm.
• Jernej Azarija (06-2013), Tweaked the code, added documentation
5.32.1 Definition
Given a graph 𝐺, with 𝑛 vertices and 𝑚 edges and 𝑘(𝐺) connected components we define the Tutte polynomial of 𝐺
as
∑︁
(𝑥 − 1)𝑘(𝐻)−𝑐 (𝑦 − 1)𝑘(𝐻)−|𝐸(𝐻)|−𝑛
𝐻
5.32.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
sage: E.unlabeled_edges
[(0, 1), (1, 2), (2, 3)]
sage: E.vertices
[0, 1, 2, 3]
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())
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()
[(0, 4, None), (0, 5, None), (3, 6, None), (3, 7, None)]
sage: len(G.edges())
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)
sage: E.vertices
[0, 1, 2, 3]
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: from sage.graphs.tutte_polynomial import contracted_edge
sage: G = Graph(multiedges=True)
sage: G.add_edges([(0,1,'a'),(1,2,'b'),(0,3,'c')])
sage: G.edges()
[(0, 1, 'a'), (0, 3, 'c'), (1, 2, 'b')]
sage: with contracted_edge(G,(0,1)) as Y:
....: G.edges(); G.vertices()
[(1, 2, 'b'), (1, 3, 'c')]
[1, 2, 3]
sage: G.edges()
[(0, 1, 'a'), (0, 3, 'c'), (1, 2, 'b')]
sage.graphs.tutte_polynomial.edge_multiplicities(G)
Return the a dictionary of multiplicities of the edges in the graph 𝐺.
EXAMPLES:
sage: from sage.graphs.tutte_polynomial import edge_multiplicities
sage: G = Graph({1: [2,2,3], 2: [2], 3: [4,4], 4: [2,2,2]})
sage: sorted(edge_multiplicities(G).items())
[((1, 2), 2), ((1, 3), 1), ((2, 2), 1), ((2, 4), 3), ((3, 4), 2)]
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: from sage.graphs.tutte_polynomial import removed_edge
sage: G = Graph()
sage: G.add_edge(0,1)
sage: G.edges()
[(0, 1, None)]
sage: with removed_edge(G,(0,1)) as Y:
....: G.edges(); G.vertices()
[]
[0, 1]
sage: G.edges()
[(0, 1, None)]
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: from sage.graphs.tutte_polynomial import removed_loops
sage: G = Graph(multiedges=True, loops=True)
sage: G.add_edges([(0,1,'a'),(1,2,'b'),(0,0,'c')])
sage: G.edges()
[(0, 0, 'c'), (0, 1, 'a'), (1, 2, 'b')]
sage: with removed_loops(G) as Y:
....: G.edges(); G.vertices(); Y
[(0, 1, 'a'), (1, 2, 'b')]
[0, 1, 2]
(continues on next page)
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:
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
sage: 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()
(continues on next page)
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 [Eppstein2008].
For more information on partial cubes, see the Wikipedia article Partial cube.
REFERENCE:
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 [Eppstein2008], 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.33.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:
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
[Eppstein2008]. The algorithm runs in 𝑂(𝑛2 ) time, where 𝑛 is the number of vertices. See the documenta-
tion of partial_cube for an overview of the algorithm.
INPUT:
• certificate (boolean; False) – The function returns True or False according to the graph, when
certificate = False. When certificate = True and the graph is a partial cube, the func-
tion 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
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 representant
of ℎ1 , then a representant of ℎ2 compatible with ℎ1 , then a representant 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
next()
x.next() -> the next value, or raise StopIteration
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: binary_string_from_dig6('?????_@?CG??B??@OG?C?G???GO??W@a???CO???OACC?OA?
˓→P@G??O??????G??C????c?G?CC?_?@???C_??_?C????PO?C_??AA?OOAHCA___?CC?A?CAOGO??????
˓→A??G?GR?C?_o`???g???A_C?OG??O?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?', 63)
˓→'000000000000000000000000000000100000000001000000000100001000000000000000000011000000000000000
˓→.. (continues on next page)
˓→1000000000000000000000000000000001000000000101101100000010000000000100111000000000000000000000
˓→'
˓→'0000000000000000000001000000000000010000100000100000001000000000000000100000000100000.
˓→..
˓→0100000000000001000100000010000000000000000000000000000010100000000010110000000000000100100000
˓→'
sage.graphs.generic_graph_pyx.binary_string_from_graph6(s, n)
Decodes a binary string from its graph6 representation
This helper function is the inverse of 𝑅 from [McK].
INPUT:
• s – a graph6 string
• n – the length of the binary string encoded by s.
EXAMPLES:
˓→A??G?GR?C?_o`???g???A_C?OG??O?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?', 63)
˓→'000000000000000000000000000000100000000001000000000100001000000000000000000011000000000000000
˓→..
˓→1000000000000000000000000000000001000000000101101100000010000000000100111000000000000000000000
˓→'
sage: binary_string_from_graph6('???C?@AA?_?A?O?C??S??O?q_?P?CHD??@?C?GC???C??GG?
˓→C_??O?COG????I?J??Q??O?_@@??@??????', 32)
˓→'0000000000000000000001000000000000010000100000100000001000000000000000100000000100000.
˓→..
˓→0100000000000001000100000010000000000000000000000000000010100000000010110000000000000100100000
˓→'
sage.graphs.generic_graph_pyx.binary_string_to_graph6(x)
Transforms a binary string into its graph6 representation.
This helper function is named 𝑅 in [McK].
INPUT:
• x – a binary string.
EXAMPLES:
REFERENCES:
sage.graphs.generic_graph_pyx.find_hamiltonian(G, max_iter=100000, re-
set_bound=30000, back-
track_bound=1000, find_path=False)
Randomized backtracking for finding Hamiltonian cycles and paths.
ALGORITHM:
A path P is maintained during the execution of the algorithm. Initially the path will contain an edge of the
graph. Every 10 iterations the path is reversed. Every reset_bound iterations the path will be cleared and
the procedure is restarted. Every backtrack_bound steps we discard the last five vertices and continue with
the procedure. The total number of steps in the algorithm is controlled by max_iter. If a Hamiltonian cycle
or Hamiltonian path is found it is returned. If the number of steps reaches max_iter then a longest path is
returned. See OUTPUT for more details.
INPUT:
• G – graph
• max_iter – maximum number of iterations
• reset_bound – number of iterations before restarting the procedure
• backtrack_bound – number of iterations to elapse before discarding the last 5 vertices of the path.
• find_path – (default: False) if set to True, will search a Hamiltonian path; if False, will search
for a Hamiltonian cycle
OUTPUT:
A pair (B, P), where B is a Boolean and P is a list of vertices.
• If B is True and find_path is False, P represents a Hamiltonian cycle.
• If B is True and find_path is True, P represents a Hamiltonian path.
• If B is False, then P represents the longest path found during the execution of the algorithm.
Warning: May loop endlessly when run on a graph with vertices of degree 1.
EXAMPLES:
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: 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.length_and_string_from_graph6(s)
Returns a pair (length,graph6_string) from a graph6 string of unknown length.
This helper function is the inverse of 𝑁 from [McK].
INPUT:
• s – a graph6 string describing an binary vector (and encoding its length).
EXAMPLES:
sage: from sage.graphs.generic_graph_pyx import length_and_string_from_graph6
sage: length_and_string_from_graph6('~??~?????_@?CG??B??@OG?C?G???GO??W@a???CO???
˓→OACC?OA?P@G??O??????G??C????c?G?CC?_?@???C_??_?C????PO?C_??AA?OOAHCA___?CC?A?
˓→CAOGO??????A??G?GR?C?_o`???g???A_C?OG??O?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?')
(continues on next page)
˓→O?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: length_and_string_from_graph6('_???C?@AA?_?A?O?C??S??O?q_?P?CHD??@?C?GC???C?
˓→?GG?C_??O?COG????I?J??Q??O?_@@??@??????')
(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)
Encodes a small integer (i.e. a number of vertices) as a graph6 string.
This helper function is named 𝑁 [McK].
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] # abs tol 0.1
[0.00..., 0.03...]
sage: pos[902] # abs tol 0.1
[-0.48..., -0.10...]
sage: len(pos) == G.order()
True
With split=True, each component of G is layed 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] # abs tol 0.1
[2.21..., -0.00...]
sage: pos[902] # abs tol 0.1
[3.07..., 0.86...]
sage: len(pos) == G.order()
True
sage.graphs.generic_graph_pyx.spring_layout_fast_split(G, **options)
Graphs each component of G separately, placing them adjacent to each other. This is done because on a dis-
connected 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 spring_layout_fast_split
sage: spring_layout_fast_split(G)
{0: [0.77..., 0.06...],
...
902: [3.13..., 0.22...]}
AUTHOR:
Robert Bradshaw
sage.graphs.generic_graph_pyx.transitive_reduction_acyclic(G)
Returns the transitive reduction of an acyclic digraph
INPUT:
• G – an acyclic digraph.
EXAMPLES:
5.35 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.35.1 Authors
5.35.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()
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 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 symetries, 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). In order to avoid symetries an orientation of an
arbitrary edge is fixed.
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 a list of the bridges (or cut edges) of given undirected graph.
cleave() Return the connected subgraphs separated by the input vertex cut.
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.36.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
orientation)
• 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: tric.print_triconnected_components()
Triconnected: [(3, 13, None), (1, 13, None), (2, 13, None), (2, 3, None), (1, 2,
˓→None), (3, 1, 'newVEdge0')]
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())
[('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)]
Todo: Cythonize the code for more efficiency. Many data structures can be turned into integer arrays. More
care is needed for the doubly linked list and for the lists of lists. Note that the internal graph copy must allow
edge addition due to the insertion of virtual edges.
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.vertices() 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.edges())
sage: tric = TriconnectivitySPQR(G)
sage: Tree = tric.get_spqr_tree()
sage: all(u[1].is_isomorphic(C4) for u in Tree.vertices() 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]:
sage.graphs.connectivity.blocks_and_cut_vertices
Compute the blocks and cut vertices of the graph.
In the case of a digraph, this computation is done on the underlying graph.
A cut vertex is one whose deletion increases the number of connected components. A block is a maximal
induced subgraph which itself has no cut vertices. Two distinct blocks cannot overlap in more than a single cut
vertex.
INPUT:
• algorithm – The algorithm to use in computing the blocks and cut vertices of G. The following al-
gorithms are supported:
OUTPUT: (B, C), where B is a list of blocks - each is a list of vertices and the blocks are the corresponding
induced subgraphs - and C is a list of cut vertices.
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.graphs.connectivity.blocks_and_cuts_tree
Returns 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 self (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()
[('B', (0, 1, 4, 5, 2, 6, 3, 7, 8, 9))]
sage.graphs.connectivity.bridges
Returns a list of the bridges (or cut edges).
A bridge is an edge whose deletion disconnects the undirected graph. A disconnected graph has no bridge.
INPUT:
sage.graphs.connectivity.cleave
Return the connected subgraphs separated by the input vertex cut.
Given a connected (multi)graph 𝐺 and a vertex cut 𝑋, this method computes the list of subgraphs of 𝐺 induced
by each connected component 𝑐 of 𝐺 ∖ 𝑋 plus 𝑋, i.e., 𝐺[𝑐 ∪ 𝑋].
INPUT:
• G – a Graph.
• cut_vertices – (default: None) a set of vertices representing a vertex cut of G. If no vertex cut is
given, the method will compute one via a call to vertex_connectivity().
• virtual_edges – boolean (default: True); whether to add virtual edges to the sides of the cut or not.
A virtual edge is an edge between a pair of vertices of the cut that are not connected by an edge in G.
• 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 sage.
numerical.mip.MixedIntegerLinearProgram.solve() of the class sage.numerical.
mip.MixedIntegerLinearProgram.
• verbose – integer (default: 0). Sets the level of verbosity. Set to 0 by default, which means quiet.
OUTPUT: A triple (𝑆, 𝐶, 𝑓 ), where
• 𝑆 is a list of the graphs that are sides of the vertex cut.
• 𝐶 is the graph of the cocycles. For each pair of vertices of the cut, if there exists an edge between them,
𝐶 has one copy of each edge connecting them in G per sides of the cut plus one extra copy. Furthermore,
when virtual_edges == True, if a pair of vertices of the cut is not connected by an edge in G, then
it has one virtual edge between them per sides of the cut.
• 𝑓 is the complement of the subgraph of G induced by the vertex cut. Hence, its vertex set is the vertex
cut, and its edge set is the set of virtual edges (i.e., edges between pairs of vertices of the cut that are not
connected by an edge in G). When virtual_edges == False, the edge set is empty.
EXAMPLES:
If there is an edge between cut vertices:
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(), f1.edges()
([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.edges())
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(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)]
sage.graphs.connectivity.connected_component_containing_vertex
Return a list of the vertices connected to vertex.
INPUT:
• G (generic_graph) – the input graph.
sage.graphs.connectivity.connected_components
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 (generic_graph) – the input graph.
• sort – boolean (default True) whether to sort vertices inside each component
EXAMPLES:
sage.graphs.connectivity.connected_components_number
Return the number of connected components.
INPUT:
• G (generic_graph) – the input graph.
EXAMPLES:
sage.graphs.connectivity.connected_components_sizes
Return the sizes of the connected components as a list.
sage.graphs.connectivity.connected_components_subgraphs
Return a list of connected components as graph objects.
EXAMPLES:
sage.graphs.connectivity.edge_connectivity
Returns the edge connectivity of the graph.
For more information, see the Wikipedia article Connectivity_(graph_theory).
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 (generic_graph) - the input 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 edge cut are returned.
• implementation – selects an implementation:
– When set to None (default): selects the best implementation available.
– When set to "boost", we use the Boost graph library (which is much more efficient). It is not avail-
able when edge_labels=True, and it is unreliable for directed graphs (see trac ticket #18753).
– When set to "Sage", we use Sage’s implementation.
• use_edge_labels – boolean (default: False)
– When set to True, computes a weighted minimum cut where each edge has a weight defined by its
label. (If an edge has no label, 1 is assumed.). Implies boost = False.
– When set to False, each edge has weight 1.
• vertices – boolean (default: False)
– When set to True, also returns the two sets of vertices that are disconnected by the cut. Implies
value_only=False.
• solver – (default: None) Specify a Linear Program (LP) solver to be used (ignored if
implementation='boost'). If set to None, the default one is used. For more infor-
mation 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:
A basic application on the PappusGraph:
The edge connectivity of a complete graph ( and of a random graph ) is its minimum degree, and one of the two
parts of the bipartition is reduced to only one vertex. The cutedges 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: g = graphs.RandomGNP(15,.5)
sage: tree = Graph()
sage: tree.add_edges(g.min_spanning_tree())
sage: for u,v in tree.edge_iterator(labels=None):
....: tree.set_edge_label(u,v,random())
sage: minimum = min([l for u,v,l in tree.edge_iterator()])
sage: [value, [(u,v,l)]] = edge_connectivity(tree, value_only=False, use_edge_
˓→labels=True)
When value_only = True and implementation="sage", this function is optimized for small con-
nectivity 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
sage: g = graphs.RandomGNP(15,.3)
sage: edge_connectivity(g) == edge_connectivity(g, implementation="sage")
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
Test whether the (di)graph is connected.
Note that in a graph, path connected is equivalent to connected.
INPUT:
• G (generic_graph) – the input graph.
See also:
• is_biconnected()
EXAMPLES:
sage.graphs.connectivity.is_cut_edge
Returns True if the input edge is a cut-edge or a bridge.
A cut edge (or bridge) is an edge that when removed increases the number of connected components. This
function works with simple graphs as well as graphs with loops and multiedges. In a digraph, a cut edge is an
edge that when removed increases the number of (weakly) connected components.
INPUT: The following forms are accepted
• is_cut_edge(G, 1, 2 )
• is_cut_edge(G, (1, 2) )
• 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
Returns True if 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 (generic_graph) - the input graph.
• u – a vertex
• weak – (default: False) boolean set to 𝑇 𝑟𝑢𝑒 if the connectivity of directed graphs is to be taken in the
weak sense, that is ignoring edges orientations.
OUTPUT:
Returns 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(6)
sage: is_cut_vertex(G,7)
Traceback (most recent call last):
...
ValueError: The input vertex is not in the vertex set.
sage.graphs.connectivity.is_strongly_connected
Returns whether the current DiGraph is strongly connected.
EXAMPLES:
The circuit is obviously strongly connected
sage.graphs.connectivity.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.
This method decomposes a biconnected graph into cycles, cocycles, and 3-connected blocks summed over
cocycles, 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 – The algorithm to use in computing the SPQR tree of G. The following algorithms are
supported:
• 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 sage.
numerical.mip.MixedIntegerLinearProgram.solve() of the class sage.numerical.
mip.MixedIntegerLinearProgram.
• verbose – integer (default: 0). Sets the level of verbosity. Set to 0 by default, which means quiet.
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: from sage.graphs.connectivity import spqr_tree
sage: G = Graph(2)
sage: for i in range(3):
....: G.add_clique([0, 1, G.add_vertex(), G.add_vertex()])
sage: Tree = spqr_tree(G)
sage: Tree.order()
4
sage: K4 = graphs.CompleteGraph(4)
sage: all(u[1].is_isomorphic(K4) for u in Tree.vertices() if u[0] == 'R')
True
sage: from sage.graphs.connectivity import spqr_tree_to_graph
sage: G.is_isomorphic(spqr_tree_to_graph(Tree))
True
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.vertices() 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.edges())
sage: Tree = spqr_tree(G)
sage: Tree.order()
13
sage: all(u[1].is_isomorphic(C4) for u in Tree.vertices() 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))
(continues on next page)
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
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
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
Returns the strongly connected component containing a given vertex
INPUT:
• G (DiGraph) - the input graph.
• 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.graphs.connectivity.strongly_connected_components_digraph
Returns the digraph of the strongly connected components
INPUT:
• G (DiGraph) - the input graph.
• keep_labels – boolean (default: False)
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 from one to the
other in 𝐺.
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
(continues on next page)
True
The following digraph has three strongly connected components, and the digraph of those is a chain:
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
Returns 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.graphs.connectivity.vertex_connectivity
Return the vertex connectivity of the graph.
For more information, see the Wikipedia article Connectivity_(graph_theory) and the Wikipedia article K-
vertex-connected_graph.
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 (generic_graph) - the input 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)
– When set to True, also returns 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 – (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, see the method solve
of the class MixedIntegerLinearProgram. Use method sage.numerical.backends.
generic_backend.default_mip_solver() to know which default solver is used or to set the
default solver.
• verbose – integer (default: 0). Sets the level of verbosity. Set to 0 by default, which means quiet.
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.
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
SIX
• Index
• Module Index
• Search Page
833
Sage Reference Manual: Graph Theory, Release 8.4
[GYLL93] I. Gutman, Y.-N. Yeh, S.-L. Lee, and Y.-L. Luo. Some recent results in the theory of the Wiener number.
Indian Journal of Chemistry, 32A:651–661, 1993.
[Borgatti95] Stephen P. Borgatti. (1995). Centrality and AIDS. [Online] Available: http://www.analytictech.com/
networks/centaids.htm
[OLJ14] Paul W. Olsen, Alan G. Labouseur, Jeong-Hyon Hwang. Efficient Top-k Closeness Centrality Search Pro-
ceedings of the IEEE 30th International Conference on Data Engineering (ICDE), 2014
[HSSNX] Aric Hagberg, Dan Schult and Pieter Swart. NetworkX documentation. [Online] Available: http://networkx.
github.io/documentation/latest/reference/index.html
[LPForm] Nathann Cohen, Several Graph problems and their Linear Program formulations, https://hal.
archives-ouvertes.fr/inria-00504914/en
[KaisPacking] Thomas Kaiser A short proof of the tree-packing theorem Arxiv 0911.2809
[SchrijverCombOpt] Alexander Schrijver Combinatorial optimization: polyhedra and efficiency 2003
[dotspec] http://www.graphviz.org/doc/info/lang.html
[Rose75] Rose, D.J. and Tarjan, R.E., Algorithmic aspects of vertex elimination, Proceedings of seventh annual ACM
symposium on Theory of computing Page 254, ACM 1975
[Fulkerson65] Fulkerson, D.R. and Gross, OA Incidence matrices and interval graphs Pacific J. Math 1965 Vol. 15,
number 3, pages 835–855
[BM04] John M. Boyer and Wendy J. Myrvold, On the Cutting Edge: Simplified O(n) Planarity by Edge Addition.
Journal of Graph Algorithms and Applications, Vol. 8, No. 3, pp. 241-273, 2004.
[erdos1978choos] Erdos, P. and Rubin, A.L. and Taylor, H. Proc. West Coast Conf. on Combinatorics Graph Theory
and Computing, Congressus Numerantium vol 26, pages 125–157, 1979
[SW12] John Shareshian and Michelle Wachs. Chromatic quasisymmetric functions and Hessenberg varieties. Con-
figuration Spaces. CRM Series. Scuola Normale Superiore. (2012) pp. 433-460. http://www.math.miami.edu/
~wachs/papers/chrom.pdf
[BC15] Patrick Brosnan and Timothy Y. Chow. Unit interval orders and the dot action on the cohomology of regular
semisimple Hessenberg varieties. (2015) Arxiv 1511.00773v1.
[Stanley95] R. P. Stanley, A symmetric function generalization of the chromatic polynomial of a graph, Adv. Math.,
*111* no.1 (1995), 166-194.
[BroKer1973] Coen Bron and Joep Kerbosch. (1973). Algorithm 457: Finding All Cliques of an Undirected Graph.
Commun. ACM. v 16. n 9. pages 575-577. ACM Press. [Online] Available: http://www.ram.org/computing/
rambin/rambin.html
835
Sage Reference Manual: Graph Theory, Release 8.4
[PSW1996] Boris Pittel, Joel Spencer and Nicholas Wormald. Sudden Emergence of a Giant k-Core in a Random
Graph. (1996). J. Combinatorial Theory. Ser B 67. pages 111-151. [Online] Available: http://cs.nyu.edu/cs/faculty/
spencer/papers/k-core.pdf
[BZ] Vladimir Batagelj and Matjaz Zaversnik. An 𝑂(𝑚) Algorithm for Cores Decomposition of Networks. Arxiv
cs/0310049v1.
[HST] Matthew D. Horton, H. M. Stark, and Audrey A. Terras, What are zeta functions of graphs and what are they
good for? in Quantum graphs and their applications, 173-189, Contemp. Math., Vol. 415
[Terras] Audrey Terras, Zeta functions of graphs: a stroll through the garden, Cambridge Studies in Advanced Math-
ematics, Vol. 128
[ScottStorm] Geoffrey Scott and Christopher Storm, The coefficients of the Ihara zeta function, Involve (http://msp.
org/involve/2008/1-2/involve-v1-n2-p08-p.pdf)
[AhaBerZiv07] R. Aharoni and E. Berger and R. Ziv Independent systems of representatives in weighted graphs
Combinatorica vol 27, num 3, p253–267 2007
[ABCHRS08] L. Addario-Berry, M. Chudnovsky, F. Havet, B. Reed, P. Seymour Bisimplicial vertices in even-hole-
free graphs Journal of Combinatorial Theory, Series B vol 98, n.6 pp 1119-1164, 2008
[CRST06] M. Chudnovsky, G. Cornuejols, X. Liu, P. Seymour, K. Vuskovic Recognizing berge graphs Combinatorica
vol 25, n 2, pages 143–186 2005
[SPGT] M. Chudnovsky, N. Robertson, P. Seymour, R. Thomas. The strong perfect graph theorem Annals of Mathe-
matics vol 164, number 1, pages 51–230 2006
[GraphClasses] A. Brandstadt, VB Le and JP Spinrad Graph classes: a survey SIAM Monographs on Discrete Math-
ematics and Applications}, 1999
[Marcolli2009] Matilde Marcolli, Feynman Motives, Chapter 3, Feynman integrals and algebraic varieties, http://
www.its.caltech.edu/~matilde/LectureN3.pdf
[Brown2011] Francis Brown, Multiple zeta values and periods: From moduli spaces to Feynman integrals, in Con-
temporary Mathematics vol 539
[Lein] Tom Leinster, The magnitude of metric spaces. Doc. Math. 18 (2013), 857-905.
[AMOZ06] Asahiro, Y. and Miyano, E. and Ono, H. and Zenmyo, K. Graph orientation algorithms to minimize the
maximum outdegree Proceedings of the 12th Computing: The Australasian Theory Symposium Volume 51, page
20 Australian Computer Society, Inc. 2006
[HabPau10] Michel Habib and Christophe Paul A survey of the algorithmic aspects of modular decomposition Com-
puter Science Review vol 4, number 1, pages 41–59, 2010 http://www.lirmm.fr/~paul/md-survey.pdf
[TedCorHabPaul08] Marc Tedder, Derek Corneil, Michel Habib and Christophe Paul Arxiv 0710.3901
[Har62] Harary, F (1962). The determinant of the adjacency matrix of a graph, SIAM Review 4, 202-210
[Biggs93] Biggs, N. L. Algebraic Graph Theory, 2nd ed. Cambridge, England: Cambridge University Press, pp. 45,
1993.
[RT75] Read, R. C. and Tarjan, R. E. Bounds on Backtrack Algorithms for Listing Cycles, Paths, and Spanning Trees
Networks, Volume 5 (1975), numer 3, pages 237-252.
[PitSta] Jim Pitman, Richard Stanley, “A polytope related to empirical distributions, plane trees, parking functions,
and the associahedron”, Arxiv math/9908029
[GQwiki] Wikipedia article Generalized_quadrangle
[PT09] S. Payne, J. A. Thas. Finite generalized quadrangles. European Mathematical Society, 2nd edition, 2009.
[CP05] A.Cossidente and T.Penttila Hemisystems on the Hermitian surface Journal of London Math. Soc. 72(2005),
731–741
836 Bibliography
Sage Reference Manual: Graph Theory, Release 8.4
[CharLes1996] Chartrand, G. and Lesniak, L.: Graphs and Digraphs. Chapman and Hall/CRC, 1996.
[Newman2003] Newman, M.E.J. The Structure and function of complex networks, SIAM Review vol. 45, no. 2
(2003), pp. 167-256.
[ChungLu2002] Chung, Fan and Lu, L. Connected components in random graphs with given expected degree se-
quences. Ann. Combinatorics (6), 2002 pp. 125-145.
[ARETT-DOREE] Arett, Danielle and Doree, Suzanne “Coloring and counting on the Hanoi graphs” Mathematics
Magazine, Volume 83, Number 3, June 2010, pages 200-9
[Mat78] R. A. Mathon, Symmetric conference matrices of order 𝑝𝑞 2 + 1, Canad. J. Math. 30 (1978) 321-331
[ST78] J. J. Seidel and D. E. Taylor, Two-graphs, a second survey. Algebraic methods in graph theory, Vol. I, II
(Szeged, 1978), pp. 689–711, Colloq. Math. Soc. János Bolyai, 25, North-Holland, Amsterdam-New York, 1981.
[Mu07] M. Muzychuk. A generalization of Wallis-Fon-Der-Flaass construction of strongly regular graphs. J. Alge-
braic Combin., 25(2):169–187, 2007.
[Hu75] X. L. Hubaut. Strongly regular graphs. Disc. Math. 13(1975), pp 357–381. doi:10.1016/0012-365X(75)90057-
6
[HHL09] T. Huang, L. Huang, M.I. Lin On a class of strongly regular designs and quasi-semisymmetric designs. In:
Recent Developments in Algebra and Related Areas, ALM vol. 8, pp. 129–153. International Press, Somerville
(2009)
[AB16] A.E. Brouwer Personal communication, 2016
[Schaeffer99] Gilles Schaeffer, Random Sampling of Large Planar Maps and Convex Polyhedra, Annual ACM Sym-
posium on Theory of Computing (Atlanta, GA, 1999)
[ErdRen1959] P. Erdos and A. Renyi. On Random Graphs, Publ. Math. 6, 290 (1959).
[Gilbert1959] E. N. Gilbert. Random Graphs, Ann. Math. Stat., 30, 1141 (1959).
[BatBra2005] V. Batagelj and U. Brandes. Efficient generation of large random networks. Phys. Rev. E, 71, 036113,
2005.
[HolmeKim2002] Holme, P. and Kim, B.J. Growing scale-free networks with tunable clustering, Phys. Rev. E (2002).
vol 65, no 2, 026107.
[boucheron2001] Boucheron, S. and FERNANDEZ de la VEGA, W., On the Independence Number of Random
Interval Graphs, Combinatorics, Probability and Computing v10, issue 05, Pages 385–396, Cambridge Univ Press,
2001
[NWS99] Newman, M.E.J., Watts, D.J. and Strogatz, S.H. Random graph models of social networks. Proc. Nat. Acad.
Sci. USA 99, 2566-2572.
[KimVu2003] Kim, Jeong Han and Vu, Van H. Generating random regular graphs. Proc. 35th ACM Symp. on Thy. of
Comp. 2003, pp 213-222. ACM Press, San Diego, CA, USA. http://doi.acm.org/10.1145/780542.780576
[StegerWormald1999] Steger, A. and Wormald, N. Generating random regular graphs quickly. Prob. and Comp. 8
(1999), pp 377-396.
[PS2006] Dominique Poulalhon and Gilles Schaeffer, Optimal coding and sampling of triangulations, Algorithmica
46 (2006), no. 3-4, 505-527, http://www.lix.polytechnique.fr/~poulalho/Articles/PoSc_Algorithmica06.pdf
[CFHM12] On the Hyperbolicity of Small-World and Tree-Like Random Graphs Wei Chen, Wenjie Fang, Guangda
Hu, Michael W. Mahoney Arxiv 1201.1717
[LLWC] Chien-Hung Lin, Jia-Jie Liu, Yue-Li Wang, William Chung-Kung Yen, The Hub Number of Sierpinski-Like
Graphs, Theory Comput Syst (2011), vol 49, doi:10.1007/s00224-010-9286-3
[Co81] A. M. Cohen, A synopsis of known distance-regular graphs with large diameters, Stichting Mathematisch
Centrum, 1981.
Bibliography 837
Sage Reference Manual: Graph Theory, Release 8.4
838 Bibliography
Sage Reference Manual: Graph Theory, Release 8.4
[Polhill09] J. Polhill, Negative Latin square type partial difference sets and amorphic association schemes with Galois
rings, Journal of Combinatorial Designs 17, no. 3 (2009): 266-282. http://onlinelibrary.wiley.com/doi/10.1002/jcd.
20206/abstract
[CDB13] I. Cardinali and B. De Bruyn, Spin-embeddings, two-intersection sets and two-weight codes, Ars Comb.
109 (2013): 309-319. https://biblio.ugent.be/publication/4241842/file/4241845.pdf
[vLintSchrijver81] J. H. van Lint, and A. Schrijver (1981), Construction of strongly regular graphs, two-weight codes
and partial geometries by finite fields, Combinatorica, 1(1), 63-73.
[Delsarte72] Ph. Delsarte, Weights of linear codes and strongly regular normed spaces, Discrete Mathematics (1972),
Volume 3, Issue 1, Pages 47-64, doi:10.1016/0012-365X(72)90024-6
[NisOst2003] Sampo Niskanen and Patric R. J. Ostergard, “Cliquer User’s Guide, Version 1.0,” Communications
Laboratory, Helsinki University of Technology, Espoo, Finland, Tech. Rep. T48, 2003.
[Koh04] E. Kohler. Recognizing graphs without asteroidal triples. Journal of Discrete Algorithms 2(4):439-452, Dec.
2004 doi:10.1016/j.jda.2004.04.005
[LB62] C. G. Lekkerkerker, J. Ch. Boland. Representation of a finite graph by a set of intervals on the real line.
Fundamenta Mathematicae, 51:45-64, 1962.
[ATGA] Advanced Topics in Graph Algorithms, Ron Shamir, http://www.cs.tau.ac.il/~rshamir/atga/atga.html
[Cleanup] A cleanup on transitive orientation, Orders, Algorithms, and Applications, 1994, Simon, K. and Trunz, P.,
ftp://ftp.inf.ethz.ch/doc/papers/ti/ga/ST94.ps.gz
[Whitney32] Congruent graphs and the connectivity of graphs, Whitney, American Journal of Mathematics, pages
150–168, 1932, available on JSTOR
[Harary69] Graph Theory, Harary, Addison-Wesley, 1969
[Beineke70] Lowell Beineke, Characterizations of derived graphs, Journal of Combinatorial Theory, Vol. 9(2), pages
129-135, 1970 doi:10.1016/S0021-9800(70)80019-9
[Aldous90] D. Aldous, ‘The random walk construction of uniform spanning trees’, SIAM J Discrete Math 3 (1990),
450-465.
[Broder89] A. Broder, ‘Generating random spanning trees’, Proceedings of the 30th IEEE Symposium on Foundations
of Computer Science, 1989, pp. 442-447. doi:10.1109/SFCS.1989.63516, <http://www.cs.cmu.edu/~15859n/
RelatedWork/Broder-GenRanSpanningTrees.pdf>_
[CormenEtAl2001] Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein. Introduction to
Algorithms. 2nd edition, The MIT Press, 2001.
[GoodrichTamassia2001] Michael T. Goodrich and Roberto Tamassia. Data Structures and Algorithms in Java. 2nd
edition, John Wiley & Sons, 2001.
[JoynerNguyenCohen2010] David Joyner, Minh Van Nguyen, and Nathann Cohen. Algorithmic Graph Theory. 2010,
http://code.google.com/p/graph-theory-algorithms-book/
[Sahni2000] Sartaj Sahni. Data Structures, Algorithms, and Applications in Java. McGraw-Hill, 2000.
[Haj] M. Hajiaghayi http://www-math.mit.edu/~hajiagha/pp11.ps
[WRIGHT-ETAL] Wright, Robert Alan; Richmond, Bruce; Odlyzko, Andrew; McKay, Brendan D. Constant time
generation of free trees. SIAM J. Comput. 15 (1986), no. 2, 540–548.
[Godsil93] Chris Godsil (1993) Algebraic Combinatorics.
[Lovasz1979] László Lovász, “On the Shannon capacity of a graph”, IEEE Trans. Inf. Th. 25(1979), 1-7.
[Brehm2000] Enno Brehm, 3-Orientations and Schnyder 3-Tree-Decompositions, 2000
Bibliography 839
Sage Reference Manual: Graph Theory, Release 8.4
[Bod98] A partial k-arboretum of graphs with bounded treewidth, Hans L. Bodlaender, Theoretical Computer Science
209(1-2):1-45, 1998.
[Kin92] The vertex separation number of a graph equals its path-width, Nancy G. Kinnersley, Information Processing
Letters 42(6):345-350, 1992.
[SP10] Lightpath Reconfiguration in WDM networks, Fernando Solano and Michal Pioro, IEEE/OSA Journal of Op-
tical Communication and Networking 2(12):1010-1021, 2010.
[CMN14] Experimental Evaluation of a Branch and Bound Algorithm for computing Pathwidth, David Coudert,
Dorian Mazauric, and Nicolas Nisse. In Symposium on Experimental Algorithms (SEA), volume 8504 of LNCS,
Copenhagen, Denmark, pages 46-58, June 2014, https://hal.inria.fr/hal-00943549/document
[RWKlause] Philipp Klaus Krause – rw v0.2 http://pholia.tdi.informatik.uni-frankfurt.de/~philipp/software/rw.shtml
[Oum] Sang-il Oum Computing rank-width exactly Information Processing Letters, 2008 vol. 109, n. 13, p. 745–748
Elsevier http://mathsci.kaist.ac.kr/~sangil/pdf/2008exp.pdf
[BL] Buckles, B.P. and Lybanon, M. Algorithm 515: generation of a vector from the lexicographical index ACM
Transactions on Mathematical Software (TOMS), 1977 vol. 3, n. 2, pages 180–182 ACM
[AW] Adams, M.D. and Wise, D.S. Fast additions on masked integers ACM SIGPLAN Notices, 2006 vol. 41, n.5,
pages 39–45 ACM http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.86.1801&rep=rep1&type=pdf
[HIK11] Handbook of Product Graphs, R. Hammack, W. Imrich, S. Klavzar, CRC press, 2011
[CHZ02] F. Harary, E. Loukakis, C. Tsouros The geodetic number of a graph Mathematical and computer modelling
vol. 17 n11 pp.89–95, 1993
[NikolopoulosPalios07] Nikolopoulos, S.D. and Palios, L. Detecting holes and antiholes in graphs Algorithmica, 2007
Vol. 47, number 2, pages 119–138 http://www.cs.uoi.gr/~stavros/C-Papers/C-2004-SODA.pdf
[KRG96b] S. Klavzar, A. Rajapakse, and I. Gutman. The Szeged and the Wiener index of graphs. Applied Mathemat-
ics Letters, 9(5):45–49, 1996.
[GYLL93c] I. Gutman, Y.-N. Yeh, S.-L. Lee, and Y.-L. Luo. Some recent results in the theory of the Wiener number.
Indian Journal of Chemistry, 32A:651–661, 1993.
[CGH+13] P. Crescenzi, R. Grossi, M. Habib, L. Lanzi, A. Marino. On computing the diameter of real-world undi-
rected graphs. Theor. Comput. Sci. 514: 84-95 (2013) doi:10.1016/j.tcs.2012.09.018
[CGI+10] P. Crescenzi, R. Grossi, C. Imbrenda, L. Lanzi, and A. Marino. Finding the Diameter in Real-World Graphs:
Experimentally Turning a Lower Bound into an Upper Bound. Proceedings of 18th Annual European Symposium
on Algorithms. Lecture Notes in Computer Science, vol. 6346, 302-313. Springer (2010).
[MLH08] C. Magnien, M. Latapy, and M. Habib. Fast computation of empirically tight bounds for the diameter of
massive graphs. ACM Journal of Experimental Algorithms 13 (2008) http://dx.doi.org/10.1145/1412228.1455266
[TK13] F. W. Takes and W. A. Kosters. Computing the eccentricity distribution of large graphs. Algorithms 6:100-118
(2013) http://dx.doi.org/10.3390/a6010100
[BCCM15] M. Borassi, D. Coudert, P. Crescenzi, and A. Marino. On Computing the Hyperbolicity of Real-World
Graphs. Proceedings of the 23rd European Symposium on Algorithms (ESA 2015)
[CCL15] N. Cohen, D. Coudert, and A. Lancin. On computing the Gromov hyperbolicity. ACM Journal of Experi-
mental Algorithmics, 20(1.6):1-18, 2015. doi:10.1145/2780652 or [https://hal.inria.fr/hal-01182890].
[FIV12] H. Fournier, A. Ismail, and A. Vigneron. Computing the Gromov hyperbolicity of a discrete metric space.
Arxiv 1210.3323.
[Gromov87] M. Gromov. Hyperbolic groups. Essays in Group Theory, 8:75–263, 1987.
[Soto11] M. A. Soto Gomez. 2011. Quelques proprietes topologiques des graphes et applications a internet et aux
reseaux. Ph.D. Dissertation. Univ. Paris Diderot (Paris 7).
840 Bibliography
Sage Reference Manual: Graph Theory, Release 8.4
[Gordon10] Computing Tutte Polynomials. Gary Haggard, David J. Pearce and Gordon Royle. In ACM Transactions
on Mathematical Software, Volume 37(3), article 24, 2010. Preprint: http://homepages.ecs.vuw.ac.nz/~djp/files/
TOMS10.pdf
[Eppstein2008] David Eppstein, “Recognizing partial cubes in quadratic time”, J. Graph Algorithms and Applications
15 (2): 269-293, 2011. Arxiv 0705.1025
[McK] McKay, Brendan. ‘Description of graph6 and sparse6 encodings.’ http://cs.anu.edu.au/~bdm/data/formats.txt
(2007-02-13)
Bibliography 841
Sage Reference Manual: Graph Theory, Release 8.4
842 Bibliography
PYTHON MODULE INDEX
c
sage.combinat.designs.incidence_structures, 625
g
sage.graphs.asteroidal_triples, 657
sage.graphs.base.boost_graph, 615
sage.graphs.base.c_graph, 546
sage.graphs.base.dense_graph, 584
sage.graphs.base.graph_backends, 608
sage.graphs.base.overview, 545
sage.graphs.base.sparse_graph, 572
sage.graphs.base.static_dense_graph, 593
sage.graphs.base.static_sparse_backend, 602
sage.graphs.base.static_sparse_graph, 596
sage.graphs.bipartite_graph, 336
sage.graphs.centrality, 655
sage.graphs.cliquer, 653
sage.graphs.comparability, 660
sage.graphs.connectivity, 809
sage.graphs.convexity_properties, 755
sage.graphs.digraph, 299
sage.graphs.digraph_generators, 486
sage.graphs.distances_all_pairs, 760
sage.graphs.generic_graph, 1
sage.graphs.generic_graph_pyx, 801
sage.graphs.genus, 686
sage.graphs.graph, 204
sage.graphs.graph_coloring, 643
sage.graphs.graph_database, 499
sage.graphs.graph_decompositions.bandwidth, 744
sage.graphs.graph_decompositions.cutwidth, 746
sage.graphs.graph_decompositions.graph_products, 751
sage.graphs.graph_decompositions.rankwidth, 742
sage.graphs.graph_decompositions.vertex_separation, 730
sage.graphs.graph_editor, 782
sage.graphs.graph_generators, 349
sage.graphs.graph_generators_pyx, 499
843
Sage Reference Manual: Graph Theory, Release 8.4
sage.graphs.graph_input, 786
sage.graphs.graph_latex, 768
sage.graphs.graph_list, 782
sage.graphs.graph_plot, 696
sage.graphs.graph_plot_js, 727
sage.graphs.hyperbolicity, 789
sage.graphs.hypergraph_generators, 623
sage.graphs.independent_sets, 658
sage.graphs.isgci, 534
sage.graphs.line_graph, 667
sage.graphs.linearextensions, 690
sage.graphs.lovasz_theta, 689
sage.graphs.matchpoly, 683
sage.graphs.orientations, 807
sage.graphs.partial_cube, 799
sage.graphs.planarity, 696
sage.graphs.pq_trees, 676
sage.graphs.schnyder, 693
sage.graphs.spanning_tree, 671
sage.graphs.strongly_regular_db, 512
sage.graphs.trees, 682
sage.graphs.tutte_polynomial, 794
sage.graphs.weakly_chordal, 757
Symbols
__eq__() (sage.graphs.generic_graph.GenericGraph method), 7
A
acyclic_edge_coloring() (in module sage.graphs.graph_coloring), 644
add_arc() (sage.graphs.base.c_graph.CGraph method), 547
add_arc() (sage.graphs.base.dense_graph.DenseGraph method), 586
add_arc() (sage.graphs.base.sparse_graph.SparseGraph method), 575
add_arc_label() (sage.graphs.base.sparse_graph.SparseGraph method), 576
add_clique() (sage.graphs.generic_graph.GenericGraph method), 8
add_cycle() (sage.graphs.generic_graph.GenericGraph method), 8
add_edge() (sage.graphs.base.dense_graph.DenseGraphBackend method), 590
add_edge() (sage.graphs.base.graph_backends.GenericGraphBackend method), 609
add_edge() (sage.graphs.base.sparse_graph.SparseGraphBackend method), 581
add_edge() (sage.graphs.bipartite_graph.BipartiteGraph method), 340
add_edge() (sage.graphs.generic_graph.GenericGraph method), 9
add_edges() (sage.graphs.base.dense_graph.DenseGraphBackend method), 590
add_edges() (sage.graphs.base.graph_backends.GenericGraphBackend method), 609
add_edges() (sage.graphs.base.sparse_graph.SparseGraphBackend method), 581
add_edges() (sage.graphs.generic_graph.GenericGraph method), 10
add_path() (sage.graphs.generic_graph.GenericGraph method), 11
add_vertex() (sage.graphs.base.c_graph.CGraph method), 547
add_vertex() (sage.graphs.base.c_graph.CGraphBackend method), 558
add_vertex() (sage.graphs.base.graph_backends.GenericGraphBackend method), 610
add_vertex() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 604
add_vertex() (sage.graphs.base.static_sparse_backend.StaticSparseCGraph method), 607
add_vertex() (sage.graphs.bipartite_graph.BipartiteGraph method), 340
add_vertex() (sage.graphs.generic_graph.GenericGraph method), 11
add_vertices() (sage.graphs.base.c_graph.CGraph method), 549
add_vertices() (sage.graphs.base.c_graph.CGraphBackend method), 559
add_vertices() (sage.graphs.base.graph_backends.GenericGraphBackend method), 610
add_vertices() (sage.graphs.bipartite_graph.BipartiteGraph method), 341
add_vertices() (sage.graphs.generic_graph.GenericGraph method), 11
adjacency_matrix() (sage.graphs.generic_graph.GenericGraph method), 12
AffineOrthogonalPolarGraph() (sage.graphs.graph_generators.GraphGenerators static method), 356
AfricaMap() (sage.graphs.graph_generators.GraphGenerators static method), 357
AhrensSzekeresGeneralizedQuadrangleGraph() (sage.graphs.graph_generators.GraphGenerators static method), 358
845
Sage Reference Manual: Graph Theory, Release 8.4
B
b_coloring() (in module sage.graphs.graph_coloring), 646
Balaban10Cage() (sage.graphs.graph_generators.GraphGenerators static method), 358
Balaban11Cage() (sage.graphs.graph_generators.GraphGenerators static method), 359
BalancedTree() (sage.graphs.graph_generators.GraphGenerators static method), 360
bandwidth() (in module sage.graphs.graph_decompositions.bandwidth), 745
bandwidth_heuristics() (in module sage.graphs.base.boost_graph), 615
BarbellGraph() (sage.graphs.graph_generators.GraphGenerators static method), 361
BidiakisCube() (sage.graphs.graph_generators.GraphGenerators static method), 362
bidirectional_dijkstra() (sage.graphs.base.c_graph.CGraphBackend method), 560
BiggsSmithGraph() (sage.graphs.graph_generators.GraphGenerators static method), 362
binary_string_from_dig6() (in module sage.graphs.generic_graph_pyx), 802
binary_string_from_graph6() (in module sage.graphs.generic_graph_pyx), 803
binary_string_to_graph6() (in module sage.graphs.generic_graph_pyx), 803
BinomialRandomUniform() (sage.graphs.hypergraph_generators.HypergraphGenerators method), 623
bipartite_color() (sage.graphs.graph.Graph method), 220
bipartite_sets() (sage.graphs.graph.Graph method), 221
BipartiteGraph (class in sage.graphs.bipartite_graph), 336
bipartition() (sage.graphs.bipartite_graph.BipartiteGraph method), 341
BishopGraph() (sage.graphs.graph_generators.GraphGenerators static method), 363
BlanusaFirstSnarkGraph() (sage.graphs.graph_generators.GraphGenerators static method), 363
BlanusaSecondSnarkGraph() (sage.graphs.graph_generators.GraphGenerators static method), 364
block_sizes() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 628
846 Index
Sage Reference Manual: Graph Theory, Release 8.4
C
c_graph() (sage.graphs.base.c_graph.CGraphBackend method), 561
CaiFurerImmermanGraph() (sage.graphs.graph_generators.GraphGenerators static method), 368
CameronGraph() (sage.graphs.graph_generators.GraphGenerators static method), 369
canaug_traverse_edge() (in module sage.graphs.graph_generators), 484
canaug_traverse_vert() (in module sage.graphs.graph_generators), 484
canonical_label() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 628
canonical_label() (sage.graphs.generic_graph.GenericGraph method), 26
cardinality() (sage.graphs.generic_graph_pyx.SubgraphSearch method), 802
cardinality() (sage.graphs.independent_sets.IndependentSets method), 660
cardinality() (sage.graphs.pq_trees.P method), 677
cardinality() (sage.graphs.pq_trees.Q method), 680
cartesian_product() (sage.graphs.generic_graph.GenericGraph method), 28
categorical_product() (sage.graphs.generic_graph.GenericGraph method), 28
Cell120() (sage.graphs.graph_generators.GraphGenerators static method), 370
Cell600() (sage.graphs.graph_generators.GraphGenerators static method), 370
center() (sage.graphs.generic_graph.GenericGraph method), 29
centrality_betweenness() (in module sage.graphs.centrality), 655
centrality_betweenness() (sage.graphs.generic_graph.GenericGraph method), 30
centrality_closeness() (sage.graphs.generic_graph.GenericGraph method), 31
centrality_closeness_random_k() (in module sage.graphs.centrality), 656
centrality_closeness_top_k() (in module sage.graphs.centrality), 656
centrality_degree() (sage.graphs.graph.Graph method), 222
CGraph (class in sage.graphs.base.c_graph), 546
CGraphBackend (class in sage.graphs.base.c_graph), 558
chang_graphs() (sage.graphs.graph_generators.GraphGenerators static method), 471
characteristic_polynomial() (sage.graphs.generic_graph.GenericGraph method), 33
charpoly() (sage.graphs.generic_graph.GenericGraph method), 33
check_aut() (in module sage.graphs.graph_generators), 485
Index 847
Sage Reference Manual: Graph Theory, Release 8.4
848 Index
Sage Reference Manual: Graph Theory, Release 8.4
D
data_to_degseq() (in module sage.graphs.graph_database), 510
DeBruijn() (sage.graphs.digraph_generators.DiGraphGenerators method), 490
degree() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 630
degree() (sage.graphs.base.c_graph.CGraphBackend method), 562
degree() (sage.graphs.base.graph_backends.GenericGraphBackend method), 610
degree() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 604
degree() (sage.graphs.generic_graph.GenericGraph method), 46
degree_constrained_subgraph() (sage.graphs.graph.Graph method), 240
degree_histogram() (sage.graphs.generic_graph.GenericGraph method), 46
degree_iterator() (sage.graphs.generic_graph.GenericGraph method), 46
degree_polynomial() (sage.graphs.digraph.DiGraph method), 311
degree_sequence() (sage.graphs.generic_graph.GenericGraph method), 47
degree_to_cell() (sage.graphs.generic_graph.GenericGraph method), 48
degrees() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 630
Index 849
Sage Reference Manual: Graph Theory, Release 8.4
850 Index
Sage Reference Manual: Graph Theory, Release 8.4
E
Ear (class in sage.graphs.tutte_polynomial), 795
ear_decomposition() (sage.graphs.graph.Graph method), 241
eccentricity (in module sage.graphs.distances_all_pairs), 765
eccentricity() (sage.graphs.generic_graph.GenericGraph method), 62
edge_boundary() (sage.graphs.generic_graph.GenericGraph method), 64
edge_coloring() (in module sage.graphs.graph_coloring), 647
edge_coloring() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 631
edge_connectivity (in module sage.graphs.connectivity), 820
edge_connectivity() (in module sage.graphs.base.boost_graph), 618
edge_connectivity() (sage.graphs.generic_graph.GenericGraph method), 64
edge_cut() (sage.graphs.generic_graph.GenericGraph method), 66
edge_disjoint_paths() (sage.graphs.generic_graph.GenericGraph method), 68
edge_disjoint_spanning_trees() (sage.graphs.generic_graph.GenericGraph method), 68
edge_iterator() (sage.graphs.generic_graph.GenericGraph method), 70
edge_label() (sage.graphs.generic_graph.GenericGraph method), 70
edge_labels() (sage.graphs.generic_graph.GenericGraph method), 71
edge_multiplicities() (in module sage.graphs.tutte_polynomial), 797
edges() (sage.graphs.generic_graph.GenericGraph method), 71
edges_incident() (sage.graphs.generic_graph.GenericGraph method), 72
EdgeSelection (class in sage.graphs.tutte_polynomial), 796
EgawaGraph() (sage.graphs.graph_generators.GraphGenerators static method), 386
eigenmatrix() (in module sage.graphs.strongly_regular_db), 519
eigenspaces() (sage.graphs.generic_graph.GenericGraph method), 73
eigenvectors() (sage.graphs.generic_graph.GenericGraph method), 74
EllinghamHorton54Graph() (sage.graphs.graph_generators.GraphGenerators static method), 386
EllinghamHorton78Graph() (sage.graphs.graph_generators.GraphGenerators static method), 387
EmptyGraph() (sage.graphs.graph_generators.GraphGenerators static method), 387
ErreraGraph() (sage.graphs.graph_generators.GraphGenerators static method), 388
eulerian_circuit() (sage.graphs.generic_graph.GenericGraph method), 76
eulerian_orientation() (sage.graphs.generic_graph.GenericGraph method), 77
EuropeMap() (sage.graphs.graph_generators.GraphGenerators static method), 389
export_to_file() (sage.graphs.generic_graph.GenericGraph method), 77
Index 851
Sage Reference Manual: Graph Theory, Release 8.4
F
F26AGraph() (sage.graphs.graph_generators.GraphGenerators static method), 389
faces() (sage.graphs.generic_graph.GenericGraph method), 78
feedback_edge_set() (sage.graphs.digraph.DiGraph method), 312
feedback_vertex_set() (sage.graphs.generic_graph.GenericGraph method), 79
FibonacciTree() (sage.graphs.graph_generators.GraphGenerators static method), 389
find_ear() (sage.graphs.tutte_polynomial.Ear static method), 795
find_hamiltonian() (in module sage.graphs.generic_graph_pyx), 803
first_coloring() (in module sage.graphs.graph_coloring), 649
flatten() (in module sage.graphs.pq_trees), 682
flatten() (sage.graphs.pq_trees.PQ method), 679
flow() (sage.graphs.generic_graph.GenericGraph method), 81
flow_polytope() (sage.graphs.digraph.DiGraph method), 313
FlowerSnark() (sage.graphs.graph_generators.GraphGenerators static method), 390
floyd_warshall (in module sage.graphs.distances_all_pairs), 765
FoldedCubeGraph() (sage.graphs.graph_generators.GraphGenerators static method), 390
FolkmanGraph() (sage.graphs.graph_generators.GraphGenerators static method), 390
forbidden_subgraphs() (sage.graphs.isgci.GraphClass method), 540
FosterGraph() (sage.graphs.graph_generators.GraphGenerators static method), 391
fractional_chromatic_index() (sage.graphs.graph.Graph method), 242
FranklinGraph() (sage.graphs.graph_generators.GraphGenerators static method), 391
FriendshipGraph() (sage.graphs.graph_generators.GraphGenerators static method), 392
from_adjacency_matrix() (in module sage.graphs.graph_input), 786
from_dict_of_dicts() (in module sage.graphs.graph_input), 786
from_dict_of_lists() (in module sage.graphs.graph_input), 787
from_dig6() (in module sage.graphs.graph_input), 787
from_graph6() (in module sage.graphs.graph_input), 787
from_graph6() (in module sage.graphs.graph_list), 783
from_incidence_matrix() (in module sage.graphs.graph_input), 788
from_oriented_incidence_matrix() (in module sage.graphs.graph_input), 788
from_seidel_adjacency_matrix() (in module sage.graphs.graph_input), 788
from_sparse6() (in module sage.graphs.graph_input), 789
from_sparse6() (in module sage.graphs.graph_list), 783
from_whatever() (in module sage.graphs.graph_list), 783
FruchtGraph() (sage.graphs.graph_generators.GraphGenerators static method), 393
fullerenes() (sage.graphs.graph_generators.GraphGenerators method), 473
FurerGadget() (sage.graphs.graph_generators.GraphGenerators static method), 394
fusenes() (sage.graphs.graph_generators.GraphGenerators method), 474
FuzzyBallGraph() (sage.graphs.graph_generators.GraphGenerators static method), 395
G
gen_html_code() (in module sage.graphs.graph_plot_js), 729
GeneralizedDeBruijn() (sage.graphs.digraph_generators.DiGraphGenerators method), 491
GeneralizedPetersenGraph() (sage.graphs.graph_generators.GraphGenerators static method), 395
generate_linear_extensions() (sage.graphs.linearextensions.LinearExtensions method), 691
GenericGraph (class in sage.graphs.generic_graph), 7
GenericGraph_pyx (class in sage.graphs.generic_graph_pyx), 801
GenericGraphBackend (class in sage.graphs.base.graph_backends), 609
GenericGraphQuery (class in sage.graphs.graph_database), 500
genus() (sage.graphs.generic_graph.GenericGraph method), 83
852 Index
Sage Reference Manual: Graph Theory, Release 8.4
H
HaemersGraph() (sage.graphs.graph_generators.GraphGenerators static method), 399
HallJankoGraph() (sage.graphs.graph_generators.GraphGenerators static method), 400
hamiltonian_cycle() (sage.graphs.generic_graph.GenericGraph method), 92
Index 853
Sage Reference Manual: Graph Theory, Release 8.4
I
IcosahedralGraph() (sage.graphs.graph_generators.GraphGenerators static method), 410
igraph_graph() (sage.graphs.generic_graph.GenericGraph method), 98
ihara_zeta_function_inverse() (sage.graphs.graph.Graph method), 246
ImaseItoh() (sage.graphs.digraph_generators.DiGraphGenerators method), 492
854 Index
Sage Reference Manual: Graph Theory, Release 8.4
Index 855
Sage Reference Manual: Graph Theory, Release 8.4
856 Index
Sage Reference Manual: Graph Theory, Release 8.4
Index 857
Sage Reference Manual: Graph Theory, Release 8.4
J
JankoKharaghaniGraph() (sage.graphs.graph_generators.GraphGenerators static method), 413
JankoKharaghaniTonchevGraph() (sage.graphs.graph_generators.GraphGenerators static method), 414
johnson_closeness_centrality() (in module sage.graphs.base.boost_graph), 619
johnson_shortest_paths() (in module sage.graphs.base.boost_graph), 619
JohnsonGraph() (sage.graphs.graph_generators.GraphGenerators static method), 414
join() (sage.graphs.graph.Graph method), 270
K
Kautz() (sage.graphs.digraph_generators.DiGraphGenerators method), 492
KingGraph() (sage.graphs.graph_generators.GraphGenerators static method), 414
kirchhoff_matrix() (sage.graphs.generic_graph.GenericGraph method), 120
kirchhoff_symanzik_polynomial() (sage.graphs.graph.Graph method), 271
KittellGraph() (sage.graphs.graph_generators.GraphGenerators static method), 415
Klein3RegularGraph() (sage.graphs.graph_generators.GraphGenerators static method), 415
Klein7RegularGraph() (sage.graphs.graph_generators.GraphGenerators static method), 416
KneserGraph() (sage.graphs.graph_generators.GraphGenerators static method), 416
KnightGraph() (sage.graphs.graph_generators.GraphGenerators static method), 416
KrackhardtKiteGraph() (sage.graphs.graph_generators.GraphGenerators static method), 417
kronecker_product() (sage.graphs.generic_graph.GenericGraph method), 122
kruskal() (in module sage.graphs.spanning_tree), 673
858 Index
Sage Reference Manual: Graph Theory, Release 8.4
L
LadderGraph() (sage.graphs.graph_generators.GraphGenerators static method), 418
laplacian_matrix() (sage.graphs.generic_graph.GenericGraph method), 122
latex() (sage.graphs.graph_latex.GraphLatex method), 775
latex_options() (sage.graphs.generic_graph.GenericGraph method), 124
latin_squares_graph_parameters() (in module sage.graphs.strongly_regular_db), 531
layout() (sage.graphs.generic_graph.GenericGraph method), 124
layout_acyclic() (sage.graphs.digraph.DiGraph method), 321
layout_acyclic_dummy() (sage.graphs.digraph.DiGraph method), 322
layout_circular() (sage.graphs.generic_graph.GenericGraph method), 126
layout_default() (sage.graphs.generic_graph.GenericGraph method), 126
layout_extend_randomly() (sage.graphs.generic_graph.GenericGraph method), 126
layout_graphviz() (sage.graphs.generic_graph.GenericGraph method), 127
layout_planar() (sage.graphs.generic_graph.GenericGraph method), 128
layout_ranked() (sage.graphs.generic_graph.GenericGraph method), 128
layout_spring() (sage.graphs.generic_graph.GenericGraph method), 129
layout_tree() (sage.graphs.generic_graph.GenericGraph method), 129
layout_tree() (sage.graphs.graph_plot.GraphPlot method), 702
LCFGraph() (sage.graphs.graph_generators.GraphGenerators static method), 417
length_and_string_from_graph6() (in module sage.graphs.generic_graph_pyx), 805
level_sets() (sage.graphs.digraph.DiGraph method), 322
lex_BFS() (sage.graphs.generic_graph.GenericGraph method), 130
lexicographic_product() (sage.graphs.generic_graph.GenericGraph method), 131
line_graph() (in module sage.graphs.line_graph), 669
line_graph() (sage.graphs.generic_graph.GenericGraph method), 131
line_graph_forbidden_subgraphs() (sage.graphs.graph_generators.GraphGenerators static method), 475
linear_arboricity() (in module sage.graphs.graph_coloring), 650
linear_ordering_to_path_decomposition (in module sage.graphs.graph_decompositions.vertex_separation), 733
LinearExtensions (class in sage.graphs.linearextensions), 690
list() (sage.graphs.linearextensions.LinearExtensions method), 691
LivingstoneGraph() (sage.graphs.graph_generators.GraphGenerators static method), 419
LjubljanaGraph() (sage.graphs.graph_generators.GraphGenerators static method), 419
load_afile() (sage.graphs.bipartite_graph.BipartiteGraph method), 343
LocalMcLaughlinGraph() (sage.graphs.graph_generators.GraphGenerators static method), 420
LollipopGraph() (sage.graphs.graph_generators.GraphGenerators static method), 420
longest_path() (sage.graphs.generic_graph.GenericGraph method), 133
loop_edges() (sage.graphs.generic_graph.GenericGraph method), 134
loop_vertices() (sage.graphs.generic_graph.GenericGraph method), 136
loops() (sage.graphs.base.c_graph.CGraphBackend method), 568
loops() (sage.graphs.base.graph_backends.GenericGraphBackend method), 612
loops() (sage.graphs.generic_graph.GenericGraph method), 136
lovasz_theta() (in module sage.graphs.lovasz_theta), 689
lovasz_theta() (sage.graphs.graph.Graph method), 272
lower_bound (in module sage.graphs.graph_decompositions.vertex_separation), 734
M
M22Graph() (sage.graphs.graph_generators.GraphGenerators static method), 420
magnitude_function() (sage.graphs.graph.Graph method), 273
MarkstroemGraph() (sage.graphs.graph_generators.GraphGenerators static method), 420
matching() (sage.graphs.bipartite_graph.BipartiteGraph method), 344
Index 859
Sage Reference Manual: Graph Theory, Release 8.4
N
name() (sage.graphs.base.graph_backends.GenericGraphBackend method), 613
name() (sage.graphs.generic_graph.GenericGraph method), 143
NauruGraph() (sage.graphs.graph_generators.GraphGenerators static method), 427
nauty() (sage.graphs.hypergraph_generators.HypergraphGenerators method), 624
nauty_geng() (sage.graphs.graph_generators.GraphGenerators method), 475
neighbor_in_iterator() (sage.graphs.digraph.DiGraph method), 323
neighbor_iterator() (sage.graphs.generic_graph.GenericGraph method), 144
neighbor_out_iterator() (sage.graphs.digraph.DiGraph method), 323
neighbors() (sage.graphs.generic_graph.GenericGraph method), 144
860 Index
Sage Reference Manual: Graph Theory, Release 8.4
O
OctahedralGraph() (sage.graphs.graph_generators.GraphGenerators static method), 430
odd_girth() (sage.graphs.graph.Graph method), 281
OddGraph() (sage.graphs.graph_generators.GraphGenerators static method), 431
order() (sage.graphs.generic_graph.GenericGraph method), 147
ordering() (sage.graphs.pq_trees.PQ method), 679
orderings() (sage.graphs.pq_trees.P method), 678
orderings() (sage.graphs.pq_trees.Q method), 681
orientations() (sage.graphs.graph.Graph method), 282
OrthogonalArrayBlockGraph() (sage.graphs.graph_generators.GraphGenerators static method), 431
OrthogonalPolarGraph() (sage.graphs.graph_generators.GraphGenerators static method), 433
out_degree() (sage.graphs.base.c_graph.CGraphBackend method), 569
out_degree() (sage.graphs.base.graph_backends.GenericGraphBackend method), 613
out_degree() (sage.graphs.base.sparse_graph.SparseGraph method), 579
out_degree() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 607
out_degree() (sage.graphs.base.static_sparse_backend.StaticSparseCGraph method), 608
out_degree() (sage.graphs.digraph.DiGraph method), 324
Index 861
Sage Reference Manual: Graph Theory, Release 8.4
P
P (class in sage.graphs.pq_trees), 677
packing() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 640
Paley() (sage.graphs.digraph_generators.DiGraphGenerators method), 493
PaleyGraph() (sage.graphs.graph_generators.GraphGenerators static method), 433
PappusGraph() (sage.graphs.graph_generators.GraphGenerators static method), 434
PasechnikGraph() (sage.graphs.graph_generators.GraphGenerators static method), 434
Path() (sage.graphs.digraph_generators.DiGraphGenerators method), 494
path_decomposition (in module sage.graphs.graph_decompositions.vertex_separation), 735
path_semigroup() (sage.graphs.digraph.DiGraph method), 325
PathGraph() (sage.graphs.graph_generators.GraphGenerators static method), 434
pathwidth (in module sage.graphs.graph_decompositions.vertex_separation), 736
pathwidth() (sage.graphs.graph.Graph method), 283
perfect_matchings() (sage.graphs.graph.Graph method), 284
period() (sage.graphs.digraph.DiGraph method), 326
periphery() (sage.graphs.generic_graph.GenericGraph method), 147
PerkelGraph() (sage.graphs.graph_generators.GraphGenerators static method), 435
PermutationGraph() (sage.graphs.graph_generators.GraphGenerators static method), 435
petersen_family() (sage.graphs.graph_generators.GraphGenerators static method), 477
PetersenGraph() (sage.graphs.graph_generators.GraphGenerators static method), 437
planar_dual() (sage.graphs.generic_graph.GenericGraph method), 148
planar_graphs() (sage.graphs.graph_generators.GraphGenerators method), 477
plot() (sage.graphs.bipartite_graph.BipartiteGraph method), 345
plot() (sage.graphs.generic_graph.GenericGraph method), 149
plot() (sage.graphs.graph_plot.GraphPlot method), 702
plot3d() (sage.graphs.generic_graph.GenericGraph method), 153
PoussinGraph() (sage.graphs.graph_generators.GraphGenerators static method), 437
PQ (class in sage.graphs.pq_trees), 679
print_triconnected_components() (sage.graphs.connectivity.TriconnectivitySPQR method), 814
project_left() (sage.graphs.bipartite_graph.BipartiteGraph method), 345
project_right() (sage.graphs.bipartite_graph.BipartiteGraph method), 346
Q
Q (class in sage.graphs.pq_trees), 680
quadrangulations() (sage.graphs.graph_generators.GraphGenerators method), 479
QueenGraph() (sage.graphs.graph_generators.GraphGenerators static method), 437
query() (sage.graphs.graph_database.GraphDatabase method), 504
query_iterator() (sage.graphs.graph_database.GraphQuery method), 508
R
radius() (sage.graphs.generic_graph.GenericGraph method), 155
862 Index
Sage Reference Manual: Graph Theory, Release 8.4
Index 863
Sage Reference Manual: Graph Theory, Release 8.4
S
s (sage.graphs.tutte_polynomial.Ear attribute), 795
sage.combinat.designs.incidence_structures (module), 625
sage.graphs.asteroidal_triples (module), 657
sage.graphs.base.boost_graph (module), 615
sage.graphs.base.c_graph (module), 546
sage.graphs.base.dense_graph (module), 584
sage.graphs.base.graph_backends (module), 608
sage.graphs.base.overview (module), 545
sage.graphs.base.sparse_graph (module), 572
sage.graphs.base.static_dense_graph (module), 593
sage.graphs.base.static_sparse_backend (module), 602
sage.graphs.base.static_sparse_graph (module), 596
sage.graphs.bipartite_graph (module), 336
sage.graphs.centrality (module), 655
sage.graphs.cliquer (module), 653
sage.graphs.comparability (module), 660
sage.graphs.connectivity (module), 809
sage.graphs.convexity_properties (module), 755
sage.graphs.digraph (module), 299
sage.graphs.digraph_generators (module), 486
sage.graphs.distances_all_pairs (module), 760
sage.graphs.generic_graph (module), 1
sage.graphs.generic_graph_pyx (module), 801
sage.graphs.genus (module), 686
sage.graphs.graph (module), 204
sage.graphs.graph_coloring (module), 643
sage.graphs.graph_database (module), 499
sage.graphs.graph_decompositions.bandwidth (module), 744
sage.graphs.graph_decompositions.cutwidth (module), 746
sage.graphs.graph_decompositions.graph_products (module), 751
sage.graphs.graph_decompositions.rankwidth (module), 742
sage.graphs.graph_decompositions.vertex_separation (module), 730
864 Index
Sage Reference Manual: Graph Theory, Release 8.4
Index 865
Sage Reference Manual: Graph Theory, Release 8.4
866 Index
Sage Reference Manual: Graph Theory, Release 8.4
Index 867
Sage Reference Manual: Graph Theory, Release 8.4
T
T2starGeneralizedQuadrangleGraph() (sage.graphs.graph_generators.GraphGenerators static method), 458
tachyon_vertex_plot() (in module sage.graphs.generic_graph), 203
TadpoleGraph() (sage.graphs.graph_generators.GraphGenerators static method), 459
tarjan_strongly_connected_components (in module sage.graphs.base.static_sparse_graph), 601
TaylorTwographDescendantSRG() (sage.graphs.graph_generators.GraphGenerators static method), 459
TaylorTwographSRG() (sage.graphs.graph_generators.GraphGenerators static method), 460
tensor_product() (sage.graphs.generic_graph.GenericGraph method), 188
Test (class in sage.graphs.graph_coloring), 643
TetrahedralGraph() (sage.graphs.graph_generators.GraphGenerators static method), 460
ThomsenGraph() (sage.graphs.graph_generators.GraphGenerators static method), 461
TietzeGraph() (sage.graphs.graph_generators.GraphGenerators static method), 461
tkz_picture() (sage.graphs.graph_latex.GraphLatex method), 780
to_dictionary() (sage.graphs.generic_graph.GenericGraph method), 189
to_directed() (sage.graphs.digraph.DiGraph method), 334
to_directed() (sage.graphs.graph.Graph method), 292
to_graph6() (in module sage.graphs.graph_list), 784
to_graphics_array() (in module sage.graphs.graph_list), 785
to_simple() (sage.graphs.generic_graph.GenericGraph method), 190
to_sparse6() (in module sage.graphs.graph_list), 785
to_undirected() (sage.graphs.bipartite_graph.BipartiteGraph method), 347
to_undirected() (sage.graphs.digraph.DiGraph method), 334
to_undirected() (sage.graphs.graph.Graph method), 292
ToleranceGraph() (sage.graphs.graph_generators.GraphGenerators static method), 461
topological_minor() (sage.graphs.graph.Graph method), 293
topological_sort() (sage.graphs.digraph.DiGraph method), 334
topological_sort_generator() (sage.graphs.digraph.DiGraph method), 335
Toroidal6RegularGrid2dGraph() (sage.graphs.graph_generators.GraphGenerators static method), 462
ToroidalGrid2dGraph() (sage.graphs.graph_generators.GraphGenerators static method), 463
tournaments_nauty() (sage.graphs.digraph_generators.DiGraphGenerators method), 498
trace() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 641
transitive_closure() (sage.graphs.generic_graph.GenericGraph method), 190
transitive_reduction() (sage.graphs.generic_graph.GenericGraph method), 191
transitive_reduction_acyclic() (in module sage.graphs.generic_graph_pyx), 807
TransitiveTournament() (sage.graphs.digraph_generators.DiGraphGenerators method), 498
traveling_salesman_problem() (sage.graphs.generic_graph.GenericGraph method), 191
TreeIterator (class in sage.graphs.trees), 682
TreeNode (class in sage.graphs.schnyder), 693
trees() (sage.graphs.graph_generators.GraphGenerators static method), 481
treewidth() (sage.graphs.graph.Graph method), 294
triangles_count (in module sage.graphs.base.static_dense_graph), 596
triangles_count (in module sage.graphs.base.static_sparse_graph), 602
triangles_count() (sage.graphs.generic_graph.GenericGraph method), 193
triangulations() (sage.graphs.graph_generators.GraphGenerators method), 482
868 Index
Sage Reference Manual: Graph Theory, Release 8.4
U
U42Graph216() (sage.graphs.graph_generators.GraphGenerators static method), 465
U42Graph540() (sage.graphs.graph_generators.GraphGenerators static method), 465
underlying_graph() (in module sage.graphs.tutte_polynomial), 799
UniformRandomUniform() (sage.graphs.hypergraph_generators.HypergraphGenerators method), 623
union() (sage.graphs.generic_graph.GenericGraph method), 194
UnitaryDualPolarGraph() (sage.graphs.graph_generators.GraphGenerators static method), 466
UnitaryPolarGraph() (sage.graphs.graph_generators.GraphGenerators static method), 467
unlabeled_edges() (sage.graphs.tutte_polynomial.Ear method), 796
unpickle_graph_backend() (in module sage.graphs.base.graph_backends), 614
update_db() (sage.graphs.isgci.GraphClasses method), 542
USAMap() (sage.graphs.graph_generators.GraphGenerators static method), 466
V
vertex_boundary() (sage.graphs.generic_graph.GenericGraph method), 195
vertex_coloring() (in module sage.graphs.graph_coloring), 652
vertex_connectivity (in module sage.graphs.connectivity), 830
vertex_connectivity() (sage.graphs.generic_graph.GenericGraph method), 195
vertex_cover() (sage.graphs.bipartite_graph.BipartiteGraph method), 347
vertex_cover() (sage.graphs.graph.Graph method), 296
vertex_cut() (sage.graphs.generic_graph.GenericGraph method), 197
vertex_disjoint_paths() (sage.graphs.generic_graph.GenericGraph method), 198
vertex_iterator() (sage.graphs.generic_graph.GenericGraph method), 198
vertex_separation (in module sage.graphs.graph_decompositions.vertex_separation), 737
vertex_separation_BAB (in module sage.graphs.graph_decompositions.vertex_separation), 738
vertex_separation_exp (in module sage.graphs.graph_decompositions.vertex_separation), 741
vertex_separation_MILP (in module sage.graphs.graph_decompositions.vertex_separation), 740
VertexOrder (class in sage.graphs.tutte_polynomial), 796
vertices (sage.graphs.tutte_polynomial.Ear attribute), 796
vertices() (sage.graphs.generic_graph.GenericGraph method), 199
verts() (sage.graphs.base.c_graph.CGraph method), 557
verts() (sage.graphs.base.static_sparse_backend.StaticSparseCGraph method), 608
W
WagnerGraph() (sage.graphs.graph_generators.GraphGenerators static method), 467
WatkinsSnarkGraph() (sage.graphs.graph_generators.GraphGenerators static method), 467
weighted() (sage.graphs.generic_graph.GenericGraph method), 200
weighted_adjacency_matrix() (sage.graphs.generic_graph.GenericGraph method), 201
Index 869
Sage Reference Manual: Graph Theory, Release 8.4
870 Index