[go: up one dir, main page]

100% found this document useful (1 vote)
705 views874 pages

Graphs in Sage Math

This chapter summarizes the key graph objects and methods available in the Sage graph theory module. It describes methods for creating and manipulating graphs, querying their properties, performing graph operations like products and complements, finding paths and cycles, applying linear algebra techniques, and calculating graph metrics. The chapter provides an overview of the basic functionality for working with graphs in Sage.

Uploaded by

elham
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (1 vote)
705 views874 pages

Graphs in Sage Math

This chapter summarizes the key graph objects and methods available in the Sage graph theory module. It describes methods for creating and manipulating graphs, querying their properties, performing graph operations like products and complements, finding paths and cycles, applying linear algebra techniques, and calculating graph metrics. The chapter provides an overview of the basic functionality for working with graphs in Sage.

Uploaded by

elham
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 874

Sage Reference Manual: Graph Theory

Release 8.4

The Sage Development Team

Oct 18, 2018


CONTENTS

1 Graph objects and methods 1

2 Constructors and databases 349

3 Low-level implementation 545

4 Hypergraphs 623

5 Libraries of algorithms 643

6 Indices and Tables 833

Bibliography 835

Python Module Index 843

Index 845

i
ii
CHAPTER

ONE

GRAPH OBJECTS AND METHODS

1.1 Generic graphs (common to directed/undirected)

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:

networkx_graph() Create a new NetworkX graph from the Sage graph


igraph_graph() Create a new igraph graph from the Sage graph
to_dictionary() Create a dictionary encoding the graph.
copy() Return a copy of the graph.
export_to_file() Export the graph to a file.
adjacency_matrix() Return the adjacency matrix of the (di)graph.
incidence_matrix() Return an incidence matrix of the (di)graph
distance_matrix() Return the distance matrix of the (strongly) connected (di)graph
Return the weighted adjacency matrix of the graph
weighted_adjacency_matrix()
kirchhoff_matrix() Return the Kirchhoff matrix (a.k.a. the Laplacian) of the graph.
has_loops() Return whether there are loops in the (di)graph
allows_loops() Return whether loops are permitted in the (di)graph
allow_loops() Change whether loops are permitted in the (di)graph
loops() Return a list of all loops in the (di)graph
loop_edges() Return a list of all loops in the (di)graph
number_of_loops() Return the number of edges that are loops
loop_vertices() Return a list of vertices with loops
remove_loops() Remove loops on vertices in vertices. If vertices is None, removes all loops.
has_multiple_edges() Return whether there are multiple edges in the (di)graph.
allows_multiple_edges() Return whether multiple edges are permitted in the (di)graph.
allow_multiple_edges() Change whether multiple edges are permitted in the (di)graph.
multiple_edges() Return any multiple edges in the (di)graph.
name() Return or sets the graph’s name.
is_immutable() Return whether the graph is immutable.
weighted() Whether the (di)graph is to be considered as a weighted (di)graph.
antisymmetric() Test whether the graph is antisymmetric
density() Return the density
order() Return the number of vertices.
size() Return the number of edges.
add_vertex() Create an isolated vertex.
add_vertices() Add vertices to the (di)graph from an iterable container
Continued on next page

1
Sage Reference Manual: Graph Theory, Release 8.4

Table 1 – continued from previous page


delete_vertex() Delete a vertex, removing all incident edges.
delete_vertices() Remove vertices from the (di)graph taken from an iterable container of vertices.
has_vertex() Return True if vertex is one of the vertices of this graph.
random_vertex() Return a random vertex of self.
random_vertex_iterator()Return an iterator over random vertices of self.
random_edge() Return a random edge of self.
random_edge_iterator() Return an iterator over random edges of self.
vertex_boundary() Return a list of all vertices in the external boundary of vertices1, intersected
with vertices2.
set_vertices() Associate arbitrary objects with each vertex
set_vertex() Associate an arbitrary object with a vertex.
get_vertex() Retrieve the object associated with a given vertex.
get_vertices() Return a dictionary of the objects associated to each vertex.
vertex_iterator() Return an iterator over the vertices.
neighbor_iterator() Return an iterator over neighbors of vertex.
vertices() Return a list of the vertices.
neighbors() Return a list of neighbors (in and out if directed) of vertex.
merge_vertices() Merge vertices.
add_edge() Add an edge from u and v.
add_edges() Add edges from an iterable container.
subdivide_edge() Subdivide an edge 𝑘 times.
subdivide_edges() Subdivide k times edges from an iterable container.
delete_edge() Delete the edge from u to v
delete_edges() Delete edges from an iterable container.
contract_edge() Contract an edge from 𝑢 to 𝑣.
contract_edges() Contract edges from an iterable container.
delete_multiedge() Delete all edges from u and v.
set_edge_label() Set the edge label of a given edge.
has_edge() Return True if (u, v) is an edge, False otherwise.
edges() Return a list of edges.
edge_boundary() Return a list of edges (𝑢, 𝑣, 𝑙) with 𝑢 in vertices1
edge_iterator() Return an iterator over edges.
edges_incident() Return incident edges to some vertices.
edge_label() Return the label of an edge.
edge_labels() Return a list of edge labels.
remove_multiple_edges() Remove all multiple edges, retaining one edge for each.
clear() Empty the graph of vertices and edges and removes name, associated objects,
and position information.
degree() Return the degree (in + out for digraphs) of a vertex or of vertices.
average_degree() Return the average degree of the graph.
degree_histogram() Return a list, whose ith entry is the frequency of degree i.
degree_iterator() Return an iterator over the degrees of the (di)graph.
degree_sequence() Return the degree sequence of this (di)graph.
random_subgraph() Return a random subgraph that contains each vertex with prob. p.
add_clique() Add a clique to the graph with the given vertices.
add_cycle() Add a cycle to the graph with the given vertices.
add_path() Add a cycle to the graph with the given vertices.
complement() Return the complement of the (di)graph.
line_graph() Return the line graph of the (di)graph.
Continued on next page

2 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

Table 1 – continued from previous page


to_simple() Return a simple version of itself (i.e., undirected and loops and multiple edges
are removed).
disjoint_union() Return the disjoint union of self and other.
union() Return the union of self and other.
relabel() Relabel the vertices of self
degree_to_cell() Return the number of edges from vertex to an edge in cell.
subgraph() Return the subgraph containing the given vertices and edges.
is_subgraph() Test whether self is a subgraph of other.

Graph products:

cartesian_product() Return the Cartesian product of self and other.


tensor_product() Return the tensor product, also called the categorical product, of self and other.
lexicographic_product() Return the lexicographic product of self and other.
strong_product() Return the strong product of self and other.
disjunctive_product() Return the disjunctive product of self and other.

Paths and cycles:

eulerian_orientation() Return a DiGraph which is an Eulerian orientation of the current graph.


eulerian_circuit() Return a list of edges forming an Eulerian circuit if one exists.
cycle_basis() Return a list of cycles which form a basis of the cycle space of self.
all_paths() Return a list of all paths (also lists) between a pair of vertices in the (di)graph.
triangles_count() Return the number of triangles in the (di)graph.

Linear algebra:

spectrum() Return a list of the eigenvalues of the adjacency matrix.


eigenvectors() Return the right eigenvectors of the adjacency matrix of the graph.
eigenspaces() Return the right eigenspaces of the adjacency matrix of the graph.

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:

1.1. Generic graphs (common to directed/undirected) 3


Sage Reference Manual: Graph Theory, Release 8.4

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:

breadth_first_search() Return an iterator over the vertices in a breadth-first ordering.


depth_first_search() Return an iterator over the vertices in a depth-first ordering.
lex_BFS() Perform a Lex BFS on the graph.

Distances:

4 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

centrality_betweenness()Return the betweenness centrality


centrality_closeness() Returns the closeness centrality (1/average distance to all vertices)
distance() Return the (directed) distance from u to v in the (di)graph
distance_all_pairs() Return the distances between all pairs of vertices.
distances_distribution()Return the distances distribution of the (di)graph in a dictionary.
eccentricity() Return the eccentricity of vertex (or vertices) v.
radius() Return the radius of the (di)graph.
center() Return the set of vertices in the center of the graph
diameter() Return the largest distance between any two vertices.
distance_graph() Return the graph on the same vertex set as the original graph but vertices are
adjacent in the returned graph if and only if they are at specified distances in the
original graph.
girth() Compute the girth of the graph.
periphery() Return the set of vertices in the periphery
shortest_path() Return a list of vertices representing some shortest path from 𝑢 to 𝑣
shortest_path_length() Return the minimal length of paths from u to v
shortest_paths() Return a dictionary associating to each vertex v a shortest path from u to v, if it
exists.
shortest_path_lengths() Return a dictionary of shortest path lengths keyed by targets that are connected
by a path from u.
Compute a shortest path between each pair of vertices.
shortest_path_all_pairs()
wiener_index() Return the Wiener index of the graph.
average_distance() Return the average distance between vertices of the graph.

Flows, connectivity, trees:

is_connected() Test whether the (di)graph is connected.


connected_components() Return the list of connected components
Return the number of connected components.
connected_components_number()
Return a list of connected components as graph objects.
connected_components_subgraphs()
Return a list of the vertices connected to vertex.
connected_component_containing_vertex()
Return the sizes of the connected components as a list.
connected_components_sizes()
Compute the blocks and cut vertices of the graph.
blocks_and_cut_vertices()
blocks_and_cuts_tree() Compute the blocks-and-cuts tree of the graph.
is_cut_edge() Return True if the input edge is a cut-edge or a bridge.
is_cut_vertex() Return True if the input vertex is a cut-vertex.
edge_cut() Return a minimum edge cut between vertices 𝑠 and 𝑡
vertex_cut() Return a minimum vertex cut between non-adjacent vertices 𝑠 and 𝑡
flow() Return a maximum flow in the graph from x to y
nowhere_zero_flow() Return a 𝑘-nowhere zero flow of the (di)graph.
edge_disjoint_paths() Return a list of edge-disjoint paths between two vertices
vertex_disjoint_paths() Return a list of vertex-disjoint paths between two vertices
edge_connectivity() Return the edge connectivity of the graph.
vertex_connectivity() Return the vertex connectivity of the graph.
transitive_closure() Compute the transitive closure of a graph and returns it.
transitive_reduction() Return a transitive reduction of a graph.
min_spanning_tree() Return the edges of a minimum spanning tree.
spanning_trees_count() Return the number of spanning trees in a graph.
dominator_tree() Returns a dominator tree of the graph.
Iterator over the induced connected subgraphs of order at most 𝑘
connected_subgraph_iterator()

1.1. Generic graphs (common to directed/undirected) 5


Sage Reference Manual: Graph Theory, Release 8.4

Plot/embedding-related methods:

set_embedding() Set a combinatorial embedding dictionary to _embedding attribute.


get_embedding() Return the attribute _embedding if it exists.
faces() Return the faces of an embedded graph.
planar_dual() Return the planar dual of an embedded graph.
get_pos() Return the position dictionary
set_pos() Set the position dictionary.
set_planar_positions() Compute a planar layout for self using Schnyder’s algorithm
layout_planar() Use Schnyder’s algorithm to compute a planar layout for self.
Test whether the position dictionary gives a planar embedding.
is_drawn_free_of_edge_crossings()
latex_options() Return an instance of GraphLatex for the graph.
set_latex_options() Set multiple options for rendering a graph with LaTeX.
layout() Return a layout for the vertices of this graph.
layout_spring() Compute a spring layout for this graph
layout_ranked() Compute a ranked layout for this graph
layout_extend_randomly()Extend randomly a partial layout
layout_circular() Compute a circular layout for this graph
layout_tree() Compute an ordered tree layout for this graph, which should be a tree (no non-
oriented cycles).
layout_graphviz() Call graphviz to compute a layout of the vertices of this graph.
_circle_embedding() Sets some vertices on a circle in the embedding of this graph.
_line_embedding() Sets some vertices on a line in the embedding of this graph.
graphplot() Return a GraphPlot object.
plot() Return a graphics object representing the (di)graph.
show() Show the (di)graph.
plot3d() Plot the graph in three dimensions.
show3d() Plot the graph using Tachyon, and shows the resulting plot.
graphviz_string() Return a representation in the dot language.
graphviz_to_file_named()Write a representation in the dot in a file.

Algorithmically hard stuff:

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.

6 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: foo = Graph(sparse=True)


sage: foo.add_edges([(0, 1, 1), (0, 2, 2)])
sage: bar = Graph(sparse=True)
(continues on next page)

1.1. Generic graphs (common to directed/undirected) 7


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: bar.add_edges([(0, 1, 2), (0, 2, 1)])
sage: foo == bar
True
sage: foo.weighted(True)
sage: foo == bar
False
sage: bar.weighted(True)
sage: foo == bar
False

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)]

This is equivalent to:

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.

8 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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)]

add_edge(u, v=None, label=None)


Adds an edge from u and v.
INPUT: The following forms are all accepted:
• G.add_edge( 1, 2 )
• G.add_edge( (1, 2) )
• G.add_edges( [ (1, 2) ])
• G.add_edge( 1, 2, ‘label’ )
• G.add_edge( (1, 2, ‘label’) )
• G.add_edges( [ (1, 2, ‘label’) ] )
WARNING: The following intuitive input results in nonintuitive output:

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}}

Use one of these instead:

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:

1.1. Generic graphs (common to directed/undirected) 9


Sage Reference Manual: Graph Theory, Release 8.4

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)]

Vertex name cannot be None, so:

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')]

We demonstrate the loops argument:

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)

10 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


[(0, 0, None)]
sage: H.add_edges([(0,0)]); H.edges()
[(0, 0, None)]

add_path(vertices)
Add a path to the graph with the given vertices.
If the vertices are already present, only the edges are added.
For digraphs, adds the directed path vertices[0], . . . , vertices[-1].
INPUT:
• vertices - 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:

sage: G = Graph(); G.add_vertex(); G


0
Graph on 1 vertex

sage: D = DiGraph(); D.add_vertex(); D


0
Digraph on 1 vertex

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.

1.1. Generic graphs (common to directed/undirected) 11


Sage Reference Manual: Graph Theory, Release 8.4

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: 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)
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]

12 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

sage: matrix(GF(2),G) # matrix over GF(2)


[0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0]
[1 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0]
[1 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0]
[0 1 1 0 0 0 0 1 0 0 0 1 0 0 0 0]
[1 0 0 0 0 1 1 0 0 0 0 0 1 0 0 0]
[0 1 0 0 1 0 0 1 0 0 0 0 0 1 0 0]
[0 0 1 0 1 0 0 1 0 0 0 0 0 0 1 0]
[0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 1]
[1 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0]
[0 1 0 0 0 0 0 0 1 0 0 1 0 1 0 0]
[0 0 1 0 0 0 0 0 1 0 0 1 0 0 1 0]
[0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 1]
[0 0 0 0 1 0 0 0 1 0 0 0 0 1 1 0]
[0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 1]
[0 0 0 0 0 0 1 0 0 0 1 0 1 0 0 1]
[0 0 0 0 0 0 0 1 0 0 0 1 0 1 1 0]

sage: D = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] }


˓→)

sage: D.adjacency_matrix()
[0 1 1 1 0 0]
[1 0 1 0 0 0]
[0 0 0 1 0 0]
[0 0 0 0 1 0]
[1 0 0 0 0 1]
[0 1 0 0 0 0]

A different ordering of the vertices:

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:

sage: eg1 = Graph({0:[1,2], 1:[4], 2:[3,4], 4:[5], 5:[6]})


sage: eg1.all_paths(0,6)
[[0, 1, 4, 5, 6], [0, 2, 4, 5, 6]]
sage: eg2 = graphs.PetersenGraph()
sage: sorted(eg2.all_paths(1,4))
[[1, 0, 4],
[1, 0, 5, 7, 2, 3, 4],
(continues on next page)

1.1. Generic graphs (common to directed/undirected) 13


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


[1, 0, 5, 7, 2, 3, 8, 6, 9, 4],
[1, 0, 5, 7, 9, 4],
[1, 0, 5, 7, 9, 6, 8, 3, 4],
[1, 0, 5, 8, 3, 2, 7, 9, 4],
[1, 0, 5, 8, 3, 4],
[1, 0, 5, 8, 6, 9, 4],
[1, 0, 5, 8, 6, 9, 7, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 8, 5, 0, 4],
[1, 2, 3, 8, 5, 7, 9, 4],
[1, 2, 3, 8, 6, 9, 4],
[1, 2, 3, 8, 6, 9, 7, 5, 0, 4],
[1, 2, 7, 5, 0, 4],
[1, 2, 7, 5, 8, 3, 4],
[1, 2, 7, 5, 8, 6, 9, 4],
[1, 2, 7, 9, 4],
[1, 2, 7, 9, 6, 8, 3, 4],
[1, 2, 7, 9, 6, 8, 5, 0, 4],
[1, 6, 8, 3, 2, 7, 5, 0, 4],
[1, 6, 8, 3, 2, 7, 9, 4],
[1, 6, 8, 3, 4],
[1, 6, 8, 5, 0, 4],
[1, 6, 8, 5, 7, 2, 3, 4],
[1, 6, 8, 5, 7, 9, 4],
[1, 6, 9, 4],
[1, 6, 9, 7, 2, 3, 4],
[1, 6, 9, 7, 2, 3, 8, 5, 0, 4],
[1, 6, 9, 7, 5, 0, 4],
[1, 6, 9, 7, 5, 8, 3, 4]]
sage: dg = DiGraph({0:[1,3], 1:[3], 2:[0,3]})
sage: sorted(dg.all_paths(0,3))
[[0, 1, 3], [0, 3]]
sage: ug = dg.to_undirected()
sage: sorted(ug.all_paths(0,3))
[[0, 1, 3], [0, 2, 3], [0, 3]]

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)

14 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: G.has_loops()
False
sage: G.edges()
[]

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()
[]

allow_multiple_edges(new, check=True, keep_label=’any’)


Changes whether multiple edges are permitted in the (di)graph.
INPUT:
• new (boolean): if True, the new graph will allow multiple edges.
• check (boolean): if True and new is False, we remove all multiple edges from the graph.
• keep_label ('any','min','max'): used only if new is False and check is True. If there
are multiple edges with different labels, this variable defines which label should be kept: any label
('any'), the smallest label ('min'), or the largest ('max').
EXAMPLES:
The standard behavior with undirected graphs:

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)]

If we ask for the minimum label:

1.1. Generic graphs (common to directed/undirected) 15


Sage Reference Manual: Graph Theory, Release 8.4

sage: G = Graph([(0, 1, 1), (0, 1, 2), (0, 1, 3)], multiedges=True,


˓→sparse=True)

sage: G.allow_multiple_edges(False, keep_label='min')


sage: G.edges()
[(0, 1, 1)]

If we ask for the maximum label:


sage: G = Graph([(0, 1, 1), (0, 1, 2), (0, 1, 3)], multiedges=True,
˓→sparse=True)

sage: G.allow_multiple_edges(False, keep_label='max')


sage: G.edges()
[(0, 1, 3)]

The standard behavior with digraphs:


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)]

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)

16 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


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()
[]

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)]

1.1. Generic graphs (common to directed/undirected) 17


Sage Reference Manual: Graph Theory, Release 8.4

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: matrix(GF(2),G) # matrix over GF(2)


[0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0]
[1 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0]
[1 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0]
[0 1 1 0 0 0 0 1 0 0 0 1 0 0 0 0]
[1 0 0 0 0 1 1 0 0 0 0 0 1 0 0 0]
[0 1 0 0 1 0 0 1 0 0 0 0 0 1 0 0]
[0 0 1 0 1 0 0 1 0 0 0 0 0 0 1 0]
[0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 1]
[1 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0]
[0 1 0 0 0 0 0 0 1 0 0 1 0 1 0 0]
[0 0 1 0 0 0 0 0 1 0 0 1 0 0 1 0]
[0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 1]
[0 0 0 0 1 0 0 0 1 0 0 0 0 1 1 0]
[0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 1]
[0 0 0 0 0 0 1 0 0 0 1 0 1 0 0 1]
[0 0 0 0 0 0 0 1 0 0 0 1 0 1 1 0]

sage: D = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] }


˓→)

sage: D.adjacency_matrix()
[0 1 1 1 0 0]
[1 0 1 0 0 0]
[0 0 0 1 0 0]
[0 0 0 0 1 0]
(continues on next page)

18 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


[1 0 0 0 0 1]
[0 1 0 0 0 0]

A different ordering of the vertices:

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

automorphism_group(partition=None, verbosity=0, edge_labels=False, order=False, re-


turn_group=True, orbits=False, algorithm=None)
Return the automorphism group of the graph.
With partition this can also return the largest subgroup of the automorphism group of the (di)graph
whose orbit partition is finer than the partition given.
INPUT:
• partition - default is the unit partition, otherwise computes the subgroup of the full automorphism
group respecting the partition.
• edge_labels - default False, otherwise allows only permutations respecting edge labels.
• order - (default False) if True, compute the order of the automorphism group
• return_group - default True
• orbits - returns the orbits of the group acting on the vertices of the graph
• algorithm - If algorithm = "bliss" the automorphism group is computed using the op-
tional package bliss (http://www.tcs.tkk.fi/Software/bliss/index.html). Setting it to “sage” uses Sage’s
implementation. If set to None (default), bliss is used when available.
OUTPUT: The order of the output is group, order, orbits. However, there are options to turn each of these
on or off.
EXAMPLES:
Graphs:

sage: graphs_query = GraphQuery(display_cols=['graph6'],num_vertices=4)


sage: L = graphs_query.get_graphs_list()
sage: graphs_list.show_graphs(L)
(continues on next page)

1.1. Generic graphs (common to directed/undirected) 19


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: for g in L:
....: G = g.automorphism_group()
....: G.order(), G.gens()
(24, [(2,3), (1,2), (0,1)])
(4, [(2,3), (0,1)])
(2, [(1,2)])
(6, [(1,2), (0,1)])
(6, [(2,3), (1,2)])
(8, [(1,2), (0,1)(2,3)])
(2, [(0,1)(2,3)])
(2, [(1,2)])
(8, [(2,3), (0,1), (0,2)(1,3)])
(4, [(2,3), (0,1)])
(24, [(2,3), (1,2), (0,1)])
sage: C = graphs.CubeGraph(4)
sage: G = C.automorphism_group()
sage: M = G.character_table() # random order of rows, thus abs() below
sage: QQ(M.determinant()).abs()
712483534798848
sage: G.order()
384

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: D = DiGraph( { 0:[1], 1:[2], 2:[3], 3:[4], 4:[0] } )


sage: D.automorphism_group()
Permutation Group with generators [(0,1,2,3,4)]

Edge labeled graphs:

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)]

sage: G.automorphism_group(edge_labels=True, algorithm="bliss") # optional -


˓→bliss

Permutation Group with generators [(1,4)(2,3)]


(continues on next page)

20 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)

sage: G.automorphism_group(edge_labels=True, algorithm="sage")


Permutation Group with generators [(1,4)(2,3)]

sage: G = Graph({0 : {1 : 7}})


sage: G.automorphism_group(edge_labels=True)
Permutation Group with generators [(0,1)]

sage: foo = Graph(sparse=True)


sage: bar = Graph(implementation='c_graph',sparse=True)
sage: foo.add_edges([(0,1,1),(1,2,2), (2,3,3)])
sage: bar.add_edges([(0,1,1),(1,2,2), (2,3,3)])
sage: foo.automorphism_group(edge_labels=True)
Permutation Group with generators [()]
sage: foo.automorphism_group()
Permutation Group with generators [(0,3)(1,2)]
sage: bar.automorphism_group(edge_labels=True)
Permutation Group with generators [()]

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')

[[0], [2, 3, 6, 7, 8, 9], [1, 4, 5]]


sage: C = graphs.CubeGraph(3)
sage: C.automorphism_group(orbits=True, return_group=False,algorithm='sage')
[['000', '001', '010', '011', '100', '101', '110', '111']]

One can also use the faster algorithm for computing the automorphism group of the graph - bliss:

sage: G = graphs.HallJankoGraph() # optional - bliss


sage: A1 = G.automorphism_group() # optional - bliss
sage: A2 = G.automorphism_group(algorithm='bliss') # optional - bliss
sage: A1.is_isomorphic(A2) # optional - bliss
True

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

1.1. Generic graphs (common to directed/undirected) 21


Sage Reference Manual: Graph Theory, Release 8.4

The average degree of a tree is always strictly less than 2:

sage: g = graphs.RandomGNP(20,.5)
sage: tree = Graph()
sage: tree.add_edges(g.min_spanning_tree())
sage: tree.average_degree() < 2
True

For any graph, it is equal to \frac {2|E|}{|V|}:

sage: g = graphs.RandomGNP(50,.8)
sage: g.average_degree() == 2*g.size()/g.order()
True

average_distance(by_weight=False, algorithm=None, weight_function=None)


Returns the average distance between vertices of the graph.
1
∑︀
Formally, for a graph 𝐺 this value is equal to 𝑛(𝑛−1) 𝑢,𝑣∈𝐺 𝑑(𝑢, 𝑣) where 𝑑(𝑢, 𝑣) denotes the distance
between vertices 𝑢 and 𝑣 and 𝑛 is the number of vertices in 𝐺.
For more information on the input variables and more examples, we refer to wiener_index() and
shortest_path_all_pairs(), which have very similar input variables.
INPUT:
• 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' - 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' for unweighted graphs,
'Dijkstra_Boost' if all weights are positive, 'Johnson_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:
From [GYLL93]:

22 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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:

– "Tarjan_Boost" (default) – Tarjan’s algorithm (Boost implementation).


– "Tarjan_Sage" – Tarjan’s algorithm (Sage implementation).

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: from sage.graphs.connectivity import blocks_and_cut_vertices


sage: rings = graphs.CycleGraph(10)
sage: rings.merge_vertices([0, 5])
sage: blocks_and_cut_vertices(rings)
([[0, 1, 4, 2, 3], [0, 6, 9, 7, 8]], [0])
sage: rings.blocks_and_cut_vertices()
([[0, 1, 4, 2, 3], [0, 6, 9, 7, 8]], [0])
sage: blocks_and_cut_vertices(rings, algorithm="Tarjan_Sage")
([[0, 1, 2, 3, 4], [0, 6, 7, 8, 9]], [0])

The Petersen graph is biconnected, hence has no cut vertices:

sage: blocks_and_cut_vertices(graphs.PetersenGraph())
([[0, 1, 4, 5, 2, 6, 3, 7, 8, 9]], [])

1.1. Generic graphs (common to directed/undirected) 23


Sage Reference Manual: Graph Theory, Release 8.4

Decomposing paths to pairs:

sage: g = graphs.PathGraph(4) + graphs.PathGraph(5)


sage: blocks_and_cut_vertices(g)
([[2, 3], [1, 2], [0, 1], [7, 8], [6, 7], [5, 6], [4, 5]], [1, 2, 5, 6, 7])

A disconnected graph:

sage: g = Graph({1:{2:28, 3:10}, 2:{1:10, 3:16}, 4:{}, 5:{6:3, 7:10, 8:4}})


sage: blocks_and_cut_vertices(g)
([[1, 2, 3], [5, 6], [5, 7], [5, 8], [4]], [5])

A directed graph with Boost’s algorithm (trac ticket #25994):

sage: rings = graphs.CycleGraph(10)


sage: rings.merge_vertices([0, 5])
sage: rings = rings.to_directed()
sage: blocks_and_cut_vertices(rings, algorithm="Tarjan_Boost")
([[0, 1, 4, 2, 3], [0, 6, 9, 7, 8]], [0])

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: from sage.graphs.connectivity import blocks_and_cuts_tree


sage: T = blocks_and_cuts_tree(graphs.KrackhardtKiteGraph()); T
Graph on 5 vertices
sage: T.is_isomorphic(graphs.PathGraph(5))
True
sage: from sage.graphs.connectivity import blocks_and_cuts_tree
sage: T = graphs.KrackhardtKiteGraph().blocks_and_cuts_tree(); T
Graph on 5 vertices

The distance between two leaves is even:

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)

24 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: all(T.distance(u,v) % 2 == 0 for u in leaves for v in leaves)
True

The tree of a biconnected graph has a single vertex, of type 𝐵:

sage: T = blocks_and_cuts_tree(graphs.PetersenGraph())
sage: T.vertices()
[('B', (0, 1, 4, 5, 2, 6, 3, 7, 8, 9))]

breadth_first_search(start, ignore_direction=False, distance=None, neighbors=None, re-


port_distance=False)
Return an iterator over the vertices in a breadth-first ordering.
INPUT:
• start – vertex or list of vertices from which to start the traversal.
• ignore_direction – (default False) only applies to directed graphs. If True, searches across
edges in either direction.
• distance – the maximum distance from the start nodes to traverse. The start nodes are
distance zero from themselves.
• neighbors – a function giving the neighbors of a vertex. The function should take a vertex and
return a list of vertices. For a graph, neighbors is by default the neighbors() function of the
graph. For a digraph, the neighbors function defaults to the neighbor_out_iterator()
function of the graph.
• report_distance – (default False) If True, reports pairs (vertex, distance) where distance is
the distance from the start nodes. If False only the vertices are reported.
See also:

• breadth_first_search – breadth-first search for fast compiled graphs.


• depth_first_search – depth-first search for fast compiled graphs.
• depth_first_search() – depth-first search for generic graphs.

EXAMPLES:

sage: G = Graph( { 0: [1], 1: [2], 2: [3], 3: [4], 4: [0]} )


sage: list(G.breadth_first_search(0))
[0, 1, 4, 2, 3]

By default, the edge direction of a digraph is respected, but this can be overridden by the
ignore_direction parameter:

sage: D = DiGraph( { 0: [1,2,3], 1: [4,5], 2: [5], 3: [6], 5: [7], 6: [7], 7:


˓→[0]})

sage: list(D.breadth_first_search(0))
[0, 1, 2, 3, 4, 5, 6, 7]
sage: list(D.breadth_first_search(0, ignore_direction=True))
[0, 1, 2, 3, 7, 4, 5, 6]

You can specify a maximum distance in which to search. A distance of zero returns the start vertices:

1.1. Generic graphs (common to directed/undirected) 25


Sage Reference Manual: Graph Theory, Release 8.4

sage: D = DiGraph( { 0: [1,2,3], 1: [4,5], 2: [5], 3: [6], 5: [7], 6: [7], 7:


˓→[0]})

sage: list(D.breadth_first_search(0,distance=0))
[0]
sage: list(D.breadth_first_search(0,distance=1))
[0, 1, 2, 3]

Multiple starting vertices can be specified in a list:

sage: D = DiGraph( { 0: [1,2,3], 1: [4,5], 2: [5], 3: [6], 5: [7], 6: [7], 7:


˓→[0]})

sage: list(D.breadth_first_search([0]))
[0, 1, 2, 3, 4, 5, 6, 7]
sage: list(D.breadth_first_search([0,6]))
[0, 6, 1, 2, 3, 7, 4, 5]
sage: list(D.breadth_first_search([0,6],distance=0))
[0, 6]
sage: list(D.breadth_first_search([0,6],distance=1))
[0, 6, 1, 2, 3, 7]
sage: list(D.breadth_first_search(6,ignore_direction=True,distance=2))
[6, 3, 7, 0, 5]

More generally, you can specify a neighbors function. For example, you can traverse the graph back-
wards by setting neighbors to be the neighbors_in() function of the graph:

sage: D = DiGraph( { 0: [1,2,3], 1: [4,5], 2: [5], 3: [6], 5: [7], 6: [7], 7:


˓→[0]})

sage: list(D.breadth_first_search(5,neighbors=D.neighbors_in, distance=2))


[5, 1, 2, 0]
sage: list(D.breadth_first_search(5,neighbors=D.neighbors_out, distance=2))
[5, 7, 0]
sage: list(D.breadth_first_search(5,neighbors=D.neighbors, distance=2))
[5, 1, 2, 7, 0, 4, 6]

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]

sage: D = DiGraph({0:[1, 3], 1:[0, 2], 2:[0, 3], 3:[4]})


sage: D.show()
sage: list(D.breadth_first_search(4, neighbors=D.neighbor_in_iterator, report_
˓→distance=True))

[(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)]

canonical_label(partition=None, certificate=False, verbosity=0, edge_labels=False, algo-


rithm=None, return_graph=True)
Return the canonical graph.

26 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

We can get the relabeling used for canonization:

sage: g, c = g1.canonical_label(algorithm='sage', certificate=True)


sage: g
Grid Graph for [2, 3]: Graph on 6 vertices
sage: c
{(0, 0): 3, (0, 1): 4, (0, 2): 2, (1, 0): 0, (1, 1): 5, (1, 2): 1}

Multigraphs and directed graphs work too:

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)

1.1. Generic graphs (common to directed/undirected) 27


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


Multi-graph on 2 vertices
sage: Graph('A?', implementation='c_graph').canonical_label()
Graph on 2 vertices

sage: P = graphs.PetersenGraph()
sage: DP = P.to_directed()
sage: DP.canonical_label(algorithm='sage').adjacency_matrix()
[0 0 0 0 0 0 0 1 1 1]
[0 0 0 0 1 0 1 0 0 1]
[0 0 0 1 0 0 1 0 1 0]
[0 0 1 0 0 1 0 0 0 1]
[0 1 0 0 0 1 0 0 1 0]
[0 0 0 1 1 0 0 1 0 0]
[0 1 1 0 0 0 0 1 0 0]
[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]

Edge labeled graphs:

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

(Graph on 5 vertices, {0: 4, 1: 3, 2: 1, 3: 0, 4: 2})

sage: G.canonical_label(edge_labels=True, algorithm="sage", certificate=True)


(Graph on 5 vertices, {0: 4, 1: 3, 2: 0, 3: 1, 4: 2})

Another example where different canonization algorithms give different graphs:

sage: g = Graph({'a': ['b'], 'c': ['d']})


sage: g_sage = g.canonical_label(algorithm='sage')
sage: g_bliss = g.canonical_label(algorithm='bliss') # optional - bliss
sage: g_sage.edges(labels=False)
[(0, 3), (1, 2)]
sage: g_bliss.edges(labels=False) # optional - bliss
[(0, 1), (2, 3)]

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:

• is_cartesian_product() – factorization of graphs according to the Cartesian product


• graph_products – a module on graph products.

categorical_product(other)
Returns the tensor product of self and other.

28 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

center(by_weight=False, algorithm=None, weight_function=None, check_weight=True)


Returns the set of vertices in the center, i.e. whose eccentricity is equal to the radius of the (di)graph.
In other words, the center is the set of vertices achieving the minimum eccentricity.
For more information and examples on how to use input variables, see shortest_paths() and
eccentricity()
INPUT:
• by_weight - if True, edge weights are taken into account; if False, all edges have weight 1.
• algorithm (string) - one of the following algorithms:
– 'BFS' - the computation is done through a BFS centered on each vertex successively. Works
only if by_weight==False.
– 'Floyd-Warshall-Cython' - a Cython implementation of the Floyd-Warshall algorithm.
Works only if by_weight==False.
– 'Floyd-Warshall-Python' - a Python implementation of the Floyd-Warshall algorithm.
Works also with weighted graphs, even with negative weights (but no negative cycle is allowed).
– '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' for unweighted graphs,
'Dijkstra_Boost' if all weights are positive, 'Johnson_Boost', otherwise.

1.1. Generic graphs (common to directed/undirected) 29


Sage Reference Manual: Graph Theory, Release 8.4

• 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']

Some other graphs. Center can be the whole graph:

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_betweenness(k=None, normalized=True, weight=None, endpoints=False,


seed=None, exact=False, algorithm=None)
Returns the betweenness centrality (fraction of number of shortest paths that go through each vertex) as a
dictionary keyed by vertices. The betweenness is normalized by default to be in range (0,1).
Measures of the centrality of a vertex within a graph determine the relative importance of that vertex to
its graph. Vertices that occur on more shortest paths between other vertices have higher betweenness than
vertices that occur on less.
INPUT:
• normalized - boolean (default True) - if set to False, result is not normalized.
• k - integer or None (default None) - if set to an integer, use k node samples to estimate betweenness.
Higher values give better approximations. Not available when algorithm="Sage".
• weight - None or string. If set to a string, use that attribute of the nodes as weight. weight =
True is equivalent to weight = "weight". Not available when algorithm="Sage".
• endpoints - Boolean. If set to True it includes the endpoints in the shortest paths count. Not
available when algorithm="Sage".
• exact (boolean, default: False) – whether to compute over rationals or on double C variables.
Not available when algorithm="NetworkX".
• algorithm (default: None) – can be either "Sage" (see centrality), "NetworkX" or
"None". In the latter case, Sage’s algorithm will be used whenever possible.
See also:

• centrality_degree()
• centrality_closeness()

EXAMPLES:

30 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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}

centrality_closeness(vert=None, by_weight=False, algorithm=None, weight_function=None,


check_weight=True)
Returns the closeness centrality of all vertices in variable vert.
In a (strongly) connected graph, the closeness centrality of a vertex 𝑣 is equal to the inverse of the average
distance between 𝑣 and other vertices. If the graph is disconnected, the closeness centrality of 𝑣 is multi-
plied by the fraction of reachable vertices in the graph: this way, central vertices should also reach several
other vertices in the graph [OLJ14]. In formulas,

𝑟(𝑣) − 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.

1.1. Generic graphs (common to directed/undirected) 31


Sage Reference Manual: Graph Theory, Release 8.4

– 'Floyd-Warshall-Python' - the Python implementation of the Floyd-Warshall algorithm.


Works only if all centralities are needed, but it can deal with weighted graphs, even with negative
weights (but no negative cycle is allowed).
– 'Johnson_Boost': the Johnson algorithm, implemented in Boost (works also with negative
weights, if there is no negative cycle).
– None (default): Sage chooses the best algorithm: 'BFS' if by_weight is False,
'Dijkstra_Boost' if all weights are positive, 'Johnson_Boost' otherwise.
• weight_function (function) - 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:
If vert is a vertex, the closeness centrality of that vertex. Otherwise, a dictionary associating to each
vertex in vert its closeness centrality. If a vertex has (out)degree 0, its closeness centrality is not defined,
and the vertex is not included in the output.
See also:

• centrality_closeness_top_k()
• centrality_degree()
• centrality_betweenness()

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.

˓→61111111111111..., 7: 0.61111111111111..., 8: 0.61111111111111..., 9: 0.

˓→61111111111111..., 10: 0.61111111111111..., 11: 0.61111111111111...}

sage: D = DiGraph({0:[1,2,3], 1:[2], 3:[0,1]})


sage: D.show(figsize=[2,2])
sage: D.centrality_closeness(vert=[0,1])
{0: 1.0, 1: 0.3333333333333333}
sage: D = D.to_undirected()
sage: D.show(figsize=[2,2])
sage: D.centrality_closeness()
{0: 1.0, 1: 1.0, 2: 0.75, 3: 0.75}

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)

32 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: d.centrality_closeness(0)
0.4
sage: dist = d.shortest_path_lengths(0).values()
sage: float(len(dist)-1) / sum(dist)
0.4

If a vertex has (out)degree 0, its closeness centrality is not defined:

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, 0): 0.75, (0, 1): 0.75}


sage: D.centrality_closeness((0,0), weight_function=weight_function) # 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

1.1. Generic graphs (common to directed/undirected) 33


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: G=graphs.CycleGraph(4); G.set_vertices({0:'vertex0'})


sage: G.order(); G.size()
4
4
sage: len(G._pos)
4
sage: G.name()
'Cycle graph'
sage: G.get_vertex(0)
'vertex0'
sage: H = G.copy(implementation='c_graph', sparse=True)
sage: H.clear()
sage: H.order(); H.size()
0
0
sage: len(H._pos)
0
sage: H.name()
''
sage: H.get_vertex(0)
sage: H = G.copy(implementation='c_graph', sparse=False)
(continues on next page)

34 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: H.clear()
sage: H.order(); H.size()
0
0
sage: len(H._pos)
0
sage: H.name()
''
sage: H.get_vertex(0)

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:

1.1. Generic graphs (common to directed/undirected) 35


Sage Reference Manual: Graph Theory, Release 8.4

sage: (graphs.FruchtGraph()).clustering_average()
1/4
sage: (graphs.FruchtGraph()).clustering_average(implementation='networkx')
0.25

clustering_coeff(nodes=None, weight=False, implementation=None)


Returns the clustering coefficient for each vertex in nodes as a dictionary keyed by vertex.
For an unweighted graph, the clustering coefficient of a node 𝑖 is
(︀ the
)︀ fraction of existing triangles contain-
ing node 𝑖 and all possible triangles containing 𝑖: 𝑐𝑖 = 𝑇 (𝑖)/ 𝑘2𝑖 where 𝑇 (𝑖) is the number of existing
triangles through 𝑖, and 𝑘𝑖 is the degree of vertex 𝑖.
For weighted graphs the clustering is defined as the geometric average of the subgraph edge weights,
normalized by the maximum weight in the network.
The value of 𝑐𝑖 is assigned 0 if 𝑘𝑖 < 2.
See also section “Clustering” in chapter “Algorithms” of [HSSNX].
INPUT:
• nodes - the vertices to inspect (default None, returns data on all vertices in graph)
• weight - string or boolean (default is False). If it is a string it used the indicated edge property as
weight. weight = True is equivalent to weight = 'weight'
• 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 or weighted graphs, and that 'sparse_copy' and 'dense_copy' do not sup-
port node different from None
EXAMPLES:

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.

36 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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)]]

ALGORITHM: Brendan D. McKay’s Master’s Thesis, University of Melbourne, 1976.


complement()
Returns the complement of the (di)graph.
The complement of a graph has the same vertices, but exactly those edges that are not in the original graph.
This is not well defined for graphs with multiple edges.
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.plot() # long time
Graphics object consisting of 26 graphics primitives
sage: PC = P.complement()
sage: PC.plot() # long time
Graphics object consisting of 41 graphics primitives

sage: graphs.TetrahedralGraph().complement().size()
0
(continues on next page)

1.1. Generic graphs (common to directed/undirected) 37


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: graphs.CycleGraph(4).complement().edges()
[(0, 2, None), (1, 3, None)]
sage: graphs.CycleGraph(4).complement()
complement(Cycle graph): Graph on 4 vertices
sage: G = Graph(multiedges=True, sparse=True)
sage: G.add_edges([(0,1)]*3)
sage: G.complement()
Traceback (most recent call last):
...
ValueError: This method is not known to work on graphs with
multiedges. Perhaps this method can be updated to handle them, but
in the meantime if you want to use it please disallow multiedges
using allow_multiple_edges().

connected_component_containing_vertex(G, vertex, sort=True)


Return a list of the vertices connected to vertex.
INPUT:
• G (generic_graph) – the input graph.
• v – the vertex to search for.
• sort – boolean (default True) whether to sort vertices inside the component
EXAMPLES:

sage: from sage.graphs.connectivity import connected_component_containing_


˓→vertex

sage: G = Graph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )


sage: connected_component_containing_vertex(G,0)
[0, 1, 2, 3]
sage: G.connected_component_containing_vertex(0)
[0, 1, 2, 3]
sage: D = DiGraph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )
sage: connected_component_containing_vertex(D,0)
[0, 1, 2, 3]

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:

sage: from sage.graphs.connectivity import connected_components


sage: G = Graph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )
sage: connected_components(G)
[[0, 1, 2, 3], [4, 5, 6]]
sage: G.connected_components()
[[0, 1, 2, 3], [4, 5, 6]]
sage: D = DiGraph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )
(continues on next page)

38 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: connected_components(D)
[[0, 1, 2, 3], [4, 5, 6]]

connected_components_number(G)
Return the number of connected components.
INPUT:
• G (generic_graph) – the input graph.
EXAMPLES:

sage: from sage.graphs.connectivity import connected_components_number


sage: G = Graph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )
sage: connected_components_number(G)
2
sage: G.connected_components_number()
2
sage: D = DiGraph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )
sage: connected_components_number(D)
2

connected_components_sizes(G)
Return the sizes of the connected components as a list.
The list is sorted from largest to lower values.
EXAMPLES:

sage: from sage.graphs.connectivity import connected_components_sizes


sage: for x in graphs(3): print(connected_components_sizes(x))
[1, 1, 1]
[2, 1]
[3]
[3]
sage: for x in graphs(3): print(x.connected_components_sizes())
[1, 1, 1]
[2, 1]
[3]
[3]

connected_components_subgraphs(G)
Return a list of connected components as graph objects.
EXAMPLES:

sage: from sage.graphs.connectivity import connected_components_subgraphs


sage: G = Graph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )
sage: L = connected_components_subgraphs(G)
sage: graphs_list.show_graphs(L)
sage: D = DiGraph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )
sage: L = connected_components_subgraphs(D)
sage: graphs_list.show_graphs(L)
sage: L = D.connected_components_subgraphs()
sage: graphs_list.show_graphs(L)

connected_subgraph_iterator(G, k=None, vertices_only=False)


Iterator over the induced connected subgraphs of order at most 𝑘.

1.1. Generic graphs (common to directed/undirected) 39


Sage Reference Manual: Graph Theory, Release 8.4

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:

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,
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(k=2, vertices_only=True))
[[1], [1, 2], [2], [2, 3], [2, 4], [3], [3, 4], [4]]

sage: G = DiGraph([(1, 2), (2, 1)])


sage: list(G.connected_subgraph_iterator())
[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], [2]]

contract_edge(u, v=None, label=None)


Contract an edge from 𝑢 to 𝑣.
This method returns silently if the edge does not exist.
INPUT: The following forms are all accepted:

40 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

• 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)

1.1. Generic graphs (common to directed/undirected) 41


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


[(0, 0, None),
(0, 0, None),
(0, 0, None),
(0, 3, None),
(0, 3, None),
(0, 3, None),
(3, 0, None),
(3, 0, None),
(3, 0, None)]

sage: edgelist = [(0,1,0), (0,1,1), (0,1,2)]


sage: G = Graph(edgelist, loops=True, multiedges=True)
sage: G.contract_edges([(0,1), (0,1,2)]); G.edges()
Traceback (most recent call last):
...
ValueError: edge tuples in input should have the same length

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)]

copy(weighted=None, implementation=’c_graph’, data_structure=None, sparse=None, im-


mutable=None)
Change the graph implementation
INPUT:
• weighted boolean (default: None) – weightedness for the copy. Might change the equality class if
not None.
• sparse (boolean) – sparse=True is an alias for data_structure="sparse",
and sparse=False is an alias for data_structure="dense". Only used when
implementation='c_graph' and data_structure=None.
• data_structure – one of "sparse", "static_sparse", or "dense". See the documen-
tation of Graph or DiGraph. Only used when implementation='c_graph'.
• immutable (boolean) – whether to create a mutable/immutable copy. Only used when
implementation='c_graph' and data_structure=None.
– immutable=None (default) means that the graph and its copy will behave the same way.
– immutable=True is a shortcut for data_structure='static_sparse' and
implementation='c_graph'
– immutable=False sets implementation to 'c_graph'. When immutable=False
is used to copy an immutable graph, the data structure used is "sparse" unless anything else is
specified.

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).

42 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

Note that vertex associations are also kept:

sage: d = {0 : graphs.DodecahedralGraph(), 1 : graphs.FlowerSnark(), 2 :


˓→graphs.MoebiusKantorGraph(), 3 : graphs.PetersenGraph() }

sage: T = graphs.TetrahedralGraph()
sage: T.set_vertices(d)
sage: T2 = copy(T)
sage: T2.get_vertex(0)
Dodecahedron: Graph on 20 vertices

Notice that the copy is at least as deep as the objects:

sage: T2.get_vertex(0) is T.get_vertex(0)


False

Examples of the keywords in use:

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

Argument weighted affects the equality class:

sage: G = graphs.CompleteGraph(5)
sage: H1 = G.copy(weighted=False)
(continues on next page)

1.1. Generic graphs (common to directed/undirected) 43


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: H2 = G.copy(weighted=True)
sage: [G.weighted(), H1.weighted(), H2.weighted()]
[False, False, True]
sage: [G == H1, G == H2, H1 == H2]
[True, False, False]
sage: G.weighted(True)
sage: [G == H1, G == H2, H1 == H2]
[False, True, False]

crossing_number()
Return the crossing number of the graph.
The crossing number of a graph is the minimum number of edge crossings needed to draw the graph on a
plane. It can be seen as a measure of non-planarity; a planar graph has crossing number zero.
See the Wikipedia article Crossing_number for more information.
EXAMPLES:

sage: P = graphs.PetersenGraph()
sage: P.crossing_number()
2

ALGORITHM:
This is slow brute force implementation: for every 𝑘 pairs of edges try adding a new vertex for a crossing
point for them. If the result is not planar in any of those, try 𝑘 + 1 pairs.
Computing the crossing number is NP-hard problem.
cycle_basis(output=’vertex’)
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]]

One can also get the result as a list of lists of edges:

44 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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)]]

Checking the given cycles are algebraically free:

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

Defining a lambda function associating a vector to the vertices of a cycle:

sage: vertices_to_edges = lambda x : zip( x, x[1:] + [x[0]] )


sage: cycle_to_vector = lambda x : sum( edge_vector[e] for e in vertices_to_
˓→edges(x) )

Finally checking the cycles are a free set:

sage: basis_as_vectors = [cycle_to_vector(_) for _ in basis]


sage: edge_space.span(basis_as_vectors).rank() == len(basis)
True

For undirected graphs with multiple edges:

sage: G = Graph([(0,2,'a'),(0,2,'b'),(0,1,'c'),(1,2,'d')], multiedges=True)


sage: G.cycle_basis()
[[0, 2], [2, 1, 0]]
sage: G.cycle_basis(output='edge')
[[(0, 2, 'a'), (2, 0, 'b')], [(2, 1, 'd'), (1, 0, 'c'),
(0, 2, 'a')]]

Disconnected graph:

sage: G.add_cycle(["Hey", "Wuuhuu", "Really ?"])


sage: G.cycle_basis()
[['Really ?', 'Hey', 'Wuuhuu'], [0, 2], [2, 1, 0]]
sage: G.cycle_basis(output='edge')
[[('Really ?', 'Hey', None),
('Hey', 'Wuuhuu', None),
('Wuuhuu', 'Really ?', None)],
[(0, 2, 'a'), (2, 0, 'b')],
[(2, 1, 'd'), (1, 0, 'c'), (0, 2, 'a')]]

Graph that allows multiple edges but does not contain any:

1.1. Generic graphs (common to directed/undirected) 45


Sage Reference Manual: Graph Theory, Release 8.4

sage: G = graphs.CycleGraph(3)
sage: G.allow_multiple_edges(True)
sage: G.cycle_basis()
[[2, 1, 0]]

Not yet implemented for directed graphs with multiple edges:


sage: G = DiGraph([(0,2,'a'),(0,2,'b'),(0,1,'c'),(1,2,'d')], multiedges=True)
sage: G.cycle_basis()
Traceback (most recent call last):
...
NotImplementedError: not implemented for directed graphs
with multiple edges

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]

sage: D = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] }


˓→)

sage: D.degree(vertices = [0,1,2], labels=True)


{0: 5, 1: 4, 2: 3}
sage: D.degree()
[5, 4, 3, 3, 3, 2]

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.

46 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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]

The degree sequence of a digraph:

1.1. Generic graphs (common to directed/undirected) 47


Sage Reference Manual: Graph Theory, Release 8.4

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 sequences of some common graphs:


sage: graphs.PetersenGraph().degree_sequence()
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
sage: graphs.HouseGraph().degree_sequence()
[3, 3, 2, 2, 2]
sage: graphs.FlowerSnark().degree_sequence()
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]

degree_to_cell(vertex, cell)
Returns the number of edges from vertex to an edge in cell. In the case of a digraph, returns a tuple
(in_degree, out_degree).
EXAMPLES:
sage: G = graphs.CubeGraph(3)
sage: cell = G.vertices()[:3]
sage: G.degree_to_cell('011', cell)
2
sage: G.degree_to_cell('111', cell)
0

sage: D = DiGraph({ 0:[1,2,3], 1:[3,4], 3:[4,5]})


sage: cell = [0,1,2]
sage: D.degree_to_cell(5, cell)
(0, 0)
sage: D.degree_to_cell(3, cell)
(2, 0)
sage: D.degree_to_cell(0, cell)
(0, 2)

delete_edge(u, v=None, label=None)


Delete the edge from u to v, returning silently if vertices or edge does not exist.
INPUT: The following forms are all accepted:
• G.delete_edge( 1, 2 )
• G.delete_edge( (1, 2) )
• G.delete_edges( [ (1, 2) ] )
• G.delete_edge( 1, 2, ‘label’ )
• G.delete_edge( (1, 2, ‘label’) )
• G.delete_edges( [ (1, 2, ‘label’) ] )
EXAMPLES:
sage: G = graphs.CompleteGraph(19).copy(implementation='c_graph')
sage: G.size()
171
sage: G.delete_edge( 1, 2 )
sage: G.delete_edge( (3, 4) )
sage: G.delete_edges( [ (5, 6), (7, 8) ] )
(continues on next page)

48 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: G.size()
167

sage: G.delete_edge( 9, 10, 'label' )


sage: G.delete_edge( (11, 12, 'label') )
sage: G.delete_edges( [ (13, 14, 'label') ] )
sage: G.size()
167

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) ] )

sage: C.delete_edge( 9, 10, 'label' )


sage: C.delete_edge( (11, 12, 'label') )
sage: C.delete_edges( [ (13, 14, 'label') ] )
sage: C.size() # correct!
338
sage: C.has_edge( (11, 12) ) # correct!
True

delete_edges(edges)
Delete edges from an iterable container.
EXAMPLES:

sage: K12 = graphs.CompleteGraph(12)


sage: K4 = graphs.CompleteGraph(4)
sage: K12.size()
66
sage: K12.delete_edges(K4.edge_iterator())
sage: K12.size()
60

sage: K12 = graphs.CompleteGraph(12).to_directed()


sage: K4 = graphs.CompleteGraph(4).to_directed()
sage: K12.size()
132
sage: K12.delete_edges(K4.edge_iterator())
sage: K12.size()
120

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)

1.1. Generic graphs (common to directed/undirected) 49


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: G.edges()
[(1, 2, None), (2, 3, None)]

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:

50 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

Note that there are more possible edges on a looped graph:

sage: G.allow_loops(True)
sage: G.density()
1/3

depth_first_search(start, ignore_direction=False, distance=None, neighbors=None)


Return an iterator over the vertices in a depth-first ordering.
INPUT:
• start - vertex or list of vertices from which to start the traversal
• ignore_direction - (default False) only applies to directed graphs. If True, searches across
edges in either direction.
• distance - Deprecated. Broken, do not use.
• neighbors - a function giving the neighbors of a vertex. The function should take a vertex and
return a list of vertices. For a graph, neighbors is by default the neighbors() function of the
graph. For a digraph, the neighbors function defaults to the neighbor_out_iterator()
function of the graph.
See also:

• breadth_first_search()
• breadth_first_search – breadth-first search for fast compiled graphs.
• depth_first_search – depth-first search for fast compiled graphs.

EXAMPLES:

1.1. Generic graphs (common to directed/undirected) 51


Sage Reference Manual: Graph Theory, Release 8.4

sage: G = Graph( { 0: [1], 1: [2], 2: [3], 3: [4], 4: [0]} )


sage: list(G.depth_first_search(0))
[0, 4, 3, 2, 1]

By default, the edge direction of a digraph is respected, but this can be overridden by the
ignore_direction parameter:

sage: D = DiGraph( { 0: [1,2,3], 1: [4,5], 2: [5], 3: [6], 5: [7], 6: [7], 7:


˓→[0]})

sage: list(D.depth_first_search(0))
[0, 3, 6, 7, 2, 5, 1, 4]
sage: list(D.depth_first_search(0, ignore_direction=True))
[0, 7, 6, 3, 5, 2, 1, 4]

Multiple starting vertices can be specified in a list:

sage: D = DiGraph( { 0: [1,2,3], 1: [4,5], 2: [5], 3: [6], 5: [7], 6: [7], 7:


˓→[0]})

sage: list(D.depth_first_search([0]))
[0, 3, 6, 7, 2, 5, 1, 4]
sage: list(D.depth_first_search([0,6]))
[0, 3, 6, 7, 2, 5, 1, 4]

More generally, you can specify a neighbors function. For example, you can traverse the graph 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]

diameter(by_weight=False, algorithm=None, weight_function=None, check_weight=True)


Returns the diameter of the (di)graph.
The diameter is defined to be the maximum distance between two vertices. It is infinite if the (di)graph is
not (strongly) connected.
For more information and examples on how to use input variables, see shortest_paths() and
eccentricity()
INPUT:
• by_weight - if True, edge weights are taken into account; if False, all edges have weight 1.
• algorithm (string) - one of the following algorithms:
– 'BFS' - the computation is done through a BFS centered on each vertex successively. Works
only if by_weight==False.
– 'Floyd-Warshall-Cython' - a Cython implementation of the Floyd-Warshall algorithm.
Works only if by_weight==False.

52 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

– 'Floyd-Warshall-Python' - a Python implementation of the Floyd-Warshall algorithm.


Works also with weighted graphs, even with negative weights (but no negative cycle is allowed).
– 'Dijkstra_NetworkX': the Dijkstra algorithm, implemented in NetworkX. It works with
weighted graphs, but no negative weight is allowed.
– 'standard', '2sweep', 'multi-sweep', 'iFUB': these algorithms are imple-
mented in sage.graphs.distances_all_pairs.diameter() They work only if
by_weight==False. See the function documentation for more information.
– '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: 'iFUB' if by_weight is False,
'Dijkstra_Boost' if all weights are positive, 'Johnson_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: The more symmetric a graph is, the smaller (diameter - radius) is.

sage: G = graphs.BarbellGraph(9, 3)
sage: G.radius()
3
sage: G.diameter()
6

sage: G = graphs.OctahedralGraph()
sage: G.radius()
2
sage: G.diameter()
2

disjoint_routed_paths(pairs, solver=None, verbose=0)


Return a set of disjoint routed paths.
Given a set of pairs (𝑠𝑖 , 𝑡𝑖 ), a set of disjoint routed paths is a set of 𝑠𝑖 − 𝑡𝑖 paths which can intersect at their
endpoints and are vertex-disjoint otherwise.
INPUT:
• pairs – list of pairs of 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) – sets the level of verbosity. Set to 0 by default (quiet).
EXAMPLES:
Given a grid, finding two vertex-disjoint paths, the first one from the top-left corner to the bottom-left
corner, and the second from the top-right corner to the bottom-right corner is easy

1.1. Generic graphs (common to directed/undirected) 53


Sage Reference Manual: Graph Theory, Release 8.4

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.

disjoint_union(other, labels=’pairs’, immutable=None)


Return the disjoint union of self and other.
INPUT:
• labels - (defaults to ‘pairs’) If set to ‘pairs’, each element v in the first graph will be named (0,v)
and each element u in other will be named (1,u) in the result. If set to ‘integers’, the elements of
the result will be relabeled with consecutive integers.
• immutable (boolean) – whether to create a mutable/immutable disjoint union. immutable=None
(default) means that the graphs and their disjoint union will behave the same way.
See also:

• union()
• join()

EXAMPLES:

sage: G = graphs.CycleGraph(3)
sage: H = graphs.CycleGraph(4)
sage: J = G.disjoint_union(H); J
Cycle graph disjoint_union Cycle graph: Graph on 7 vertices
sage: J.vertices()
[(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]

sage: G=Graph({'a': ['b']})


sage: G.name("Custom path")
sage: G.name()
'Custom path'
sage: H=graphs.CycleGraph(3)
sage: J=G.disjoint_union(H); J
Custom path disjoint_union Cycle graph: Graph on 5 vertices
sage: J.vertices()
[(0, 'a'), (0, 'b'), (1, 0), (1, 1), (1, 2)]

disjunctive_product(other)
Returns the disjunctive product of self and other.

54 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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)

sage: G.plot(edge_labels=True).show() # long time


sage: G.distance(0, 3)
2
sage: G.distance(0, 3, by_weight=True)
3

distance_all_pairs(by_weight=False, algorithm=None, weight_function=None,


check_weight=True)
Returns the distances between all pairs of vertices.
INPUT:
• 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:

1.1. Generic graphs (common to directed/undirected) 55


Sage Reference Manual: Graph Theory, Release 8.4

– '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.

Note: This algorithm simply calls GenericGraph.shortest_path_all_pairs(), and we sug-


gest to look at that method for more information and examples.

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:

˓→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}}

Testing on Random Graphs:

56 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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.

1.1. Generic graphs (common to directed/undirected) 57


Sage Reference Manual: Graph Theory, Release 8.4

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

The graph of eight-bit strings, adjacent if different in an odd number of bits.

sage: G = graphs.CubeGraph(8) # long time


sage: H = G.distance_graph([1,3,5,7]) # long time
sage: degrees = [0]*sum([binomial(8,j) for j in [1,3,5,7]]) # long time
sage: degrees.append(2^8) # long time
sage: degrees == H.degree_histogram() # long time
True

An example of using Infinity as the distance in a graph that is not connected.

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: d = DiGraph({1: [2, 3], 2: [3], 3: [4], 4: [1]})


sage: d.distance_matrix()
[0 1 1 2]
[1 0 1 2]
[1 1 0 1]
[2 2 1 0]

sage: G = graphs.CubeGraph(3)
(continues on next page)

58 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: G.distance_matrix()
[0 1 1 2 1 2 2 3]
[1 0 2 1 2 1 3 2]
[1 2 0 1 2 3 1 2]
[2 1 1 0 3 2 2 1]
[1 2 2 3 0 1 1 2]
[2 1 3 2 1 0 2 1]
[2 3 1 2 1 2 0 1]
[3 2 2 1 2 1 1 0]

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 :

sage: all(T.distance_matrix().det() == (-1)^9*(9)*2^8 for T in graphs.


˓→trees(10))

True

See also:

• distance_all_pairs() – computes the distance between any two vertices.

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()
{}

A Graph of order 2 without edge:

sage: g = Graph()
sage: g.add_vertices([1,2])
sage: g.distances_distribution()
{+Infinity: 1}

1.1. Generic graphs (common to directed/undirected) 59


Sage Reference Manual: Graph Theory, Release 8.4

The Petersen Graph:


sage: g = graphs.PetersenGraph()
sage: g.distances_distribution()
{1: 1/3, 2: 2/3}

A graph with multiple disconnected components:


sage: g = graphs.PetersenGraph()
sage: g.add_edge('good','wine')
sage: g.distances_distribution()
{1: 8/33, 2: 5/11, +Infinity: 10/33}

The de Bruijn digraph dB(2,3):


sage: D = digraphs.DeBruijn(2,3)
sage: D.distances_distribution()
{1: 1/4, 2: 11/28, 3: 5/14}

dominating_set(independent=False, total=False, value_only=False, solver=None, verbose=0)


Return a minimum dominating set of the graph.
A minimum dominating set 𝑆 of a graph 𝐺 is a set of its vertices of minimal cardinality such that any
vertex of 𝐺 is in 𝑆 or has one of its neighbors in 𝑆. See the Wikipedia article Dominating_set.
As an optimization problem, it can be expressed as:
∑︁
Minimize : 𝑏𝑣
𝑣∈𝐺
∑︁
Such that : ∀𝑣 ∈ 𝐺, 𝑏𝑣 + 𝑏𝑢 ≥ 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:

60 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

The total dominating set of the Petersen graph has cardinality 4:

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

dominator_tree(g, root, return_dict=False, reverse=False)


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.

1.1. Generic graphs (common to directed/undirected) 61


Sage Reference Manual: Graph Theory, Release 8.4

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}

An example with a directed graph:

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]}

If the output is a dictionary:

sage: graphs.GridGraph([2,2]).dominator_tree((0,0), return_dict=True)


{(0, 0): None, (0, 1): (0, 0), (1, 0): (0, 0), (1, 1): (0, 0)}

eccentricity(v=None, by_weight=False, algorithm=None, weight_function=None,


check_weight=True, dist_dict=None, with_labels=False)
Return the eccentricity of vertex (or vertices) v.
The eccentricity of a vertex is the maximum distance to any other vertex.
For more information and examples on how to use input variables, see shortest_paths()
INPUT:
• v - either a single vertex or a list of vertices. If it is not specified, then it is taken to be all vertices.
• by_weight - if True, edge weights are taken into account; if False, all edges have weight 1.
• algorithm (string) - one of the following algorithms:
– 'BFS' - the computation is done through a BFS centered on each vertex successively. Works
only if by_weight==False.
– 'Floyd-Warshall-Cython' - a Cython implementation of the Floyd-Warshall algorithm.
Works only if by_weight==False and v is None.
– 'Floyd-Warshall-Python' - a Python implementation of the Floyd-Warshall algorithm.
Works also with weighted graphs, even with negative weights (but no negative cycle is allowed).
However, v must be None.

62 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

– '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).
– 'From_Dictionary': uses the (already computed) distances, that are provided by input vari-
able dist_dict.
– None (default): Sage chooses the best algorithm: 'From_Dictionary' if dist_dict is
not None, 'BFS' for unweighted graphs, 'Dijkstra_Boost' if all weights are positive,
'Johnson_Boost' otherwise.
• weight_function (function) - 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.
• dist_dict - used only if algorithm=='From_Dictionary' - a dict of dicts of distances.
• with_labels - Whether to return a list or a dict.
EXAMPLES:

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)

1.1. Generic graphs (common to directed/undirected) 63


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: G.eccentricity(by_weight = True, algorithm = 'Floyd-Warshall-Python')
[2, 1, 2]
sage: G.eccentricity(dist_dict = G.shortest_path_all_pairs(by_weight =
˓→True)[0])

[2, 1, 2]

edge_boundary(vertices1, vertices2=None, labels=True, sort=False)


Return a list of edges (𝑢, 𝑣, 𝑙) with 𝑢 in vertices1 and 𝑣 in vertices2.
If vertices2 is None, then it is set to the complement of vertices1.
In a digraph, the external boundary of a vertex 𝑣 are those vertices 𝑢 with an arc (𝑣, 𝑢).
INPUT:
• labels – if False, each edge is a tuple (𝑢, 𝑣) of vertices.
• sort – boolean (default False) whether to sort the result
EXAMPLES:

sage: K = graphs.CompleteBipartiteGraph(9,3)
sage: len(K.edge_boundary( [0,1,2,3,4,5,6,7,8], [9,10,11] ))
27
sage: K.size()
27

Note that the edge boundary preserves direction:

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

sage: D = DiGraph({0:[1,2], 3:[0]})


sage: D.edge_boundary([0], sort=True)
[(0, 1, None), (0, 2, None)]
sage: D.edge_boundary([0], labels=False, sort=True)
[(0, 1), (0, 2)]

edge_connectivity(G, value_only=True, implementation=None, use_edge_labels=False, ver-


tices=False, solver=None, verbose=0)
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.

64 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

– 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:

sage: from sage.graphs.connectivity import edge_connectivity


sage: g = graphs.PappusGraph()
sage: edge_connectivity(g)
3
sage: g.edge_connectivity()
3

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

1.1. Generic graphs (common to directed/undirected) 65


Sage Reference Manual: Graph Theory, Release 8.4

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

Boost interface also works with directed graphs

sage: edge_connectivity(digraphs.Circuit(10), implementation = "boost",


˓→vertices = True)

[1, [(0, 1)], [{0}, {1, 2, 3, 4, 5, 6, 7, 8, 9}]]

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

edge_cut(s, t, value_only=True, use_edge_labels=False, vertices=False, algorithm=’FF’,


solver=None, verbose=0)
Return a minimum edge cut between vertices 𝑠 and 𝑡.

66 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

Or on Petersen’s graph, with the corresponding bipartition of the vertex set:

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]]]

1.1. Generic graphs (common to directed/undirected) 67


Sage Reference Manual: Graph Theory, Release 8.4

If the graph is a path with randomly weighted edges:

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:

sage: minimum = min([l for u,v,l in g.edge_iterator()])


sage: minimum == g.edge_cut(0, 14, use_edge_labels=True)
True
sage: [value,[e]] = g.edge_cut(0, 14, use_edge_labels=True, value_only=False)
sage: g.edge_label(e[0],e[1]) == minimum
True

The two sides of the edge cut are obviously shorter paths:

sage: value,edges,[set1,set2] = g.edge_cut(0, 14, use_edge_labels=True,


˓→vertices=True)

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

edge_disjoint_paths(s, t, algorithm=’FF’, solver=None, verbose=False)


Return a list of edge-disjoint paths between two vertices.
The edge version of Menger’s theorem asserts that the size of the minimum edge cut between two vertices
𝑠 and‘t‘ (the minimum number of edges whose removal disconnects 𝑠 and 𝑡) is equal to the maximum
number of pairwise edge-independent paths from 𝑠 to 𝑡.
This function returns a list of such paths.
INPUT:
• algorithm – There are currently two different implementations of this method :
– If algorithm = "FF" (default), a Python implementation of the Ford-Fulkerson algorithm is
used.
– If algorithm = "LP", the flow problem is solved using Linear Programming.
• 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 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]]

68 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

edge_disjoint_spanning_trees(k, root=None, solver=None, verbose=0)


Return the desired number of edge-disjoint spanning trees/arborescences.
INPUT:
• k (integer) – the required number of edge-disjoint spanning trees/arborescences
• root (vertex) – root of the disjoint arborescences when the graph is directed. If set to None, the first
vertex in the graph is picked.
• 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:
Mixed Integer Linear Program. The formulation can be found in [LPForm].
There are at least two possible rewritings of this method which do not use Linear Programming:
• The algorithm presented in the paper entitled “A short proof of the tree-packing theorem”, by Thomas
Kaiser [KaisPacking].
• The implementation of a Matroid class and of the Matroid Union Theorem (see section 42.3 of
[SchrijverCombOpt]), applied to the cycle Matroid (see chapter 51 of [SchrijverCombOpt]).
EXAMPLES:
The Petersen Graph does have a spanning tree (it is connected):
sage: g = graphs.PetersenGraph()
sage: [T] = g.edge_disjoint_spanning_trees(1)
sage: T.is_tree()
True

Though, it does not have 2 edge-disjoint trees (as it has less than 2(|𝑉 | − 1) edges):
sage: g.edge_disjoint_spanning_trees(2)
Traceback (most recent call last):
...
EmptySetError: This graph does not contain the required number of trees/
˓→arborescences !

By Edmond’s theorem, a graph which is 𝑘-connected always has 𝑘 edge-disjoint arborescences, regardless
of the root we pick:
sage: 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

In the undirected case, we can only ensure half of it:


sage: g = graphs.RandomGNP(30,.3)
sage: k = floor(Integer(g.edge_connectivity())/2)
sage: trees = g.edge_disjoint_spanning_trees(k)
(continues on next page)

1.1. Generic graphs (common to directed/undirected) 69


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: all([t.is_tree() for t in trees])
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: for i in graphs.PetersenGraph().edge_iterator([0]):


....: print(i)
(0, 1, None)
(0, 4, None)
(0, 5, None)
sage: D = DiGraph( { 0 : [1,2], 1: [0] } )
sage: for i in D.edge_iterator([0]):
....: print(i)
(0, 1, None)
(0, 2, None)

sage: G = graphs.TetrahedralGraph()
sage: list(G.edge_iterator(labels=False))
[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]

sage: D = DiGraph({1:[0], 2:[0]})


sage: list(D.edge_iterator(0))
[]
sage: list(D.edge_iterator(0, ignore_direction=True))
[(1, 0, None), (2, 0, None)]

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({0 : {1 : 'edgelabel'}})


sage: G.edge_label(0, 1)
'edgelabel'
(continues on next page)

70 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: D = DiGraph({1 : {2: 'up'}, 2: {1: 'down'}})
sage: D.edge_label(2, 1)
'down'

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:

sage: G = Graph({0:{1:'x',2:'z',3:'a'}, 2:{5:'out'}}, sparse=True)


sage: G.edge_labels()
['x', 'z', 'a', 'out']
sage: G = DiGraph({0:{1:'x',2:'z',3:'a'}, 2:{5:'out'}}, sparse=True)
sage: G.edge_labels()
['x', 'z', 'a', 'out']

edges(labels=True, sort=True, key=None)


Return a list of edges.
Each edge is a triple (u,v,l) where u and v are vertices and l is a label. If the parameter labels is False
then a list of couple (u,v) is returned where u and v are vertices.
INPUT:
• labels - default: True - if False, each edge is simply a pair (u,v) of vertices.
• sort - default: True - if True, edges are sorted according to the default ordering.
• key - default: None - a function takes an edge (a pair or a triple, according to the labels keyword)
as its one argument and returns a value that can be used for comparisons in the sorting algorithm.
OUTPUT: A list of tuples. It is safe to change the returned list.

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)]

1.1. Generic graphs (common to directed/undirected) 71


Sage Reference Manual: Graph Theory, Release 8.4

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,

˓→15), (15, 16), (16, 17), (17, 18), (18, 19)]

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,

˓→None), (19, 18, None)]

sage: D.edges(labels = False)


[(0, 1), (0, 10), (0, 19), (1, 0), (1, 2), (1, 8), (2, 1), (2, 3), (2, 6), (3,
˓→ 2), (3, 4), (3, 19), (4, 3), (4, 5), (4, 17), (5, 4), (5, 6), (5, 15), (6,

˓→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')]

edges_incident(vertices=None, labels=True, sort=False)


Return incident edges to some vertices.
If vertices` is a vertex, then it returns the list of edges incident to
that vertex. If ``vertices is a list of vertices then it returns the list of all edges adjacent
to those vertices. If vertices is None, it returns a list of all edges in graph. For digraphs, only lists
outward edges.
INPUT:

72 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

• vertices – object (default: None) - a vertex, a list of vertices or None.


• labels – boolean (default: True) - if False, each edge is a tuple (u,v) of vertices.
• sort – boolean (default: False) - if True the returned list is sorted.
EXAMPLES:
sage: graphs.PetersenGraph().edges_incident([0,9], labels=False)
[(0, 1), (0, 4), (0, 5), (4, 9), (6, 9), (7, 9)]
sage: D = DiGraph({0:[1]})
sage: D.edges_incident([0])
[(0, 1, None)]
sage: D.edges_incident([1])
[]

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)

1.1. Generic graphs (common to directed/undirected) 73


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


[1 1 1 1 1 1 1 1 1 1]),
(5, Vector space of degree 10 and dimension 4 over Rational Field
User basis matrix:
[ 1 0 0 0 -1 -1 -1 0 1 1]
[ 0 1 0 0 -1 0 -2 -1 1 2]
[ 0 0 1 0 -1 1 -1 -2 0 2]
[ 0 0 0 1 -1 1 0 -1 -1 1]),
(2, 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])
]

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

User basis matrix:


[ 1 0 -1 -a3 -1 0 1 a3]
[ 0 1 a3 1 0 -1 -a3 -1])
]

A digraph may have complex eigenvalues and eigenvectors. For a 3-cycle, we have:

sage: T = DiGraph({0:[1], 1:[2], 2:[0]})


sage: T.eigenspaces()
[
(1, Vector space of degree 3 and dimension 1 over Rational Field
User basis matrix:
[1 1 1]),
(a1, Vector space of degree 3 and dimension 1 over Number Field in a1 with
˓→defining polynomial x^2 + x + 1

User basis matrix:


[ 1 a1 -a1 - 1])
]

eigenvectors(laplacian=False)
Returns the right eigenvectors of the adjacency matrix of the graph.
INPUT:

74 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

• laplacian - if True, use the Laplacian matrix (see kirchhoff_matrix())


OUTPUT:
A list of triples. Each triple begins with an eigenvalue of the adjacency matrix of the graph. This is
followed by a list of eigenvectors for the eigenvalue, when the eigenvectors are placed on the right side
of the matrix. Together, the eigenvectors form a basis for the eigenspace. The triple concludes with the
algebraic multiplicity of the eigenvalue.
For some graphs, the exact eigenspaces provided by eigenspaces() provide additional insight into the
structure of the eigenspaces.
EXAMPLES:

sage: P = graphs.PetersenGraph()
sage: P.eigenvectors()
[(3, [
(1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
], 1), (-2, [
(1, 0, 0, 0, -1, -1, -1, 0, 1, 1),
(0, 1, 0, 0, -1, 0, -2, -1, 1, 2),
(0, 0, 1, 0, -1, 1, -1, -2, 0, 2),
(0, 0, 0, 1, -1, 1, 0, -1, -1, 1)
], 4), (1, [
(1, 0, 0, 0, 0, 1, -1, 0, 0, -1),
(0, 1, 0, 0, 0, -1, 1, -1, 0, 0),
(0, 0, 1, 0, 0, 0, -1, 1, -1, 0),
(0, 0, 0, 1, 0, 0, 0, -1, 1, -1),
(0, 0, 0, 0, 1, -1, 0, 0, -1, 1)
], 5)]

Eigenspaces for the Laplacian should be identical since the Petersen graph is regular. However, since the
output also contains the eigenvalues, the two outputs are slightly different.

sage: P.eigenvectors(laplacian=True)
[(0, [
(1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
], 1), (5, [
(1, 0, 0, 0, -1, -1, -1, 0, 1, 1),
(0, 1, 0, 0, -1, 0, -2, -1, 1, 2),
(0, 0, 1, 0, -1, 1, -1, -2, 0, 2),
(0, 0, 0, 1, -1, 1, 0, -1, -1, 1)
], 4), (2, [
(1, 0, 0, 0, 0, 1, -1, 0, 0, -1),
(0, 1, 0, 0, 0, -1, 1, -1, 0, 0),
(0, 0, 1, 0, 0, 0, -1, 1, -1, 0),
(0, 0, 0, 1, 0, 0, 0, -1, 1, -1),
(0, 0, 0, 0, 1, -1, 0, 0, -1, 1)
], 5)]

sage: C = graphs.CycleGraph(8)
sage: C.eigenvectors()
[(2, [
(1, 1, 1, 1, 1, 1, 1, 1)
], 1), (-2, [
(1, -1, 1, -1, 1, -1, 1, -1)
], 1), (0, [
(1, 0, -1, 0, 1, 0, -1, 0),
(continues on next page)

1.1. Generic graphs (common to directed/undirected) 75


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


(0, 1, 0, -1, 0, 1, 0, -1)
], 2), (-1.4142135623..., [(1, 0, -1, 1.4142135623..., -1, 0, 1, -1.
˓→4142135623...), (0, 1, -1.4142135623..., 1, 0, -1, 1.4142135623..., -1)],

˓→2), (1.4142135623..., [(1, 0, -1, -1.4142135623..., -1, 0, 1, 1.4142135623..

˓→.), (0, 1, 1.4142135623..., 1, 0, -1, -1.4142135623..., -1)], 2)]

A digraph may have complex eigenvalues. Previously, the complex parts of graph eigenvalues were being
dropped. For a 3-cycle, we have:

sage: T = DiGraph({0:[1], 1:[2], 2:[0]})


sage: T.eigenvectors()
[(1, [
(1, 1, 1)
], 1), (-0.5000000000... - 0.8660254037...*I, [(1, -0.5000000000... - 0.
˓→8660254037...*I, -0.5000000000... + 0.8660254037...*I)], 1), (-0.5000000000.

˓→.. + 0.8660254037...*I, [(1, -0.5000000000... + 0.8660254037...*I, -0.

˓→5000000000... - 0.8660254037...*I)], 1)]

eulerian_circuit(return_vertices=False, labels=True, path=False)


Return a list of edges forming an Eulerian circuit if one exists. Otherwise return False.
This is implemented using Hierholzer’s algorithm.
INPUT:
• return_vertices – (default: False) optionally provide a list of vertices for the path
• labels – (default: True) whether to return edges with labels (3-tuples)
• path – (default: False) find an Eulerian path instead
OUTPUT:
either ([edges], [vertices]) or [edges] of an Eulerian circuit (or path)
EXAMPLES:

sage: g = graphs.CycleGraph(5)
sage: g.eulerian_circuit()
[(0, 4, None), (4, 3, None), (3, 2, None), (2, 1, None), (1, 0, None)]
sage: g.eulerian_circuit(labels=False)
[(0, 4), (4, 3), (3, 2), (2, 1), (1, 0)]

sage: g = graphs.CompleteGraph(7)
sage: edges, vertices = g.eulerian_circuit(return_vertices=True)
sage: vertices
[0, 6, 5, 4, 6, 3, 5, 2, 4, 3, 2, 6, 1, 5, 0, 4, 1, 3, 0, 2, 1, 0]

sage: graphs.CompleteGraph(4).eulerian_circuit()
False

A disconnected graph can be Eulerian:

sage: g = Graph({0: [], 1: [2], 2: [3], 3: [1], 4: []})


sage: g.eulerian_circuit(labels=False)
[(1, 3), (3, 2), (2, 1)]

76 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

sage: g = DiGraph({0: [1], 1: [2, 4], 2:[3], 3:[1]})


sage: g.eulerian_circuit(labels=False, path=True)
[(0, 1), (1, 2), (2, 3), (3, 1), (1, 4)]

sage: g = Graph({0:[1,2,3], 1:[2,3], 2:[3,4], 3:[4]})


sage: g.is_eulerian(path=True)
(0, 1)
sage: g.eulerian_circuit(labels=False, path=True)
[(1, 3), (3, 4), (4, 2), (2, 3), (3, 0), (0, 2), (2, 1), (1, 0)]

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]

export_to_file(filename, format=None, **kwds)


Export the graph to a file.
INPUT:
• filename (string) – a file name.
• format (string) – select the output format explicitly. If set to None (default), the format is set to be
the file extension of filename. Admissible formats are: adjlist, dot, edgelist, gexf, gml,

1.1. Generic graphs (common to directed/undirected) 77


Sage Reference Manual: Graph Theory, Release 8.4

graphml, multiline_adjlist, pajek, yaml.


• All other arguments are forwarded to the subfunction. For more information, see their respective
documentation:

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:

78 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

• 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).

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)]]

With no embedding provided:

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)]]

With no embedding provided (non-planar graph):

sage: graphs.PetersenGraph().faces()
Traceback (most recent call last):
...
ValueError: No embedding is provided and the graph is not planar.

feedback_vertex_set(value_only=False, solver=None, verbose=0, constraint_generation=True)


Return the minimum feedback vertex set of a (di)graph.
The minimum feedback vertex set of a (di)graph is a set of vertices that intersect all of its cycles. Equiva-
lently, a minimum feedback vertex set of a (di)graph is a set 𝑆 of vertices such that the digraph 𝐺 − 𝑆 is
acyclic. For more information, see the Wikipedia article Feedback_vertex_set.
INPUT:
• value_only – boolean (default: False)
– When set to True, only the minimum cardinal of a minimum vertex set is returned.
– When set to False, the Set of vertices of a minimal feedback vertex set is returned.

1.1. Generic graphs (common to directed/undirected) 79


Sage Reference Manual: Graph Theory, Release 8.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.
• 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

80 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: cycle = graphs.CycleGraph(5)


sage: dcycle = DiGraph(cycle)
sage: cycle.vertex_cover(value_only=True)
3
sage: feedback = dcycle.feedback_vertex_set()
sage: len(feedback)
3
sage: (u,v,l) = next(cycle.edge_iterator())
sage: u in feedback or v in feedback
True

For a circuit, the minimum feedback arc set is clearly 1:

sage: circuit = digraphs.Circuit(5)


sage: circuit.feedback_vertex_set(value_only=True) == 1
True

flow(x, y, value_only=True, integer=False, use_edge_labels=True, vertex_bound=False, algo-


rithm=None, solver=None, verbose=0)
Return a maximum flow in the graph from x to y.
The returned flow is represented by an optimal valuation of the edges. For more information, see the
Wikipedia article Max_flow.
As an optimization problem, is can be expressed this way :
∑︁
Maximize : 𝑤𝑒 𝑏𝑒
𝑒∈𝐺.𝑒𝑑𝑔𝑒𝑠()
∑︁
Such that : ∀𝑣 ∈ 𝐺, 𝑏(𝑢,𝑣) ≤ 1
(𝑢,𝑣)∈𝐺.𝑒𝑑𝑔𝑒𝑠()

∀𝑥 ∈ 𝐺, 𝑏𝑥 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.

1.1. Generic graphs (common to directed/undirected) 81


Sage Reference Manual: Graph Theory, Release 8.4

• vertex_bound – boolean (default: False)


– When set to True, sets the maximum flow leaving a vertex different from 𝑥 to 1 (useful for vertex
connectivity parameters).
• algorithm – There are currently three different implementations of this method:
– If algorithm = "FF", a Python implementation of the Ford-Fulkerson algorithm is used
(only available when vertex_bound = False)
– 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 and vertex_bound = False)
– 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.
Only useful when LP is used to solve the flow problem.
• verbose (integer) – sets the level of verbosity. Set to 0 by default (quiet).
Only useful when LP is used to solve the flow problem.

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

The undirected case:

82 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.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

genus(set_embedding=True, on_embedding=None, minimal=True, maximal=False, circular=None, or-


dered=True)
Returns the minimal genus of the graph.
The genus of a compact surface is the number of handles it has. The genus of a graph is the minimal genus
of the surface it can be embedded into. It can be seen as a measure of non-planarity; a planar graph has
genus zero.
Note - This function uses Euler’s formula and thus it is necessary to consider only connected graphs.
INPUT:
• set_embedding (boolean) - whether or not to store an embedding attribute of the computed
(minimal) genus of the graph. (Default is True).
• on_embedding (default: None) - two kinds of input are allowed:
– a dictionary representing a combinatorial embedding on which the genus should be com-
puted. Note that this must be a valid embedding for the graph. The dictionary struc-
ture is given by: vertex1: [neighbor1, neighbor2, neighbor3], vertex2:
[neighbor] where there is a key for each vertex in the graph and a (clockwise) ordered list of
each vertex’s neighbors as values. The value of on_embedding takes precedence over a stored
_embedding attribute if minimal is set to False.
– The value True, in order to indicate that the embedding stored as _embedding should be used
(see examples).
• minimal (boolean) - whether or not to compute the minimal genus of the graph (i.e., testing all
embeddings). If minimal is False, then either maximal must be True or on_embedding must not be
None. If on_embedding is not None, it will take priority over minimal. Similarly, if maximal is True,
it will take priority over minimal.
• maximal (boolean) - whether or not to compute the maximal genus of the graph (i.e., testing
all embeddings). If maximal is False, then either minimal must be True or on_embedding must not
be None. If on_embedding is not None, it will take priority over maximal. However, maximal takes
priority over the default minimal.
• circular (list) - if circular is a list of vertices, the method computes the genus preserving
a planar embedding of the this list. If circular is defined, on_embedding is not a valid option. It is
set to None by default.
• ordered (boolean) - if circular is True, then whether or not the boundary order may be per-
muted. (Default is True, which means the boundary order is preserved.)
EXAMPLES:

sage: g = graphs.PetersenGraph()
sage: g.genus() # tests for minimal genus by default
1
sage: g.genus(on_embedding=True, maximal=True) # on_embedding overrides
˓→minimal and maximal arguments

(continues on next page)

1.1. Generic graphs (common to directed/undirected) 83


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


1
sage: g.genus(maximal=True) # setting maximal to True overrides default
˓→minimal=True

3
sage: g.genus(on_embedding=g.get_embedding()) # can also send a valid
˓→combinatorial embedding dict

3
sage: (graphs.CubeGraph(3)).genus()
0
sage: K23 = graphs.CompleteBipartiteGraph(2,3)
sage: K23.genus()
0
sage: K33 = graphs.CompleteBipartiteGraph(3,3)
sage: K33.genus()
1

Using the circular argument, we can compute the minimal genus preserving a planar, ordered boundary:

sage: cube = graphs.CubeGraph(2)


sage: cube.genus(circular=['01','10'])
0
sage: cube.is_circular_planar()
True
sage: cube.genus(circular=['01','10'])
0
sage: cube.genus(circular=['01','10'], on_embedding=True)
0
sage: cube.genus(circular=['01','10'], maximal=True)
Traceback (most recent call last):
...
NotImplementedError: Cannot compute the maximal genus of a genus respecting a
˓→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.

sage: G = DiGraph({ 0 : [0,1,1,1], 1 : [2,2,3,3], 2 : [1,3,3], 3:[0,3]})


sage: G.genus()
Traceback (most recent call last):
...
NotImplementedError: Can't work with embeddings of non-simple graphs
sage: G.to_simple().genus()
0
sage: G.genus(set_embedding=False)
0
sage: G.genus(maximal=True, set_embedding=False)
Traceback (most recent call last):
...
NotImplementedError: Can't compute the maximal genus of a graph with loops or
˓→multiple edges

We break graphs with cut vertices into their blocks, which greatly speeds up computation of minimal
genus. This is not implemented for maximal genus.

84 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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()
{}

Some of the named graphs come with a pre-specified positioning:

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:

1.1. Generic graphs (common to directed/undirected) 85


Sage Reference Manual: Graph Theory, Release 8.4

sage: d = {0 : graphs.DodecahedralGraph(), 1 : graphs.FlowerSnark(), 2 :


˓→graphs.MoebiusKantorGraph(), 3 : graphs.PetersenGraph() }

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: d = {0 : graphs.DodecahedralGraph(), 1 : graphs.FlowerSnark(), 2 :


˓→graphs.MoebiusKantorGraph(), 3 : graphs.PetersenGraph() }

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:

• odd_girth() – computes the odd girth of a graph.

graphplot(**options)
Returns a GraphPlot object.
EXAMPLES:
Creating a graphplot object uses the same options as graph.plot():

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'),
(continues on next page)

86 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


....: (0,1,'e'),(0,1,'f'),(0,1,'f'),(2,1,'g'),(2,2,'h')])
sage: GP = g.graphplot(edge_labels=True, color_by_label=True, edge_style=
˓→'dashed')

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

graphviz_string(rankdir=’down’, edge_color=None, vertex_labels=True, edge_options=(), la-


bels=’string’, color_by_label=False, edge_colors=None, edge_labels=False,
subgraph_clusters=[], **options)
Return a representation in the 𝑑𝑜𝑡 language.
The 𝑑𝑜𝑡 language is a text based format for graphs. It is used by the software suite 𝑔𝑟𝑎𝑝ℎ𝑣𝑖𝑧. The
specifications of the language are available on the web (see the reference [dotspec]).
INPUT:
• labels – “string” or “latex” (default: “string”). If labels is string latex command are not interpreted.
This option stands for both vertex labels and edge labels.
• vertex_labels – boolean (default: True) whether to add the labels on vertices.
• edge_labels – boolean (default: False) whether to add the labels on edges.
• edge_color – (default: None) specify a default color for the edges. The color could be one of
– a name given as a string such as "blue" or "orchid"
– a HSV sequence in a string such as ".52,.386,.22"
– an hexadecimal code such as "#DA3305"
– a 3-tuple of floating point (to be interpreted as RGB tuple). In this case the 3-tuple is converted
in hexadecimal code.
• edge_colors – (default: None) a dictionary whose keys are colors and values are list of edges.
The list of edges need not to be complete in which case the default color is used. See the option
edge_color for a description of valid color formats.
• color_by_label – (default: False) a boolean or dictionary or function 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. See the option edge_color for a description of valid color
formats.
• edge_options – a function (or tuple thereof) mapping edges to a dictionary of options for this
edge.
• rankdir – ‘left’, ‘right’, ‘up’, or ‘down’ (default: ‘down’, for consistency with 𝑔𝑟𝑎𝑝ℎ𝑣𝑖𝑧): the
preferred ranking direction for acyclic layouts; see the 𝑟𝑎𝑛𝑘𝑑𝑖𝑟 option of 𝑔𝑟𝑎𝑝ℎ𝑣𝑖𝑧.
• subgraph_clusters – (default: []) a list of lists of vertices, From [dotspec]: “If supported, the
layout engine will do the layout so that the nodes belonging to the cluster are drawn together, with

1.1. Generic graphs (common to directed/undirected) 87


Sage Reference Manual: Graph Theory, Release 8.4

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: G = Graph({0:{1:None,2:None}, 1:{0:None,2:None}, 2:{0:None,1:None,3:'foo


˓→'}, 3:{2:'foo'}},sparse=True)

sage: print(G.graphviz_string(edge_labels=True))
graph {
node_0 [label="0"];
node_1 [label="1"];
node_2 [label="2"];
node_3 [label="3"];

node_0 -- node_1;
node_0 -- node_2;
node_1 -- node_2;
node_2 -- node_3 [label="foo"];
}

A variant, with the labels in latex, for post-processing with dot2tex:

sage: print(G.graphviz_string(edge_labels=True,labels = "latex"))


graph {
node [shape="plaintext"];
node_0 [label=" ", texlbl="$0$"];
node_1 [label=" ", texlbl="$1$"];
node_2 [label=" ", texlbl="$2$"];
node_3 [label=" ", texlbl="$3$"];

node_0 -- node_1;
node_0 -- node_2;
node_1 -- node_2;
node_2 -- node_3 [label=" ", texlbl="$\text{\texttt{foo}}$"];
}

Same, with a digraph and a color for edges:

sage: G = DiGraph({0:{1:None,2:None}, 1:{2:None}, 2:{3:'foo'}, 3:{}} ,


˓→sparse=True)

sage: print(G.graphviz_string(edge_color="red"))
digraph {
node_0 [label="0"];
node_1 [label="1"];
node_2 [label="2"];
node_3 [label="3"];

edge [color="red"];
node_0 -> node_1;
node_0 -> node_2;
node_1 -> node_2;
node_2 -> node_3;
}

A digraph using latex labels for vertices and edges:

88 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

sage: f(x) = -1/x


sage: g(x) = 1/(x+1)
sage: G = DiGraph()
sage: G.add_edges([(i,f(i),f) for i in (1,2,1/2,1/4)])
sage: G.add_edges([(i,g(i),g) for i in (1,2,1/2,1/4)])
sage: print(G.graphviz_string(labels="latex",edge_labels=True)) # random
digraph {
node [shape="plaintext"];
node_10 [label=" ", texlbl="$1$"];
node_11 [label=" ", texlbl="$2$"];
node_3 [label=" ", texlbl="$-\frac{1}{2}$"];
node_6 [label=" ", texlbl="$\frac{1}{2}$"];
node_7 [label=" ", texlbl="$\frac{1}{2}$"];
node_5 [label=" ", texlbl="$\frac{1}{3}$"];
node_8 [label=" ", texlbl="$\frac{2}{3}$"];
node_4 [label=" ", texlbl="$\frac{1}{4}$"];
node_1 [label=" ", texlbl="$-2$"];
node_9 [label=" ", texlbl="$\frac{4}{5}$"];
node_0 [label=" ", texlbl="$-4$"];
node_2 [label=" ", texlbl="$-1$"];

node_10 -> node_2 [label=" ", texlbl="$x \ {\mapsto}\ -\frac{1}{x}$"];


node_10 -> node_6 [label=" ", texlbl="$x \ {\mapsto}\ \frac{1}{x + 1}$"];
node_11 -> node_3 [label=" ", texlbl="$x \ {\mapsto}\ -\frac{1}{x}$"];
node_11 -> node_5 [label=" ", texlbl="$x \ {\mapsto}\ \frac{1}{x + 1}$"];
node_7 -> node_1 [label=" ", texlbl="$x \ {\mapsto}\ -\frac{1}{x}$"];
node_7 -> node_8 [label=" ", texlbl="$x \ {\mapsto}\ \frac{1}{x + 1}$"];
node_4 -> node_0 [label=" ", texlbl="$x \ {\mapsto}\ -\frac{1}{x}$"];
node_4 -> node_9 [label=" ", texlbl="$x \ {\mapsto}\ \frac{1}{x + 1}$"];
}

sage: print(G.graphviz_string(labels="latex",color_by_label=True)) # random


digraph {
node [shape="plaintext"];
node_10 [label=" ", texlbl="$1$"];
node_11 [label=" ", texlbl="$2$"];
node_3 [label=" ", texlbl="$-\frac{1}{2}$"];
node_6 [label=" ", texlbl="$\frac{1}{2}$"];
node_7 [label=" ", texlbl="$\frac{1}{2}$"];
node_5 [label=" ", texlbl="$\frac{1}{3}$"];
node_8 [label=" ", texlbl="$\frac{2}{3}$"];
node_4 [label=" ", texlbl="$\frac{1}{4}$"];
node_1 [label=" ", texlbl="$-2$"];
node_9 [label=" ", texlbl="$\frac{4}{5}$"];
node_0 [label=" ", texlbl="$-4$"];
node_2 [label=" ", texlbl="$-1$"];

node_10 -> node_2 [color = "#ff0000"];


node_10 -> node_6 [color = "#00ffff"];
node_11 -> node_3 [color = "#ff0000"];
node_11 -> node_5 [color = "#00ffff"];
node_7 -> node_1 [color = "#ff0000"];
node_7 -> node_8 [color = "#00ffff"];
node_4 -> node_0 [color = "#ff0000"];
node_4 -> node_9 [color = "#00ffff"];
}

(continues on next page)

1.1. Generic graphs (common to directed/undirected) 89


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: print(G.graphviz_string(labels="latex",color_by_label={ f: "red", g:
˓→"blue" })) # random
digraph {
node [shape="plaintext"];
node_10 [label=" ", texlbl="$1$"];
node_11 [label=" ", texlbl="$2$"];
node_3 [label=" ", texlbl="$-\frac{1}{2}$"];
node_6 [label=" ", texlbl="$\frac{1}{2}$"];
node_7 [label=" ", texlbl="$\frac{1}{2}$"];
node_5 [label=" ", texlbl="$\frac{1}{3}$"];
node_8 [label=" ", texlbl="$\frac{2}{3}$"];
node_4 [label=" ", texlbl="$\frac{1}{4}$"];
node_1 [label=" ", texlbl="$-2$"];
node_9 [label=" ", texlbl="$\frac{4}{5}$"];
node_0 [label=" ", texlbl="$-4$"];
node_2 [label=" ", texlbl="$-1$"];

node_10 -> node_2 [color = "red"];


node_10 -> node_6 [color = "blue"];
node_11 -> node_3 [color = "red"];
node_11 -> node_5 [color = "blue"];
node_7 -> node_1 [color = "red"];
node_7 -> node_8 [color = "blue"];
node_4 -> node_0 [color = "red"];
node_4 -> node_9 [color = "blue"];
}

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"];

node_0 -> node_1;


}
sage: print(D.graphviz_string(rankdir="down"))
digraph {
node_0 [label="1"];
node_1 [label="2"];

node_0 -> node_1;


}
sage: print(D.graphviz_string(rankdir="left"))
digraph {
rankdir=RL
node_0 [label="1"];
node_1 [label="2"];

node_0 -> node_1;


}
sage: print(D.graphviz_string(rankdir="right"))
digraph {
(continues on next page)

90 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


rankdir=LR
node_0 [label="1"];
node_1 [label="2"];

node_0 -> node_1;


}

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):

sage: def edge_options(data):


....: u, v, label = data
....: return { "backward": u == 1 }
sage: print(G.graphviz_string(edge_options = edge_options)) # random
digraph {
node_10 [label="1"];
node_11 [label="2"];
node_3 [label="-1/2"];
node_6 [label="1/2"];
node_7 [label="1/2"];
node_5 [label="1/3"];
node_8 [label="2/3"];
node_4 [label="1/4"];
node_1 [label="-2"];
node_9 [label="4/5"];
node_0 [label="-4"];
node_2 [label="-1"];

node_2 -> node_10 [dir=back];


node_6 -> node_10 [dir=back];
node_11 -> node_3;
node_11 -> node_5;
node_7 -> node_1;
node_7 -> node_8;
node_4 -> node_0;
node_4 -> node_9;
}

We now test all options:

sage: def edge_options(data):


....: u, v, label = data
....: options = { "color": { f: "red", g: "blue" }[label] }
....: if (u,v) == (1/2, -2): options["label"] = "coucou"; options[
˓→"label_style"] = "string"

....: if (u,v) == (1/2,2/3): options["dot"] = "x=1,y=2"


....: if (u,v) == (1, -1): options["label_style"] = "latex"
....: if (u,v) == (1, 1/2): options["edge_string"] = "<-"
....: if (u,v) == (1/2, 1): options["backward"] = True
....: return options
sage: print(G.graphviz_string(edge_options = edge_options)) # random
digraph {
node_10 [label="1"];
(continues on next page)

1.1. Generic graphs (common to directed/undirected) 91


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


node_11 [label="2"];
node_3 [label="-1/2"];
node_6 [label="1/2"];
node_7 [label="1/2"];
node_5 [label="1/3"];
node_8 [label="2/3"];
node_4 [label="1/4"];
node_1 [label="-2"];
node_9 [label="4/5"];
node_0 [label="-4"];
node_2 [label="-1"];

node_10 -> node_2 [label=" ", texlbl="$x \ {\mapsto}\ -\frac{1}{x}$", color


˓→ = "red"];
node_10 <- node_6 [color = "blue"];
node_11 -> node_3 [color = "red"];
node_11 -> node_5 [color = "blue"];
node_7 -> node_1 [label="coucou", color = "red"];
node_7 -> node_8 [x=1,y=2, color = "blue"];
node_4 -> node_0 [color = "red"];
node_4 -> node_9 [color = "blue"];
}

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:

sage: G = Graph({0:{1:None,2:None}, 1:{0:None,2:None}, 2:{0:None,1:None,3:'foo


˓→'}, 3:{2:'foo'}},sparse=True)

sage: tempfile = os.path.join(SAGE_TMP, 'temp_graphviz')


sage: G.graphviz_to_file_named(tempfile, edge_labels=True)
sage: print(open(tempfile).read())
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"];
}

hamiltonian_cycle(algorithm=’tsp’, solver=None, constraint_generation=None, verbose=0, ver-


bose_constraints=False)
Return a Hamiltonian cycle/circuit of the current graph/digraph.

92 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

The Petersen Graph, though, is not

sage: g = graphs.PetersenGraph()
sage: g.hamiltonian_cycle()
Traceback (most recent call last):
(continues on next page)

1.1. Generic graphs (common to directed/undirected) 93


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


...
EmptySetError: The given graph is not Hamiltonian

Now, using the backtrack algorithm in the Heawood graph

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])

And now in the Petersen graph

sage: G=graphs.PetersenGraph()
sage: G.hamiltonian_cycle(algorithm='backtrack')
(False, [6, 8, 5, 0, 1, 2, 7, 9, 4, 3])

Finally, we test the algorithm in a cube graph, which is Hamiltonian

sage: G=graphs.CubeGraph(3)
sage: G.hamiltonian_cycle(algorithm='backtrack')
(True, ['010', '110', '100', '000', '001', '101', '111', '011'])

hamiltonian_path(s=None, t=None, use_edge_labels=False, maximize=False, algorithm=’MILP’,


solver=None, verbose=0)
Return a Hamiltonian path of the current graph/digraph.
A path is Hamiltonian if it goes through all the vertices exactly once. Computing a Hamiltonian path being
NP-Complete, this algorithm could run for some time depending on the instance.
When use_edge_labels == True, this method returns either a minimum weight hamiltonian path
or a maximum weight Hamiltonian path (if maximize == True).
See also:

• 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.

94 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

• 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_edge(u, v=None, label=None)


Returns True if (u, v) is an edge, False otherwise.
INPUT: The following forms are accepted by NetworkX:
• G.has_edge( 1, 2 )
• G.has_edge( (1, 2) )
• G.has_edge( 1, 2, ‘label’ )
• G.has_edge( (1, 2, ‘label’) )
EXAMPLES:
sage: graphs.EmptyGraph().has_edge(9,2)
False
sage: DiGraph().has_edge(9,2)
False
sage: G = Graph(sparse=True)
sage: G.add_edge(0,1,"label")
sage: G.has_edge(0,1,"different label")
False
sage: G.has_edge(0,1,"label")
True

has_loops()
Return whether there are loops in the (di)graph
EXAMPLES:
sage: G = Graph(loops=True); G
Looped graph on 0 vertices
sage: G.has_loops()
(continues on next page)

1.1. Generic graphs (common to directed/undirected) 95


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


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
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)

96 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


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)]

sage: G = DiGraph({1:{2: 'h'}, 2:{1:'g'}},sparse=True)


sage: G.has_multiple_edges()
False
sage: G.has_multiple_edges(to_undirected=True)
True
sage: G.multiple_edges()
[]
sage: G.multiple_edges(to_undirected=True)
[(1, 2, 'h'), (2, 1, 'g')]

A loop is not a multiedge:

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:

sage: g = Graph({0:[1,2,3], 2:[4]}); g


Graph on 5 vertices
sage: 2 in g
True
sage: 10 in g
False
(continues on next page)

1.1. Generic graphs (common to directed/undirected) 97


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: graphs.PetersenGraph().has_vertex(99)
False

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 = graphs.TetrahedralGraph() # optional - python_igraph


sage: H = G.igraph_graph() # optional - python_igraph
sage: H.summary() # optional - python_igraph
'IGRAPH U--- 4 6 -- '
sage: G = digraphs.Path(3) # optional - python_igraph
sage: H = G.igraph_graph() # optional - python_igraph
sage: H.summary() # optional - python_igraph
'IGRAPH D--- 3 2 -- '

Adding edge attributes:

sage: G = Graph([(1,2,'a'),(2,3,'b')]) #
˓→optional - python_igraph

sage: H = G.igraph_graph(edge_attrs = {'label':[e[2] for e in G.edges()]}) #


˓→optional - python_igraph

sage: H.es['label'] #
˓→optional - python_igraph

['a', 'b']

If edges have an attribute weight, the igraph graph is considered weighted:

98 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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]

Adding vertex attributes:

sage: G = graphs.GridGraph([2,2]) # optional -


˓→python_igraph

sage: H = G.igraph_graph(vertex_attrs={'name':G.vertices()}) # optional -


˓→python_igraph

sage: H.vs()['name'] # optional -


˓→python_igraph

[(0, 0), (0, 1), (1, 0), (1, 1)]

Sometimes, Sage integer/floats are not compatible with igraph:

sage: G = Graph([(0,1,2)])
˓→# optional - python_igraph

sage: H = G.igraph_graph(edge_attrs = {'capacity':[e[2] for e in G.edges()]})


˓→# optional - python_igraph

sage: H.maxflow_value(0, 1, 'capacity')


˓→# optional - python_igraph

1.0
sage: H = G.igraph_graph(edge_attrs = {'capacity':[float(e[2]) for e in G.
˓→edges()]}) # optional - python_igraph

sage: H.maxflow_value(0, 1, 'capacity')


˓→ # optional - python_igraph
2.0

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.

1.1. Generic graphs (common to directed/undirected) 99


Sage Reference Manual: Graph Theory, Release 8.4

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: G = digraphs.Circulant(4, [1,3])


sage: G.incidence_matrix()
[-1 -1 1 0 0 0 1 0]
[ 1 0 -1 -1 1 0 0 0]
[ 0 0 0 1 -1 -1 0 1]
[ 0 1 0 0 0 1 -1 -1]

sage: graphs.CompleteGraph(3).incidence_matrix()
[1 1 0]
[1 0 1]
[0 1 1]
sage: G = Graph([(0,0),(0,1),(0,1)], loops=True, multiedges=True)
sage: G.incidence_matrix(oriented=False)
[2 1 1]
[0 1 1]

A well known result states that the product of the (oriented) incidence matrix with its transpose of a (non-
oriented graph) is in fact the Kirchhoff matrix:

sage: G = graphs.PetersenGraph()
sage: m = G.incidence_matrix(oriented=True)
sage: m * m.transpose() == G.kirchhoff_matrix()
True

sage: K = graphs.CompleteGraph(3)
sage: m = K.incidence_matrix(oriented=True)
sage: m * m.transpose() == K.kirchhoff_matrix()
True

sage: H = Graph([(0,0),(0,1),(0,1)], loops=True, multiedges=True)


sage: m = H.incidence_matrix(oriented=True)
sage: m * m.transpose() == H.kirchhoff_matrix()
True

is_bipartite(certificate=False)
Returns True if graph 𝐺 is bipartite, False if not.

100 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

Traverse the graph G with breadth-first-search and color nodes.


INPUT:
• certificate – whether to return a certificate (False by default). If set to True, the certificate
returned in a proper 2-coloring when 𝐺 is bipartite, and an odd cycle otherwise.
EXAMPLES:

sage: graphs.CycleGraph(4).is_bipartite()
True
sage: graphs.CycleGraph(5).is_bipartite()
False
sage: graphs.RandomBipartite(100,100,0.7).is_bipartite()
True

A random graph is very rarely bipartite:

sage: g = graphs.PetersenGraph()
sage: g.is_bipartite()
False
sage: false, oddcycle = g.is_bipartite(certificate = True)
sage: len(oddcycle) % 2
1

The method works identically with oriented graphs:

sage: g = DiGraph({0: [1, 2, 3], 2: [1], 3: [4]})


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

is_cayley(return_group=False, mapping=False, generators=False, allow_disconnected=False)


Check whether the graph is a Cayley graph.
If none of the parameters are True, return a boolean indicating whether the graph is a Cayley graph.
Otherwise, return a tuple containing said boolean and the requested data. If the graph is not a Cayley
graph, each of the data will be None.
The empty graph is defined to be not a Cayley graph.

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.

1.1. Generic graphs (common to directed/undirected) 101


Sage Reference Manual: Graph Theory, Release 8.4

• allow_disconnected (boolean; False) – If True, disconnected graphs are considered Cayley


if they can be obtained from the Cayley construction with a generating set that does not generate the
group.
ALGORITHM:
For connected graphs, find a regular subgroup of the automorphism group. For disconnected graphs, check
that the graph is vertex-transitive and perform the check on one of its connected components. If a simple
graph has density over 1/2, perform the check on its complement as its disconnectedness may increase
performance.
EXAMPLES:
A Petersen Graph is not a Cayley graph:

sage: g = graphs.PetersenGraph()
sage: g.is_cayley()
False

A Cayley digraph is a Cayley graph:

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:

sage: g = Graph(graphs.PaleyGraph(9), loops=True, multiedges=True)


sage: g.add_edges([(u, u) for u in g])
sage: g.add_edges([(u, u+1) for u in g])
sage: _, S = g.is_cayley(generators=True)
sage: S # random
[(),
(0,2,1)(a,a + 2,a + 1)(2*a,2*a + 2,2*a + 1),
(0,2,1)(a,a + 2,a + 1)(2*a,2*a + 2,2*a + 1),
(0,1,2)(a,a + 1,a + 2)(2*a,2*a + 1,2*a + 2),
(0,1,2)(a,a + 1,a + 2)(2*a,2*a + 1,2*a + 2),
(0,2*a + 2,a + 1)(1,2*a,a + 2)(2,2*a + 1,a),
(0,a + 1,2*a + 2)(1,a + 2,2*a)(2,a,2*a + 1)]

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.

102 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

The disjoint union of chordal graphs is still chordal:


sage: (2*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)

Of course, the Petersen Graph is not chordal as it has girth 5


sage: g = graphs.PetersenGraph()
sage: g.girth()
5
sage: g.is_chordal()
False

1.1. Generic graphs (common to directed/undirected) 103


Sage Reference Manual: Graph Theory, Release 8.4

We can even obtain such a cycle as a certificate


sage: (_, hole) = g.is_chordal(certificate = True)
sage: hole
Subgraph of (Petersen graph): Graph on 5 vertices
sage: hole.is_isomorphic(graphs.CycleGraph(5))
True

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])])

The same goes for directed graphs:


sage: g = digraphs.Circuit(5)
sage: g.is_circulant(certificate = True)
(True, [(5, [1]), (5, [3]), (5, [2]), (5, [4])])

With this information, it is very easy to create (and plot) all possible drawings of a circulant graph:
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

104 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

is_circular_planar(on_embedding=None, kuratowski=False, set_embedding=True, bound-


ary=None, ordered=False, set_pos=False)
Tests whether the graph is circular planar (outerplanar)
A graph is circular planar if it has a planar embedding in which all vertices can be drawn in order on a
circle. This method can also be used to check the existence of a planar embedding in which the vertices of
a specific set (the boundary) can be drawn on a circle, all other vertices being drawn inside of the circle.
An order can be defined on the vertices of the boundary in order to define how they are to appear on the
circle.
INPUT:
• kuratowski (boolean) - if set to True, returns a tuple with boolean first entry and the Kuratowski
subgraph (i.e. an edge subdivision of 𝐾5 or 𝐾3,3 ) as the second entry (see OUTPUT below). It is set
to False by default.
• on_embedding (boolean) - the embedding dictionary to test planarity on. (i.e.: will return True
or False only for the given embedding). It is set to False by default.
• set_embedding (boolean) - whether or not to set the instance field variable that contains a combi-
natorial embedding (clockwise ordering of neighbors at each vertex). This value will only be set if a
circular 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. It is set to True by default.
• boundary - a set of vertices that are required to be drawn on the circle, all others being drawn inside
of it. It is set to None by default, meaning that all vertices should be drawn on the boundary.
• ordered (boolean) - whether or not to consider the order of the boundary. It is set to False by
default, and required boundary to be defined.
• 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 circular planar embedding is found.
OUTPUT:
The method returns True if the graph is circular planar, and False if it is not.
If kuratowski is set to True, then this function will return a tuple, whose first entry is a boolean and
whose second entry is the Kuratowski subgraph (i.e. an edge subdivision of 𝐾5 or 𝐾3,3 ) isolated by the
Boyer-Myrvold algorithm. Note that this graph might contain a vertex or edges that were not in the initial
graph. These would be elements referred to below as parts of the wheel and the star, which were added
to the graph to require that the boundary can be drawn on the boundary of a disc, with all other vertices
drawn inside (and no edge crossings).
ALGORITHM:
This is a linear time algorithm to test for circular planarity. It relies on the edge-addition planarity algorithm
due to Boyer-Myrvold. We accomplish linear time for circular planarity by modifying the graph before
running the general planarity algorithm.
REFERENCE:
EXAMPLES:
sage: g439 = Graph({1:[5,7], 2:[5,6], 3:[6,7], 4:[5,6,7]})
sage: g439.show()
sage: g439.is_circular_planar(boundary = [1,2,3,4])
False
sage: g439.is_circular_planar(kuratowski=True, boundary = [1,2,3,4])
(False, Graph on 8 vertices)
sage: g439.is_circular_planar(kuratowski=True, boundary = [1,2,3])
(continues on next page)

1.1. Generic graphs (common to directed/undirected) 105


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


(True, None)
sage: g439.get_embedding()
{1: [7, 5],
2: [5, 6],
3: [6, 7],
4: [7, 6, 5],
5: [1, 4, 2],
6: [2, 4, 3],
7: [3, 4, 1]}

Order matters:

sage: K23 = graphs.CompleteBipartiteGraph(2,3)


sage: K23.is_circular_planar(boundary = [0,1,2,3])
True
sage: K23.is_circular_planar(ordered=True, boundary = [0,1,2,3])
False

With a different order:

sage: K23.is_circular_planar(set_embedding=True, boundary = [0,2,1,3])


True

is_clique(vertices=None, directed_clique=False, induced=True, loops=False)


Tests whether a set of vertices is a clique
A clique is a set of vertices such that there is exactly one 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.
• directed_clique – (default: False) If set to False, only consider the underlying undirected
graph. If set to True and the graph is directed, only return True if all possible edges in _both_
directions exist.
• induced – (default: True) If set to True, check that the graph has exactly one edge between any
two vertices. If set to False, check that the graph has at least one edge between any two vertices.
• loops – (default: False) If set to True, check that each vertex of the graph has a loop, and exactly
one if furthermore induced == True. If set to False, check that the graph has no loop when
induced == True, and ignore loops otherwise.
EXAMPLES:

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)

106 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: i = graphs.CompleteGraph(4).to_directed()
sage: i.delete_edge([0,1])
sage: i.is_clique(directed_clique=False, induced=True)
False
sage: i.is_clique(directed_clique=False, induced=False)
True
sage: i.is_clique(directed_clique=True)
False

is_connected(G)
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

is_cut_edge(G, u, v=None, label=None)


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:

1.1. Generic graphs (common to directed/undirected) 107


Sage Reference Manual: Graph Theory, Release 8.4

• Returns True if (u,v) is a cut edge, False otherwise


EXAMPLES:

sage: from sage.graphs.connectivity import is_cut_edge


sage: G = graphs.CompleteGraph(4)
sage: is_cut_edge(G,0,2)
False
sage: G.is_cut_edge(0,2)
False

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 = Graph([[0,1],[0,2],[1,1]], loops = True)


sage: is_cut_edge(G,(1,1))
False

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: from sage.graphs.connectivity import is_cut_vertex


sage: G = graphs.LollipopGraph(4,2)
sage: is_cut_vertex(G,0)
(continues on next page)

108 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


False
sage: is_cut_vertex(G,3)
True
sage: G.is_cut_vertex(3)
True

Comparing the weak and strong connectivity of a digraph:

sage: from sage.graphs.connectivity import is_strongly_connected


sage: D = digraphs.Circuit(6)
sage: is_strongly_connected(D)
True
sage: is_cut_vertex(D,2)
True
sage: is_cut_vertex(D, 2, weak=True)
False

Giving a vertex that is not in the graph:

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)

1.1. Generic graphs (common to directed/undirected) 109


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


False
sage: Graph().is_cycle()
False
sage: G = Graph(); G.allow_loops(True); G.add_edge(0,0)
sage: G.is_cycle()
True
sage: digraphs.Circuit(3).is_cycle()
True
sage: digraphs.Circuit(2).is_cycle()
True
sage: digraphs.Circuit(2).is_cycle(directed_cycle = False)
True
sage: D = DiGraph( graphs.CycleGraph(3) )
sage: D.is_cycle()
False
sage: D.is_cycle(directed_cycle = False)
False
sage: D.edges(labels = False)
[(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]

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)

110 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


[1 2 0]
[1 0 2]
[0 2 1]

sage: ss = (graphs.WheelGraph(6)).line_graph(labels=False)
sage: prt = [[(0, 1)], [(0, 2), (0, 3), (0, 4), (1, 2), (1, 4)], [(2, 3), (3,
˓→4)]]

sage: ss.is_equitable(prt)
Traceback (most recent call last):
...
TypeError: Partition ([[(0, 1)], [(0, 2), (0, 3), (0, 4), (1, 2), (1, 4)],
˓→[(2, 3), (3, 4)]]) is not valid for this graph: vertices are incorrect.

sage: ss = (graphs.WheelGraph(5)).line_graph(labels=False)
sage: ss.is_equitable(prt)
False

is_eulerian(path=False)
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

sage: g = DiGraph({0: [1]}); g.is_eulerian(path=True)


(1, 0)
sage: graphs.CycleGraph(4).is_eulerian(path=True)
False
sage: g = DiGraph({0: [1], 1: [2,3], 2: [4]}); g.is_eulerian(path=True)
False

1.1. Generic graphs (common to directed/undirected) 111


Sage Reference Manual: Graph Theory, Release 8.4

sage: g = Graph({0:[1,2,3], 1:[2,3], 2:[3,4], 3:[4]}, multiedges=True)


sage: g.is_eulerian()
False
sage: e = g.is_eulerian(path=True); e
(0, 1)
sage: g.add_edge(e)
sage: g.is_eulerian(path=False)
True
sage: g.is_eulerian(path=True)
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

The Petersen Graph is not:


sage: g = graphs.PetersenGraph()
sage: g.is_gallai_tree()
False

A Graph built from vertex-disjoint complete graphs linked by one edge to a special vertex −1 is a ‘’star-
shaped” Gallai tree
sage: g = 8 * graphs.CompleteGraph(6)
sage: g.add_edges([(-1,c[0]) for c in g.connected_components()])
sage: g.is_gallai_tree()
True

is_hamiltonian(solver=None, constraint_generation=None, verbose=0, ver-


bose_constraints=False)
Test whether the current graph is Hamiltonian.
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.
Testing for Hamiltonicity being NP-Complete, this algorithm could run for some time depending on the
instance.
ALGORITHM:
See traveling_salesman_problem().
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.

112 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

• constraint_generation (boolean) – whether to use constraint generation when solving the


Mixed Integer Linear Program. When constraint_generation = None, constraint genera-
tion 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:
Returns True if a Hamiltonian cycle/circuit exists, and False otherwise.
NOTE:
This function, as hamiltonian_cycle and traveling_salesman_problem, computes a
Hamiltonian cycle if it exists: the user should NOT test for Hamiltonicity using is_hamiltonian
before calling hamiltonian_cycle or traveling_salesman_problem as it would result in
computing it twice.
EXAMPLES:
The Heawood Graph is known to be Hamiltonian

sage: g = graphs.HeawoodGraph()
sage: g.is_hamiltonian()
True

The Petergraph, though, is not

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.

1.1. Generic graphs (common to directed/undirected) 113


Sage Reference Manual: Graph Theory, Release 8.4

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 = Graph({1: [2, 3, 4], 4: [2, 3]})


sage: g.is_interval()
True
sage: g.is_interval(certificate=True)
(True, {1: (0, 5), 2: (4, 6), 3: (1, 3), 4: (2, 7)})

The Petersen Graph is not chordal, so it can’t be an interval graph:

sage: g = graphs.PetersenGraph()
sage: g.is_interval()
False

A chordal but still not an interval graph:

sage: g = Graph({1: [4, 2, 3], 2: [3, 5], 3: [6]})


sage: g.is_interval()
False

See also:

• Interval Graph Recognition.


• PQ – Implementation of PQ-Trees.
• is_chordal()
• IntervalGraph()
• RandomIntervalGraph()

is_isomorphic(other, certificate=False, verbosity=0, edge_labels=False)


Tests for isomorphism between self and other.
INPUT:
• certificate - if True, then output is (𝑎, 𝑏), where 𝑎 is a boolean and 𝑏 is either a map or None.
• edge_labels - default False, otherwise allows only permutations respecting edge labels.
OUTPUT:

114 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

• either a boolean or, if certificate is True, a tuple consisting of a boolean and a map or None
EXAMPLES:
Graphs:

sage: from sage.groups.perm_gps.permgroup_named import SymmetricGroup


sage: D = graphs.DodecahedralGraph()
sage: E = copy(D)
sage: gamma = SymmetricGroup(20).random_element()
sage: E.relabel(gamma)
sage: D.is_isomorphic(E)
True

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: A = DiGraph( { 0 : [1,2] } )


sage: B = DiGraph( { 1 : [0,2] } )
sage: A.is_isomorphic(B, certificate=True)
(True, {0: 1, 1: 0, 2: 2})

Edge labeled graphs:

1.1. Generic graphs (common to directed/undirected) 115


Sage Reference Manual: Graph Theory, Release 8.4

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

Edge labeled digraphs:

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})

is_planar(on_embedding=None, kuratowski=False, set_embedding=False, set_pos=False)


Test whether the graph is planar.
This wraps the reference implementation provided by John Boyer of the linear time planarity algorithm by
edge addition due to Boyer Myrvold. (See reference code in planarity).

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:

• “Almost planar graph”: is_apex()


• “Measuring non-planarity”: genus(), crossing_number()
• planar_dual()
• faces()
• is_polyhedral()

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:

116 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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: k43 = graphs.CompleteBipartiteGraph(4,3)


sage: result = k43.is_planar(kuratowski=True); result
(False, Graph on 6 vertices)
sage: result[1].is_isomorphic(graphs.CompleteBipartiteGraph(3,3))
True

Multi-edged and looped graphs are partially supported:


sage: G = Graph({0:[1,1]}, multiedges=True)
sage: G.is_planar()
True
sage: G.is_planar(on_embedding={})
Traceback (most recent call last):
...
NotImplementedError: Cannot compute with embeddings of multiple-edged or
˓→looped graphs.

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)

1.1. Generic graphs (common to directed/undirected) 117


Sage Reference Manual: Graph Theory, Release 8.4

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

The house graph is not regular:

sage: graphs.HouseGraph().is_regular()
False

A graph without vertices is 𝑘-regular for every 𝑘:

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:

• Wikipedia article Self-complementary_graph


• OEIS sequence A000171 for the numbers of self-complementary graphs of order 𝑛
• OEIS sequence A003086 for the numbers of self-complementary digraphs of order 𝑛.

EXAMPLES:
The only self-complementary path graph is 𝑃4 :

118 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

sage: graphs.PathGraph(4).is_self_complementary()
True
sage: graphs.PathGraph(5).is_self_complementary()
False

The only self-complementary directed path is 𝑃2 :


sage: digraphs.Path(2).is_self_complementary()
True
sage: digraphs.Path(3).is_self_complementary()
False

Every Paley graph is self-complementary:


sage: G = graphs.PaleyGraph(9)
sage: G.is_self_complementary()
True

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)

1.1. Generic graphs (common to directed/undirected) 119


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: G.is_subgraph(H)
False
sage: G.is_subgraph(H, induced=False)
True
sage: H.is_subgraph(G, induced=False)
False

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

is_vertex_transitive(partition=None, verbosity=0, edge_labels=False, order=False, re-


turn_group=True, orbits=False)
Returns whether the automorphism group of self is transitive within the partition provided, by default the
unit partition of the vertices of self (thus by default tests for vertex transitivity in the usual sense).
EXAMPLES:

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

kirchhoff_matrix(weighted=None, indegree=True, normalized=False, **kwds)


Returns the Kirchhoff matrix (a.k.a. the Laplacian) of the graph.
The Kirchhoff matrix is defined to be 𝐷 − 𝑀 , where 𝐷 is the diagonal degree matrix (each diagonal entry
is the degree of the corresponding vertex), and 𝑀 is the adjacency matrix. If normalized is True, then
the returned matrix is 𝐷−1/2 (𝐷 − 𝑀 )𝐷−1/2 .
( In the special case of DiGraphs, 𝐷 is defined as the diagonal in-degree matrix or diagonal out-degree
matrix according to the value of indegree)
INPUT:
• weighted – Binary variable :

120 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

– 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)

1.1. Generic graphs (common to directed/undirected) 121


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


[ 0 1 -1]
[ 0 -1 1]

A weighted directed graph with loops, changing the variable indegree

sage: G = DiGraph({1:{1:2,2:3}, 2:{1:4}}, weighted=True,sparse=True)


sage: G.laplacian_matrix()
[ 4 -3]
[-4 3]

sage: G = DiGraph({1:{1:2,2:3}, 2:{1:4}}, weighted=True,sparse=True)


sage: G.laplacian_matrix(indegree=False)
[ 3 -3]
[-4 4]

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

laplacian_matrix(weighted=None, indegree=True, normalized=False, **kwds)


Returns the Kirchhoff matrix (a.k.a. the Laplacian) of the graph.
The Kirchhoff matrix is defined to be 𝐷 − 𝑀 , where 𝐷 is the diagonal degree matrix (each diagonal entry
is the degree of the corresponding vertex), and 𝑀 is the adjacency matrix. If normalized is True, then
the returned matrix is 𝐷−1/2 (𝐷 − 𝑀 )𝐷−1/2 .
( In the special case of DiGraphs, 𝐷 is defined as the diagonal in-degree matrix or diagonal out-degree
matrix according to the value of indegree)
INPUT:
• weighted – Binary variable :

122 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

– 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)

1.1. Generic graphs (common to directed/undirected) 123


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


[ 0 1 -1]
[ 0 -1 1]

A weighted directed graph with loops, changing the variable indegree

sage: G = DiGraph({1:{1:2,2:3}, 2:{1:4}}, weighted=True,sparse=True)


sage: G.laplacian_matrix()
[ 4 -3]
[-4 3]

sage: G = DiGraph({1:{1:2,2:3}, 2:{1:4}}, weighted=True,sparse=True)


sage: G.laplacian_matrix(indegree=False)
[ 3 -3]
[-4 4]

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'}

layout(layout=None, pos=None, dim=2, save_pos=False, **options)


Returns a layout for the vertices of this graph.
INPUT:
• layout – one of “acyclic”, “circular”, “ranked”, “graphviz”, “planar”, “spring”, or “tree”
• pos – a dictionary of positions or None (the default)
• save_pos – a boolean
• layout options – (see below)
If layout=algorithm is specified, this algorithm is used to compute the positions.
Otherwise, if pos is specified, use the given positions.
Otherwise, try to fetch previously computed and saved positions.
Otherwise use the default layout (usually the spring layout)
If save_pos = True, the layout is saved for later use.
EXAMPLES:

sage: g = digraphs.ButterflyGraph(1)
sage: g.layout()
{('0', 0): [2.69..., 0.43...],
('0', 1): [1.35..., 0.86...],
(continues on next page)

124 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


('1', 0): [0.89..., -0.42...],
('1', 1): [2.26..., -0.87...]}

sage: g.layout(layout="acyclic_dummy", save_pos=True)


{('0', 0): [0.3..., 0],
('0', 1): [0.3..., 1],
('1', 0): [0.6..., 0],
('1', 1): [0.6..., 1]}

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...]}

Here is the list of all the available layout options:

sage: from sage.graphs.graph_plot import layout_options


sage: for key, value in sorted(layout_options.items()):
....: print("option {} : {}".format(key, value))
option by_component : Whether to do the spring layout by connected component -
˓→- a boolean.

option dim : The dimension of the layout -- 2 or 3.


option heights : A dictionary mapping heights to the list of vertices at this
˓→height.

option iterations : The number of times to execute the spring layout


˓→algorithm.

option layout : A layout algorithm -- one of : "acyclic", "circular" (plots


˓→the graph with vertices evenly distributed on a circle), "ranked", "graphviz

˓→", "planar", "spring" (traditional 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).

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'.

option tree_root : A vertex designation for drawing trees. A vertex of the


˓→tree to be used as the root for the ``layout='tree'`` option. If no root is

˓→specified, then one is chosen close to the center of the tree. Ignored

˓→unless ``layout='tree'``

Some of them only apply to certain layout algorithms. For details, see layout_acyclic(),
layout_planar(), layout_circular(), layout_spring(), . . .

Warning: unknown optional arguments are silently ignored

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-

1.1. Generic graphs (common to directed/undirected) 125


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: G = graphs.CirculantGraph(7, [1, 3])


sage: G.layout_circular()
{0: (0.0, 1.0),
1: (-0.78..., 0.62...),
2: (-0.97..., -0.22...),
3: (-0.43..., -0.90...),
4: (0.43..., -0.90...),
5: (0.97..., -0.22...),
6: (0.78..., 0.62...)}
sage: G.plot(layout = "circular")
Graphics object consisting of 22 graphics primitives

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:

sage: g = graphs.LadderGraph(3) #TODO!!!!


sage: g.layout_spring()
{0: [0.73..., -0.29...],
1: [1.37..., 0.30...],
2: [2.08..., 0.89...],
3: [1.23..., -0.83...],
4: [1.88..., -0.30...],
5: [2.53..., 0.22...]}
sage: g = graphs.LadderGraph(7)
sage: g.plot(layout = "spring")
Graphics object consisting of 34 graphics primitives

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

126 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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)}

layout_graphviz(dim=2, prog=’dot’, **options)


Calls graphviz to compute a layout of the vertices of this graph.
INPUT:
• prog – one of “dot”, “neato”, “twopi”, “circo”, or “fdp”
EXAMPLES:

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

Note: the actual coordinates are not deterministic


By default, an acyclic layout is computed using graphviz’s dot layout program. One may specify an
alternative layout program:

sage: g.plot(layout = "graphviz", prog = "dot") # optional - dot2tex


˓→graphviz

Graphics object consisting of 29 graphics primitives


sage: g.plot(layout = "graphviz", prog = "neato") # optional - dot2tex
˓→graphviz

Graphics object consisting of 29 graphics primitives


sage: g.plot(layout = "graphviz", prog = "twopi") # optional - dot2tex
˓→graphviz

Graphics object consisting of 29 graphics primitives


sage: g.plot(layout = "graphviz", prog = "fdp") # optional - dot2tex
˓→graphviz

Graphics object consisting of 29 graphics primitives


sage: g = graphs.BalancedTree(5,2)
sage: g.plot(layout = "graphviz", prog = "circo") # optional - dot2tex
˓→graphviz

Graphics object consisting of 62 graphics primitives

1.1. Generic graphs (common to directed/undirected) 127


Sage Reference Manual: Graph Theory, Release 8.4

Todo: Put here some cool examples showcasing graphviz features.

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_planar(set_embedding=False, on_embedding=None, external_face=None, test=False, cir-


cular=False, **options)
Uses Schnyder’s algorithm to compute a planar layout for self, raising an error if self is not planar.
INPUT:
• set_embedding - if True, sets the combinatorial embedding used (see self.get_embedding())
• on_embedding - dict: provide a combinatorial embedding
• external_face - ignored
• test - if True, perform sanity tests along the way
• circular - ignored
EXAMPLES:
sage: g = graphs.PathGraph(10)
sage: g.set_planar_positions(test=True)
True
sage: g = graphs.BalancedTree(3,4)
sage: g.set_planar_positions(test=True)
True
sage: g = graphs.CycleGraph(7)
sage: g.set_planar_positions(test=True)
True
sage: g = graphs.CompleteGraph(5)
sage: g.set_planar_positions(test=True,set_embedding=True)
Traceback (most recent call last):
...
ValueError: Complete graph is not a planar graph

layout_ranked(heights=None, dim=2, spring=False, **options)


Computes a ranked layout for this graph
INPUT:
• heights – a dictionary mapping heights to the list of vertices at this height
OUTPUT: a dictionary mapping vertices to positions
Returns a layout computed by randomly arranging the vertices along the given heights
EXAMPLES:
sage: g = graphs.LadderGraph(3)
sage: g.layout_ranked(heights = dict( (i,[i, i+3]) for i in range(3) ))
{0: [0.668..., 0],
(continues on next page)

128 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


1: [0.667..., 1],
2: [0.677..., 2],
3: [1.34..., 0],
4: [1.33..., 1],
5: [1.33..., 2]}
sage: g = graphs.LadderGraph(7)
sage: g.plot(layout = "ranked", heights = dict( (i,[i, i+7]) for i in
˓→range(7) ))

Graphics object consisting of 34 graphics primitives

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.LadderGraph(3) #TODO!!!!


sage: g.layout_spring()
{0: [0.73..., -0.29...],
1: [1.37..., 0.30...],
2: [2.08..., 0.89...],
3: [1.23..., -0.83...],
4: [1.88..., -0.30...],
5: [2.53..., 0.22...]}
sage: g = graphs.LadderGraph(7)
sage: g.plot(layout = "spring")
Graphics object consisting of 34 graphics primitives

layout_tree(tree_orientation=’down’, tree_root=None, dim=2, **options)


Compute an ordered tree layout for this graph, which should be a tree (no non-oriented cycles).
INPUT:
• tree_root – the root vertex. By default None. In this case, a vertex is chosen close to the center
of the tree.
• tree_orientation – the direction in which the tree is growing, can be 'up', 'down', 'left'
or 'right' (default is 'down')
If the tree has been given a planar embedding (fixed circular order on the set of neighbors of every vertex)
using set_embedding, the algorithm will create a layout that respects this embedding.
OUTPUT: a dictionary mapping vertices to positions
EXAMPLES:

sage: T = graphs.RandomLobster(25, 0.3, 0.3)


sage: T.show(layout='tree', tree_orientation='up')

sage: G = graphs.HoffmanSingletonGraph()
sage: T = Graph()
(continues on next page)

1.1. Generic graphs (common to directed/undirected) 129


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: T.add_edges(G.min_spanning_tree(starting_vertex=0))
sage: T.show(layout='tree', tree_root=0)

sage: G = graphs.BalancedTree(2, 2)
sage: G.layout_tree(tree_root=0)
{0: (1.5, 0),
1: (2.5, -1),
2: (0.5, -1),
3: (3.0, -2),
4: (2.0, -2),
5: (1.0, -2),
6: (0.0, -2)}

sage: G = graphs.BalancedTree(2,4)
sage: G.plot(layout="tree", tree_root = 0, tree_orientation = "up")
Graphics object consisting of 62 graphics primitives

sage: G = graphs.RandomTree(80)
sage: G.plot(layout="tree", tree_orientation = "right")
Graphics object consisting of 160 graphics primitives

Using the embedding when it exists:

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

lex_BFS(reverse=False, tree=False, initial_vertex=None)


Performs a Lex BFS on the graph.
A Lex BFS ( or Lexicographic Breadth-First Search ) is a Breadth First Search used for the recognition of
Chordal Graphs. For more information, see the Wikipedia article Lexicographic_breadth-first_search.
INPUT:
• reverse (boolean) – whether to return the vertices in discovery order, or the reverse.
False by default.
• tree (boolean) – whether to return the discovery directed tree (each vertex being linked to the one
that saw it for the first time)
False by default.
• initial_vertex – the first vertex to consider.
None by default.

130 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

For a Chordal Graph, a reversed Lex BFS is a Perfect Elimination Order

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

1.1. Generic graphs (common to directed/undirected) 131


Sage Reference Manual: Graph Theory, Release 8.4

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:

• The line_graph module.


• line_graph_forbidden_subgraphs() – the forbidden subgraphs of a line graph.
• is_line_graph() – tests whether a graph is a line graph.

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)

132 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


(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),
((1, 3, None), (3, 4, None), None),
((2, 3, None), (3, 4, None), None)]

longest_path(s=None, t=None, use_edge_labels=False, algorithm=’MILP’, solver=None, ver-


bose=0)
Return a longest path of self.
INPUT:
• s (vertex) – forces the source of the path (the method then returns the longest path starting at s). The
argument is set to None by default, which means that no constraint is set upon the first vertex in the
path.
• t (vertex) – forces the destination of the path (the method then returns the longest path ending at t).
The argument is set to None by default, which means that no constraint is set upon the last vertex in
the path.
• use_edge_labels (boolean) – whether the labels on the edges are to be considered as weights (a
label set to None or {} being considered as a weight of 1). Set to False by default.
• 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.
– As the backtrack algorithm does not support edge weighting, 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 of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0). Sets the level of verbosity. Set to 0 by default, which means quiet.

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

1.1. Generic graphs (common to directed/undirected) 133


Sage Reference Manual: Graph Theory, Release 8.4

The heuristic totally agrees:

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:

sage: for i in range(20):


....: g = graphs.RandomGNP(15, 0.3)
....: for u, v in g.edges(labels=False):
....: g.set_edge_label(u, v, random())
....: lp = g.longest_path()
....: if (not lp.is_forest() or
....: not max(lp.degree()) <= 2 or
....: not lp.is_connected()):
....: print("Error!")
....: break

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))

134 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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()
[]

sage: D = DiGraph(4, loops=True)


sage: D.add_edges( [ (0,0), (1,1), (2,2), (3,3), (2,3) ] )
sage: D.loop_edges()
[(0, 0, None), (1, 1, None), (2, 2, None), (3, 3, None)]

sage: G = Graph(4, loops=True, multiedges=True, sparse=True)


sage: G.add_edges([(i,i) for i in range(4)])
sage: G.loop_edges()
[(0, 0, None), (1, 1, None), (2, 2, None), (3, 3, None)]
sage: G.add_edges([(0, 0), (1, 1)])
(continues on next page)

1.1. Generic graphs (common to directed/undirected) 135


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: G.loop_edges(labels=False)
[(0, 0), (0, 0), (1, 1), (1, 1), (2, 2), (3, 3)]

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)

136 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


False
sage: D.edges()
[]

sage: G = graphs.PetersenGraph()
sage: G.loops()
[]

sage: D = DiGraph(4, loops=True)


sage: D.add_edges( [ (0,0), (1,1), (2,2), (3,3), (2,3) ] )
sage: D.loop_edges()
[(0, 0, None), (1, 1, None), (2, 2, None), (3, 3, None)]

sage: G = Graph(4, loops=True, multiedges=True, sparse=True)


sage: G.add_edges([(i,i) for i in range(4)])
sage: G.loop_edges()
[(0, 0, None), (1, 1, None), (2, 2, None), (3, 3, None)]
sage: G.add_edges([(0, 0), (1, 1)])
sage: G.loop_edges(labels=False)
[(0, 0), (0, 0), (1, 1), (1, 1), (2, 2), (3, 3)]

max_cut(value_only=True, use_edge_labels=False, vertices=False, solver=None, verbose=0)


Return a maximum edge cut of the graph.
For more information, see the Wikipedia article Maximum_cut.
INPUT:
• value_only – boolean (default: True)
– When set to True (default), only the value is returned.
– When set to False, both the value and a maximum edge cut are returned.
• use_edge_labels – boolean (default: False)
– When set to True, computes a maximum weighted cut where each edge has a weight defined by
its label. (If an edge has no label, 1 is assumed.)
– 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. This
implies value_only=False.
• 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:
Quite obviously, the max cut of a bipartite graph is the number of edges, and the two sets of vertices are
the two sides

sage: g = graphs.CompleteBipartiteGraph(5,6)
sage: [ value, edges, [ setA, setB ]] = g.max_cut(vertices=True)
sage: value == 5*6
(continues on next page)

1.1. Generic graphs (common to directed/undirected) 137


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


True
sage: bsetA, bsetB = map(list,g.bipartite_sets())
sage: (bsetA == setA and bsetB == setB ) or ((bsetA == setB and bsetB == setA
˓→))

True

The max cut of a Petersen graph:

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: # With a Multigraph :


sage: g=graphs.CycleGraph(3)
sage: g.allow_multiple_edges(True)
sage: g.merge_vertices([0,1])
sage: g.edges(labels=False)
[(0, 2), (0, 2)]

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)]

min_spanning_tree(weight_function=None, algorithm=’Prim_Boost’, starting_vertex=None,


check=False)

138 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

Returns the edges of a minimum spanning tree.


At the moment, no algorithm for directed graph is implemented: if the graph is directed, a minimum
spanning tree of the corresponding undirected graph is returned.
We expect all weights of the graph to be convertible to float. Otherwise, an exception is raised.
INPUT:
• weight_function (function) - a function that takes as input 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 weight_function can be used to transform the label into a weight (note that, if the weight
returned is not convertible to a float, an error is raised). In particular:
– if weight_function is not None, the weight of an edge e is weight_function(e);
– if weight_function is None (default) and g is weighted (that is, g.
weighted()==True), for each edge e=(u,v,l), we set weight l;
– if weight_function is None and g is not weighted, we set all weights to 1 (hence, the output
can be any spanning tree).
• algorithm – The algorithm to use in computing a minimum spanning tree of G. The following
algorithms are supported:
– "Prim_Boost" (default) – Prim’s algorithm (Boost implementation).
– "Prim_fringe" – a variant of Prim’s algorithm. "Prim_fringe" ignores the labels on the
edges.
– "Prim_edge" – a variant of Prim’s algorithm.
– "Kruskal" – Kruskal’s algorithm.
– "Kruskal_Boost" – Kruskal’s algorithm (Boost implementation).
– "Boruvka" – Boruvka’s algorithm.
– NetworkX – Uses NetworkX’s minimum spanning tree implementation.
• starting_vertex – The vertex from which to begin the search for a minimum spanning tree
(available only for Prim_fringe and Prim_edge).
• check – Boolean; default: False. Whether to first perform sanity checks on the input graph G.
If appropriate, check is passed on to any minimum spanning tree functions that are invoked from
the current method. See the documentation of the corresponding functions for details on what sort of
sanity checks will be performed.
OUTPUT:
The edges of a minimum spanning tree of G, if one exists, otherwise returns the empty list.
See also:

• sage.graphs.spanning_tree.kruskal()
• sage.graphs.spanning_tree.boruvka()
• sage.graphs.base.boost_graph.min_spanning_tree()

EXAMPLES:
Kruskal’s algorithm:

1.1. Generic graphs (common to directed/undirected) 139


Sage Reference Manual: Graph Theory, Release 8.4

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)

[(0, 4, None), (1, 4, None), (2, 4, None), (3, 4, None)]


sage: g.min_spanning_tree(algorithm='Prim_fringe', starting_vertex=2, weight_
˓→function=weight)

[(0, 4, None), (1, 4, None), (2, 4, None), (3, 4, None)]


sage: g.min_spanning_tree(weight_function=weight, algorithm='Prim_Boost')
[(0, 4, None), (1, 4, None), (2, 4, None), (3, 4, None)]

NetworkX algorithm:

sage: g.min_spanning_tree(algorithm='NetworkX')
[(0, 1, None), (0, 2, None), (0, 3, None), (0, 4, None)]

More complicated weights:

sage: G = Graph([(0,1,{'name':'a','weight':1}), (0,2,{'name':'b','weight':3}),


˓→ (1,2,{'name':'b','weight':1})])

sage: G.min_spanning_tree(weight_function=lambda e: e[2]['weight'])


[(0, 1, {'name': 'a', 'weight': 1}), (1, 2, {'name': 'b', 'weight': 1})]

If the graph is not weighted, edge labels are not considered, even if they are numbers:

sage: g = Graph([[1,2,1], [1,3,2], [2,3,1]])


sage: g.min_spanning_tree()
[(1, 2, 1), (1, 3, 2)]

In order to use weights, we need to set variable weighted to True:

sage: g.weighted(True)
sage: g.min_spanning_tree()
[(1, 2, 1), (2, 3, 1)]

140 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

multicommodity_flow(terminals, integer=True, use_edge_labels=False, vertex_bound=False,


solver=None, verbose=0)
Solve a multicommodity flow problem.
In the multicommodity flow problem, we are given a set of pairs (𝑠𝑖 , 𝑡𝑖 ), called terminals meaning that 𝑠𝑖
is willing some flow to 𝑡𝑖 .
Even though it is a natural generalisation of the flow problem this version of it is NP-Complete to solve
when the flows are required to be integer.
For more information, see the Wikipedia article Multi-commodity_flow_problem.
INPUT:
• terminals – a list of pairs (𝑠𝑖 , 𝑡𝑖 ) or triples (𝑠𝑖 , 𝑡𝑖 , 𝑤𝑖 ) representing a flow from 𝑠𝑖 to 𝑡𝑖 of intensity
𝑤𝑖 . When the pairs are of size 2, a intensity of 1 is assumed.
• integer (boolean) – whether to require an integer multicommodity flow
• use_edge_labels (boolean) – whether to consider the label of edges as numerical values repre-
senting a capacity. If set to False, a capacity of 1 is assumed
• vertex_bound (boolean) – whether to require that a vertex can stand at most 1 commodity of flow
through it of intensity 1. Terminals can obviously still send or receive several units of flow even
though vertex_bound is set to True, as this parameter is meant to represent topological properties.
• 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) – sets the level of verbosity. Set to 0 by default (quiet).
ALGORITHM:
(Mixed Integer) Linear Program, depending on the value of integer.
EXAMPLES:
An easy way to obtain a satisfiable multiflow is to compute a matching in a graph, and to consider the
paired vertices as terminals

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

An exception is raised when the problem has no solution

sage: h = g.multicommodity_flow([(u,v,3) for u,v in matching])


Traceback (most recent call last):
...
EmptySetError: The multiflow problem has no solution

multiple_edges(to_undirected=False, labels=True, sort=False)


Return any multiple edges in the (di)graph.

1.1. Generic graphs (common to directed/undirected) 141


Sage Reference Manual: Graph Theory, Release 8.4

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 = DiGraph({1:{2: 'h'}, 2:{1:'g'}},sparse=True)


sage: G.has_multiple_edges()
False
sage: G.has_multiple_edges(to_undirected=True)
True
sage: G.multiple_edges()
[]
sage: G.multiple_edges(to_undirected=True, sort=True)
[(1, 2, 'h'), (2, 1, 'g')]

multiway_cut(vertices, value_only=False, use_edge_labels=False, solver=None, verbose=0)


Return a minimum edge multiway cut.
A multiway cut for a vertex set 𝑆 in a graph or a digraph 𝐺 is a set 𝐶 of edges such that any two vertices

142 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

𝑢, 𝑣 in 𝑆 are disconnected when removing the edges of 𝐶 from 𝐺. ( cf. http://www.d.kth.se/~viggo/


wwwcompendium/node92.html )
Such a cut is said to be minimum when its cardinality (or weight) is minimum.
INPUT:
• vertices (iterable)– the set of vertices
• value_only (boolean)
– When set to True, only the value of a minimum multiway cut is returned.
– When set to False (default), the list of edges is returned
• use_edge_labels (boolean)
– 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 )
– when set to False (default), 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. 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:
Of course, a multiway cut between two vertices correspond to a minimum edge cut

sage: g = graphs.PetersenGraph()
sage: g.edge_cut(0,3) == g.multiway_cut([0,3], value_only = True)
True

As Petersen’s graph is 3-regular, a minimum multiway cut between three vertices contains at most 2 × 3
edges (which could correspond to the neighborhood of 2 vertices):

sage: g.multiway_cut([0,3,9], value_only = True) == 2*3


True

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

sage: g.multiway_cut([0,7,9], value_only = True) == 2*3 - 1


True

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

1.1. Generic graphs (common to directed/undirected) 143


Sage Reference Manual: Graph Theory, Release 8.4

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

sage: D = DiGraph({0:[1,2], 3:[0]})


sage: list(D.neighbor_iterator(0))
[1, 2, 3]

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:

144 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

• 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'>

nowhere_zero_flow(k=None, solver=None, verbose=0)


Return a k-nowhere zero flow of the (di)graph.
A flow on a graph 𝐺 = (𝑉, 𝐸) is a pair (𝐷, 𝑓 ) such that 𝐷 is an orientation of 𝐺 and 𝑓 is a function on 𝐸
satisfying
∑︁ ∑︁
𝑓 (𝑢𝑣) = 𝑓 (𝑣𝑤), ∀𝑣 ∈ 𝑉.
− +
𝑢∈𝑁𝐷 (𝑣) 𝑤∈𝑁𝐷 (𝑣)

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)

1.1. Generic graphs (common to directed/undirected) 145


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: h = g.nowhere_zero_flow(k=3)
Traceback (most recent call last):
...
EmptySetError: the problem has no feasible solution

The de Bruijn digraph admits a 2-nowhere zero flow:


sage: g = digraphs.DeBruijn(2, 3)
sage: h = g.nowhere_zero_flow(k=2)
sage: sorted(list( set(h.edge_labels()) ))
[-1, 1]

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

sage: D = DiGraph(4, loops=True)


sage: D.add_edges( [ (0,0), (1,1), (2,2), (3,3), (2,3) ] )
(continues on next page)

146 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: D.edges(labels=False)
[(0, 0), (1, 1), (2, 2), (2, 3), (3, 3)]
sage: D.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

periphery(by_weight=False, algorithm=None, weight_function=None, check_weight=True)


Returns the set of vertices in the periphery, i.e. whose eccentricity is equal to the diameter of the (di)graph.
In other words, the periphery is the set of vertices achieving the maximum eccentricity.
For more information and examples on how to use input variables, see shortest_paths() and
eccentricity()
INPUT:
• by_weight - if True, edge weights are taken into account; if False, all edges have weight 1.
• algorithm (string) - one of the following algorithms:
– 'BFS' - the computation is done through a BFS centered on each vertex successively. Works
only if by_weight==False.
– 'Floyd-Warshall-Cython' - a Cython implementation of the Floyd-Warshall algorithm.
Works only if by_weight==False.
– 'Floyd-Warshall-Python' - a Python implementation of the Floyd-Warshall algorithm.
Works also with weighted graphs, even with negative weights (but no negative cycle is allowed).
– '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' for unweighted graphs,
'Dijkstra_Boost' if all weights are positive, 'Johnson_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:

1.1. Generic graphs (common to directed/undirected) 147


Sage Reference Manual: Graph Theory, Release 8.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-

148 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

connectivity test (trac ticket #24635).

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’.

1.1. Generic graphs (common to directed/undirected) 149


Sage Reference Manual: Graph Theory, Release 8.4

• 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: from math import sin, cos, pi


sage: P = graphs.PetersenGraph()
sage: d = {'#FF0000':[0,5], '#FF9900':[1,6], '#FFFF00':[2,7], '#00FF00':[3,8],
˓→ '#0000FF':[4,9]}

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:

˓→[19], 19: []} , sparse=True)

(continues on next page)

150 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: for u,v,l in D.edges():
....: D.set_edge_label(u,v,'(' + str(u) + ',' + str(v) + ')')
sage: D.plot(edge_labels=True, layout='circular').show()

sage: from sage.plot.colors import rainbow


sage: C = graphs.CubeGraph(5)
sage: R = rainbow(5)
sage: edge_colors = {}
sage: for i in range(5):
....: edge_colors[R[i]] = []
sage: for u,v,l in C.edges():
....: for i in range(5):
....: if u[i] != v[i]:
....: edge_colors[R[i]].append((u,v,l))
sage: C.plot(vertex_labels=False, vertex_size=0, edge_colors=edge_colors).
˓→show()

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: D = DiGraph({0:[0,1], 1:[2], 2:[3]}, loops=True)


sage: D.show()
sage: D.show(edge_colors={(0,1,0):[(0,1,None),(1,2,None)],(0,0,0):[(2,3,
˓→None)]})

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({0:[1], 1:[2], 2:[3], 3:[4], 4:[0]})


sage: g.plot(pos=pos, layout='spring', iterations=0)
Graphics object consisting of 11 graphics primitives

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)

1.1. Generic graphs (common to directed/undirected) 151


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


6: (-0.47..., 0.15...),
7: (-0.29..., -0.40...),
8: (0.29..., -0.40...),
9: (0.47..., 0.15...)}
sage: P = G.plot(save_pos=True, layout='spring')

The following illustrates the format of a position dictionary.

sage: G.get_pos() # currently random across platforms, see #9593


{0: [1.17..., -0.855...],
1: [1.81..., -0.0990...],
2: [1.35..., 0.184...],
3: [1.51..., 0.644...],
4: [2.00..., -0.507...],
5: [0.597..., -0.236...],
6: [2.04..., 0.687...],
7: [1.46..., -0.473...],
8: [0.902..., 0.773...],
9: [2.48..., -0.119...]}

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)

152 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: D.plot(edge_labels=True,edge_colors=D._color_by_label())
Graphics object consisting of 34 graphics primitives
sage: D.plot(edge_labels=True, color_by_label={'a':'blue', 'b':'red'}, edge_
˓→style='dashed')

Graphics object consisting of 34 graphics primitives

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: g.plot(edge_labels=True, color_by_label=True, edge_style='dashed')
Graphics object consisting of 26 graphics primitives

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]})

plot3d(bgcolor=(1, 1, 1), vertex_colors=None, vertex_size=0.06, vertex_labels=False,


edge_colors=None, edge_size=0.02, edge_size2=0.0325, pos3d=None, color_by_label=False,
engine=’jmol’, **kwds)
Plot a graph in three dimensions.
See also the sage.graphs.graph_latex module for ways to use LaTeX to produce an image of a
graph.
INPUT:
• bgcolor - rgb tuple (default: (1,1,1))
• vertex_size - float (default: 0.06)
• vertex_labels – a boolean (default: False) whether to display vertices using text labels instead
of spheres
• vertex_colors - optional dictionary to specify vertex colors: each key is a color recognizable by
tachyon (rgb tuple (default: (1,0,0))), 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 tachyon (
default: (0,0,0) ), and each entry is a list of edges.
• 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.
• edge_size - float (default: 0.02)
• edge_size2 - float (default: 0.0325), used for Tachyon sleeves
• pos3d - a position dictionary for the vertices
• layout, iterations, . . . - layout options; see layout()
• engine - which renderer to use. Options:
– 'jmol' - default

1.1. Generic graphs (common to directed/undirected) 153


Sage Reference Manual: Graph Theory, Release 8.4

– '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

We plot a fairly complicated Cayley graph:

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

Some Tachyon examples:

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

A directed version of the dodecahedron

sage: D = DiGraph( { 0: [1, 10, 19], 1: [8, 2], 2: [3, 6], 3: [19, 4], 4: [17,
˓→ 5], 5: [6, 15], 6: [7], 7: [8, 14], 8: [9], 9: [10, 13], 10: [11], 11: [12,

˓→ 18], 12: [16, 13], 13: [14], 14: [15], 15: [16], 16: [17], 17: [18], 18:

˓→[19], 19: []} )

sage: D.plot3d().show() # long time

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

154 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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.

Using the partition keyword:

sage: G = graphs.WheelGraph(7)
sage: G.plot3d(partition=[[0],[1,2,3,4,5,6]])
Graphics3d Object

See also:

• plot()
• graphviz_string()

radius(by_weight=False, algorithm=None, weight_function=None, check_weight=True)


Returns the radius of the (di)graph.
The radius is defined to be the minimum eccentricity of any vertex, where the eccentricity is the maximum
distance to any other vertex. For more information and examples on how to use input variables, see
shortest_paths() and eccentricity()
INPUT:
• by_weight - if True, edge weights are taken into account; if False, all edges have weight 1.
• algorithm (string) - one of the following algorithms:
– 'BFS' - the computation is done through a BFS centered on each vertex successively. Works
only if by_weight==False.
– 'Floyd-Warshall-Cython' - a Cython implementation of the Floyd-Warshall algorithm.
Works only if by_weight==False.
– 'Floyd-Warshall-Python' - a Python implementation of the Floyd-Warshall algorithm.
Works also with weighted graphs, even with negative weights (but no negative cycle is allowed).
– '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' for unweighted graphs,
'Dijkstra_Boost' if all weights are positive, 'Johnson_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: The more symmetric a graph is, the smaller (diameter - radius) is.

1.1. Generic graphs (common to directed/undirected) 155


Sage Reference Manual: Graph Theory, Release 8.4

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):

sage: print(next(g.random_edge_iterator())) # random


(0, 5, None)
sage: print(next(g.random_edge_iterator(labels=False))) # random
(5, 7)

156 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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]

relabel(perm=None, inplace=True, return_map=False, check_input=True, com-


plete_partial_function=True, immutable=None)
Relabels the vertices of self
INPUT:
• perm – a function, dictionary, list, permutation, or None (default: None)
• inplace – a boolean (default: True)
• return_map – a boolean (default: False)
• check_input (boolean) – whether to test input for correctness. This can potentially be very time-
consuming !.
• complete_partial_function (boolean) – whether to automatically complete the permutation
if some elements of the graph are not associated with any new name. In this case, those elements are
not relabeled This can potentially be very time-consuming !.

1.1. Generic graphs (common to directed/undirected) 157


Sage Reference Manual: Graph Theory, Release 8.4

• immutable (boolean) – with inplace=False, whether to create a mutable/immutable relabelled


copy. immutable=None (default) means that the graph and its copy will behave the same way.
If perm is a function f, then each vertex v is relabeled to f(v).
If perm is a dictionary d, then each vertex v (which should be a key of d) is relabeled to d[v]. Similarly,
if perm is a list or tuple l of length n, then the first vertex returned by G.vertices() is relabeled to
l[0], the second to l[1], . . .
If perm is a permutation, then each vertex v is relabeled to perm(v). Caveat: this assumes that the
vertices are labelled {0, 1, ..., 𝑛 − 1}; since permutations act by default on the set {1, 2, ..., 𝑛}, this is
achieved by identifying 𝑛 and 0.
If perm is None, the graph is relabeled to be on the vertices {0, 1, ..., 𝑛 − 1}. This is not any kind of
canonical labeling, but neither a random relabeling.
If inplace is True, the graph is modified in place and None is returned. Otherwise a relabeled copy of
the graph is returned.
If return_map is True a dictionary representing the relabelling map is returned (incompatible with
inplace==False).
EXAMPLES:

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:

sage: G.relabel({1:2,2:1}, inplace=False).am()


[0 0 1]
[0 0 1]
[1 1 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.relabel({1:2,2:1}, inplace=False, complete_partial_function = False).


˓→am()

Traceback (most recent call last):


...
KeyError: 0

Relabeling using a list:

sage: G.relabel([0,2,1], inplace=False).am()


[0 0 1]
[0 0 1]
[1 1 0]

Relabeling using a tuple:

sage: G.relabel((0,2,1), inplace=False).am()


[0 0 1]
[0 0 1]
[1 1 0]

158 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

Relabeling using a Sage permutation:

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]

A way to get a random relabeling:

sage: set_random_seed(0) # Results are reproducible


sage: D = DiGraph({1: [2], 3: [4]})
sage: D.relabel(Permutations(D.vertices()).random_element())
sage: D.sources()
[1, 4]

Relabeling using an injective function:

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)]

Relabeling using a non injective function has no meaning:

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

But this test can be disabled, which can lead to . . . problems:

sage: G.edges()
[(0, 1, None), (1, 2, None)]
sage: G.relabel(lambda i: 0, check_input = False)
sage: G.edges()
[]

Relabeling to simpler labels:

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]

Recovering the relabeling with return_map:

1.1. Generic graphs (common to directed/undirected) 159


Sage Reference Manual: Graph Theory, Release 8.4

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.relabel(return_map=True) == expecting


True

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

sage: D = DiGraph(4, loops=True)


sage: D.add_edges( [ (0,0), (1,1), (2,2), (3,3), (2,3) ] )
sage: D.edges(labels=False)
[(0, 0), (1, 1), (2, 2), (2, 3), (3, 3)]
sage: D.remove_loops()
sage: D.edges(labels=False)
[(2, 3)]
sage: D.allows_loops()
True
sage: D.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)]

sage: D = DiGraph(multiedges=True, sparse=True)


sage: D.add_edges( [ (0,1,1), (0,1,2), (0,1,3), (0,1,4), (1,2,None) ] )
sage: D.edges(labels=False)
[(0, 1), (0, 1), (0, 1), (0, 1), (1, 2)]
(continues on next page)

160 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: D.remove_multiple_edges()
sage: D.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: SD = DiGraph( { 1:[18,2], 2:[5,3], 3:[4,6], 4:[7,2], 5:[4], 6:[13,12],


˓→7:[18,8,10], 8:[6,9,10], 9:[6], 10:[11,13], 11:[12], 12:[13], 13:[17,14],

˓→14:[16,15], 15:[2], 16:[13], 17:[15,13], 18:[13] }, sparse=True)

sage: SD.set_edge_label(1, 18, 'discrete')


sage: SD.set_edge_label(4, 7, 'discrete')
sage: SD.set_edge_label(2, 5, 'h = 0')
sage: SD.set_edge_label(7, 18, 'h = 0')
sage: SD.set_edge_label(7, 10, 'aut')
sage: SD.set_edge_label(8, 10, 'aut')
sage: SD.set_edge_label(8, 9, 'label')
sage: SD.set_edge_label(8, 6, 'no label')
sage: SD.set_edge_label(13, 17, 'k > h')
sage: SD.set_edge_label(13, 14, 'k = h')
sage: SD.set_edge_label(17, 15, 'v_k finite')
sage: SD.set_edge_label(14, 15, 'v_k m.c.r.')
sage: posn = {1:[ 3,-3], 2:[0,2], 3:[0, 13], 4:[3,9], 5:[3,3], 6:[16,
˓→13], 7:[6,1], 8:[6,6], 9:[6,11], 10:[9,1], 11:[10,6], 12:[13,6], 13:[16,
˓→2], 14:[10,-6], 15:[0,-10], 16:[14,-6], 17:[16,-10], 18:[6,-4]}

sage: SD.plot(pos=posn, vertex_size=400, vertex_colors={'#FFFFFF


˓→':list(range(1,19))}, edge_labels=True).show() # long time

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)')]

sage: g = Graph({0: [0,1,1,2]}, loops=True, multiedges=True, sparse=True)


sage: g.set_edge_label(0,0,'test')
sage: g.edges()
[(0, 0, 'test'), (0, 1, None), (0, 1, None), (0, 2, None)]
sage: g.add_edge(0,0,'test2')
sage: g.set_edge_label(0,0,'test3')
(continues on next page)

1.1. Generic graphs (common to directed/undirected) 161


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


Traceback (most recent call last):
...
RuntimeError: Cannot set edge label, since there are multiple edges from 0 to
˓→0.

sage: dg = DiGraph({0 : [1], 1 : [0]}, sparse=True)


sage: dg.set_edge_label(0,1,5)
sage: dg.set_edge_label(1,0,9)
sage: dg.outgoing_edges(1)
[(1, 0, 9)]
sage: dg.incoming_edges(1)
[(0, 1, 5)]
sage: dg.outgoing_edges(0)
[(0, 1, 5)]
sage: dg.incoming_edges(0)
[(1, 0, 9)]

sage: G = Graph({0:{1:1}}, sparse=True)


sage: G.num_edges()
1
sage: G.set_edge_label(0,1,1)
sage: G.num_edges()
1

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]})

sage: G.set_embedding({'s': [1, 5, 4], 1: [0, 2, 6], 2: [1, 3, 7], 3: [8, 2,


˓→4], 4: [0, 9, 3], 5: [0, 8, 7], 6: [8, 1, 9], 7: [9, 2, 5], 8: [3, 5, 6],

˓→9: [4, 6, 7]})

Traceback (most recent call last):


...
ValueError: The following vertices from the embedding do not belong to the
˓→graph: ['s']

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().

162 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

This method is deprecated since Sage-4.4.1.alpha2. Please use instead:


sage: g.layout(layout = “planar”, save_pos = True) {0: [1, 4], 1: [5, 1], 2: [0, 5], 3: [1, 0], 4: [1,
2], 5: [2, 1], 6: [4, 1]}
set_pos(pos, dim=2)
Sets the position dictionary, a dictionary specifying the coordinates of each vertex.
EXAMPLES: Note that set_pos will allow you to do ridiculous things, which will not blow up until plot-
ting:

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

1.1. Generic graphs (common to directed/undirected) 163


Sage Reference Manual: Graph Theory, Release 8.4

set_vertices(vertex_dict)
Associate arbitrary objects with each vertex, via an association dictionary.
INPUT:
• vertex_dict - the association dictionary
EXAMPLES:

sage: d = {0 : graphs.DodecahedralGraph(), 1 : graphs.FlowerSnark(), 2 :


˓→graphs.MoebiusKantorGraph(), 3 : graphs.PetersenGraph() }

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

shortest_path(u, v, by_weight=False, algorithm=None, weight_function=None,


check_weight=True)
Returns a list of vertices representing some shortest path from u to v: if there is no path from u to v, the
list is empty.
For more information and more examples, see shortest_paths() (the inputs are very similar).
INPUT:
• u, v (vertices) - the start and the end vertices of the paths.
• 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.
– 'BFS_Bid: performs a BFS from u and from v. Does not work with edge weights.
– 'Dijkstra_NetworkX': the Dijkstra algorithm, implemented in NetworkX. Works only with
positive weights.
– 'Dijkstra_Bid_NetworkX': performs a Dijkstra visit from u and from v (NetworkX im-
plementation). Works only with positive weights.
– 'Dijkstra_Bid': a Cython implementation that performs a Dijkstra visit from u and from v.
Works only with positive weights.
– 'Bellman-Ford_Boost': the Bellman-Ford algorithm, implemented in Boost. Works also
with negative weights, if there is no negative cycle.
– None (default): Sage chooses the best algorithm: 'BFS_Bid' if by_weight is False,
'Dijkstra_Bid' otherwise.

Note: If there are negative weights and algorithm is None, the result is not reliable. This
occurs because, for performance reasons, we cannot check whether there are edges with neg-
ative weights before running the algorithm. If there are, the user should explicitly input
algorithm='Bellman-Ford_Boost'.

164 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

• 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)

sage: G.plot(edge_labels=True).show() # long time


sage: G.shortest_path(0, 3)
[0, 4, 3]
sage: G.shortest_path(0, 3, by_weight=True)
[0, 1, 2, 3]
sage: G.shortest_path(0, 3, by_weight=True, algorithm='Dijkstra_NetworkX')
[0, 1, 2, 3]
sage: G.shortest_path(0, 3, by_weight=True, algorithm='Dijkstra_Bid_NetworkX')
[0, 1, 2, 3]

shortest_path_all_pairs(by_weight=False, algorithm=None, weight_function=None,


check_weight=True)
Computes a shortest path between each pair of vertices.
INPUT:
• 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' - 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).

1.1. Generic graphs (common to directed/undirected) 165


Sage Reference Manual: Graph Theory, Release 8.4

– '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: Only reachable vertices are present in the dictionaries.

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)

sage: G.plot(edge_labels=True).show() # long time


sage: dist, pred = G.shortest_path_all_pairs(by_weight = True)
sage: dist
{0: {0: 0, 1: 1, 2: 2, 3: 3, 4: 2}, 1: {0: 1, 1: 0, 2: 1, 3: 2, 4: 3}, 2: {0:
˓→2, 1: 1, 2: 0, 3: 1, 4: 3}, 3: {0: 3, 1: 2, 2: 1, 3: 0, 4: 2}, 4: {0: 2, 1:

˓→3, 2: 3, 3: 2, 4: 0}}

sage: pred
{0: {0: None, 1: 0, 2: 1, 3: 2, 4: 0}, 1: {0: 1, 1: None, 2: 1, 3: 2, 4: 0},
˓→2: {0: 1, 1: 2, 2: None, 3: 2, 4: 3}, 3: {0: 1, 1: 2, 2: 3, 3: None, 4: 3},

˓→4: {0: 4, 1: 0, 2: 3, 3: 4, 4: None}}

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, pred = G.shortest_path_all_pairs(weight_function = lambda e:e[2][


˓→'weight'])

sage: dist
{0: {0: 0, 1: 1, 2: 2, 3: 3, 4: 2}, 1: {0: 1, 1: 0, 2: 1, 3: 2, 4: 3}, 2: {0:
˓→2, 1: 1, 2: 0, 3: 1, 4: 3}, 3: {0: 3, 1: 2, 2: 1, 3: 0, 4: 2}, 4: {0: 2, 1:

˓→3, 2: 3, 3: 2, 4: 0}}

sage: pred
{0: {0: None, 1: 0, 2: 1, 3: 2, 4: 0}, 1: {0: 1, 1: None, 2: 1, 3: 2, 4: 0},
˓→2: {0: 1, 1: 2, 2: None, 3: 2, 4: 3}, 3: {0: 1, 1: 2, 2: 3, 3: None, 4: 3},

˓→4: {0: 4, 1: 0, 2: 3, 3: 4, 4: None}} (continues on next page)

166 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)

So for example the shortest weighted path from 0 to 3 is obtained as follows. The predecessor of 3
is pred[0][3] == 2, the predecessor of 2 is pred[0][2] == 1, and the predecessor of 1 is
pred[0][1] == 0.

sage: G = Graph( { 0: {1:None}, 1: {2:None}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2} }


˓→, sparse=True )

sage: G.shortest_path_all_pairs()
({0: {0: 0, 1: 1, 2: 2, 3: 2, 4: 1},
1: {0: 1, 1: 0, 2: 1, 3: 2, 4: 2},
2: {0: 2, 1: 1, 2: 0, 3: 1, 4: 2},
3: {0: 2, 1: 2, 2: 1, 3: 0, 4: 1},
4: {0: 1, 1: 2, 2: 2, 3: 1, 4: 0}},
{0: {0: None, 1: 0, 2: 1, 3: 4, 4: 0},
1: {0: 1, 1: None, 2: 1, 3: 2, 4: 0},
2: {0: 1, 1: 2, 2: None, 3: 2, 4: 3},
3: {0: 4, 1: 2, 2: 3, 3: None, 4: 3},
4: {0: 4, 1: 0, 2: 3, 3: 4, 4: None}})
sage: G.shortest_path_all_pairs(weight_function=lambda e:(e[2] if e[2] is not
˓→None else 1))

({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}},
{0: {0: None, 1: 0, 2: 1, 3: 2, 4: 0},
1: {0: 1, 1: None, 2: 1, 3: 2, 4: 0},
2: {0: 1, 1: 2, 2: None, 3: 2, 4: 3},
3: {0: 1, 1: 2, 2: 3, 3: None, 4: 3},
4: {0: 4, 1: 0, 2: 3, 3: 4, 4: None}})

Checking that distances are equal regardless of the algorithm used:

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

Checking that distances are equal regardless of the algorithm used:

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:

1.1. Generic graphs (common to directed/undirected) 167


Sage Reference Manual: Graph Theory, Release 8.4

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

Checking a random path is valid:

sage: dist, path = g.shortest_path_all_pairs(algorithm="BFS")


sage: u,v = g.random_vertex(), g.random_vertex()
sage: p = [v]
sage: while p[0] is not None:
....: p.insert(0,path[u][p[0]])
sage: len(p) == dist[u][v] + 2
True

Negative weights:

sage: g = DiGraph([(0,1,-2),(1,0,1)], weighted=True)


sage: g.shortest_path_all_pairs(by_weight=True)
Traceback (most recent call last):
...
ValueError: The graph contains a negative cycle.

Unreachable vertices are not present in the dictionaries:

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)

168 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: for u,v in itertools.combinations(G.vertices(),2):
....: print("dist({}, {}) = {}".format(u,v, d[u].get(v,+Infinity)))
dist(0, 1) = 1
dist(0, 2) = +Infinity
dist(0, 3) = +Infinity
dist(1, 2) = +Infinity
dist(1, 3) = +Infinity
dist(2, 3) = 1

shortest_path_length(u, v, by_weight=False, algorithm=None, weight_function=None,


check_weight=True)
Returns the minimal length of a path from u to v.
If there is no path from u to v, returns Infinity.
For more information and more examples, we refer to shortest_path() and shortest_paths(),
which have very similar inputs.
INPUT:
• u, v (vertices) - the start and the end vertices of the paths.
• 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.
– 'BFS_Bid: performs a BFS from u and from v. Does not work with edge weights.
– 'Dijkstra_NetworkX': the Dijkstra algorithm, implemented in NetworkX.
– 'Dijkstra_Bid_NetworkX': performs a Dijkstra visit from u and from v (NetworkX im-
plementation).
– 'Dijkstra_Bid': a Cython implementation that performs a Dijkstra visit from u and from v.
– 'Bellman-Ford_Boost': the Bellman-Ford algorithm, implemented in Boost. Works also
with negative weights, if there is no negative cycle.
– None (default): Sage chooses the best algorithm: 'BFS_Bid' if by_weight is False,
'Dijkstra_Bid' otherwise.

Note: If there are negative weights and algorithm is None, the result is not reliable. This
occurs because, for performance reasons, we cannot check whether there are edges with neg-
ative weights before running the algorithm. If there are, the user should explicitly input
algorithm='Bellman-Ford_Boost'.

• weight_function (function) - 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:

1.1. Generic graphs (common to directed/undirected) 169


Sage Reference Manual: Graph Theory, Release 8.4

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)

sage: G.plot(edge_labels=True).show() # long time


sage: G.shortest_path_length(0, 3)
2
sage: G.shortest_path_length(0, 3, by_weight=True)
3
sage: G.shortest_path_length(0, 3, by_weight=True, algorithm='Dijkstra_
˓→NetworkX')

3
sage: G.shortest_path_length(0, 3, by_weight=True, algorithm='Dijkstra_Bid_
˓→NetworkX')

If Dijkstra is used with negative weights, usually it raises an error:

sage: G = DiGraph({0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: -2}},
˓→sparse = True)

sage: G.shortest_path_length(4, 1, by_weight=True, algorithm=None)


Traceback (most recent call last):
...
ValueError: The graph contains an edge with negative weight!
sage: G.shortest_path_length(4, 1, by_weight=True, algorithm='Bellman-Ford_
˓→Boost')

-1

However, sometimes the result may be wrong, and no error is raised:

sage: G = DiGraph([(0,1,1),(1,2,1),(0,3,1000),(3,4,-3000), (4,2,1000)])


sage: G.shortest_path_length(0, 2, by_weight=True, algorithm='Bellman-Ford_
˓→Boost')

-1000
sage: G.shortest_path_length(0, 2, by_weight=True)
2

shortest_path_lengths(u, by_weight=False, algorithm=None, weight_function=None,


check_weight=True)
Computes the length of a shortest path from u to any other vertex.
Returns a dictionary of shortest path lengths keyed by targets, excluding all vertices that are not reachable

170 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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)

sage: G.plot(edge_labels=True).show() # long time


sage: G.shortest_path_lengths(0, by_weight=True)
{0: 0, 1: 1, 2: 2, 3: 3, 4: 2}

Using a weight function:


sage: D = DiGraph([(0,1,{'weight':1}),(1,2,{'weight':3}),(0,2,{'weight':5})])
sage: weight_function = lambda e:e[2]['weight']
sage: D.shortest_path_lengths(1, algorithm='Dijkstra_NetworkX', by_
˓→weight=False)

{1: 0, 2: 1}
sage: D.shortest_path_lengths(0, weight_function=weight_function)
{0: 0, 1: 1, 2: 4}
sage: D.shortest_path_lengths(1, weight_function=weight_function)
{1: 0, 2: 3}

1.1. Generic graphs (common to directed/undirected) 171


Sage Reference Manual: Graph Theory, Release 8.4

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

Checking that distances are equal regardless of the algorithm used:

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

shortest_paths(u, by_weight=False, algorithm=None, weight_function=None,


check_weight=True, cutoff=None)
Returns a dictionary associating to each vertex v a shortest path from u to v, if it exists.
If u and v are not connected, vertex v is not present in the dictionary.
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.
• cutoff (integer) - integer depth to stop search (used only if algorithm=='BFS').

172 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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]}

All these paths are obviously induced graphs:


sage: all([D.subgraph(p).is_isomorphic(graphs.PathGraph(len(p)) )for p in D.
˓→shortest_paths(0).values()])

True

sage: D.shortest_paths(0, cutoff=2)


{0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 19, 3], 8: [0, 1, 8], 9: [0, 10, 9],
˓→10: [0, 10], 11: [0, 10, 11], 18: [0, 19, 18], 19: [0, 19]}

sage: G = Graph( { 0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2} },
˓→sparse=True)

sage: G.plot(edge_labels=True).show() # long time


sage: G.shortest_paths(0, by_weight=True)
{0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 1, 2, 3], 4: [0, 4]}

Weighted shortest paths:


sage: D = DiGraph([(0,1,1),(1,2,3),(0,2,5)])
sage: D.shortest_paths(0)
{0: [0], 1: [0, 1], 2: [0, 2]}
sage: D.shortest_paths(0, by_weight=True)
{0: [0], 1: [0, 1], 2: [0, 1, 2]}

Using a weight function (this way, by_weight is set to True):


sage: D = DiGraph([(0,1,{'weight':1}),(1,2,{'weight':3}),(0,2,{'weight':5})])
sage: weight_function = lambda e:e[2]['weight']
sage: D.shortest_paths(0, weight_function=weight_function)
{0: [0], 1: [0, 1], 2: [0, 1, 2]}

If the weight function does not match the label:


sage: D.shortest_paths(0, weight_function=lambda e:e[2])
Traceback (most recent call last):
...
ValueError: The weight function cannot find the weight of (0, 1, {'weight': 1}
˓→).

However, if check_weight is set to False, unexpected behavior may occur:


sage: D.shortest_paths(0, algorithm='Dijkstra_NetworkX', weight_
˓→function=lambda e:e[2], check_weight=False)

Traceback (most recent call last):


...
TypeError: unsupported operand type(s) for +: 'int' and 'dict'

Negative weights:

1.1. Generic graphs (common to directed/undirected) 173


Sage Reference Manual: Graph Theory, Release 8.4

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)

show3d(bgcolor=(1, 1, 1), vertex_colors=None, vertex_size=0.06, edge_colors=None, edge_size=0.02,


edge_size2=0.0325, pos3d=None, color_by_label=False, engine=’jmol’, **kwds)
Plots the graph using Tachyon, and shows the resulting plot.
INPUT:
• bgcolor - rgb tuple (default: (1,1,1))
• vertex_size - float (default: 0.06)
• vertex_colors - optional dictionary to specify vertex colors: each key is a color recognizable by
tachyon (rgb tuple (default: (1,0,0))), 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 tachyon (
default: (0,0,0) ), and each entry is a list of edges.
• edge_size - float (default: 0.02)
• edge_size2 - float (default: 0.0325), used for Tachyon sleeves
• pos3d - a position dictionary for the vertices
• iterations - how many iterations of the spring layout algorithm to go through, if applicable
• engine - which renderer to use. Options:
• 'jmol' - default ‘tachyon’
• xres - resolution

174 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

• 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

We plot a fairly complicated Cayley graph:

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,

˓→iterations=200) # long time

Some Tachyon examples:

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:

1.1. Generic graphs (common to directed/undirected) 175


Sage Reference Manual: Graph Theory, Release 8.4

• 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.

176 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

EXAMPLES:

sage: from sage.graphs.base.static_sparse_graph import spectral_radius

sage: G = DiGraph([(0,0),(0,1),(1,0)], loops=True)


sage: phi = (RR(1) + RR(5).sqrt() ) / 2
sage: phi # abs tol 1e-14
1.618033988749895
sage: e_min, e_max = spectral_radius(G, 1e-14)
sage: e_min, e_max # abs tol 1e-14
(1.618033988749894, 1.618033988749896)
sage: (e_max - e_min) # abs tol 1e-14
1e-14
sage: e_min < phi < e_max
True

This function also works for graphs:

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

sage: G.spectral_radius() # abs tol 1e-9


(2.48119430408, 2.4811943041)

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

A much larger example:

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)

The algorithm takes care of multiple edges:

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)

1.1. Generic graphs (common to directed/undirected) 177


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: max(G.adjacency_matrix().eigenvalues(AA))
2.414213562373095?

Some bipartite graphs:

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:

sage: T = DiGraph({0:[1], 1:[2], 2:[0]})


sage: T.spectrum()
[1, -0.5000000000... + 0.8660254037...*I, -0.5000000000... - 0.8660254037...
˓→*I]

steiner_tree(vertices, weighted=False, solver=None, verbose=0)


Return a tree of minimum weight connecting the given set of vertices.

178 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

And all the 5 vertices are contained in this tree

sage: all([v in st for v in g.vertices()[:5] ])


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)

1.1. Generic graphs (common to directed/undirected) 179


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


...
EmptySetError: The given vertices do not all belong to the same connected
˓→component. This problem has no solution !

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:

180 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

sage: g = graphs.PathGraph(3)
sage: edge = g.edges()[0]
sage: g.subdivide_edge(edge, 5)
sage: g.is_isomorphic(graphs.PathGraph(8))
True

Subdividing a labelled edge in two ways

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')]

Specifying the label:

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')]

The lazy way:

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,

˓→'label2'), (9, 10, 'label2')]

If too many arguments are given, an exception is raised

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() – subdivides multiples edges at a time

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

1.1. Generic graphs (common to directed/undirected) 181


Sage Reference Manual: Graph Theory, Release 8.4

Note: If a given edge is labelled with 𝑙, all the edges created by its subdivision will have the same label.

EXAMPLES:
If we are given the disjoint union of several paths:

sage: paths = [2,5,9]


sage: paths = map(graphs.PathGraph, paths)
sage: g = Graph()
sage: for P in paths:
....: g = g + P

. . . subdividing edges in each of them will only change their lengths:

sage: edges = [P.edges()[0] for P in g.connected_components_subgraphs()]


sage: k = 6
sage: g.subdivide_edges(edges, k)

Let us check this by creating the graph we expect to have built through subdivision:

sage: paths2 = [2+k, 5+k, 9+k]


sage: paths2 = map(graphs.PathGraph, paths2)
sage: g2 = Graph()
sage: for P in paths2:
....: g2 = g2 + P
sage: g.is_isomorphic(g2)
True

See also:

• subdivide_edge() – subdivides one edge

subgraph(vertices=None, edges=None, inplace=False, vertex_property=None, edge_property=None,


algorithm=None, immutable=None)
Returns the subgraph containing the given vertices and edges.
If either vertices or edges are not specified, they are assumed to be all vertices or edges. If edges are not
specified, returns the subgraph induced by the vertices.
INPUT:
• inplace - Using inplace is True will simply delete the extra vertices and edges from the current
graph. This will modify the graph.
• 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.
• edges - As with vertices, edges can be a single edge or an iterable container of edges (e.g., a list, set,
file, numeric array, etc.). If not edges are not specified, then all edges are assumed and the returned
graph is an induced subgraph. In the case of multiple edges, specifying an edge as (u,v) means to keep
all edges (u,v), regardless of the label.
• vertex_property - If specified, this is expected to be a function on vertices, which is intersected
with the vertices specified, if any are.
• edge_property - If specified, this is expected to be a function on edges, which is intersected with
the edges specified, if any are.

182 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

• algorithm - If algorithm=delete or inplace=True, then the graph is constructed by delet-


ing edges and vertices. If add, then the graph is constructed by building a new graph from the ap-
propriate vertices and edges. If not specified, then the algorithm is chosen based on the number of
vertices in the subgraph.
• immutable (boolean) – whether to create a mutable/immutable subgraph. immutable=None
(default) means that the graph and its subgraph will behave the same way.
EXAMPLES:
sage: G = graphs.CompleteGraph(9)
sage: H = G.subgraph([0,1,2]); H
Subgraph of (Complete graph): Graph on 3 vertices
sage: G
Complete graph: Graph on 9 vertices
sage: J = G.subgraph(edges=[(0,1)])
sage: J.edges(labels=False)
[(0, 1)]
sage: J.vertices()==G.vertices()
True
sage: G.subgraph([0,1,2], inplace=True); G
Subgraph of (Complete graph): Graph on 3 vertices
sage: G.subgraph()==G
True

sage: D = 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

A more complicated example involving multiple edges and labels.


sage: G = Graph(multiedges=True, sparse=True)
sage: G.add_edges([(0,1,'a'), (0,1,'b'), (1,0,'c'), (0,2,'d'), (0,2,'e'), (2,
˓→0,'f'), (1,2,'g')])

sage: G.subgraph(edges=[(0,1), (0,2,'d'), (0,2,'not in graph')]).edges()


[(0, 1, 'a'), (0, 1, 'b'), (0, 1, 'c'), (0, 2, 'd')]
sage: J = G.subgraph(vertices=[0,1], edges=[(0,1,'a'), (0,2,'c')])
sage: J.edges()
[(0, 1, 'a')]
sage: J.vertices()
[0, 1]
sage: G.subgraph(vertices=G.vertices())==G
True

sage: D = DiGraph(multiedges=True, sparse=True)


sage: D.add_edges([(0,1,'a'), (0,1,'b'), (1,0,'c'), (0,2,'d'), (0,2,'e'), (2,
˓→0,'f'), (1,2,'g')])

(continues on next page)

1.1. Generic graphs (common to directed/undirected) 183


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: D.subgraph(edges=[(0,1), (0,2,'d'), (0,2,'not in graph')]).edges()
[(0, 1, 'a'), (0, 1, 'b'), (0, 2, 'd')]
sage: H = D.subgraph(vertices=[0,1], edges=[(0,1,'a'), (0,2,'c')])
sage: H.edges()
[(0, 1, 'a')]
sage: H.vertices()
[0, 1]

Using the property arguments:

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.

184 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

See also:

• subgraph_search_count() – Counts the number of copies of 𝐻 inside of 𝐺


• subgraph_search_iterator() – Iterate on the copies of 𝐻 inside of 𝐺

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)]

It also contains the claw 𝐾1,3 :

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

However, the Petersen graph does not contain a subgraph isomorphic to 𝐾3 :

sage: g.subgraph_search(graphs.CompleteGraph(3)) is None


True

Nor does it contain a nonempty induced subgraph isomorphic to 𝑃6 :

sage: g.subgraph_search(graphs.PathGraph(6), induced=True) is None


True

The empty graph is a subgraph of every graph:

1.1. Generic graphs (common to directed/undirected) 185


Sage Reference Manual: Graph Theory, Release 8.4

sage: g.subgraph_search(graphs.EmptyGraph())
Graph on 0 vertices
sage: g.subgraph_search(graphs.EmptyGraph(), induced=True)
Graph on 0 vertices

The subgraph may just have edges missing:

sage: k3=graphs.CompleteGraph(3); p3=graphs.PathGraph(3)


sage: k3.relabel(list('abc'))
sage: s=k3.subgraph_search(p3)
sage: s.edges(labels=False)
[('a', 'b'), ('b', 'c')]

Of course, 𝑃3 is not an induced subgraph of 𝐾3 , though:

sage: k3=graphs.CompleteGraph(3); p3=graphs.PathGraph(3)


sage: k3.relabel(list('abc'))
sage: k3.subgraph_search(p3, induced=True) is None
True

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:

• subgraph_search() – finds an subgraph isomorphic to 𝐻 inside of a graph 𝐺


• subgraph_search_iterator() – Iterate on the copies of a graph 𝐻 inside of a graph 𝐺

EXAMPLES:
Counting the number of paths 𝑃5 in a PetersenGraph:

sage: g = graphs.PetersenGraph()
sage: g.subgraph_search_count(graphs.PathGraph(5))
240

Requiring these subgraphs be induced:

sage: g.subgraph_search_count(graphs.PathGraph(5), induced = True)


120

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

186 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

The empty graph is a subgraph of every graph:


sage: g.subgraph_search_count(graphs.EmptyGraph())
1

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 . . .

Note: This method also works on digraphs.

See also:

• subgraph_search() – finds an subgraph isomorphic to 𝐻 inside of 𝐺


• subgraph_search_count() – Counts the number of copies of 𝐻 inside of 𝐺

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)

1.1. Generic graphs (common to directed/undirected) 187


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


[2, 3, 4]
[3, 2, 1]
[4, 3, 2]

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

True for all trees [1]:

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)

188 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: T.plot() # long time
Graphics object consisting of 1101 graphics primitives

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)

1.1. Generic graphs (common to directed/undirected) 189


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


4: {0: None, 3: None, 9: None},
5: {0: None, 7: None, 8: None},
6: {1: None, 8: None, 9: None},
7: {2: None, 5: None, 9: None},
8: {3: None, 5: None, 6: None},
9: {4: None, 6: None, 7: None}}
sage: graphs.PetersenGraph().to_dictionary(edge_labels=True,multiple_
˓→edges=True)

{0: {1: [None], 4: [None], 5: [None]},


1: {0: [None], 2: [None], 6: [None]},
2: {1: [None], 3: [None], 7: [None]},
3: {2: [None], 4: [None], 8: [None]},
4: {0: [None], 3: [None], 9: [None]},
5: {0: [None], 7: [None], 8: [None]},
6: {1: [None], 8: [None], 9: [None]},
7: {2: [None], 5: [None], 9: [None]},
8: {3: [None], 5: [None], 6: [None]},
9: {4: [None], 6: [None], 7: [None]}}

to_simple(to_undirected=True, keep_label=’any’, immutable=None)


Returns a simple version of itself.
In particular, loops and multiple edges are removed, and the graph might optionally be converted to an
undirected graph.
INPUT:
• to_undirected - boolean - if True, the graph is also converted to an undirected graph.
• keep_label ('any','min','max'): if there are multiple edges with different labels, this vari-
able defines which label should be kept: any label ('any'), the smallest label ('min'), or the largest
('max').
• immutable (boolean) – whether to create a mutable/immutable copy. immutable=None (default)
means that the graph and its copy will behave the same way.
EXAMPLES:

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.

190 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

traveling_salesman_problem(use_edge_labels=False, maximize=False, solver=None,


constraint_generation=None, verbose=0, ver-
bose_constraints=False)
Solves the traveling salesman problem (TSP)
Given a graph (resp. a digraph) 𝐺 with weighted edges, the traveling salesman problem consists in finding
a Hamiltonian cycle (resp. circuit) of the graph of minimum cost.
This TSP is one of the most famous NP-Complete problems, this function can thus be expected to take
some time before returning its result.
INPUT:
• use_edge_labels (boolean) – whether to consider the weights of the edges.
– If set to False (default), all edges are assumed to weight 1
– If set to True, the weights are taken into account, and the circuit returned is the one minimizing
the sum of the weights (an edge with no label is assumed to have weight 1).

1.1. Generic graphs (common to directed/undirected) 191


Sage Reference Manual: Graph Theory, Release 8.4

• 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

The solution to the TSP has to be connected

sage: tsp.is_connected()
True

It must also be a 2-regular graph:

sage: tsp.is_regular(k=2)
True

And obviously it is a subgraph of the Heawood graph:

sage: tsp.is_subgraph(g, induced=False)


True

On the other hand, the Petersen Graph is known not to be Hamiltonian:

sage: g = graphs.PetersenGraph()
sage: tsp = g.traveling_salesman_problem()
Traceback (most recent call last):
(continues on next page)

192 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


...
EmptySetError: The given graph is not Hamiltonian

One easy way to change it is obviously to add to this graph the edges corresponding to a Hamiltonian
cycle. If we do this by setting the cost of these new edges to 2, while the others are set to 1, we notice that
not all the edges we added are used in the optimal solution

sage: for u, v in g.edges(labels = None):


....: g.set_edge_label(u,v,1)

sage: cycle = graphs.CycleGraph(10)


sage: for u,v in cycle.edges(labels = None):
....: if not g.has_edge(u,v):
....: g.add_edge(u,v)
....: g.set_edge_label(u,v,2)

sage: tsp = g.traveling_salesman_problem(use_edge_labels = True)


sage: sum( tsp.edge_labels() ) < 2*10
True

If we pick 1/2 instead of 2 as a cost for these new edges, they clearly become the optimal solution:

sage: for u,v in cycle.edges(labels = None):


....: g.set_edge_label(u,v,1/2)

sage: tsp = g.traveling_salesman_problem(use_edge_labels = True)


sage: sum( tsp.edge_labels() ) == (1/2)*10
True

Search for a minimum and a maximum weight Hamiltonian cycle:

sage: G = Graph([(0, 1, 1), (0, 2, 2), (0, 3, 1), (1, 2, 1), (1, 3, 2), (2, 3,
˓→ 1)])

sage: tsp = G.traveling_salesman_problem(use_edge_labels=True, maximize=False)


sage: print(sum(tsp.edge_labels()))
4
sage: tsp = G.traveling_salesman_problem(use_edge_labels=True, maximize=True)
sage: print(sum(tsp.edge_labels()))
6

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

1.1. Generic graphs (common to directed/undirected) 193


Sage Reference Manual: Graph Theory, Release 8.4

– None – for undirected graphs, uses "sparse_copy" or "dense_copy" depending on


whether the graph is stored as dense or sparse. For directed graphs, uses 'iter'.
EXAMPLES:
The Petersen graph is triangle free and thus:

sage: G = graphs.PetersenGraph()
sage: G.triangles_count()
0

Any triple of vertices in the complete graph induces a triangle so we have:

sage: G = graphs.CompleteGraph(150)
sage: G.triangles_count() == binomial(150,3)
True

The 2-dimensional DeBruijn graph of 2 symbols has 2 directed C3:

sage: G = digraphs.DeBruijn(2,2)
sage: G.triangles_count()
2

The directed n-cycle is trivially triangle free for n > 3:

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)

194 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: J.edges(labels=False)
[(0, 1), (0, 2), (0, 3), (1, 2), (2, 3)]

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']

sage: G.vertex_boundary(['0000', '1111'], l)


['0111', '0001', '0010', '0100', '1101', '1011']

sage: D = DiGraph({0:[1,2], 3:[0]})


sage: D.vertex_boundary([0])
[1, 2]

vertex_connectivity(G, value_only=True, sets=False, k=None, solver=None, verbose=0)


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

1.1. Generic graphs (common to directed/undirected) 195


Sage Reference Manual: Graph Theory, Release 8.4

• 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:

sage: from sage.graphs.connectivity import vertex_connectivity


sage: g=graphs.PappusGraph()
sage: vertex_connectivity(g)
3
sage: g.vertex_connectivity()
3

In a grid, the vertex connectivity is equal to the minimum degree, in which case one of the two sets is of
cardinality 1:

sage: g = graphs.GridGraph([ 3,3 ])


sage: [value, cut, [ setA, setB ]] = vertex_connectivity(g, sets=True)
sage: len(setA) == 1 or len(setB) == 1
True

A vertex cut in a tree is any internal vertex:

sage: tree = graphs.RandomTree(15)


sage: val, [cut_vertex] = vertex_connectivity(tree, value_only=False)
sage: tree.degree(cut_vertex) > 1
True

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

Or if they are just 1-connected:

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

A complete graph on 10 vertices is 9-connected:

196 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

sage: g = graphs.CompleteGraph(10)
sage: vertex_connectivity(g)
9

A complete digraph on 10 vertices is 9-connected:

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

vertex_cut(s, t, value_only=True, vertices=False, solver=None, verbose=0)


Returns a minimum vertex cut between non-adjacent vertices 𝑠 and 𝑡 represented by a list of vertices.
A vertex cut between two non-adjacent vertices is a set 𝑈 of vertices of self such that the graph ob-
tained by removing 𝑈 from self is disconnected. For more information, see the Wikipedia article
Cut_(graph_theory).
INPUT:
• value_only – boolean (default: True). When set to True, only the size of the minimum cut is
returned.
• vertices – boolean (default: False). When set to True, also returns the two sets of vertices that
are disconnected by the cut. Implies value_only set to False.
• 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:
Real number or tuple, depending on the given arguments (examples are given below).
EXAMPLES:
A basic application in the Pappus graph:

sage: g = graphs.PappusGraph()
sage: g.vertex_cut(1, 16, value_only=True)
3

In the bipartite complete graph 𝐾2,8 , a cut between the two vertices in the size 2 part consists of the other
8 vertices:

sage: g = graphs.CompleteBipartiteGraph(2, 8)
sage: [value, vertices] = g.vertex_cut(0, 1, value_only=False)
sage: print(value)
8
sage: vertices == list(range(2,10))
True

1.1. Generic graphs (common to directed/undirected) 197


Sage Reference Manual: Graph Theory, Release 8.4

Clearly, in this case the two sides of the cut are singletons

sage: [value, vertices, [set1, set2]] = g.vertex_cut(0,1, vertices=True)


sage: len(set1) == 1
True
sage: len(set2) == 1
True

vertex_disjoint_paths(s, t, solver=None, verbose=0)


Return a list of vertex-disjoint paths between two vertices.
The vertex version of Menger’s theorem asserts that the size of the minimum vertex cut between two
vertices 𝑠 and 𝑡 (the minimum number of vertices whose removal disconnects 𝑠 and 𝑡) is equal to the
maximum number of pairwise vertex-independent paths from 𝑠 to 𝑡.
This function returns a list of such paths.
INPUT:
• s,t – two vertices of the 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.
EXAMPLES:
In a complete bipartite graph

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)

198 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


1
2
3

Note that since the intersection option is available, the vertex_iterator() function is sub-optimal, speed-
wise, but note the following optimization:

sage: timeit V = P.vertices() # not tested


100000 loops, best of 3: 8.85 [micro]s per loop
sage: timeit V = list(P.vertex_iterator()) # not tested
100000 loops, best of 3: 5.74 [micro]s per loop
sage: timeit V = list(P._nxg.adj) # not tested
100000 loops, best of 3: 3.45 [micro]s per loop

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: timeit V = P.vertices() # not tested


100000 loops, best of 3: 8.85 [micro]s per loop
sage: timeit V = list(P.vertex_iterator()) # not tested
100000 loops, best of 3: 5.74 [micro]s per loop
sage: timeit V = list(P._nxg.adj) # not tested
100000 loops, best of 3: 3.45 [micro]s per loop

We illustrate various ways to use a key to sort the list:

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)

1.1. Generic graphs (common to directed/undirected) 199


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: H.vertices(key=lambda x: -x)
[26, 25, 24, 23, 22, ... 4, 3, 2, 1, 0]

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.

sage: t = polygen(QQ, 't')


sage: K = Graph({5*t:[t^2], t^2:[t^2+2], t^2+2:[4*t^2-6], 4*t^2-6:[5*t]})
sage: dsc = sage.rings.polynomial.polynomial_rational_flint.Polynomial_
˓→rational_flint.discriminant

sage: verts = K.vertices(key=dsc)


sage: verts
[t^2 + 2, t^2, 5*t, 4*t^2 - 6]
sage: [x.discriminant() for x in verts]
[-8, 0, 1, 96]

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:

sage: G = Graph({0:{1:'a'}}, sparse=True)


sage: H = Graph({0:{1:'b'}}, sparse=True)
sage: G == H
True

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

However, if both are weighted, then we finally compare ‘a’ to ‘b’:

200 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: G = Graph(sparse=True, weighted=True)


sage: G.add_edges([(0,1,1),(1,2,2),(0,2,3),(0,3,4)])
sage: M = G.weighted_adjacency_matrix(); M
[0 1 3 4]
[1 0 2 0]
[3 2 0 0]
[4 0 0 0]
sage: H = Graph(data=M, format='weighted_adjacency_matrix', sparse=True)
sage: H == G
True

wiener_index(by_weight=False, algorithm=None, weight_function=None, check_weight=True)


Return the Wiener index of the graph.
The graph is expected to have no cycles of negative weight.
The Wiener index of a graph 𝐺 is 𝑊 (𝐺) = 21 𝑢,𝑣∈𝐺 𝑑(𝑢, 𝑣) where 𝑑(𝑢, 𝑣) denotes the distance between
∑︀
vertices 𝑢 and 𝑣 (see [KRG96b]).
For more information on the input variables and more examples, we refer to shortest_paths() and
shortest_path_all_pairs(), which have very similar input variables.
INPUT:
• by_weight (boolean) - if True, the edges in the graph are weighted; if False, all edges have
weight 1.
• algorithm (string) - the algorithm to use:
– For by_weight==False only:

* '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:

* 'Dijkstra_Boost': the Dijkstra algorithm, implemented in Boost.


* 'Dijkstra_NetworkX': the Dijkstra algorithm, implemented in NetworkX. Usually
slower than 'Dijkstra_Boost'.
– For graphs with negative weights:

* 'Johnson_Boost': the Johnson algorithm, implemented in Boost.


* 'Floyd-Warshall-Python' - the Python implementation of the Floyd-Warshall algo-
rithm. Usually slower than 'Johnson_Boost'.
– None (default): Sage chooses the best algorithm: 'BFS' for unweighted graphs,
'Dijkstra_Boost' if all weights are positive, 'Johnson_Boost', otherwise.

1.1. Generic graphs (common to directed/undirected) 201


Sage Reference Manual: Graph Theory, Release 8.4

• 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.

202 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

[Graph on 6 vertices, [[0, 3], [1, 2], [4], [5]]]

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.graphs.generic_graph.tachyon_vertex_plot(g, bgcolor=(1, 1, 1), vertex_colors=None,


vertex_size=0.06, pos3d=None, **kwds)
Helper function for plotting graphs in 3d with Tachyon. Returns a plot containing only the vertices, as well as
the 3d position dictionary used for the plot.
INPUT:
• 𝑝𝑜𝑠3𝑑 - a 3D layout of the vertices

1.1. Generic graphs (common to directed/undirected) 203


Sage Reference Manual: Graph Theory, Release 8.4

• various rendering options


EXAMPLES:

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'>

1.2 Undirected graphs

This module implements functions and operations involving undirected graphs.


Algorithmically hard stuff

chromatic_index() Return the chromatic index of the graph.


chromatic_number() Return the minimal number of colors needed to color the vertices of the graph.
chromatic_polynomial() Compute the chromatic polynomial of the graph G.
Return the chromatic quasisymmetric function of self.
chromatic_quasisymmetric_function()
Return the chromatic symmetric function of self.
chromatic_symmetric_function()
coloring() Return the first (optimal) proper vertex-coloring found.
convexity_properties() Return a ConvexityProperties object corresponding to self.
has_homomorphism_to() Checks whether there is a homomorphism between two graphs.
independent_set() Return a maximum independent set.
Return an independent set of representatives.
independent_set_of_representatives()
is_perfect() Tests whether the graph is perfect.
matching_polynomial() Computes the matching polynomial of the graph 𝐺.
minor() Return the vertices of a minor isomorphic to 𝐻 in the current graph.
pathwidth() Computes the pathwidth of self (and provides a decomposition)
rank_decomposition() Computes an optimal rank-decomposition of the given graph.
topological_minor() Return a topological 𝐻-minor from self if one exists.
treewidth() Computes the tree-width of 𝐺 (and provides a decomposition)
tutte_polynomial() Return the Tutte polynomial of the graph 𝐺.
vertex_cover() Return a minimum vertex cover of self represented by a set of vertices.

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

204 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

clique_complex() Return the clique complex of self.


clique_maximum() Return the vertex set of a maximal order complete subgraph.
clique_number() Return the order of the largest clique of the graph
clique_polynomial() Return the clique polynomial of self.
Return the cliques containing each vertex, represented as a dictionary of lists of
cliques_containing_vertex()
lists, keyed by vertex.
Return a bipartite graph constructed such that maximal cliques are the right
cliques_get_clique_bipartite()
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.
Return the clique graph.
cliques_get_max_clique_graph()
cliques_maximal() Return the list of all maximal cliques.
cliques_maximum() Returns the vertex sets of ALL the maximum complete subgraphs.
cliques_number_of() Return a dictionary of the number of maximal cliques containing each vertex,
keyed by vertex.
Return a dictionary of sizes of the largest maximal cliques containing each ver-
cliques_vertex_clique_number()
tex, keyed by vertex.

Connectivity, orientations, trees

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

centrality_degree() Return the degree centrality of a vertex.

Graph properties

apex_vertices() Return the list of apex vertices.


is_apex() Test if the graph is apex.
is_arc_transitive() Returns true if self is an arc-transitive graph
Test if the input graph is asteroidal triple-free
is_asteroidal_triple_free()
is_biconnected() Test if the graph is biconnected.
is_block_graph() Return whether this graph is a block graph.
is_cactus() Check whether the graph is cactus graph.
is_cartesian_product() Tests whether the graph is a Cartesian product.
Continued on next page

1.2. Undirected graphs 205


Sage Reference Manual: Graph Theory, Release 8.4

Table 2 – continued from previous page


is_circumscribable() Test whether the graph is the graph of a circumscribed polyhedron.
is_cograph() Check whether the graph is cograph.
is_distance_regular() Tests if the graph is distance-regular
is_edge_transitive() Returns true if self is an edge transitive graph.
is_even_hole_free() Tests whether self contains an induced even hole.
is_forest() Tests if the graph is a forest, i.e. a disjoint union of trees.
is_half_transitive() Returns true if self is a half-transitive graph.
is_inscribable() Test whether the graph is the graph of an inscribed polyhedron.
is_line_graph() Tests wether the graph is a line graph.
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.
is_long_hole_free() Tests whether g contains an induced cycle of length at least 5.
is_odd_hole_free() Tests whether self contains an induced odd hole.
is_overfull() Tests whether the current graph is overfull.
is_partial_cube() Test whether the given graph is a partial cube.
is_polyhedral() Test whether the graph is the graph of the polyhedron.
is_prime() Test whether the current graph is prime.
is_semi_symmetric() Returns true if self is semi-symmetric.
is_split() Returns True if the graph is a Split graph, False otherwise.
is_strongly_regular() Tests whether self is strongly regular.
is_tree() Tests if the graph is a tree
is_triangle_free() Returns whether self is triangle-free
is_weakly_chordal() Tests whether the given graph is weakly chordal, i.e., the graph and its comple-
ment have no induced cycle of length at least 5.
odd_girth() Returns the odd girth of self.

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

206 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

1.2.1 Graph Format

Supported formats

Sage Graphs can be created from a wide range of inputs. A few examples are covered here.

1.2. Undirected graphs 207


Sage Reference Manual: Graph Theory, Release 8.4

• NetworkX dictionary format:

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.plot().show() # or G.show()

• A NetworkX graph:

sage: import networkx


sage: K = networkx.complete_bipartite_graph(12,7)
sage: G = Graph(K)
sage: G.degree()
[7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 12]

• graph6 or sparse6 format:

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.

In Python, the escaped character \ is represented by \\:

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.

208 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

sage: M = Matrix([(-1, 0, 0, 0, 1, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0),


....: ( 1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0),
....: ( 0, 1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0),
....: ( 0, 0, 1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0),
....: ( 0, 0, 0, 1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1),
....: ( 0, 0, 0, 0, 0,-1, 0, 0, 0, 1, 1, 0, 0, 0, 0),
....: ( 0, 0, 0, 0, 0, 0, 0, 1,-1, 0, 0, 1, 0, 0, 0),
....: ( 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, 0, 1, 0, 0),
....: ( 0, 0, 0, 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 1, 0),
....: ( 0, 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, 0, 0, 1)])
sage: M
[-1 0 0 0 1 0 0 0 0 0 -1 0 0 0 0]
[ 1 -1 0 0 0 0 0 0 0 0 0 -1 0 0 0]
[ 0 1 -1 0 0 0 0 0 0 0 0 0 -1 0 0]
[ 0 0 1 -1 0 0 0 0 0 0 0 0 0 -1 0]
[ 0 0 0 1 -1 0 0 0 0 0 0 0 0 0 -1]
[ 0 0 0 0 0 -1 0 0 0 1 1 0 0 0 0]
[ 0 0 0 0 0 0 0 1 -1 0 0 1 0 0 0]
[ 0 0 0 0 0 1 -1 0 0 0 0 0 1 0 0]
[ 0 0 0 0 0 0 0 0 1 -1 0 0 0 1 0]
[ 0 0 0 0 0 0 1 -1 0 0 0 0 0 0 1]
sage: G = Graph(M); G
Graph on 10 vertices
sage: G.plot().show() # or G.show()
sage: DiGraph(matrix(2,[0,0,-1,1]), format="incidence_matrix")
Traceback (most recent call last):
...
ValueError: There must be two nonzero entries (-1 & 1) per column.

• 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

Use graphs(n) to iterate through all non-isomorphic graphs of given size:


sage: for g in graphs(4):
....: print(g.degree_sequence())
[0, 0, 0, 0]
[1, 1, 0, 0]
[2, 1, 1, 0]
[3, 1, 1, 1]
[1, 1, 1, 1]
[2, 2, 1, 1]
[2, 2, 2, 0]
[3, 2, 2, 1]
(continues on next page)

1.2. Undirected graphs 209


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


[2, 2, 2, 2]
[3, 3, 2, 2]
[3, 3, 3, 3]

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:

sage: for g in graphs():


....: if g.chromatic_number() > 3:
....: break
sage: g.is_isomorphic(graphs.CompleteGraph(4))
True

For some commonly used graphs to play with, type

sage: graphs.[tab] # not tested

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

sage: G = GraphQuery(display_cols=['graph6'], num_vertices=7, diameter=5)


sage: L = G.get_graphs_list()
sage: graphs_list.show_graphs(L)

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:

210 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

sage: M = Matrix( [[0,0],[0,0]] )


sage: G = Graph({ 0 : { M : None } })
Traceback (most recent call last):
...
TypeError: mutable matrices are unhashable

However, if one wants to define a dictionary, with the same keys and arbitrary objects for entries, one can make that
association:

sage: d = {0 : graphs.DodecahedralGraph(), 1 : graphs.FlowerSnark(), \


2 : graphs.MoebiusKantorGraph(), 3 : graphs.PetersenGraph() }
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

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()
{...}

For more details on data types or keyword input, enter

sage: GraphQuery? # not tested

The results of a query can be viewed with the show method, or can be viewed individually by iterating through the
results:

sage: Q = GraphQuery(display_cols=['graph6'],num_vertices=7, diameter=5)


sage: Q.show()
Graph6
--------------------
F?`po
F?gqg
F@?]O
F@OKg
F@R@o
FA_pW
FEOhW
FGC{o
FIAHo

Show each graph as you iterate through the results:

sage: for g in Q:
....: show(g)

1.2. Undirected graphs 211


Sage Reference Manual: Graph Theory, Release 8.4

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.

sage: from sage.graphs.graph_latex import check_tkz_graph


sage: check_tkz_graph() # random - depends on TeX installation
sage: latex(G)
\begin{tikzpicture}
...
\end{tikzpicture}

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)`

sage: G_immutable = Graph(G, immutable=True)


sage: G_immutable == G
True
sage: {G_immutable:1}[G_immutable]
1

1.2.7 Methods

class sage.graphs.graph.Graph(data=None, pos=None, loops=None, format=None,


weighted=None, implementation=’c_graph’,
data_structure=’sparse’, vertex_labels=True, name=None,
multiedges=None, convert_empty_dict_labels_to_None=None,
sparse=True, immutable=False)
Bases: sage.graphs.generic_graph.GenericGraph
Undirected graph.
A graph is a set of vertices connected by edges. See the Wikipedia article Graph_(mathematics) for more
information. For a collection of pre-defined graphs, see the graph_generators module.
A Graph object has many methods whose list can be obtained by typing g.<tab> (i.e. hit the ‘tab’ key) or by
reading the documentation of graph, generic_graph, and digraph.

212 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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):

1. Graph() – build a graph on 0 vertices.


2. Graph(5) – return an edgeless graph on the 5 vertices 0,. . . ,4.
3. Graph([list_of_vertices,list_of_edges]) – returns a graph with given vertices/edges.
To bypass auto-detection, prefer the more explicit Graph([V,E],
format='vertices_and_edges').
4. Graph(list_of_edges) – return a graph with a given list of edges (see documentation of
add_edges()).
To bypass auto-detection, prefer the more explicit Graph(L, format='list_of_edges').
5. Graph({1:[2,3,4],3:[4]}) – return a graph by associating to each vertex the list of its neighbors.
To bypass auto-detection, prefer the more explicit Graph(D, format='dict_of_lists').
6. Graph({1: {2: 'a', 3:'b'} ,3:{2:'c'}}) – return a graph by associating a list of neigh-
bors to each vertex and providing its edge label.
To bypass auto-detection, prefer the more explicit Graph(D, format='dict_of_dicts').
For graphs with multiple edges, you can provide a list of labels instead, e.g.: Graph({1: {2:
['a1', 'a2'], 3:['b']} ,3:{2:['c']}}).
7. Graph(a_symmetric_matrix) – return a graph with given (weighted) adjacency matrix (see docu-
mentation of adjacency_matrix()).
To bypass auto-detection, prefer the more explicit Graph(M, format='adjacency_matrix').
To take weights into account, use format='weighted_adjacency_matrix' instead.
8. Graph(a_nonsymmetric_matrix) – return a graph with given incidence matrix (see documentation
of incidence_matrix()).
To bypass auto-detection, prefer the more explicit Graph(M, format='incidence_matrix').
9. Graph([V, f]) – return a graph from a vertex set V and a symmetric function f. The graph con-
tains an edge 𝑢, 𝑣 whenever f(u,v) is True.. Example: Graph([ [1..10], lambda x,y:
abs(x-y).is_square()])
10. Graph(':I`ES@obGkqegW~') – return a graph from a graph6 or sparse6 string (see documentation
of graph6_string() or sparse6_string()).
11. Graph(a_seidel_matrix, format='seidel_adjacency_matrix') – return a graph with
a given Seidel adjacency matrix (see documentation of seidel_adjacency_matrix()).
12. Graph(another_graph) – return a graph from a Sage (di)graph, pygraphviz graph, NetworkX graph,
or igraph graph.

• 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]}

1.2. Undirected graphs 213


Sage Reference Manual: Graph Theory, Release 8.4

• 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:

sage: g = Graph({0:{1:'x',2:'z',3:'a'}, 2:{5:'out'}}); g


Graph on 5 vertices

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.

214 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

sage: a,b,c,d,e,f = sorted(SymmetricGroup(3))


sage: Graph({b:{d:'c',e:'p'}, c:{d:'p',e:'c'}})
Graph on 4 vertices

3. A dictionary of lists:

sage: g = Graph({0:[1,2,3], 2:[4]}); g


Graph on 5 vertices

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=Graph([GF(13), lambda i,j: i!=j and (i-j).is_square()])


sage: g.vertices()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
sage: g.adjacency_matrix()
[0 1 0 1 1 0 0 0 0 1 1 0 1]
[1 0 1 0 1 1 0 0 0 0 1 1 0]
[0 1 0 1 0 1 1 0 0 0 0 1 1]
[1 0 1 0 1 0 1 1 0 0 0 0 1]
[1 1 0 1 0 1 0 1 1 0 0 0 0]
[0 1 1 0 1 0 1 0 1 1 0 0 0]
[0 0 1 1 0 1 0 1 0 1 1 0 0]
[0 0 0 1 1 0 1 0 1 0 1 1 0]
[0 0 0 0 1 1 0 1 0 1 0 1 1]
[1 0 0 0 0 1 1 0 1 0 1 0 1]
[1 1 0 0 0 0 1 1 0 1 0 1 0]
[0 1 1 0 0 0 0 1 1 0 1 0 1]
[1 0 1 1 0 0 0 0 1 1 0 1 0]

Construct the line graph of a complete graph.

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)

1.2. Undirected graphs 215


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


...
RuntimeError: The string seems corrupt: valid characters are
?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
sage: G = Graph('G??????')
Traceback (most recent call last):
...
RuntimeError: The string (G??????) seems corrupt: for n = 8, the string is
˓→too long.

sage: G = Graph(":I'AKGsaOs`cI]Gb~")
Traceback (most recent call last):
...
RuntimeError: The string seems corrupt: valid characters are
?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~

There are also list functions to take care of lists of graphs:

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:

216 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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: 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

Check that trac ticket #9714 is fixed:

sage: MA = Matrix([[1,2,0], [0,2,0], [0,0,1]])


sage: GA = Graph(MA, format='adjacency_matrix')
sage: MI = GA.incidence_matrix(oriented=False)
sage: MI
[2 1 1 0 0 0]
[0 1 1 2 2 0]
[0 0 0 0 0 2]
sage: Graph(MI).edges(labels=None)
[(0, 0), (0, 1), (0, 1), (1, 1), (1, 1), (2, 2)]

sage: M = Matrix([[1], [-1]]); M


[ 1]
[-1]
sage: Graph(M).edges()
[(0, 1, None)]

7. A Seidel adjacency matrix:

1.2. Undirected graphs 217


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.combinat.matrices.hadamard_matrix import \


....: regular_symmetric_hadamard_matrix_with_constant_diagonal as rshcd
sage: m=rshcd(16,1)- matrix.identity(16)
sage: Graph(m,format="seidel_adjacency_matrix").is_strongly_
˓→regular(parameters=True)

(16, 6, 2, 2)

8. a list of edges, or labelled edges:

sage: g = Graph([(1,3),(3,8),(5,2)])
sage: g
Graph on 5 vertices

sage: g = Graph([(1,2,"Peace"),(7,-9,"and"),(77,2, "Love")])


sage: g
Graph on 5 vertices
sage: g = Graph([(0, 2, '0'), (0, 2, '1'), (3, 3, '2')], loops=True,
˓→multiedges=True)

sage: g.loops()
[(3, 3, '2')]

9. A NetworkX MultiGraph:

sage: import networkx


sage: g = networkx.MultiGraph({0:[1,2,3], 2:[4]})
sage: Graph(g)
Graph on 5 vertices

10. A NetworkX graph:

sage: import networkx


sage: g = networkx.Graph({0:[1,2,3], 2:[4]})
sage: DiGraph(g)
Digraph on 5 vertices

11. An igraph Graph (see also igraph_graph()):

sage: import igraph # optional - python_igraph


sage: g = igraph.Graph([(0,1),(0,2)]) # optional - python_igraph
sage: Graph(g) # optional - python_igraph
Graph on 3 vertices

If vertex_labels is True, the names of the vertices are given by the vertex attribute 'name', if
available:

sage: g = igraph.Graph([(0,1),(0,2)], vertex_attrs={'name':['a','b','c']}) #


˓→optional - python_igraph

sage: Graph(g).vertices() #
˓→optional - python_igraph

['a', 'b', 'c']


sage: g = igraph.Graph([(0,1),(0,2)], vertex_attrs={'label':['a','b','c']}) #
˓→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:

218 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

sage: g = igraph.Graph([(0,1),(0,2)], edge_attrs={'name':['a','b'], 'weight


˓→':[1,3]}) # optional - python_igraph

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:

sage: f_sym = lambda x,y : abs(x-y) == 1


sage: f_nonsym = lambda x,y : (x-y) == 1
sage: G_sym = Graph([[4,6,1,5,3,7,2,0], f_sym])
sage: G_sym.is_isomorphic(graphs.PathGraph(8))
True
sage: G_nonsym = Graph([[4,6,1,5,3,7,2,0], f_nonsym])
sage: G_nonsym.size()
4
sage: G_nonsym.is_isomorphic(G_sym)
False

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)`

When providing the optional arguments data_structure="static_sparse" or immutable=True


(both mean the same), then an immutable graph results.

sage: G_imm = Graph(G, immutable=True)


sage: H_imm = Graph(G, data_structure='static_sparse')
sage: G_imm == H_imm == G
True
sage: {G_imm:1}[H_imm]
1

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:

1.2. Undirected graphs 219


Sage Reference Manual: Graph Theory, Release 8.4

• 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']

The Petersen graph is not apex:

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()
[]

Neighbors of an apex of degree 2 are apex:

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)]

220 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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.

bounded_outdegree_orientation(bound, solver=None, verbose=False)


Computes an orientation of self such that every vertex 𝑣 has out-degree less than 𝑏(𝑣)
INPUT:
• bound – Maximum bound on the out-degree. Can be of three different types :

• 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 ⌉:

1.2. Undirected graphs 221


Sage Reference Manual: Graph Theory, Release 8.4

sage: g = graphs.RandomGNP(40, .4)


sage: b = lambda v : ceil(g.degree(v)/2)
sage: D = g.bounded_outdegree_orientation(b)
sage: all( D.out_degree(v) <= b(v) for v in g )
True

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))

While this is not:

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:

sage: from sage.graphs.connectivity import bridges


sage: from sage.graphs.connectivity import is_connected
sage: g = 2*graphs.PetersenGraph()
sage: g.add_edge(1,10)
sage: is_connected(g)
True
sage: bridges(g)
[(1, 10, None)]
sage: g.bridges()
[(1, 10, None)]

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.

222 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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:

• Wikipedia article Edge_coloring for further details on edge coloring


• sage.graphs.graph_coloring.edge_coloring()
• fractional_chromatic_index()
• chromatic_number()

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

The path 𝑃𝑛 with 𝑛 ≥ 2 has chromatic index 2:

sage: graphs.PathGraph(5).chromatic_index()
2

The windmill graph with parameters 𝑘, 𝑛 has chromatic index (𝑘 − 1)𝑛:

1.2. Undirected graphs 223


Sage Reference Manual: Graph Theory, Release 8.4

sage: k,n = 3,4


sage: G = graphs.WindmillGraph(k,n)
sage: G.chromatic_index() == (k-1)*n
True

chromatic_number(algorithm=’DLX’, solver=None, verbose=0)


Return the minimal number of colors needed to color the vertices of the graph.
INPUT:
• algorithm – Select an algorithm from the following supported algorithms:
– If algorithm="DLX" (default), the chromatic number is computed using the dancing link
algorithm. It is inefficient speedwise to compute the chromatic number through the dancing link
algorithm because this algorithm computes all the possible colorings to check that one exists.
– If algorithm="CP", the chromatic number is computed using the coefficients of the chromatic
polynomial. Again, this method is inefficient in terms of speed and it only useful for small graphs.
– If algorithm="MILP", the chromatic number is computed using a mixed integer linear pro-
gram. The performance of this implementation is affected by whether optional MILP solvers have
been installed (see the MILP module, or Sage’s tutorial on Linear Programming).
– 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 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({0: [1, 2, 3], 1: [2]})


sage: G.chromatic_number(algorithm="DLX")
3
sage: G.chromatic_number(algorithm="MILP")
3
sage: G.chromatic_number(algorithm="CP")
3

A bipartite graph has (by definition) chromatic number 2:

sage: graphs.RandomBipartite(50,50,0.7).chromatic_number()
2

A complete multipartite graph with k parts has chromatic number k:

sage: all(graphs.CompleteMultipartiteGraph([5]*i).chromatic_number() == i for


˓→i in range(2,5))

True

The complete graph has the largest chromatic number from all the graphs of order n. Namely its chromatic
number is n:

sage: all(graphs.CompleteGraph(i).chromatic_number() == i for i in range(10))


True

224 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

The Kneser graph with parameters (n,2) for n > 3 has chromatic number n-2:

sage: all(graphs.KneserGraph(i,2).chromatic_number() == i-2 for i in range(4,


˓→6))

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)

sage: C(2) # long time


0

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)

1.2. Undirected graphs 225


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: min(i for i in range(11) if P(i) > 0) == G.chromatic_number()
True

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]

Not all chromatic quasisymmetric functions are symmetric:


sage: G = Graph([[1,2], [1,5], [3,4], [3,5]])
sage: G.chromatic_quasisymmetric_function().is_symmetric()
False

We check that at 𝑡 = 1, we recover the usual chromatic symmetric function:


sage: p = SymmetricFunctions(QQ).p()
sage: G = graphs.CycleGraph(5)
sage: XG = G.chromatic_quasisymmetric_function(t=1); XG
120*M[1, 1, 1, 1, 1] + 30*M[1, 1, 1, 2] + 30*M[1, 1, 2, 1]
+ 30*M[1, 2, 1, 1] + 10*M[1, 2, 2] + 30*M[2, 1, 1, 1]
+ 10*M[2, 1, 2] + 10*M[2, 2, 1]
(continues on next page)

226 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: p(XG.to_symmetric_function())
p[1, 1, 1, 1, 1] - 5*p[2, 1, 1, 1] + 5*p[2, 2, 1]
+ 5*p[3, 1, 1] - 5*p[3, 2] - 5*p[4, 1] + 4*p[5]

sage: G = graphs.ClawGraph()
sage: XG = G.chromatic_quasisymmetric_function(t=1); XG
24*M[1, 1, 1, 1] + 6*M[1, 1, 2] + 6*M[1, 2, 1] + M[1, 3]
+ 6*M[2, 1, 1] + M[3, 1]
sage: p(XG.to_symmetric_function())
p[1, 1, 1, 1] - 3*p[2, 1, 1] + 3*p[3, 1] - p[4]

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]

Not all graphs have a positive Schur expansion:

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)

1.2. Undirected graphs 227


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: G3.delete_edge([1,3])
sage: XG3 = G3.chromatic_symmetric_function()
sage: XG == XG1 + XG2 - XG3
True

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: from sage.graphs.connectivity import cleave


sage: G = Graph(2)
sage: for _ in range(3):
....: G.add_clique([0, 1, G.add_vertex(), G.add_vertex()])
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, 4)
sage: f1.vertices(), f1.edges()
([0, 1], [])

If virtual_edges == False and there is an edge between cut vertices:

228 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

sage: G.subgraph([0, 1]).complement() == Graph([[0, 1], []])


True
sage: S2,C2,f2 = cleave(G, cut_vertices=[0, 1], virtual_edges = False)
sage: (S1 == S2, C1 == C2, f1 == f2)
(True, True, True)

If cut vertices doesn’t have edge between them:

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:

sage: G.subgraph([0, 1]).complement() == Graph([[0, 1], []])


False
sage: S2,C2,f2 = cleave(G, cut_vertices=[0, 1], virtual_edges = False)
sage: [g.order() for g in S2]
[4, 4, 4]
sage: C2.order(), C2.size()
(2, 0)
sage: f2.vertices(), f2.edges()
([0, 1], [])
sage: (S1 == S2, C1 == C2, f1 == f2)
(False, False, False)

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)}

(continues on next page)

1.2. Undirected graphs 229


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: h = Graph({0:[1,2,3,4],1:[2,3,4],2:[3]})
sage: x = h.clique_complex()
sage: x
Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(0, 1, 4), (0,
˓→1, 2, 3)}

sage: i = x.graph()
sage: i==h
True
sage: x==i.clique_complex()
True

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]

Through a Linear Program:

sage: len(C.clique_maximum(algorithm = "MILP"))


4

clique_number(algorithm=’Cliquer’, cliques=None, solver=None, verbose=0)


Return the order of the largest clique of the graph
This is also called as the clique number.

Note: Currently only implemented for undirected graphs. Use to_undirected to convert a digraph to
an undirected graph.

230 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

By definition the clique number of a complete graph is its order:

sage: all(graphs.CompleteGraph(i).clique_number() == i for i in range(1,15))


True

A non-empty graph without edges has a clique number of 1:

sage: all((i*graphs.CompleteGraph(1)).clique_number() == 1 for i in range(1,


˓→15))

True

A complete multipartite graph with k parts has clique number k:

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:

1.2. Undirected graphs 231


Sage Reference Manual: Graph Theory, Release 8.4

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)]]}

sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})


sage: G.show(figsize=[2,2])
sage: G.cliques_containing_vertex()
{0: [[0, 1, 2], [0, 1, 3]], 1: [[0, 1, 2], [0, 1, 3]], 2: [[0, 1, 2]], 3: [[0,
˓→ 1, 3]]}

cliques_get_clique_bipartite(**kwds)
Return a bipartite graph constructed such that maximal cliques are the right vertices and the left vertices

232 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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)

sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})


sage: G.show(figsize=[2,2])
sage: G.cliques_get_clique_bipartite()
Bipartite graph on 6 vertices
sage: (G.cliques_get_clique_bipartite()).show(figsize=[2,2])

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)

sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})


sage: G.show(figsize=[2,2])
sage: G.cliques_get_max_clique_graph()
Graph on 2 vertices
sage: (G.cliques_get_max_clique_graph()).show(figsize=[2,2])

cliques_maximal(algorithm=’native’)
Return the list of all maximal cliques.
Each clique is represented by a list of vertices. A clique is an induced complete subgraph, and a maximal
clique is one not contained in a larger one.
INPUT:
• algorithm – can be set to "native" (default) to use Sage’s own implementation, or
to "NetworkX" to use NetworkX’ implementation of the Bron and Kerbosch Algorithm
[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.

1.2. Undirected graphs 233


Sage Reference Manual: Graph Theory, Release 8.4

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]]

Comparing the two implementations:

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:

sage: graphs.ChvatalGraph().cliques_maximum() # indirect doctest


[[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]]
(continues on next page)

234 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
sage: G.show(figsize=[2,2])
sage: G.cliques_maximum()
[[0, 1, 2], [0, 1, 3]]
sage: C=graphs.PetersenGraph()
sage: C.cliques_maximum()
[[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_maximum()
[[1, 2, 3, 4]]

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}

cliques_vertex_clique_number(algorithm=’cliquer’, vertices=None, cliques=None)


Return a dictionary of sizes of the largest maximal cliques containing each vertex, keyed by vertex.
Returns a single value if only one input vertex.

1.2. Undirected graphs 235


Sage Reference Manual: Graph Theory, Release 8.4

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].

• vertices - the vertices to inspect (default is entire graph). Ignored unless


algorithm=='networkx'.
• cliques - list of cliques (if already computed). Ignored unless algorithm=='networkx'.

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}

coloring(algorithm=’DLX’, hex_colors=False, verbose=0)


Return the first (optimal) proper vertex-coloring found.
INPUT:
• algorithm – Select an algorithm from the following supported algorithms:
– If algorithm="DLX" (default), the coloring is computed using the dancing link algorithm.
– If algorithm="MILP", the coloring is computed using a mixed integer linear program. The
performance of this implementation is affected by whether optional MILP solvers have been
installed (see the MILP module).
• hex_colors – (default: False) if True, return a dictionary which can easily be used for plotting.

236 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

• 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]

Is a terrible waste of computations, while

sage: g = graphs.PetersenGraph()
sage: CP = g.convexity_properties()
sage: CP.hull([1, 3])
[1, 2, 3]
(continues on next page)

1.2. Undirected graphs 237


Sage Reference Manual: Graph Theory, Release 8.4

238 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: CP.hull([3, 7])
[2, 3, 7]

Makes perfect sense.

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().

1.2. Undirected graphs 239


Sage Reference Manual: Graph Theory, Release 8.4

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: [v for v,c in cores.items() if c>=2] # the vertices in the 2-core


[0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

Checking the 2-core of a random lobster is indeed the empty set:

sage: g = graphs.RandomLobster(20,.5,.5)
sage: ordering, core = g.cores(2)
sage: len(core) == 0
True

degree_constrained_subgraph(bounds, solver=None, verbose=0)


Returns a degree-constrained subgraph.
Given a graph 𝐺 and two functions 𝑓, 𝑔 : 𝑉 (𝐺) → Z such that 𝑓 ≤ 𝑔, a degree-constrained subgraph in
𝐺 is a subgraph 𝐺′ ⊆ 𝐺 such that for any vertex 𝑣 ∈ 𝐺, 𝑓 (𝑣) ≤ 𝑑𝐺′ (𝑣) ≤ 𝑔(𝑣).
INPUT:
• bounds – (default: None) Two possibilities:
– A dictionary whose keys are the vertices, and values a pair of real values (min,max) corre-
sponding to the values (𝑓 (𝑣), 𝑔(𝑣)).
– A function associating to each vertex a pair of real values (min,max) corresponding to the
values (𝑓 (𝑣), 𝑔(𝑣)).
• 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:
• When a solution exists, this method outputs the degree-constained subgraph as a Graph object.
• When no solution exists, returns False.

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:

240 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

Is there a perfect matching in an even cycle?

sage: g = graphs.CycleGraph(6)
sage: bounds = lambda x: [1,1]
sage: m = g.degree_constrained_subgraph(bounds=bounds)
sage: m.size()
3

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]]

Ear decomposition of a biconnected graph:

sage: g = graphs.CubeGraph(2)
sage: g.ear_decomposition()
[['00', '01', '11', '10', '00']]

Ear decomposition of a connected but not biconnected graph:

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]]

1.2. Undirected graphs 241


Sage Reference Manual: Graph Theory, Release 8.4

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

fractional_chromatic_index(solver=’PPL’, verbose_constraints=False, verbose=0)


Return the fractional chromatic index of the graph.
The fractional chromatic index is a relaxed version of edge-coloring. An edge coloring of a graph being
actually a covering of its edges into the smallest possible number of matchings, the fractional chromatic
index of a graph 𝐺 is the smallest real value 𝜒𝑓 (𝐺) such that there exists a list of matchings 𝑀1 , ..., 𝑀𝑘 of
𝐺 and coefficients 𝛼1 , ..., 𝛼𝑘 with the property that each edge is covered by the matchings in the following
relaxed way
∑︁
∀𝑒 ∈ 𝐸(𝐺), 𝛼𝑖 ≥ 1
𝑒∈𝑀𝑖

For more information, see the Wikipedia article Fractional_coloring.


ALGORITHM:
The fractional chromatic index is computed through Linear Programming through its dual. The LP solved
by sage is actually:
∑︁
Maximize : 𝑟𝑒
𝑒∈𝐸(𝐺)

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.

• verbose_constraints – boolean (default: False) whether to display which constraints are


being generated.
• verbose – integer (default: 0) level of verbosity required from the LP solver
EXAMPLES:
The fractional chromatic index of a 𝐶5 is 5/2:

242 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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()

Obviously, this graph is a 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:

sage: all([ t.flow(u,v) == g.flow(u,v) for u,v in Subsets( g.vertices(), 2 )


˓→])

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

And also the min cut:

1.2. Undirected graphs 243


Sage Reference Manual: Graph Theory, Release 8.4

sage: g.edge_connectivity() == min(t.edge_labels())


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:

• dig6_string() – a similar string format for directed graphs

EXAMPLES:

sage: G = graphs.KrackhardtKiteGraph()
sage: G.graph6_string()
'IvUqwK@?G'

has_homomorphism_to(H, core=False, solver=None, verbose=0)


Checks whether there is a homomorphism between two graphs.
A homomorphism from a graph 𝐺 to a graph 𝐻 is a function 𝜑 : 𝑉 (𝐺) ↦→ 𝑉 (𝐻) such that for any edge
𝑢𝑣 ∈ 𝐸(𝐺) the pair 𝜑(𝑢)𝜑(𝑣) is an edge of 𝐻.
Saying that a graph can be 𝑘-colored is equivalent to saying that it has a homomorphism to 𝐾𝑘 , the
complete graph on 𝑘 elements.
For more information, see the Wikipedia article Graph_homomorphism.
INPUT:
• H – the graph to which self should be sent.
• core (boolean) – whether to minimize the size of the mapping’s image (see note below). This is set
to False by default.
• solver – (default: None) Specify a Linear Program (LP) solver to be used. If set to None, the
default one is used. For more information on LP solvers and which default solver is used, see the
method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0). Sets the level of verbosity. Set to 0 by default, which means quiet.

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 𝐺.

244 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

has_perfect_matching(algorithm=’Edmonds’, solver=None, verbose=0)


Return whether this graph has a perfect matching.
INPUT:
• algorithm – string (default: "Edmonds")
– "Edmonds" uses Edmonds’ algorithm as implemented in NetworkX to find a matching of max-
imal cardinality, then check whether this cardinality is half the number of vertices of the graph.
– "LP_matching" uses a Linear Program to find a matching of maximal cardinality, then check
whether this cardinality is half the number of vertices of the graph.
– "LP" uses a Linear Program formulation of the perfect matching problem: put a binary variable
b[e] on each edge e, and for each vertex v, require that the sum of the values of the edges
incident to v is 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_matching" or algorithm == "LP")
For more information on LP solvers and which default solver is used, see the method solve of the class
MixedIntegerLinearProgram.
OUTPUT:
A boolean.
EXAMPLES:

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)

1.2. Undirected graphs 245


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


False
sage: graphs.PetersenGraph().has_perfect_matching(algorithm="LP_matching")
True
sage: graphs.WheelGraph(6).has_perfect_matching(algorithm="LP_matching")
True
sage: graphs.WheelGraph(5).has_perfect_matching(algorithm="LP_matching")
False

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

246 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

– If algorithm = "Cliquer" (default), the problem is solved using Cliquer [NisOst2003].


(see the Cliquer modules)
– 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.

• 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

independent_set_of_representatives(family, solver=None, verbose=0)


Return an independent set of representatives.
Given a graph 𝐺 and a family 𝐹 = {𝐹𝑖 : 𝑖 ∈ [1, ..., 𝑘]} of subsets of g.vertices(), an Independent
Set of Representatives (ISR) is an assignation of a vertex 𝑣𝑖 ∈ 𝐹𝑖 to each set 𝐹𝑖 such that 𝑣𝑖 ! = 𝑣𝑗 if 𝑖 < 𝑗
(they are representatives) and the set ∪𝑖 𝑣𝑖 is an independent set in 𝐺.
It generalizes, for example, graph coloring and graph list coloring.
(See [AhaBerZiv07] for more information.)
INPUT:
• family – A list of lists defining the family 𝐹 (actually, a Family of subsets of G.vertices()).

1.2. Undirected graphs 247


Sage Reference Manual: Graph Theory, Release 8.4

248 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.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:

1.2. Undirected graphs 249


Sage Reference Manual: Graph Theory, Release 8.4

sage: G = graphs.CompleteGraph(5)
sage: G.is_apex()
True
sage: G = graphs.CompleteBipartiteGraph(3,3)
sage: G.is_apex()
True

The Petersen graph is not apex:

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:

• Wikipedia article arc-transitive_graph


• is_edge_transitive()
• is_half_transitive()
• is_semi_symmetric()

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:

250 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

• 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

The PetersenGraph is not AT-free:

sage: from sage.graphs.asteroidal_triples import *


sage: G = graphs.PetersenGraph()
sage: G.is_asteroidal_triple_free()
False
sage: G.is_asteroidal_triple_free(certificate=True)
(False, [0, 2, 6])

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.

1.2. Undirected graphs 251


Sage Reference Manual: Graph Theory, Release 8.4

A block graph is a connected graph in which every biconnected component (block) is a clique.
See also:

• Wikipedia article Block_graph for more details on these graphs


• RandomBlockGraph() – generator of random block graphs
• blocks_and_cut_vertices()
• blocks_and_cuts_tree()

EXAMPLES:

sage: G = graphs.RandomBlockGraph(6, 2, kmax=4)


sage: G.is_block_graph()
True
sage: from sage.graphs.isgci import graph_classes
sage: G in graph_classes.Block
True
sage: graphs.CompleteGraph(4).is_block_graph()
True
sage: graphs.RandomTree(6).is_block_graph()
True
sage: graphs.PetersenGraph().is_block_graph()
False
sage: Graph(4).is_block_graph()
False

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

is_cartesian_product(g, certificate=False, relabeling=False)


Tests whether the graph is a Cartesian product.
INPUT:

252 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

• 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

A 2d grid is the product of paths:


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

Forgetting the graph’s labels, then finding them back:


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

1.2. Undirected graphs 253


Sage Reference Manual: Graph Theory, Release 8.4

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

Stellating in a face of the octahedral graph is not circumscribable:

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()

Todo: Allow the use of other, inexact but faster solvers.

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

254 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

1.2. Undirected graphs 255


Sage Reference Manual: Graph Theory, Release 8.4

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:

• Wikipedia article Edge-transitive_graph


• is_arc_transitive()
• is_half_transitive()
• is_semi_symmetric()

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:

256 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

sage: g = graphs.RandomBipartite(10, 10, .5)


sage: g.is_even_hole_free() and not g.is_forest()
False

We can check the certificate returned is indeed an even cycle:

sage: if not g.is_forest():


....: cycle = g.is_even_hole_free(certificate = True)
....: if cycle.order() % 2 == 1:
....: print("Error !")
....: if not cycle.is_isomorphic(
....: graphs.CycleGraph(cycle.order())):
....: print("Error !")
...
sage: print("Everything is Fine !")
Everything is Fine !

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:

sage: seven_acre_wood = sum(graphs.trees(7), Graph())


sage: seven_acre_wood.is_forest()
True

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:

• Wikipedia article half-transitive_graph


• is_edge_transitive()
• is_arc_transitive()
• is_semi_symmetric()

1.2. Undirected graphs 257


Sage Reference Manual: Graph Theory, Release 8.4

EXAMPLES:
The Petersen Graph is not half-transitive:

sage: P = graphs.PetersenGraph()
sage: P.is_half_transitive()
False

The smallest half-transitive graph is the Holt Graph:

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

Cutting off a vertex from the cube yields an uninscribable graph:

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

Breaking a face of the cube yields an uninscribable graph:

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

258 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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:

• The line_graph module.


• line_graph_forbidden_subgraphs() – the forbidden subgraphs of a line graph.
• line_graph()

EXAMPLES:
A complete graph is always the line graph of a star:

sage: graphs.CompleteGraph(5).is_line_graph()
True

The Petersen Graph not being claw-free, it is not a line graph:

sage: graphs.PetersenGraph().is_line_graph()
False

This is indeed the subgraph returned:

sage: C = graphs.PetersenGraph().is_line_graph(certificate = True)[1]


sage: C.is_isomorphic(graphs.ClawGraph())
True

The house graph is a line graph:

1.2. Undirected graphs 259


Sage Reference Manual: Graph Theory, Release 8.4

sage: g = graphs.HouseGraph()
sage: g.is_line_graph()
True

But what is the graph whose line graph is the house ?:

sage: is_line, R, isom = g.is_line_graph(certificate = True)


sage: R.sparse6_string()
':DaHI~'
sage: R.show()
sage: isom
{0: (0, 1), 1: (0, 2), 2: (1, 3), 3: (2, 3), 4: (3, 4)}

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

The complement of a cycle is an antihole:

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

260 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

The following graph contains a hole, which we want to display:

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

1.2. Undirected graphs 261


Sage Reference Manual: Graph Theory, Release 8.4

sage: g = graphs.PetersenGraph()
sage: g.is_odd_hole_free()
False

Which was to be expected, as its girth is 5

sage: g.girth()
5

We can check the certificate returned is indeed a 5-cycle:

sage: cycle = g.is_odd_hole_free(certificate = True)


sage: cycle.is_isomorphic(graphs.CycleGraph(5))
True

As any chordal graph is hole-free, no interval graph has an odd hole:

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

The claw graph is not overfull:

sage: from sage.graphs.graph_coloring import edge_coloring


sage: g = graphs.ClawGraph()
sage: g
Claw graph: Graph on 4 vertices
sage: edge_coloring(g, value_only=True)
3
sage: g.is_overfull()
False

The Holt graph is an example of a overfull graph:

262 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

sage: G = graphs.HoltGraph()
sage: G.is_overfull()
True

Checking that all complete graphs 𝐾𝑛 for even 0 ≤ 𝑛 ≤ 100 are not overfull:

sage: def check_overfull_Kn_even(n):


....: i = 0
....: while i <= n:
....: if graphs.CompleteGraph(i).is_overfull():
....: print("A complete graph of even order cannot be overfull.")
....: return
....: i += 2
....: print("Complete graphs of even order up to %s are not overfull." %
˓→n)

...
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:

sage: def check_overfull_Kn_odd(n):


....: i = 3
....: while i <= n:
....: if not graphs.CompleteGraph(i).is_overfull():
....: print("A complete graph of odd order > 1 must be overfull.")
....: return
....: i += 2
....: print("Complete graphs of odd order > 1 up to %s are overfull." % n)
...
sage: check_overfull_Kn_odd(100) # long time
Complete graphs of odd order > 1 up to 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

1.2. Undirected graphs 263


Sage Reference Manual: Graph Theory, Release 8.4

documentation 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 function returns (True, mapping), where mapping is an isometric mapping of the vertices
of the graph to the vertices of a hypercube ((0, 1)-strings of a fixed length). When certificate
= True and the graph is not a partial cube, (False, None) is returned.
EXAMPLES:
The Petersen graph is not a partial cube:

sage: g = graphs.PetersenGraph()
sage: g.is_partial_cube()
False

All prisms are partial cubes:

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

So is the line graph of a bipartite graph:

sage: g = graphs.RandomBipartite(4,3,0.7)
sage: g.line_graph().is_perfect() # long time
True

As well as the Cartesian product of two complete graphs:

264 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

sage: g = graphs.CompleteGraph(3).cartesian_product(graphs.CompleteGraph(3))
sage: g.is_perfect()
True

Interval Graphs, which are chordal graphs, too

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

We can obtain an induced 5-cycle as a certificate:

sage: g.is_perfect(certificate = True)


Subgraph of (Petersen graph): Graph on 5 vertices

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().

1.2. Undirected graphs 265


Sage Reference Manual: Graph Theory, Release 8.4

EXAMPLES:
The Petersen Graph and the Bull Graph are both prime:
sage: graphs.PetersenGraph().is_prime()
True
sage: graphs.BullGraph().is_prime()
True

Though quite obviously, the disjoint union of them is not:


sage: (graphs.PetersenGraph() + graphs.BullGraph()).is_prime()
False

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:

• Wikipedia article Semi-symmetric_graph


• is_edge_transitive()
• is_arc_transitive()
• is_half_transitive()

EXAMPLES:
The Petersen graph is not semi-symmetric:
sage: P = graphs.PetersenGraph()
sage: P.is_semi_symmetric()
False

The Gray graph is the smallest possible cubic semi-symmetric graph:


sage: G = graphs.GrayGraph()
sage: G.is_semi_symmetric()
True

Another well known semi-symmetric graph is the Ljubljana graph:


sage: L = graphs.LjubljanaGraph()
sage: L.is_semi_symmetric()
True

is_split()
Returns True if the graph is a Split graph, False otherwise.
A Graph 𝐺 is said to be a split graph if its vertices 𝑉 (𝐺) can be partitioned into two sets 𝐾 and 𝐼 such
that the vertices of 𝐾 induce a complete graph, and those of 𝐼 are an independent set.
There is a simple test to check whether a graph is a split graph (see, for instance, the book “Graph Classes,
a survey” [GraphClasses] page 203) :
Given the degree sequence 𝑑1 ≥ ... ≥ 𝑑𝑛 of 𝐺, a graph is a split graph if and only if :
𝜔
∑︁ 𝑛
∑︁
𝑑𝑖 = 𝜔(𝜔 − 1) + 𝑑𝑖
𝑖=1 𝑖=𝜔+1

266 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

where 𝜔 = 𝑚𝑎𝑥{𝑖 : 𝑑𝑖 ≥ 𝑖 − 1}.


EXAMPLES:
Split graphs are, in particular, chordal graphs. Hence, The Petersen graph can not be split:

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:

sage: sum([g.subgraph_search_count(H,induced=True) for H in [graphs.


˓→CycleGraph(4),graphs.CycleGraph(5), 2*graphs.CompleteGraph(2)]])

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)

And Clebsch’s graph is too:

1.2. Undirected graphs 267


Sage Reference Manual: Graph Theory, Release 8.4

sage: g = graphs.ClebschGraph()
sage: g.is_strongly_regular()
True
sage: g.is_strongly_regular(parameters = True)
(16, 5, 0, 2)

But Chvatal’s graph is not:

sage: g = graphs.ChvatalGraph()
sage: g.is_strongly_regular()
False

Complete graphs are not strongly regular. (trac ticket #14297)

sage: g = graphs.CompleteGraph(5)
sage: g.is_strongly_regular()
False

Completements of complete graphs are not strongly regular:

sage: g = graphs.CompleteGraph(5).complement()
sage: g.is_strongly_regular()
False

The empty graph is not strongly regular:

sage: g = graphs.EmptyGraph()
sage: g.is_strongly_regular()
False

If the input graph has loops or multiedges an exception is raised:

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.

268 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

• 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:

sage: all(T.is_tree() for T in graphs.trees(15))


True

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

One can also ask for the certificate as a list of edges:

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)])

This is useful for graphs with multiple edges:

sage: G = Graph([(1, 2, 'a'), (1, 2, 'b')], multiedges=True)


sage: G.is_tree(certificate=True)
(False, [1, 2])
sage: G.is_tree(certificate=True, output='edge')
(False, [(1, 2, 'a'), (2, 1, 'b')])

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

or a complete Bipartite Graph:

1.2. Undirected graphs 269


Sage Reference Manual: Graph Theory, Release 8.4

sage: G = graphs.CompleteBipartiteGraph(5,6)
sage: G.is_triangle_free(algorithm='matrix')
True
sage: G.is_triangle_free(algorithm='bitset')
True

a tripartite graph, though, contains many triangles:

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

join(other, labels=’pairs’, immutable=None)


Return the join of self and other.
INPUT:
• labels - (defaults to ‘pairs’) If set to ‘pairs’, each element v in the first graph will be named (0,v)
and each element u in other will be named (1,u) in the result. If set to ‘integers’, the elements of
the result will be relabeled with consecutive integers.
• immutable (boolean) – whether to create a mutable/immutable join. immutable=None (default)
means that the graphs and their join will behave the same way.
See also:

270 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

• 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.

1.2. Undirected graphs 271


Sage Reference Manual: Graph Theory, Release 8.4

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

One can use another letter for variables:

sage: G.kirchhoff_symanzik_polynomial(name='u')
u0 + u1 + u2 + u3 + u4

For the ‘coffee bean’ graph:

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

For the ‘parachute’ graph:

sage: G = Graph([(0,2,'a'),(0,2,'b'),(0,1,'c'),(1,2,'d')], multiedges=True)


sage: G.kirchhoff_symanzik_polynomial()
t0*t1 + t0*t2 + t1*t2 + t1*t3 + t2*t3

For the complete graph with 4 vertices:

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.

272 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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 = Graph({1:[], 2:[]})


sage: g.magnitude_function()
2

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)

One can expand the magnitude as a power series in 𝑞 as follows:

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.

1.2. Undirected graphs 273


Sage Reference Manual: Graph Theory, Release 8.4

As an optimization problem, it can be expressed as:


∑︁
Maximize : 𝑤𝑒 𝑏𝑒
𝑒∈𝐺.𝑒𝑑𝑔𝑒𝑠()
∑︁
Such that : ∀𝑣 ∈ 𝐺, 𝑏(𝑢,𝑣) ≤ 1
(𝑢,𝑣)∈𝐺.𝑒𝑑𝑔𝑒𝑠()

∀𝑥 ∈ 𝐺, 𝑏𝑥 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

Same test with the Linear Program formulation:


sage: g = graphs.PappusGraph()
sage: g.matching(algorithm="LP", value_only=True)
9

matching_polynomial(G, complement=True, name=None)


Computes the matching polynomial of the graph 𝐺.
If 𝑝(𝐺, 𝑘) denotes the number of 𝑘-matchings (matchings with 𝑘 edges) in 𝐺, then the matching polyno-
mial is defined as [Godsil93]:
∑︁
𝜇(𝑥) = (−1)𝑘 𝑝(𝐺, 𝑘)𝑥𝑛−2𝑘
𝑘≥0

INPUT:

274 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

1.2. Undirected graphs 275


Sage Reference Manual: Graph Theory, Release 8.4

• 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

Where 𝐺 is the complement of 𝐺, and 𝐾𝑛 the complete graph on 𝑛 vertices.


EXAMPLES:

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: for i in range(1, 12): # long time (10s on sage.math, 2011)


....: for t in graphs.trees(i):
....: if t.matching_polynomial() != t.characteristic_polynomial():
....: raise RuntimeError('bug for a tree A of size {0}'.format(i))
....: c = t.complement()
....: if c.matching_polynomial(complement=False) != c.matching_
˓→polynomial():

....: raise RuntimeError('bug for a tree B of size {0}'.format(i))

sage: from sage.graphs.matchpoly import matching_polynomial


sage: matching_polynomial(graphs.CompleteGraph(0))
1
sage: matching_polynomial(graphs.CompleteGraph(1))
(continues on next page)

276 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


x
sage: matching_polynomial(graphs.CompleteGraph(2))
x^2 - 1
sage: matching_polynomial(graphs.CompleteGraph(3))
x^3 - 3*x
sage: matching_polynomial(graphs.CompleteGraph(4))
x^4 - 6*x^2 + 3
sage: matching_polynomial(graphs.CompleteGraph(5))
x^5 - 10*x^3 + 15*x
sage: matching_polynomial(graphs.CompleteGraph(6))
x^6 - 15*x^4 + 45*x^2 - 15
sage: matching_polynomial(graphs.CompleteGraph(7))
x^7 - 21*x^5 + 105*x^3 - 105*x
sage: matching_polynomial(graphs.CompleteGraph(8))
x^8 - 28*x^6 + 210*x^4 - 420*x^2 + 105
sage: matching_polynomial(graphs.CompleteGraph(9))
x^9 - 36*x^7 + 378*x^5 - 1260*x^3 + 945*x
sage: matching_polynomial(graphs.CompleteGraph(10))
x^10 - 45*x^8 + 630*x^6 - 3150*x^4 + 4725*x^2 - 945
sage: matching_polynomial(graphs.CompleteGraph(11))
x^11 - 55*x^9 + 990*x^7 - 6930*x^5 + 17325*x^3 - 10395*x
sage: matching_polynomial(graphs.CompleteGraph(12))
x^12 - 66*x^10 + 1485*x^8 - 13860*x^6 + 51975*x^4 - 62370*x^2 + 10395
sage: matching_polynomial(graphs.CompleteGraph(13))
x^13 - 78*x^11 + 2145*x^9 - 25740*x^7 + 135135*x^5 - 270270*x^3 + 135135*x

sage: G = Graph({0:[1,2], 1:[2]})


sage: matching_polynomial(G)
x^3 - 3* x
sage: G = Graph({0:[1,2]})
sage: matching_polynomial(G)
x^3 - 2* x
sage: G = Graph({0:[1], 2:[]})
sage: matching_polynomial(G)
x^3 - x
sage: G = Graph({0:[], 1:[], 2:[]})
sage: matching_polynomial(G)
x^3

sage: matching_polynomial(graphs.CompleteGraph(0), complement=False)


1
sage: matching_polynomial(graphs.CompleteGraph(1), complement=False)
x
sage: matching_polynomial(graphs.CompleteGraph(2), complement=False)
x^2 - 1
sage: matching_polynomial(graphs.CompleteGraph(3), complement=False)
x^3 - 3* x
sage: matching_polynomial(graphs.CompleteGraph(4), complement=False)
x^4 - 6*x^2 + 3
sage: matching_polynomial(graphs.CompleteGraph(5), complement=False)
x^5 - 10*x^3 + 15*x
sage: matching_polynomial(graphs.CompleteGraph(6), complement=False)
x^6 - 15*x^4 + 45*x^2 - 15
sage: matching_polynomial(graphs.CompleteGraph(7), complement=False)
x^7 - 21*x^5 + 105*x^3 - 105*x
sage: matching_polynomial(graphs.CompleteGraph(8), complement=False)
(continues on next page)

1.2. Undirected graphs 277


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


x^8 - 28*x^6 + 210*x^4 - 420*x^2 + 105
sage: matching_polynomial(graphs.CompleteGraph(9), complement=False)
x^9 - 36*x^7 + 378*x^5 - 1260*x^3 + 945*x
sage: matching_polynomial(graphs.CompleteGraph(10), complement=False)
x^10 - 45*x^8 + 630*x^6 - 3150*x^4 + 4725*x^2 - 945
sage: matching_polynomial(graphs.CompleteGraph(11), complement=False)
x^11 - 55*x^9 + 990*x^7 - 6930*x^5 + 17325*x^3 - 10395*x
sage: matching_polynomial(graphs.CompleteGraph(12), complement=False)
x^12 - 66*x^10 + 1485*x^8 - 13860*x^6 + 51975*x^4 - 62370*x^2 + 10395
sage: matching_polynomial(graphs.CompleteGraph(13), complement=False)
x^13 - 78*x^11 + 2145*x^9 - 25740*x^7 + 135135*x^5 - 270270*x^3 + 135135*x

maximum_average_degree(value_only=True, solver=None, verbose=0)


Return the Maximum Average Degree (MAD) of the current graph.
The Maximum Average Degree (MAD) of a graph is defined as the average degree of its densest subgraph.
More formally, Mad(G) = \max_{H\subseteq G} Ad(H), where 𝐴𝑑(𝐺) denotes the average de-
gree of 𝐺.
This can be computed in polynomial time.
INPUT:
• value_only (boolean) – True by default
– If value_only=True, only the numerical value of the 𝑀 𝐴𝐷 is returned.
– Else, the subgraph of 𝐺 realizing the 𝑀 𝐴𝐷 is returned.
• 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:
In any graph, the 𝑀 𝑎𝑑 is always larger than the average degree:

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

This also works for complete bipartite graphs

278 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

sage: g = graphs.CompleteBipartiteGraph(3,4)
sage: mad_g = g.maximum_average_degree(value_only=False)
sage: g.is_isomorphic(mad_g)
True

minimum_outdegree_orientation(use_edge_labels=False, solver=None, verbose=0)


Returns an orientation of self with the smallest possible maximum outdegree.
Given a Graph 𝐺, it is polynomial to compute an orientation 𝐷 of the edges of 𝐺 such that the maximum
out-degree in 𝐷 is minimized. This problem, though, is NP-complete in the weighted case [AMOZ06].
INPUT:
• use_edge_labels – boolean (default: False)
– When set to True, uses edge labels as weights to compute the orientation and assumes a weight
of 1 when there is no value available for a given edge.
– When set to False (default), gives a weight of 1 to all the edges.
• 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:
⌈︁ ⌉︁
𝑛𝑚
Given a complete bipartite graph 𝐾𝑛,𝑚 , the maximum out-degree of an optimal orientation is 𝑛+𝑚 :

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:

1.2. Undirected graphs 279


Sage Reference Manual: Graph Theory, Release 8.4

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

And even a 𝐾3,3 minor:


sage: K33_minor = g.minor(graphs.CompleteBipartiteGraph(3,3)) # 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 :

280 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

• 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])

The Petersen Graph too:

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:

• is_prime() – Tests whether a graph is prime.

REFERENCE:

1.2. Undirected graphs 281


Sage Reference Manual: Graph Theory, Release 8.4

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:

• girth() – computes the girth of a graph.

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:

282 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

sage: G = Graph([[1,2,3], [(1, 2, 'a'), (1, 3, 'b')]], format='vertices_and_


˓→edges')

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')]

pathwidth(k=None, certificate=False, algorithm=’BAB’, verbose=False, max_prefix_length=20,


max_prefix_number=1000000)
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 restric-
tion 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:

• Graph.treewidth() – computes the treewidth of a graph


• vertex_separation() – computes the vertex separation of a (di)graph

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)

1.2. Undirected graphs 283


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: decomp.vertices()
[{1, 2, 5}, {2, 3, 4}, {0, 1, 5}, {2, 4, 5}]

The pathwidth of a Petersen graph is 5:


sage: g = graphs.PetersenGraph()
sage: g.pathwidth()
5
sage: g.pathwidth(k=2)
False
sage: g.pathwidth(k=6)
True
sage: g.pathwidth(k=6, certificate=True)
(True, Graph on 5 vertices)

perfect_matchings(labels=False)
Return an iterator over all perfect matchings of the graph.
ALGORITHM:
Choose a vertex 𝑣, then recurse through all edges incident to 𝑣, removing one edge at a time whenever an
edge is added to a matching.
INPUT:
• labels – boolean (default: False); when True, the edges in each perfect matching are triples
(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 = Graph([[1,-1,'a'], [2,-2, 'b'], [1,-2,'x'], [2,-1,'y']])


sage: list(G.perfect_matchings(labels=True))
[[(-2, 1, 'x'), (-1, 2, 'y')], [(-2, 2, 'b'), (-1, 1, 'a')]]

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)

284 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


[(0, 4), (1, 2), (3, 8), (5, 7), (6, 9)],
[(0, 4), (1, 6), (2, 3), (5, 8), (7, 9)],
[(0, 5), (1, 2), (3, 4), (6, 8), (7, 9)],
[(0, 5), (1, 6), (2, 7), (3, 8), (4, 9)]]

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)

1.2. Undirected graphs 285


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


(0, 8),
(8, 7),
(7, 6),
(7, 2),
(2, 1),
(1, 5),
(9, 10),
(5, 4),
(2, 3)]
sage: Graph(rg).is_tree()
True

A visual example for the grid graph:

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: from sage.graphs.graph_decompositions.rankwidth import rank_


˓→decomposition

sage: g = graphs.PetersenGraph()
sage: rank_decomposition(g)
(3, Graph on 19 vertices)

On more than 32 vertices:

sage: g = graphs.RandomGNP(40, .5)


sage: rank_decomposition(g)
Traceback (most recent call last):
...
RuntimeError: the rank decomposition cannot be computed on graphs of >= 32
˓→vertices

The empty graph:

sage: g = Graph()
sage: rank_decomposition(g)
(0, Graph on 0 vertices)

286 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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)

1.2. Undirected graphs 287


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


6
sage: G.spanning_trees_count()
6

See also:

• spanning_trees_count() – counts the number of spanning trees.


• random_spanning_tree() – returns a random spanning tree.

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'

sage: G = Graph(loops=True, multiedges=True,data_structure="sparse")


sage: Graph(':?',data_structure="sparse") == G
True

spqr_tree(G, algorithm=’Hopcroft_Tarjan’, solver=None, verbose=0)


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.

288 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

• algorithm – The algorithm to use in computing the SPQR tree of G. The following algorithms
are supported:

– "Hopcroft_Tarjan" (default) – Use the algorithm proposed by Hopcroft and Tar-


jan in [Hopcroft1973] and later corrected by Gutwenger and Mutzel in [Gut2001]. See
TriconnectivitySPQR.
– "cleave" – Using method cleave().

• 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)
(continues on next page)

1.2. Undirected graphs 289


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: Tree = spqr_tree(G)
sage: Tree.order()
1
sage: G.is_isomorphic(spqr_tree_to_graph(Tree))
True
sage: G.add_edge(0, 3)
sage: Tree = spqr_tree(G)
sage: Tree.order()
3
sage: G.is_isomorphic(spqr_tree_to_graph(Tree))
True

sage: G = Graph('LlCG{O@?GBoMw?')
sage: T = spqr_tree(G, algorithm="Hopcroft_Tarjan")
sage: G.is_isomorphic(spqr_tree_to_graph(T))
True
sage: T2 = spqr_tree(G, algorithm='cleave')
sage: G.is_isomorphic(spqr_tree_to_graph(T2))
True

sage: G = Graph([(0, 1)], multiedges=True)


sage: T = spqr_tree(G, algorithm='cleave')
sage: T.vertices()
[('Q', Multi-graph on 2 vertices)]
sage: G.is_isomorphic(spqr_tree_to_graph(T))
True
sage: T = spqr_tree(G, algorithm='Hopcroft_Tarjan')
sage: T.vertices()
[('Q', Multi-graph on 2 vertices)]
sage: G.add_edge(0, 1)
sage: spqr_tree(G, algorithm='cleave').vertices()
[('P', Multi-graph on 2 vertices)]

sage: from collections import Counter


sage: G = graphs.PetersenGraph()
sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan")
sage: Counter(u[0] for u in T)
Counter({'R': 1})
sage: T = G.spqr_tree(algorithm="cleave")
sage: Counter(u[0] for u in T)
Counter({'R': 1})
sage: for u,v in G.edges(labels=False):
....: G.add_path([u, G.add_vertex(), G.add_vertex(), v])
sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan")
sage: Counter(u[0] for u in T)
Counter({'P': 15, 'S': 15, 'R': 1})
sage: T = G.spqr_tree(algorithm="cleave")
sage: Counter(u[0] for u in T)
Counter({'P': 15, 'S': 15, 'R': 1})
sage: for u,v in G.edges(labels=False):
....: G.add_path([u, G.add_vertex(), G.add_vertex(), v])
sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan")
sage: Counter(u[0] for u in T)
Counter({'S': 75, 'P': 60, 'R': 1})
sage: T = G.spqr_tree(algorithm="cleave") # long time
sage: Counter(u[0] for u in T) # long time
Counter({'S': 75, 'P': 60, 'R': 1})

290 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

The same goes for the CubeGraph in any dimension

sage: all(len(graphs.CubeGraph(i).strong_orientation().strongly_connected_
˓→components()) == 1 for i in range(2,6))

True

A multigraph also has a strong orientation

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

1.2. Undirected graphs 291


Sage Reference Manual: Graph Theory, Release 8.4

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

A tree cannot be strongly oriented:

sage: g = graphs.RandomTree(100)
sage: len(list(g.strong_orientations_iterator()))
0

Neither can be a disconnected graph:

sage: g = graphs.CompleteGraph(6)
sage: g.add_vertex(7)
sage: len(list(g.strong_orientations_iterator()))
0

to_directed(implementation=’c_graph’, data_structure=None, sparse=None)


Return a directed version of the graph.
A single edge becomes two edges, one in each direction.
INPUT:
• data_structure – one of "sparse", "static_sparse", or "dense". See the documen-
tation of Graph or DiGraph.
• sparse (boolean) – sparse=True is an alias for data_structure="sparse", and
sparse=False is an alias for data_structure="dense".
EXAMPLES:

sage: graphs.PetersenGraph().to_directed()
Petersen graph: Digraph on 10 vertices

to_undirected()
Since the graph is already undirected, simply returns a copy of itself.
EXAMPLES:

292 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

sage: graphs.PetersenGraph().to_undirected()
Petersen graph: Graph on 10 vertices

topological_minor(H, vertices=False, paths=False, solver=None, verbose=0)


Return a topological 𝐻-minor from self if one exists.
We say that a graph 𝐺 has a topological 𝐻-minor (or that it has a graph isomorphic to 𝐻 as a topological
minor), if 𝐺 contains a subdivision of a graph isomorphic to 𝐻 (i.e. obtained from 𝐻 through arbitrary
subdivision of its edges) as a subgraph.
For more information, see the Wikipedia article Minor_(graph_theory).
INPUT:
• H – The topological minor to find 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:
The topological 𝐻-minor found is returned as a subgraph 𝑀 of self, such that the vertex 𝑣 of 𝑀 that
represents a vertex ℎ ∈ 𝐻 has h as a label (see get_vertex and set_vertex), and such that every
edge of 𝑀 has as a label the edge of 𝐻 it (partially) represents.
If no topological minor is found, this method returns False.
ALGORITHM:
Mixed Integer Linear Programming.
COMPLEXITY:
Theoretically, when 𝐻 is fixed, testing for the existence of a topological 𝐻-minor is polynomial. The
known algorithms are highly exponential in 𝐻, though.

Note: This function can be expected to be very slow, especially where the topological minor does not
exist.
(CPLEX seems to be much more efficient than GLPK on this kind of problem)

EXAMPLES:
Petersen’s graph has a topological 𝐾4 -minor:

sage: g = graphs.PetersenGraph()
sage: g.topological_minor(graphs.CompleteGraph(4))
Subgraph of (Petersen graph): Graph on ...

And a topological 𝐾3,3 -minor:

sage: g.topological_minor(graphs.CompleteBipartiteGraph(3,3))
Subgraph of (Petersen graph): Graph on ...

And of course, a tree has no topological 𝐶3 -minor:

1.2. Undirected graphs 293


Sage Reference Manual: Graph Theory, Release 8.4

sage: g = graphs.RandomGNP(15,.3)
sage: g = g.subgraph(edges = g.min_spanning_tree())
sage: g.topological_minor(graphs.CycleGraph(3))
False

treewidth(k=None, certificate=False, algorithm=None)


Computes the tree-width of 𝐺 (and provides a decomposition)
INPUT:
• k (integer) – the width to be considered. When k is an integer, the method checks that the graph has
treewidth ≤ 𝑘. If k is None (default), the method computes the optimal tree-width.
• certificate – whether to return the tree-decomposition itself.
• algorithm – whether to use "sage" or "tdlib" (requires the installation of the ‘tdlib’ package).
The default behaviour is to use ‘tdlib’ if it is available, and Sage’s own algorithm when it is not.
OUTPUT:
g.treewidth() returns the treewidth of g. When k is specified, it returns False
when no tree-decomposition of width ≤ 𝑘 exists or True otherwise. When
certificate=True, the tree-decomposition is also returned.
ALGORITHM:
This function virtually explores the graph of all pairs (vertex_cut,cc), where
vertex_cut is a vertex cut of the graph of cardinality ≤ 𝑘+1, and connected_component
is a connected component of the graph induced by G-vertex_cut.
We deduce that the pair (vertex_cut,cc) is feasible with tree-width 𝑘 if cc is empty, or
if a vertex v from vertex_cut can be replaced with a vertex from cc, such that the pair
(vertex_cut+v,cc-v) is feasible.

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

The treewidth of a 2d grid is its smallest side:

sage: graphs.Grid2dGraph(2,5).treewidth()
2
sage: graphs.Grid2dGraph(3,5).treewidth()
3

294 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

tutte_polynomial(G, edge_selector=None, cache=None)


Return the Tutte polynomial of the graph 𝐺.
INPUT:
• edge_selector (optional; method) this argument allows the user to specify his own heuristic for
selecting edges used in the deletion contraction recurrence
• cache – (optional; dict) a dictionary to cache the Tutte polynomials generated in the recursive pro-
cess. One will be created automatically if not provided.
EXAMPLES:
The Tutte polynomial of any tree of order 𝑛 is 𝑥𝑛−1 :

sage: all(T.tutte_polynomial() == x**9 for T in graphs.trees(10))


True

The Tutte polynomial of the Petersen graph is:

sage: P = graphs.PetersenGraph()
sage: P.tutte_polynomial()
x^9 + 6*x^8 + 21*x^7 + 56*x^6 + 12*x^5*y + y^6 + 114*x^5 + 70*x^4*y
+ 30*x^3*y^2 + 15*x^2*y^3 + 10*x*y^4 + 9*y^5 + 170*x^4 + 170*x^3*y
+ 105*x^2*y^2 + 65*x*y^3 + 35*y^4 + 180*x^3 + 240*x^2*y + 171*x*y^2
+ 75*y^3 + 120*x^2 + 168*x*y + 84*y^2 + 36*x + 36*y

The Tutte polynomial of 𝐺 evaluated at (1,1) is the number of spanning trees of 𝐺:

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.

1.2. Undirected graphs 295


Sage Reference Manual: Graph Theory, Release 8.4

• 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

sage: g = graphs.CirculantGraph(24, [7, 11])


sage: cl = g.two_factor_petersen()
sage: g.plot(edge_colors={'black':cl[0], 'red':cl[1]})
Graphics object consisting of 73 graphics primitives

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:

• descendant() – computes the descendant graph of the two-graph of self at a vertex


• twograph_descendant() – ditto, but much faster.

vertex_cover(algorithm=’Cliquer’, value_only=False, reduction_rules=True, solver=None, ver-


bosity=0)
Return a minimum vertex cover of self represented by a set of vertices.
A minimum vertex cover of a graph is a set 𝑆 of vertices such that each edge is incident to at least one
element of 𝑆, and such that 𝑆 is of minimum cardinality. For more information, see the Wikipedia article
Vertex_cover.
Equivalently, a vertex cover is defined as the complement of an independent set.

296 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

As an optimization problem, it can be expressed as follows:


∑︁
Minimize : 𝑏𝑣
𝑣∈𝐺
Such that : ∀(𝑢, 𝑣) ∈ 𝐺.𝑒𝑑𝑔𝑒𝑠(), 𝑏𝑢 + 𝑏𝑣 ≥ 1
∀𝑥 ∈ 𝐺, 𝑏𝑥 is a binary variable

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'))

It is relatively simple to include this file in a LaTeX document. \usepackage{graphics} must


appear in the preamble, and \includegraphics{filename} will include the file. To compile the
document to pdf with pdflatex or xelatex the file needs first to be converted to pdf, for example
with ps2pdf filename.eps filename.pdf.

1.2. Undirected graphs 297


Sage Reference Manual: Graph Theory, Release 8.4

298 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

1.3 Directed graphs

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.

Paths and cycles:

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:

1.3. Directed graphs 299


Sage Reference Manual: Graph Theory, Release 8.4

is_strongly_connected() Returns whether the current DiGraph is strongly connected.


Returns the digraph of the strongly connected components
strongly_connected_components_digraph()
Returns the strongly connected components as a list of subgraphs.
strongly_connected_components_subgraphs()
Returns the strongly connected component containing a given vertex
strongly_connected_component_containing_vertex()
Returns the list of strongly connected components.
strongly_connected_components()
immediate_dominators() Return the immediate dominators of all vertices reachable from 𝑟𝑜𝑜𝑡.
Return the strong articulation points of this digraph.
strong_articulation_points()

Acyclicity:

is_directed_acyclic() Returns whether the digraph is acyclic or not.


is_transitive() Returns whether the digraph is transitive or not.
is_aperiodic() Returns whether the digraph is aperiodic or not.
is_tournament() Check whether the digraph is a tournament.
period() Returns the period of the digraph.
level_sets() Returns the level set decomposition of the digraph.
Returns a list of all topological sorts of the digraph if it is acyclic
topological_sort_generator()
topological_sort() Returns a topological sort of the digraph if it is acyclic

Hard stuff:

feedback_edge_set() Computes the minimum feedback edge (arc) set of a digraph

Miscellanous:

flow_polytope() Computes the flow polytope of a digraph


degree_polynomial() Returns the generating polynomial of degrees of vertices in self.

1.3.1 Methods

class sage.graphs.digraph.DiGraph(data=None, pos=None, loops=None, for-


mat=None, weighted=None, implementa-
tion=’c_graph’, data_structure=’sparse’, ver-
tex_labels=True, name=None, multiedges=None, con-
vert_empty_dict_labels_to_None=None, sparse=True,
immutable=False)
Bases: sage.graphs.generic_graph.GenericGraph
Directed graph.
A digraph or directed graph is a set of vertices connected by oriented edges. See also the Wikipedia article
Directed_graph. For a collection of pre-defined digraphs, see the digraph_generators module.
A DiGraph object has many methods whose list can be obtained by typing g.<tab> (i.e. hit the ‘tab’ key) or
by reading the documentation of digraph, generic_graph, and graph.
INPUT:
By default, a DiGraph 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):

300 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

1. DiGraph() – build a digraph on 0 vertices.


2. DiGraph(5) – return an edgeless digraph on the 5 vertices 0,. . . ,4.
3. DiGraph([list_of_vertices,list_of_edges]) – returns a digraph with given ver-
tices/edges.
To bypass auto-detection, prefer the more explicit DiGraph([V,E],
format='vertices_and_edges').
4. DiGraph(list_of_edges) – return a digraph with a given list of edges (see documentation of
add_edges()).
To bypass auto-detection, prefer the more explicit DiGraph(L, format='list_of_edges').
5. DiGraph({1:[2,3,4],3:[4]}) – return a digraph by associating to each vertex the list of its out-
neighbors.
To bypass auto-detection, prefer the more explicit DiGraph(D, format='dict_of_lists').
6. DiGraph({1: {2: 'a', 3:'b'} ,3:{2:'c'}}) – return a digraph by associating a list of
out-neighbors to each vertex and providing its edge label.
To bypass auto-detection, prefer the more explicit DiGraph(D, format='dict_of_dicts').
For digraphs with multiple edges, you can provide a list of labels instead, e.g.: DiGraph({1: {2:
['a1', 'a2'], 3:['b']} ,3:{2:['c']}}).
7. DiGraph(a_matrix) – return a digraph with given (weighted) adjacency matrix (see documentation
of adjacency_matrix()).
To bypass auto-detection, prefer the more explicit DiGraph(M, format='adjacency_matrix').
To take weights into account, use format='weighted_adjacency_matrix' instead.
8. DiGraph(a_nonsquare_matrix) – return a digraph with given incidence matrix (see documenta-
tion of incidence_matrix()).
To bypass auto-detection, prefer the more explicit DiGraph(M, format='incidence_matrix').
9. DiGraph([V, f]) – return a digraph with a vertex set V and an edge 𝑢, 𝑣 whenever f(u,v) is True.
Example: DiGraph([ [1..10], lambda x,y: abs(x-y).is_square()])
10. DiGraph('FOC@?OC@_?') – return a digraph from a dig6 string (see documentation of
dig6_string()).
11. DiGraph(another_digraph) – return a digraph from a Sage (di)graph, pygraphviz digraph, Net-
workX digraph, or igraph digraph.

• pos - a positioning dictionary: for example, the spring layout from NetworkX for the 5-cycle is:

{0: [-0.91679746, 0.88169588],


1: [ 0.47294849, 1.125 ],
2: [ 1.125 ,-0.12867615],
3: [ 0.12743933,-1.125 ],
4: [-1.125 ,-0.50118505]}

• 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()

1.3. Directed graphs 301


Sage Reference Manual: Graph Theory, Release 8.4

• 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:

sage: g = DiGraph({0:{1:'x',2:'z',3:'a'}, 2:{5:'out'}}); g


Digraph on 5 vertices

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):

sage: g = DiGraph({0:[1,2,3], 2:[4]}); g


Digraph on 5 vertices
sage: g = DiGraph({0:(1,2,3), 2:(4,)}); g
Digraph on 5 vertices

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.

sage: g=DiGraph([[1..12],lambda i,j: i!=j and i.divides(j)])


sage: g.vertices()
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
sage: g.adjacency_matrix()
[0 1 1 1 1 1 1 1 1 1 1 1]
[0 0 0 1 0 1 0 1 0 1 0 1]
[0 0 0 0 0 1 0 0 1 0 0 1]
[0 0 0 0 0 0 0 1 0 0 0 1]
(continues on next page)

302 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


[0 0 0 0 0 0 0 0 0 1 0 0]
[0 0 0 0 0 0 0 0 0 0 0 1]
[0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0]

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)

1.3. Directed graphs 303


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous 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:

sage: import networkx


sage: g = networkx.MultiDiGraph({0:[1,2,3], 2:[4]})
sage: DiGraph(g)
Digraph on 5 vertices

7. A NetworkX digraph:

sage: import networkx


sage: g = networkx.DiGraph({0:[1,2,3], 2:[4]})
sage: DiGraph(g)
Digraph on 5 vertices

8. An igraph directed Graph (see also igraph_graph()):

sage: import igraph # optional - python_


˓→igraph

sage: g = igraph.Graph([(0,1),(0,2)], directed=True) # optional - python_


˓→igraph

sage: DiGraph(g) # optional - python_


˓→igraph

Digraph on 3 vertices

If vertex_labels is True, the names of the vertices are given by the vertex attribute 'name', if
available:

sage: g = igraph.Graph([(0,1),(0,2)], directed=True, vertex_attrs={'name':['a


˓→','b','c']}) # optional - python_igraph
sage: DiGraph(g).vertices()
˓→ # optional - python_igraph
['a', 'b', 'c']
sage: g = igraph.Graph([(0,1),(0,2)], directed=True, vertex_attrs={'label':['a
˓→','b','c']}) # optional - python_igraph

sage: DiGraph(g).vertices()
˓→ # optional - python_igraph
[0, 1, 2]

If the igraph Graph has edge attributes, they are used as edge labels:

sage: g = igraph.Graph([(0,1),(0,2)], directed=True, edge_attrs={'name':['a',


˓→'b'], 'weight':[1,3]}) # optional - python_igraph

sage: DiGraph(g).edges()
˓→ # optional - python_igraph
[(0, 1, {'name': 'a', 'weight': 1}), (0, 2, {'name': 'b', 'weight': 3})]

all_cycles_iterator(starting_vertices=None, simple=False, rooted=False, max_length=None,


trivial=False)
Returns an iterator over all the cycles of self starting with one of the given vertices. The cycles are
enumerated in increasing length order.

304 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

Note: See also all_simple_cycles().

AUTHOR:
Alexandre Blondin Masse
EXAMPLES:

sage: g = DiGraph({'a' : ['a', 'b'], 'b' : ['c'], 'c' : ['d'], 'd' : ['c']},
˓→loops=True)

sage: it = g.all_cycles_iterator()
sage: for _ in range(7): print(next(it))
['a', 'a']
['a', 'a', 'a']
['c', 'd', 'c']
['a', 'a', 'a', 'a']
['a', 'a', 'a', 'a', 'a']
['c', 'd', 'c', 'd', 'c']
['a', 'a', 'a', 'a', 'a', 'a']

There are no cycles in the empty graph and in acyclic graphs:

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)
[]

It is possible to restrict the starting vertices of the cycles:

sage: g = DiGraph({'a' : ['a', 'b'], 'b' : ['c'], 'c' : ['d'], 'd' : ['c']},
˓→loops=True)

sage: it = g.all_cycles_iterator(starting_vertices=['b', 'c'])


sage: for _ in range(3): print(next(it))
['c', 'd', 'c']
(continues on next page)

1.3. Directed graphs 305


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


['c', 'd', 'c', 'd', 'c']
['c', 'd', 'c', 'd', 'c', 'd', 'c']

Also, one can bound the length of the cycles:

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:

sage: it = g.all_cycles_iterator(max_length=3, rooted=False)


sage: list(it)
[['a', 'a'], ['a', 'a', 'a'], ['c', 'd', 'c'],
['a', 'a', 'a', 'a']]
sage: it = g.all_cycles_iterator(max_length=3, rooted=True)
sage: list(it)
[['a', 'a'], ['a', 'a', 'a'], ['c', 'd', 'c'], ['d', 'c', 'd'],
['a', 'a', 'a', 'a']]

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]]

all_paths_iterator(starting_vertices=None, ending_vertices=None, simple=False,


max_length=None, trivial=False)
Returns an iterator over the paths of self. The paths are enumerated in increasing length order.
INPUT:
• starting_vertices - iterable (default: None) on the vertices from which the paths must start. If
None, then all vertices of the graph can be starting points.
• ending_vertices - iterable (default: None) on the allowed ending vertices of the paths. If None,
then all vertices are allowed.
• simple - boolean (default: False). If set to True, then only simple paths are considered. These are
paths in which no two arcs share a head or share a tail, i.e. every vertex in the path is entered at most
once and exited at most once.
• max_length - non negative integer (default: None). The maximum length of the enumerated paths.
If set to None, then all lengths are allowed.
• trivial - boolean (default: False). If set to True, then the empty paths are also enumerated.
OUTPUT:
iterator
AUTHOR:
Alexandre Blondin Masse

306 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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']

It is possible to precise the allowed starting and/or ending vertices:

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: for _ in range(5): print(next(pi))


['a', 'b']
['a', 'a', 'b']
['a', 'a', 'a', 'b']
['a', 'a', 'a', 'a', 'b']
['a', 'a', 'a', 'a', 'a', 'b']

One may prefer to enumerate only simple paths (see all_simple_paths()):

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']]

Or simply bound the length of the enumerated paths:

sage: pi = g.all_paths_iterator(starting_vertices=['a'], ending_vertices=['b',


˓→ 'c'], max_length=6)

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']]

By default, empty paths are not enumerated, but it may be parametrized:

1.3. Directed graphs 307


Sage Reference Manual: Graph Theory, Release 8.4

sage: pi = g.all_paths_iterator(simple=True, trivial=True)


sage: list(pi)
[['a'], ['b'], ['c'], ['d'], ['a', 'a'], ['a', 'b'], ['b', 'c'],
['c', 'd'], ['d', 'c'], ['a', 'b', 'c'], ['b', 'c', 'd'],
['c', 'd', 'c'], ['d', 'c', 'd'], ['a', 'b', 'c', 'd']]
sage: pi = g.all_paths_iterator(simple=True, trivial=False)
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']]

all_simple_cycles(starting_vertices=None, rooted=False, max_length=None, trivial=False)


Returns a list of all simple cycles of self.
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.
• rooted - boolean (default: False). If set to False, then equivalent cycles are merged into one single
cycle (the one starting with minimum vertex). Two cycles are called equivalent if they differ only from
their starting vertex (e.g. ['a', 'b', 'c', 'a'] and ['b', 'c', 'a', 'b']). Other-
wise, 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:
list

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']]

The directed version of the Petersen graph:


sage: g = graphs.PetersenGraph().to_directed()
sage: g.all_simple_cycles(max_length=4)
[[0, 1, 0], [0, 4, 0], [0, 5, 0], [1, 2, 1], [1, 6, 1], [2, 3, 2],
[2, 7, 2], [3, 8, 3], [3, 4, 3], [4, 9, 4], [5, 8, 5], [5, 7, 5],
[6, 8, 6], [6, 9, 6], [7, 9, 7]]
sage: g.all_simple_cycles(max_length=6)
[[0, 1, 0], [0, 4, 0], [0, 5, 0], [1, 2, 1], [1, 6, 1], [2, 3, 2],
[2, 7, 2], [3, 8, 3], [3, 4, 3], [4, 9, 4], [5, 8, 5], [5, 7, 5],
[6, 8, 6], [6, 9, 6], [7, 9, 7], [0, 1, 2, 3, 4, 0],
[0, 1, 2, 7, 5, 0], [0, 1, 6, 8, 5, 0], [0, 1, 6, 9, 4, 0],
[0, 4, 9, 6, 1, 0], [0, 4, 9, 7, 5, 0], [0, 4, 3, 8, 5, 0],
[0, 4, 3, 2, 1, 0], [0, 5, 8, 3, 4, 0], [0, 5, 8, 6, 1, 0],
[0, 5, 7, 9, 4, 0], [0, 5, 7, 2, 1, 0], [1, 2, 3, 8, 6, 1],
(continues on next page)

308 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


[1, 2, 7, 9, 6, 1], [1, 6, 8, 3, 2, 1], [1, 6, 9, 7, 2, 1],
[2, 3, 8, 5, 7, 2], [2, 3, 4, 9, 7, 2], [2, 7, 9, 4, 3, 2],
[2, 7, 5, 8, 3, 2], [3, 8, 6, 9, 4, 3], [3, 4, 9, 6, 8, 3],
[5, 8, 6, 9, 7, 5], [5, 7, 9, 6, 8, 5], [0, 1, 2, 3, 8, 5, 0],
[0, 1, 2, 7, 9, 4, 0], [0, 1, 6, 8, 3, 4, 0],
[0, 1, 6, 9, 7, 5, 0], [0, 4, 9, 6, 8, 5, 0],
[0, 4, 9, 7, 2, 1, 0], [0, 4, 3, 8, 6, 1, 0],
[0, 4, 3, 2, 7, 5, 0], [0, 5, 8, 3, 2, 1, 0],
[0, 5, 8, 6, 9, 4, 0], [0, 5, 7, 9, 6, 1, 0],
[0, 5, 7, 2, 3, 4, 0], [1, 2, 3, 4, 9, 6, 1],
[1, 2, 7, 5, 8, 6, 1], [1, 6, 8, 5, 7, 2, 1],
[1, 6, 9, 4, 3, 2, 1], [2, 3, 8, 6, 9, 7, 2],
[2, 7, 9, 6, 8, 3, 2], [3, 8, 5, 7, 9, 4, 3],
[3, 4, 9, 7, 5, 8, 3]]

The complete graph (without loops) on 4 vertices:

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)

1.3. Directed graphs 309


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


[9, 10, 9], [9, 11, 9], [9, 12, 9], [9, 13, 9], [9, 14, 9],
[9, 15, 9], [9, 16, 9], [9, 17, 9], [9, 18, 9], [9, 19, 9],
[10, 11, 10], [10, 12, 10], [10, 13, 10], [10, 14, 10],
[10, 15, 10], [10, 16, 10], [10, 17, 10], [10, 18, 10],
[10, 19, 10], [11, 12, 11], [11, 13, 11], [11, 14, 11],
[11, 15, 11], [11, 16, 11], [11, 17, 11], [11, 18, 11],
[11, 19, 11], [12, 13, 12], [12, 14, 12], [12, 15, 12],
[12, 16, 12], [12, 17, 12], [12, 18, 12], [12, 19, 12],
[13, 14, 13], [13, 15, 13], [13, 16, 13], [13, 17, 13],
[13, 18, 13], [13, 19, 13], [14, 15, 14], [14, 16, 14],
[14, 17, 14], [14, 18, 14], [14, 19, 14], [15, 16, 15],
[15, 17, 15], [15, 18, 15], [15, 19, 15], [16, 17, 16],
[16, 18, 16], [16, 19, 16], [17, 18, 17], [17, 19, 17],
[18, 19, 18]]
sage: g = graphs.CompleteGraph(20).to_directed()
sage: g.all_simple_cycles(max_length=2, starting_vertices=[0])
[[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]]

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]]

all_simple_paths(starting_vertices=None, ending_vertices=None, max_length=None, triv-


ial=False)
Returns a list of all the simple paths of self starting with one of the given vertices. Simple paths are paths
in which no two arcs share a head or share a tail, i.e. every vertex in the path is entered at most once and
exited at most once.
INPUT:
• starting_vertices - list (default: None) of vertices from which the paths must start. If None,
then all vertices of the graph can be starting points.
• ending_vertices - iterable (default: None) on the allowed ending vertices of the paths. If None,
then all vertices are allowed.
• max_length - non negative integer (default: None). The maximum length of the enumerated paths.
If set to None, then all lengths are allowed.
• trivial - boolean (default: False). If set to True, then the empty paths are also enumerated.
OUTPUT:
list

Note: Although the number of simple paths of a finite graph is always finite, computing all its paths may
take a very long time.

EXAMPLES:

310 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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']]

It is also possible to bound the length of the paths:

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:

sage: g.all_simple_paths(starting_vertices=['a'], trivial=True)


[['a'], ['a', 'a'], ['a', 'b'], ['a', 'b', 'c'],
['a', 'b', 'c', 'd']]
sage: g.all_simple_paths(starting_vertices=['a'], trivial=False)
[['a', 'a'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'd']]

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.

1.3. Directed graphs 311


Sage Reference Manual: Graph Theory, Release 8.4

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:

• graph6_string() – a similar string format for undirected graphs

EXAMPLES:
sage: D = DiGraph({0: [1, 2], 1: [2], 2: [3], 3: [0]})
sage: D.dig6_string()
'CW`_'

feedback_edge_set(constraint_generation=True, value_only=False, solver=None, verbose=0)


Computes the minimum feedback edge set of a digraph (also called feedback arc set).
The minimum feedback edge set of a digraph is a set of edges that intersect all the circuits of the digraph.
Equivalently, a minimum feedback arc set of a DiGraph is a set 𝑆 of arcs such that the digraph 𝐺 − 𝑆 is
acyclic. For more information, see the Wikipedia article Feedback_arc_set.
INPUT:
• value_only – boolean (default: False)
– When set to True, only the minimum cardinal of a minimum edge set is returned.
– When set to False, the Set of edges of a minimal edge set is returned.
• constraint_generation (boolean) – whether to use constraint generation when solving the
Mixed Integer Linear Program (default: True).
• solver – (default: None) Specify a Linear Program (LP) solver to be used. If set to None, the
default one is used. For more information on LP solvers and which default solver is used, see the
method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0). Sets the level of verbosity. Set to 0 by default, which means quiet.
ALGORITHM:
This problem is solved using Linear Programming, in two different ways. The first one is to solve the
following formulation:
∑︁
Minimize : 𝑏(𝑢,𝑣)
(𝑢,𝑣)∈𝐺

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.

312 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(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].

1.3. Directed graphs 313


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: G = DiGraph({1: [2, 3], 2: [4], 3: [4]})


sage: fl = G.flow_polytope(); fl
A 1-dimensional polyhedron in QQ^4 defined as the convex hull
of 2 vertices
sage: fl.vertices()
(A vertex at (0, 1, 0, 1), A vertex at (1, 0, 1, 0))

Using a different order for the edges of the graph:

sage: fl = G.flow_polytope(edges=G.edges(key=lambda x: x[0]-x[1])); fl


A 1-dimensional polyhedron in QQ^4 defined as the convex hull
of 2 vertices
sage: fl.vertices()
(A vertex at (0, 1, 1, 0), A vertex at (1, 0, 0, 1))

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))

Restricting to a subset of the edges:

sage: fl = H.flow_polytope(edges=[(0, 1, None), (1, 2, None),


....: (2, 3, None), (0, 3, None)])
sage: fl
A 1-dimensional polyhedron in QQ^4 defined as the convex hull
of 2 vertices
sage: fl.vertices()
(A vertex at (0, 0, 0, 1), A vertex at (1, 1, 1, 0))

314 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

Using a different choice of sources and sinks:

sage: fl = H.flow_polytope(ends=([1], [3])); fl


A 1-dimensional polyhedron in QQ^6 defined as the convex hull
of 2 vertices
sage: fl.vertices()
(A vertex at (0, 0, 0, 1, 0, 1), A vertex at (0, 0, 0, 0, 1, 0))
sage: fl = H.flow_polytope(ends=([0, 1], [3])); fl
The empty polyhedron in QQ^6
sage: fl = H.flow_polytope(ends=([3], [0])); fl
The empty polyhedron in QQ^6
sage: fl = H.flow_polytope(ends=([0, 1], [2, 3])); fl
A 3-dimensional polyhedron in QQ^6 defined as the convex hull
of 5 vertices
sage: fl.vertices()
(A vertex at (0, 0, 1, 1, 0, 0),
A vertex at (0, 1, 0, 0, 1, 0),
A vertex at (1, 0, 0, 2, 0, 1),
A vertex at (1, 0, 0, 1, 1, 0),
A vertex at (0, 1, 0, 1, 0, 1))
sage: fl = H.flow_polytope(edges=[(0, 1, None), (1, 2, None),
....: (2, 3, None), (0, 2, None),
....: (1, 3, None)],
....: ends=([0, 1], [2, 3])); fl
A 2-dimensional polyhedron in QQ^5 defined as the convex hull
of 4 vertices
sage: fl.vertices()
(A vertex at (0, 0, 0, 1, 1),
A vertex at (1, 2, 1, 0, 0),
A vertex at (1, 1, 0, 0, 1),
A vertex at (0, 1, 1, 1, 0))

A digraph with one source and two sinks:

sage: Y = DiGraph({1: [2], 2: [3, 4]})


sage: Y.flow_polytope()
The empty polyhedron in QQ^3

A digraph with one vertex and no edge:

sage: Z = DiGraph({1: []})


sage: Z.flow_polytope()
A 0-dimensional polyhedron in QQ^0 defined as the convex hull
of 1 vertex

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,

1.3. Directed graphs 315


Sage Reference Manual: Graph Theory, Release 8.4

although its worst case time complexity is in 𝑂(𝑛2 ).


INPUT:
• r – a vertex of the digraph, the root of the immediate dominators tree
• reverse – boolean (default: False); When set to True, we consider the reversed digraph in which
out-neighbors become the in-neighbors and vice-versa. This option is available only if the backend of
the digraph is SparseGraphBackend.
OUTPUT: The (immediate) dominator tree rooted at 𝑟, encoded as a predecessor dictionary.
EXAMPLES:
The output encodes a tree rooted at 𝑟:

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.

See https://trac.sagemath.org/25030 for details.


sage: T = DiGraph([(d[u], u) for u in d if u != d[u]])
sage: Graph(T).is_tree()
True
sage: all(T.in_degree(u) <= 1 for u in T)
True

In a strongly connected digraph, the result depends on the root:

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}

The (immediate) dominator tree contains only reachable vertices:

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}

Immediate dominators in the reverse digraph:

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:

• Wikipedia article Dominator_(graph_theory)


• strong_articulation_points()

316 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

• strongly_connected_components()

in_degree(vertices=None, labels=False)
Same as degree, but for in degree.
EXAMPLES:

sage: D = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] }


˓→)

sage: D.in_degree(vertices = [0,1,2], labels=True)


{0: 2, 1: 2, 2: 2}
sage: D.in_degree()
[2, 2, 2, 2, 1, 1]
sage: G = graphs.PetersenGraph().to_directed()
sage: G.in_degree(0)
3

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]

sage: V = [2, 3, 5, 7, 8, 9, 10, 11]


sage: E = [[], [8, 10], [11], [8, 11], [9], [], [], [2, 9, 10]]
sage: g = DiGraph(dict(zip(V, E)))
(continues on next page)

1.3. Directed graphs 317


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: g.in_degree_sequence()
[2, 2, 2, 2, 1, 0, 0, 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:

sage: D = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] }


˓→)

sage: for a in D.incoming_edge_iterator([0]):


....: print(a)
(1, 0, None)
(4, 0, None)

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 = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] }


˓→)

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:

sage: g = DiGraph({ 0: [1], 1: [0] })


sage: g.is_aperiodic()
False

The following graph has a cycle of length 2 and a cycle of length 3, so it is aperiodic:

sage: g = DiGraph({ 0: [1, 4], 1: [2], 2: [0], 4: [0]})


sage: g.is_aperiodic()
True

See also:
period()

318 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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 = DiGraph({ 0:[1,2,3], 4:[2,5], 1:[8], 2:[7], 3:[7], 5:[6,7], 7:[8],


˓→6:[9], 8:[10], 9:[10] })

sage: D.plot(layout='circular').show()
sage: D.is_directed_acyclic()
True

Adding an edge from 9 to 7 does not change it:

sage: D.add_edge(9,7)
sage: D.is_directed_acyclic()
True

We can obtain as a proof an ordering of the vertices such that 𝑢 appears before 𝑣 if 𝑢𝑣 is an edge of the
graph:

sage: D.is_directed_acyclic(certificate = True)


(True, [4, 5, 6, 9, 0, 1, 2, 3, 7, 8, 10])

Adding an edge from 7 to 4, though, makes a difference:

sage: D.add_edge(7,4)
sage: D.is_directed_acyclic()
False

Indeed, it creates a circuit 7, 4, 5:

1.3. Directed graphs 319


Sage Reference Manual: Graph Theory, Release 8.4

sage: D.is_directed_acyclic(certificate = True)


(False, [7, 4, 5])

Checking acyclic graphs are indeed acyclic

sage: def random_acyclic(n, p):


....: g = graphs.RandomGNP(n, p)
....: h = DiGraph()
....: h.add_edges([ ((u,v) if u<v else (v,u)) for u,v,_ in g.edges() ])
....: return h
...
sage: all( random_acyclic(100, .2).is_directed_acyclic() # long time
....: for i in range(50)) # long time
True

is_strongly_connected(G)
Returns whether the current DiGraph is strongly connected.
EXAMPLES:
The circuit is obviously strongly connected

sage: from sage.graphs.connectivity import is_strongly_connected


sage: g = digraphs.Circuit(5)
sage: is_strongly_connected(g)
True
sage: g.is_strongly_connected()
True

But a transitive triangle is not:

sage: g = DiGraph({ 0 : [1,2], 1 : [2]})


sage: is_strongly_connected(g)
False

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:

• Wikipedia article Tournament_(graph_theory)


• RandomTournament()
• TransitiveTournament()

320 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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)

1.3. Directed graphs 321


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: pos[1][1] > pos[0][1] + .5
True
sage: pos = H.layout_acyclic(rankdir='down')
sage: pos[1][1] < pos[0][1] - .5
True
sage: pos = H.layout_acyclic(rankdir='right')
sage: pos[1][0] > pos[0][0] + .5
True
sage: pos = H.layout_acyclic(rankdir='left')
sage: pos[1][0] < pos[0][0] - .5
True

layout_acyclic_dummy(heights=None, 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 a spring layout with fixed vertical placement of the vertices other-
wise (see layout_acyclic_dummy() and layout_ranked()).
INPUT:
• rankdir – ‘up’, ‘down’, ‘left’, or ‘right’ (default: ‘up’): which direction the edges should point
toward
• **options – passed down to layout_ranked()
EXAMPLES:

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

322 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

the usual level set decomposition of the corresponding poset.


EXAMPLES:

sage: H = DiGraph({0:[1,2],1:[3],2:[3],3:[],5:[1,6],6:[2,3]})
sage: H.level_sets()
[[0, 5], [1, 6], [2], [3]]

sage: H = DiGraph({0:[1,2],1:[3],2:[3],3:[1],5:[1,6],6:[2,3]})
sage: H.level_sets()
[[0, 5], [6], [2]]

This routine is mostly used for Hasse diagrams of posets:

sage: from sage.combinat.posets.hasse_diagram import HasseDiagram


sage: H = HasseDiagram({0:[1,2],1:[3],2:[3],3:[]})
sage: [len(x) for x in H.level_sets()]
[1, 2, 1]

sage: from sage.combinat.posets.hasse_diagram import HasseDiagram


sage: H = HasseDiagram({0:[1,2], 1:[3], 2:[4], 3:[4]})
sage: [len(x) for x in H.level_sets()]
[1, 2, 1, 1]

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:

sage: D = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] }


˓→)

sage: for a in D.neighbor_in_iterator(0):


....: print(a)
1
4

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:

sage: D = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] }


˓→)

sage: for a in D.neighbor_out_iterator(0):


....: print(a)
1
2
3

neighbors_in(vertex)
Returns the list of the in-neighbors of a given vertex.

1.3. Directed graphs 323


Sage Reference Manual: Graph Theory, Release 8.4

An vertex 𝑢 is an in-neighbor of a vertex 𝑣 if 𝑢𝑣 in an edge.


EXAMPLES:

sage: D = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] }


˓→)

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 = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] }


˓→)

sage: D.neighbors_out(0)
[1, 2, 3]

out_degree(vertices=None, labels=False)
Same as degree, but for out degree.
EXAMPLES:

sage: D = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] }


˓→)

sage: D.out_degree(vertices = [0,1,2], labels=True)


{0: 3, 1: 2, 2: 1}
sage: D.out_degree()
[3, 2, 1, 1, 2, 1]
sage: D.out_degree(2)
1

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)

324 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


((1, 0), 2)
((0, 2), 3)

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]

sage: V = [2, 3, 5, 7, 8, 9, 10, 11]


sage: E = [[], [8, 10], [11], [8, 11], [9], [], [], [2, 9, 10]]
sage: g = DiGraph(dict(zip(V, E)))
sage: g.out_degree_sequence()
[3, 2, 2, 1, 1, 0, 0, 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:

sage: D = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] }


˓→)

sage: for a in D.outgoing_edge_iterator([0]):


....: print(a)
(0, 1, None)
(0, 2, None)
(0, 3, None)

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 = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] }


˓→)

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:

1.3. Directed graphs 325


Sage Reference Manual: Graph Theory, Release 8.4

sage: Q = DiGraph({1:{2:['a','c']}, 2:{3:['b']}})


sage: F = Q.path_semigroup(); F
Partial semigroup formed by the directed paths of Multi-digraph on 3 vertices
sage: list(F)
[e_1, e_2, e_3, a, c, b, a*b, c*b]

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:

sage: g = DiGraph({0: [1], 1: [0]})


sage: g.period()
2

The following graph has a cycle of length 2 and a cycle of length 3, so it has period 1:

sage: g = DiGraph({0: [1, 4], 1: [2], 2: [0], 4: [0]})


sage: g.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:

sage: g = DiGraph({-1: [-2], -2: [-3], -3: [-1],


....: 1: [2], 2: [1]})
sage: g.period()
1
sage: sorted([s.period() for s
....: in g.strongly_connected_components_subgraphs()])
[2, 3]

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:

sage: D = DiGraph({ 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] })


sage: D.reverse()
Reverse of (): Digraph on 6 vertices

reverse_edge(u, v=None, label=None, inplace=True, multiedges=None)


Reverses the edge from u to v.
INPUT:
• inplace – (default: True) if False, a new digraph is created and returned as output, otherwise
self is modified.

326 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

• 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 inplace is False, self is not modified and a new digraph is returned:


sage: D = DiGraph([(0,1,2)])
sage: re = D.reverse_edge(0,1, inplace=False)
sage: re.edges()
[(1, 0, 2)]
sage: D.edges()
[(0, 1, 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

1.3. Directed graphs 327


Sage Reference Manual: Graph Theory, Release 8.4

If user specifies multiedges = False, self will not be forced to allow parallel edges and a parallel
edge will get deleted:

sage: D = DiGraph( [(1, 2, 'A'), (2, 1,'A'), (2, 3, None)] )


sage: D.edges()
[(1, 2, 'A'), (2, 1, 'A'), (2, 3, None)]
sage: D.reverse_edge(1,2, multiedges=False)
sage: D.edges()
[(2, 1, 'A'), (2, 3, None)]

Note that in the following graph, specifying multiedges = False will result in overwriting the label
of (1, 2) with the label of (2, 1):

sage: D = DiGraph( [(1, 2, 'B'), (2, 1,'A'), (2, 3, None)] )


sage: D.edges()
[(1, 2, 'B'), (2, 1, 'A'), (2, 3, None)]
sage: D.reverse_edge(2,1, multiedges=False)
sage: D.edges()
[(1, 2, 'A'), (2, 3, None)]

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:

sage: D = DiGraph([[0,1,2],[1,2,1]], weighted=True)


sage: D.reverse_edge(0,1)
sage: D.edges()
[(1, 0, 2), (1, 2, 1)]
sage: re = D.reverse_edge([1,2],inplace=False)
sage: re.edges()
[(1, 0, 2), (2, 1, 1)]

If self has multiple copies (parallel edges) of the input edge, only 1 of the parallel edges is reversed:

sage: D = DiGraph([(0,1,'01'),(0,1,'01'),(0,1,'cat'),(1,2,'12')], weighted =


˓→True, multiedges = true)

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 = DiGraph([(0,1,'A'),(0,1,'B'),(0,1,'mouse'),(0,1,'cat')], multiedges


˓→= true)

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)

328 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


...
ValueError: Reversing the given edge is about to create two parallel
edges but input digraph doesn't allow them - User needs to specify
multiedges is True or False.

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)]

reverse_edges(edges, inplace=True, multiedges=None)


Reverses a list of edges.
INPUT:
• edges – a list of edges in the DiGraph.
• inplace – (default: True) if False, a new digraph is created and returned as output, otherwise
self is modified.
• multiedges – (default: None) if True, input graph will be forced to allow parallel edges when
necessary (for more information see the documentation of reverse_edge())
See also:
reverse_edge() - Reverses a single edge.
EXAMPLES:
If inplace is True (default value), self is modified:

sage: D = DiGraph({ 0: [1,1,3], 2: [3,3], 4: [1,5]}, multiedges = true)


sage: D.reverse_edges( [ [0,1], [0,3] ])
sage: D.reverse_edges( [ (2,3),(4,5) ])
sage: D.edges()
[(0, 1, None), (1, 0, None), (2, 3, None), (3, 0, None),
(3, 2, None), (4, 1, None), (5, 4, None)]

If inplace is False, self is not modified and a new digraph is returned:

sage: D = DiGraph ([(0,1,'A'),(1,0,'B'),(1,2,'C')])


sage: re = D.reverse_edges( [ (0,1), (1,2) ],
....: inplace = False,
....: multiedges = True)
sage: re.edges()
[(1, 0, 'A'), (1, 0, 'B'), (2, 1, 'C')]
sage: D.edges()
[(0, 1, 'A'), (1, 0, 'B'), (1, 2, 'C')]
(continues on next page)

1.3. Directed graphs 329


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: D.allows_multiple_edges()
False
sage: re.allows_multiple_edges()
True

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_edges([(1,2),(2,3)], multiedges=True)
sage: D.edges()
[(2, 1, 'A'), (2, 1, 'A'), (3, 2, 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_edges([(2,3)], multiedges=True)
sage: D.edges()
[(1, 2, 'A'), (2, 1, 'A'), (3, 2, None)]
sage: D.allows_multiple_edges()
False

If multiedges is False, self will not be forced to allow parallel edges and an edge will get deleted:

sage: D = DiGraph( [(1,2), (2,1)] )


sage: D.edges()
[(1, 2, None), (2, 1, None)]
sage: D.reverse_edges([(1,2)], multiedges=False)
sage: D.edges()
[(2, 1, None)]

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:

sage: D = DiGraph([(0,1,'01'),(1,2,1),(2,3,'23')], weighted = True)


sage: D.reverse_edges([(0,1,'01'),(1,2),(2,3)])
sage: D.edges()
[(1, 0, '01'), (2, 1, 1), (3, 2, '23')]

sinks()
Returns a list of sinks of the digraph.
OUTPUT:
• list, the vertices of the digraph that have no edges beginning at them
EXAMPLES:

sage: G = DiGraph({1:{3:['a']}, 2:{3:['b']}})


sage: G.sinks()
[3]
sage: T = DiGraph({1:{}})
sage: T.sinks()
[1]

sources()
Returns a list of sources of the digraph.

330 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

OUTPUT:
• list, the vertices of the digraph that have no edges going into them
EXAMPLES:

sage: G = DiGraph({1:{3:['a']}, 2:{3:['b']}})


sage: G.sources()
[1, 2]
sage: T = DiGraph({1:{}})
sage: T.sources()
[1]

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: from sage.graphs.connectivity import strong_articulation_points


sage: D = digraphs.Complete(4)
sage: D.add_clique([3, 4, 5, 6])
sage: strong_articulation_points(D)
[3]
sage: D.strong_articulation_points()
[3]

Two cliques connected by some arcs:

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

1.3. Directed graphs 331


Sage Reference Manual: Graph Theory, Release 8.4

EXAMPLES:
In the symmetric digraph of a graph, the strongly connected components are the connected components:

sage: from sage.graphs.connectivity import strongly_connected_component_


˓→containing_vertex

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: from sage.graphs.base.static_sparse_graph import tarjan_strongly_


˓→connected_components

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)

332 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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: from sage.graphs.connectivity import strongly_connected_components_


˓→digraph

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:

sage: g = DiGraph({0:{1:"01", 2: "02", 3: "03"}, 1: {2: "12"}, 2:{1: "21", 3:


˓→"23"}})

sage: scc_digraph = strongly_connected_components_digraph(g)


sage: scc_digraph.vertices(key=sorted)
[{0}, {1, 2}, {3}]
sage: scc_digraph.edges()
[({0}, {1, 2}, None), ({0}, {3}, None), ({1, 2}, {3}, None)]

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: g = DiGraph({0:{1:"0-12", 2: "0-12", 3: "0-3"}, 1: {2: "1-2", 3: "1-3"},


˓→ 2:{1: "2-1", 3: "2-3"}})

sage: scc_digraph = strongly_connected_components_digraph(g, keep_labels =


˓→True)

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')]

1.3. Directed graphs 333


Sage Reference Manual: Graph Theory, Release 8.4

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

to_undirected(implementation=’c_graph’, data_structure=None, sparse=None)


Returns an undirected version of the graph. Every directed edge becomes an edge.
INPUT:
• data_structure – one of "sparse", "static_sparse", or "dense". See the documen-
tation of Graph or DiGraph.
• sparse (boolean) – sparse=True is an alias for data_structure="sparse", and
sparse=False is an alias for data_structure="dense".
EXAMPLES:
sage: D = DiGraph({0:[1,2],1:[0]})
sage: G = D.to_undirected()
sage: D.edges(labels=False)
[(0, 1), (0, 2), (1, 0)]
sage: G.edges(labels=False)
[(0, 1), (0, 2)]

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).

334 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

EXAMPLES:

sage: D = DiGraph({ 0:[1,2,3], 4:[2,5], 1:[8], 2:[7], 3:[7],


....: 5:[6,7], 7:[8], 6:[9], 8:[10], 9:[10] })
sage: D.plot(layout='circular').show()
sage: D.topological_sort()
[4, 5, 6, 9, 0, 1, 2, 3, 7, 8, 10]

sage: D.add_edge(9,7)
sage: D.topological_sort()
[4, 5, 6, 9, 0, 1, 2, 3, 7, 8, 10]

Using the NetworkX implementation

sage: list(D.topological_sort(implementation = "NetworkX"))


[4, 5, 6, 9, 0, 3, 2, 7, 1, 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: D = DiGraph({ 0:[1,2], 1:[3], 2:[3,4] })


sage: D.plot(layout='circular').show()
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]]

sage: for sort in D.topological_sort_generator():


....: for edge in D.edge_iterator():
....: u,v,l = edge
....: if sort.index(u) > sort.index(v):
....: print("This should never happen.")

1.3. Directed graphs 335


Sage Reference Manual: Graph Theory, Release 8.4

1.4 Bipartite graphs

This module implements bipartite graphs.


AUTHORS:
• Robert L. Miller (2008-01-20): initial version
• Ryan W. Hinton (2010-03-04): overrides for adding and deleting vertices and edges

sage: B = BipartiteGraph(graphs.CycleGraph(4))
sage: B == B.copy()
True
sage: type(B.copy())
<class 'sage.graphs.bipartite_graph.BipartiteGraph'>

class sage.graphs.bipartite_graph.BipartiteGraph(data=None, partition=None,


check=True, *args, **kwds)
Bases: sage.graphs.graph.Graph
Bipartite graph.
INPUT:
• data – can be any of the following:
1. Empty or None (creates an empty graph).
2. An arbitrary graph.
3. A reduced adjacency matrix.
4. A file in alist format.
5. From a NetworkX bipartite 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]]. The columns correspond to vertices on the left, and the rows
correspond to vertices on the right.
The alist file format is described at http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html
• partition – (default: None) a tuple defining vertices of the left and right partition of the graph. Parti-
tions will be determined automatically if partition``=``None.
• check – (default: True) if True, an invalid input partition raises an exception. In the other case offend-
ing edges simply won’t be included.

Note: All remaining arguments are passed to the Graph constructor

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)

336 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: B == BipartiteGraph(None)
True

2. From a graph: without any more information, finds a bipartition:

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: B = BipartiteGraph(P, partition, check=False)


sage: B.left
{0, 1, 2, 3, 4}
sage: B.show()

sage: G = Graph({0:[5,6], 1:[4,5], 2:[4,6], 3:[4,5,6]})


sage: B = BipartiteGraph(G)
sage: B2 = BipartiteGraph(B)
sage: B == B2
True
sage: B3 = BipartiteGraph(G, [list(range(4)), list(range(4,7))])
sage: B3
Bipartite graph on 7 vertices
sage: B3 == B2
True

1.4. Bipartite graphs 337


Sage Reference Manual: Graph Theory, Release 8.4

sage: G = Graph({0:[], 1:[], 2:[]})


sage: part = (list(range(2)), [2])
sage: B = BipartiteGraph(G, part)
sage: B2 = BipartiteGraph(B)
sage: B == B2
True

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}

1. From a reduced adjacency matrix:

sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0),


....: (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)])
sage: M
[1 1 1 0 0 0 0]
[1 0 0 1 1 0 0]
[0 1 0 1 0 1 0]
[1 1 0 1 0 0 1]
sage: H = BipartiteGraph(M); H
Bipartite graph on 11 vertices
sage: H.edges()
[(0, 7, None),
(0, 8, None),
(0, 10, None),
(1, 7, None),
(1, 9, None),
(1, 10, None),
(2, 7, None),
(3, 8, None),
(3, 9, None),
(3, 10, None),
(4, 8, None),
(5, 9, None),
(6, 10, None)]

sage: M = Matrix([(1, 1, 2, 0, 0), (0, 2, 1, 1, 1), (0, 1, 2, 1, 1)])


sage: B = BipartiteGraph(M, multiedges=True, sparse=True)
sage: B.edges()
[(0, 5, None),
(1, 5, None),
(1, 6, None),
(1, 6, None),
(1, 7, None),
(2, 5, None),
(2, 5, None),
(2, 6, None),
(2, 7, None),
(2, 7, None),
(continues on next page)

338 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


(3, 6, None),
(3, 7, None),
(4, 6, None),
(4, 7, None)]

sage: F.<a> = GF(4)


sage: MS = MatrixSpace(F, 2, 3)
sage: M = MS.matrix([[0, 1, a+1], [a, 1, 1]])
sage: B = BipartiteGraph(M, weighted=True, sparse=True)
sage: B.edges()
[(0, 4, a), (1, 3, 1), (1, 4, 1), (2, 3, a + 1), (2, 4, 1)]
sage: B.weighted()
True

1. From an alist file:

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(file_name)
sage: B == H
True

2. From a NetworkX bipartite graph:

sage: import networkx


sage: G = graphs.OctahedralGraph()
sage: N = networkx.make_clique_bipartite(G.networkx_graph())
sage: B = BipartiteGraph(N)

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):

1.4. Bipartite graphs 339


Sage Reference Manual: Graph Theory, Release 8.4

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

add_edge(u, v=None, label=None)


Adds an edge from u and v.
INPUT:
• u – the tail of an edge.
• v – (default: None) the head of an edge. If v=None, then attempt to understand u as a edge tuple.
• label – (default: None) the label of the edge (u, v).
The following forms are all accepted:
• G.add_edge(1, 2)
• G.add_edge((1, 2))
• G.add_edges([(1, 2)])
• G.add_edge(1, 2, 'label')
• G.add_edge((1, 2, 'label'))
• G.add_edges([(1, 2, 'label')])
See Graph.add_edge for more detail.
This method simply checks that the edge endpoints are in different partitions. If a new vertex is to be
created, it will be added to the proper partition. If both vertices are created, the first one will be added to
the left partition, the second to the right partition.
add_vertex(name=None, left=False, right=False)
Creates an isolated vertex. If the vertex already exists, then nothing is done.
INPUT:
• name – (default: None) name of the new vertex. If no name is specified, then the vertex will be
represented by the least non-negative integer not already representing a vertex. Name must be an
immutable object and cannot be None.
• left – (default: False) if True, puts the new vertex in the left partition.
• right – (default: False) if True, puts the new vertex in the right partition.
Obviously, left and right are mutually exclusive.
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:

340 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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}

add_vertices(vertices, left=False, right=False)


Add vertices to the bipartite graph from an iterable container of vertices. Vertices that already exist in the
graph will not be added again.
INPUT:
• vertices – sequence of vertices to add.
• left – (default: False) either True or sequence of same length as vertices with True/False
elements.
• right – (default: False) either True or sequence of the same length as vertices with
True/False elements.
Only one of left and right keywords should be provided. See the examples below.
EXAMPLES:

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

1.4. Bipartite graphs 341


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: B = BipartiteGraph({1: [2, 4], 3: [4, 5]})


sage: G = B.complement(); G
Graph on 5 vertices
sage: G.edges(labels=False)
[(1, 3), (1, 5), (2, 3), (2, 4), (2, 5), (4, 5)]

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.

sage: g = Graph({'a':['b'], 'c':['b']})


sage: bg = BipartiteGraph(g) # finds bipartition
sage: bg.vertices()
['a', 'b', 'c']
sage: bg.delete_vertex('a')
sage: bg.edges()
[('b', 'c', None)]
(continues on next page)

342 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: bg.vertices()
['b', 'c']
sage: bg2 = BipartiteGraph(g)
sage: bg2.delete_vertex(0, in_order=True)
sage: bg2 == bg
True

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)

1.4. Bipartite graphs 343


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


(2, 7, None),
(3, 8, None),
(3, 9, None),
(3, 10, None),
(4, 8, None),
(5, 9, None),
(6, 10, None)]
sage: B2 = BipartiteGraph(file_name)
sage: B2 == B
True

matching(value_only=False, algorithm=None, use_edge_labels=False, solver=None, verbose=0)


Return a maximum matching of the graph represented by the list of its edges.
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.
INPUT:
• value_only – boolean (default: False); when set to True, only the cardinal (or the weight) of
the matching is returned
• algorithm – string (default: "Hopcroft-Karp" if use_edge_labels==False, otherwise
"Edmonds")
– "Hopcroft-Karp" selects the default bipartite graph algorithm as implemented in NetworkX
– "Eppstein" selects Eppstein’s algorithm as implemented in NetworkX
– "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); only if algorithm is "Edmonds", "LP"
– when set to False, each edge has weight 1
• solver – (default: None) a specific Linear Program (LP) solver to be used
• verbose – integer (default: 0); sets the level of verbosity: set to 0 by default, which means quiet
See also:

• Wikipedia article Matching_(graph_theory)


• matching()

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)]

The size of a maximum matching in a complete bipartite graph using Eppstein:

344 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

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

Compute the matching polynomial of a line with 60 vertices:

sage: from sage.functions.orthogonal_polys import chebyshev_U


sage: g = next(graphs.trees(60))
sage: chebyshev_U(60, x/2) == BipartiteGraph(g).matching_polynomial(algorithm=
˓→'rook')

True

The matching polynomial of a tree graphs is equal to its characteristic polynomial:

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:

1.4. Bipartite graphs 345


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0),


....: (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)])
sage: B = BipartiteGraph(M)
sage: N = B.reduced_adjacency_matrix()
sage: N
[1 1 1 0 0 0 0]
[1 0 0 1 1 0 0]
[0 1 0 1 0 1 0]
[1 1 0 1 0 0 1]
sage: N == M
True
sage: N[0,0].parent()
Integer Ring

Multi-edge graphs also return a matrix over ZZ:

sage: M = Matrix([(1,1,2,0,0), (0,2,1,1,1), (0,1,2,1,1)])


sage: B = BipartiteGraph(M, multiedges=True, sparse=True)
sage: N = B.reduced_adjacency_matrix()
sage: N == M
True
sage: N[0,0].parent()
Integer Ring

Weighted graphs will return a matrix over the ring given by their (first) weights:

sage: F.<a> = GF(4)


sage: MS = MatrixSpace(F, 2, 3)
sage: M = MS.matrix([[0, 1, a+1], [a, 1, 1]])
(continues on next page)

346 Chapter 1. Graph objects and methods


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: B = BipartiteGraph(M, weighted=True, sparse=True)
sage: N = B.reduced_adjacency_matrix(sparse=False)
sage: N == M
True
sage: N[0,0].parent()
Finite Field in a of size 2^2

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:

sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0),


....: (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)])
sage: M
[1 1 1 0 0 0 0]
[1 0 0 1 1 0 0]
[0 1 0 1 0 1 0]
[1 1 0 1 0 0 1]
sage: b = BipartiteGraph(M)
sage: file_name = os.path.join(SAGE_TMP, 'deleteme.alist.txt')
sage: b.save_afile(file_name)
sage: b2 = BipartiteGraph(file_name)
sage: b == b2
True

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

vertex_cover(algorithm=’Konig’, value_only=False, reduction_rules=True, solver=None, ver-


bosity=0)
Return a minimum vertex cover of self represented by a set of vertices.
A minimum vertex cover of a graph is a set 𝑆 of vertices such that each edge is incident to at least one
element of 𝑆, and such that 𝑆 is of minimum cardinality. For more information, see Wikipedia article
Vertex_cover.
Equivalently, a vertex cover is defined as the complement of an independent set.
As an optimization problem, it can be expressed as follows:
∑︁
Minimize : 𝑏𝑣
𝑣∈𝐺
Such that : ∀(𝑢, 𝑣) ∈ 𝐺.𝑒𝑑𝑔𝑒𝑠(), 𝑏𝑢 + 𝑏𝑣 ≥ 1
∀𝑥 ∈ 𝐺, 𝑏𝑥 is a binary variable

INPUT:
• algorithm – string (default: "Konig"). Indicating which algorithm to use. It can be one of those
values.

1.4. Bipartite graphs 347


Sage Reference Manual: Graph Theory, Release 8.4

– "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

The two algorithms should return the same result:

sage: g = BipartiteGraph(graphs.RandomBipartite(10, 10, .5))


sage: vc1 = g.vertex_cover(algorithm="Konig")
sage: vc2 = g.vertex_cover(algorithm="Cliquer")
sage: len(vc1) == len(vc2)
True

348 Chapter 1. Graph objects and methods


CHAPTER

TWO

CONSTRUCTORS AND DATABASES

2.1 Common Graphs

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)

To get a path with 4 vertices, and the house graph:

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

AztecDiamondGraph CompleteMultipartiteGraph LadderGraph


BullGraph DiamondGraph LollipopGraph
ButterflyGraph DipoleGraph PathGraph
CircularLadderGraph EmptyGraph StarGraph
ClawGraph Grid2dGraph TadpoleGraph
CycleGraph GridGraph ToroidalGrid2dGraph
CompleteBipartiteGraph HouseGraph Toroidal6RegularGrid2dGraph
CompleteGraph HouseXGraph

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

Balaban10Cage GossetGraph MoebiusKantorGraph


Balaban11Cage GrayGraph MoserSpindle
BidiakisCube GrotzschGraph NauruGraph
BiggsSmithGraph HallJankoGraph PappusGraph
BlanusaFirstSnarkGraph HarborthGraph PoussinGraph
BlanusaSecondSnarkGraph HarriesGraph PerkelGraph
BrinkmannGraph HarriesWongGraph PetersenGraph
BrouwerHaemersGraph HeawoodGraph RobertsonGraph
BuckyBall HerschelGraph SchlaefliGraph
CameronGraph HigmanSimsGraph ShrikhandeGraph
Cell600 HoffmanGraph SimsGewirtzGraph
Cell120 HoffmanSingletonGraph SousselierGraph
ChvatalGraph HoltGraph SylvesterGraph
ClebschGraph HortonGraph SzekeresSnarkGraph
CoxeterGraph IoninKharaghani765Graph ThomsenGraph
DesarguesGraph JankoKharaghaniGraph TietzeGraph
DejterGraph JankoKharaghaniTonchevGraph
TruncatedIcosidodecahedralGraph
DoubleStarSnark KittellGraph TruncatedTetrahedralGraph
DurerGraph KrackhardtKiteGraph Tutte12Cage
DyckGraph Klein3RegularGraph TutteCoxeterGraph
EllinghamHorton54Graph Klein7RegularGraph TutteGraph
EllinghamHorton78Graph LocalMcLaughlinGraph U42Graph216
ErreraGraph LjubljanaGraph U42Graph540
F26AGraph LivingstoneGraph WagnerGraph
FlowerSnark M22Graph WatkinsSnarkGraph
FolkmanGraph MarkstroemGraph WellsGraph
FosterGraph MathonStronglyRegularGraphWienerArayaGraph
FranklinGraph McGeeGraph SuzukiGraph
FruchtGraph McLaughlinGraph
GoldnerHararyGraph MeredithGraph

Platonic solids (ordered ascending by number of vertices)

TetrahedralGraph HexahedralGraph DodecahedralGraph


OctahedralGraph IcosahedralGraph

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 . . . )

350 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

BalancedTree GeneralizedPetersenGraph OddGraph


BarbellGraph GoethalsSeidelGraph PaleyGraph
BubbleSortGraph HammingGraph PasechnikGraph
CaiFurerImmermanGraph HanoiTowerGraph petersen_family
chang_graphs HararyGraph planar_graphs
CirculantGraph HyperStarGraph quadrangulations
cospectral_graphs JohnsonGraph RingedTree
CubeGraph KneserGraph SierpinskiGasketGraph
DorogovtsevGoltsevMendesGraph
LCFGraph SquaredSkewHadamardMatrixGraph
EgawaGraph line_graph_forbidden_subgraphs
SwitchedSquaredSkewHadamardMatrixGraph
FibonacciTree MathonPseudocyclicMergingGraph
strongly_regular_graph
FoldedCubeGraph MathonPseudocyclicStronglyRegularGraph
trees
FriendshipGraph MuzychukS6Graph triangulations
fullerenes MycielskiGraph TuranGraph
FurerGadget MycielskiStep WheelGraph
fusenes NKStarGraph WindmillGraph
FuzzyBallGraph NStarGraph

Graphs from classical geometries over finite fields


A number of classes of graphs related to geometries over finite fields and quadrics and Hermitean varieties there.

AffineOrthogonalPolarGraphSymplecticDualPolarGraph Nowhere0WordsTwoWeightCodeGraph
AhrensSzekeresGeneralizedQuadrangleGraph
SymplecticPolarGraph HaemersGraph
NonisotropicOrthogonalPolarGraph
TaylorTwographDescendantSRG
CossidentePenttilaGraph
NonisotropicUnitaryPolarGraph
TaylorTwographSRG UnitaryDualPolarGraph
OrthogonalPolarGraph T2starGeneralizedQuadrangleGraph
UnitaryPolarGraph

Chessboard Graphs

BishopGraph KnightGraph RookGraph


KingGraph QueenGraph

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.

IntersectionGraph OrthogonalArrayBlockGraph ToleranceGraph


IntervalGraph PermutationGraph

Random graphs

RandomBarabasiAlbert RandomGNM RandomRegular


RandomBicubicPlanar RandomGNP RandomShell
RandomBipartite RandomHolmeKim RandomToleranceGraph
RandomRegularBipartite RandomIntervalGraph RandomTree
RandomBlockGraph RandomLobster RandomTreePowerlaw
RandomBoundedToleranceGraph
RandomNewmanWattsStrogatz RandomTriangulation

Graphs with a given degree sequence

2.1. Common Graphs 351


Sage Reference Manual: Graph Theory, Release 8.4

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

352 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

2.1.1 Functions and methods

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:

graphs(vertices, property=lambda x: True, augment='edges', size=None)

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

2.1. Common Graphs 353


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: for G in graphs(3, augment='vertices'):


....: print(G)
Graph on 0 vertices
Graph on 1 vertex
Graph on 2 vertices
Graph on 3 vertices
Graph on 3 vertices
Graph on 3 vertices
Graph on 2 vertices
Graph on 3 vertices

Note that we can also get graphs with underlying Cython implementation:

sage: for G in graphs(3, augment='vertices', implementation='c_graph'):


....: print(G)
Graph on 0 vertices
Graph on 1 vertex
Graph on 2 vertices
Graph on 3 vertices
Graph on 3 vertices
Graph on 3 vertices
Graph on 2 vertices
Graph on 3 vertices

Print graphs on 3 vertices.

sage: for G in graphs(3):


....: print(G)
Graph on 3 vertices
Graph on 3 vertices
Graph on 3 vertices
Graph on 3 vertices

Generate all graphs with 5 vertices and 4 edges.

sage: L = graphs(5, size=4)


sage: len(list(L))
6

Generate all graphs with 5 vertices and up to 4 edges.

sage: L = list(graphs(5, lambda G: G.size() <= 4))


sage: len(L)
14
sage: graphs_list.show_graphs(L) # long time

Generate all graphs with up to 5 vertices and up to 4 edges.

sage: L = list(graphs(5, lambda G: G.size() <= 4, augment='vertices'))


sage: len(L)
(continues on next page)

354 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


31
sage: graphs_list.show_graphs(L) # long time

Generate all graphs with degree at most 2, up to 6 vertices.

sage: property = lambda G: ( max([G.degree(v) for v in G] + [0]) <= 2 )


sage: L = list(graphs(6, property, augment='vertices'))
sage: len(L)
45

Generate all bipartite graphs on up to 7 vertices: (see OEIS sequence A033995)

sage: L = list( graphs(7, lambda G: G.is_bipartite(), augment='vertices') )


sage: [len([g for g in L if g.order() == i]) for i in [1..7]]
[1, 2, 3, 7, 13, 35, 88]

Generate all bipartite graphs on exactly 7 vertices:

sage: L = list( graphs(7, lambda G: G.is_bipartite()) )


sage: len(L)
88

Generate all bipartite graphs on exactly 8 vertices:

sage: L = list( graphs(8, lambda G: G.is_bipartite()) ) # long time


sage: len(L) # long time
303

Remember that the property argument does not behave as a filter, except for appropriately inheritable properties:

sage: property = lambda G: G.is_vertex_transitive()


sage: len(list(graphs(4, property)))
1
sage: sum(1 for g in graphs(4) if property(g))
4

sage: property = lambda G: G.is_bipartite()


sage: len(list(graphs(4, property)))
7
sage: sum(1 for g in graphs(4) if property(g))
7

Generate graphs on the fly: (see OEIS sequence A000088)

sage: for i in range(7):


....: print(len(list(graphs(i))))
1
1
2
4
11
34
156

Generate all simple graphs, allowing loops: (see OEIS sequence A000666)

2.1. Common Graphs 355


Sage Reference Manual: Graph Theory, Release 8.4

sage: L = list(graphs(5,augment='vertices',loops=True)) # long time


sage: for i in [0..5]: # long time
....: print((i, len([g for g in L if g.order() == i]))) # long time
(0, 1)
(1, 2)
(2, 6)
(3, 20)
(4, 90)
(5, 544)

Generate all graphs with a specified degree sequence (see OEIS sequence A002851):

sage: for i in [4,6,8]: # long time (4s on sage.math, 2012)


....: print((i, len([g for g in graphs(i, degree_sequence=[3]*i) if g.is_
˓→connected()])))

(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)

sage: print((10, len([g for g in graphs(10,degree_sequence=[3]*10) if g.is_


˓→connected()]))) # not tested

(10, 19)

Make sure that the graphs are really independent and the generator survives repeated vertex removal (trac ticket
#8458):

sage: for G in graphs(3):


....: G.delete_vertex(0)
....: print(G.order())
2
2
2
2

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.

356 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

• 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

Some examples from Brouwer’s table or strongly regular graphs:

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)

When sign is None:

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

static AfricaMap(continental=False, year=2018)


Return African states as a graph of common border.
“African state” here is defined as an independent state having the capital city in Africa. The graph has an
edge between those countries that have common land border.
INPUT:
• continental, a Boolean – if set, only return states in the continental Africa
• year – reserved for future use
EXAMPLES:

sage: Africa = graphs.AfricaMap(); Africa


Africa Map: Graph on 54 vertices
sage: sorted(Africa.neighbors('Libya'))
['Algeria', 'Chad', 'Egypt', 'Niger', 'Sudan', 'Tunisia']

sage: cont_Africa = graphs.AfricaMap(continental=True)


sage: cont_Africa.order()
48
(continues on next page)

2.1. Common Graphs 357


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: 'Madagaskar' in cont_Africa
False

static AhrensSzekeresGeneralizedQuadrangleGraph(q, dual=False)


Return the collinearity graph of the generalized quadrangle 𝐴𝑆(𝑞), or of its dual
Let 𝑞 be an odd prime power. 𝐴𝑆(𝑞) is a generalized quadrangle [GQwiki] of order (𝑞 − 1, 𝑞 + 1), see
3.1.5 in [PT09]. Its points are elements of 𝐹𝑞3 , and lines are sets of size 𝑞 of the form
• {(𝜎, 𝑎, 𝑏) | 𝜎 ∈ 𝐹𝑞 }
• {(𝑎, 𝜎, 𝑏) | 𝜎 ∈ 𝐹𝑞 }
• {(𝑐𝜎 2 − 𝑏𝜎 + 𝑎, −2𝑐𝜎 + 𝑏, 𝜎) | 𝜎 ∈ 𝐹𝑞 },
where 𝑎, 𝑏, 𝑐 are arbitrary elements of 𝐹𝑞 .
INPUT:
• q – a power of an odd prime number
• dual – if False (default), return the collinearity graph of 𝐴𝑆(𝑞). Otherwise return the collinearity
graph of the dual 𝐴𝑆(𝑞).
EXAMPLES:

sage: g=graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5); g
AS(5); GQ(4, 6): Graph on 125 vertices
sage: g.is_strongly_regular(parameters=True)
(125, 28, 3, 7)
sage: g=graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5,dual=True); g
AS(5)*; GQ(6, 4): Graph on 175 vertices
sage: g.is_strongly_regular(parameters=True)
(175, 30, 5, 5)

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: [graphs.AztecDiamondGraph(i).num_verts() for i in range(8)]


[0, 4, 12, 24, 40, 60, 84, 112]

sage: [graphs.AztecDiamondGraph(i).num_edges() for i in range(8)]


[0, 4, 16, 36, 64, 100, 144, 196]

sage: G = graphs.AztecDiamondGraph(3)
sage: sum(1 for p in G.perfect_matchings())
64

static Balaban10Cage(embedding=1)
Return the Balaban 10-cage.

358 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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.

Note: The vertex labeling changes according to the value of embedding=1.

EXAMPLES:
Basic properties:

2.1. Common Graphs 359


Sage Reference Manual: Graph Theory, Release 8.4

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

Our many embeddings:

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

Proof that the embeddings are the same graph:

sage: g1.is_isomorphic(g2) # g2 and g3 are obviously isomorphic


True

static BalancedTree(r, h)
Returns the perfectly balanced tree of height ℎ ≥ 1, whose root has degree 𝑟 ≥ 2.
𝑟 ℎ+1 −1
The number of vertices of this graph is 1 + 𝑟 + 𝑟2 + · · · + 𝑟ℎ , that is, 𝑟−1 . The number of edges is one
less than the number of vertices.
INPUT:
• r – positive integer ≥ 2. The degree of the root node.
• h – positive integer ≥ 1. The height of the balanced tree.
OUTPUT:
The perfectly balanced tree of height ℎ ≥ 1 and whose root has degree 𝑟 ≥ 2. A NetworkXError is
returned if 𝑟 < 2 or ℎ < 1.
ALGORITHM:
Uses NetworkX.
EXAMPLES:
A balanced tree whose root node has degree 𝑟 = 2, and of height ℎ = 1, has order 3 and size 2:

sage: G = graphs.BalancedTree(2, 1); G


Balanced tree: Graph on 3 vertices
sage: G.order(); G.size()
3
2
sage: r = 2; h = 1
sage: v = 1 + r
sage: v; v - 1
3
2

360 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

Plot a balanced tree of height 5, whose root node has degree 𝑟 = 3:


sage: G = graphs.BalancedTree(3, 5)
sage: G.show() # long time

A tree is bipartite. If its vertex set is finite, then it is planar.


sage: r = randint(2, 5); h = randint(1, 7)
sage: T = graphs.BalancedTree(r, h)
sage: T.is_bipartite()
True
sage: T.is_planar()
True
sage: v = (r^(h + 1) - 1) / (r - 1)
sage: T.order() == v
True
sage: T.size() == v - 1
True

static BarbellGraph(n1, n2)


Returns a barbell graph with 2*n1 + n2 nodes. The argument n1 must be greater than or equal to 2.
A barbell graph is a basic structure that consists of a path graph of order n2 connecting two complete
graphs of order n1 each.
INPUT:
• n1 – integer ≥ 2. The order of each of the two complete graphs.
• n2 – nonnegative integer. The order of the path graph connecting the two complete graphs.
OUTPUT:
A barbell graph of order 2*n1 + n2. A ValueError is returned if n1 < 2 or n2 < 0.
PLOTTING:
Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention,
each barbell graph will be displayed with the two complete graphs in the lower-left and upper-right corners,
with the path graph connecting diagonally between the two. Thus the n1-th node will be drawn at a 45
degree angle from the horizontal right center of the first complete graph, and the n1 + n2 + 1-th node
will be drawn 45 degrees below the left horizontal center of the second complete graph.
EXAMPLES:
Construct and show a barbell graph Bar = 4, Bells = 9:
sage: g = graphs.BarbellGraph(9, 4); g
Barbell graph: Graph on 22 vertices
sage: g.show() # long time

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)

2.1. Common Graphs 361


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: P_n2 = graphs.PathGraph(n2)
sage: s_K = g.subgraph_search(K_n1, induced=True)
sage: s_P = g.subgraph_search(P_n2, induced=True)
sage: K_n1.is_isomorphic(s_K)
True
sage: P_n2.is_isomorphic(s_P)
True

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

It is a Hamiltonian graph with diameter 3 and girth 4:

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:

362 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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

The other embedding:

sage: graphs.BiggsSmithGraph(embedding=2).show() # long time

static BishopGraph(dim_list, radius=None, relabel=False)


Returns the 𝑑-dimensional Bishop Graph with prescribed dimensions.
The 2-dimensional Bishop Graph of parameters 𝑛 and 𝑚 is a graph with 𝑛𝑚 vertices in which each vertex
represents a square in an 𝑛 × 𝑚 chessboard, and each edge corresponds to a legal move by a bishop.
The 𝑑-dimensional Bishop Graph with 𝑑 >= 2 has for vertex set the cells of a 𝑑-dimensional grid with
prescribed dimensions, and each edge corresponds to a legal move by a bishop in any pairs of dimensions.
The Bishop Graph is not connected.
INPUT:
• dim_list – 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 decrease the power of
the bishop to at most radius steps.
• relabel – (default: False) a boolean set to True if vertices must be relabeled as integers.
EXAMPLES:
The (n,m)-Bishop Graph is not connected:

sage: G = graphs.BishopGraph( [3, 4] )


sage: G.is_connected()
False

The Bishop Graph can be obtained from Knight Graphs:

sage: for d in range(3,12): # long time


....: H = Graph()
....: for r in range(1,d+1):
....: B = graphs.BishopGraph([d,d],radius=r)
....: H.add_edges( graphs.KnightGraph([d,d],one=r,two=r).edges() )
....: if not B.is_isomorphic(H):
....: print("that's not good!")

static BlanusaFirstSnarkGraph()
Return the first Blanusa Snark Graph.

2.1. Common Graphs 363


Sage Reference Manual: Graph Theory, Release 8.4

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)

364 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


21
sage: G.size()
42
sage: G.is_regular(4)
True

It is an Eulerian graph with radius 3, diameter 3, and girth 5.

sage: G.is_eulerian()
True
sage: G.radius()
3
sage: G.diameter()
3
sage: G.girth()
5

The Brinkmann graph is also Hamiltonian with chromatic number 4:

sage: G.is_hamiltonian()
True
sage: G.chromatic_number()
4

Its automorphism group is isomorphic to 𝐷7 :

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

It is indeed strongly regular with parameters (81, 20, 1, 6):

sage: g.is_strongly_regular(parameters = True) # long time


(81, 20, 1, 6)

Its has as eigenvalues 20, 2 and −7:

sage: set(g.spectrum()) == {20,2,-7}


True

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

2.1. Common Graphs 365


Sage Reference Manual: Graph Theory, Release 8.4

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

The bubble sort graph on 𝑛 = 1 symbol is the trivial graph 𝐾1 :

sage: graphs.BubbleSortGraph(1)
Bubble sort: Graph on 1 vertex

If 𝑛 ≥ 1, then the order of 𝐵(𝑛) is 𝑛!:

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.

366 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

sage: g = polytopes.buckyball().vertex_graph()
sage: g.remove_loops()
sage: h = graphs.BuckyBall()
sage: g.is_isomorphic(h)
True

The graph is returned along with an attractive embedding.

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.

sage: g.order(); g.size()


5
5
sage: g.radius(); g.diameter(); g.girth()
2
3
3
sage: g.chromatic_number()
3

The bull graph has chromatic polynomial 𝑥(𝑥 − 2)(𝑥 − 1)3 and Tutte polynomial 𝑥4 + 𝑥3 + 𝑥2 𝑦. Its
characteristic polynomial is 𝑥(𝑥2 − 𝑥 − 3)(𝑥2 + 𝑥 − 1), which follows from the definition of characteristic
polynomials for graphs, i.e. det(𝑥𝐼 − 𝐴), where 𝑥 is a variable, 𝐴 the adjacency matrix of the graph, and
𝐼 the identity matrix of the same dimensions as 𝐴.

sage: chrompoly = g.chromatic_polynomial()


sage: bool(expand(x * (x - 2) * (x - 1)^3) == chrompoly)
True
sage: charpoly = g.characteristic_polynomial()
sage: M = g.adjacency_matrix(); M
[0 1 1 0 0]
[1 0 1 1 0]
[1 1 0 0 1]
(continues on next page)

2.1. Common Graphs 367


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


[0 1 0 0 0]
[0 0 1 0 0]
sage: Id = identity_matrix(ZZ, M.nrows())
sage: D = x*Id - M
sage: bool(D.determinant() == charpoly)
True
sage: bool(expand(x * (x^2 - x - 3) * (x^2 + x - 1)) == charpoly)
True

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

It has diameter 2, girth 3, and radius 1.


sage: G.diameter()
2
sage: G.girth()
3
sage: G.radius()
1

The butterfly graph is Eulerian, with chromatic number 3.


sage: G.is_eulerian()
True
sage: G.chromatic_number()
3

static CaiFurerImmermanGraph(G, twisted=False)


Return the a Cai-Furer-Immerman graph from 𝐺, possibly a twisted one, and a partition of its nodes.
A Cai-Furer-Immerman graph from/on 𝐺 is a graph created by applying the transformation described in
[CFI1992] on a graph 𝐺, that is substituting every vertex v in 𝐺 with a Furer gadget 𝐹 (𝑣) of order d
equal to the degree of the vertex, and then substituting every edge (𝑣, 𝑢) in 𝐺 with a pair of edges, one
connecting the two “a” nodes of 𝐹 (𝑣) and 𝐹 (𝑢) and the other their two “b” nodes. The returned coloring
of the vertices is made by the union of the colorings of each single Furer gadget, individualised for each

368 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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)]

2.1. Common Graphs 369


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: g = graphs.Cell120() # long time


sage: g.size() # long time
1200
sage: g.is_regular(4) # long time
True
sage: g.is_vertex_transitive() # long time
True

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:

sage: g = graphs.Cell600() # long time


sage: g.size() # long time
720
sage: g.is_regular(12) # long time
True
sage: g.is_vertex_transitive() # long time
True

static ChessboardGraphGenerator(dim_list, rook=True, rook_radius=None, bishop=True,


bishop_radius=None, knight=True, knight_x=1,
knight_y=2, relabel=False)
Returns a Graph built on a 𝑑-dimensional chessboard with prescribed dimensions and interconnections.
This function allows to generate many kinds of graphs corresponding to legal movements on a 𝑑-
dimensional chessboard: Queen Graph, King Graph, Knight Graphs, Bishop Graph, and many general-
izations. It also allows to avoid redondant code.

370 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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, _ = graphs.ChessboardGraphGenerator( [2,2] )


sage: G.is_isomorphic( graphs.CompleteGraph(4) )
True

A Rook’s Graph in 2 dimensions is isomorphic to the Cartesian product of 2 complete graphs:

sage: G, _ = graphs.ChessboardGraphGenerator( [3,4], rook=True, rook_


˓→radius=None, bishop=False, knight=False )

sage: H = ( graphs.CompleteGraph(3) ).cartesian_product( graphs.


˓→CompleteGraph(4) )

sage: G.is_isomorphic(H)
True

static ChvatalGraph()
Return the Chvatal graph.
Chvatal graph is one of the few known graphs to satisfy Grunbaum’s conjecture that for every 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.

2.1. Common Graphs 371


Sage Reference Manual: Graph Theory, Release 8.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

static CirculantGraph(n, adjacency)


Returns a circulant graph with n nodes.
A circulant graph has the property that the vertex 𝑖 is connected with the vertices 𝑖 + 𝑗 and 𝑖 − 𝑗 for each j
in adjacency.
INPUT:
• n - number of vertices in the graph
• adjacency - the list of j values
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, each circulant graph will be displayed with the first (0) node at the top, with the rest
following in a counterclockwise manner.
Filling the position dictionary in advance adds O(n) to the constructor.
See also:

• sage.graphs.generic_graph.GenericGraph.is_circulant() – checks whether a


(di)graph is circulant, and/or returns all possible sets of parameters.

EXAMPLES: Compare plotting using the predefined layout and networkx:

sage: import networkx


sage: n = networkx.cycle_graph(23)
sage: spring23 = Graph(n)
sage: posdict23 = graphs.CirculantGraph(23,2)
sage: spring23.show() # long time
sage: posdict23.show() # long time

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)

372 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: G = sage.plot.graphics.GraphicsArray(j)
sage: G.show() # long time

Compare to plotting with the spring-layout algorithm:

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

Passing a 1 into adjacency should give the cycle.

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:

2.1. Common Graphs 373


Sage Reference Manual: Graph Theory, Release 8.4

sage: g = graphs.CircularLadderGraph(13)
sage: g.show() # long time

Create several circular ladder graphs in a Sage graphics array:

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: (graphs.ClawGraph()).show() # long time

Inspect 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

static CompleteBipartiteGraph(n1, n2, set_position=True)


Return a Complete Bipartite Graph on 𝑛1 + 𝑛2 vertices.
A Complete Bipartite Graph is a graph with its vertices partitioned into two groups, 𝑉1 = {0, ..., 𝑛1 − 1}
and 𝑉2 = {𝑛1, ..., 𝑛1 + 𝑛2 − 1}. Each 𝑢 ∈ 𝑉1 is connected to every 𝑣 ∈ 𝑉2 .
INPUT:

374 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

• n1, n2 – number of vertices in each side


• set_position – boolean (default True); if set to True, we assign positions to the vertices so that
the set of cardinality 𝑛1 is on the line 𝑦 = 1 and the set of cardinality 𝑛2 is on the line 𝑦 = 0.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, each complete bipartite graph will be displayed with the first 𝑛1 nodes on the top row (at
𝑦 = 1) from left to right. The remaining 𝑛2 nodes appear at 𝑦 = 0, also from left to right. The shorter row
(partition with fewer nodes) is stretched to the same length as the longer row, unless the shorter row has 1
node; in which case it is centered. The 𝑥 values in the plot are in domain [0, max(𝑛1, 𝑛2)].
In the Complete Bipartite graph, there is a visual difference in using the spring-layout algorithm vs. the
position dictionary used in this constructor. The position dictionary flattens the graph and separates the
partitioned nodes, making it clear which nodes an edge is connected to. The Complete Bipartite graph
plotted with the spring-layout algorithm tends to center the nodes in n1 (see spring_med in examples
below), thus overlapping its nodes and edges, making it typically hard to decipher.
Filling the position dictionary in advance adds 𝑂(𝑛) to the constructor. Feel free to race the constructors
below in the examples section. The much larger difference is the time added by the spring-layout algorithm
when plotting. (Also shown in the example below). The spring model is typically described as 𝑂(𝑛3 ), as
appears to be the case in the NetworkX source code.
EXAMPLES:
Two ways of constructing the complete bipartite graph, using different layout algorithms:
sage: import networkx
sage: n = networkx.complete_bipartite_graph(389, 157); spring_big = Graph(n)
˓→ # long time

sage: posdict_big = graphs.CompleteBipartiteGraph(389, 157)


˓→ # long time

Compare the plotting:


sage: n = networkx.complete_bipartite_graph(11, 17)
sage: spring_med = Graph(n)
sage: posdict_med = graphs.CompleteBipartiteGraph(11, 17)

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

We compare to plotting with the spring-layout algorithm:

2.1. Common Graphs 375


Sage Reference Manual: Graph Theory, Release 8.4

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

trac ticket #12155:

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 to plotting with the spring-layout algorithm:

sage: import networkx


sage: g = []
sage: j = []
sage: for i in range(9):
....: spr = networkx.complete_graph(i+3)
....: k = Graph(spr)
(continues on next page)

376 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


....: 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

Compare the constructors (results will vary)

sage: import networkx


sage: t = cputime()
sage: n = networkx.complete_graph(389); spring389 = Graph(n)
sage: cputime(t) # random
0.59203700000000126
sage: t = cputime()
sage: posdict389 = graphs.CompleteGraph(389)
sage: cputime(t) # random
0.6680419999999998

We compare plotting:

sage: import networkx


sage: n = networkx.complete_graph(23)
sage: spring23 = Graph(n)
sage: posdict23 = graphs.CompleteGraph(23)
sage: spring23.show() # long time
sage: posdict23.show() # long time

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 = graphs.CompleteMultipartiteGraph([5, 6, 8]); g


Multipartite Graph with set sizes [5, 6, 8]: Graph on 19 vertices

It clearly has a chromatic number of 3:

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

2.1. Common Graphs 377


Sage Reference Manual: Graph Theory, Release 8.4

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.

sage: G=graphs.CossidentePenttilaGraph(3) # optional - gap_packages (grape)


sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape)
(56, 10, 0, 2)

For 𝑞 > 3 one gets new graphs.

sage: G=graphs.CossidentePenttilaGraph(5) # optional - gap_packages (grape)


sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape)
(378, 52, 1, 8)

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

378 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

sage: g = graphs.CubeGraph(7)
sage: g.distance('0100110','1011010')
5

Plot several 𝑛-cubes in a Sage Graphics Array

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

Use the plot options to display larger 𝑛-cubes

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:

sage: import networkx


sage: n = networkx.cycle_graph(23)
sage: spring23 = Graph(n)
sage: posdict23 = graphs.CycleGraph(23)
sage: spring23.show() # long time
sage: posdict23.show() # long time

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)

2.1. Common Graphs 379


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: for i in range(9):
....: k = graphs.CycleGraph(i+3)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = sage.plot.graphics.GraphicsArray(j)
sage: G.show() # long time

Compare to plotting with the spring-layout algorithm:

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:

380 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

static DegreeSequenceBipartite(s1, s2)


Returns a bipartite graph whose two sets have the given degree sequences.
Given two different sequences of degrees 𝑠1 and 𝑠2 , this functions returns ( if possible ) a bipartite graph on
sets 𝐴 and 𝐵 such that the vertices in 𝐴 have 𝑠1 as their degree sequence, while 𝑠2 is the degree sequence
of the vertices in 𝐵.
INPUT:
• s_1 – list of integers corresponding to the degree sequence of the first set.
• s_2 – list of integers corresponding to the degree sequence of the second set.
ALGORITHM:
This function works through the computation of the matrix given by the Gale-Ryser theorem, which is in
this case the adjacency matrix of the bipartite graph.
EXAMPLES:
If we are given as sequences [2,2,2,2,2] and [5,5] we are given as expected the complete bipartite
graph 𝐾2,5

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

static DegreeSequenceConfigurationModel(deg_sequence, seed=None)


Returns a random pseudograph with the given degree sequence. Raises a NetworkX error if the proposed
degree sequence cannot be that of a graph with multiple edges and loops.
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.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.

2.1. Common Graphs 381


Sage Reference Manual: Graph Theory, Release 8.4

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)

382 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: g.girth()
4

static DesarguesGraph()
Return the Desargues graph.
PLOTTING: The layout chosen is the same as on the cover of [Har1994].
EXAMPLES:

sage: D = graphs.DesarguesGraph()
sage: L = graphs.LCFGraph(20,[5,-5,9,-9],5)
sage: D.is_isomorphic(L)
True
sage: D.show() # long time

static DiamondGraph()
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

2.1. Common Graphs 383


Sage Reference Manual: Graph Theory, Release 8.4

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.

384 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

sage: G = graphs.DurerGraph(); G
Durer graph: Graph on 12 vertices
sage: G.is_planar()
True
sage: G.order()
12
sage: G.size()
18

The Dürer graph has chromatic number 3, diameter 4, and girth 3.

sage: G.chromatic_number()
3
sage: G.diameter()
4
sage: G.girth()
3

Its automorphism group is isomorphic to 𝐷6 .

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

It is non-planar and Hamiltonian, as well as bipartite (making it a bicubic graph):

sage: G.is_planar()
False
sage: G.is_hamiltonian()
True
sage: G.is_bipartite()
True

It has radius 5, diameter 5, and girth 6:

sage: G.radius()
5
(continues on next page)

2.1. Common Graphs 385


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: G.diameter()
5
sage: G.girth()
6

Its chromatic number is 2 and its automorphism group is of order 192:

sage: G.chromatic_number()
2
sage: G.automorphism_group().cardinality()
192

It is a non-integral graph as it has irrational eigenvalues:

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.

386 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

EXAMPLES:
This graph is 3-regular:

sage: g = graphs.EllinghamHorton54Graph()
sage: g.is_regular(k=3)
True

It is 3-connected and bipartite:

sage: g.vertex_connectivity() # not tested - too long


3
sage: g.is_bipartite()
True

It is not Hamiltonian:

sage: g.is_hamiltonian() # not tested - too long


False

. . . and it has a nice drawing

sage: g.show(figsize=[10, 10]) # not tested - too long

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 3-connected and bipartite:

sage: g.vertex_connectivity() # not tested - too long


3
sage: g.is_bipartite()
True

It is not Hamiltonian:

sage: g.is_hamiltonian() # not tested - too long


False

. . . and it has a nice drawing

sage: g.show(figsize=[10,10]) # not tested - too long

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.

2.1. Common Graphs 387


Sage Reference Manual: Graph Theory, Release 8.4

EXAMPLES: Add one vertex to an empty graph and then show:

sage: empty1 = graphs.EmptyGraph()


sage: empty1.add_vertex()
0
sage: empty1.show() # long time

Use for loops to build a graph from an empty graph:

sage: empty2 = graphs.EmptyGraph()


sage: for i in range(5):
....: empty2.add_vertex() # add 5 nodes, labeled 0-4
0
1
2
3
4
sage: for i in range(3):
....: empty2.add_edge(i,i+1) # add edges {[0:1],[1:2],[2:3]}
sage: for i in range(1, 4):
....: empty2.add_edge(4,i) # add edges {[1:4],[2:4],[3:4]}
sage: empty2.show() # long time

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.

388 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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 EuropeMap(continental=False, year=2018)


Return European states as a graph of common border.
“European state” here is defined as an independent state having the capital city in Europe. The graph has
an edge between those countries that have common land border.
INPUT:
• continental, a Boolean – if set, only return states in the continental Europe
• year – reserved for future use
EXAMPLES:

sage: Europe = graphs.EuropeMap(); Europe


Europe Map: Graph on 44 vertices
sage: Europe.neighbors('Ireland')
['United Kingdom']

sage: cont_Europe = graphs.EuropeMap(continental=True)


sage: cont_Europe.order()
40
sage: 'Iceland' in cont_Europe
False

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.

2.1. Common Graphs 389


Sage Reference Manual: Graph Theory, Release 8.4

INPUT:
• n - the recursion depth of the Fibonacci Tree
EXAMPLES:

sage: g = graphs.FibonacciTree(3)
sage: g.is_tree()
True

sage: l1 = [ len(graphs.FibonacciTree(_)) + 1 for _ in range(6) ]


sage: l2 = list(fibonacci_sequence(2,8))
sage: l1 == l2
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'

Now show it:

sage: F.show() # long time

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.

390 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

See the Wikipedia article Folkman_graph.


EXAMPLES:
sage: g = graphs.FolkmanGraph()
sage: g.order()
20
sage: g.size()
40
sage: g.diameter()
4
sage: g.girth()
4
sage: g.charpoly().factor()
(x - 4) * (x + 4) * x^10 * (x^2 - 6)^4
sage: g.chromatic_number()
2
sage: g.is_eulerian()
True
sage: g.is_hamiltonian()
True
sage: g.is_vertex_transitive()
False
sage: g.is_bipartite()
True

static 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)

2.1. Common Graphs 391


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


True
sage: G.order()
12
sage: G.size()
18

The Franklin graph is a Hamiltonian, bipartite graph with radius 3, diameter 3, and girth 4.

sage: G.is_hamiltonian()
True
sage: G.is_bipartite()
True
sage: G.radius()
3
sage: G.diameter()
3
sage: G.girth()
4

It is a perfect, triangle-free graph having chromatic number 2.

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)

392 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


....: for j in range(3):
....: n.append(A[3*i + j].plot(vertex_size=20, vertex_labels=False))
....: B.append(n)
sage: G = sage.plot.graphics.GraphicsArray(B)
sage: G.show() # long time

For 𝑛 = 1, the friendship graph 𝐹1 is isomorphic to the cycle graph 𝐶3 , whose visual representation is a
triangle.

sage: G = graphs.FriendshipGraph(1); G
Friendship graph: Graph on 3 vertices
sage: G.show() # long time
sage: G.is_isomorphic(graphs.CycleGraph(3))
True

For 𝑛 = 2, the friendship graph 𝐹2 is isomorphic to the butterfly graph, otherwise known as the bowtie
graph.

sage: G = graphs.FriendshipGraph(2); G
Friendship graph: Graph on 5 vertices
sage: G.is_isomorphic(graphs.ButterflyGraph())
True

If 𝑛 ≥ 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.

sage: n = randint(1, 10^3)


sage: G = graphs.FriendshipGraph(n)
sage: G.order() == 2*n + 1
True
sage: G.size() == 3*n
True
sage: G.radius()
1
sage: G.diameter()
2
sage: G.girth()
3
sage: G.chromatic_number()
3
sage: G.is_planar()
True
sage: G.is_eulerian()
True

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:

2.1. Common Graphs 393


Sage Reference Manual: Graph Theory, Release 8.4

sage: FRUCHT = graphs.FruchtGraph()


sage: FRUCHT
Frucht graph: Graph on 12 vertices
sage: FRUCHT.graph6_string()
'KhCKM?_EGK?L'
sage: (graphs.FruchtGraph()).show() # long time

static FurerGadget(k, prefix=None)


Return a Furer gadget of order k and their coloring.
Construct the Furer gadget described in [CFI1992], a graph composed by a middle layer of 2( 𝑘 − 1) nodes
and two sets of nodes (𝑎0 , ..., 𝑎𝑘−1 ) and (𝑏0 , ..., 𝑏𝑘−1 ). Each node in the middle is connected to either 𝑎𝑖
or 𝑏𝑖 , for each i in [0,k[. To read about the complete construction, see [CFI1992]. The returned coloring
colors the middle section with one color, and then each pair (𝑎𝑖 , 𝑏𝑖 ) with another color. Since this method
is mainly used to create Furer gadgets for the Cai-Furer-Immerman construction, returning gadgets that
don’t always have the same vertex labels is important, that’s why there is a parameter to manually set a
prefix to be appended to each vertex label.
INPUT:
• k – The order of the returned Furer gadget, greater than 0.
• prefix – Prefix of to be appended to each vertex label, so as to individualise the returned Furer
gadget. Must be comparable for equality and hashable.
OUTPUT:
• G – The Furer gadget of order k
• coloring – A list of list of vertices, representing the partition induced by the coloring of G’s ver-
tices
EXAMPLES:
Furer gadget of order 3, without any prefix.
sage: G, p = graphs.FurerGadget(3)
sage: G.vertices()
[(), (0, 1), (0, 2), (0, 'a'), (0, 'b'), (1, 2), (1, 'a'),
(1, 'b'), (2, 'a'), (2, 'b')]
sage: G.edges()
[((), (0, 'b'), None), ((), (1, 'b'), None),
((), (2, 'b'), None), ((0, 1), (0, 'a'), None),
((0, 1), (1, 'a'), None), ((0, 1), (2, 'b'), None),
((0, 2), (0, 'a'), None), ((0, 2), (1, 'b'), None),
((0, 2), (2, 'a'), None), ((0, 'b'), (1, 2), None),
((1, 2), (1, 'a'), None), ((1, 2), (2, 'a'), None)]

Furer gadget of order 3, with a prefix.


sage: G, p = graphs.FurerGadget(3, 'Prefix')
sage: G.vertices()
[('Prefix', ()), ('Prefix', (0, 1)), ('Prefix', (0, 2)),
('Prefix', (0, 'a')), ('Prefix', (0, 'b')), ('Prefix', (1, 2)),
('Prefix', (1, 'a')), ('Prefix', (1, 'b')), ('Prefix', (2, 'a')),
('Prefix', (2, 'b'))]
sage: G.edges()
[(('Prefix', ()), ('Prefix', (0, 'b')), None),
(('Prefix', ()), ('Prefix', (1, 'b')), None),
(('Prefix', ()), ('Prefix', (2, 'b')), None),
(continues on next page)

394 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


(('Prefix', (0, 1)), ('Prefix', (0, 'a')), None),
(('Prefix', (0, 1)), ('Prefix', (1, 'a')), None),
(('Prefix', (0, 1)), ('Prefix', (2, 'b')), None),
(('Prefix', (0, 2)), ('Prefix', (0, 'a')), None),
(('Prefix', (0, 2)), ('Prefix', (1, 'b')), None),
(('Prefix', (0, 2)), ('Prefix', (2, 'a')), None),
(('Prefix', (0, 'b')), ('Prefix', (1, 2)), None),
(('Prefix', (1, 2)), ('Prefix', (1, 'a')), None),
(('Prefix', (1, 2)), ('Prefix', (2, 'a')), None)]

static FuzzyBallGraph(partition, q)
Construct a Fuzzy Ball graph with the integer partition partition and q extra vertices.
Let 𝑞 be an integer and let 𝑚1 , 𝑚2 , ..., 𝑚𝑘 be a set of positive integers. Let 𝑛 = 𝑞 + 𝑚1 + ... + 𝑚𝑘 .
The Fuzzy Ball graph with partition 𝑚1 , 𝑚2 , ..., 𝑚𝑘 and 𝑞 extra vertices is the graph constructed from the
graph 𝐺 = 𝐾𝑛 by attaching, for each 𝑖 = 1, 2, ..., 𝑘, a new vertex 𝑎𝑖 to 𝑚𝑖 distinct vertices of 𝐺.
For given positive integers 𝑘 and 𝑚 and nonnegative integer 𝑞, the set of graphs FuzzyBallGraph(p,
q) for all partitions 𝑝 of 𝑚 with 𝑘 parts are cospectral with respect to the normalized Laplacian.
EXAMPLES:

sage: 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:

sage: m=4; q=2; k=2


sage: g_list=[graphs.FuzzyBallGraph(p,q) for p in Partitions(m, length=k)]
sage: set([g.laplacian_matrix(normalized=True).charpoly() for g in g_list])
˓→# long time (7s on sage.math, 2011)

{x^8 - 8*x^7 + 4079/150*x^6 - 68689/1350*x^5 + 610783/10800*x^4 - 120877/


˓→3240*x^3 + 1351/100*x^2 - 931/450*x}

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

2.1. Common Graphs 395


Sage Reference Manual: Graph Theory, Release 8.4

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

The Desargues graph:


sage: g = graphs.GeneralizedPetersenGraph(10,3)
sage: g.girth()
6
sage: g.is_bipartite()
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)

396 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: G.order()
11
sage: G.size()
27

The Goldner-Harary graph is chordal with radius 2, diameter 2, and girth 3.

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

sage: g.order(), g.size()


(56, 756)

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)

2.1. Common Graphs 397


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: g.show(figsize=[10, 10]) # long time
sage: graphs.GrayGraph(embedding = 2).show(figsize=[10, 10]) # long time

static Grid2dGraph(n1, n2, set_positions=True)


Returns a 2-dimensional grid graph with 𝑛1 𝑛2 nodes (𝑛1 rows and 𝑛2 columns).
A 2d grid graph resembles a 2 dimensional grid. All inner nodes are connected to their 4 neighbors. Outer
(non-corner) nodes are connected to their 3 neighbors. Corner nodes are connected to their 2 neighbors.
INPUT:
• n1 and n2 – two positive integers
• set_positions – (default: True) boolean use to prevent setting the position of the nodes.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, nodes are labelled in (row, column) pairs with (0, 0) in the top left corner. Edges will
always be horizontal and vertical - another advantage of filling the position dictionary.
EXAMPLES: Construct and show a grid 2d graph Rows = 5, Columns = 7

sage: g = graphs.Grid2dGraph(5,7)
sage: g.show() # long time

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)

398 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


11
sage: G.size()
20

The Grötzsch graph is triangle-free and having radius 2, diameter 2, and girth 4.

sage: G.is_triangle_free()
True
sage: G.radius()
2
sage: G.diameter()
2
sage: G.girth()
4

Its chromatic number is 4 and its automorphism group is isomorphic to the dihedral group 𝐷5 .

sage: G.chromatic_number()
4
sage: ag = G.automorphism_group()
sage: ag.is_isomorphic(DihedralGroup(5))
True

static HaemersGraph(q, hyperoval=None, hyperoval_matching=None, field=None,


check_hyperoval=True)
Return the Haemers graph obtained from 𝑇2* (𝑞)*
Let 𝑞 be a power of 2. In Sect. 8.A of [BvL84] one finds a construction of a strongly regular
graph with parameters (𝑞 2 (𝑞 + 2), 𝑞 2 + 𝑞 − 1, 𝑞 − 2, 𝑞) from the graph of 𝑇2* (𝑞)* , constructed by
T2starGeneralizedQuadrangleGraph(), by redefining adjacencies in the way specified by an
arbitrary hyperoval_matching of the points (i.e. partitioning into size two parts) of hyperoval
defining 𝑇2* (𝑞)* .
While [BvL84] gives the construction in geometric terms, it can be formulated, and is implemented, in
graph-theoretic ones, of re-adjusting the edges. Namely, 𝐺 = 𝑇2* (𝑞)* has a partition into 𝑞 +2 independent
sets 𝐼𝑘 of size 𝑞 2 each. Each vertex in 𝐼𝑗 is adjacent to 𝑞 vertices from 𝐼𝑘 . Each 𝐼𝑘 is paired to some 𝐼𝑘′ ,
according to hyperoval_matching. One adds edges (𝑠, 𝑡) for 𝑠, 𝑡 ∈ 𝐼𝑘 whenever 𝑠 and 𝑡 are adjacent
to some 𝑢 ∈ 𝐼𝑘′ , and removes all the edges between 𝐼𝑘 and 𝐼𝑘′ .
INPUT:
• q – a power of two
• hyperoval_matching – if None (default), pair each 𝑖-th point of hyperoval with (𝑖 + 1)-th.
Otherwise, specifies the pairing in the format ((𝑖1 , 𝑖′1 ), (𝑖2 , 𝑖′2 ), ...).
• hyperoval – a hyperoval defining 𝑇2* (𝑞)* . If None (default), the classical hyperoval obtained
from a conic is used. See the documentation of T2starGeneralizedQuadrangleGraph(),
for more information.
• field – an instance of a finite field of order 𝑞, must be provided if hyperoval is provided.
• check_hyperoval – (default: True) if True, check hyperoval for correctness.
EXAMPLES:
using the built-in constructions:

2.1. Common Graphs 399


Sage Reference Manual: Graph Theory, Release 8.4

sage: g=graphs.HaemersGraph(4); g
Haemers(4): Graph on 96 vertices
sage: g.is_strongly_regular(parameters=True)
(96, 19, 2, 4)

supplying your own hyperoval_matching:

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

Is it really strongly regular with parameters 14, 12?

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

Some other properties that we know how to check:

sage: g.diameter()
2
sage: g.girth()
3
sage: factor(g.characteristic_polynomial())
(x - 36) * (x - 6)^36 * (x + 4)^63

400 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

static HammingGraph(n, q, X=None)


Returns the Hamming graph with parameters n, q over X.
Hamming graphs are graphs over the cartesian product of n copies of X, where 𝑞 = |𝑋|, where the vertices,
labelled with the corresponding tuple in 𝑋 𝑛 , are connected if the Hamming distance between their labels
is 1. All Hamming graphs are regular, vertex-transitive and distance-regular.
Hamming graphs with parameters (1, 𝑞) represent the complete graph with q vertices over the set X.
INPUT:
• n – power to which X will be raised to provide vertices for the Hamming graph
• q – cardinality of X
• X – list of labels representing the vertices of the underlying graph the Hamming graph will be
based on; if None (or left unused), the list [0, ..., 𝑞 − 1] will be used
OUTPUT:
• G – The Hamming graph with parameters (𝑛, 𝑞, 𝑋)
EXAMPLES:
Every Hamming graph is distance-regular, regular and vertex-transitive.

sage: g = graphs.HammingGraph(3, 7)
sage: g.is_distance_regular()
True
sage: g.is_regular()
True
sage: g.is_vertex_transitive()
True

A Hamming graph with parameters (1,q) is isomorphic to the Complete graph with parameter q.

sage: g = graphs.HammingGraph(1, 23)


sage: g.is_isomorphic(graphs.CompleteGraph(23))
True

If a parameter q is provided which is not equal to X’s cardinality, an exception is raised.

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.

2.1. Common Graphs 401


Sage Reference Manual: Graph Theory, Release 8.4

• 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.

sage: H = graphs.HanoiTowerGraph(3, 5, labels=False, positions=False)


sage: H.distance(0, 3^5-1)
31

A slightly larger instance.

sage: H = graphs.HanoiTowerGraph(4, 6, labels=False, positions=False)


sage: H.num_verts()
4096
sage: H.distance(0, 4^6-1)
17

402 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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, 3, labels=True, positions=True)


sage: H.shortest_path((0,0,0), (1,1,1))
[(0, 0, 0), (0, 0, 1), (0, 2, 1), (0, 2, 2), (1, 2, 2), (1, 2, 0), (1, 1, 0),
˓→(1, 1, 1)]

Some facts about this graph with 𝑝 pegs and 𝑑 disks:


• only automorphisms are the “obvious” ones - renumber the pegs.
• chromatic number is less than or equal to 𝑝
• independence number is 𝑝𝑑−1

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.

2.1. Common Graphs 403


Sage Reference Manual: Graph Theory, Release 8.4

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.

404 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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.

2.1. Common Graphs 405


Sage Reference Manual: Graph Theory, Release 8.4

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)

406 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


....: j.append(n)
sage: G = sage.plot.graphics.GraphicsArray(j)
sage: G.show() # long time

static HigmanSimsGraph(relabel=True)
Return the Higman-Sims graph.
The Higman-Sims graph is a remarkable strongly regular graph of degree 22 on 100 vertices. For 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:

2.1. Common Graphs 407


Sage Reference Manual: Graph Theory, Release 8.4

• Rob Beezer (2009-10-24)


static HoffmanGraph()
Return the Hoffman Graph.
See the Wikipedia article Hoffman_graph.
EXAMPLES:
sage: g = graphs.HoffmanGraph()
sage: g.is_bipartite()
True
sage: g.is_hamiltonian() # long time
True
sage: g.radius()
3
sage: g.diameter()
4
sage: g.automorphism_group().cardinality()
48

static HoffmanSingletonGraph()
Return the Hoffman-Singleton graph.
The Hoffman-Singleton graph is the Moore graph of degree 7, diameter 2 and girth 5. The Hoffman-
Singleton theorem states that any Moore graph with girth 5 must have degree 2, 3, 7 or 57. The first three
respectively are the pentagon, the Petersen graph, and the Hoffman-Singleton graph. The existence of a
Moore graph with girth 5 and degree 57 is still open.
A Moore graph is a graph with diameter 𝑑 and girth 2𝑑 + 1. This implies that the graph is regular, and
distance regular.
For more details, see [GR2001] and the Wikipedia article Hoffman–Singleton_graph.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
A novel algorithm written by Tom Boothby gives a random layout which is pleasing to the eye.
EXAMPLES:
sage: HS = graphs.HoffmanSingletonGraph()
sage: Set(HS.degree())
{7}
sage: HS.girth()
5
sage: HS.diameter()
2
sage: HS.num_verts()
50

Note that you get a different layout each time you create the graph.
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:

408 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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

2.1. Common Graphs 409


Sage Reference Manual: Graph Theory, Release 8.4

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.

410 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

EXAMPLES: Construct and show an Octahedral graph

sage: g = graphs.IcosahedralGraph()
sage: g.show() # long time

Create several icosahedral graphs in a Sage graphics array. They will be drawn differently due to the use
of the spring-layout algorithm.

sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.IcosahedralGraph()
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
sage: G = 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

static IntervalGraph(intervals, points_ordered=False)


Return the graph corresponding to the given intervals.
An interval graph is built from a list (𝑎𝑖 , 𝑏𝑖 )1≤𝑖≤𝑛 of intervals : to each interval of the list is associated one
vertex, two vertices being adjacent if the two corresponding (closed) intervals intersect.
INPUT:
• intervals – the list of pairs (𝑎𝑖 , 𝑏𝑖 ) defining the graph.
• points_ordered – states whether every interval (𝑎𝑖 , 𝑏𝑖 ) of 𝑖𝑛𝑡𝑒𝑟𝑣𝑎𝑙𝑠 satisfies 𝑎𝑖 < 𝑏𝑖 . If satisfied
then setting points_ordered to True will speed up the creation of the graph.

Note:
• The vertices are named 0, 1, 2, and so on. The intervals used to create the graph are saved with the
graph and can be recovered using get_vertex() or get_vertices().

EXAMPLES:

2.1. Common Graphs 411


Sage Reference Manual: Graph Theory, Release 8.4

The following line creates the sequence of intervals (𝑖, 𝑖 + 2) for i in [0, ..., 8]:

sage: intervals = [(i,i+2) for i in range(9)]

In the corresponding graph

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)

The is_interval() method verifies that this graph is an interval graph.

sage: g.is_interval()
True

The intervals in the list need not be distinct.

sage: intervals = [ (1,2), (1,2), (1,2), (2,3), (3,4) ]


sage: g = graphs.IntervalGraph(intervals,True)
sage: g.clique_maximum()
[0, 1, 2, 3]
sage: g.get_vertices()
{0: (1, 2), 1: (1, 2), 2: (1, 2), 3: (2, 3), 4: (3, 4)}

The endpoints of the intervals are not ordered we get the same graph (except for the vertex labels).

sage: rev_intervals = [ (2,1), (2,1), (2,1), (3,2), (4,3) ]


sage: h = graphs.IntervalGraph(rev_intervals,False)
sage: h.get_vertices()
{0: (2, 1), 1: (2, 1), 2: (2, 1), 3: (3, 2), 4: (4, 3)}
sage: g.edges() == h.edges()
True

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.

412 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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 )

Observe that if (𝑋1 , 𝑋2 , 𝑋3 , 𝑋4 , 𝑋5 ) is an 𝑀 𝐹 -tuple, then 𝑁 (𝑋1 , 𝑋2 , 𝑋3 , 𝑋4 , 𝑋5 ) is the sym-


metric incidence matrix of a symmetric (45, 12, 3)-design.
Let ℱ be the set of all 𝑀 𝐹 -tuples and let 𝜎 be the following permutation of ℱ:

𝜎(𝑋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:

2.1. Common Graphs 413


Sage Reference Manual: Graph Theory, Release 8.4

• v (integer) – one of 936 or 1800.


EXAMPLES:

sage: g = graphs.JankoKharaghaniGraph(936) # long time


sage: g.is_strongly_regular(parameters=True) # long time
(936, 375, 150, 150)

sage: g = graphs.JankoKharaghaniGraph(1800) # not tested (30s)


sage: g.is_strongly_regular(parameters=True) # not tested (30s)
(1800, 1029, 588, 588)

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:

sage: Gamma=graphs.JankoKharaghaniTonchevGraph() # long time


sage: Gamma.is_strongly_regular(parameters=True) # long time
(324, 153, 72, 72)

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

Every Johnson graph is vertex transitive.

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

static KingGraph(dim_list, radius=None, relabel=False)


Returns the 𝑑-dimensional King Graph with prescribed dimensions.
The 2-dimensional King 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 king.
The d-dimensional King Graph with 𝑑 >= 2 has for vertex set the cells of a d-dimensional grid with pre-
scribed dimensions, and each edge corresponds to a legal move by a king in either one or two dimensions.

414 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: G = graphs.QueenGraph( [2, 2] )


sage: G.is_isomorphic( graphs.CompleteGraph(4) )
True

The King Graph with large enough radius is isomorphic to a Queen Graph:

sage: G = graphs.KingGraph( [5, 4], radius=5 )


sage: H = graphs.QueenGraph( [4, 5] )
sage: G.is_isomorphic( H )
True

Also True in higher dimensions:

sage: G = graphs.KingGraph( [2, 5, 4], radius=5 )


sage: H = graphs.QueenGraph( [4, 5, 2] )
sage: G.is_isomorphic( H )
True

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.

2.1. Common Graphs 415


Sage Reference Manual: Graph Theory, Release 8.4

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 KnightGraph(dim_list, one=1, two=2, relabel=False)


Returns the d-dimensional Knight Graph with prescribed dimensions.
The 2-dimensional Knight 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 knight.
The d-dimensional Knight Graph with 𝑑 >= 2 has for vertex set the cells of a d-dimensional grid with
prescribed dimensions, and each edge corresponds to a legal move by a knight in any pairs of dimensions.

416 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

The (𝑛, 𝑛)-Knight Graph is Hamiltonian for even 𝑛 > 4.


INPUT:
• dim_list – an iterable object (list, set, dict) providing the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1,
of the chessboard.
• one – (default: 1) integer indicating the number on steps in one dimension.
• two – (default: 2) integer indicating the number on steps in the second dimension.
• relabel – (default: False) a boolean set to True if vertices must be relabeled as integers.
EXAMPLES:
The (3, 3)-Knight Graph has an isolated vertex:

sage: G = graphs.KnightGraph( [3, 3] )


sage: G.degree( (1,1) )
0

The (3, 3)-Knight Graph minus vertex (1,1) is a cycle of order 8:

sage: G = graphs.KnightGraph( [3, 3] )


sage: G.delete_vertex( (1,1) )
sage: G.is_isomorphic( graphs.CycleGraph(8) )
True

The (6, 6)-Knight Graph is Hamiltonian:

sage: G = graphs.KnightGraph( [6, 6] )


sage: G.is_hamiltonian()
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

static LCFGraph(n, shift_list, repeats)


Return the cubic graph specified in LCF notation.

2.1. Common Graphs 417


Sage Reference Manual: Graph Theory, Release 8.4

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 = graphs.LCFGraph(4, [2,-2], 2)


sage: G.is_isomorphic(graphs.TetrahedralGraph())
True

sage: G = graphs.LCFGraph(20, [10,7,4,-4,-7,10,-4,7,-7,4], 2)


sage: G.is_isomorphic(graphs.DodecahedralGraph())
True

sage: G = graphs.LCFGraph(14, [5,-5], 7)


sage: G.is_isomorphic(graphs.HeawoodGraph())
True

The largest cubic nonplanar graph of diameter three:

sage: G = graphs.LCFGraph(20, [-10,-7,-5,4,7,-10,-7,-4,5,7,-10,-7,6,-5,7,-10,-


˓→7,5,-6,7], 1)

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

418 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

right on the top horizontal line.


EXAMPLES: Construct and show a ladder graph with 14 nodes

sage: g = graphs.LadderGraph(7)
sage: g.show() # long time

Create several ladder graphs in a Sage graphics array

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:

sage: g = graphs.LivingstoneGraph() # optional - gap_packages internet


sage: g.order() # optional - gap_packages internet
266
sage: g.size() # optional - gap_packages internet
1463
sage: g.girth() # optional - gap_packages internet
5
sage: g.is_vertex_transitive() # optional - gap_packages internet
True
sage: g.is_distance_regular() # optional - gap_packages internet
True

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)

2.1. Common Graphs 419


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


168
sage: g.girth()
10
sage: g.diameter()
8
sage: g.show(figsize=[10, 10]) # long time
sage: graphs.LjubljanaGraph(embedding=2).show(figsize=[10, 10]) # long time

static LocalMcLaughlinGraph()
Return the local McLaughlin graph.
The local McLaughlin graph is a strongly regular graph with parameters (162, 56, 10, 24). It can be ob-
tained from McLaughlinGraph() by considering the stabilizer of a point: one of its orbits has cardi-
nality 162.
EXAMPLES:

sage: g = graphs.LocalMcLaughlinGraph(); g # long time # optional - gap_


˓→packages

Local McLaughlin Graph: Graph on 162 vertices


sage: g.is_strongly_regular(parameters=True) # long time # optional - gap_
˓→packages

(162, 56, 10, 24)

static LollipopGraph(n1, n2)


Returns a lollipop graph with n1+n2 nodes.
A lollipop graph is a path graph (order n2) connected to a complete graph (order n1). (A barbell graph
minus one of the bells).
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, the complete graph will be drawn in the lower-left corner with the (n1)th node at a 45
degree angle above the right horizontal center of the complete graph, leading directly into the path graph.
EXAMPLES:
Construct and show a lollipop graph Candy = 13, Stick = 4:

sage: g = graphs.LollipopGraph(13,4); g
Lollipop graph: Graph on 17 vertices
sage: g.show() # long time

static M22Graph()
Return the M22 graph.
The 𝑀22 graph is the unique strongly regular graph with parameters 𝑣 = 77, 𝑘 = 16, 𝜆 = 0, 𝜇 = 4.
For more information on the 𝑀22 graph, see https://www.win.tue.nl/~aeb/graphs/M22.html.
EXAMPLES:

sage: g = graphs.M22Graph()
sage: g.order()
77
sage: g.size()
616
sage: g.is_strongly_regular(parameters = True)
(77, 16, 0, 4)

420 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.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()

static MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None)


Return a strongly regular graph on (4𝑡 + 1)(4𝑡 − 1)2 vertices from [Mat78]
Let 4𝑡−1 be a prime power, and 4𝑡+1 be such that there exists a strongly regular graph 𝐺 with parameters
(4𝑡 + 1, 2𝑡, 𝑡 − 1, 𝑡). In particular, 4𝑡 + 1 must be a sum of two squares [Mat78]. With this input, Mathon
[Mat78] gives a construction of a strongly regular graph with parameters (4𝜇 + 1, 2𝜇, 𝜇 − 1, 𝜇), where
𝜇 = 𝑡(4𝑡(4𝑡 − 1) − 1). The construction is optionally parametrised by an a skew-symmetric Latin square
of order 4𝑡 + 1, with entries in −2𝑡, ..., −1, 0, 1, ..., 2𝑡.
Our implementation follows a description given in [ST78].
INPUT:
• t – a positive integer
• G – if None (default), try to construct the necessary graph with parameters (4𝑡 + 1, 2𝑡, 𝑡 − 1, 𝑡),
otherwise use the user-supplied one, with vertices labelled from 0 to 4𝑡.
• L – if None (default), construct a necessary skew Latin square, otherwise use the user-supplied one.
Here non-isomorphic Latin squares – one constructed from 𝑍/9𝑍, and the other from (𝑍/3𝑍)2 – lead
to non-isomorphic graphs.

2.1. Common Graphs 421


Sage Reference Manual: Graph Theory, Release 8.4

See also:

• is_mathon_PC_srg()

EXAMPLES:
Using default G and L.

sage: from sage.graphs.generators.families import


˓→MathonPseudocyclicStronglyRegularGraph

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)

Supplying G and L (constructed from the automorphism group of G).

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]))

sage: ff=list(map(lambda y: (y[0]-1,y[1]-1),


....: Permutation(map(lambda x: 1+r.index(x^-1), r)).cycle_
˓→tuples()[1:]))

sage: L = sum(i*(r[a]-r[b]) for i,(a,b) in zip(range(1,len(ff)+1), ff)); L


[ 0 -1 1 -2 -3 -4 2 4 3]
[ 1 0 -1 -4 -2 -3 3 2 4]
[-1 1 0 -3 -4 -2 4 3 2]
[ 2 4 3 0 -1 1 -2 -3 -4]
[ 3 2 4 1 0 -1 -4 -2 -3]
[ 4 3 2 -1 1 0 -3 -4 -2]
[-2 -3 -4 2 4 3 0 -1 1]
[-4 -2 -3 3 2 4 1 0 -1]
[-3 -4 -2 4 3 2 -1 1 0]
sage: G.relabel()
sage: G3x3=graphs.MathonPseudocyclicStronglyRegularGraph(2,G=G,L=L)
sage: G3x3.is_strongly_regular(parameters=True)
(441, 220, 109, 110)
sage: G3x3.automorphism_group(algorithm="bliss").order() # optional - bliss
27
sage: G9=graphs.MathonPseudocyclicStronglyRegularGraph(2)
sage: G9.is_strongly_regular(parameters=True)
(441, 220, 109, 110)
sage: G9.automorphism_group(algorithm="bliss").order() # optional - bliss
9

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:

422 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.generators.smallgraphs import


˓→MathonStronglyRegularGraph

sage: G = MathonStronglyRegularGraph(0) # long time


sage: G.is_strongly_regular(parameters=True) # long time
(784, 243, 82, 72)

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:

sage: g = graphs.McLaughlinGraph() # optional gap_packages


sage: g.is_strongly_regular(parameters=True) # optional gap_packages
(275, 112, 30, 56)
sage: set(g.spectrum()) == {112, 2, -28} # optional gap_packages
True

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)

2.1. Common Graphs 423


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: g.order()
70
sage: g.size()
140
sage: g.radius()
7
sage: g.diameter()
8
sage: g.girth()
4
sage: g.chromatic_number()
3
sage: g.is_hamiltonian() # long time
False

static MoebiusKantorGraph()
Return a Möbius-Kantor Graph.
A Möbius-Kantor graph is a cubic symmetric graph. (See also the Heawood graph). It has 16 nodes and
24 edges. It is nonplanar and Hamiltonian. It has diameter = 4, girth = 6, and chromatic number = 2. It is
identical to the Generalized Petersen graph, P[8,3].
For more details, see Möbius-Kantor Graph - from Wolfram MathWorld.
PLOTTING: See the plotting section for the generalized Petersen graphs.
EXAMPLES:
sage: MK = graphs.MoebiusKantorGraph()
sage: MK
Moebius-Kantor Graph: Graph on 16 vertices
sage: MK.graph6_string()
'OhCGKE?O@?ACAC@I?Q_AS'
sage: (graphs.MoebiusKantorGraph()).show() # long time

static MoserSpindle()
Return the Moser spindle.
For more information, see 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

It is a Hamiltonian graph with radius 2, diameter 2, and girth 3.


sage: G.is_hamiltonian()
True
sage: G.radius()
2
(continues on next page)

424 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: G.diameter()
2
sage: G.girth()
3

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

static MuzychukS6Graph(n, d, Phi=’fixed’, Sigma=’fixed’, verbose=False)


Return a strongly regular graph of S6 type from [Mu07] on 𝑛𝑑 ((𝑛𝑑 − 1)/(𝑛 − 1) + 1) vertices
The construction depends upon a number of parameters, two of them, 𝑛 and 𝑑, mandatory, and Φ and Σ
mappings defined in [Mu07]. These graphs have parameters (𝑚𝑛𝑑 , 𝑛𝑑−1 (𝑚 − 1) − 1, 𝜇 − 2, 𝜇), where
𝑑−1 𝑑
𝜇 = 𝑛 𝑛−1−1 𝑛𝑑−1 and 𝑚 := 𝑛𝑛−1−1
+ 1.
Some details on Φ and Σ are as follows. Let 𝐿 be the complete graph on 𝑀 := {0, ..., 𝑚 − 1} with the
matching {(2𝑖, 2𝑖+1)|𝑖 = 0, ..., 𝑚/2} removed. Then one arbitrarily chooses injections Φ𝑖 from the edges
of 𝐿 on 𝑖 ∈ 𝑀 into sets of parallel classes of affine 𝑑-dimensional designs; our implementation uses the
designs of hyperplanes in 𝑑-dimensional affine geometries over 𝐺𝐹 (𝑛). Finally, for each edge 𝑖𝑗 of 𝐿 one
arbitrarily chooses bijections Σ𝑖𝑗 between Φ𝑖 and Φ𝑗 . More details, in particular how these choices lead
to non-isomorphic graphs, are in [Mu07].
INPUT:
• n (integer)– a prime power
• d (integer)– must be odd if 𝑛 is odd
• Phi is an optional parameter of the construction; it must be either
– ‘fixed’– this will generate fixed default Φ𝑖 , for 𝑖 ∈ 𝑀 , or
– ‘random’– Φ𝑖 are generated at random, or
– A dictionary describing the functions Φ𝑖 ; for 𝑖 ∈ 𝑀 , Phi[(i, T)] in 𝑀 , for each edge T of 𝐿 on 𝑖.
Also, each Φ𝑖 must be injective.
• Sigma is an optional parameter of the construction; it must be either
– ‘fixed’– this will generate a fixed default Σ, or
– ‘random’– Σ is generated at random.
• verbose (Boolean)– default is False. If True, print progress information
See also:

• is_muzychuk_S6()

Todo: Implement the possibility to explicitly supply the parameter Σ of the construction.

EXAMPLES:

2.1. Common Graphs 425


Sage Reference Manual: Graph Theory, Release 8.4

sage: graphs.MuzychukS6Graph(3, 3).is_strongly_regular(parameters=True)


(378, 116, 34, 36)
sage: phi={(2,(0,2)):0,(1,(1,3)):1,(0,(0,3)):1,(2,(1,2)):1,(1,(1,
....: 2)):0,(0,(0,2)):0,(3,(0,3)):0,(3,(1,3)):1}
sage: graphs.MuzychukS6Graph(2,2,Phi=phi).is_strongly_regular(parameters=True)
(16, 5, 0, 2)

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

The graphs 𝑀4 is (isomorphic to) the Grotzsch graph.

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

426 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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.

2.1. Common Graphs 427


Sage Reference Manual: Graph Theory, Release 8.4

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()

static NonisotropicOrthogonalPolarGraph(m, q, sign=’+’, perp=None)


𝜖,⊥
Returns the Graph 𝑁 𝑂𝑚 (𝑞)
Let the vectorspace of dimension 𝑚 over 𝐹𝑞 be endowed with a nondegenerate quadratic form 𝐹 , of type
sign for 𝑚 even.
• 𝑚 even: assume further that 𝑞 = 2 or 3. Returns the graph of the points (in the underlying projective
space) 𝑥 satisfying 𝐹 (𝑥) = 1, with adjacency given by orthogonality w.r.t. 𝐹 . Parameter perp is
ignored.
• 𝑚 odd: if perp is not None, then we assume that 𝑞 = 5 and return the graph of the points 𝑥 sat-
isfying 𝐹 (𝑥) = ±1 if sign="+", respectively 𝐹 (𝑥) ∈ {2, 3} if sign="-", with adjacency given
by orthogonality w.r.t. 𝐹 (cf. Sect 7.D of [BvL84]). Otherwise return the graph of nongenerate hy-
perplanes of type sign, adjacent whenever the intersection is degenerate (cf. Sect. 7.C of [BvL84]).
Note that for 𝑞 = 2 one will get a complete graph.
For more information, see Sect. 9.9 of [BH12] and [BvL84]. Note that the page of Andries Brouwer’s
website uses different notation.
INPUT:
• m - integer, half the dimension of the underlying vectorspace
• q - a power of a prime number, the size of the underlying field
• sign – "+" (default) or "-".
EXAMPLES:
𝑁 𝑂− (4, 2) is isomorphic to Petersen graph:

sage: g=graphs.NonisotropicOrthogonalPolarGraph(4,2,'-'); g
NO^-(4, 2): Graph on 10 vertices
sage: g.is_strongly_regular(parameters=True)
(10, 3, 0, 1)

𝑁 𝑂− (6, 2) and 𝑁 𝑂+ (6, 2):

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)

428 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: g.is_strongly_regular(parameters=True)
(28, 15, 6, 10)

𝑁 𝑂+ (8, 2):

sage: g=graphs.NonisotropicOrthogonalPolarGraph(8,2,'+')
sage: g.is_strongly_regular(parameters=True)
(120, 63, 30, 36)

Wilbrink’s graphs for 𝑞 = 5:

sage: graphs.NonisotropicOrthogonalPolarGraph(5,5,perp=1).is_strongly_
˓→regular(parameters=True) # long time

(325, 60, 15, 10)


sage: graphs.NonisotropicOrthogonalPolarGraph(5,5,'-',perp=1).is_strongly_
˓→regular(parameters=True) # long time

(300, 65, 10, 15)

Wilbrink’s graphs:

sage: g=graphs.NonisotropicOrthogonalPolarGraph(5,4,'+')
sage: g.is_strongly_regular(parameters=True)
(136, 75, 42, 40)
sage: g=graphs.NonisotropicOrthogonalPolarGraph(5,4,'-')
sage: g.is_strongly_regular(parameters=True)
(120, 51, 18, 24)
sage: g=graphs.NonisotropicOrthogonalPolarGraph(7,4,'+'); g # not tested
˓→(long time)

NO^+(7, 4): Graph on 2080 vertices


sage: g.is_strongly_regular(parameters=True) # not tested (long time)
(2080, 1071, 558, 544)

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

2.1. Common Graphs 429


Sage Reference Manual: Graph Theory, Release 8.4

linear code over 𝐹𝑞 with words 𝑐(𝑣) obtained from 𝑣 ∈ 𝑉 by computing

𝑐(𝑣) = (⟨𝑣, 𝑜1 ⟩, ..., ⟨𝑣, 𝑜𝑞+2 ⟩), 𝑜𝑗 ∈ 𝑂.

𝐶 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)

supplying your own hyperoval:

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

430 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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

static OrthogonalArrayBlockGraph(k, n, OA=None)


Returns the graph of an 𝑂𝐴(𝑘, 𝑛).
The intersection graph of the blocks of a transversal design with parameters (𝑘, 𝑛), or 𝑇 𝐷(𝑘, 𝑛) for short,
is a strongly regular graph (unless it is a complete graph). Its parameters (𝑣, 𝑘 ′ , 𝜆, 𝜇) are determined by
the parameters 𝑘, 𝑛 via:

𝑣 = 𝑛2 , 𝑘 ′ = 𝑘(𝑛 − 1), 𝜆 = (𝑘 − 1)(𝑘 − 2) + 𝑛 − 2, 𝜇 = 𝑘(𝑘 − 1)

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:

2.1. Common Graphs 431


Sage Reference Manual: Graph Theory, Release 8.4

• Brouwer’s website uses the notation 𝑂𝐴(𝑛, 𝑘) instead of 𝑂𝐴(𝑘, 𝑛)


• For given parameters 𝑘 and 𝑛 there can be many 𝑂𝐴(𝑘, 𝑛) : the graphs returned are not uniquely
defined by their parameters (see the examples below).
• If the function is called only with the parameter k and n the results might be different with two
versions of Sage, or even worse : some could not be available anymore.

See also:
sage.combinat.designs.orthogonal_arrays
INPUT:
• k,n (integers)
• OA – An orthogonal array. If set to None (default) then orthogonal_array() is called to 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)

432 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: g1 = graphs.OrthogonalArrayBlockGraph(3,4,oa1)
sage: g0.is_isomorphic(g1)
False

But nevertheless isospectral:


sage: g0.spectrum()
[9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3]
sage: g1.spectrum()
[9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3]

Note that the graph g0 is actually isomorphic to the affine polar graph 𝑉 𝑂+ (4, 2):
sage: graphs.AffineOrthogonalPolarGraph(4,2,'+').is_isomorphic(g0)
True

static OrthogonalPolarGraph(m, q, sign=’+’)


Returns the Orthogonal Polar Graph 𝑂𝜖 (𝑚, 𝑞).
For more information on Orthogonal Polar graphs, see the page of Andries Brouwer’s website.
INPUT:
• m,q (integers) – 𝑞 must be a prime power.
• sign – "+" or "-" if 𝑚 is even, "+" (default) otherwise.
EXAMPLES:
sage: G = graphs.OrthogonalPolarGraph(6,3,"+"); G
Orthogonal Polar Graph O^+(6, 3): Graph on 130 vertices
sage: G.is_strongly_regular(parameters=True)
(130, 48, 20, 16)
sage: G = graphs.OrthogonalPolarGraph(6,3,"-"); G
Orthogonal Polar Graph O^-(6, 3): Graph on 112 vertices
sage: G.is_strongly_regular(parameters=True)
(112, 30, 2, 10)
sage: G = graphs.OrthogonalPolarGraph(5,3); G
Orthogonal Polar Graph O(5, 3): Graph on 40 vertices
sage: G.is_strongly_regular(parameters=True)
(40, 12, 2, 4)
sage: G = graphs.OrthogonalPolarGraph(8,2,"+"); G
Orthogonal Polar Graph O^+(8, 2): Graph on 135 vertices
sage: G.is_strongly_regular(parameters=True)
(135, 70, 37, 35)
sage: G = graphs.OrthogonalPolarGraph(8,2,"-"); G
Orthogonal Polar Graph O^-(8, 2): Graph on 119 vertices
sage: G.is_strongly_regular(parameters=True)
(119, 54, 21, 27)

static PaleyGraph(q)
Paley graph with 𝑞 vertices
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)

2.1. Common Graphs 433


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: G.is_regular()
True

A Paley graph is always self-complementary:

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

(1225, 578, 273, 272)

static PathGraph(n, pos=None)


Return a path graph with 𝑛 nodes.
A path graph is a graph where all inner nodes are connected to their two neighbors and the two end-nodes
are connected to their one inner neighbors (i.e.: a cycle graph without the first and last node connected).
INPUT:
• n – number of nodes of the path graph
• pos (default: None) – a string which is either ‘circle’ or ‘line’ (otherwise the default is used) indi-
cating which embedding algorithm to use. See the plotting section below for more detail.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, the graph may be drawn in one of two ways: The ‘line’ argument will draw the graph in
a horizontal line (left to right) if there are less than 11 nodes. Otherwise the ‘line’ argument will append
horizontal lines of length 10 nodes below, alternating left to right and right to left. The ‘circle’ argument
will cause the graph to be drawn in a cycle-shape, with the first node at the top and then about the circle

434 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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

‘circle’: 10 < 𝑛 < 41

sage: q = graphs.PathGraph(25)
sage: q.show() # long time

‘line’: 𝑛 ≥ 41

sage: r = graphs.PathGraph(55)
sage: r.show() # long time

Override the default drawing:

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])

static PermutationGraph(second_permutation, first_permutation=None)


Build a permutation graph from one permutation or from two lists.
Definition:
If 𝜎 is a permutation of {1, 2, . . . , 𝑛}, then the permutation graph of 𝜎 is the graph on vertex set
{1, 2, . . . , 𝑛} in which two vertices 𝑖 and 𝑗 satisfying 𝑖 < 𝑗 are connected by an edge if and only if
𝜎 −1 (𝑖) > 𝜎 −1 (𝑗). A visual way to construct this graph is as follows:
Take two horizontal lines in the euclidean plane, and mark points 1, ..., 𝑛 from left to right on
the first of them. On the second one, still from left to right, mark 𝑛 points 𝜎(1), 𝜎(2), . . . , 𝜎(𝑛).
Now, link by a segment the two points marked with 1, then link together the points marked with
2, and so on. The permutation graph of 𝜎 is the intersection graph of those segments: there exists
a vertex in this graph for each element from 1 to 𝑛, two vertices 𝑖, 𝑗 being adjacent if the segments
𝑖 and 𝑗 cross each other.
The set of edges of the permutation graph can thus be identified with the set of inversions of the inverse of
the given permutation 𝜎.
A more general notion of permutation graph can be defined as follows: If 𝑆 is a set, and (𝑎1 , 𝑎2 , . . . , 𝑎𝑛 )
and (𝑏1 , 𝑏2 , . . . , 𝑏𝑛 ) are two lists of elements of 𝑆, each of which lists contains every element of 𝑆 exactly
once, then the permutation graph defined by these two lists is the graph on the vertex set 𝑆 in which two
vertices 𝑖 and 𝑗 are connected by an edge if and only if the order in which these vertices appear in the

2.1. Common Graphs 435


Sage Reference Manual: Graph Theory, Release 8.4

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:

• Recognition of Permutation graphs in the comparability module.


• Drawings of permutation graphs as intersection graphs of segments is possible through the show()
method of Permutation objects.
The correct argument to use in this case is show(representation = "braid").
• inversions()

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)

436 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


(2, 3, None),
(2, 5, None),
(3, 4, None),
(3, 5, None)]

sage: PG = graphs.PermutationGraph(Permutation([1,3,2]), Permutation([1,2,3]))


sage: sorted(PG.edges())
[(2, 3, None)]

sage: graphs.PermutationGraph([]).edges()
[]
sage: graphs.PermutationGraph([], []).edges()
[]

sage: PG = graphs.PermutationGraph("graph", "phrag")


sage: sorted(PG.edges())
[('a', 'g', None),
('a', 'h', None),
('a', 'p', None),
('g', 'h', None),
('g', 'p', None),
('g', 'r', None),
('h', 'r', None),
('p', 'r', None)]

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:

sage: petersen_spring = Graph({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: petersen_spring.show() # long time


sage: petersen_database = graphs.PetersenGraph()
sage: petersen_database.show() # long time

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

static QueenGraph(dim_list, radius=None, relabel=False)


Returns the 𝑑-dimensional Queen Graph with prescribed dimensions.

2.1. Common Graphs 437


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: G = graphs.QueenGraph( [2, 2] )


sage: G.is_isomorphic( graphs.CompleteGraph(4) )
True

The Queen Graph with radius 1 is isomorphic to the King Graph:

sage: G = graphs.QueenGraph( [4, 5], radius=1 )


sage: H = graphs.KingGraph( [5, 4] )
sage: G.is_isomorphic( H )
True

Also True in higher dimensions:

sage: G = graphs.QueenGraph( [3, 4, 5], radius=1 )


sage: H = graphs.KingGraph( [5, 3, 4] )
sage: G.is_isomorphic( H )
True

The Queen Graph can be obtained from the Rook Graph and the Bishop Graph:

sage: for d in range(3,12): # long time


....: for r in range(1,d+1):
....: G = graphs.QueenGraph([d,d],radius=r)
....: H = graphs.RookGraph([d,d],radius=r)
....: B = graphs.BishopGraph([d,d],radius=r)
....: H.add_edges(B.edges())
....: if not G.is_isomorphic(H):
....: print("that's not good!")

static RandomBarabasiAlbert(n, m, seed=None)


Return a random graph created using the Barabasi-Albert preferential attachment model.
A graph with m vertices and no edges is initialized, and a graph of n vertices is grown by attaching new
vertices each with m edges that are attached to existing vertices, preferentially with high degree.
INPUT:
• n - number of vertices in the graph

438 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

• m - number of edges to attach from each new node


• seed – integer seed for random number generator (default None).
EXAMPLES:
We show the edge list of a random graph on 6 nodes with m = 2.

sage: graphs.RandomBarabasiAlbert(6,2).edges(labels=False)
[(0, 2), (0, 3), (0, 4), (1, 2), (2, 3), (2, 4), (2, 5), (3, 5)]

We plot a random graph on 12 nodes with m = 3.

sage: ba = graphs.RandomBarabasiAlbert(12,3)
sage: ba.show() # long time

We view many random graphs using a graphics array:

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:

sage: n = randint(200, 300)


sage: G = graphs.RandomBicubicPlanar(n)
(continues on next page)

2.1. Common Graphs 439


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: G.order() == 2*n
True
sage: G.size() == 3*n
True
sage: G.is_bipartite() and G.is_planar() and G.is_regular(3)
True
sage: dic = {'red':[v for v in G.vertices() if v[0] == 'n'],
....: 'blue': [v for v in G.vertices() if v[0] != 'n']}
sage: G.plot(vertex_labels=False,vertex_size=20,vertex_colors=dic)
Graphics object consisting of ... graphics primitives

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:

sage: g = graphs.RandomBipartite(5, 2, 0.5)


sage: g.vertices()
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1)]

static RandomBlockGraph(m, k, kmax=None, incidence_structure=False)


Return a Random Block Graph.
A block graph is a connected graph in which every biconnected component (block) is a clique.
See also:

• Wikipedia article Block_graph for more details on these graphs


• is_block_graph() – test if a graph is a block graph

440 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

• 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

A block graph with blocks of order 2 is a tree:

sage: B = graphs.RandomBlockGraph(10, 2)
sage: B.is_tree()
True

Every biconnected component of a block graph is a clique:

sage: B = graphs.RandomBlockGraph(5, 3, kmax=6)


sage: blocks,cuts = B.blocks_and_cut_vertices()
sage: all(B.is_clique(block) for block in blocks)
True

A block graph with blocks of order 𝑘 has 𝑚 * (𝑘 − 1) + 1 vertices:

sage: m, k = 6, 4
sage: B = graphs.RandomBlockGraph(m, k)
sage: B.order() == m*(k-1)+1
True

Test recognition methods:

sage: B = graphs.RandomBlockGraph(6, 2, kmax=6)


sage: B.is_block_graph()
True
sage: B in graph_classes.Block
True

Asking for the incidence structure:

2.1. Common Graphs 441


Sage Reference Manual: Graph Theory, Release 8.4

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

static RandomGNM(n, m, dense=False, seed=None)


Returns a graph randomly picked out of all graphs on n vertices with m edges.
INPUT:
• n - number of vertices.
• m - number of edges.
• dense - whether to use NetworkX’s dense_gnm_random_graph or gnm_random_graph
• seed – integer seed for random number generator (default None).
EXAMPLES: We show the edge list of a random graph on 5 nodes with 10 edges.

sage: graphs.RandomGNM(5, 10).edges(labels=False)


[(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3,
˓→4)]

We plot a random graph on 12 nodes with m = 12.

sage: gnm = graphs.RandomGNM(12, 12)


sage: gnm.show() # long time

We view many random graphs using a graphics array:

442 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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

static RandomGNP(n, p, seed=None, fast=True, algorithm=’Sage’)


Returns a random graph on 𝑛 nodes. Each edge is inserted independently with probability 𝑝.
INPUT:
• n – number of nodes of the graph
• p – probability of an edge
• seed – integer seed for random number generator (default None).
• fast – boolean set to True (default) to use the algorithm with time complexity in 𝑂(𝑛+𝑚) proposed
in [BatBra2005]. It is designed for generating large sparse graphs. It is faster than other algorithms
for LARGE instances (try it to know whether it is useful for you).
• algorithm – By default (`algorithm='Sage'), this function uses the algorithm implemented
in `sage.graphs.graph_generators_pyx.pyx. When algorithm='networkx', this
function calls the NetworkX function fast_gnp_random_graph, unless fast=False, then
gnp_random_graph. Try them to know which algorithm is the best for you. The fast parameter
is not taken into account by the ‘Sage’ algorithm so far.
REFERENCES:
PLOTTING: When plotting, this graph will use the default spring-layout algorithm, unless a position
dictionary is specified.
EXAMPLES: We show the edge list of a random graph on 6 nodes with probability 𝑝 = .4:
sage: set_random_seed(0)
sage: graphs.RandomGNP(6, .4).edges(labels=False)
[(0, 1), (0, 5), (1, 2), (2, 4), (3, 4), (3, 5), (4, 5)]

We plot a random graph on 12 nodes with probability 𝑝 = .71:


sage: gnp = graphs.RandomGNP(12,.71)
sage: gnp.show() # long time

We view many random graphs using a graphics array:


sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.RandomGNP(i+3,.43)
....: g.append(k)
sage: for i in range(3):
....: n = []
....: for m in range(3):
(continues on next page)

2.1. Common Graphs 443


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


....: 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.RandomGNP(4,1)
Complete graph: Graph on 4 vertices

static RandomHolmeKim(n, m, p, seed=None)


Returns a random graph generated by the Holme and Kim algorithm for graphs with power law degree
distribution and approximate average clustering.
INPUT:
• n - number of vertices.
• m - number of random edges to add for each new node.
• p - probability of adding a triangle after adding a random edge.
• seed – integer seed for random number generator (default None).
From the NetworkX documentation: The average clustering has a hard time getting above a certain cutoff
that depends on m. This cutoff is often quite low. Note that the transitivity (fraction of triangles to possible
triangles) seems to go down with network size. It is essentially the Barabasi-Albert growth model with
an extra step that each random edge is followed by a chance of making an edge to one of its neighbors
too (and thus a triangle). This algorithm improves on B-A in the sense that it enables a higher average
clustering to be attained if desired. It seems possible to have a disconnected graph with this algorithm
since the initial m nodes may not be all linked to a new node on the first iteration like the BA model.
EXAMPLES: We show the edge list of a random graph on 8 nodes with 2 random edges per node and a
probability 𝑝 = 0.5 of forming triangles.

sage: graphs.RandomHolmeKim(8, 2, 0.5).edges(labels=False)


[(0, 2), (0, 5), (1, 2), (1, 3), (2, 3), (2, 4), (2, 6), (2, 7),
(3, 4), (3, 6), (3, 7), (4, 5)]

sage: G = graphs.RandomHolmeKim(12, 3, .3)


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.

444 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: graphs.RandomLobster(3, 0.7, 0.3).edges(labels=False)


[(0, 1), (1, 2)]

sage: G = graphs.RandomLobster(9, .6, .3)


sage: G.show() # long time

static RandomNewmanWattsStrogatz(n, k, p, seed=None)


Returns a Newman-Watts-Strogatz small world random graph on n vertices.
From the NetworkX documentation: First create a ring over n nodes. Then each node in the ring is
connected with its k nearest neighbors. Then shortcuts are created by adding new edges as follows: for
each edge u-v in the underlying “n-ring with k nearest neighbors”; with probability p add a new edge u-w
with randomly-chosen existing node w. In contrast with watts_strogatz_graph(), no edges are removed.
INPUT:
• n - number of vertices.
• k - each vertex is connected to its k nearest neighbors
• p - the probability of adding a new edge for each edge
• seed – integer seed for random number generator (default None).
EXAMPLES: We show the edge list of a random graph on 7 nodes with 2 “nearest neighbors” and proba-
bility 𝑝 = 0.2:

sage: graphs.RandomNewmanWattsStrogatz(7, 2, 0.2).edges(labels=False)


[(0, 1), (0, 2), (0, 3), (0, 6), (1, 2), (2, 3), (2, 4), (3, 4), (3, 6), (4,
˓→5), (5, 6)]

sage: G = graphs.RandomNewmanWattsStrogatz(12, 2, .3)


sage: G.show() # long time

2.1. Common Graphs 445


Sage Reference Manual: Graph Theory, Release 8.4

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.

sage: graphs.RandomRegular(3, 8).edges(labels=False)


[(0, 1), (0, 4), (0, 7), (1, 5), (1, 7), (2, 3), (2, 5), (2, 6), (3, 4), (3,
˓→6), (4, 5), (6, 7)]

sage: G = graphs.RandomRegular(3, 20)


sage: if G:
....: G.show() # random output, long time

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: graphs.RandomRegularBipartite(1, 2, 2, set_position=True).get_pos()


{0: (1, 1.0), 1: (0, 0), 2: (2.0, 0.0)}
sage: graphs.RandomRegularBipartite(2, 1, 1, set_position=True).get_pos()
{0: (0, 1), 1: (2.0, 1.0), 2: (1, 0.0)}
sage: graphs.RandomRegularBipartite(2, 3, 3, set_position=True).get_pos()
{0: (0, 1), 1: (3.0, 1.0), 2: (0, 0), 3: (1.5, 0.0), 4: (3.0, 0.0)}
sage: graphs.RandomRegularBipartite(2, 3, 3, set_position=False).get_pos()

446 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

static RandomShell(constructor, seed=None)


Returns a random shell graph for the constructor given.
INPUT:
• constructor - a list of 3-tuples (n,m,d), each representing a shell
• n - the number of vertices in the shell
• m - the number of edges in the shell
• d - the ratio of inter (next) shell edges to intra shell edges
• seed – integer seed for random number generator (default None).
EXAMPLES:

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,

˓→26), (24, 27), (25, 27), (25, 29)]

sage: G.show() # long time

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.

2.1. Common Graphs 447


Sage Reference Manual: Graph Theory, Release 8.4

INPUT:
• n - number of vertices in the tree
EXAMPLES:

sage: G = graphs.RandomTree(10)
sage: G.is_tree()
True
sage: G.show() # long time

static RandomTreePowerlaw(n, gamma=3, tries=100, seed=None)


Returns a tree with a power law degree distribution. Returns False on failure.
From the NetworkX documentation: A trial power law degree sequence is chosen and then elements are
swapped with new elements from a power law distribution until the sequence makes a tree (size = order -
1).
INPUT:
• n - number of vertices
• gamma - exponent of power law
• tries - number of attempts to adjust sequence to make a tree
• seed – integer seed for random number generator (default None).
EXAMPLES: We show the edge list of a random graph with 10 nodes and a power law exponent of 2.

sage: graphs.RandomTreePowerlaw(10, 2).edges(labels=False)


[(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (6, 8), (6, 9)]

sage: G = graphs.RandomTreePowerlaw(15, 2)
sage: if G:
....: G.show() # random output, long time

static RandomTriangulation(n, set_position=False)


Return a random triangulation on 𝑛 vertices.
A triangulation is a planar graph all of whose faces are triangles (3-cycles).
INPUT:
• 𝑛 – an integer
• set_position – boolean (default False) if set to True, this will compute coordinates for a
planar drawing of the graph.
OUTPUT:
A random triangulation chosen uniformly among the rooted triangulations on 𝑛 vertices. This is a planar
graph and comes with a combinatorial embedding.
Because some triangulations have nontrivial automorphism groups, this may not be equal to the uniform
distribution among unrooted triangulations.
ALGORITHM:
The algorithm is taken from [PS2006], section 2.1.
Starting from a planar tree (represented by its contour as a sequence of vertices), one first performs local
closures, until no one is possible. A local closure amounts to replace in the cyclic contour word a sequence

448 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: G = graphs.RandomTriangulation(6, True); G


Graph on 6 vertices
sage: G.is_planar()
True
sage: G.girth()
3
sage: G.plot(vertex_size=0, vertex_labels=False)
Graphics object consisting of 13 graphics primitives

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.

2.1. Common Graphs 449


Sage Reference Manual: Graph Theory, Release 8.4

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

static RookGraph(dim_list, radius=None, relabel=False)


Returns the 𝑑-dimensional Rook’s Graph with prescribed dimensions.
The 2-dimensional Rook’s 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 rook.
The 𝑑-dimensional Rook Graph with 𝑑 >= 2 has for vertex set the cells of a 𝑑-dimensional grid with
prescribed dimensions, and each edge corresponds to a legal move by a rook in any of the dimensions.
The Rook’s Graph for an 𝑛 × 𝑚 chessboard may also be defined as the Cartesian product of two complete
graphs 𝐾𝑛 𝐾𝑚 .
INPUT:
• dim_list – 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 decrease the power of
the rook to at most radius steps. When the radius is 1, the resulting graph is a d-dimensional grid.
• relabel – (default: False) a boolean set to True if vertices must be relabeled as integers.
EXAMPLES:
The (𝑛, 𝑚)-Rook’s Graph is isomorphic to the Cartesian product of two complete graphs:

sage: G = graphs.RookGraph( [3, 4] )


sage: H = ( graphs.CompleteGraph(3) ).cartesian_product( graphs.
˓→CompleteGraph(4) )

sage: G.is_isomorphic( H )
True

When the radius is 1, the Rook’s Graph is a grid:

sage: G = graphs.RookGraph( [3, 3, 4], radius=1 )


sage: H = graphs.GridGraph( [3, 4, 3] )
sage: G.is_isomorphic( H )
True

450 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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.

Todo: Find a beautiful layout for this beautiful graph.

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)

The graph is vertex-transitive:

sage: S.is_vertex_transitive()
True

The neighborhood of each vertex is isomorphic to the complement of the Clebsch graph:

sage: neighborhood = S.subgraph(vertices = S.neighbors(0))


sage: graphs.ClebschGraph().complement().is_isomorphic(neighborhood)
True

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)

2.1. Common Graphs 451


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


....: for j in range(i) ])
{2}

It is non-planar, and both Hamiltonian and Eulerian:

sage: G.is_planar()
False
sage: G.is_hamiltonian()
True
sage: G.is_eulerian()
True

It has radius 2, diameter 2, and girth 3:

sage: G.radius()
2
sage: G.diameter()
2
sage: G.girth()
3

Its chromatic number is 4 and its automorphism group is of order 192:

sage: G.chromatic_number()
4
sage: G.automorphism_group().cardinality()
192

It is an integral graph since it has only integral eigenvalues:

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:

452 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

2.1. Common Graphs 453


Sage Reference Manual: Graph Theory, Release 8.4

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)

454 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


2
sage: g.is_hamiltonian()
False
sage: g.delete_vertex(g.random_vertex())
sage: g.is_hamiltonian()
True

static SquaredSkewHadamardMatrixGraph(n)
Pseudo-𝑂𝐴(2𝑛, 4𝑛 − 1)-graph from a skew Hadamard matrix of order 4𝑛
A strongly regular graph with parameters of the orthogonal array graph
OrthogonalArrayBlockGraph, also known as pseudo Latin squares graph 𝐿2𝑛 (4𝑛 − 1),
constructed from a skew Hadamard matrix of order 4𝑛, due to Goethals and Seidel, see [BvL84].
See also:

• is_orthogonal_array_block_graph()

EXAMPLES:

sage: graphs.SquaredSkewHadamardMatrixGraph(4).is_strongly_
˓→regular(parameters=True)

(225, 112, 55, 56)


sage: graphs.SquaredSkewHadamardMatrixGraph(9).is_strongly_
˓→regular(parameters=True) # long time

(1225, 612, 305, 306)

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: import networkx

Compare the plots:

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

View many star graphs as a Sage Graphics Array


With this constructor (i.e., the position dictionary filled)

2.1. Common Graphs 455


Sage Reference Manual: Graph Theory, Release 8.4

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

Compared to plotting with the spring-layout algorithm

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:

sage: g = graphs.SuzukiGraph(); g # optional database_gap internet


˓→# not tested

Suzuki graph: Graph on 1782 vertices


sage: g.is_strongly_regular(parameters=True) # optional database_gap internet
˓→# not tested

(1782, 416, 100, 96)

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:

456 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

• is_switch_skewhad()

EXAMPLES:

sage: g=graphs.SwitchedSquaredSkewHadamardMatrixGraph(4)
sage: g.is_strongly_regular(parameters=True)
(226, 105, 48, 49)
sage: from sage.combinat.designs.twographs import twograph_descendant
sage: twograph_descendant(g,0).is_strongly_regular(parameters=True)
(225, 112, 55, 56)
sage: twograph_descendant(g.complement(),0).is_strongly_
˓→regular(parameters=True)

(225, 112, 55, 56)

static SylvesterGraph()
Return the Sylvester Graph.
This graph is obtained from the Hoffman Singleton graph by considering the graph induced by the vertices
at distance two from the vertices of an (any) edge.
For more information on the Sylvester graph, see https://www.win.tue.nl/~aeb/graphs/Sylvester.html.
See also:

• HoffmanSingletonGraph().

EXAMPLES:

sage: g = graphs.SylvesterGraph(); g
Sylvester Graph: Graph on 36 vertices
sage: g.order()
36
sage: g.size()
90
sage: g.is_regular(k=5)
True

static SymplecticDualPolarGraph(m, q)
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:

sage: G = graphs.SymplecticDualPolarGraph(6,3); G # not tested (long


˓→time)

Symplectic Dual Polar Graph DSp(6, 3): Graph on 1120 vertices


sage: G.is_distance_regular(parameters=True) # not tested (long
˓→time)

([39, 36, 27, None], [None, 1, 4, 13])

REFERENCE:
static SymplecticPolarGraph(d, q, algorithm=None)
Returns the Symplectic Polar Graph 𝑆𝑝(𝑑, 𝑞).

2.1. Common Graphs 457


Sage Reference Manual: Graph Theory, Release 8.4

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)

(1365, 340, 83, 85)

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

static T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None,


check_hyperoval=True)
Return the collinearity graph of the generalized quadrangle 𝑇2* (𝑞), or of its dual
Let 𝑞 = 2𝑘 and Θ = 𝑃 𝐺(3, 𝑞). 𝑇2* (𝑞) is a generalized quadrangle [GQwiki] of order (𝑞 − 1, 𝑞 + 1), see
3.1.3 in [PT09]. Fix a plane Π ⊂ Θ and a hyperoval 𝑂 ⊂ Π. The points of 𝑇2* (𝑞) := 𝑇2* (𝑂) are the points
of Θ outside Π, and the lines are the lines of Θ outside Π that meet Π in a point of 𝑂.
INPUT:

458 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

• 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)

supplying your own hyperoval:

sage: F=GF(4,'b')
sage: O=[vector(F,(0,0,0,1)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for
˓→x in F]

sage: g=graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F); g


T2*(O,4); GQ(3, 5): Graph on 64 vertices
sage: g.is_strongly_regular(parameters=True)
(64, 18, 2, 6)

static TadpoleGraph(n1, n2)


Return a tadpole graph with n1+n2 nodes.
A tadpole graph is a path graph (order n2) connected to a cycle graph (order n1).
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm.
By convention, the cycle graph will be drawn in the lower-left corner with the (n1)th node at a 45 degree
angle above the right horizontal center of the cycle graph, leading directly into the path graph.
EXAMPLES:
Construct and show a tadpole graph Cycle = 13, Stick = 4:

sage: g = graphs.TadpoleGraph(13, 4); g


Tadpole graph: Graph on 17 vertices
sage: g.show() # long time

static TaylorTwographDescendantSRG(q, clique_partition=None)


constructing the descendant graph of the Taylor’s two-graph for 𝑈3 (𝑞), 𝑞 odd
This is a strongly regular graph with parameters (𝑣, 𝑘, 𝜆, 𝜇) = (𝑞 3 , (𝑞 2 +1)(𝑞 −1)/2, (𝑞 −1)3 /4−1, (𝑞 2 +
1)(𝑞 − 1)/4) obtained as a two-graph descendant of the Taylor's two-graph 𝑇 . This graph admits
a partition into cliques of size 𝑞, which are useful in TaylorTwographSRG(), a strongly regular graph
on 𝑞 3 + 1 vertices in the Seidel switching class of 𝑇 , for which we need (𝑞 2 + 1)/2 cliques. The cliques

2.1. Common Graphs 459


Sage Reference Manual: Graph Theory, Release 8.4

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

460 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

The following example requires networkx:

sage: import networkx as NX

Compare this Tetrahedral, Wheel(4), Complete(4), and the Tetrahedral plotted with the spring-layout al-
gorithm below in a Sage graphics array:

sage: tetra_pos = graphs.TetrahedralGraph()


sage: tetra_spring = Graph(NX.tetrahedral_graph())
sage: wheel = graphs.WheelGraph(4)
sage: complete = graphs.CompleteGraph(4)
sage: g = [tetra_pos, tetra_spring, wheel, complete]
sage: j = []
sage: for i in range(2):
....: n = []
....: for m in range(2):
....: n.append(g[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 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

2.1. Common Graphs 461


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: tolrep = [(1,4,3),(1,2,1),(2,3,1),(0,3,3)]


sage: g = graphs.ToleranceGraph(tolrep)
sage: g.get_vertex(3)
(0, 3, 3)
sage: neigh = g.neighbors(3)
sage: for v in neigh: print(g.get_vertex(v))
(1, 2, 1)
(2, 3, 1)
sage: g.is_interval()
False
sage: g.is_weakly_chordal()
True

The intervals in the list need not be distinct

sage: tolrep2 = [(0,4,5),(1,2,1),(2,3,1),(0,4,5)]


sage: g2 = graphs.ToleranceGraph(tolrep2)
sage: g2.get_vertices()
{0: (0, 4, 5), 1: (1, 2, 1), 2: (2, 3, 1), 3: (0, 4, 5)}
sage: g2.is_isomorphic(g)
True

Real values are also allowed

sage: tolrep = [(0.1,3.3,4.4),(1.1,2.5,1.1),(1.4,4.4,3.3)]


sage: g = graphs.ToleranceGraph(tolrep)
sage: g.is_isomorphic(graphs.PathGraph(3))
True

static Toroidal6RegularGrid2dGraph(n1, n2)


Returns a toroidal 6-regular grid.
The toroidal 6-regular grid is a 6-regular graph on 𝑛1 × 𝑛2 vertices and its elements have coordinates (𝑖, 𝑗)
for 𝑖 ∈ {0...𝑖 − 1} and 𝑗 ∈ {0...𝑗 − 1}.
Its edges are those of the ToroidalGrid2dGraph(), to which are added the edges between (𝑖, 𝑗) and
((𝑖 + 1)%𝑛1 , (𝑗 + 1)%𝑛2 ).

462 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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 ToroidalGrid2dGraph(n1, n2)


Returns a toroidal 2-dimensional grid graph with 𝑛1 𝑛2 nodes (𝑛1 rows and 𝑛2 columns).
The toroidal 2-dimensional grid with parameters 𝑛1 , 𝑛2 is the 2-dimensional grid graph with identical
parameters to which are added the edges ((𝑖, 0), (𝑖, 𝑛2 − 1)) and ((0, 𝑖), (𝑛1 − 1, 𝑖)).
EXAMPLES:
The toroidal 2-dimensional grid is a regular graph, while the usual 2-dimensional grid is not

sage: tgrid = graphs.ToroidalGrid2dGraph(8,9)


sage: print(tgrid)
Toroidal 2D Grid Graph with parameters 8,9
sage: grid = graphs.Grid2dGraph(8,9)
sage: grid.is_regular()
False
sage: tgrid.is_regular()
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.

sage: g.order(), g.size() # not tested


(120, 180)

static TruncatedTetrahedralGraph()
Return the truncated tetrahedron.

2.1. Common Graphs 463


Sage Reference Manual: Graph Theory, Release 8.4

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()

464 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: G=graphs.U42Graph216() # optional - gap_packages (grape)


sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape)
(216, 40, 4, 8)

2.1. Common Graphs 465


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: G=graphs.U42Graph540() # optional - gap_packages (grape)


sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape)
(540, 187, 58, 68)

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:

sage: USA = graphs.USAMap()


sage: len([n2 for n2 in USA if USA.distance('Pennsylvania', n2) == 2])
7

Diameter for continental USA:

sage: USAcont = graphs.USAMap(continental=True)


sage: USAcont.diameter()
11

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(5,2); G # long time


Unitary Dual Polar Graph DU(5, 2); GQ(8, 4): Graph on 297 vertices
sage: G.is_strongly_regular(parameters=True) # long time
(297, 40, 7, 5)

Another way to get the generalized quadrangle of order (2,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

466 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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 UnitaryPolarGraph(m, q, algorithm=’gap’)


Returns the Unitary Polar Graph 𝑈 (𝑚, 𝑞).
For more information on Unitary Polar graphs, see the page of Andries Brouwer’s website.
INPUT:
• m,q (integers) – 𝑞 must be a prime power.
• algorithm – if set to ‘gap’ then the computation is carried via GAP library interface, computing
totally singular subspaces, which is faster for large examples (especially with 𝑞 > 2). Otherwise it is
done directly.
EXAMPLES:
sage: G = graphs.UnitaryPolarGraph(4,2); G
Unitary Polar Graph U(4, 2); GQ(4, 2): Graph on 45 vertices
sage: G.is_strongly_regular(parameters=True)
(45, 12, 3, 3)
sage: graphs.UnitaryPolarGraph(5,2).is_strongly_regular(parameters=True)
(165, 36, 3, 9)
sage: graphs.UnitaryPolarGraph(6,2) # not tested (long time)
Unitary Polar Graph U(6, 2): Graph on 693 vertices

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)

2.1. Common Graphs 467


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


75
sage: g.chromatic_number()
3

static WellsGraph()
Return the Wells graph.
For more information on the Wells graph (also called Armanios-Wells graph), see this page.
The implementation follows the construction given on page 266 of [BCN1989]. This requires to create 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)

468 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


....: 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

Next, using the spring-layout algorithm:

sage: import networkx


sage: g = []
sage: j = []
sage: for i in range(9):
....: spr = networkx.wheel_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

Compare the plotting:

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

2.1. Common Graphs 469


Sage Reference Manual: Graph Theory, Release 8.4

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:

• Wikipedia article Windmill_graph


• GraphGenerators.StarGraph()
• GraphGenerators.FriendshipGraph()

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

The Windmill graph 𝑊 𝑑(3, 𝑛) is the Friendship graph 𝐹𝑛 :


sage: n = 5
sage: W = graphs.WindmillGraph(3, n)
sage: W.is_isomorphic( graphs.FriendshipGraph(n) )
True

The Windmill graph 𝑊 𝑑(3, 2) is the Butterfly graph:


sage: W = graphs.WindmillGraph(3, 2)
sage: W.is_isomorphic( graphs.ButterflyGraph() )
True

The Windmill graph 𝑊 𝑑(𝑘, 𝑛) has chromatic number 𝑘:


sage: n,k = 5,6
sage: W = graphs.WindmillGraph(k, n)
sage: W.chromatic_number() == k
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)

470 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: g.gps_coordinates["Bolivia"]
[[17, 'S'], [65, 'W']]
sage: sorted(g.connected_component_containing_vertex('Ireland'))
['Ireland', 'United Kingdom']

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: chang_graphs = graphs.chang_graphs()


sage: K8 = graphs.CompleteGraph(8)
sage: T8 = K8.line_graph()
sage: four_srg = chang_graphs + [T8]
sage: for g in four_srg:
....: print(g.is_strongly_regular(parameters=True))
(28, 12, 6, 4)
(28, 12, 6, 4)
(28, 12, 6, 4)
(28, 12, 6, 4)
sage: from itertools import combinations
sage: for g1,g2 in combinations(four_srg,2):
....: assert not g1.is_isomorphic(g2)

Construct the Chang graphs by Seidel switching:

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]

cospectral_graphs(vertices, matrix_function=<function <lambda>>, graphs=None)


Find all sets of graphs on vertices vertices (with possible restrictions) which are cospectral with respect
to a constructed matrix.
INPUT:
• vertices - The number of vertices in the graphs to be tested
• matrix_function - A function taking a graph and giving back a matrix. This defaults to the
adjacency matrix. The spectra examined are the spectra of these matrices.
• graphs - One of three things:
– None (default) - test all graphs having vertices vertices
– a function taking a graph and returning True or False - test only the graphs on vertices
vertices for which the function returns True

2.1. Common Graphs 471


Sage Reference Manual: Graph Theory, Release 8.4

– 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:

sage: g=graphs.cospectral_graphs(6, graphs=lambda x: min(x.degree())>0)


sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g)
[['Ep__', 'Er?G'], ['ExGg', 'ExoG']]
sage: g[0][1].am().charpoly()==g[0][1].am().charpoly()
True
sage: g[1][1].am().charpoly()==g[1][1].am().charpoly()
True

There is one pair of cospectral trees on eight vertices:

sage: g=graphs.cospectral_graphs(6, graphs=graphs.trees(8))


sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g)
[['GiPC?C', 'GiQCC?']]
sage: g[0][1].am().charpoly()==g[0][1].am().charpoly()
True

There are two sets of cospectral graphs (with respect to the Laplacian matrix) on six vertices:

sage: g=graphs.cospectral_graphs(6, matrix_function=lambda g: g.laplacian_


˓→matrix())

sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g)


[['Edq_', 'ErcG'], ['Exoo', 'EzcG']]
sage: g[0][1].laplacian_matrix().charpoly()==g[0][1].laplacian_matrix().
˓→charpoly()

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:

sage: def DinverseA(g):


....: A=g.adjacency_matrix().change_ring(QQ)
(continues on next page)

472 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


....: for i in range(g.order()):
....: A.rescale_row(i, 1/len(A.nonzero_positions_in_row(i)))
....: return A
sage: g=graphs.cospectral_graphs(5, matrix_function=DinverseA, graphs=lambda
˓→g: min(g.degree())>0)

sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g)


[['Dlg', 'Ds_']]
sage: g[0][1].laplacian_matrix(normalized=True).charpoly()==g[0][1].laplacian_
˓→matrix(normalized=True).charpoly()

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:

• set_embedding(), get_embedding() – get/set methods for embeddings.

EXAMPLES:
There are 1812 isomers of C60 , i.e., 1812 fullerene graphs on 60 vertices:

sage: gen = graphs.fullerenes(60) # optional buckygen


sage: len(list(gen)) # optional buckygen
1812

However, there is only one IPR fullerene graph on 60 vertices: the famous Buckminster Fullerene:

sage: gen = graphs.fullerenes(60, ipr=True) # optional buckygen


sage: next(gen) # optional buckygen
Graph on 60 vertices
sage: next(gen) # optional buckygen
Traceback (most recent call last):
...
StopIteration

The unique fullerene graph on 20 vertices is isomorphic to the dodecahedron graph.

sage: gen = graphs.fullerenes(20) # optional buckygen


sage: g = next(gen) # optional buckygen
sage: g.is_isomorphic(graphs.DodecahedralGraph()) # optional buckygen
True
sage: g.get_embedding() # optional buckygen
{1: [2, 3, 4],
2: [1, 5, 6],
(continues on next page)

2.1. Common Graphs 473


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


3: [1, 7, 8],
4: [1, 9, 10],
5: [2, 10, 11],
6: [2, 12, 7],
7: [3, 6, 13],
8: [3, 14, 9],
9: [4, 8, 15],
10: [4, 16, 5],
11: [5, 17, 12],
12: [6, 11, 18],
13: [7, 18, 14],
14: [8, 13, 19],
15: [9, 19, 16],
16: [10, 15, 17],
17: [11, 16, 20],
18: [12, 20, 13],
19: [14, 20, 15],
20: [17, 19, 18]}
sage: g.plot3d(layout='spring') # optional buckygen
Graphics3d Object

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:

• set_embedding(), get_embedding() – get/set methods for embeddings.

EXAMPLES:
There is a unique fusene with 2 hexagons:

sage: gen = graphs.fusenes(2) # optional benzene


sage: len(list(gen)) # optional benzene
1

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:

sage: gen = graphs.fusenes(2) # optional benzene


sage: next(gen) # optional benzene
Graph on 10 vertices
(continues on next page)

474 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: next(gen) # optional benzene
Traceback (most recent call last):
...
StopIteration

There are 6505 benzenoids with 9 hexagons:


sage: gen = graphs.fusenes(9, benzenoids=True) # optional benzene
sage: len(list(gen)) # optional benzene
6505

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

-c : only write connected graphs


-C : only write biconnected graphs
-t : only generate triangle-free graphs
-f : only generate 4-cycle-free graphs
(continues on next page)

2.1. Common Graphs 475


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


-b : only generate bipartite graphs
(-t, -f and -b can be used in any combination)
-m : save memory at the expense of time (only makes a
difference in the absence of -b, -t, -f and n <= 28).
-d# : a lower bound for the minimum degree
-D# : a upper bound for the maximum degree
-v : display counts by number of edges
-l : canonically label output graphs

-q : suppress auxiliary output (except from -v)

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.

sage: gen = graphs.nauty_geng("2")


sage: next(gen)
Graph on 2 vertices
sage: next(gen)
Graph on 2 vertices
sage: next(gen)
Traceback (most recent call last):
...
StopIteration

A list of all graphs on 7 vertices. This agrees with OEIS sequence A000088.

sage: gen = graphs.nauty_geng("7")


sage: len(list(gen))
1044

A list of just the connected graphs on 7 vertices. This agrees with OEIS sequence A001349.

sage: gen = graphs.nauty_geng("7 -c")


sage: len(list(gen))
853

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.

476 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

sage: gen = graphs.nauty_geng("4", debug=True)


sage: print(next(gen))
>A geng -d0D3 n=4 e=0-6

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]

The two different inputs generate the same graphs:

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

planar_graphs(order, minimum_degree=None, minimum_connectivity=None, ex-


act_connectivity=False, only_bipartite=False, dual=False)
An iterator over connected planar graphs using the plantri generator.
This uses the plantri generator (see [plantri]) which is available through the optional package plantri.

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.

2.1. Common Graphs 477


Sage Reference Manual: Graph Theory, Release 8.4

• 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:

• set_embedding(), get_embedding() – get/set methods for embeddings.

EXAMPLES:
There are 6 planar graphs on 4 vertices:
sage: gen = graphs.planar_graphs(4) # optional plantri
sage: len(list(gen)) # optional plantri
6

Three of these planar graphs are bipartite:


sage: gen = graphs.planar_graphs(4, only_bipartite=True) # optional plantri
sage: len(list(gen)) # optional plantri
3

Setting dual=True gives the planar dual graphs:


sage: gen = graphs.planar_graphs(4, dual=True) # optional plantri
sage: [u for u in list(gen)] # optional plantri
[Graph on 4 vertices,
Multi-graph on 3 vertices,
Multi-graph on 2 vertices,
Looped multi-graph on 2 vertices,
Looped multi-graph on 1 vertex,
Looped multi-graph on 1 vertex]

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
[]

478 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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:

• set_embedding(), get_embedding() – get/set methods for embeddings.

EXAMPLES:
The cube is the only 3-connected planar quadrangulation on 8 vertices:

sage: gen = graphs.quadrangulations(8, minimum_connectivity=3) # optional


˓→plantri

sage: g = next(gen) # optional


˓→plantri

sage: g.is_isomorphic(graphs.CubeGraph(3)) # optional


˓→plantri

True
sage: next(gen) # optional
˓→plantri

Traceback (most recent call last):


...
StopIteration

An overview of the number of quadrangulations on up to 12 vertices. This agrees with OEIS sequence
A113201:

2.1. Common Graphs 479


Sage Reference Manual: Graph Theory, Release 8.4

sage: for i in range(4,13): # optional plantri


....: L = len(list(graphs.quadrangulations(i))) # optional plantri
....: print("{:2d} {:3d}".format(i,L)) # optional plantri
4 1
5 1
6 2
7 3
8 9
9 18
10 62
11 198
12 803

There are 2 planar quadrangulation on 12 vertices that do not have a non-facial quadrangle:

sage: len([g for g in graphs.quadrangulations(12, no_nonfacial_


˓→quadrangles=True)]) # optional plantri
2

Setting dual=True gives the planar dual graphs:

sage: [len(g) for g in graphs.quadrangulations(12, no_nonfacial_


˓→quadrangles=True, dual=True)] # optional plantri
[10, 10]

static strongly_regular_graph(v, k, l, mu=-1, existence=False, check=True)


Return a (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular graph.
This function relies partly on Andries Brouwer’s database of strongly regular graphs. See the documenta-
tion 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

Now without specifying 𝜇:

sage: graphs.strongly_regular_graph(10,3,0)
complement(Johnson graph with parameters 5,2): Graph on 10 vertices

480 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

An obviously infeasible set of parameters:

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

An set of parameters proved in a paper to be infeasible:

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>

A set of parameters unknown to be realizable in Andries Brouwer’s database:

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:

A large unknown set of parameters (not in Andries Brouwer’s database):

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.

Test the Claw bound (see 3.D of [BvL84]):

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:

2.1. Common Graphs 481


Sage Reference Manual: Graph Theory, Release 8.4

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.

sage: tree_iterator = graphs.trees(7)


sage: for T in tree_iterator:
....: print(T.degree_sequence())
[2, 2, 2, 2, 2, 1, 1]
[3, 2, 2, 2, 1, 1, 1]
[3, 2, 2, 2, 1, 1, 1]
[4, 2, 2, 1, 1, 1, 1]
[3, 3, 2, 1, 1, 1, 1]
[3, 3, 2, 1, 1, 1, 1]
[4, 3, 1, 1, 1, 1, 1]
[3, 2, 2, 2, 1, 1, 1]
[4, 2, 2, 1, 1, 1, 1]
[5, 2, 1, 1, 1, 1, 1]
[6, 1, 1, 1, 1, 1, 1]

The number of trees on the first few vertex counts. This is sequence A000055 in Sloane’s OEIS.

sage: [len(list(graphs.trees(i))) for i in range(0, 15)]


[1, 1, 1, 1, 2, 3, 6, 11, 23, 47, 106, 235, 551, 1301, 3159]

triangulations(order, minimum_degree=None, minimum_connectivity=None, ex-


act_connectivity=False, only_eulerian=False, dual=False)
An iterator over connected planar triangulations 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 triangulations.
• minimum_degree - default: None - a value ≥ 3 and ≤ 5, or None. This specifies the minimum
degree of the generated triangulations. 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 3.
• minimum_connectivity - default: None - a value ≥ 3 and ≤ 5, or None. This specifies the
minimum connectivity of the generated triangulations. 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 3.
• exact_connectivity - default: False - if True only triangulations with exactly the specified
connectivity will be generated. This option cannot be used with minimum_connectivity=3, or
if the minimum connectivity is not explicitely set.
• only_eulerian - default: False - if True only Eulerian triangulations will be generated. This
option cannot be used if the minimum degree is explicitely set to anything else than 4.
• dual - default: False - if True return instead the planar duals of the generated graphs.
OUTPUT:
An iterator which will produce all planar triangulations 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).

482 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

See also:

• set_embedding(), get_embedding() – get/set methods for embeddings.


• RandomTriangulation() – build a random triangulation.

EXAMPLES:
The unique planar embedding of the 𝐾4 is the only planar triangulations on 4 vertices:

sage: gen = graphs.triangulations(4) # optional plantri


sage: [g.get_embedding() for g in gen] # optional plantri
[{1: [2, 3, 4], 2: [1, 4, 3], 3: [1, 2, 4], 4: [1, 3, 2]}]

but, of course, this graph is not Eulerian:

sage: gen = graphs.triangulations(4, only_eulerian=True) # optional plantri


sage: len(list(gen)) # optional plantri
0

The unique Eulerian triangulation on 6 vertices is isomorphic to the octahedral graph.

sage: gen = graphs.triangulations(6, only_eulerian=True) # optional plantri


sage: g = next(gen) # optional plantri
sage: g.is_isomorphic(graphs.OctahedralGraph()) # optional plantri
True

An overview of the number of 5-connected triangulations on up to 22 vertices. This agrees with OEIS
sequence A081621:

sage: for i in range(12, 23): #


˓→optional plantri

....: L = len(list(graphs.triangulations(i, minimum_connectivity=5))) #


˓→optional plantri

....: print("{} {:3d}".format(i,L)) #


˓→optional plantri

12 1
13 0
14 1
15 1
16 3
17 4
18 12
19 23
20 71
21 187
22 627

The minimum connectivity can be at most the minimum degree:

sage: gen = next(graphs.triangulations(10, minimum_degree=3, minimum_


˓→connectivity=5)) # optional plantri
Traceback (most recent call last):
...
ValueError: Minimum connectivity can be at most the minimum degree.

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:

2.1. Common Graphs 483


Sage Reference Manual: Graph Theory, Release 8.4

sage: len([g for g in graphs.triangulations(9, minimum_degree=4, minimum_


˓→connectivity=3)]) # optional plantri

5
sage: len([g for g in graphs.triangulations(9, minimum_degree=4, minimum_
˓→connectivity=3, exact_connectivity=True)]) # optional plantri

Setting dual=True gives the planar dual graphs:

sage: [len(g) for g in graphs.triangulations(9, minimum_degree=4, minimum_


˓→connectivity=3, dual=True)] # optional plantri
[14, 14, 14, 14, 14]

sage.graphs.graph_generators.canaug_traverse_edge(g, aut_gens, property, dig=False,


loops=False, implementa-
tion=’c_graph’, sparse=True)
Main function for exhaustive generation. Recursive traversal of a canonically generated tree of isomorph free
graphs satisfying a given property.
INPUT:
• g - current position on the tree.
• aut_gens - list of generators of Aut(g), in list notation.
• property - check before traversing below g.
EXAMPLES:

sage: from sage.graphs.graph_generators import canaug_traverse_edge


sage: G = Graph(3)
sage: list(canaug_traverse_edge(G, [], lambda x: True))
[Graph on 3 vertices, ... Graph on 3 vertices]

The best way to access this function is through the graphs() iterator:
Print graphs on 3 or less vertices.

sage: for G in graphs(3):


....: print(G)
Graph on 3 vertices
Graph on 3 vertices
Graph on 3 vertices
Graph on 3 vertices

Print digraphs on 3 or less vertices.

sage: for G in digraphs(3):


....: print(G)
Digraph on 3 vertices
Digraph on 3 vertices
...
Digraph on 3 vertices
Digraph on 3 vertices

sage.graphs.graph_generators.canaug_traverse_vert(g, aut_gens, max_verts, property,


dig=False, loops=False, implemen-
tation=’c_graph’, sparse=True)
Main function for exhaustive generation. Recursive traversal of a canonically generated tree of isomorph free
(di)graphs satisfying a given property.

484 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: from sage.graphs.graph_generators import canaug_traverse_vert


sage: list(canaug_traverse_vert(Graph(), [], 3, lambda x: True))
[Graph on 0 vertices, ... Graph on 3 vertices]

The best way to access this function is through the graphs() iterator:
Print graphs on 3 or less vertices.

sage: for G in graphs(3, augment='vertices'):


....: print(G)
Graph on 0 vertices
Graph on 1 vertex
Graph on 2 vertices
Graph on 3 vertices
Graph on 3 vertices
Graph on 3 vertices
Graph on 2 vertices
Graph on 3 vertices

Print digraphs on 2 or less vertices.

sage: for D in digraphs(2, augment='vertices'):


....: print(D)
Digraph on 0 vertices
Digraph on 1 vertex
Digraph on 2 vertices
Digraph on 2 vertices
Digraph on 2 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:

sage: from sage.graphs.graph_generators import check_aut


sage: list( check_aut( [ [0, 3, 2, 1], [1, 0, 3, 2], [2, 1, 0, 3] ], 2, 3))
[[1, 0, 3, 2], [1, 2, 3, 0]]

sage.graphs.graph_generators.check_aut_edge(aut_gens, cut_edge, i, j, n, dig=False)


Helper function for exhaustive generation.

2.1. Common Graphs 485


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: from sage.graphs.graph_generators import check_aut


sage: list( check_aut( [ [0, 3, 2, 1], [1, 0, 3, 2], [2, 1, 0, 3] ], 2, 3))
[[1, 0, 3, 2], [1, 2, 3, 0]]

2.2 Common Digraphs

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)

To get a circulant graph on 10 vertices in which a vertex 𝑖 has 𝑖 + 2 and 𝑖 + 3 as outneighbors:

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.

ButterflyGraph() Returns a n-dimensional butterfly graph.


Circuit() Returns the circuit on 𝑛 vertices.
Circulant() Returns a circulant digraph on 𝑛 vertices from a set of integers.
Complete() Return a complete digraph on 𝑛 vertices.
DeBruijn() Returns the De Bruijn digraph with parameters 𝑘, 𝑛.
GeneralizedDeBruijn() Returns the generalized de Bruijn digraph of order 𝑛 and degree 𝑑.
ImaseItoh() Returns the digraph of Imase and Itoh of order 𝑛 and degree 𝑑.
Kautz() Returns the Kautz digraph of degree 𝑑 and diameter 𝐷.
Paley() Return a Paley digraph on 𝑞 vertices.
Path() Returns a directed path on 𝑛 vertices.
RandomDirectedGNC() Returns a random GNC (growing network with copying) digraph with 𝑛 ver-
tices.
RandomDirectedGNM() Returns a random labelled digraph on 𝑛 nodes and 𝑚 arcs.
RandomDirectedGNP() Returns a random digraph on 𝑛 nodes.
RandomDirectedGN() Returns a random GN (growing network) digraph with 𝑛 vertices.
RandomDirectedGNR() Returns a random GNR (growing network with redirection) digraph.
RandomSemiComplete() Return a random semi-complete digraph of order 𝑛.
RandomTournament() Returns a random tournament on 𝑛 vertices.
TransitiveTournament() Returns a transitive tournament on 𝑛 vertices.
tournaments_nauty() Returns all tournaments on 𝑛 vertices using Nauty.

AUTHORS:
• Robert L. Miller (2006)
• Emily A. Kirkman (2006)

486 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

• Michael C. Yurko (2009)


• David Coudert (2012)

2.2.1 Functions and methods

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:

Random Directed Graphs:


- RandomDirectedGN
- RandomDirectedGNC
- RandomDirectedGNP
- RandomDirectedGNM
- RandomDirectedGNR
- RandomTournament
- RandomSemiComplete

Families of Graphs:
- Complete
- DeBruijn
- GeneralizedDeBruijn
- Kautz
- Path
- ImaseItoh
- RandomTournament
- TransitiveTournament
- tournaments_nauty

ORDERLY GENERATION: digraphs(vertices, property=lambda x: True, augment=’edges’, size=None)


Accesses the generator of isomorphism class representatives. Iterates over distinct, exhaustive representatives.
INPUT:
• vertices - natural number or None to infinitely generate bigger and bigger digraphs.
• property - any property to be tested on digraphs before generation.
• augment - choices:
– 'vertices' - augments by adding a vertex, and edges incident to that vertex. In this case, all di-
graphs on up to n=vertices are generated. If for any digraph 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 digraphs with that property. If this does not hold, then all the digraphs
generated will satisfy the property, but there will be some missing.
– 'edges' - augments a fixed number of vertices by adding one edge In this case, all digraphs 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

2.2. Common Digraphs 487


Sage Reference Manual: Graph Theory, Release 8.4

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.

sage: for D in digraphs(2, augment='vertices'):


....: print(D)
Digraph on 0 vertices
Digraph on 1 vertex
Digraph on 2 vertices
Digraph on 2 vertices
Digraph on 2 vertices

Note that we can also get digraphs with underlying Cython implementation:

sage: for D in digraphs(2, augment='vertices', implementation='c_graph'):


....: print(D)
Digraph on 0 vertices
Digraph on 1 vertex
Digraph on 2 vertices
Digraph on 2 vertices
Digraph on 2 vertices

Print digraphs on 3 vertices.

sage: for D in digraphs(3):


....: print(D)
Digraph on 3 vertices
Digraph on 3 vertices
...
Digraph on 3 vertices
Digraph on 3 vertices

Generate all digraphs with 4 vertices and 3 edges.

sage: L = digraphs(4, size=3)


sage: len(list(L))
13

Generate all digraphs with 4 vertices and up to 3 edges.

sage: L = list(digraphs(4, lambda G: G.size() <= 3))


sage: len(L)
20
sage: graphs_list.show_graphs(L) # long time

Generate all digraphs with degree at most 2, up to 5 vertices.

sage: property = lambda G: ( max([G.degree(v) for v in G] + [0]) <= 2 )


sage: L = list(digraphs(5, property, augment='vertices'))
sage: len(L)
75

Generate digraphs on the fly: (see http://oeis.org/classic/A000273)

488 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

sage: for i in range(5):


....: print(len(list(digraphs(i))))
1
1
3
16
218

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)

2.2. Common Digraphs 489


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


(((1, 1), 1), ((1, 0), 2)),
(((1, 1), 1), ((1, 1), 2))]

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!

490 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: db = digraphs.DeBruijn(2, 2); db


De Bruijn digraph (k=2, n=2): Looped digraph on 4 vertices
sage: db.order(), db.size()
(4, 8)
sage: db.diameter()
2

Building a de Bruijn digraph on a different alphabet:

sage: g = digraphs.DeBruijn(['a', 'b'], 2)


sage: g.vertices()
['aa', 'ab', 'ba', 'bb']
sage: g.is_isomorphic(db)
True
sage: g = digraphs.DeBruijn(['AA', 'BB'], 2)
sage: g.vertices()
['AA,AA', 'AA,BB', 'BB,AA', 'BB,BB']
sage: g.is_isomorphic(db)
True

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

2.2. Common Digraphs 491


Sage Reference Manual: Graph Theory, Release 8.4

• d – is the degree of the digraph


See also:

• sage.graphs.generic_graph.GenericGraph.is_circulant() – checks whether a


(di)graph is circulant, and/or returns all possible sets of parameters.

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:

492 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

• k – Two possibilities for this parameter :


– An integer equal to the degree of the digraph to be produced, that is the cardinality minus one
of the alphabet to use.
– An iterable object to be used as the set of letters. The degree of the resulting digraph is the
cardinality of the set of letters minus one.
• D – An integer equal to the diameter of the digraph, and also to the length of a vertex label when
vertices == 'strings'.
• vertices – ‘strings’ (default) or ‘integers’, specifying whether the vertices are words build
upon an alphabet or integers.
EXAMPLES:

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',

˓→ 'aA,1', '1'), ('BB,aA', 'aA,BB', 'BB'), ('aA,1', '1,BB', 'BB'), ('aA,1',

˓→'1,aA', 'aA'), ('aA,BB', 'BB,1', '1'), ('aA,BB', 'BB,aA', 'aA')]

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:

• Wikipedia article Paley_graph


• PaleyGraph()

EXAMPLES:
A Paley digraph has 𝑛 * (𝑛 − 1)/2 edges, its underlying graph is a clique, and so it is a tournament:

2.2. Common Digraphs 493


Sage Reference Manual: Graph Theory, Release 8.4

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

A Paley digraph is always self-complementary:

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

RandomDirectedGN(n, kernel=<function <lambda>>, seed=None)


Returns a random GN (growing network) 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 default
attachment kernel is a linear function of degree. The digraph is always a tree, so in particular it is a directed
acyclic graph.
INPUT:
• n - number of vertices.
• kernel - the attachment kernel
• seed - for the random number generator
EXAMPLES:

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)]

sage: D.show() # long time

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.

494 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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)]

sage: D.show() # long time

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: D = digraphs.RandomDirectedGNM(10, 100, loops = True)


sage: D.num_verts()
10
sage: D.loops()
[(0, 0, None), (1, 1, None), (2, 2, None), (3, 3, None), (4, 4, None), (5, 5,
˓→None), (6, 6, None), (7, 7, None), (8, 8, None), (9, 9, None)]

2.2. Common Digraphs 495


Sage Reference Manual: Graph Theory, Release 8.4

RandomDirectedGNP(n, p, loops=False, seed=None)


Returns a random digraph on 𝑛 nodes. Each edge is inserted independently with probability 𝑝.
INPUT:
• n – number of nodes of the digraph
• p – probability of an edge
• loops – is a boolean set to True if the random digraph may have loops, and False (default) otherwise.
• seed – integer seed for random number generator (default=None).
REFERENCES:
PLOTTING: When plotting, this graph will use the default spring-layout algorithm, unless a position
dictionary is specified.
EXAMPLES:

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:

sage: D = digraphs.RandomDirectedGNR(25, .2)


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)]

sage: D.show() # long time

REFERENCE:
• [1] Krapivsky, P.L. and Redner, S. Organization of Growing Random Networks, Phys. Rev. E vol. 63
(2001), p. 066123.

496 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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:

• Wikipedia article Tournament_(graph_theory)


• is_tournament()

2.2. Common Digraphs 497


Sage Reference Manual: Graph Theory, Release 8.4

• 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:

• Wikipedia article Tournament_(graph_theory)


• is_tournament()
• is_transitive()
• RandomTournament()

tournaments_nauty(n, min_out_degree=None, max_out_degree=None, strongly_connected=False,


debug=False, options=”)
Returns all tournaments on 𝑛 vertices using Nauty.
INPUT:
• n (integer) – number of vertices.
• min_out_degree, max_out_degree (integers) – if set to None (default), then the min/max
out-degree is not constrained.
• debug (boolean) – if True the first line of genbg’s output to standard error is captured and the first
call to the generator’s next() function will return this line as a string. A line leading with “>A”
indicates a successful initiation of the program with some information on the arguments, while a line
beginning with “>E” indicates an error with the input.
• options (string) – anything else that should be forwarded as input to Nauty’s genbg. See its docu-
mentation for more information : http://cs.anu.edu.au/~bdm/nauty/.

Note: To use this method you must first install the Nauty spkg.

EXAMPLES:

498 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

sage: for g in digraphs.tournaments_nauty(4):


....: print(g.edges(labels = False))
[(1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2)]
[(1, 0), (1, 3), (2, 0), (2, 1), (3, 0), (3, 2)]
[(0, 2), (1, 0), (2, 1), (3, 0), (3, 1), (3, 2)]
[(0, 2), (0, 3), (1, 0), (2, 1), (3, 1), (3, 2)]
sage: tournaments = digraphs.tournaments_nauty
sage: [len(list(tournaments(x))) for x in range(1,8)]
[1, 1, 2, 4, 12, 56, 456]
sage: [len(list(tournaments(x, strongly_connected = True))) for x in range(1,
˓→9)]

[1, 0, 1, 1, 6, 35, 353, 6008]

2.3 Common graphs and digraphs generators (Cython)

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:

sage: from sage.graphs.graph_generators_pyx import RandomGNP


sage: set_random_seed(0)
sage: D = RandomGNP(10, .2, directed = True)
sage: D.num_verts()
10
sage: D.edges(labels=False)
[(0, 2), (0, 5), (1, 5), (1, 7), (4, 1), (4, 2), (4, 9), (5, 0), (5, 2), (5, 3),
˓→(5, 7), (6, 5), (7, 1), (8, 2), (8, 6), (9, 4)]

2.4 Graph database

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).

2.3. Common graphs and digraphs generators (Cython) 499


Sage Reference Manual: Graph Theory, Release 8.4

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.

See GraphDatabase class docstrings or enter:


sage: G = GraphDatabase()
sage: G.get_skeleton()
{...

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=(?)'

sage: param = (22,5)


sage: Q = SQLQuery(G,q,param)
sage: Q.show()
graph_id graph6 num_vertices num_edges
--------------------------------------------------------------------------------
(continues on next page)

500 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


18 D?? 5 0
19 D?C 5 1
20 D?K 5 2
21 D@O 5 2
22 D?[ 5 3

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)

2.4. Graph database 501


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


'sql': u'BOOLEAN',
'unique': False}},
u'degrees': {u'average_degree': {'index': True,
'primary_key': False,
'sql': u'REAL',
'unique': False},
u'degree_sequence': {'index': False,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
u'degrees_sd': {'index': True,
'primary_key': False,
'sql': u'REAL',
'unique': False},
u'graph_id': {'index': False,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
u'max_degree': {'index': True,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
u'min_degree': {'index': True,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
u'regular': {'index': True,
'primary_key': False,
'sql': u'BOOLEAN',
'unique': False}},
u'graph_data': {u'complement_graph6': {'index': True,
'primary_key': False,
'sql': u'TEXT',
'unique': False},
u'eulerian': {'index': True,
'primary_key': False,
'sql': u'BOOLEAN',
'unique': False},
u'graph6': {'index': True,
'primary_key': False,
'sql': u'TEXT',
'unique': False},
u'graph_id': {'index': True,
'primary_key': False,
'sql': u'INTEGER',
'unique': True},
u'lovasz_number': {'index': True,
'primary_key': False,
'sql': u'REAL',
'unique': False},
u'num_cycles': {'index': True,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
u'num_edges': {'index': True,
'primary_key': False,
'sql': u'INTEGER',
(continues on next page)

502 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


'unique': False},
u'num_hamiltonian_cycles': {'index': True,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
u'num_vertices': {'index': True,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
u'perfect': {'index': True,
'primary_key': False,
'sql': u'BOOLEAN',
'unique': False},
u'planar': {'index': True,
'primary_key': False,
'sql': u'BOOLEAN',
'unique': False}},
u'misc': {u'clique_number': {'index': True,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
u'diameter': {'index': True,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
u'edge_connectivity': {'index': True,
'primary_key': False,
'sql': u'BOOLEAN',
'unique': False},
u'girth': {'index': True,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
u'graph_id': {'index': False,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
u'independence_number': {'index': True,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
u'induced_subgraphs': {'index': True,
'primary_key': False,
'sql': u'TEXT',
'unique': False},
u'min_vertex_cover_size': {'index': True,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
u'num_components': {'index': True,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
u'num_cut_vertices': {'index': True,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
(continues on next page)

2.4. Graph database 503


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


u'num_spanning_trees': {'index': True,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
u'radius': {'index': True,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
u'vertex_connectivity': {'index': True,
'primary_key': False,
'sql': u'BOOLEAN',
'unique': False}},
u'spectrum': {u'eigenvalues_sd': {'index': True,
'primary_key': False,
'sql': u'REAL',
'unique': False},
u'energy': {'index': True,
'primary_key': False,
'sql': u'REAL',
'unique': False},
u'graph_id': {'index': False,
'primary_key': False,
'sql': u'INTEGER',
'unique': False},
u'max_eigenvalue': {'index': True,
'primary_key': False,
'sql': u'REAL',
'unique': False},
u'min_eigenvalue': {'index': True,
'primary_key': False,
'sql': u'REAL',
'unique': False},
u'spectrum': {'index': False,
'primary_key': False,
'sql': u'TEXT',
'unique': False}}}

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>

query(query_dict=None, display_cols=None, **kwds)


Creates a GraphQuery on this database. For full class details, type GraphQuery? and press shift+enter.
EXAMPLES:

504 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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)

2.4. Graph database 505


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


E?Kw 6 [0, 0, 2, 2, 3, 3]
E?LO 6 [0, 1, 1, 2, 2, 2]
E?LW 6 [0, 1, 1, 2, 3, 3]
E?N? 6 [1, 1, 1, 1, 2, 2]
E?NG 6 [1, 1, 1, 1, 3, 3]
E@FG 6 [1, 1, 1, 2, 2, 3]
E@HW 6 [0, 1, 2, 2, 2, 3]
E@N? 6 [1, 1, 2, 2, 2, 2]
E@Ow 6 [0, 1, 2, 2, 2, 3]
E@Q? 6 [1, 1, 1, 1, 1, 1]
E@QW 6 [1, 1, 1, 2, 2, 3]
E@T_ 6 [0, 2, 2, 2, 2, 2]
E@YO 6 [1, 1, 2, 2, 2, 2]
EG?W 6 [0, 1, 1, 1, 1, 2]
EGCW 6 [0, 1, 1, 2, 2, 2]
E_?w 6 [1, 1, 1, 1, 1, 3]
E_Cg 6 [1, 1, 1, 1, 2, 2]
E_Cw 6 [1, 1, 1, 2, 2, 3]
E_Ko 6 [1, 1, 2, 2, 2, 2]
F???? 7 [0, 0, 0, 0, 0, 0, 0]
F???G 7 [0, 0, 0, 0, 0, 1, 1]
F???W 7 [0, 0, 0, 0, 1, 1, 2]
F???w 7 [0, 0, 0, 1, 1, 1, 3]
F??@w 7 [0, 0, 1, 1, 1, 1, 4]
F??Bw 7 [0, 1, 1, 1, 1, 1, 5]
F??GW 7 [0, 0, 0, 0, 2, 2, 2]
F??G_ 7 [0, 0, 0, 1, 1, 1, 1]
F??Gg 7 [0, 0, 0, 1, 1, 2, 2]
F??Gw 7 [0, 0, 0, 1, 2, 2, 3]
F??Hg 7 [0, 0, 1, 1, 1, 2, 3]
F??Hw 7 [0, 0, 1, 1, 2, 2, 4]
F??Jg 7 [0, 1, 1, 1, 1, 2, 4]
F??Wo 7 [0, 0, 0, 2, 2, 2, 2]
F??Ww 7 [0, 0, 0, 2, 2, 3, 3]
F??XO 7 [0, 0, 1, 1, 2, 2, 2]
F??XW 7 [0, 0, 1, 1, 2, 3, 3]
F??Z? 7 [0, 1, 1, 1, 1, 2, 2]
F??ZG 7 [0, 1, 1, 1, 1, 3, 3]
F??^? 7 [1, 1, 1, 1, 1, 2, 3]
F?CJG 7 [0, 1, 1, 1, 2, 2, 3]
F?CPW 7 [0, 0, 1, 2, 2, 2, 3]
F?CZ? 7 [0, 1, 1, 2, 2, 2, 2]
F?C_w 7 [0, 0, 1, 2, 2, 2, 3]
F?Ca? 7 [0, 1, 1, 1, 1, 1, 1]
F?CaW 7 [0, 1, 1, 1, 2, 2, 3]
F?Ch_ 7 [0, 0, 2, 2, 2, 2, 2]
F?CqO 7 [0, 1, 1, 2, 2, 2, 2]
F?LCG 7 [1, 1, 1, 1, 2, 2, 2]
F@??W 7 [0, 0, 1, 1, 1, 1, 2]
F@?GW 7 [0, 0, 1, 1, 2, 2, 2]
FG??w 7 [0, 1, 1, 1, 1, 1, 3]
FG?Gg 7 [0, 1, 1, 1, 1, 2, 2]
FG?Gw 7 [0, 1, 1, 1, 2, 2, 3]
FG?Wo 7 [0, 1, 1, 2, 2, 2, 2]
FK??W 7 [1, 1, 1, 1, 1, 1, 2]
FK?GW 7 [1, 1, 1, 1, 2, 2, 2]
F_?@w 7 [1, 1, 1, 1, 1, 1, 4]
(continues on next page)

506 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


F_?Hg 7 [1, 1, 1, 1, 1, 2, 3]
F_?XO 7 [1, 1, 1, 1, 2, 2, 2]

class sage.graphs.graph_database.GraphQuery(graph_db=None, query_dict=None, dis-


play_cols=None, **kwds)
Bases: sage.graphs.graph_database.GenericGraphQuery
A query for an instance of GraphDatabase. This class nicely wraps the SQLQuery class located in
sage.databases.database.py to make the query constraints intuitive and with as many pre-definitions as possi-
ble. (i.e.: since it has to be a GraphDatabase, we already know the table structure and types; and since it is
immutable, we can treat these as a guarantee).

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)

2.4. Graph database 507


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


D_K 5 [1, 1, 1, 1, 2]
D`K 5 [1, 1, 2, 2, 2]
E?Bw 6 [1, 1, 1, 1, 1, 5]
E?Fg 6 [1, 1, 1, 1, 2, 4]
E?N? 6 [1, 1, 1, 1, 2, 2]
E?NG 6 [1, 1, 1, 1, 3, 3]
E@FG 6 [1, 1, 1, 2, 2, 3]
E@N? 6 [1, 1, 2, 2, 2, 2]
E@Q? 6 [1, 1, 1, 1, 1, 1]
E@QW 6 [1, 1, 1, 2, 2, 3]
E@YO 6 [1, 1, 2, 2, 2, 2]
E_?w 6 [1, 1, 1, 1, 1, 3]
E_Cg 6 [1, 1, 1, 1, 2, 2]
E_Cw 6 [1, 1, 1, 2, 2, 3]
E_Ko 6 [1, 1, 2, 2, 2, 2]
F??^? 7 [1, 1, 1, 1, 1, 2, 3]
F?LCG 7 [1, 1, 1, 1, 2, 2, 2]
FK??W 7 [1, 1, 1, 1, 1, 1, 2]
FK?GW 7 [1, 1, 1, 1, 2, 2, 2]
F_?@w 7 [1, 1, 1, 1, 1, 1, 4]
F_?Hg 7 [1, 1, 1, 1, 1, 2, 3]
F_?XO 7 [1, 1, 1, 1, 2, 2, 2]

get_graphs_list()
Return a list of Sage Graph objects that satisfy the query.
EXAMPLES:

sage: 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:

sage: Q = GraphQuery(display_cols=['graph6'],num_vertices=7, diameter=5)


sage: for g in Q:
....: print(g.graph6_string())
F?`po
F?gqg
F@?]O
(continues on next page)

508 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


F@OKg
F@R@o
FA_pW
FEOhW
FGC{o
FIAHo
sage: Q = GraphQuery(display_cols=['graph6'],num_vertices=7, diameter=5)
sage: it = iter(Q)
sage: while True:
....: try: print(next(it).graph6_string())
....: except StopIteration: break
F?`po
F?gqg
F@?]O
F@OKg
F@R@o
FA_pW
FEOhW
FGC{o
FIAHo

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 = GraphQuery(G, display_cols=['graph6','num_vertices','degree_sequence


˓→'], num_vertices=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]

2.4. Graph database 509


Sage Reference Manual: Graph Theory, Release 8.4

Show the pictures (in notebook mode only):

sage: S = GraphQuery(G, display_cols=['graph6','aut_grp_size'], num_


˓→vertices=4)

sage: S.show(with_picture=True)
Traceback (most recent call last):
...
NotImplementedError: Cannot display plot on command line.

Note that pictures can be turned off:

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):

sage: (GenericGraphQuery('select degree_sequence from degrees where max_


˓→degree=2 and min_degree >= 1',G)).show()

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)

510 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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: from sage.graphs.graph_database import data_to_degseq


sage: data_to_degseq(3221)
[1, 2, 2, 3]
sage: data_to_degseq(0,'D??')
[0, 0, 0, 0, 0]

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: from sage.graphs.graph_database import degseq_to_data


sage: degseq_to_data([2,2,3,1])
3221

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: from sage.graphs.graph_database import graph6_to_plot


sage: type(graph6_to_plot('D??'))
<class 'sage.plot.graphics.Graphics'>

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:

2.4. Graph database 511


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: from sage.graphs.graph_database import subgraphs_to_query


sage: gd = GraphDatabase()
sage: q = subgraphs_to_query(['all_of','A?','B?','C?'],gd)
sage: q.get_query_string()
'SELECT ,,,,, FROM misc WHERE ( ( misc.induced_subgraphs regexp ? ) AND (
misc.induced_subgraphs regexp ? ) ) AND ( misc.induced_subgraphs regexp ? )'

2.5 Database of strongly regular graphs

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:

sage: from sage.graphs.strongly_regular_db import SRG_100_44_18_20


sage: G = SRG_100_44_18_20() # long time
sage: G.is_strongly_regular(parameters=True) # long time
(100, 44, 18, 20)

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:

512 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.strongly_regular_db import SRG_100_45_20_20


sage: G = SRG_100_45_20_20() # long time
sage: G.is_strongly_regular(parameters=True) # long time
(100, 45, 20, 20)

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:

sage: from sage.graphs.strongly_regular_db import SRG_105_32_4_12


sage: G = SRG_105_32_4_12(); G
Aut L(3,4) on flags: Graph on 105 vertices
sage: G.is_strongly_regular(parameters=True)
(105, 32, 4, 12)

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: from sage.graphs.strongly_regular_db import SRG_120_63_30_36


sage: G = SRG_120_63_30_36()
sage: G.is_strongly_regular(parameters=True)
(120, 63, 30, 36)

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: from sage.graphs.strongly_regular_db import SRG_120_77_52_44


sage: G = SRG_120_77_52_44() # optional - gap_packages
sage: G.is_strongly_regular(parameters=True) # optional - gap_packages
(120, 77, 52, 44)

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: from sage.graphs.strongly_regular_db import SRG_126_25_8_4


sage: G = SRG_126_25_8_4()
sage: G.is_strongly_regular(parameters=True)
(126, 25, 8, 4)

sage.graphs.strongly_regular_db.SRG_126_50_13_24()
Return a (126, 50, 13, 24)-strongly regular graph

2.5. Database of strongly regular graphs 513


Sage Reference Manual: Graph Theory, Release 8.4

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: from sage.graphs.strongly_regular_db import SRG_126_50_13_24


sage: G = SRG_126_50_13_24(); G
Goethals graph: Graph on 126 vertices
sage: G.is_strongly_regular(parameters=True)
(126, 50, 13, 24)

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:

sage: from sage.graphs.strongly_regular_db import SRG_1288_792_476_504


sage: G = SRG_1288_792_476_504() # long time
sage: G.is_strongly_regular(parameters=True) # long time
(1288, 792, 476, 504)

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: from sage.graphs.strongly_regular_db import SRG_144_39_6_12


sage: G = SRG_144_39_6_12()
sage: G.is_strongly_regular(parameters=True)
(144, 39, 6, 12)

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: from sage.graphs.strongly_regular_db import SRG_175_72_20_36


sage: G = SRG_175_72_20_36()
sage: G.is_strongly_regular(parameters=True)
(175, 72, 20, 36)

sage.graphs.strongly_regular_db.SRG_176_105_68_54()
Return a (176, 105, 68, 54)-strongly regular graph.

514 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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: from sage.graphs.strongly_regular_db import SRG_176_105_68_54


sage: G = SRG_176_105_68_54() # optional - gap_packages
sage: G.is_strongly_regular(parameters=True) # optional - gap_packages
(176, 105, 68, 54)

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:

sage: from sage.graphs.strongly_regular_db import SRG_176_49_12_14


sage: G = SRG_176_49_12_14() # optional - gap_packages # long time
sage: G.is_strongly_regular(parameters=True) # optional - gap_packages # long time
(176, 49, 12, 14)

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: from sage.graphs.strongly_regular_db import SRG_176_90_38_54


sage: G = SRG_176_90_38_54()
sage: G.is_strongly_regular(parameters=True)
(176, 90, 38, 54)

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:

sage: from sage.graphs.strongly_regular_db import SRG_196_91_42_42


sage: G = SRG_196_91_42_42()
sage: G.is_strongly_regular(parameters=True)
(196, 91, 42, 42)

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.

2.5. Database of strongly regular graphs 515


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: from sage.graphs.strongly_regular_db import SRG_210_99_48_45


sage: g=SRG_210_99_48_45()
sage: g.is_strongly_regular(parameters=True)
(210, 99, 48, 45)

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: from sage.graphs.strongly_regular_db import SRG_220_84_38_28


sage: g=SRG_220_84_38_28()
sage: g.is_strongly_regular(parameters=True)
(220, 84, 38, 28)

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:

sage: from sage.graphs.strongly_regular_db import SRG_243_110_37_60


sage: G = SRG_243_110_37_60()
sage: G.is_strongly_regular(parameters=True)
(243, 110, 37, 60)

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: from sage.graphs.strongly_regular_db import SRG_253_140_87_65


sage: G = SRG_253_140_87_65() # optional - gap_packages
sage: G.is_strongly_regular(parameters=True) # optional - gap_packages
(253, 140, 87, 65)

sage.graphs.strongly_regular_db.SRG_276_140_58_84()
Return a (276, 140, 58, 84)-strongly regular graph.

516 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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).

2.5. Database of strongly regular graphs 517


Sage Reference Manual: Graph Theory, Release 8.4

EXAMPLES:

sage: from sage.graphs.strongly_regular_db import SRG_560_208_72_80


sage: g = SRG_560_208_72_80() # optional - database_gap # not
˓→tested (~2s)

sage: g.is_strongly_regular(parameters=True) # optional - database_gap # not


˓→tested (~2s)

(560, 208, 72, 80)

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:

sage: from sage.graphs.strongly_regular_db import SRG_630_85_20_10


sage: G = SRG_630_85_20_10() # long time
sage: G.is_strongly_regular(parameters=True) # long time
(630, 85, 20, 10)

sage.graphs.strongly_regular_db.SRG_from_RSHCD(v, k, l, mu, existence=False,


check=True)
Return a (𝑣, 𝑘, 𝑙, 𝑚𝑢)-strongly regular graph from a RSHCD
This construction appears in 8.D of [BvL84]. For more information, see
regular_symmetric_hadamard_matrix_with_constant_diagonal().
INPUT:
• v,k,l,mu (integers)
• existence (boolean) – whether to return a graph or to test if Sage can build such a graph.
• 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 graphs

sage: from sage.graphs.strongly_regular_db import SRG_from_RSHCD


sage: SRG_from_RSHCD(784, 0, 14, 38, existence=True)
False
sage: SRG_from_RSHCD(784, 377, 180, 182, existence=True)
True
sage: SRG_from_RSHCD(144, 65, 28, 30)
Graph on 144 vertices

an example with vertex-transitive automorphism group, found during the implementation of the case 𝑣 = 324

sage: G=SRG_from_RSHCD(324,152,70,72) # long time


sage: a=G.automorphism_group() # long time
sage: a.order() # long time
2592
sage: len(a.orbits()) # long time
1

518 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: from sage.graphs.strongly_regular_db import apparently_feasible_parameters


sage: small_feasible = apparently_feasible_parameters(20); small_feasible
{(5, 2, 0, 1),
(9, 4, 1, 2),
(10, 3, 0, 1),
(10, 6, 3, 4),
(13, 6, 2, 3),
(15, 6, 1, 3),
(15, 8, 4, 4),
(16, 5, 0, 2),
(16, 6, 2, 2),
(16, 9, 4, 6),
(16, 10, 6, 6),
(17, 8, 3, 4)}
sage: all(graphs.strongly_regular_graph(*x,existence=True) for x in small_
˓→feasible)

True

But that becomes wrong for 𝑣 < 60 (because of the non-existence of a (49, 16, 3, 6)-strongly regular graph):

sage: small_feasible = apparently_feasible_parameters(60)


sage: all(graphs.strongly_regular_graph(*x,existence=True) for x in small_
˓→feasible)

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:

2.5. Database of strongly regular graphs 519


Sage Reference Manual: Graph Theory, Release 8.4

• 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]

The line graph of 𝐾3,3 is self-dual:


sage: P=eigenmatrix(9,4,1,2); P
[ 1 4 4]
[ 1 1 -2]
[ 1 -2 1]
sage: 9*P^-1
[ 1 4 4]
[ 1 1 -2]
[ 1 -2 1]

A strongly regular graph with a non-isomorphic dual coming from another strongly regular graph:
sage: graphs.strongly_regular_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)

520 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


(<function AhrensSzekeresGeneralizedQuadrangleGraph at ...>, 3, False)
sage: g = t[0](*t[1:]); g
AS(3); GQ(2, 4): Graph on 27 vertices
sage: t = is_GQqmqp(45,12,3,3); t
(<function AhrensSzekeresGeneralizedQuadrangleGraph at ...>, 3, True)
sage: g = t[0](*t[1:]); g
AS(3)*; GQ(4, 2): Graph on 45 vertices
sage: g.is_strongly_regular(parameters=True)
(45, 12, 3, 3)
sage: t = is_GQqmqp(16,6,2,2); t
(<function T2starGeneralizedQuadrangleGraph at ...>, 2, True)
sage: g = t[0](*t[1:]); g
T2*(O,2)*; GQ(3, 1): Graph on 16 vertices
sage: g.is_strongly_regular(parameters=True)
(16, 6, 2, 2)
sage: t = is_GQqmqp(64,18,2,6); t
(<function T2starGeneralizedQuadrangleGraph at ...>, 4, False)
sage: g = t[0](*t[1:]); g
T2*(O,4); GQ(3, 5): Graph on 64 vertices
sage: g.is_strongly_regular(parameters=True)
(64, 18, 2, 6)

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: from sage.graphs.strongly_regular_db import is_NO_F2


sage: t = is_NO_F2(10, 3, 0, 1); t
(<function NonisotropicOrthogonalPolarGraph at ...>, 4, 2, '-')
sage: g = t[0](*t[1:]); g
NO^-(4, 2): Graph on 10 vertices
sage: g.is_strongly_regular(parameters=True)
(10, 3, 0, 1)

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:

2.5. Database of strongly regular graphs 521


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.strongly_regular_db import is_NO_F3


sage: t = is_NO_F3(15, 6, 1, 3); t
(<function NonisotropicOrthogonalPolarGraph at ...>, 4, 3, '-')
sage: g = t[0](*t[1:]); g
NO^-(4, 3): Graph on 15 vertices
sage: g.is_strongly_regular(parameters=True)
(15, 6, 1, 3)

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: from sage.graphs.strongly_regular_db import is_NOodd


sage: t = is_NOodd(120, 51, 18, 24); t
(<function NonisotropicOrthogonalPolarGraph at ...>, 5, 4, '-')
sage: g = t[0](*t[1:]); g
NO^-(5, 4): Graph on 120 vertices
sage: g.is_strongly_regular(parameters=True)
(120, 51, 18, 24)

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: from sage.graphs.strongly_regular_db import is_NOperp_F5


sage: t = is_NOperp_F5(10, 3, 0, 1); t
(<function NonisotropicOrthogonalPolarGraph at ...>, 3, 5, '-', 1)
sage: g = t[0](*t[1:]); g
NO^-,perp(3, 5): Graph on 10 vertices
sage: g.is_strongly_regular(parameters=True)
(10, 3, 0, 1)

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].

522 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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_NU


sage: t = is_NU(40, 27, 18, 18); t
(<function NonisotropicUnitaryPolarGraph at ...>, 4, 2)
sage: g = t[0](*t[1:]); g
NU(4, 2): Graph on 40 vertices
sage: g.is_strongly_regular(parameters=True)
(40, 27, 18, 18)

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: from sage.graphs.strongly_regular_db import is_RSHCD


sage: t = is_RSHCD(64,27,10,12); t
[<built-in function SRG_from_RSHCD>, 64, 27, 10, 12]
sage: g = t[0](*t[1:]); g
Graph on 64 vertices
sage: g.is_strongly_regular(parameters=True)
(64, 27, 10, 12)

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: from sage.graphs.strongly_regular_db import is_affine_polar


sage: t = is_affine_polar(81,32,13,12); t
(..., 4, 3)
sage: g = t[0](*t[1:]); g
Affine Polar Graph VO^+(4,3): Graph on 81 vertices
sage: g.is_strongly_regular(parameters=True)
(81, 32, 13, 12)
(continues on next page)

2.5. Database of strongly regular graphs 523


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)

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: from sage.graphs.strongly_regular_db import is_complete_multipartite


sage: t = is_complete_multipartite(12,8,4,8); t
(<cyfunction is_complete_multipartite.<locals>.CompleteMultipartiteSRG at ...>,
3,
4)
sage: g = t[0](*t[1:]); g
Multipartite Graph with set sizes [4, 4, 4]: Graph on 12 vertices
sage: g.is_strongly_regular(parameters=True)
(12, 8, 4, 8)

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: from sage.graphs.strongly_regular_db import is_cossidente_penttila


sage: t = is_cossidente_penttila(378, 52, 1, 8); t
(<function CossidentePenttilaGraph at ...>, 5)
sage: g = t[0](*t[1:]); g # optional - gap_packages
CossidentePenttila(5): Graph on 378 vertices
sage: g.is_strongly_regular(parameters=True) # optional - gap_packages
(378, 52, 1, 8)

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:

524 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.strongly_regular_db import is_goethals_seidel


sage: t = is_goethals_seidel(28, 15, 6, 10); t
[<function GoethalsSeidelGraph at ...>, 3, 3]
sage: g = t[0](*t[1:]); g
Graph on 28 vertices
sage: g.is_strongly_regular(parameters=True)
(28, 15, 6, 10)

sage: t = is_goethals_seidel(256, 135, 70, 72); t


[<function GoethalsSeidelGraph at ...>, 2, 15]
sage: g = t[0](*t[1:]); g
Graph on 256 vertices
sage: g.is_strongly_regular(parameters=True)
(256, 135, 70, 72)

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: from sage.graphs.strongly_regular_db import is_haemers


sage: t = is_haemers(96, 19, 2, 4); t
(<function HaemersGraph at ...>, 4)
sage: g = t[0](*t[1:]); g
Haemers(4): Graph on 96 vertices
sage: g.is_strongly_regular(parameters=True)
(96, 19, 2, 4)

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: from sage.graphs.strongly_regular_db import is_johnson


sage: t = is_johnson(10,6,3,4); t
(..., 5)
sage: g = t[0](*t[1:]); g
Johnson graph with parameters 5,2: Graph on 10 vertices
sage: g.is_strongly_regular(parameters=True)
(10, 6, 3, 4)
(continues on next page)

2.5. Database of strongly regular graphs 525


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)

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: from sage.graphs.strongly_regular_db import is_mathon_PC_srg


sage: t = is_mathon_PC_srg(45,22,10,11); t
(..., 1)
sage: g = t[0](*t[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.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: from sage.graphs.strongly_regular_db import is_muzychuk_S6


sage: t = is_muzychuk_S6(378, 116, 34, 36)
sage: G = t[0](*t[1:]); G
Muzychuk S6 graph with parameters (3,3): Graph on 378 vertices
sage: G.is_strongly_regular(parameters=True)
(378, 116, 34, 36)
sage: t = is_muzychuk_S6(5, 5, 5, 5); t

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:

526 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

• 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_graph(196, 60, 14, 20)


Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices

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: from sage.graphs.strongly_regular_db import is_orthogonal_array_block_graph


sage: t = is_orthogonal_array_block_graph(64, 35, 18, 20); t
(..., 5, 8)
sage: g = t[0](*t[1:]); g
OA(5,8): Graph on 64 vertices
sage: g.is_strongly_regular(parameters=True)
(64, 35, 18, 20)
sage: t=is_orthogonal_array_block_graph(225,98,43,42); t
(..., 4)
sage: g = t[0](*t[1:]); g
Pasechnik Graph_4: Graph on 225 vertices
sage: g.is_strongly_regular(parameters=True)
(225, 98, 43, 42)
sage: t=is_orthogonal_array_block_graph(225,112,55,56); t
(..., 4)
sage: g = t[0](*t[1:]); g
skewhad^2_4: Graph on 225 vertices
sage: g.is_strongly_regular(parameters=True)
(225, 112, 55, 56)

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:

2.5. Database of strongly regular graphs 527


Sage Reference Manual: Graph Theory, Release 8.4

• 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_orthogonal_polar


sage: t = is_orthogonal_polar(85, 20, 3, 5); t
(<function OrthogonalPolarGraph at ...>, 5, 4, '')
sage: g = t[0](*t[1:]); g
Orthogonal Polar Graph O(5, 4): Graph on 85 vertices
sage: g.is_strongly_regular(parameters=True)
(85, 20, 3, 5)

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: from sage.graphs.strongly_regular_db import is_paley


sage: t = is_paley(13,6,2,3); t
(..., 13)
sage: g = t[0](*t[1:]); g
Paley graph with parameter 13: Graph on 13 vertices
sage: g.is_strongly_regular(parameters=True)
(13, 6, 2, 3)
sage: t = is_paley(5,5,5,5); t

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:

528 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.strongly_regular_db import is_polhill


sage: t = is_polhill(1024, 231, 38, 56); t
[<cyfunction is_polhill.<locals>.<lambda> at ...>]
sage: g = t[0](*t[1:]); g # not tested (too long)
Graph on 1024 vertices
sage: g.is_strongly_regular(parameters=True) # not tested (too long)
(1024, 231, 38, 56)
sage: t = is_polhill(1024, 264, 56, 72); t
[<cyfunction is_polhill.<locals>.<lambda> at ...>]
sage: t = is_polhill(1024, 297, 76, 90); t
[<cyfunction is_polhill.<locals>.<lambda> at ...>]
sage: t = is_polhill(1024, 330, 98, 110); t
[<cyfunction is_polhill.<locals>.<lambda> at ...>]
sage: t = is_polhill(1024, 462, 206, 210); t
[<cyfunction is_polhill.<locals>.<lambda> at ...>]

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: from sage.graphs.strongly_regular_db import is_steiner


sage: t = is_steiner(26,15,8,9); t
(..., 13, 3)
sage: g = t[0](*t[1:]); g
Intersection Graph: Graph on 26 vertices
sage: g.is_strongly_regular(parameters=True)
(26, 15, 8, 9)

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_graph(170, 78, 35, 36) # indirect doctest


Graph on 170 vertices

2.5. Database of strongly regular graphs 529


Sage Reference Manual: Graph Theory, Release 8.4

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_graph(226, 105, 48, 49)


switch skewhad^2+*_4: Graph on 226 vertices

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:

sage: from sage.graphs.strongly_regular_db import is_taylor_twograph_srg


sage: t = is_taylor_twograph_srg(28, 15, 6, 10); t
(<function TaylorTwographSRG at ...>, 3)
sage: g = t[0](*t[1:]); g
Taylor two-graph SRG: Graph on 28 vertices
sage: g.is_strongly_regular(parameters=True)
(28, 15, 6, 10)
sage: t = is_taylor_twograph_srg(5,5,5,5); t

sage.graphs.strongly_regular_db.is_twograph_descendant_of_srg(v, k0, l, mu)


Test whether some descendant graph of a s.r.g. is (𝑣, 𝑘0 , 𝜆, 𝜇)-s.r.g.
We check whether there can exist (𝑣 + 1, 𝑘, 𝜆* , 𝜇* )-s.r.g. 𝐺 so that self is a descendant graph of the regular
two-graph specified by 𝐺. Specifically, we must have that 𝑣 + 1 = 2(2𝑘 − 𝜆* − 𝜇* ), and 𝑘0 = 2(𝑘 − 𝜇* ),
𝜆 = 𝑘 +𝜆* −2𝜇* , 𝜇 = 𝑘 −𝜇* , which give 2 independent linear conditions, say 𝑘 −𝜇* = 𝜇 and 𝜆* −𝜇* = 𝜆−𝜇.
Further, there is a quadratic relation 2𝑘 2 − (𝑣 + 1 + 4𝜇)𝑘 + 2𝑣𝜇 = 0.
If we can construct such 𝐺 then we return a function to build a (𝑣, 𝑘0 , 𝜆, 𝜇)-s.r.g. For more information, see
10.3 in https://www.win.tue.nl/~aeb/2WF02/spectra.pdf
INPUT:
• v,k0,l,mu (integers)
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists and is known, and None other-
wise.

530 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

EXAMPLES:

sage: from sage.graphs.strongly_regular_db import is_twograph_descendant_of_srg


sage: t = is_twograph_descendant_of_srg(27, 10, 1, 5); t
(<cyfunction is_twograph_descendant_of_srg.<locals>.la at...
sage: g = t[0](*t[1:]); g
descendant of complement(Johnson graph with parameters 8,2) at {5, 7}: Graph on
˓→27 vertices

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: from sage.graphs.strongly_regular_db import is_unitary_dual_polar


sage: t = is_unitary_dual_polar(297, 40, 7, 5); t
(<function UnitaryDualPolarGraph at ...>, 5, 2)
sage: g = t[0](*t[1:]); g
Unitary Dual Polar Graph DU(5, 2); GQ(8, 4): Graph on 297 vertices
sage: g.is_strongly_regular(parameters=True)
(297, 40, 7, 5)
sage: t = is_unitary_dual_polar(5,5,5,5); t

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: from sage.graphs.strongly_regular_db import is_unitary_polar


sage: t = is_unitary_polar(45, 12, 3, 3); t
(<function UnitaryPolarGraph at ...>, 4, 2)
sage: g = t[0](*t[1:]); g
Unitary Polar Graph U(4, 2); GQ(4, 2): Graph on 45 vertices
sage: g.is_strongly_regular(parameters=True)
(45, 12, 3, 3)

sage: t = is_unitary_polar(5,5,5,5); t

2.5. Database of strongly regular graphs 531


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: from sage.graphs.strongly_regular_db import strongly_regular_from_two_


˓→intersection_set

sage: S = Matrix([(0,0,1),(0,1,0)] + [(1,x^2,x) for x in GF(4,'b')])


sage: g = strongly_regular_from_two_intersection_set(S); g
two-intersection set in PG(3,4): Graph on 64 vertices
sage: g.is_strongly_regular(parameters=True)
(64, 18, 2, 6)

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:

532 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.strongly_regular_db import strongly_regular_from_two_


˓→weight_code

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

Now without specifying 𝜇:

sage: graphs.strongly_regular_graph(10,3,0)
complement(Johnson graph with parameters 5,2): Graph on 10 vertices

An obviously infeasible set of parameters:

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

An set of parameters proved in a paper to be infeasible:

2.5. Database of strongly regular graphs 533


Sage Reference Manual: Graph Theory, Release 8.4

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>

A set of parameters unknown to be realizable in Andries Brouwer’s database:

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:

A large unknown set of parameters (not in Andries Brouwer’s database):

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.

Test the Claw bound (see 3.D of [BvL84]):

sage: graphs.strongly_regular_graph(2058,242,91,20,existence=True)
False

2.6 ISGCI: Information System on Graph Classes and their Inclusions

This module implements an interface to the ISGCI database in Sage.


This database gathers information on graph classes and their inclusions in each other. It also contains information on
the complexity of several computational problems.
It is available on the GraphClasses.org website maintained by H.N. de Ridder et al.

2.6.1 How to use it?

Presently, it is possible to use this database through the variables and methods present in the graph_classes object.
For instance:

sage: Trees = graph_classes.Tree


sage: Chordal = graph_classes.Chordal

534 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

Inclusions

It is then possible to check the inclusion of classes inside of others, if the information is available in the database:

sage: Trees <= Chordal


True

And indeed, trees are chordal graphs.


The ISGCI database is not all-knowing, and so comparing two classes can return True, False, or Unknown (see
the documentation of the Unknown truth value).
An unknown answer to A <= B only means that ISGCI cannot deduce from the information in its database that A is
a subclass of B nor that it is not. For instance, ISGCI does not know at the moment that some chordal graphs are not
trees:

sage: graph_classes.Chordal <= graph_classes.Tree


Unknown

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

--------------------------------------------------------------------------------------
˓→--------------------------------

gc_309 | $K_4$--minor--free | base |


gc_541 | $N^*$ | base |
gc_215 | $N^*$--perfect | base |
gc_5 | $P_4$--bipartite | base |
gc_3 | $P_4$--brittle | base |
gc_6 | $P_4$--comparability | base |
gc_7 | $P_4$--extendible | base |
...

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

sage: graphs.PathGraph(5) in graph_classes.Tree


True

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

Or directly from ISGCI

sage: gc = graph_classes.get_class("gc_441")
sage: gc
diamond--free graphs
sage: graphs.PetersenGraph() in gc
True

2.6.2 Predefined classes

graph_classes currently predefines the following graph classes

536 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

Class Related methods


Apex is_apex(), apex_vertices()
AT_free is_asteroidal_triple_free()
Biconnected is_biconnected(), blocks_and_cut_vertices(),
blocks_and_cuts_tree()
BinaryTrees BalancedTree(), is_tree()
Bipartite BalancedTree(), is_bipartite()
Block is_block_graph(), blocks_and_cut_vertices(),
RandomBlockGraph()
Chordal is_chordal()
Claw-Free ClawGraph()
Comparability
Gallai is_gallai_tree()
Grid Grid2dGraph(), GridGraph()
Interval RandomIntervalGraph(), IntervalGraph(),
is_interval()
Line line_graph_forbidden_subgraphs(),
is_line_graph()
Modular modular_decomposition()
Outerplanar is_circular_planar()
Perfect is_perfect()
Planar is_planar()
Polyhedral is_polyhedral()
Split is_split()
Tree trees(), is_tree()
UnitDisk IntervalGraph()
UnitInterval is_interval()

2.6.3 Sage’s view of ISGCI

The database is stored by Sage in two ways.


The classes: the list of all graph classes and their properties is stored in a huge dictionary (see classes()). Below
is what Sage knows of gc_249:

sage: graph_classes.classes()['gc_249'] # random


{'problem':
{'Independent set': 'Polynomial',
'Treewidth': 'Unknown',
'Weighted independent set': 'Polynomial',
'Cliquewidth expression': 'NP-complete',
'Weighted clique': 'Polynomial',
'Clique cover': 'Unknown',
'Domination': 'NP-complete',
'Clique': 'Polynomial',
'Colourability': 'NP-complete',
'Cliquewidth': 'Unbounded',
'3-Colourability': 'NP-complete',
'Recognition': 'Linear'},
'type': 'base',
'id': 'gc_249',
'name': 'line'}

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

2.6.4 Information for developpers

• 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().

538 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

• 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).

Todo: Technical things:


• Query the database for non-inclusion results so that comparisons can return False, and implement strict inclu-
sions.
• Implement a proper search method for the classes not listed in graph_classes
See also:
sage.graphs.isgci.show_all().
• Some of the graph classes appearing in graph_classes already have a recognition algorithm implemented
in Sage. It would be so nice to be able to write g in Trees, g in Perfect, g in Chordal, . . . :-)
Long-term stuff:
• Implement simple accessors for all the information in the ISGCI database (as can be done from the website)
• Implement intersection of graph classes
• Write generic recognition algorithms for specific classes (when a graph class is defined by the exclusion of
subgraphs, one can write a generic algorithm checking the existence of each of the graphs, and this method
already exists in Sage).
• Improve the performance of Sage’s graph library by letting it take advantage of the properties of graph classes.
For example, Graph.independent_set() could use the library to detect that a given graph is, say, a tree
or a planar graph, and use a specialized algorithm for finding an independent set.

2.6.5 AUTHORS:

• H.N. de Ridder et al. (ISGCI database)


• Nathann Cohen (Sage implementation)

2.6.6 Methods

class sage.graphs.isgci.GraphClass(name, gc_id, recognition_function=None)


Bases: sage.structure.sage_object.SageObject, sage.structure.
unique_representation.CachedRepresentation
An instance of this class represents a Graph Class, matching some entry in the ISGCI database.
EXAMPLES:
Testing the inclusion of two classes:

2.6. ISGCI: Information System on Graph Classes and their Inclusions 539
Sage Reference Manual: Graph Theory, Release 8.4

sage: Chordal = graph_classes.Chordal


sage: Trees = graph_classes.Tree
sage: Trees <= Chordal
True
sage: Chordal <= Trees
Unknown

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

540 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

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: Cographs = graph_classes.get_class("gc_151")


sage: Cographs
cograph graphs

With a wrong 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

------------------------------------------------------------------------------
˓→----------------------------------------

gc_309 | $K_4$--minor--free | base |


gc_541 | $N^*$ | base |
gc_215 | $N^*$--perfect | base |
gc_5 | $P_4$--bipartite | base |
gc_3 | $P_4$--brittle | base |
gc_6 | $P_4$--comparability | base |
gc_7 | $P_4$--extendible | base |
...

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:

542 Chapter 2. Constructors and databases


Sage Reference Manual: Graph Theory, Release 8.4

sage: graph_classes.update_db() # Not tested -- requires internet

2.6. ISGCI: Information System on Graph Classes and their Inclusions 543
Sage Reference Manual: Graph Theory, Release 8.4

544 Chapter 2. Constructors and databases


CHAPTER

THREE

LOW-LEVEL IMPLEMENTATION

3.1 Overview of (di)graph data structures

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)

3.1.1 Data structures

Four data structures are natively available for (di)graphs in Sage:


• sparse_graph (default) – for sparse (di)graphs, with a log(𝑛) edge test, and easy enumeration of neighbors.
It is the most general-purpose data structure, though it can have a high memory cost in practice.
– Supports: Addition/removal of edges/vertices, multiple edges, edge labels and loops.
• dense_graph – for dense (di)graphs, with a 𝑂(1) edge test, and slow enumeration of neighbors.
– Supports: addition/removal of edges/vertices, and loops.
– Does not support: multiple edges and edge labels.
• static_sparse_graph – for sparse (di)graphs and very intensive computations (at C-level). It is faster
than sparse_graph in practice and much lighter in memory.
– Supports: multiple edges, edge labels and loops
– Does not support: addition/removal of edges/vertices.
• static_dense_graph – for dense (di)graphs and very intensive computations (at C-level). It is mostly a
wrapper over bitsets.
– Supports: addition/removal of edges/vertices, and loops.
– Does not support: multiple edges and edge labels.
For more information, see the data structures’ respective pages.

3.1.2 The backends

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.

3.1.3 CGraph and 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.

3.2 Fast compiled graphs

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.

3.2.1 Data structure

The class CGraph maintains the following variables:


• cdef int num_verts
• cdef int num_arcs
• cdef int *in_degrees
• cdef int *out_degrees
• cdef bitset_t active_vertices
The bitset active_vertices is a list of all available vertices for use, but only the ones which are set are considered
to actually be in the graph. The variables num_verts and num_arcs are self-explanatory. Note that num_verts
is the number of bits set in active_vertices, not the full length of the bitset. The arrays in_degrees and
out_degrees are of the same length as the bitset.
For more information about active vertices, see the documentation for the method realloc.

546 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

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:

• add_arc – add_arc method for sparse graphs.


• add_arc – add_arc method for dense graphs.

EXAMPLES:

sage: from sage.graphs.base.c_graph import CGraph


sage: G = CGraph()
sage: G.add_arc(0, 1)
Traceback (most recent call last):
...
NotImplementedError

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:

3.2. Fast compiled graphs 547


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.base.sparse_graph import SparseGraph


sage: G = SparseGraph(3, extra_vertices=3)
sage: G.add_vertex(3)
3
sage: G.add_arc(2, 5)
Traceback (most recent call last):
...
LookupError: Vertex (5) is not a vertex of the graph.
sage: G.add_arc(1, 3)
sage: G.has_arc(1, 3)
True
sage: G.has_arc(2, 3)
False

Adding vertices to a dense graph:

sage: from sage.graphs.base.dense_graph import DenseGraph


sage: G = DenseGraph(3, extra_vertices=3)
sage: G.add_vertex(3)
3
sage: G.add_arc(2,5)
Traceback (most recent call last):
...
LookupError: Vertex (5) is not a vertex of the graph.
sage: G.add_arc(1, 3)
sage: G.has_arc(1, 3)
True
sage: G.has_arc(2, 3)
False

Repeatedly adding a vertex using 𝑘 = −1 will allocate more memory as required:

sage: from sage.graphs.base.sparse_graph import SparseGraph


sage: G = SparseGraph(3, extra_vertices=0)
sage: G.verts()
[0, 1, 2]
sage: for i in range(10):
....: _ = G.add_vertex(-1);
...
sage: G.verts()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

sage: from sage.graphs.base.dense_graph import DenseGraph


sage: G = DenseGraph(3, extra_vertices=0)
sage: G.verts()
[0, 1, 2]
sage: for i in range(12):
....: _ = G.add_vertex(-1);
...
sage: G.verts()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

sage: from sage.graphs.base.dense_graph import DenseGraph


sage: G = DenseGraph(3, extra_vertices=0)
sage: G.add_vertex(6)
Traceback (most recent call last):
(continues on next page)

548 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


...
RuntimeError: Requested vertex is past twice the allocated range: use realloc.

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:

• add_vertex() – add a vertex to a graph.

EXAMPLES:
Adding vertices for sparse graphs:

sage: from sage.graphs.base.sparse_graph import SparseGraph


sage: S = SparseGraph(nverts=4, extra_vertices=4)
sage: S.verts()
[0, 1, 2, 3]
sage: S.add_vertices([3,-1,4,9])
[5]
sage: S.verts()
[0, 1, 2, 3, 4, 5, 9]
sage: S.realloc(20)
sage: S.verts()
[0, 1, 2, 3, 4, 5, 9]

Adding vertices for dense graphs:

sage: from sage.graphs.base.dense_graph import DenseGraph


sage: D = DenseGraph(nverts=4, extra_vertices=4)
sage: D.verts()
[0, 1, 2, 3]
sage: D.add_vertices([3,-1,4,9])
[5]
sage: D.verts()
[0, 1, 2, 3, 4, 5, 9]
sage: D.realloc(20)
sage: D.verts()
[0, 1, 2, 3, 4, 5, 9]

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:

3.2. Fast compiled graphs 549


Sage Reference Manual: Graph Theory, Release 8.4

• Raise NotImplementedError. This method is not implemented at the CGraph level. A child
class should provide a suitable implementation.
See also:

• all_arcs – all_arcs method for sparse graphs.

EXAMPLES:

sage: from sage.graphs.base.c_graph import CGraph


sage: G = CGraph()
sage: G.all_arcs(0, 1)
Traceback (most recent call last):
...
NotImplementedError

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:

• has_vertex() – determine whether this graph has a specific vertex.

EXAMPLES:

sage: from sage.graphs.base.sparse_graph import SparseGraph


sage: S = SparseGraph(nverts=10, expected_degree=3, extra_vertices=10)
sage: S.check_vertex(4)
sage: S.check_vertex(12)
Traceback (most recent call last):
...
LookupError: Vertex (12) is not a vertex of the graph.
sage: S.check_vertex(24)
Traceback (most recent call last):
...
LookupError: Vertex (24) is not a vertex of the graph.
sage: S.check_vertex(-19)
Traceback (most recent call last):
...
LookupError: Vertex (-19) is not a vertex of the graph.

sage: from sage.graphs.base.dense_graph import DenseGraph


sage: D = DenseGraph(nverts=10, extra_vertices=10)
sage: D.check_vertex(4)
sage: D.check_vertex(12)
Traceback (most recent call last):
...
(continues on next page)

550 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


LookupError: Vertex (12) is not a vertex of the graph.
sage: D.check_vertex(24)
Traceback (most recent call last):
...
LookupError: Vertex (24) is not a vertex of the graph.
sage: D.check_vertex(-19)
Traceback (most recent call last):
...
LookupError: Vertex (-19) is not a vertex of the graph.

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:

sage: from sage.graphs.base.sparse_graph import SparseGraph


sage: S = SparseGraph(nverts=4, extra_vertices=4)
sage: S.current_allocation()
8
sage: S.add_vertex(6)
6
sage: S.current_allocation()
8
sage: S.add_vertex(10)
10
sage: S.current_allocation()
16
sage: S.add_vertex(40)
Traceback (most recent call last):
...
RuntimeError: Requested vertex is past twice the allocated range: use realloc.
sage: S.realloc(50)
sage: S.add_vertex(40)
40
sage: S.current_allocation()
50
sage: S.realloc(30)
-1
sage: S.current_allocation()
50
sage: S.del_vertex(40)
sage: S.realloc(30)
sage: S.current_allocation()
30

The actual number of vertices in a graph might be less than the number of vertices allocated for the graph:

3.2. Fast compiled graphs 551


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.base.dense_graph import DenseGraph


sage: G = DenseGraph(nverts=3, extra_vertices=2)
sage: order = len(G.verts())
sage: order
3
sage: G.current_allocation()
5
sage: order < G.current_allocation()
True

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:

• del_all_arcs – del_all_arcs method for sparse graphs.


• del_all_arcs – del_all_arcs method for dense graphs.

EXAMPLES:

sage: from sage.graphs.base.c_graph import CGraph


sage: G = CGraph()
sage: G.del_all_arcs(0,1)
Traceback (most recent call last):
...
NotImplementedError

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:

552 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.base.sparse_graph import SparseGraph


sage: G = SparseGraph(3)
sage: G.add_arc(0, 1)
sage: G.add_arc(0, 2)
sage: G.add_arc(1, 2)
sage: G.add_arc(2, 0)
sage: G.del_vertex(2)
sage: for i in range(2):
....: for j in range(2):
....: if G.has_arc(i, j):
....: print("{} {}".format(i,j))
0 1
sage: G = SparseGraph(3)
sage: G.add_arc(0, 1)
sage: G.add_arc(0, 2)
sage: G.add_arc(1, 2)
sage: G.add_arc(2, 0)
sage: G.del_vertex(1)
sage: for i in range(3):
....: for j in range(3):
....: if G.has_arc(i, j):
....: print("{} {}".format(i,j))
0 2
2 0

Deleting vertices of dense graphs:


sage: from sage.graphs.base.dense_graph import DenseGraph
sage: G = DenseGraph(4)
sage: G.add_arc(0, 1); G.add_arc(0, 2)
sage: G.add_arc(3, 1); G.add_arc(3, 2)
sage: G.add_arc(1, 2)
sage: G.verts()
[0, 1, 2, 3]
sage: G.del_vertex(3); G.verts()
[0, 1, 2]
sage: for i in range(3):
....: for j in range(3):
....: if G.has_arc(i, j):
....: print("{} {}".format(i,j))
0 1
0 2
1 2

If the vertex to be deleted is not in this graph, then fail silently:


sage: from sage.graphs.base.sparse_graph import SparseGraph
sage: G = SparseGraph(3)
sage: G.verts()
[0, 1, 2]
sage: G.has_vertex(3)
False
sage: G.del_vertex(3)
sage: G.verts()
[0, 1, 2]

sage: from sage.graphs.base.dense_graph import DenseGraph


(continues on next page)

3.2. Fast compiled graphs 553


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: G = DenseGraph(5)
sage: G.verts()
[0, 1, 2, 3, 4]
sage: G.has_vertex(6)
False
sage: G.del_vertex(6)
sage: G.verts()
[0, 1, 2, 3, 4]

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:

• has_arc – has_arc method for sparse graphs.


• has_arc – has_arc method for dense graphs.

EXAMPLES:

sage: from sage.graphs.base.c_graph import CGraph


sage: G = CGraph()
sage: G.has_arc(0, 1)
Traceback (most recent call last):
...
NotImplementedError

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:

554 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.base.sparse_graph import SparseGraph


sage: S = SparseGraph(nverts=10, expected_degree=3, extra_vertices=10)
sage: S.has_vertex(6)
True
sage: S.has_vertex(12)
False
sage: S.has_vertex(24)
False
sage: S.has_vertex(-19)
False

sage: from sage.graphs.base.dense_graph import DenseGraph


sage: D = DenseGraph(nverts=10, extra_vertices=10)
sage: D.has_vertex(6)
True
sage: D.has_vertex(12)
False
sage: D.has_vertex(24)
False
sage: D.has_vertex(-19)
False

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:

• in_neighbors – in_neighbors method for sparse graphs.


• in_neighbors – in_neighbors method for dense graphs.

EXAMPLES:

sage: from sage.graphs.base.c_graph import CGraph


sage: G = CGraph()
sage: G.in_neighbors(0)
Traceback (most recent call last):
...
NotImplementedError

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.

3.2. Fast compiled graphs 555


Sage Reference Manual: Graph Theory, Release 8.4

See also:

• out_neighbors – out_neighbors implementation for sparse graphs.


• out_neighbors – out_neighbors implementation for dense graphs.

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:

• realloc – a realloc implementation for sparse graphs.


• realloc – a realloc implementation for dense graphs.

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

The realloc implementation for sparse graphs:


sage: from sage.graphs.base.sparse_graph import SparseGraph
sage: S = SparseGraph(nverts=4, extra_vertices=4)
sage: S.current_allocation()
8
sage: S.add_vertex(6)
6
sage: S.current_allocation()
8
sage: S.add_vertex(10)
10
sage: S.current_allocation()
16
sage: S.add_vertex(40)
(continues on next page)

556 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


Traceback (most recent call last):
...
RuntimeError: Requested vertex is past twice the allocated range: use realloc.
sage: S.realloc(50)
sage: S.add_vertex(40)
40
sage: S.current_allocation()
50
sage: S.realloc(30)
-1
sage: S.current_allocation()
50
sage: S.del_vertex(40)
sage: S.realloc(30)
sage: S.current_allocation()
30

The realloc implementation for dense graphs:

sage: from sage.graphs.base.dense_graph import DenseGraph


sage: D = DenseGraph(nverts=4, extra_vertices=4)
sage: D.current_allocation()
8
sage: D.add_vertex(6)
6
sage: D.current_allocation()
8
sage: D.add_vertex(10)
10
sage: D.current_allocation()
16
sage: D.add_vertex(40)
Traceback (most recent call last):
...
RuntimeError: Requested vertex is past twice the allocated range: use realloc.
sage: D.realloc(50)
sage: D.add_vertex(40)
40
sage: D.current_allocation()
50
sage: D.realloc(30)
-1
sage: D.current_allocation()
50
sage: D.del_vertex(40)
sage: D.realloc(30)
sage: D.current_allocation()
30

verts()
Returns a list of the vertices in self.
INPUT:
• None.
OUTPUT:
• A list of all vertices in this graph.

3.2. Fast compiled graphs 557


Sage Reference Manual: Graph Theory, Release 8.4

EXAMPLES:

sage: from sage.graphs.base.sparse_graph import SparseGraph


sage: S = SparseGraph(nverts=4, extra_vertices=4)
sage: S.verts()
[0, 1, 2, 3]
sage: S.add_vertices([3,5,7,9])
sage: S.verts()
[0, 1, 2, 3, 5, 7, 9]
sage: S.realloc(20)
sage: S.verts()
[0, 1, 2, 3, 5, 7, 9]

sage: from sage.graphs.base.dense_graph import DenseGraph


sage: G = DenseGraph(3, extra_vertices=2)
sage: G.verts()
[0, 1, 2]
sage: G.del_vertex(0)
sage: G.verts()
[1, 2]

class sage.graphs.base.c_graph.CGraphBackend
Bases: sage.graphs.base.graph_backends.GenericGraphBackend
Base class for sparse and dense graph backends.

sage: from sage.graphs.base.c_graph import CGraphBackend

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:

sage: from sage.graphs.base.c_graph import CGraphBackend


sage: CGB = CGraphBackend()
sage: CGB.degree(0, True)
Traceback (most recent call last):
...
TypeError: 'NoneType' object is not iterable

The appropriate way to use these backends is via Sage graphs:

sage: G = Graph(30, implementation="c_graph")


sage: G.add_edges([(0,1), (0,3), (4,5), (9, 23)])
sage: G.edges(labels=False)
[(0, 1), (0, 3), (4, 5), (9, 23)]

This class handles the labels of vertices and edges. For vertices it uses two dictionaries vertex_labels
and vertex_ints. They are just opposite of each other: vertex_ints makes a translation from label to
integers (that are internally used) and vertex_labels make the translation from internally used integers to
actual labels. This class tries hard to avoid translation if possible. This will work only if the graph is built on
integers from 0 to 𝑛 − 1 and the vertices are basically added in increasing order.
See also:

• SparseGraphBackend – backend for sparse graphs.


• DenseGraphBackend – backend for dense graphs.

558 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

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:

• add_vertices() – add a bunch of vertices of this graph.


• has_vertex() – returns whether or not this graph has a specific vertex.

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:

• add_vertex() – add a vertex to this graph.

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)

3.2. Fast compiled graphs 559


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


[0, 1]
sage: list(G.iterator_edges([0,1], True))
[]

sage: import sage.graphs.base.dense_graph


sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
sage: D.add_vertices([10,11,12])

bidirectional_dijkstra(x, y, weight_function=None, distance_flag=False)


Returns the shortest path or distance from x to y using a bidirectional version of Dijkstra’s algorithm.
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.
• weight_function – a function that inputs an edge (u, v, l) and outputs its weight. If None,
we use the edge label l as a weight.
• distance_flag – boolean (default: False). When set to True, the shortest path distance from
x to y is returned instead of the path.
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: for (u,v) in G.edges(labels=None):
....: G.set_edge_label(u,v,1)
sage: G.shortest_path(0, 1, by_weight=True)
[0, 1]
sage: G.shortest_path_length(0, 1, by_weight=True)
1
sage: G = DiGraph([(1,2,{'weight':1}), (1,3,{'weight':5}), (2,3,{'weight':1}
˓→)])

sage: G.shortest_path(1, 3, weight_function=lambda e:e[2]['weight'])


[1, 2, 3]
sage: G.shortest_path_length(1, 3, weight_function=lambda e:e[2]['weight'])
2

breadth_first_search(v, reverse=False, ignore_direction=False)


Returns a breadth-first search from vertex v.
INPUT:
• v – a vertex from which to start the breadth-first search.
• reverse – boolean (default: False). This is only relevant to digraphs. If this is a digraph, consider
the reversed graph in which the out-neighbors become the in-neighbors and vice versa.
• ignore_direction – boolean (default: False). This is only relevant to digraphs. If this is a
digraph, ignore all orientations and consider the graph as undirected.
ALGORITHM:
Below is a general template for breadth-first search.

560 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

• 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 𝑠.

1. 𝑄 ← [𝑠] # a queue of nodes to visit


2. 𝐷 ← [∞, ∞, . . . , ∞] # 𝑛 copies of ∞
3. 𝐷[𝑠] ← 0
4. 𝑇 ← [ ]
5. while length(𝑄) > 0 do
(a) 𝑣 ← dequeue(𝑄)
(b) for each 𝑤 ∈ adj(𝑣) do # for digraphs, use out-neighbor set oadj(𝑣)
i. if 𝐷[𝑤] = ∞ then
A. 𝐷[𝑤] ← 𝐷[𝑣] + 1
B. enqueue(𝑄, 𝑤)
C. append(𝑇, 𝑣𝑤)
6. return (𝐷, 𝑇 )

See also:

• breadth_first_search – breadth-first search for generic graphs.


• depth_first_search – depth-first search for generic graphs.
• depth_first_search() – depth-first search for fast compiled graphs.

EXAMPLES:
Breadth-first search of the Petersen graph starting at vertex 0:

sage: G = Graph(graphs.PetersenGraph(), implementation="c_graph")


sage: list(G.breadth_first_search(0))
[0, 1, 4, 5, 2, 6, 3, 9, 7, 8]

Visiting German cities using breadth-first search:

sage: G = Graph({"Mannheim": ["Frankfurt","Karlsruhe"],


....: "Frankfurt": ["Mannheim","Wurzburg","Kassel"],
....: "Kassel": ["Frankfurt","Munchen"],
....: "Munchen": ["Kassel","Nurnberg","Augsburg"],
....: "Augsburg": ["Munchen","Karlsruhe"],
....: "Karlsruhe": ["Mannheim","Augsburg"],
....: "Wurzburg": ["Frankfurt","Erfurt","Nurnberg"],
....: "Nurnberg": ["Wurzburg","Stuttgart","Munchen"],
....: "Stuttgart": ["Nurnberg"],
....: "Erfurt": ["Wurzburg"]}, implementation="c_graph")
sage: list(G.breadth_first_search("Frankfurt"))
['Frankfurt', 'Mannheim', 'Kassel', 'Wurzburg', 'Karlsruhe', 'Munchen',
˓→'Erfurt', 'Nurnberg', 'Augsburg', 'Stuttgart']

3.2. Fast compiled graphs 561


Sage Reference Manual: Graph Theory, Release 8.4

c_graph()
Return the ._cg and ._cg_rev attributes
EXAMPLES:

sage: cg,cg_rev = graphs.PetersenGraph()._backend.c_graph()


sage: cg
<sage.graphs.base.sparse_graph.SparseGraph object at ...>
sage: cg_rev
<sage.graphs.base.sparse_graph.SparseGraph object at ...>

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:

sage: from sage.graphs.base.sparse_graph import SparseGraphBackend


sage: B = SparseGraphBackend(7)
sage: B.degree(3, False)
0

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:

• del_vertices() – delete a bunch of vertices from this graph.

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.

562 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

INPUT:
• vertices – iterator of vertex labels.
OUTPUT:
• Same as for del_vertex().
See also:

• del_vertex() – delete a vertex of this graph.

EXAMPLES:

sage: import sage.graphs.base.dense_graph


sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
sage: D.del_vertices([7,8])
sage: D.has_vertex(7)
False
sage: D.has_vertex(6)
True

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

depth_first_search(v, reverse=False, ignore_direction=False)


Returns a depth-first search from vertex v.
INPUT:
• v – a vertex from which to start the depth-first search.
• reverse – boolean (default: False). This is only relevant to digraphs. If this is a digraph, consider
the reversed graph in which the out-neighbors become the in-neighbors and vice versa.
• ignore_direction – boolean (default: False). This is only relevant to digraphs. If this is a
digraph, ignore all orientations and consider the graph as undirected.
ALGORITHM:
Below is a general template for depth-first search.
• 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 𝑠.

1. 𝑆 ← [𝑠] # a stack of nodes to visit


2. 𝐷 ← [∞, ∞, . . . , ∞] # 𝑛 copies of ∞
3. 𝐷[𝑠] ← 0
4. 𝑇 ← [ ]
5. while length(𝑆) > 0 do
(a) 𝑣 ← pop(𝑆)
(b) for each 𝑤 ∈ adj(𝑣) do # for digraphs, use out-neighbor set oadj(𝑣)

3.2. Fast compiled graphs 563


Sage Reference Manual: Graph Theory, Release 8.4

i. if 𝐷[𝑤] = ∞ then
A. 𝐷[𝑤] ← 𝐷[𝑣] + 1
B. push(𝑆, 𝑤)
C. append(𝑇, 𝑣𝑤)
6. return (𝐷, 𝑇 )

See also:

• breadth_first_search() – breadth-first search for fast compiled graphs.


• breadth_first_search – breadth-first search for generic graphs.
• depth_first_search – depth-first search for generic graphs.

EXAMPLES:
Traversing the Petersen graph using depth-first search:

sage: G = Graph(graphs.PetersenGraph(), implementation="c_graph")


sage: list(G.depth_first_search(0))
[0, 5, 8, 6, 9, 7, 2, 3, 4, 1]

Visiting German cities using depth-first search:

sage: G = Graph({"Mannheim": ["Frankfurt","Karlsruhe"],


....: "Frankfurt": ["Mannheim","Wurzburg","Kassel"],
....: "Kassel": ["Frankfurt","Munchen"],
....: "Munchen": ["Kassel","Nurnberg","Augsburg"],
....: "Augsburg": ["Munchen","Karlsruhe"],
....: "Karlsruhe": ["Mannheim","Augsburg"],
....: "Wurzburg": ["Frankfurt","Erfurt","Nurnberg"],
....: "Nurnberg": ["Wurzburg","Stuttgart","Munchen"],
....: "Stuttgart": ["Nurnberg"],
....: "Erfurt": ["Wurzburg"]}, implementation="c_graph")
sage: list(G.depth_first_search("Frankfurt"))
['Frankfurt', 'Wurzburg', 'Nurnberg', 'Munchen', 'Kassel', 'Augsburg',
˓→'Karlsruhe', 'Mannheim', 'Stuttgart', 'Erfurt']

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:

sage: from sage.graphs.base.sparse_graph import SparseGraphBackend


sage: B = SparseGraphBackend(7)
sage: B.has_vertex(6)
True
sage: B.has_vertex(7)
False

564 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

in_degree(v)
Returns the in-degree of v
INPUT:
• v – a vertex of the graph.
EXAMPLES:

sage: D = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] }


˓→)

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

While the disjoint union of two of them is not:

sage: DiGraph(2*graphs.PetersenGraph(),implementation="c_graph").is_
˓→connected()

False

A graph with non-integer vertex labels:

sage: Graph(graphs.CubeGraph(3), implementation='c_graph').is_connected()


True

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.

3.2. Fast compiled graphs 565


Sage Reference Manual: Graph Theory, Release 8.4

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.

Note: The graph is assumed to be directed. An exception is raised if it is not.

EXAMPLES:
At first, the following graph is acyclic:

sage: D = DiGraph({ 0:[1,2,3], 4:[2,5], 1:[8], 2:[7], 3:[7], 5:[6,7], 7:[8],


˓→6:[9], 8:[10], 9:[10] })

sage: D.plot(layout='circular').show()
sage: D.is_directed_acyclic()
True

Adding an edge from 9 to 7 does not change it:

sage: D.add_edge(9,7)
sage: D.is_directed_acyclic()
True

We can obtain as a proof an ordering of the vertices such that 𝑢 appears before 𝑣 if 𝑢𝑣 is an edge of the
graph:

sage: D.is_directed_acyclic(certificate = True)


(True, [4, 5, 6, 9, 0, 1, 2, 3, 7, 8, 10])

Adding an edge from 7 to 4, though, makes a difference:

sage: D.add_edge(7,4)
sage: D.is_directed_acyclic()
False

Indeed, it creates a circuit 7, 4, 5:

sage: D.is_directed_acyclic(certificate = True)


(False, [7, 4, 5])

Checking acyclic graphs are indeed acyclic

sage: def random_acyclic(n, p):


....: g = graphs.RandomGNP(n, p)
....: h = DiGraph()
....: h.add_edges([ ((u,v) if u<v else (v,u)) for u,v,_ in g.edges() ])
....: return h
...
sage: all( random_acyclic(100, .2).is_directed_acyclic() # long time
....: for i in range(50)) # long time
True

is_strongly_connected()
Returns whether the graph is strongly connected.
EXAMPLES:
The circuit on 3 vertices is obviously strongly connected:

566 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

sage: g = DiGraph({0: [1], 1: [2], 2: [0]}, implementation="c_graph")


sage: g.is_strongly_connected()
True

But a transitive triangle is not:

sage: g = DiGraph({0: [1,2], 1: [2]}, implementation="c_graph")


sage: g.is_strongly_connected()
False

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:

• iterator_nbrs() – returns an iterator over the neighbors of a vertex.


• iterator_out_nbrs() – returns an iterator over the out-neighbors of a vertex.

EXAMPLES:

sage: P = DiGraph(graphs.PetersenGraph().to_directed(), implementation="c_


˓→graph")

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:

• iterator_in_nbrs() – returns an iterator over the in-neighbors of a vertex.


• iterator_out_nbrs() – returns an iterator over the out-neighbors of a vertex.
• iterator_verts() – returns an iterator over a given set of vertices.

EXAMPLES:

sage: P = Graph(graphs.PetersenGraph(), implementation="c_graph")


sage: list(P._backend.iterator_nbrs(0))
[1, 4, 5]

iterator_out_nbrs(v)
Returns an iterator over the outgoing neighbors of v.

3.2. Fast compiled graphs 567


Sage Reference Manual: Graph Theory, Release 8.4

INPUT:
• v – a vertex of this graph.
OUTPUT:
• An iterator over the out-neighbors of the vertex v.
See also:

• iterator_nbrs() – returns an iterator over the neighbors of a vertex.


• iterator_in_nbrs() – returns an iterator over the in-neighbors of a vertex.

EXAMPLES:

sage: P = DiGraph(graphs.PetersenGraph().to_directed(), implementation="c_


˓→graph")

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:

• iterator_nbrs() – returns an iterator over the neighbors of a vertex.

EXAMPLES:

sage: P = Graph(graphs.PetersenGraph(), implementation="c_graph")


sage: list(P._backend.iterator_verts(P))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sage: list(P._backend.iterator_verts())
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sage: list(P._backend.iterator_verts([1, 2, 3]))
[1, 2, 3]
sage: list(P._backend.iterator_verts([1, 2, 10]))
[1, 2]

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.

568 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

• 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:

• num_verts() – return the order of this graph.

EXAMPLES:

sage: G = Graph(graphs.PetersenGraph(), implementation="c_graph")


sage: G._backend.num_edges(False)
15

num_verts()
Returns the number of vertices in self.
INPUT:
• None.
OUTPUT:
• The order of this graph.
See also:

• num_edges() – return the number of (directed) edges in this graph.

EXAMPLES:

sage: G = Graph(graphs.PetersenGraph(), implementation="c_graph")


sage: G._backend.num_verts()
10

out_degree(v)
Returns the out-degree of v
INPUT:
• v – a vertex of the graph.
EXAMPLES:

3.2. Fast compiled graphs 569


Sage Reference Manual: Graph Theory, Release 8.4

sage: D = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] }


˓→)

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

shortest_path_all_vertices(v, cutoff=None, distance_flag=False)


Returns for each vertex u a shortest v-u path or distance from v to u.

570 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

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

Note: The weight of edges is not taken into account.

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]

In the Butterfly DiGraph, each vertex is a strongly connected component:

sage: g = digraphs.ButterflyGraph(3)
sage: all([[v] == g.strongly_connected_component_containing_vertex(v) for v
˓→in g])

True

3.2. Fast compiled graphs 571


Sage Reference Manual: Graph Theory, Release 8.4

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

3.3 Fast sparse graphs

For an overview of graph data structures in sage, see overview.

3.3.1 Usage Introduction

sage: from sage.graphs.base.sparse_graph import SparseGraph

Sparse graphs are initialized as follows:

sage: S = SparseGraph(nverts = 10, expected_degree = 3, extra_vertices = 10)

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)

572 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


9
sage: S.verts()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

But 10 is not, until we add it:

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]

Zero specifies only that there is no labeled arc:

3.3. Fast sparse graphs 573


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: T = SparseGraph(nverts = 3, expected_degree = 2)


sage: T.add_arc(0,1)
sage: T.add_arc(1,2)
sage: T.add_arc(2,0)
sage: T.has_arc(0,1)
True

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

Multiple unlabeled edges are also possible:

sage: for _ in range(10): S.add_arc(5,4)


sage: S.all_arcs(5,4)
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

The curious developer is encouraged to check out the unsafe functions, which do not check input but which run in
pure C.

3.3.2 Underlying Data Structure

The class SparseGraph contains the following variables which are inherited from CGraph (for explanation, refer
to the documentation there):

cdef int num_verts


cdef int num_arcs
cdef int *in_degrees
cdef int *out_degrees
cdef bitset_t active_vertices

It also contains the following variables:

cdef int hash_length


cdef int hash_mask
cdef SparseGraphBTNode **vertices

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

574 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

speed access to individual arcs, whose nodes (each of which represents a pair (u,v)) are instances of the following
type:

cdef struct SparseGraphBTNode:


int vertex
int number
SparseGraphLLNode *labels
SparseGraphBTNode *left
SparseGraphBTNode *right

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:

cdef struct SparseGraphLLNode:


int label
int number
SparseGraphLLNode *next

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.

sage: from sage.graphs.base.sparse_graph import SparseGraph

Sparse graphs are initialized as follows:

sage: S = SparseGraph(nverts = 10, expected_degree = 3, extra_vertices = 10)

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:

3.3. Fast sparse graphs 575


Sage Reference Manual: Graph Theory, Release 8.4

• u, v – non-negative integers, must be in self


EXAMPLES:
sage: from sage.graphs.base.sparse_graph import SparseGraph
sage: G = SparseGraph(5)
sage: G.add_arc(0,1)
sage: G.add_arc(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

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).

576 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

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: from sage.graphs.base.sparse_graph import SparseGraph


sage: G = SparseGraph(5)
sage: G.add_arc_label(3,4,7)
sage: G.arc_label(3,4)
7

To this function, an unlabeled arc is indistinguishable from a non-arc:

sage: G.add_arc_label(1,0)
sage: G.arc_label(1,0)
0
sage: G.arc_label(1,1)
0

This function only returns the first label it finds from u to v:

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:

sage: from sage.graphs.base.sparse_graph import SparseGraph


sage: G = SparseGraph(5)
sage: G.add_arc_label(0,1,0)
sage: G.add_arc_label(0,1,1)
sage: G.add_arc_label(0,1,2)
sage: G.add_arc_label(0,1,3)
sage: G.del_all_arcs(0,1)
sage: G.has_arc(0,1)
False
sage: G.arc_label(0,1)
0
sage: G.del_all_arcs(0,1)

del_arc_label(u, v, l)
Delete an arc (u, v) with label l.
INPUT:
• u, v - non-negative integers, must be in self

3.3. Fast sparse graphs 577


Sage Reference Manual: Graph Theory, Release 8.4

• 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,0)
sage: G.add_arc_label(0,1,1)
sage: G.add_arc_label(0,1,2)
sage: G.add_arc_label(0,1,2)
sage: G.add_arc_label(0,1,3)
sage: G.del_arc_label(0,1,2)
sage: G.all_arcs(0,1)
[0, 3, 2, 1]
sage: G.del_arc_label(0,1,0)
sage: G.all_arcs(0,1)
[3, 2, 1]

has_arc(u, v)
Checks whether arc (u, v) is in the graph.
INPUT:
• u, v - integers
EXAMPLES:

sage: from sage.graphs.base.sparse_graph import SparseGraph


sage: G = SparseGraph(5)
sage: G.add_arc_label(0,1)
sage: G.has_arc(1,0)
False
sage: G.has_arc(0,1)
True

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:

sage: from sage.graphs.base.sparse_graph import SparseGraph


sage: G = SparseGraph(5)
sage: G.add_arc_label(0,1,0)
sage: G.add_arc_label(0,1,1)
sage: G.add_arc_label(0,1,2)
sage: G.add_arc_label(0,1,2)
sage: G.has_arc_label(0,1,1)
True
sage: G.has_arc_label(0,1,2)
True
sage: G.has_arc_label(0,1,3)
False

in_degree(u)
Returns the in-degree of v

578 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

INPUT:
• u - integer
EXAMPLES:

sage: from sage.graphs.base.sparse_graph import SparseGraph


sage: G = SparseGraph(5)
sage: G.add_arc(0,1)
sage: G.add_arc(1,2)
sage: G.add_arc(1,3)
sage: G.in_degree(0)
0
sage: G.in_degree(1)
1

in_neighbors(v)
Gives all u such that (u, v) is an arc of the graph.
INPUT:
• v - integer
EXAMPLES:

sage: from sage.graphs.base.sparse_graph import SparseGraph


sage: G = SparseGraph(5)
sage: G.add_arc(0,1)
sage: G.add_arc(3,1)
sage: G.add_arc(1,3)
sage: G.in_neighbors(1)
[0, 3]
sage: G.in_neighbors(3)
[1]

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:

sage: from sage.graphs.base.sparse_graph import SparseGraph


sage: G = SparseGraph(5)
sage: G.add_arc(0,1)
sage: G.add_arc(1,2)
sage: G.add_arc(1,3)
sage: G.out_degree(0)
1
sage: G.out_degree(1)
2

out_neighbors(u)
Gives all v such that (u, v) is an arc of the graph.
INPUT:

3.3. Fast sparse graphs 579


Sage Reference Manual: Graph Theory, Release 8.4

• u - integer
EXAMPLES:

sage: from sage.graphs.base.sparse_graph import SparseGraph


sage: G = SparseGraph(5)
sage: G.add_arc(0,1)
sage: G.add_arc(1,2)
sage: G.add_arc(1,3)
sage: G.out_neighbors(0)
[1]
sage: G.out_neighbors(1)
[2, 3]

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:

sage: from sage.graphs.base.sparse_graph import SparseGraph


sage: S = SparseGraph(nverts=4, extra_vertices=4)
sage: S.current_allocation()
8
sage: S.add_vertex(6)
6
sage: S.current_allocation()
8
sage: S.add_vertex(10)
10
sage: S.current_allocation()
16
sage: S.add_vertex(40)
Traceback (most recent call last):
...
RuntimeError: Requested vertex is past twice the allocated range: use realloc.
sage: S.realloc(50)
sage: S.add_vertex(40)
40
sage: S.current_allocation()
50
sage: S.realloc(30)
-1
sage: S.current_allocation()
50
sage: S.del_vertex(40)
sage: S.realloc(30)
sage: S.current_allocation()
30

class sage.graphs.base.sparse_graph.SparseGraphBackend
Bases: sage.graphs.base.c_graph.CGraphBackend
Backend for Sage graphs using SparseGraphs.

580 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.base.sparse_graph import SparseGraphBackend

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:

sage: G = Graph(30, implementation="c_graph", sparse=True)


sage: G.add_edges([(0,1), (0,3), (4,5), (9, 23)])
sage: G.edges(labels=False)
[(0, 1), (0, 3), (4, 5), (9, 23)]

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)

3.3. Fast sparse graphs 581


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


[(0, 1, None),
(2, 3, None),
(4, 5, None),
(5, 6, None)]

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

582 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

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)

3.3. Fast sparse graphs 583


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: list(G.iterator_out_edges([1], True))
[(1, 2, 3)]

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')]

Note that it fails silently if there is no edge there:

sage: G.set_edge_label(2,1,'b',True)
sage: list(G.iterator_edges(range(9), True))
[(1, 2, 'a')]

3.4 Fast dense graphs

For an overview of graph data structures in sage, see overview.

584 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

3.4.1 Usage Introduction

sage: from sage.graphs.base.dense_graph import DenseGraph

Dense graphs are initialized as follows:

sage: D = DenseGraph(nverts = 10, extra_vertices = 10)

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]

But 10 is not, until we add it:

sage: D.add_vertex(10)
10
sage: D.verts()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

You can begin working right away as follows:

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 do not support multiple or labeled edges.

sage: T = DenseGraph(nverts = 3, extra_vertices = 2)


sage: T.add_arc(0,1)
sage: T.add_arc(1,2)
sage: T.add_arc(2,0)
sage: T.has_arc(0,1)
True

3.4. Fast dense graphs 585


Sage Reference Manual: Graph Theory, Release 8.4

sage: for _ in range(10): D.add_arc(5,4)


sage: D.has_arc(5,4)
True

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.

3.4.2 Underlying Data Structure

The class DenseGraph contains the following variables which are inherited from CGraph (for explanation, refer to
the documentation there):

cdef int num_verts


cdef int num_arcs
cdef int *in_degrees
cdef int *out_degrees
cdef bitset_t active_vertices

It also contains the following variables:

cdef int num_longs


cdef unsigned long *edges

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.

sage: from sage.graphs.base.dense_graph import DenseGraph

Dense graphs are initialized as follows:

sage: D = DenseGraph(nverts = 10, extra_vertices = 10)

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.

586 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

add_arc(u, v)
Adds arc (u, v) to the graph.
INPUT:
• u, v – non-negative integers, must be in self
EXAMPLES:

sage: from sage.graphs.base.dense_graph import DenseGraph


sage: G = DenseGraph(5)
sage: G.add_arc(0,1)
sage: G.add_arc(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

complement()
Replaces the graph with its complement

Note: Assumes that the graph has no loop.

EXAMPLES:

sage: from sage.graphs.base.dense_graph import DenseGraph


sage: G = DenseGraph(5)
sage: G.add_arc(0,1)
sage: G.has_arc(0,1)
True
sage: G.complement()
sage: G.has_arc(0,1)
False

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:

sage: from sage.graphs.base.dense_graph import DenseGraph


sage: G = DenseGraph(5)
sage: G.add_arc(0,1)
sage: G.has_arc(0,1)
True
sage: G.del_all_arcs(0,1)
sage: G.has_arc(0,1)
False

3.4. Fast dense graphs 587


Sage Reference Manual: Graph Theory, Release 8.4

has_arc(u, v)
Checks whether arc (u, v) is in the graph.
INPUT: u, v – integers
EXAMPLES:

sage: from sage.graphs.base.dense_graph import DenseGraph


sage: G = DenseGraph(5)
sage: G.add_arc(0,1)
sage: G.has_arc(1,0)
False
sage: G.has_arc(0,1)
True

in_neighbors(v)
Gives all u such that (u, v) is an arc of the graph.
INPUT:
• v - integer
EXAMPLES:

sage: from sage.graphs.base.dense_graph import DenseGraph


sage: G = DenseGraph(5)
sage: G.add_arc(0,1)
sage: G.add_arc(3,1)
sage: G.add_arc(1,3)
sage: G.in_neighbors(1)
[0, 3]
sage: G.in_neighbors(3)
[1]

out_neighbors(u)
Gives all v such that (u, v) is an arc of the graph.
INPUT:
• u - integer
EXAMPLES:

sage: from sage.graphs.base.dense_graph import DenseGraph


sage: G = DenseGraph(5)
sage: G.add_arc(0,1)
sage: G.add_arc(1,2)
sage: G.add_arc(1,3)
sage: G.out_neighbors(0)
[1]
sage: G.out_neighbors(1)
[2, 3]

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:

588 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.base.dense_graph import DenseGraph


sage: D = DenseGraph(nverts=4, extra_vertices=4)
sage: D.current_allocation()
8
sage: D.add_vertex(6)
6
sage: D.current_allocation()
8
sage: D.add_vertex(10)
10
sage: D.current_allocation()
16
sage: D.add_vertex(40)
Traceback (most recent call last):
...
RuntimeError: Requested vertex is past twice the allocated range: use realloc.
sage: D.realloc(50)
sage: D.add_vertex(40)
40
sage: D.current_allocation()
50
sage: D.realloc(30)
-1
sage: D.current_allocation()
50
sage: D.del_vertex(40)
sage: D.realloc(30)
sage: D.current_allocation()
30

class sage.graphs.base.dense_graph.DenseGraphBackend
Bases: sage.graphs.base.c_graph.CGraphBackend
Backend for Sage graphs using DenseGraphs.

sage: from sage.graphs.base.dense_graph import DenseGraphBackend

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:

sage: G = Graph(30, implementation="c_graph", sparse=False)


sage: G.add_edges([(0,1), (0,3), (4,5), (9, 23)])
sage: G.edges(labels=False)
[(0, 1), (0, 3), (4, 5), (9, 23)]

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)

3.4. Fast dense graphs 589


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: DG.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 (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)

590 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


[(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). 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:

3.4. Fast dense graphs 591


Sage Reference Manual: Graph Theory, Release 8.4

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)]

592 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

multiple_edges(new)
Get/set whether or not self allows multiple edges.
INPUT:
• new - boolean (to set) or None (to get)
EXAMPLES:

sage: import sage.graphs.base.dense_graph


sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9)
sage: G.multiple_edges(True)
Traceback (most recent call last):
...
NotImplementedError: Dense graphs do not support multiple edges.
sage: G.multiple_edges(None)
False

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: import sage.graphs.base.dense_graph


sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9)
sage: G.set_edge_label(1,2,'a',True)
Traceback (most recent call last):
...
NotImplementedError: Dense graphs do not support edge labels.

3.5 Static dense graphs

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. Static dense graphs 593


Sage Reference Manual: Graph Theory, Release 8.4

3.5.1 Index

Cython functions

dense_graph_init Fills a binary matrix with the information of a (di)graph.

Python functions

is_strongly_regular() Tests if a graph is strongly regular


triangles_count() Return the number of triangles containing 𝑣, for every 𝑣
Iterator over the induced connected subgraphs of order at most 𝑘
connected_subgraph_iterator()

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)

594 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


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(k=2, vertices_only=True))
[[1], [1, 2], [2], [2, 3], [2, 4], [3], [3, 4], [4]]

sage: G = DiGraph([(1, 2), (2, 1)])


sage: list(G.connected_subgraph_iterator())
[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], [2]]

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)

And Clebsch’s graph is too:


sage: g = graphs.ClebschGraph()
sage: g.is_strongly_regular()
True
sage: g.is_strongly_regular(parameters = True)
(16, 5, 0, 2)

But Chvatal’s graph is not:


sage: g = graphs.ChvatalGraph()
sage: g.is_strongly_regular()
False

3.5. Static dense graphs 595


Sage Reference Manual: Graph Theory, Release 8.4

Complete graphs are not strongly regular. (trac ticket #14297)

sage: g = graphs.CompleteGraph(5)
sage: g.is_strongly_regular()
False

Completements of complete graphs are not strongly regular:

sage: g = graphs.CompleteGraph(5).complement()
sage: g.is_strongly_regular()
False

The empty graph is not strongly regular:

sage: g = graphs.EmptyGraph()
sage: g.is_strongly_regular()
False

If the input graph has loops or multiedges an exception is raised:

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:

sage: from sage.graphs.base.static_dense_graph import triangles_count


sage: triangles_count(graphs.PetersenGraph())
{0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0}
sage: sum(triangles_count(graphs.CompleteGraph(15)).values()) == 3*binomial(15,3)
True

3.6 Static Sparse Graphs

3.6.1 What is the point ?

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.

596 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

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)

3.6.2 Data structure

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:

cdef list_edges(short_digraph g):


cdef int i, j
for i in range(g.n):
for j in range(g.neighbors[i+1]-g.neighbors[i]):
print("There is an edge from {} to {}".format(i, g.neighbors[i][j]))

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 !
:-)

3.6. Static Sparse Graphs 597


Sage Reference Manual: Graph Theory, Release 8.4

3.6.3 Technical details

• 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.

3.6.4 Cython functions

Initializes short_digraph g from a Sage (Di)Graph.


init_short_digraph(short_digraph
g, G)
int Returns the number of edges in g
n_edges(short_digraph
g)
int Returns the out-degree of vertex 𝑖 in g
out_degree(short_digraph
g, int i)
has_edge(short_digraph Tests the existence of an edge.
g, int u, int v)
edge_label(short_digraphReturns the label associated with a given edge
g, int * edge)
Allocates dst so that it can contain as many vertices and edges as src.
init_empty_copy(short_digraph
dst, short_digraph
src)
Initializes dst to a copy of src with all edges in the opposite direction.
init_reverse(short_digraph
dst, short_digraph
src)
Free the ressources used by g
free_short_digraph(short_digraph
g)

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)

598 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

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.

3.6.5 What is this module used for ?

At the moment, it is used in the sage.graphs.distances_all_pairs module, and in the


strongly_connected_components() method.

3.6.6 Python functions

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: from sage.graphs.base.static_sparse_graph import spectral_radius

sage: G = DiGraph([(0,0),(0,1),(1,0)], loops=True)


sage: phi = (RR(1) + RR(5).sqrt() ) / 2
sage: phi # abs tol 1e-14
1.618033988749895
(continues on next page)

3.6. Static Sparse Graphs 599


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: e_min, e_max = spectral_radius(G, 1e-14)
sage: e_min, e_max # abs tol 1e-14
(1.618033988749894, 1.618033988749896)
sage: (e_max - e_min) # abs tol 1e-14
1e-14
sage: e_min < phi < e_max
True

This function also works for graphs:

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

sage: G.spectral_radius() # abs tol 1e-9


(2.48119430408, 2.4811943041)

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

A much larger example:

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)

The algorithm takes care of multiple edges:

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?

Some bipartite graphs:

sage: G = Graph([(0,1),(0,3),(2,3)])
sage: G.spectral_radius() # abs tol 1e-10
(continues on next page)

600 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


(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)

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: from sage.graphs.base.static_sparse_graph import strongly_connected_


˓→components_digraph

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: from sage.graphs.base.static_sparse_graph import tarjan_strongly_connected_


˓→components

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)

3.6. Static Sparse Graphs 601


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


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']]

sage.graphs.base.static_sparse_graph.triangles_count
Return the number of triangles containing 𝑣, for every 𝑣.
INPUT:
• 𝐺– a graph
EXAMPLES:

sage: from sage.graphs.base.static_sparse_graph import triangles_count


sage: triangles_count(graphs.PetersenGraph())
{0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0}
sage: sum(triangles_count(graphs.CompleteGraph(15)).values()) == 3*binomial(15,3)
True

3.7 Static sparse graph backend

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.

3.7.1 Two classes

This module implements two classes


• StaticSparseCGraph extends CGraph and is a Cython class that manages the definition/deallocation of
the short_digraph structure. It does not know anything about labels on vertices.
• StaticSparseBackend extends CGraphBackend and is a Python class that does know about ver-
tex labels and contains an instance of StaticSparseCGraph as an internal variable. The input/output
of its methods are labeled vertices, which it translates to integer id before forwarding them to the
StaticSparseCGraph instance.

3.7.2 Classes and methods

class sage.graphs.base.static_sparse_backend.StaticSparseBackend
Bases: sage.graphs.base.c_graph.CGraphBackend
A graph backend for static sparse graphs.
EXAMPLES:

602 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

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: from sage.graphs.base.static_sparse_backend import StaticSparseBackend


sage: g = StaticSparseBackend(graphs.PetersenGraph())
sage: list(g.iterator_edges([0],1))
[(0, 1, None), (0, 4, None), (0, 5, 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: sorted(g.edges()) == sorted(gi.edges())


True

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: (0,4,2) in gi.edges()


True
sage: gi.has_edge(0,4)
True

sage: G = Graph({1:{2:28, 6:10}, 2:{3:16, 7:14}, 3:{4:12}, 4:{5:22, 7:18}, 5:


˓→{6:25, 7:24}})

sage: GI = Graph({1:{2:28, 6:10}, 2:{3:16, 7:14}, 3:{4:12}, 4:{5:22, 7:18}, 5:


˓→{6:25, 7:24}}, 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

sage: g = Graph({1:{1:[1,2,3]}}, data_structure="static_sparse")


sage: g.size()
3
sage: g.order()
1
sage: g.vertices()
[1]
(continues on next page)

3.7. Static sparse graph backend 603


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: g.edges()
[(1, 1, 1), (1, 1, 2), (1, 1, 3)]

trac ticket #15810 is fixed:

sage: DiGraph({1:{2:['a','b'], 3:['c']}, 2:{3:['d']}}, immutable=True).is_


˓→directed_acyclic()

True

add_vertex(v)
Addition of vertices is not available on an immutable graph.
EXAMPLES:

sage: g = DiGraph(graphs.PetersenGraph(), data_structure="static_sparse")


sage: g.add_vertex(1)
Traceback (most recent call last):
...
ValueError: Thou shalt not add a vertex to an immutable graph
sage: g.add_vertices([1,2,3])
Traceback (most recent call last):
...
ValueError: Thou shalt not add a vertex to an immutable graph

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: g = Graph(graphs.PetersenGraph(), data_structure="static_sparse")


sage: g.degree(0)
3

trac ticket #17225 about the degree of a vertex with a loop:

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:

604 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

sage: g = DiGraph(graphs.PetersenGraph(), data_structure="static_sparse")


sage: g.delete_vertex(1)
Traceback (most recent call last):
...
ValueError: Thou shalt not remove a vertex from an immutable graph
sage: g.delete_vertices([1,2,3])
Traceback (most recent call last):
...
ValueError: Thou shalt not remove a vertex from an immutable graph

get_edge_label(u, v)
Returns the edge label for (u,v).
INPUT:
• u,v – two vertices

sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend


sage: g = StaticSparseBackend(digraphs.DeBruijn(3,2))
sage: g.has_edge('00','01','1')
True
sage: g.has_edge('00','01','0')
False

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:

sage: g = DiGraph(graphs.PetersenGraph(), data_structure="static_sparse")


sage: g.in_degree(0)
3

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

3.7. Static sparse graph backend 605


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: g = DiGraph(graphs.PetersenGraph(), data_structure="static_sparse")


sage: g.neighbors_in(0)
[1, 4, 5]

iterator_nbrs(v)
Returns the neighbors of a vertex
INPUT:
• v – a vertex
EXAMPLES:

sage: g = Graph(graphs.PetersenGraph(), data_structure="static_sparse")


sage: g.neighbors(0)
[1, 4, 5]

iterator_out_edges(vertices, labels)
Iterate over the outbound edges incident to a sequence of vertices.
INPUT:
• vertices – a list of vertices
• labels – whether to return labels too
iterator_out_nbrs(v)
Returns the out-neighbors of a vertex
INPUT:
• v – a vertex
EXAMPLES:

sage: g = DiGraph(graphs.PetersenGraph(), data_structure="static_sparse")


sage: g.neighbors_out(0)
[1, 4, 5]

606 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: g = DiGraph(graphs.PetersenGraph(), data_structure="static_sparse")


sage: g.out_degree(0)
3

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:

3.7. Static sparse graph backend 607


Sage Reference Manual: Graph Theory, Release 8.4

• 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

3.8 Backends for Sage (di)graphs.

This module implements GenericGraphBackend (the base class for backends).


Any graph backend must redefine the following methods (for which GenericGraphBackend raises a
NotImplementedError)

608 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

add_edge() Add an edge (𝑢, 𝑣) to self, with label 𝑙.


add_edges() Add a sequence of edges to self.
add_vertex() Add a labelled vertex to self.
add_vertices() Add labelled vertices to self.
degree() Return the total number of vertices incident to 𝑣.
in_degree() Return the in-degree of 𝑣
out_degree() Return the out-degree of 𝑣
del_edge() Delete the edge (𝑢, 𝑣) with label 𝑙.
del_vertex() Delete a labelled vertex in self.
del_vertices() Delete labelled vertices in self.
get_edge_label() Return the edge label of (𝑢, 𝑣).
has_edge() True if self has an edge (𝑢, 𝑣) with label 𝑙.
has_vertex() True if self has a vertex with label 𝑣.
iterator_edges() Iterate over the edges incident to a sequence of vertices.
iterator_in_edges() Iterate over the incoming edges incident to a sequence of vertices.
iterator_out_edges() Iterate over the outbound edges incident to a sequence of vertices.
iterator_nbrs() Iterate over the vertices adjacent to 𝑣.
iterator_in_nbrs() Iterate over the vertices u such that the edge (𝑢, 𝑣) is in self (that is, prede-
cessors of 𝑣).
iterator_out_nbrs() Iterate over the vertices u such that the edge (𝑣, 𝑢) is in self (that is, successors
of 𝑣).
iterator_verts() Iterate over the vertices 𝑣 with labels in verts.
loops() Get/set whether or not self allows loops.
multiple_edges() Get/set whether or not self allows multiple edges.
name() Get/set name of self.
num_edges() The number of edges in self
num_verts() The number of vertices in self
relabel() Relabel the vertices of self by a permutation.
set_edge_label() Label the edge (𝑢, 𝑣) by 𝑙.

For an overview of graph data structures in sage, see overview.

3.8.1 Classes and methods

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:

3.8. Backends for Sage (di)graphs. 609


Sage Reference Manual: Graph Theory, Release 8.4

• edges – list/iterator of edges to be added.


• directed – boolean
add_vertex(name)
Add a labelled vertex to self.
INPUT:
• name – vertex label
OUTPUT:
If name=None, the new vertex name is returned, None otherwise.
add_vertices(vertices)
Add labelled vertices to self.
INPUT:
• vertices – iterator of vertex labels. A new label is created, used and returned in the output list for
all None values in vertices.
OUTPUT:
Generated names of new vertices if there is at least one None value present in vertices. None other-
wise.
EXAMPLES:

sage: G = sage.graphs.base.graph_backends.GenericGraphBackend()
sage: G.add_vertices([1,2,3])
Traceback (most recent call last):
...
NotImplementedError

degree(v, directed)
Return the total number of vertices incident to 𝑣.
INPUT:
• v – a vertex label
• directed – boolean
OUTPUT:
degree of 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

610 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

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

3.8. Backends for Sage (di)graphs. 611


Sage Reference Manual: Graph Theory, Release 8.4

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.

612 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

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:

3.8. Backends for Sage (di)graphs. 613


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.base.graph_backends import NetworkXDiGraphDeprecated


˓→as NXDGD

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: from sage.graphs.base.graph_backends import NetworkXGraphDeprecated as


˓→NXGD

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.graphs.base.graph_backends.unpickle_graph_backend(directed, vertices, edges,


kwds)
Return a backend from its pickled data
This methods is defined because Python’s pickling mechanism can only build objects from a pair (f,args)
by running f(*args). In particular, there is apparently no way to define a **kwargs (i.e. define the value of
keyword arguments of f), which means that one must know the order of all arguments of f (here, f is Graph
or DiGraph).
As a consequence, this means that the order cannot change in the future, which is something we cannot swear.
INPUT:
• directed (boolean)
• vertices – list of vertices.
• edges – list of edges
• kwds – any dictionary whose keywords will be forwarded to the graph constructor.
This function builds a Graph or DiGraph from its data, and returns the _backend attribute of this object.
EXAMPLES:

614 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.base.graph_backends import unpickle_graph_backend


sage: b = unpickle_graph_backend(0,[0,1,2,3],[(0,3,'label'),(0,0,1)],{'loops
˓→':True})

sage: b
<sage.graphs.base.sparse_graph.SparseGraphBackend object at ...>
sage: list(b.iterator_edges(range(4),1))
[(0, 0, 1), (0, 3, 'label')]

3.9 Interface to run Boost algorithms

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:

clustering_coeff() Returns the clustering coefficient of all vertices in the graph.


edge_connectivity() Returns the edge connectivity of the graph.
dominator_tree() Returns a dominator tree of the graph.
bandwidth_heuristics() Uses heuristics to approximate the bandwidth of the graph.
min_spanning_tree() Computes a minimum spanning tree of a (weighted) graph.
shortest_paths() Uses Dijkstra or Bellman-Ford algorithm to compute the single-source shortest
paths.
johnson_shortest_paths()Uses Johnson algorithm to compute the all-pairs shortest paths.
Uses Johnson algorithm to compute the closeness centrality of all vertices.
johnson_closeness_centrality()
Uses Tarjan’s algorithm to compute the blocks and cut vertices of the graph.
blocks_and_cut_vertices()

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.

3.9. Interface to run Boost algorithms 615


Sage Reference Manual: Graph Theory, Release 8.4

• 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: from sage.graphs.base.boost_graph import bandwidth_heuristics


sage: bandwidth_heuristics(graphs.PathGraph(10))
(1, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
sage: bandwidth_heuristics(graphs.GridGraph([3,3]))
(3, [(0, 0), (1, 0), (0, 1), (2, 0), (1, 1), (0, 2), (2, 1), (1, 2), (2, 2)])
sage: bandwidth_heuristics(graphs.GridGraph([3,3]), algorithm='king')
(3, [(0, 0), (1, 0), (0, 1), (2, 0), (1, 1), (0, 2), (2, 1), (1, 2), (2, 2)])

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: from sage.graphs.base.boost_graph import blocks_and_cut_vertices


sage: g = graphs.KrackhardtKiteGraph()
sage: blocks_and_cut_vertices(g)
([[8, 9], [7, 8], [0, 1, 2, 3, 5, 4, 6, 7]], [8, 7])

sage: G = Graph([(0,1,{'name':'a','weight':1}), (0,2,{'name':'b','weight':3}), (1,


˓→2,{'name':'b','weight':1})])

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).

616 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

OUTPUT: a pair (average_clustering_coefficient, clust_of_v), where


average_clustering_coefficient is the average clustering of the vertices in variable vertices,
clust_of_v is a dictionary that associates to each vertex its clustering coefficient. If vertices is None,
all vertices are considered.
EXAMPLES:
Computing the clustering coefficient of a clique:

sage: from sage.graphs.base.boost_graph import clustering_coeff


sage: g = graphs.CompleteGraph(5)
sage: clustering_coeff(g)
(1.0, {0: 1.0, 1: 1.0, 2: 1.0, 3: 1.0, 4: 1.0})
sage: clustering_coeff(g, vertices = [0,1,2])
(1.0, {0: 1.0, 1: 1.0, 2: 1.0})

Of a non-clique graph with triangles:

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:

3.9. Interface to run Boost algorithms 617


Sage Reference Manual: Graph Theory, Release 8.4

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}

An example with a directed graph:

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]}

If the output is a dictionary:

sage: graphs.GridGraph([2,2]).dominator_tree((0,0), return_dict=True)


{(0, 0): None, (0, 1): (0, 0), (1, 0): (0, 0), (1, 1): (0, 0)}

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:

sage: from sage.graphs.base.boost_graph import edge_connectivity


sage: g = graphs.CompleteGraph(5)
sage: edge_connectivity(g)
(4, [(0, 1), (0, 2), (0, 3), (0, 4)])

Vertex-labeled graphs:

618 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.base.boost_graph import edge_connectivity


sage: g = graphs.GridGraph([2,2])
sage: edge_connectivity(g)
(2, [((0, 0), (0, 1)), ((0, 0), (1, 0))])

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:

sage: from sage.graphs.base.boost_graph import johnson_closeness_centrality


sage: g = Graph([(0,1,1),(1,2,2),(1,3,4),(2,3,1)], weighted=True)
sage: johnson_closeness_centrality(g)
{0: 0.375, 1: 0.5, 2: 0.5, 3: 0.375}

Directed graphs:

sage: from sage.graphs.base.boost_graph import johnson_closeness_centrality


sage: g = DiGraph([(0,1,1),(1,2,-2),(1,3,4),(2,3,1)], weighted=True)
sage: johnson_closeness_centrality(g)
{0: inf, 1: -0.4444444444444444, 2: 0.3333333333333333}

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.

3.9. Interface to run Boost algorithms 619


Sage Reference Manual: Graph Theory, Release 8.4

EXAMPLES:
Undirected graphs:

sage: from sage.graphs.base.boost_graph import johnson_shortest_paths


sage: g = Graph([(0,1,1),(1,2,2),(1,3,4),(2,3,1)], weighted=True)
sage: johnson_shortest_paths(g)
{0: {0: 0, 1: 1, 2: 3, 3: 4},
1: {0: 1, 1: 0, 2: 2, 3: 3},
2: {0: 3, 1: 2, 2: 0, 3: 1},
3: {0: 4, 1: 3, 2: 1, 3: 0}}

Directed graphs:

sage: g = DiGraph([(0,1,1),(1,2,-2),(1,3,4),(2,3,1)], weighted=True)


sage: johnson_shortest_paths(g)
{0: {0: 0, 1: 1, 2: -1, 3: 0},
1: {1: 0, 2: -2, 3: -1},
2: {2: 0, 3: 1},
3: {3: 0}}

sage.graphs.base.boost_graph.min_spanning_tree(g, weight_function=None, algo-


rithm=’Kruskal’)
Uses Boost to compute the minimum spanning tree of the input graph.
INPUT:
• g (Graph) - the input graph.
• weight_function (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
weight_function can be used to transform the label into a weight (see the example below). In partic-
ular:
– if weight_function is not None, the weight of an edge e is weight_function(e);
– if weight_function is None (default) and g is weighted (that is, g.weighted()==True), for
each edge e=(u,v,l), we set weight l;
– if weight_function is None and g is not weighted, we set all weights to 1 (hence, the output can
be any spanning tree).
Note that, if the weight is not convertible to a number with function float(), an error is raised (see tests
below).
• algorithm ('Kruskal' or 'Prim') - the algorithm used.
OUTPUT:
The edges of a minimum spanning tree of g, if one exists, otherwise the empty list.
See also:

• sage.graphs.generic_graph.GenericGraph.min_spanning_tree()

EXAMPLES:

sage: from sage.graphs.base.boost_graph import min_spanning_tree


sage: min_spanning_tree(graphs.PathGraph(4))
[(0, 1, None), (1, 2, None), (2, 3, None)]

(continues on next page)

620 Chapter 3. Low-level implementation


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: G = Graph([(0,1,{'name':'a','weight':1}), (0,2,{'name':'b','weight':3}), (1,
˓→2,{'name':'b','weight':1})])

sage: min_spanning_tree(G, weight_function=lambda e: e[2]['weight'])


[(0, 1, {'name': 'a', 'weight': 1}), (1, 2, {'name': 'b', 'weight': 1})]

sage.graphs.base.boost_graph.shortest_paths(g, start, weight_function=None, algo-


rithm=None)
Computes the shortest paths from start to all other vertices.
This routine outputs all shortest paths from node start to any other node in the graph. The input graph can be
weighted: if the algorithm is Dijkstra, no negative weights are allowed, while if the algorithm is Bellman-Ford,
negative weights are allowed, but there must be no negative cycle (otherwise, the shortest paths might not exist).
However, Dijkstra algorithm is more efficient: for this reason, we suggest to use Bellman-Ford only if necessary
(which is also the default option). Note that, if the graph is undirected, a negative edge automatically creates a
negative cycle: for this reason, in this case, Dijkstra algorithm is always better.
The running-time is 𝑂(𝑛 log 𝑛 + 𝑚) for Dijkstra algorithm and 𝑂(𝑚𝑛) for Bellman-Ford algorithm, where 𝑛 is
the number of nodes and 𝑚 is the number of edges.
INPUT:
• g (generic_graph) - the input graph.
• start (vertex) - the starting vertex to compute shortest paths.
• weight_function (function) - a function that associates a weight to each edge. If None (default), the
weights of g are used, if available, otherwise all edges have weight 1.
• algorithm (string) - one of the following algorithms:
– 'Dijkstra','Dijkstra_Boost': the Dijkstra algorithm implemented in Boost (works only
with positive weights).
– 'Bellman-Ford','Bellman-Ford_Boost': the Bellman-Ford algorithm implemented in
Boost (works also with negative weights, if there is no negative cycle).
OUTPUT:
A pair of dictionaries (distances, predecessors) such that, for each vertex v, distances[v] is
the distance from start to v, predecessors[v] is the last vertex in a shortest path from start to v.
EXAMPLES:
Undirected graphs:

sage: from sage.graphs.base.boost_graph import shortest_paths


sage: g = Graph([(0,1,1),(1,2,2),(1,3,4),(2,3,1)], weighted=True)
sage: shortest_paths(g, 1)
({0: 1, 1: 0, 2: 2, 3: 3}, {0: 1, 1: None, 2: 1, 3: 2})
sage: g = graphs.GridGraph([2,2])
sage: shortest_paths(g,(0,0),weight_function=lambda e:2)
({(0, 0): 0, (0, 1): 2, (1, 0): 2, (1, 1): 4},
{(0, 0): None, (0, 1): (0, 0), (1, 0): (0, 0), (1, 1): (0, 1)})

Directed graphs:

sage: g = DiGraph([(0,1,1),(1,2,2),(1,3,4),(2,3,1)], weighted=True)


sage: shortest_paths(g, 1)
({1: 0, 2: 2, 3: 3}, {1: None, 2: 1, 3: 2})

3.9. Interface to run Boost algorithms 621


Sage Reference Manual: Graph Theory, Release 8.4

622 Chapter 3. Low-level implementation


CHAPTER

FOUR

HYPERGRAPHS

4.1 Hypergraph generators

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:

sage: hypergraphs.BinomialRandomUniform(50, 3, 1).num_blocks()


19600
sage: hypergraphs.BinomialRandomUniform(50, 3, 0).num_blocks()
0

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:

sage: H = hypergraphs.UniformRandomUniform(52, 3, 17)


sage: H
Incidence structure with 52 points and 17 blocks
sage: H.is_connected()
False

nauty(number_of_sets, number_of_vertices, multiple_sets=False, vertex_min_degree=None,


vertex_max_degree=None, set_max_size=None, set_min_size=None, regular=False, uni-
form=False, max_intersection=None, connected=False, options=”, debug=False)
Enumerates hypergraphs up to isomorphism using Nauty.
INPUT:
• number_of_sets, number_of_vertices (integers)
• multiple_sets (boolean) – whether to allow several sets of the hypergraph to be equal (set to
False by default).
• vertex_min_degree, vertex_max_degree (integers) – define the maximum and minimum
degree of an element from the ground set (i.e. the number of sets which contain it). Set to None by
default.
• set_min_size, set_max_size (integers) – define the maximum and minimum size of a set. Set
to None by default.
• regular (integer) – if set to an integer value 𝑘, requires the hypergraphs to be 𝑘-regular. It is actually
a shortcut for the corresponding min/max values.
• uniform (integer) – if set to an integer value 𝑘, requires the hypergraphs to be 𝑘-uniform. It is
actually a shortcut for the corresponding min/max values.
• max_intersection (integer) – constraints the maximum cardinality of the intersection of two
sets fro the hypergraphs. Set to None by default.
• connected (boolean) – whether to require the hypergraphs to be connected. Set to False by
default.
• debug (boolean) – if True the first line of genbg’s output to standard error is captured and the first
call to the generator’s next() function will return this line as a string. A line leading with “>A”
indicates a successful initiation of the program with some information on the arguments, while a line
beginning with “>E” indicates an error with the input.
• options (string) – anything else that should be forwarded as input to Nauty’s genbg. See its docu-
mentation for more information : http://cs.anu.edu.au/~bdm/nauty/.

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))]

624 Chapter 4. Hypergraphs


Sage Reference Manual: Graph Theory, Release 8.4

Only connected ones:

sage: list(hypergraphs.nauty(2,2, connected = True))


[((0,), (0, 1))]

Non-empty sets only:

sage: list(hypergraphs.nauty(3,2, set_min_size = 1))


[((0,), (1,), (0, 1))]

The Fano Plane, as the only 3-uniform hypergraph with 7 sets and 7 vertices:

sage: fano = next(hypergraphs.nauty(7, 7, uniform=3, max_intersection=1))


sage: print(fano)
((0, 1, 2), (0, 3, 4), (0, 5, 6), (1, 3, 5), (2, 4, 5), (2, 3, 6), (1, 4, 6))

The Fano Plane, as the only 3-regular hypergraph with 7 sets and 7 vertices:

sage: fano = next(hypergraphs.nauty(7, 7, regular=3, max_intersection=1))


sage: print(fano)
((0, 1, 2), (0, 3, 4), (0, 5, 6), (1, 3, 5), (2, 4, 5), (2, 3, 6), (1, 4, 6))

4.2 Incidence structures (i.e. hypergraphs, i.e. set systems)

An incidence structure is specified by a list of points, blocks, or an incidence matrix (1 ,2 ). IncidenceStructure


instances have the following methods:

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.

4.2. Incidence structures (i.e. hypergraphs, i.e. set systems) 625


Sage Reference Manual: Graph Theory, Release 8.4

Table 1 – continued from previous page


is_regular() Test whether the incidence structure is 𝑟-regular.
is_resolvable() Test whether the hypergraph is resolvable
is_simple() Test whether this design is simple (i.e. no repeated block).
is_t_design() Test whether self is a 𝑡 − (𝑣, 𝑘, 𝑙) design.
is_uniform() Test whether the incidence structure is 𝑘-uniform
Iterates over all copies of H2 contained in self.
isomorphic_substructures_iterator()
num_blocks() Return the number of blocks.
num_points() Return the size of the ground set.
packing() Return a maximum packing
rank() Return the rank of the hypergraph (the maximum size of a block).
relabel() Relabel the ground set
trace() Return the trace of a set of points.

REFERENCES:
AUTHORS:
• Peter Dobcsanyi and David Joyner (2007-2008)
This is a significantly modified form of part of the module block_design.py (version 0.6) written by Peter
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.

626 Chapter 4. Hypergraphs


Sage Reference Manual: Graph Theory, Release 8.4

• incidence_matrix – a binary incidence matrix. Each column represents a set.


• name (a string, such as “Fano plane”).
• check – whether to check the input
• copy – (use with caution) if set to False then blocks must be a list of lists of integers. The list will not
be copied but will be modified in place (each block is sorted, and the whole list is sorted). Your blocks
object will become the IncidenceStructure instance’s internal data.
EXAMPLES:
An incidence structure can be constructed by giving the number of points and the list of blocks:

sage: IncidenceStructure(7, [[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,


˓→5]])

Incidence structure with 7 points and 7 blocks

Only providing the set of blocks is sufficient. In this case, the ground set is defined as the union of the blocks:

sage: IncidenceStructure([[1,2,3],[2,3,4]])
Incidence structure with 4 points and 2 blocks

Or by its adjacency matrix (a {0, 1}-matrix in which rows are indexed by points and columns by blocks):

sage: m = matrix([[0,1,0],[0,0,1],[1,0,1],[1,1,1]])
sage: IncidenceStructure(m)
Incidence structure with 4 points and 3 blocks

The points can be any (hashable) object:

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):

sage: A = IncidenceStructure([0,1,2], [[0],[0,2]])


sage: B = IncidenceStructure([1,0,2], [[0],[2,0]])
sage: B == A
True

sage: C = BlockDesign(2, [[0], [1,0]])


sage: D = BlockDesign(2, [[0,1], [0]])
sage: C == D
True

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:

sage: blocks = [[0,1],[2,0],[1,2]] # a list of lists of integers


sage: I = IncidenceStructure(3, blocks, copy=False)
sage: I._blocks is blocks
True

4.2. Incidence structures (i.e. hypergraphs, i.e. set systems) 627


Sage Reference Manual: Graph Theory, Release 8.4

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

A non self-dual example:


sage: IS = IncidenceStructure(list(range(4)), [[0,1,2,3],[1,2,3]])
sage: IS.automorphism_group().cardinality()
6
sage: IS.dual().automorphism_group().cardinality()
1

Examples with non-integer points:


sage: I = IncidenceStructure('abc', ('ab','ac','bc'))
sage: I.automorphism_group()
Permutation Group with generators [('b','c'), ('a','b')]
sage: IncidenceStructure([[(1,2),(3,4)]]).automorphism_group()
Permutation Group with generators [((1,2),(3,4))]

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.

628 Chapter 4. Hypergraphs


Sage Reference Manual: Graph Theory, Release 8.4

EXAMPLES:

sage: fano1 = designs.balanced_incomplete_block_design(7,3)


sage: fano2 = designs.projective_plane(2)
sage: fano1 == fano2
False
sage: fano1.relabel(fano1.canonical_label())
sage: fano2.relabel(fano2.canonical_label())
sage: fano1 == fano2
True

coloring(k=None, solver=None, verbose=0)


Compute a (weak) 𝑘-coloring of the hypergraph
A weak coloring of a hypergraph ℋ is an assignment of colors to its vertices such that no set is monochro-
matic.
INPUT:
• k (integer) – compute a coloring with 𝑘 colors if an integer is provided, otherwise returns an optimal
coloring (i.e. with the minimum possible number of colors).
• solver – (default: None) Specify a 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 – non-negative integer (default: 0). Set the level of verbosity you want from the linear
program solver. Since the problem is 𝑁 𝑃 -complete, its solving may take some time depending on the
graph. A value of 0 means that there will be no message printed by the solver.
EXAMPLES:
The Fano plane has chromatic number 3:

sage: len(designs.steiner_triple_system(7).coloring())
3

One admissible 3-coloring:

sage: designs.steiner_triple_system(7).coloring() # not tested - architecture-


˓→dependent

[[0, 2, 5, 1], [4, 3], [6]]

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) –

4.2. Incidence structures (i.e. hypergraphs, i.e. set systems) 629


Sage Reference Manual: Graph Theory, Release 8.4

– 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: bibd = designs.balanced_incomplete_block_design(13,4)


sage: bibd.is_t_design(return_parameters=True)
(True, (2, 13, 4, 1))
sage: bibd.complement().is_t_design(return_parameters=True)
(True, (2, 13, 9, 6))

The “uniform” complement of a graph is a graph:

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

630 Chapter 4. Hypergraphs


Sage Reference Manual: Graph Theory, Release 8.4

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}

In a Steiner triple system, all pairs have degree 1:

sage: S13 = designs.steiner_triple_system(13)


sage: all(v == 1 for v in S13.degrees(2).values())
True

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.

4.2. Incidence structures (i.e. hypergraphs, i.e. set systems) 631


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: IncidenceStructure(3, [[0,1],[0,2]]).ground_set()


[0, 1, 2]

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 = 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.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:

632 Chapter 4. Hypergraphs


Sage Reference Manual: Graph Theory, Release 8.4

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]
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]

sage: I = IncidenceStructure('abc', ('ab','abc','ac','c'))


sage: I.incidence_matrix()
[1 1 1 0]
[1 1 0 0]
[0 1 1 1]

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):

sage: BIBD = designs.balanced_incomplete_block_design(19,3)


sage: G = BIBD.intersection_graph(1)
(continues on next page)

4.2. Incidence structures (i.e. hypergraphs, i.e. set systems) 633


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: G.is_strongly_regular(parameters=True)
(57, 24, 11, 9)

is_connected()
Test whether the design is connected.
EXAMPLES:

sage: IncidenceStructure(3, [[0,1],[0,2]]).is_connected()


True
sage: IncidenceStructure(4, [[0,1],[2,3]]).is_connected()
False

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

This is actually a regular generalized quadrangle:

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.

634 Chapter 4. Hypergraphs


Sage Reference Manual: Graph Theory, Release 8.4

• certificate (boolean) – whether to return an isomorphism from self to other instead of a


boolean answer.
EXAMPLES:

sage: fano1 = designs.balanced_incomplete_block_design(7,3)


sage: fano2 = designs.projective_plane(2)
sage: fano1.is_isomorphic(fano2)
True
sage: fano1.is_isomorphic(fano2,certificate=True)
{0: 0, 1: 1, 2: 2, 3: 6, 4: 4, 5: 3, 6: 5}

is_regular(r=None)
Test whether the incidence structure is 𝑟-regular.
An incidence structure is said to be 𝑟-regular if all its points are incident with exactly 𝑟 blocks.
INPUT:
• r (integer)
OUTPUT:
If r is defined, a boolean is returned. If r is set to None (default), the method returns either False or the
integer r such that the incidence structure is 𝑟-regular.

Warning: In case of 0-regular incidence structure, beware that if not H.is_regular() is a


satisfied condition.

EXAMPLES:

sage: designs.balanced_incomplete_block_design(7,3).is_regular()
3
sage: designs.balanced_incomplete_block_design(7,3).is_regular(r=3)
True
sage: designs.balanced_incomplete_block_design(7,3).is_regular(r=4)
False

is_resolvable(certificate=False, solver=None, verbose=0, check=True)


Test whether the hypergraph is resolvable
A hypergraph is said to be resolvable if its sets can be partitionned into classes, each of which is a partition
of the ground set.

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.

4.2. Incidence structures (i.e. hypergraphs, i.e. set systems) 635


Sage Reference Manual: Graph Theory, Release 8.4

• 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]]]

sage: b,cls = AG.is_resolvable(True)


sage: b
True
sage: cls # random
[[[6, 7], [4, 5], [0, 1], [2, 3]],
[[5, 7], [0, 4], [3, 6], [1, 2]],
[[0, 2], [4, 7], [1, 3], [5, 6]],
[[3, 4], [0, 7], [1, 5], [2, 6]],
[[3, 7], [1, 6], [0, 5], [2, 4]],
[[0, 6], [2, 7], [1, 4], [3, 5]],
[[4, 6], [0, 3], [2, 5], [1, 7]]]

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)

636 Chapter 4. Hypergraphs


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: I2 = IncidenceStructure(V, B*2)
sage: I2.is_simple()
False

is_t_design(t=None, v=None, k=None, l=None, return_parameters=False)


Test whether self is a 𝑡 − (𝑣, 𝑘, 𝑙) design.
A 𝑡 − (𝑣, 𝑘, 𝜆) (sometimes called 𝑡-design for short) is a block design in which:
• the underlying set has cardinality 𝑣
• the blocks have size 𝑘
• each 𝑡-subset of points is covered by 𝜆 blocks
INPUT:
• t,v,k,l (integers) – their value is set to None by default. The function tests whether the design is a
t-(v,k,l) design using the provided values and guesses the others. Note that 𝑙‘ cannot be specified
if t is not.
• return_parameters (boolean)– whether to return the parameters of the 𝑡-design. If set to True,
the function returns a pair (boolean_answer,(t,v,k,l)).
EXAMPLES:

sage: fano_blocks = [[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]]


sage: BD = IncidenceStructure(7, fano_blocks)
sage: BD.is_t_design()
True
sage: BD.is_t_design(return_parameters=True)
(True, (2, 7, 3, 1))
sage: BD.is_t_design(2, 7, 3, 1)
True
sage: BD.is_t_design(1, 7, 3, 3)
True
sage: BD.is_t_design(0, 7, 3, 7)
True

sage: BD.is_t_design(0,6,3,7) or BD.is_t_design(0,7,4,7) or BD.is_t_design(0,


˓→7,3,8)

False

sage: BD = designs.AffineGeometryDesign(3, 1, GF(2))


sage: BD.is_t_design(1)
True
sage: BD.is_t_design(2)
True

Steiner triple and quadruple systems are other names for 2 − (𝑣, 3, 1) and 3 − (𝑣, 4, 1) designs:

sage: S3_9 = designs.steiner_triple_system(9)


sage: S3_9.is_t_design(2,9,3,1)
True

sage: blocks = designs.steiner_quadruple_system(8)


sage: S4_8 = IncidenceStructure(8, blocks)
sage: S4_8.is_t_design(3,8,4,1)
True
(continues on next page)

4.2. Incidence structures (i.e. hypergraphs, i.e. set systems) 637


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)

sage: blocks = designs.steiner_quadruple_system(14)


sage: S4_14 = IncidenceStructure(14, blocks)
sage: S4_14.is_t_design(3,14,4,1)
True

Some examples of Witt designs that need the gap database:

sage: BD = designs.WittDesign(9) # optional - gap_packages


sage: BD.is_t_design(2,9,3,1) # optional - gap_packages
True
sage: W12 = designs.WittDesign(12) # optional - gap_packages
sage: W12.is_t_design(5,12,6,1) # optional - gap_packages
True
sage: W12.is_t_design(4) # optional - gap_packages
True

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],[0,2],[0,3]])


sage: D.is_t_design(return_parameters=True)
(True, (0, 4, 2, 3))

sage: D = IncidenceStructure(4, [[0],[1],[2],[3]])


sage: D.is_t_design(return_parameters=True)
(True, (1, 4, 1, 1))

sage: D = IncidenceStructure(4,[[0,1],[2,3]])
sage: D.is_t_design(return_parameters=True)
(True, (1, 4, 2, 1))

sage: D = IncidenceStructure(4, [list(range(4))])


sage: D.is_t_design(return_parameters=True)
(True, (4, 4, 4, 1))

is_uniform(k=None)
Test whether the incidence structure is 𝑘-uniform
An incidence structure is said to be 𝑘-uniform if all its blocks have size 𝑘.
INPUT:
• k (integer)
OUTPUT:
If k is defined, a boolean is returned. If k is set to None (default), the method returns either False or the
integer k such that the incidence structure is 𝑘-uniform.

Warning: In case of 0-uniform incidence structure, beware that if not H.is_uniform() is a


satisfied condition.

EXAMPLES:

638 Chapter 4. Hypergraphs


Sage Reference Manual: Graph Theory, Release 8.4

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: for f in IP.isomorphic_substructures_iterator(IC):


....: assert all(P.has_edge(f[x],f[y]) for x,y in C.edges(labels=False))

The number of induced copies, in this case, is the same:

sage: sum(1 for _ in IP.isomorphic_substructures_iterator(IC,induced=True))


120

They begin to differ if we make one vertex universal:

sage: P.add_edges([(0,x) for x in P], loops=False)


sage: IP = IncidenceStructure(P.edges(labels=False))
sage: IC = IncidenceStructure(C.edges(labels=False))
sage: sum(1 for _ in IP.isomorphic_substructures_iterator(IC))
420
sage: sum(1 for _ in IP.isomorphic_substructures_iterator(IC,induced=True))
60

The number of copies of 𝐻 in itself is the size of its automorphism group:

4.2. Incidence structures (i.e. hypergraphs, i.e. set systems) 639


Sage Reference Manual: Graph Theory, Release 8.4

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:

640 Chapter 4. Hypergraphs


Sage Reference Manual: Graph Theory, Release 8.4

sage: h = Hypergraph(8, [[0,1,3],[1,4,5,6],[1,2]])


sage: h.rank()
4

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
˓→']]

Relabel to integer points:

sage: TD.relabel()
sage: TD.blocks()[:3]
[[0, 5, 10, 15, 20], [0, 6, 12, 18, 24], [0, 7, 14, 16, 23]]

trace(points, min_size=1, multiset=True)


Return the trace of a set of points.
Given an hypergraph ℋ, the trace of a set 𝑋 of points in ℋ is the hypergraph whose blocks are all non-
empty 𝑆 ∩ 𝑋 where 𝑆 ∈ ℋ.
INPUT:
• points – a set of points.
• min_size (integer; default 1) – minimum size of the sets to keep. By default all empty sets are
discarded, i.e. min_size=1.
• multiset (boolean; default True) – whether to keep multiple copies of the same set.

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:

4.2. Incidence structures (i.e. hypergraphs, i.e. set systems) 641


Sage Reference Manual: Graph Theory, Release 8.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

642 Chapter 4. Hypergraphs


CHAPTER

FIVE

LIBRARIES OF ALGORITHMS

5.1 Graph coloring

This module gathers all methods related to graph coloring. Here is what it can do :
Proper vertex coloring

all_graph_colorings() Computes all 𝑛-colorings a graph


first_coloring() Returns the first vertex coloring found
number_of_n_colorings() Computes the number of 𝑛-colorings of a graph
numbers_of_colorings() Computes the number of colorings of a graph
chromatic_number() Returns the chromatic number of the graph
vertex_coloring() Computes Vertex colorings and chromatic numbers

Other colorings

grundy_coloring() Computes Grundy numbers and Grundy colorings


b_coloring() Computes a b-chromatic numbers and b-colorings
edge_coloring() Compute chromatic index and edge colorings
round_robin() Computes a round-robin coloring of the complete graph on 𝑛 vertices
linear_arboricity() Computes the linear arboricity of the given graph
acyclic_edge_coloring() Computes an acyclic edge coloring of the current graph

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:

644 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.graph_coloring import acyclic_edge_coloring


sage: g = graphs.CompleteGraph(8)
sage: colors = acyclic_edge_coloring(g)

Each color class is of course a matching

sage: all([max(gg.degree())<=1 for gg in colors])


True

These matchings being a partition of the edge set:

sage: all([ any([gg.has_edge(e) for gg in colors]) for e in g.edges(labels =


˓→False)])

True

Besides, the union of any two of them is a forest

sage: all([g1.union(g2).is_forest() for g1 in colors for g2 in colors])


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.

The optimal coloring give us 3 classes:

sage: colors = acyclic_edge_coloring(g, k=None)


sage: len(colors)
3

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.

5.1. Graph coloring 645


Sage Reference Manual: Graph Theory, Release 8.4

• 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:

sage: from sage.graphs.graph_coloring import all_graph_colorings


sage: G = Graph({0:[1,2,3],1:[2]})
sage: n = 0
sage: for C in all_graph_colorings(G,3,hex_colors=True):
....: parts = [C[k] for k in C]
....: for P in parts:
....: l = len(P)
....: for i in range(l):
....: for j in range(i+1,l):
....: if G.has_edge(P[i],P[j]):
....: raise RuntimeError("Coloring Failed.")
....: n+=1
sage: print("G has %s 3-colorings." % n)
G has 12 3-colorings.

sage.graphs.graph_coloring.b_coloring(g, k, value_only=True, solver=None, verbose=0)


Computes a b-coloring with at most k colors that maximizes the number of colors, if such a coloring exists
Definition :
Given a proper coloring of a graph 𝐺 and a color class 𝐶 such that none of its vertices have neighbors in all
the other color classes, one can eliminate color class 𝐶 assigning to each of its elements a missing color in its
neighborhood.
Let a b-vertex be a vertex with neighbors in all other colorings. Then, one can repeat the above procedure until
a coloring is obtained where every color class contains a b-vertex, in which case none of the color classes can
be eliminated with the same ideia. So, one can define a b-coloring as a proper coloring where each color class
has a b-vertex.
In the worst case, after successive applications of the above procedure, one get a proper coloring that uses a
number of colors equal to the the b-chromatic number of 𝐺 (denoted 𝜒𝑏 (𝐺)): the maximum 𝑘 such that 𝐺
admits a b-coloring with 𝑘 colors.
An useful upper bound for calculating the b-chromatic number is the following. If G admits a b-coloring with
k colors, then there are 𝑘 vertices of degree at least 𝑘 − 1 (the b-vertices of each color class). So, if we set
𝑚(𝐺) = 𝑚𝑎𝑥 {𝑘|‘𝑡ℎ𝑒𝑟𝑒𝑎𝑟𝑒𝑘𝑣𝑒𝑟𝑡𝑖𝑐𝑒𝑠𝑜𝑓 𝑑𝑒𝑔𝑟𝑒𝑒𝑎𝑡𝑙𝑒𝑎𝑠𝑡‘𝑘 − 1}, we have that 𝜒𝑏 (𝐺) ≤ 𝑚(𝐺).

646 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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: from sage.graphs.graph_coloring import b_coloring


sage: g = graphs.PathGraph(5)
sage: b_coloring(g, 5)
3

The b-chromatic number of the Petersen Graph 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: from sage.graphs.graph_coloring import chromatic_number


sage: G = Graph({0:[1,2,3],1:[2]})
sage: chromatic_number(G)
3

sage: G = graphs.PetersenGraph()
sage: G.chromatic_number()
3

sage.graphs.graph_coloring.edge_coloring(g, value_only=False, vizing=False,


hex_colors=False, solver=None, verbose=0)
Compute chromatic index and edge colorings.
INPUT:

5.1. Graph coloring 647


Sage Reference Manual: Graph Theory, Release 8.4

• 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:

• Wikipedia article Edge_coloring for further details on edge coloring


• chromatic_index()
• fractional_chromatic_index()
• chromatic_number()
• sage.graphs.graph_coloring.vertex_coloring()

EXAMPLES:
The Petersen graph has chromatic index 4:

648 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.graph_coloring import edge_coloring


sage: g = graphs.PetersenGraph()
sage: edge_coloring(g, value_only=True, solver='GLPK')
4
sage: edge_coloring(g, value_only=False, solver='GLPK')
[[(0, 1), (2, 3), (4, 9), (5, 7)],
[(0, 4), (1, 2), (3, 8), (6, 9)],
[(1, 6), (5, 8), (7, 9)],
[(0, 5), (2, 7), (3, 4), (6, 8)]]
sage: edge_coloring(g, value_only=False, hex_colors=True, solver='GLPK')
{'#00ffff': [(1, 6), (5, 8), (7, 9)],
'#7f00ff': [(0, 5), (2, 7), (3, 4), (6, 8)],
'#7fff00': [(0, 4), (1, 2), (3, 8), (6, 9)],
'#ff0000': [(0, 1), (2, 3), (4, 9), (5, 7)]}

Complete graphs are colored using the linear-time round-robin coloring:

sage: from sage.graphs.graph_coloring import edge_coloring


sage: len(edge_coloring(graphs.CompleteGraph(20)))
19

The chromatic index of a non connected graph is the maximum over its connected components:

sage: g = graphs.CompleteGraph(4) + graphs.CompleteGraph(10)


sage: edge_coloring(g, value_only=True)
9

sage.graphs.graph_coloring.first_coloring(G, n=0, hex_colors=False)


Given a graph, and optionally a natural number 𝑛, returns the first coloring we find with at least 𝑛 colors.
INPUT:
• 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).
• n – The minimal number of colors to try.
EXAMPLES:

sage: from sage.graphs.graph_coloring import first_coloring


sage: G = Graph({0: [1, 2, 3], 1: [2]})
sage: first_coloring(G, 3)
[[1, 3], [0], [2]]

sage.graphs.graph_coloring.grundy_coloring(g, k, value_only=True, solver=None, ver-


bose=0)
Computes the worst-case of a first-fit coloring with less than 𝑘 colors.
Definition :
A first-fit coloring is obtained by sequentially coloring the vertices of a graph, assigning them the smallest color
not already assigned to one of its neighbors. The result is clearly a proper coloring, which usually requires much
more colors than an optimal vertex coloring of the graph, and heavily depends on the ordering of the vertices.
The number of colors required by the worst-case application of this algorithm on a graph 𝐺 is called the Grundy
number, written Γ(𝐺).
Equivalent formulation :
Equivalently, a Grundy coloring is a proper vertex coloring such that any vertex colored with 𝑖 has, for every
𝑗 < 𝑖, a neighbor colored with 𝑗. This can define a Linear Program, which is used here to compute the Grundy

5.1. Graph coloring 649


Sage Reference Manual: Graph Theory, Release 8.4

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: from sage.graphs.graph_coloring import grundy_coloring


sage: g = graphs.PathGraph(4)
sage: grundy_coloring(g, 4)
3

The Grundy number of the PetersenGraph is equal to 4:

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 ⌉.

It is conjectured in [Aki1980] that 𝑙𝑎(𝐺) ≤ ⌈ Δ(𝐺)+1


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).

650 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

– 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.

– If 0, computes a decomposition of 𝐺 into ⌈ Δ(𝐺)


2 ⌉ forests of paths

– If 1, computes a decomposition of 𝐺 into ⌈ Δ(𝐺)+1


2 ⌉ colors, which is the conjectured general bound.
– If plus_one = None (default), computes a decomposition using the least possible number of col-
ors.
• 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
COMPLEXITY:
NP-Hard
EXAMPLES:
Obviously, a square grid has a linear arboricity of 2, as the set of horizontal lines and the set of vertical lines are
an admissible partition:

sage: from sage.graphs.graph_coloring import linear_arboricity


sage: g = graphs.GridGraph([4,4])
sage: g1,g2 = linear_arboricity(g)

Each graph is of course a forest:

sage: g1.is_forest() and g2.is_forest()


True

Of maximum degree 2:

sage: max(g1.degree()) <= 2 and max(g2.degree()) <= 2


True

Which constitutes a partition of the whole edge set:

sage: all([g1.has_edge(e) or g2.has_edge(e) for e in g.edges(labels = None)])


True

sage.graphs.graph_coloring.number_of_n_colorings(G, n)
Computes the number of 𝑛-colorings of a graph
EXAMPLES:

5.1. Graph coloring 651


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.graph_coloring import number_of_n_colorings


sage: G = Graph({0:[1,2,3],1:[2]})
sage: number_of_n_colorings(G,3)
12

sage.graphs.graph_coloring.numbers_of_colorings(G)
Returns the number of 𝑛-colorings of the graph 𝐺 for 𝑛 from 0 to |𝑉 |.
EXAMPLES:

sage: from sage.graphs.graph_coloring import numbers_of_colorings


sage: G = Graph({0:[1,2,3],1:[2]})
sage: numbers_of_colorings(G)
[0, 0, 0, 12, 72]

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: from sage.graphs.graph_coloring import round_robin


sage: round_robin(3).edges()
[(0, 1, 2), (0, 2, 1), (1, 2, 0)]

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

sage.graphs.graph_coloring.vertex_coloring(g, k=None, value_only=False,


hex_colors=False, solver=None, verbose=0)
Computes the chromatic number of the given graph or tests its 𝑘-colorability.

652 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: from sage.graphs.graph_coloring import vertex_coloring


sage: g = graphs.PetersenGraph()
sage: vertex_coloring(g, value_only=True)
3

5.2 Interface with Cliquer (clique-related problems)

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. Interface with Cliquer (clique-related problems) 653


Sage Reference Manual: Graph Theory, Release 8.4

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.ChvatalGraph().cliques_maximum() # indirect doctest


[[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_maximum()
[[0, 1, 2], [0, 1, 3]]
sage: C=graphs.PetersenGraph()
sage: C.cliques_maximum()
[[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_maximum()
[[1, 2, 3, 4]]

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:

654 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

sage: C=graphs.PetersenGraph()
sage: from sage.graphs.cliquer import max_clique
sage: max_clique(C)
[7, 9]

5.3 Centrality

This module is meant for all functions related to centrality in networks.

centrality_betweenness()Return the centrality betweenness of 𝐺


Return the k most closeness central vertices of 𝐺
centrality_closeness_top_k()
Return an estimation of the closeness centrality of 𝐺.
centrality_closeness_random_k()

5.3.1 Functions

sage.graphs.centrality.centrality_betweenness(G, exact=False, normalize=True)


Return the centrality betweenness of 𝐺
The centrality betweenness of a vertex 𝑣 ∈ 𝐺 is defined by:
∑︁ #{shortest 𝑠𝑡 − paths containing v}
𝑐(𝑣) =
#{shortest 𝑠𝑡 − paths}
𝑠̸=𝑣̸=𝑡

For more information, see the Wikipedia article Betweenness_centrality.


INPUT:
• G – a (di)graph
• exact (boolean, default: False) – whether to compute over rationals or on double C variables.
(︀𝑛−1)︀
• normalize (boolean; default: True) – whether to renormalize the values by dividing them by 2
(for graphs) or 2 𝑛−1
(︀ )︀
2 (for digraphs).
ALGORITHM:
To compute 𝑐(𝑣), we fix 𝑠 and define 𝑐𝑠 (𝑣) as the
∑︀ centrality of 𝑣 due to 𝑠, obtained from the formula above by
running the sum over 𝑡 only. We obtain 𝑐(𝑣) = 𝑠̸=𝑣 𝑐𝑠 (𝑣).
For every vertex 𝑠, we compute the value of 𝑐𝑠 (𝑣) for all 𝑣, using the following remark (see [Brandes01]):
Let 𝑣1 , ..., 𝑣𝑘 be the out-neighbors of 𝑣 such that 𝑑𝑖𝑠𝑡(𝑠, 𝑣𝑖 ) = 𝑑𝑖𝑠𝑡(𝑠, 𝑣) + 1. Then
∑︁ #{shortest 𝑠𝑣𝑖 − paths}
𝑐𝑠 (𝑣) = 𝑐𝑠 (𝑣𝑖 )
#{shortest 𝑠𝑣 − paths}
1≤𝑖≤𝑘

The number of shortest paths between 𝑠 and every other vertex can be computed with a slightly modified BFS.
While running this BFS we can also store the list of the vertices 𝑣1 , ..., 𝑣𝑘 associated with each 𝑣.
EXAMPLES:
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}

5.3. Centrality 655


Sage Reference Manual: Graph Theory, Release 8.4

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 𝑘 == 𝑛:

sage: from sage.graphs.centrality import centrality_closeness_random_k


sage: G = graphs.PetersenGraph()
sage: centrality_closeness_random_k(G, 10)
{0: 0.6,
1: 0.6,
2: 0.6,
3: 0.6,
4: 0.6,
5: 0.6,
6: 0.6,
7: 0.6,
8: 0.6,
9: 0.6}

sage.graphs.centrality.centrality_closeness_top_k(G, k=1, verbose=0)


Computes the k vertices with largest closeness centrality.
The algorithm is based on performing a breadth-first-search (BFS) from each vertex, and to use bounds in order
to cut these BFSes as soon as possible. If k is small, it is much more efficient than computing all centralities
with centrality_closeness(). Conversely, if k is close to the number of nodes, the running-time is
approximately the same (it might even be a bit longer, because more computations are needed). For more
information, see [BCM15]. The algorithm does not work on weighted graphs.
INPUT:
• G a Sage Graph or DiGraph;
• k (integer, default: 1): the algorithm will return the k vertices with largest closeness centrality. This value
should be between 1 and the number of vertices with positive (out)degree, because the closeness centrality
is not defined for vertices with (out)degree 0. If k is bigger than this value, the output will contain all
vertices of positive (out)degree.

656 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

• 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:

sage: from sage.graphs.centrality import centrality_closeness_top_k


sage: g = graphs.PathGraph(10)
sage: centrality_closeness_top_k(g, 4, 1)
Final performance ratio: 0.711111111111
[(0.36, 5),
(0.36, 4),
(0.3333333333333333, 6),
(0.3333333333333333, 3)]
sage: g = digraphs.Path(10)
sage: centrality_closeness_top_k(g, 5, 1)
Final performance ratio: 0.422222222222
[(0.2, 0),
(0.19753086419753085, 1),
(0.19444444444444442, 2),
(0.19047619047619047, 3),
(0.18518518518518517, 4)]

5.4 Asteroidal triples

This module contains the following function:

Test if the input graph is asteroidal triple-free


is_asteroidal_triple_free()

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.

5.4. Asteroidal triples 657


Sage Reference Manual: Graph Theory, Release 8.4

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

The PetersenGraph is not AT-free:

sage: from sage.graphs.asteroidal_triples import *


sage: G = graphs.PetersenGraph()
sage: G.is_asteroidal_triple_free()
False
sage: G.is_asteroidal_triple_free(certificate=True)
(False, [0, 2, 6])

5.5 Independent sets

This module implements the IndependentSets class which can be used to :


• List the independent sets (or cliques) of a graph

658 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

• Count them (which is obviously faster)


• Test whether a set of vertices is an independent set
It can also be restricted to focus on (inclusionwise) maximal independent sets. See the documentation of
IndependentSets for actual examples.

5.5.1 Classes and methods

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:

sage: from sage.graphs.independent_sets import IndependentSets


sage: g = graphs.ClawGraph()
sage: I = IndependentSets(g)
sage: list(I)
[[0], [1], [1, 2], [1, 2, 3], [1, 3], [2], [2, 3], [3], []]

Count them:

sage: I.cardinality()
9

List only the maximal independent sets:

5.5. Independent sets 659


Sage Reference Manual: Graph Theory, Release 8.4

sage: Im = IndependentSets(g, maximal = True)


sage: list(Im)
[[0], [1, 2, 3]]

And count them:

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: is4 = (x for x in IndependentSets(g) if len(x) == 4)


sage: list(is4)
[[0, 2, 8, 9], [0, 3, 6, 7], [1, 3, 5, 9], [1, 4, 7, 8], [2, 4, 5, 6]]

Given a subset of the vertices, it is possible to test whether it is an independent set:

sage: g = graphs.DurerGraph()
sage: I = IndependentSets(g)
sage: [0,2] in I
True
sage: [0,3,5] in I
False

If an element of the subset is not a vertex, then an error is raised:

sage: [0, 'a', 'b', 'c'] in I


Traceback (most recent call last):
...
ValueError: a is not a vertex of the graph.

cardinality()
Computes and returns the number of independent sets

5.6 Comparability and permutation graphs

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

660 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

is_comparability_MILP() Tests whether the graph is a comparability graph (MILP)


Tests whether the graph is a comparability graph (greedy algorithm)
greedy_is_comparability()
Tests whether the graph is a comparability graph and returns certificates (greedy
greedy_is_comparability_with_certificate()
algorithm)
is_comparability() Tests whether the graph is a comparability graph
is_permutation() Tests whether the graph is a permutation graph.
is_transitive() Tests whether the digraph is transitive.

Author:
• Nathann Cohen 2012-04

5.6.1 Graph classes

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.

5.6.2 Recognition algorithm for comparability graphs

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]):

5.6. Comparability and permutation graphs 661


Sage Reference Manual: Graph Theory, Release 8.4

Theorem – The following statements are equivalent :


• 𝐺 is a comparability graph
𝐺
• ∀𝑢𝑣 ∈ 𝐺, 𝑣𝑢 ̸∈ 𝐶𝑢𝑣
• The edges of 𝐺 can be partitionned into 𝐵1 , ..., 𝐵𝑘 where 𝐵𝑖 is the equivalence class of some
oriented edge in 𝐺 − 𝐵1 − · · · − 𝐵𝑖−1
Hence, ensuring that a graph is a comparability graph can be done by checking that no equivalence class is contradic-
tory. Building the orientation, however, requires to build equivalence classes step by step until an orientation has been
found for all of them.
Mixed Integer Linear Program
A MILP formulation is available to check the other methods for correction. It is easily built :
To each edge are associated two binary variables (one for each possible direction). We then ensure that
each triangle is transitively oriented, and that each pair of incident edges 𝑢𝑣, 𝑢𝑣 ′ such that 𝑣𝑣 ′ ̸∈ 𝐺 do not
create a 2-path.
Here is the formulation:
Maximize : Nothing
Such that :
∀𝑢𝑣 ∈ 𝐺
· 𝑜𝑢𝑣 + 𝑜𝑣𝑢 = 1
∀𝑢 ∈ 𝐺, ∀𝑣, 𝑣 ′ ∈ 𝑁 (𝑣) such that 𝑣𝑣 ′ ̸∈ 𝐺
· 𝑜𝑢𝑣 + 𝑜𝑣′ 𝑢 − 𝑜𝑣′ 𝑣 ≤ 1
· 𝑜𝑢𝑣′ + 𝑜𝑣𝑢 − 𝑜𝑣𝑣′ ≤ 1
∀𝑢 ∈ 𝐺, ∀𝑣, 𝑣 ′ ∈ 𝑁 (𝑣) such that 𝑣𝑣 ′ ∈ 𝐺
· 𝑜𝑢𝑣 + 𝑜𝑣′ 𝑢 ≤ 1
· 𝑜𝑢𝑣′ + 𝑜𝑣𝑢 ≤ 1
𝑜𝑢𝑣 is a binary variable

Note: The MILP formulation is usually much slower than the greedy algorithm. This MILP has been implemented
to check the results of the greedy algorithm that has been implemented to check the results of a faster algorithm which
has not been implemented yet.

5.6.3 Certificates

Comparability graphs
The yes-certificates that a graph is a comparability graphs are transitive orientations of it. The no-certificates, on the
other hand, are odd cycles of such graph. These odd cycles have the property that around each vertex 𝑣 of the cycle its
two incident edges must have the same orientation (toward 𝑣, or outward 𝑣) in any transitive orientation of the graph.
This is impossible whenever the cycle has odd length. Explanations are given in the “Greedy algorithm” part of the
previous section.
Permutation graphs
Permutation graphs are precisely the intersection of comparability graphs and co-comparability graphs. Hence, nega-
tive certificates are precisely negative certificates of comparability or co-comparability. Positive certificates are a pair
of permutations that can be used through PermutationGraph() (whose documentation says more about what
these permutations represent).

662 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

5.6.4 Implementation details

Test that the equivalence classes are not self-contradictory


This is done by a call to Graph.is_bipartite(), and here is how :
Around a vertex 𝑢, any two edges 𝑢𝑣, 𝑢𝑣 ′ such that 𝑣𝑣 ′ ̸∈ 𝐺 are equivalent. Hence, the equivalence classe
of edges around a vertex are precisely the connected components of the complement of the graph induced
by the neighbors of 𝑢.
In each equivalence class (around a given vertex 𝑢), the edges should all have the same orientation, i.e.
all should go toward 𝑢 at the same time, or leave it at the same time. To represent this, we create a graph
with vertices for all equivalent classes around all vertices of 𝐺, and link (𝑣, 𝐶) to (𝑢, 𝐶 ′ ) if 𝑢 ∈ 𝐶 and
𝑣 ∈ 𝐶 ′.
A bipartite coloring of this graph with colors 0 and 1 tells us that the edges of an equivalence class 𝐶
around 𝑢 should be directed toward 𝑢 if (𝑢, 𝐶) is colored with 0, and outward if (𝑢, 𝐶) is colored with 1.
If the graph is not bipartite, this is the proof that some equivalence class is self-contradictory !

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: from sage.graphs.comparability import greedy_is_comparability as is_


˓→comparability

sage: g = graphs.PetersenGraph()
sage: is_comparability(g)
False
(continues on next page)

5.6. Comparability and permutation graphs 663


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: is_comparability(g, no_certificate = True)
(False, [0, 4, 9, 6, 1, 0])

But the Bull graph is:

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: from sage.graphs.comparability import greedy_is_comparability_with_


˓→certificate as is_comparability

sage: is_comparability(graphs.CycleGraph(5), certificate = True)


(False, [1, 2, 3, 4, 0, 1])
sage: g = graphs.PetersenGraph()
sage: is_comparability(g)
False
sage: is_comparability(g, certificate = True)
(False, [0, 4, 9, 6, 1, 0])

But the Bull graph is:

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.

664 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

• 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: from sage.graphs.comparability import is_comparability


sage: g = graphs.PetersenGraph()
sage: is_comparability(g)
False
sage: is_comparability(graphs.CompleteGraph(5), certificate=True)
(True, Digraph on 5 vertices)

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:

The 5-cycle or the Petersen Graph are not transitively orientable:

sage: from sage.graphs.comparability import is_comparability_MILP as is_


˓→comparability

sage: is_comparability(graphs.CycleGraph(5), certificate = True)


(False, None)
sage: g = graphs.PetersenGraph()
sage: is_comparability(g, certificate = True)
(False, None)

But the Bull graph is:

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:

5.6. Comparability and permutation graphs 665


Sage Reference Manual: Graph Theory, Release 8.4

• algorithm – choose the implementation used for the subcalls to is_comparability().


– "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 for the answer given. For True answers the
certificate is a permutation, for False answers it is a no-certificate for the test of comparability or co-
comparability.
• check (boolean) – whether to check that the permutations returned indeed create the expected Permuta-
tion graph. Pretty cheap compared to the rest, hence a good investment. 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.

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: from sage.graphs.comparability import is_permutation


sage: g = graphs.BullGraph()
sage: _ , certif = is_permutation(g, certificate=True)
sage: h = graphs.PermutationGraph(*certif)
sage: h.is_isomorphic(g)
True

Plotting the realization as an intersection graph of segments:

sage: true, perm = is_permutation(g, certificate=True)


sage: p1 = Permutation([nn+1 for nn in perm[0]])
sage: p2 = Permutation([nn+1 for nn in perm[1]])
sage: p = p2 * p1.inverse()
sage: p.show(representation = "braid")

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:

666 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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

5.7 Line graphs

This module gather everything which is related to line graphs. Right now, this amounts to the following functions :

line_graph() Computes the line graph of a given graph


is_line_graph() Check whether a graph is a line graph
root_graph() Computes the root graph corresponding to the given graph

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.

5.7.2 Root 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 𝑣.

5.7. Line graphs 667


Sage Reference Manual: Graph Theory, Release 8.4

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.

668 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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:

• The line_graph module.


• line_graph_forbidden_subgraphs() – the forbidden subgraphs of a line graph.
• line_graph()

EXAMPLES:
A complete graph is always the line graph of a star:

sage: graphs.CompleteGraph(5).is_line_graph()
True

The Petersen Graph not being claw-free, it is not a line graph:

sage: graphs.PetersenGraph().is_line_graph()
False

This is indeed the subgraph returned:

sage: C = graphs.PetersenGraph().is_line_graph(certificate = True)[1]


sage: C.is_isomorphic(graphs.ClawGraph())
True

The house graph is a line graph:

sage: g = graphs.HouseGraph()
sage: g.is_line_graph()
True

But what is the graph whose line graph is the house ?:

sage: is_line, R, isom = g.is_line_graph(certificate = True)


sage: R.sparse6_string()
':DaHI~'
sage: R.show()
sage: isom
{0: (0, 1), 1: (0, 2), 2: (1, 3), 3: (2, 3), 4: (3, 4)}

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.

5.7. Line graphs 669


Sage Reference Manual: Graph Theory, Release 8.4

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:

• The line_graph module.


• line_graph_forbidden_subgraphs() – the forbidden subgraphs of a line graph.
• is_line_graph() – tests whether a graph is a line graph.

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)

670 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


((1, 3, None), (3, 4, None), None),
((2, 3, None), (3, 4, None), None)]

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 !

5.8 Spanning trees

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

sage.graphs.spanning_tree.boruvka(G, wfunction=None, check=False, by_weight=True)


Minimum spanning tree using Boruvka’s algorithm.

5.8. Spanning trees 671


Sage Reference Manual: Graph Theory, Release 8.4

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: from sage.graphs.spanning_tree import boruvka


sage: G = Graph({1:{2:28, 6:10}, 2:{3:16, 7:14}, 3:{4:12}, 4:{5:22, 7:18}, 5:
˓→{6:25, 7:24}})

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)

672 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: boruvka(G, by_weight=False)
[(1, 2, 28), (2, 3, 16), (3, 4, 12), (4, 5, 22), (1, 6, 10), (2, 7, 14)]

An example with custom edge labels

sage: G = Graph([[0,1,1],[1,2,1],[2,0,10]], weighted=True)


sage: weight = lambda e:3-e[0]-e[1]
sage: boruvka(G, wfunction=lambda e:3-e[0]-e[1], by_weight=True)
[(0, 2, 10), (1, 2, 1)]
sage: boruvka(G, wfunction=lambda e:float(1/e[2]), by_weight=True)
[(0, 2, 10), (0, 1, 1)]

An example of disconnected graph with check disabled

sage: from sage.graphs.spanning_tree import boruvka


sage: G = Graph({1:{2:28}, 3:{4:16}}, weighted=True)
sage: boruvka(G, check=False)
[]

sage.graphs.spanning_tree.kruskal(G, wfunction=None, check=False)


Minimum spanning tree using Kruskal’s algorithm.
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.
• weight_function (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
weight_function can be used to transform the label into a weight. In particular:
– if weight_function is not None, the weight of an edge e is weight_function(e);
– if weight_function 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 weight_function 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 Kruskal’s
algorithm on that input graph:
– Is G the null graph?
– Is G disconnected?
– Is G a tree?
– Does G have self-loops?
– Does G have multiple edges?
By default, we turn off the sanity checks for performance reasons. This means that by default the func-
tion assumes that its input graph is connected, and has at least one vertex. Otherwise, you should set
check=True to perform some sanity checks and preprocessing on the input graph. If G has multiple
edges or self-loops, the algorithm still works, but the running-time can be improved if these edges are

5.8. Spanning trees 673


Sage Reference Manual: Graph Theory, Release 8.4

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: from sage.graphs.spanning_tree import kruskal


sage: G = Graph({1:{2:28, 6:10}, 2:{3:16, 7:14}, 3:{4:12}, 4:{5:22, 7:18}, 5:
˓→{6:25, 7:24}})

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)]

Variants of the previous example.

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

An example from pages 599–601 in [GoodrichTamassia2001].

674 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

sage: G = Graph({"SFO":{"BOS":2704, "ORD":1846, "DFW":1464, "LAX":337},


....: "BOS":{"ORD":867, "JFK":187, "MIA":1258},
....: "ORD":{"PVD":849, "JFK":740, "BWI":621, "DFW":802},
....: "DFW":{"JFK":1391, "MIA":1121, "LAX":1235},
....: "LAX":{"MIA":2342},
....: "PVD":{"JFK":144},
....: "JFK":{"MIA":1090, "BWI":184},
....: "BWI":{"MIA":946}})
sage: G.weighted(True)
sage: kruskal(G, check=True)
[('BOS', 'JFK', 187), ('BWI', 'JFK', 184), ('BWI', 'MIA', 946), ('BWI', 'ORD',
˓→621), ('DFW', 'LAX', 1235), ('DFW', 'ORD', 802), ('JFK', 'PVD', 144), ('LAX',

˓→'SFO', 337)]

An example from pages 568–569 in [CormenEtAl2001].

sage: G = Graph({"a":{"b":4, "h":8}, "b":{"c":8, "h":11},


....: "c":{"d":7, "f":4, "i":2}, "d":{"e":9, "f":14},
....: "e":{"f":10}, "f":{"g":2}, "g":{"h":1, "i":6}, "h":{"i":7}})
sage: G.weighted(True)
sage: kruskal(G, check=True)
[('a', 'b', 4), ('a', 'h', 8), ('c', 'd', 7), ('c', 'f', 4), ('c', 'i', 2), ('d',
˓→'e', 9), ('f', 'g', 2), ('g', 'h', 1)]

An example with custom edge labels:

sage: G = Graph([[0,1,1],[1,2,1],[2,0,10]], weighted=True)


sage: weight = lambda e:3-e[0]-e[1]
sage: kruskal(G, check=True)
[(0, 1, 1), (1, 2, 1)]
sage: kruskal(G, wfunction=weight, check=True)
[(0, 2, 10), (1, 2, 1)]
sage: kruskal(G, wfunction=weight, check=False)
[(0, 2, 10), (1, 2, 1)]

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)

5.8. Spanning trees 675


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


[(0, 9),
(9, 11),
(0, 8),
(8, 7),
(7, 6),
(7, 2),
(2, 1),
(1, 5),
(9, 10),
(5, 4),
(2, 3)]
sage: Graph(rg).is_tree()
True

A visual example for the grid graph:

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 𝑥.

676 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

• a new 𝑃 -tree whose children are the 𝑐𝑥 sets 𝑆𝑖 containing 𝑥.


This describes the set of all 𝑐𝑥 ! × 𝑐¯′𝑥 ! permutations of 𝑆1 , ..., 𝑆𝑘 that keep the sets containing 𝑥 on an interval.
3. We take a second element 𝑥′ and update the data structure 𝑇 to restrict the permutations it describes to those
that keep 𝑥′ on an interval of [1, ..., 𝑘]. The sets 𝑆1 , ..., 𝑆𝑘 belong to 4 categories:
• The family 𝑆00 of sets which do not contain any of 𝑥, 𝑥′ .
• The family 𝑆01 of sets which contain 𝑥′ but do not contain 𝑥.
• The family 𝑆10 of sets which contain 𝑥 but do not contain 𝑥′ .
• The family 𝑆11 of sets which contain 𝑥′ and 𝑥′ .
With these notations, the permutations of 𝑆1 , ..., 𝑆𝑘 which keep the occurrences of 𝑥 and 𝑥′ on an interval are
of two forms:
• <some sets 𝑆00 >, <sets from 𝑆10 >, <sets from 𝑆11 >, <sets from 𝑆01 >, <other sets from 𝑆00 >
• <some sets 𝑆00 >, <sets from 𝑆01 >, <sets from 𝑆11 >, <sets from 𝑆10 >, <other sets from 𝑆00 >
These permutations can be modeled with the following 𝑃 𝑄-tree:
• A 𝑃 -tree whose children are:
– All sets from 𝑆00
– A 𝑄-tree whose children are:

* A 𝑃 -tree with whose children are the sets from 𝑆10


* A 𝑃 -tree with whose children are the sets from 𝑆11
* A 𝑃 -tree with whose children are the sets from 𝑆01
4. One at a time, we update the data structure with each element until they are all exhausted, or until we reach a
proof that no permutation satisfying the consecutive ones property exists.
Using these two types of tree, and exploring the different cases of intersection, it is possible to represent all the
possible permutations of our sets satisfying our constraints, or to prove that no such ordering exists. This is the
whole purpose of this module, and is explained with more details in many places, for example in the following
document from Hajiaghayi [Haj].
REFERENCES:
Authors:
Nathann Cohen (initial implementation)

5.9.1 Methods and functions

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:

5.9. PQ-Trees 677


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.pq_trees import P, Q


sage: p = P([[0,3], [1,2], [2,3], [2,4], [4,0],[2,8], [2,9]])
sage: p.cardinality()
5040
sage: p.set_contiguous(3)
(1, True)
sage: p.cardinality()
1440

orderings()
Iterate over all orderings of the sets allowed by the structure.
See also:
cardinality() – return the number of orderings
EXAMPLES:

sage: from sage.graphs.pq_trees import P, Q


sage: p = P([[2,4], [1,2], [0,8], [0,5]])
sage: for o in p.orderings():
....: print(o)
({2, 4}, {1, 2}, {0, 8}, {0, 5})
({2, 4}, {1, 2}, {0, 5}, {0, 8})
({2, 4}, {0, 8}, {1, 2}, {0, 5})
({2, 4}, {0, 8}, {0, 5}, {1, 2})
...

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:

sage: from sage.graphs.pq_trees import P, Q


sage: p = P([[0,3], [1,2], [2,3], [2,4], [4,0],[2,8], [2,9]])
sage: p.set_contiguous(0)
(1, True)
sage: print(p)
('P', [{1, 2}, {2, 3}, {2, 4}, {8, 2}, {9, 2}, ('P', [{0, 3}, {0, 4}])])

678 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

Impossible situation:

sage: p = P([[0,1], [1,2], [2,3], [3,0]])


sage: p.set_contiguous(0)
(1, True)
sage: p.set_contiguous(1)
(1, True)
sage: p.set_contiguous(2)
(1, True)
sage: p.set_contiguous(3)
Traceback (most recent call last):
...
ValueError: Impossible

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:

sage: from sage.graphs.pq_trees import P, Q


sage: p = Q([P([[2,4], [2,8], [2,9]])])
sage: p.flatten()
('P', [{2, 4}, {8, 2}, {9, 2}])

number_of_children()
Returns the number of children of self
EXAMPLES:

sage: from sage.graphs.pq_trees import P, Q


sage: p = Q([[1,2], [2,3], P([[2,4], [2,8], [2,9]])])
sage: p.number_of_children()
3

ordering()
Returns the current ordering given by listing the leaves from left to right.
EXAMPLES:

sage: from sage.graphs.pq_trees import P, Q


sage: p = Q([[1,2], [2,3], P([[2,4], [2,8], [2,9]])])
sage: p.ordering()
[{1, 2}, {2, 3}, {2, 4}, {8, 2}, {9, 2}]

reverse()
Recursively reverses self and its children
EXAMPLES:

5.9. PQ-Trees 679


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.pq_trees import P, Q


sage: p = Q([[1,2], [2,3], P([[2,4], [2,8], [2,9]])])
sage: p.ordering()
[{1, 2}, {2, 3}, {2, 4}, {8, 2}, {9, 2}]
sage: p.reverse()
sage: p.ordering()
[{9, 2}, {8, 2}, {2, 4}, {2, 3}, {1, 2}]

simplify(v, left=False, right=False)


Returns a simplified copy of self according to the element v
If self is a partial P-tree for v, we would like to restrict the permutations of its children to permutations
keeping the children containing v contiguous. This function also “locks” all the elements not containing
v inside a 𝑃 -tree, which is useful when one want to keep the elements containing v on one side (which is
the case when this method is called).
INPUT:
• left, right (boolean) – whether v is aligned to the right or to the left
• v– an element of the ground set
OUTPUT:
If self is a 𝑄-Tree, the sequence of its children is returned. If self is a 𝑃 -tree, 2 𝑃 -tree are returned,
namely the two 𝑃 -tree defined above and restricting the permutations, in the order implied by left,
right (if right =True, the second 𝑃 -tree will be the one gathering the elements containing v, if
left=True, the opposite).

Note: This method is assumes that self is partial for v, and aligned to the side indicated by left,
right.

EXAMPLES:
A 𝑃 -Tree

sage: from sage.graphs.pq_trees import P, Q


sage: p = P([[2,4], [1,2], [0,8], [0,5]])
sage: p.simplify(0, right = True)
[('P', [{2, 4}, {1, 2}]), ('P', [{0, 8}, {0, 5}])]

A 𝑄-Tree

sage: q = Q([[2,4], [1,2], [0,8], [0,5]])


sage: q.simplify(0, right = True)
[{2, 4}, {1, 2}, {0, 8}, {0, 5}]

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

680 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

EXAMPLES:

sage: from sage.graphs.pq_trees import P, Q


sage: q = Q([[0,3], [1,2], [2,3], [2,4], [4,0],[2,8], [2,9]])
sage: q.cardinality()
2

orderings()
Iterates over all orderings of the sets allowed by the structure
See also:
cardinality() – return the number of orderings
EXAMPLES:

sage: from sage.graphs.pq_trees import P, Q


sage: q = Q([[2,4], [1,2], [0,8], [0,5]])
sage: for o in q.orderings():
....: print(o)
({2, 4}, {1, 2}, {0, 8}, {0, 5})
({0, 5}, {0, 8}, {1, 2}, {2, 4})

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:

sage: from sage.graphs.pq_trees import P, Q


sage: q = Q([[2,3], Q([[3,0],[3,1]]), Q([[4,0],[4,5]])])
sage: q.set_contiguous(0)
(1, False)
sage: print(q)
('Q', [{2, 3}, {1, 3}, {0, 3}, {0, 4}, {4, 5}])

Impossible situation:

sage: p = Q([[0,1], [1,2], [2,0]])


sage: p.set_contiguous(0)
(continues on next page)

5.9. PQ-Trees 681


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


Traceback (most recent call last):
...
ValueError: Impossible

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: from sage.graphs.pq_trees import reorder_sets


sage: seq = [Set([i-1,i,i+1]) for i in range(1,15)]

We apply a random permutation:

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)

5.10 Generation of trees

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:

682 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

class sage.graphs.trees.TreeIterator
Bases: object
This class iterates over all trees with n vertices (up to isomorphism).
EXAMPLES:

sage: from sage.graphs.trees import TreeIterator


sage: def check_trees(n):
....: trees = []
....: for t in TreeIterator(n):
....: if not t.is_tree():
....: return False
....: if t.num_verts() != n:
....: return False
....: if t.num_edges() != n - 1:
....: return False
....: for tree in trees:
....: if tree.is_isomorphic(t):
....: return False
....: trees.append(t)
....: return True
sage: check_trees(10)
True

sage: from sage.graphs.trees import TreeIterator


sage: count = 0
sage: for t in TreeIterator(15):
....: count += 1
sage: count
7741

next()
x.next() -> the next value, or raise StopIteration

5.11 Matching Polynomial

This module contains the following methods:

matching_polynomial() Computes the matching polynomial of a given graph


complete_poly() Compute the matching polynomial of the complete graph on 𝑛 vertices.

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

5.11. Matching Polynomial 683


Sage Reference Manual: Graph Theory, Release 8.4

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: from sage.graphs.matchpoly import complete_poly


sage: f = complete_poly(10)
sage: f
x^10 - 45*x^8 + 630*x^6 - 3150*x^4 + 4725*x^2 - 945
sage: f = complete_poly(20)
sage: f[8]
1309458150
sage: f = complete_poly(1000)
sage: len(str(f))
406824

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

Where 𝐺 is the complement of 𝐺, and 𝐾𝑛 the complete graph on 𝑛 vertices.


EXAMPLES:

684 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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: for i in range(1, 12): # long time (10s on sage.math, 2011)


....: for t in graphs.trees(i):
....: if t.matching_polynomial() != t.characteristic_polynomial():
....: raise RuntimeError('bug for a tree A of size {0}'.format(i))
....: c = t.complement()
....: if c.matching_polynomial(complement=False) != c.matching_
˓→polynomial():

....: raise RuntimeError('bug for a tree B of size {0}'.format(i))

sage: from sage.graphs.matchpoly import matching_polynomial


sage: matching_polynomial(graphs.CompleteGraph(0))
1
sage: matching_polynomial(graphs.CompleteGraph(1))
x
sage: matching_polynomial(graphs.CompleteGraph(2))
x^2 - 1
sage: matching_polynomial(graphs.CompleteGraph(3))
x^3 - 3*x
sage: matching_polynomial(graphs.CompleteGraph(4))
x^4 - 6*x^2 + 3
sage: matching_polynomial(graphs.CompleteGraph(5))
x^5 - 10*x^3 + 15*x
sage: matching_polynomial(graphs.CompleteGraph(6))
x^6 - 15*x^4 + 45*x^2 - 15
sage: matching_polynomial(graphs.CompleteGraph(7))
x^7 - 21*x^5 + 105*x^3 - 105*x
sage: matching_polynomial(graphs.CompleteGraph(8))
x^8 - 28*x^6 + 210*x^4 - 420*x^2 + 105
sage: matching_polynomial(graphs.CompleteGraph(9))
x^9 - 36*x^7 + 378*x^5 - 1260*x^3 + 945*x
sage: matching_polynomial(graphs.CompleteGraph(10))
x^10 - 45*x^8 + 630*x^6 - 3150*x^4 + 4725*x^2 - 945
sage: matching_polynomial(graphs.CompleteGraph(11))
x^11 - 55*x^9 + 990*x^7 - 6930*x^5 + 17325*x^3 - 10395*x
sage: matching_polynomial(graphs.CompleteGraph(12))
x^12 - 66*x^10 + 1485*x^8 - 13860*x^6 + 51975*x^4 - 62370*x^2 + 10395
sage: matching_polynomial(graphs.CompleteGraph(13))
x^13 - 78*x^11 + 2145*x^9 - 25740*x^7 + 135135*x^5 - 270270*x^3 + 135135*x

sage: G = Graph({0:[1,2], 1:[2]})


sage: matching_polynomial(G)
x^3 - 3*x
sage: G = Graph({0:[1,2]})
(continues on next page)

5.11. Matching Polynomial 685


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: matching_polynomial(G)
x^3 - 2*x
sage: G = Graph({0:[1], 2:[]})
sage: matching_polynomial(G)
x^3 - x
sage: G = Graph({0:[], 1:[], 2:[]})
sage: matching_polynomial(G)
x^3

sage: matching_polynomial(graphs.CompleteGraph(0), complement=False)


1
sage: matching_polynomial(graphs.CompleteGraph(1), complement=False)
x
sage: matching_polynomial(graphs.CompleteGraph(2), complement=False)
x^2 - 1
sage: matching_polynomial(graphs.CompleteGraph(3), complement=False)
x^3 - 3*x
sage: matching_polynomial(graphs.CompleteGraph(4), complement=False)
x^4 - 6*x^2 + 3
sage: matching_polynomial(graphs.CompleteGraph(5), complement=False)
x^5 - 10*x^3 + 15*x
sage: matching_polynomial(graphs.CompleteGraph(6), complement=False)
x^6 - 15*x^4 + 45*x^2 - 15
sage: matching_polynomial(graphs.CompleteGraph(7), complement=False)
x^7 - 21*x^5 + 105*x^3 - 105*x
sage: matching_polynomial(graphs.CompleteGraph(8), complement=False)
x^8 - 28*x^6 + 210*x^4 - 420*x^2 + 105
sage: matching_polynomial(graphs.CompleteGraph(9), complement=False)
x^9 - 36*x^7 + 378*x^5 - 1260*x^3 + 945*x
sage: matching_polynomial(graphs.CompleteGraph(10), complement=False)
x^10 - 45*x^8 + 630*x^6 - 3150*x^4 + 4725*x^2 - 945
sage: matching_polynomial(graphs.CompleteGraph(11), complement=False)
x^11 - 55*x^9 + 990*x^7 - 6930*x^5 + 17325*x^3 - 10395*x
sage: matching_polynomial(graphs.CompleteGraph(12), complement=False)
x^12 - 66*x^10 + 1485*x^8 - 13860*x^6 + 51975*x^4 - 62370*x^2 + 10395
sage: matching_polynomial(graphs.CompleteGraph(13), complement=False)
x^13 - 78*x^11 + 2145*x^9 - 25740*x^7 + 135135*x^5 - 270270*x^3 + 135135*x

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.

686 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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:

THIS MAY SEGFAULT OR HANG ON:


* DISCONNECTED GRAPHS
* DIRECTED GRAPHS
* LOOPED GRAPHS
* MULTIGRAPHS

EXAMPLES:

sage: import sage.graphs.genus


sage: G = graphs.CompleteGraph(6)
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() #long time


1
sage: bt.genus(cutoff=1)
1
sage: G = graphs.PetersenGraph()
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()
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

genus(style=1, cutoff=0, record_embedding=0)


Compute the minimal or maximal genus of self’s graph. Note, this is a remarkably naive algorithm for
a very difficult problem. Most interesting cases will take millenia to finish, with the exception of graphs
with max degree 3.
INPUT:
• style – int, find minimum genus if 1, maximum genus if 2
• cutoff – int, stop searching if search style is 1 and genus <= cutoff, or if style is 2 and genus >=
cutoff. This is useful where the genus of the graph has a known bound.
• record_embedding – bool, whether or not to remember the best embedding seen. This embedding
can be retrieved with self.get_embedding().

5.12. Genus 687


Sage Reference Manual: Graph Theory, Release 8.4

OUTPUT:
the minimal or maximal genus for self’s graph.
EXAMPLES:

sage: import sage.graphs.genus


sage: G = Graph(graphs.CompleteGraph(5), implementation='c_graph',
˓→sparse=False)

sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[0])

sage: gb.genus(cutoff = 2, record_embedding = True)


2
sage: E = gb.get_embedding()
sage: gb.genus(record_embedding = False)
1
sage: gb.get_embedding() == E
True
sage: gb.genus(style=2, cutoff=5)
3
sage: G = Graph(implementation='c_graph', sparse=False)
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: import sage.graphs.genus


sage: G = Graph(graphs.CompleteGraph(5), implementation='c_graph',
˓→sparse=False)

sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[0])

sage: gb.genus(record_embedding = True)


1
sage: gb.get_embedding()
{0: [1, 2, 3, 4], 1: [0, 2, 3, 4], 2: [0, 1, 4, 3], 3: [0, 2, 1, 4], 4: [0, 3,
˓→ 1, 2]}

sage: G = Graph(implementation='c_graph', sparse=False)


sage: G.add_edge(0,1)
sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[0])

sage: gb.get_embedding()
{0: [1], 1: [0]}
sage: G = Graph(implementation='c_graph', sparse=False)
sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[0])

sage: gb.get_embedding()
{}

sage.graphs.genus.simple_connected_graph_genus(G, set_embedding=False, check=True,


minimal=True)
Compute the genus of a simple connected graph.
WARNING:

688 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

THIS MAY SEGFAULT OR HANG ON:


* DISCONNECTED GRAPHS
* DIRECTED GRAPHS
* LOOPED GRAPHS
* MULTIGRAPHS

DO NOT CALL WITH ``check = False`` UNLESS YOU ARE CERTAIN.

EXAMPLES:

sage: import sage.graphs.genus


sage: from sage.graphs.genus import simple_connected_graph_genus as genus
sage: [genus(g) for g in graphs(6) if g.is_connected()].count(1)
13
sage: G = graphs.FlowerSnark()
sage: genus(G) # see [1]
2
sage: G = graphs.BubbleSortGraph(4)
sage: genus(G)
0
sage: G = graphs.OddGraph(3)
sage: genus(G)
1

REFERENCES:
[1] http://www.springerlink.com/content/0776127h0r7548v7/

5.13 Lovász theta-function of graphs

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.

5.13. Lovász theta-function of graphs 689


Sage Reference Manual: Graph Theory, Release 8.4

• 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

5.14 Linear Extensions of Directed Acyclic Graphs.

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:

sage: from sage.graphs.linearextensions import LinearExtensions


sage: D = DiGraph({ 0:[1,2], 1:[3], 2:[3,4] })
sage: D.is_directed_acyclic()
True
sage: LinearExtensions(D).list()
[[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]]

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”.

690 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

EXAMPLES:

sage: from sage.graphs.linearextensions import LinearExtensions


sage: D = DiGraph({ 0:[1,2], 1:[3], 2:[3,4] })
sage: l = LinearExtensions(D)
sage: l == loads(dumps(l))
True

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:

sage: from sage.graphs.linearextensions import LinearExtensions


sage: D = DiGraph({ 0:[1,2], 1:[3], 2:[3,4] })
sage: l = LinearExtensions(D)
sage: l.linear_extensions = []
sage: l.linear_extensions.append(l.le[:])
sage: l.generate_linear_extensions(l.max_pair)
sage: l.linear_extensions
[[0, 1, 2, 3, 4], [0, 2, 1, 3, 4]]

incomparable(x, y)
Returns True if vertices x and y are incomparable in the directed acyclic graph when thought of as a poset.
EXAMPLES:

sage: from sage.graphs.linearextensions import LinearExtensions


sage: D = DiGraph({ 0:[1,2], 1:[3], 2:[3,4] })
sage: l = LinearExtensions(D)
sage: l.incomparable(0,1)
False
sage: l.incomparable(1,2)
True

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:

sage: from sage.graphs.linearextensions import LinearExtensions


sage: D = DiGraph({ 0:[1,2], 1:[3], 2:[3,4] })
sage: LinearExtensions(D).list()
[[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]]

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.

5.14. Linear Extensions of Directed Acyclic Graphs. 691


Sage Reference Manual: Graph Theory, Release 8.4

Note that this is meant to be called by the generate_linear_extensions method and is not meant to be used
directly.
EXAMPLES:

sage: from sage.graphs.linearextensions import LinearExtensions


sage: D = DiGraph({ 0:[1,2], 1:[3], 2:[3,4] })
sage: l = LinearExtensions(D)
sage: _ = l.list()
sage: l.le = [0, 1, 2, 3, 4]
sage: l.move(1, "left")
sage: l.le
[1, 0, 2, 3, 4]
sage: l.move(1, "right")
sage: l.le
[0, 1, 2, 3, 4]

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:

sage: from sage.graphs.linearextensions import LinearExtensions


sage: D = DiGraph({ 0:[1,2], 1:[3], 2:[3,4] })
sage: l = LinearExtensions(D)
sage: _ = l.list()
sage: l.le
[0, 1, 2, 4, 3]
sage: l.a
[1, 4]
sage: l.b
[2, 3]
sage: l.right(0, "a")
False
sage: l.right(1, "a")
False
sage: l.right(0, "b")
False
sage: l.right(1, "b")
False

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:

692 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.linearextensions import LinearExtensions


sage: D = DiGraph({ 0:[1,2], 1:[3], 2:[3,4] })
sage: l = LinearExtensions(D)
sage: _ = l.list()
sage: l.le = [0, 1, 2, 3, 4]
sage: l.is_plus
True
sage: l.switch(-1)
sage: l.is_plus
False
sage: l.a
[1, 4]
sage: l.b
[2, 3]
sage: l.switch(0)
sage: l.le
[0, 2, 1, 3, 4]
sage: l.a
[2, 4]
sage: l.b
[1, 3]

5.15 Schnyder’s Algorithm for straight-line planar embeddings

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:

sage: from sage.graphs.schnyder import TreeNode


sage: tn = TreeNode(label=5)
sage: tn2 = TreeNode(label=2,parent=tn)
sage: tn3 = TreeNode(label=3)
sage: tn.append_child(tn3)
sage: tn.compute_number_of_descendants()
2
(continues on next page)

5.15. Schnyder’s Algorithm for straight-line planar embeddings 693


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: tn.number_of_descendants
2
sage: tn3.number_of_descendants
1
sage: tn.compute_depth_of_self_and_children()
sage: tn3.depth
2

append_child(child)
Add a child to list of children.
EXAMPLES:

sage: from sage.graphs.schnyder import TreeNode


sage: tn = TreeNode(label=5)
sage: tn2 = TreeNode(label=2,parent=tn)
sage: tn3 = TreeNode(label=3)
sage: tn.append_child(tn3)
sage: tn.compute_number_of_descendants()
2
sage: tn.number_of_descendants
2
sage: tn3.number_of_descendants
1
sage: tn.compute_depth_of_self_and_children()
sage: tn3.depth
2

compute_depth_of_self_and_children()
Computes the depth of self and all descendants.
For each TreeNode, sets result as attribute self.depth
EXAMPLES:

sage: from sage.graphs.schnyder import TreeNode


sage: tn = TreeNode(label=5)
sage: tn2 = TreeNode(label=2,parent=tn)
sage: tn3 = TreeNode(label=3)
sage: tn.append_child(tn3)
sage: tn.compute_number_of_descendants()
2
sage: tn.number_of_descendants
2
sage: tn3.number_of_descendants
1
sage: tn.compute_depth_of_self_and_children()
sage: tn3.depth
2

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:

694 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.schnyder import TreeNode


sage: tn = TreeNode(label=5)
sage: tn2 = TreeNode(label=2,parent=tn)
sage: tn3 = TreeNode(label=3)
sage: tn.append_child(tn3)
sage: tn.compute_number_of_descendants()
2
sage: tn.number_of_descendants
2
sage: tn3.number_of_descendants
1
sage: tn.compute_depth_of_self_and_children()
sage: tn3.depth
2

sage.graphs.schnyder.minimal_schnyder_wood(graph, root_edge=None, minimal=True,


check=True)
Return the minimal Schnyder wood of a planar rooted triangulation.
INPUT:
• graph – a planar triangulation, given by a graph with an embedding.
• root_edge – a pair of vertices (default is from 'a' to 'b') The third boundary vertex is then determined
using the orientation and will be labelled 'c'.
• minimal – boolean (default True), whether to return a minimal or a maximal Schnyder wood.
• check – boolean (default True), whether to check if the input is a planar triangulation
OUTPUT:
a planar graph, with edges oriented and colored. The three outer edges of the initial graph are removed.
The algorithm is taken from [Brehm2000] (section 4.2).
EXAMPLES:
sage: from sage.graphs.schnyder import minimal_schnyder_wood
sage: g = Graph([(0,'a'),(0,'b'),(0,'c'),('a','b'),('b','c'),
....: ('c','a')], format='list_of_edges')
sage: g.set_embedding({'a':['b',0,'c'],'b':['c',0,'a'],
....: 'c':['a',0,'b'],0:['a','b','c']})
sage: newg = minimal_schnyder_wood(g)
sage: newg.edges()
[(0, 'a', 'green'), (0, 'b', 'blue'), (0, 'c', 'red')]
sage: newg.plot(color_by_label={'red':'red','blue':'blue',
....: 'green':'green',None:'black'})
Graphics object consisting of 8 graphics primitives

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)

5.15. Schnyder’s Algorithm for straight-line planar embeddings 695


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


(1, 0, 'green'),
(1, 'b', 'blue'),
(1, 'c', 'red'),
(2, 1, 'red'),
(2, 'a', 'green'),
(2, 'b', 'blue')]
sage: newg2 = minimal_schnyder_wood(g, minimal=False)
sage: sorted(newg2.edges(), key=lambda e:(str(e[0]),str(e[1])))
[(0, 1, 'blue'),
(0, 'a', 'green'),
(0, 'c', 'red'),
(1, 2, 'green'),
(1, 'b', 'blue'),
(1, 'c', 'red'),
(2, 0, 'red'),
(2, 'a', 'green'),
(2, 'b', 'blue')]

REFERENCES:

5.16 Wrapper for Boyer’s (C) planarity algorithm.

sage.graphs.planarity.is_planar(g, kuratowski=False, set_pos=False, set_embedding=False,


circular=False)
Calls Boyer’s planarity algorithm to determine whether g is planar. If kuratowski is False, returns True if g is
planar, False otherwise. If kuratowski is True, returns a tuple, first entry is a boolean (whether or not the graph
is planar) and second entry is a Kuratowski subgraph, i.e. an edge subdivision of 𝐾5 or 𝐾3,3 (if not planar) or
None (if planar). Also, will set an _embedding attribute for the graph g if set_embedding is set to True.
INPUT:
• kuratowski – If True, return a tuple of a boolean and either None or a Kuratowski subgraph (i.e. an
edge subdivision of 𝐾5 or 𝐾3,3 )
• set_pos – if True, uses Schnyder’s algorithm to determine positions
• set_embedding – if True, records the combinatorial embedding returned (see g.get_embedding())
• circular – if True, test for circular planarity
EXAMPLES:

sage: G = graphs.DodecahedralGraph()
sage: from sage.graphs.planarity import is_planar
sage: is_planar(G)
True
sage: Graph('@').is_planar()
True

5.17 Graph Plotting

(For LaTeX drawings of graphs, see the graph_latex module.)


All graphs have an associated Sage graphics object, which you can display:

696 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: petersen_spring = Graph(':I`ES@obGkqegW~')


sage: petersen_spring.show() # long time

sage: petersen_database = graphs.PetersenGraph()


sage: petersen_database.show() # long time

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().

5.17. Graph Plotting 697


Sage Reference Manual: Graph Theory, Release 8.4

698 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

5.17. Graph Plotting 699


Sage Reference Manual: Graph Theory, Release 8.4

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):

700 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

sage: import sage.graphs.graph_plot


sage: sage.graphs.graph_plot.DEFAULT_SHOW_OPTIONS['figsize'] = [6,6]
sage: graphs.PetersenGraph().show() # long time
sage: graphs.ChvatalGraph().show() # long time
sage: graphs.PetersenGraph().show(figsize=[4,4]) # long time

We can now reset the default to its initial value, and now display graphs as previously:

sage: sage.graphs.graph_plot.DEFAULT_SHOW_OPTIONS['figsize'] = [4,4]


sage: graphs.PetersenGraph().show() # long time
sage: graphs.ChvatalGraph().show() # long time

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

sage: import sage.graphs.graph_plot


sage: sage.graphs.graph_plot.DEFAULT_SHOW_OPTIONS['figsize'] = [4,4]

Index of methods and functions

GraphPlot.set_pos() Sets the position plotting parameters for this GraphPlot.


GraphPlot. Sets the vertex plotting parameters for this GraphPlot.
set_vertices()
GraphPlot.set_edges() Sets the edge (or arrow) plotting parameters for the GraphPlot object.
GraphPlot.show() Shows the (Di)Graph associated with this GraphPlot object.
GraphPlot.plot() Returns a graphics object representing the (di)graph.
GraphPlot. Compute a nice layout of a tree.
layout_tree()

class sage.graphs.graph_plot.GraphPlot(graph, options)


Bases: sage.structure.sage_object.SageObject
Returns a GraphPlot object, which stores all the parameters needed for plotting (Di)Graphs. A GraphPlot
has a plot and show function, as well as some functions to set parameters for vertices and edges. This constructor
assumes default options are set. Defaults are shown in the example below.
EXAMPLES:

sage: from sage.graphs.graph_plot import GraphPlot


sage: options = {
....: 'vertex_size':200,
....: 'vertex_labels':True,
....: 'layout':None,
....: 'edge_style':'solid',
....: 'edge_color':'black',
....: 'edge_colors':None,
....: 'edge_labels':False,
....: 'iterations':50,
....: 'tree_orientation':'down',
....: 'heights':None,
(continues on next page)

5.17. Graph Plotting 701


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


....: 'graph_border':False,
....: 'talk':False,
....: 'color_by_label':False,
....: 'partition':None,
....: 'dist':.075,
....: 'max_dist':1.5,
....: 'loop_size':.075,
....: 'edge_labels_background':'transparent'}
sage: g = Graph({0:[1,2], 2:[3], 4:[0,1]})
sage: GP = GraphPlot(g, options)

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

sage: from sage.graphs.graph_plot import GraphPlot


sage: G = graphs.HoffmanSingletonGraph()
sage: T = Graph()
sage: T.add_edges(G.min_spanning_tree(starting_vertex=0))
sage: T.show(layout='tree',tree_root=0) # 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.

We can specify some pretty precise plotting of familiar graphs:


sage: from math import sin, cos, pi
sage: P = graphs.PetersenGraph()
sage: d = {'#FF0000':[0,5], '#FF9900':[1,6], '#FFFF00':[2,7], '#00FF00':[3,8],
....: '#0000FF':[4,9]}
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):
(continues on next page)

702 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


....: 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.graphplot(pos=pos_dict, vertex_colors=d)
sage: pl.show()

Here are some more common graphs with typical options:


sage: C = graphs.CubeGraph(8)
sage: P = C.graphplot(vertex_labels=False, vertex_size=0, graph_border=True)
sage: P.show()

sage: G = graphs.HeawoodGraph().copy(sparse=True)
sage: for u,v,l in G.edges():
....: G.set_edge_label(u,v,'(' + str(u) + ',' + str(v) + ')')
sage: G.graphplot(edge_labels=True).show()

The options for plotting also work with directed graphs:


sage: D = DiGraph( { 0: [1, 10, 19], 1: [8, 2], 2: [3, 6], 3: [19, 4],
....: 4: [17, 5], 5: [6, 15], 6: [7], 7: [8, 14], 8: [9], 9: [10, 13],
....: 10: [11], 11: [12, 18], 12: [16, 13], 13: [14], 14: [15], 15: [16],
(continues on next page)

5.17. Graph Plotting 703


Sage Reference Manual: Graph Theory, Release 8.4

704 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

5.17. Graph Plotting 705


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


....: 16: [17], 17: [18], 18: [19], 19: []})
sage: for u,v,l in D.edges():
....: D.set_edge_label(u,v,'(' + str(u) + ',' + str(v) + ')')
sage: D.graphplot(edge_labels=True, layout='circular').show()

This example shows off the coloring of edges:


sage: from sage.plot.colors import rainbow
sage: C = graphs.CubeGraph(5)
sage: R = rainbow(5)
sage: edge_colors = {}
sage: for i in range(5):
....: edge_colors[R[i]] = []
sage: for u,v,l in C.edges():
....: for i in range(5):
....: if u[i] != v[i]:
....: edge_colors[R[i]].append((u,v,l))
sage: C.graphplot(vertex_labels=False, vertex_size=0, edge_colors=edge_
˓→colors).show()

With the partition option, we can separate out same-color groups of vertices:

sage: D = graphs.DodecahedralGraph()
(continues on next page)

706 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

5.17. Graph Plotting 707


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


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)

Loops are also plotted correctly:

sage: G = graphs.PetersenGraph()
sage: G.allow_loops(True)
sage: G.add_edge(0,0)
sage: G.show()

sage: D = DiGraph({0:[0,1], 1:[2], 2:[3]}, loops=True)


sage: D.show()
sage: D.show(edge_colors={(0,1,0):[(0,1,None),(1,2,None)],(0,0,0):[(2,3,
˓→None)]})

More options:

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({0:[1], 1:[2], 2:[3], 3:[4], 4:[0]})
sage: g.graphplot(pos=pos, layout='spring', iterations=0).plot()
Graphics object consisting of 11 graphics primitives

708 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

5.17. Graph Plotting 709


Sage Reference Manual: Graph Theory, Release 8.4

710 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

5.17. Graph Plotting 711


Sage Reference Manual: Graph Theory, Release 8.4

sage: G = Graph()
sage: P = G.graphplot().plot()
sage: P.axes()
False
sage: G = DiGraph()
sage: P = G.graphplot().plot()
sage: P.axes()
False

We can plot multiple graphs:


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 = 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)

712 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

5.17. Graph Plotting 713


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


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.graphplot(heights={0:[0], 1:[4,5,1], 2:[2], 3:[3,6]}, edge_
˓→labels=True).plot()

Graphics object consisting of 20 graphics primitives

sage: T = list(graphs.trees(7))
sage: t = T[3]
sage: t.graphplot(layout='tree').show()

The tree layout is also useful:

sage: t = DiGraph('JCC???@A??GO??CO??GO??')
sage: t.graphplot(layout='tree', tree_root=0, tree_orientation="up").show()

More examples:

sage: D = DiGraph({0:[1,2,3], 2:[1,4], 3:[0]})


sage: D.graphplot().show()

714 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

5.17. Graph Plotting 715


Sage Reference Manual: Graph Theory, Release 8.4

716 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

5.17. Graph Plotting 717


Sage Reference Manual: Graph Theory, Release 8.4

sage: D = DiGraph(multiedges=True, sparse=True)


sage: for i in range(5):
....: D.add_edge((i,i+1,'a'))
....: D.add_edge((i,i-1,'b'))
sage: D.graphplot(edge_labels=True,edge_colors=D._color_by_label()).plot()
Graphics object consisting of 34 graphics primitives

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: g.graphplot(edge_labels=True, color_by_label=True, edge_style='dashed').
˓→plot()

Graphics object consisting of 26 graphics primitives

The edge_style option may be provided in the short format too:


sage: g.graphplot(edge_labels=True, color_by_label=True, edge_style='--').
˓→plot()

Graphics object consisting of 26 graphics primitives

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.

718 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

5.17. Graph Plotting 719


Sage Reference Manual: Graph Theory, Release 8.4

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_edges(edge_style='solid')
sage: GP.plot()
Graphics object consisting of 26 graphics primitives

sage: GP.set_edges(edge_color='black')
sage: GP.plot()
Graphics object consisting of 26 graphics primitives

sage: d = DiGraph({}, loops=True, multiedges=True, sparse=True)


sage: d.add_edges([(0,0,'a'),(0,0,'b'),(0,1,'c'),(0,1,'d'),
....: (0,1,'e'),(0,1,'f'),(0,1,'f'),(2,1,'g'),(2,2,'h')])
sage: GP = d.graphplot(vertex_size=100, edge_labels=True, color_by_label=True,
....: edge_style='dashed')
sage: GP.set_edges(edge_style='solid')
sage: GP.plot()
Graphics object consisting of 28 graphics primitives

720 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

5.17. Graph Plotting 721


Sage Reference Manual: Graph Theory, Release 8.4

722 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: g = Graph({0:[1,2], 2:[3], 4:[0,1]})


sage: g.graphplot(save_pos=True, layout='circular') # indirect doctest
GraphPlot object for Graph on 5 vertices

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...)}

5.17. Graph Plotting 723


Sage Reference Manual: Graph Theory, Release 8.4

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)

724 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

5.17. Graph Plotting 725


Sage Reference Manual: Graph Theory, Release 8.4

726 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

Shows the (Di)Graph associated with this GraphPlot object.


INPUT:
This method accepts all parameters of sage.plot.graphics.Graphics.show().

Note:
• See the module's documentation for information on default values of this method.
• Any options not used by plot will be passed on to the show() method.

EXAMPLES:

sage: C = graphs.CubeGraph(8)
sage: P = C.graphplot(vertex_labels=False, vertex_size=0, graph_border=True)
sage: P.show()

5.18 Graph plotting in Javascript with d3.js

This module implements everything that can be used to draw graphs with d3.js in Sage.

5.18. Graph plotting in Javascript with d3.js 727


Sage Reference Manual: Graph Theory, Release 8.4

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.

728 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

5.18.1 Functions

sage.graphs.graph_plot_js.gen_html_code(G, vertex_labels=True, edge_labels=False,


vertex_partition=[], vertex_colors=None,
edge_partition=[], force_spring_layout=False,
charge=-120, link_distance=30, link_strength=2,
gravity=0.04, vertex_size=7, edge_thickness=4)
Creates a .html file showing the graph using d3.js.
This function returns the name of the .html file. If you want to visualize the actual graph use show().
INPUT:
• G – the graph
• vertex_labels (boolean) – Whether to display vertex labels (set to False by default).
• edge_labels (boolean) – Whether to display edge labels (set to False by default).
• vertex_partition – a list of lists representing a partition of the vertex set. Vertices are then colored
in the graph according to the partition. Set to [] by default.
• vertex_colors – a dictionary representing a partition of the vertex set. Keys are colors (ignored) and
values are lists of vertices. Vertices are then colored in the graph according to the partition. Set to None
by default.
• edge_partition – same as vertex_partition, with edges instead. Set to [] by default.
• force_spring_layout – whether to take previously computed position of nodes into account if there
is one, or to compute a spring layout. Set to False by default.
• vertex_size – The size of a vertex’ circle. Set to 7 by default.
• edge_thickness – Thickness of an edge. Set to 4 by default.
• charge – the vertices’ charge. Defines how they repulse each other. See https://github.com/mbostock/
d3/wiki/Force-Layout for more information. Set to -120 by default.
• link_distance – See https://github.com/mbostock/d3/wiki/Force-Layout for more information. Set
to 30 by default.
• link_strength – See https://github.com/mbostock/d3/wiki/Force-Layout for more information. Set
to 2 by default.
• gravity – See https://github.com/mbostock/d3/wiki/Force-Layout for more information. Set to 0.04
by default.

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: graphs.RandomTree(50).show(method="js") # optional -- internet

sage: g = graphs.PetersenGraph()
sage: g.show(method = "js", vertex_partition=g.coloring()) # optional -- internet

sage: graphs.DodecahedralGraph().show(method="js", force_spring_layout=True) #


˓→optional -- internet

(continues on next page)

5.18. Graph plotting in Javascript with d3.js 729


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)

sage: graphs.DodecahedralGraph().show(method="js") # 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

5.19 Vertex separation

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:

𝑐(𝑣1 , ..., 𝑣𝑛 ) = max 𝑐′ ({𝑣1 , ..., 𝑣𝑖 })


1≤𝑖≤𝑛

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

pathwidth() Computes the pathwidth of self (and provides a decomposition)


path_decomposition() Returns the pathwidth of the given graph and the ordering of the vertices result-
ing in a corresponding path decomposition
vertex_separation() Returns an optimal ordering of the vertices and its cost for vertex-separation
vertex_separation_exp() Computes the vertex separation of 𝐺 using an exponential time and space algo-
rithm
vertex_separation_MILP()Computes the vertex separation of 𝐺 and the optimal ordering of its vertices
using an MILP formulation
vertex_separation_BAB() Computes the vertex separation of 𝐺 and the optimal ordering of its vertices
using a branch and bound algorithm
lower_bound() Returns a lower bound on the vertex separation of 𝐺
is_valid_ordering() Test if the linear vertex ordering 𝐿 is valid for (di)graph 𝐺
Returns the width of the path decomposition induced by the linear ordering 𝐿
width_of_path_decomposition()
of the vertices of 𝐺
Return the path decomposition encoded in the ordering 𝐿
linear_ordering_to_path_decomposition()

730 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

5.19.1 Exponential algorithm for vertex separation

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 : −𝐷

Lower bound on the vertex separation


One can obtain a lower bound on the vertex separation of a graph in exponential time but small memory
by computing once the cost of each set 𝑆. Indeed, the cost of a sequence 𝑣1 , ..., 𝑣𝑛 corresponding to sets
{𝑣1 }, {𝑣1 , 𝑣2 }, ..., {𝑣1 , ..., 𝑣𝑛 } is

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.

5.19.2 MILP formulation for the vertex separation

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:

5.19. Vertex separation 731


Sage Reference Manual: Graph Theory, Release 8.4

• 𝑦𝑣𝑡 – 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.

5.19.3 Branch and Bound algorithm for the vertex separation

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.

732 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

• 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

• Nathann Cohen (2011-10): Initial version and exact exponential algorithm


• David Coudert (2012-04): MILP formulation and tests functions
• David Coudert (2015-01): BAB formulation and tests functions

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: from sage.graphs.graph_decompositions import vertex_separation


sage: G = graphs.CycleGraph(6)
sage: L = [u for u in G.vertices()]
sage: vertex_separation.is_valid_ordering(G, L)
True
sage: vertex_separation.is_valid_ordering(G, [1,2])
False

5.19. Vertex separation 733


Sage Reference Manual: Graph Theory, Release 8.4

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: from sage.graphs.graph_decompositions.vertex_separation import vertex_


˓→separation

sage: from sage.graphs.graph_decompositions.vertex_separation import linear_


˓→ordering_to_path_decomposition

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})]

Giving a non-optimal linear ordering:

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:

734 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

A lower bound on the vertex separation of 𝐷 (see the module’s documentation).

Note: This method runs in exponential time but has no memory constraint.

EXAMPLES:
On a circuit:

sage: from sage.graphs.graph_decompositions.vertex_separation import lower_bound


sage: g = digraphs.Circuit(6)
sage: lower_bound(g)
1

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:

• Graph.treewidth() – computes the treewidth of a graph

EXAMPLES:
The pathwidth of a cycle is equal to 2:

5.19. Vertex separation 735


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.graph_decompositions.vertex_separation import path_


˓→decomposition

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:

• Graph.treewidth() – computes the treewidth of a graph


• vertex_separation() – computes the vertex separation of a (di)graph

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}]

736 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

The pathwidth of a Petersen graph is 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: from sage.graphs.graph_decompositions.vertex_separation import vertex_


˓→separation

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)

5.19. Vertex separation 737


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


2
sage: vs,L = vertex_separation(G, algorithm="MILP"); vs
2
sage: G = graphs.Grid2dGraph(3,3)
sage: vs,L = vertex_separation(G, algorithm="BAB"); vs
3
sage: vs,L = vertex_separation(G, algorithm="exponential"); vs
3
sage: vs,L = vertex_separation(G, algorithm="MILP"); vs
3

Digraphs with multiple strongly connected components:

sage: from sage.graphs.graph_decompositions.vertex_separation import vertex_


˓→separation

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:

738 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

• width – the computed vertex separation


• seq – an ordering of the vertices of width width.
EXAMPLES:
The algorithm is valid for the vertex separation:

sage: from sage.graphs.graph_decompositions import vertex_separation as VS


sage: D = digraphs.RandomDirectedGNP(15, .2)
sage: vb, seqb = VS.vertex_separation_BAB(D)
sage: vd, seqd = VS.vertex_separation_exp(D)
sage: vb == vd
True
sage: vb == VS.width_of_path_decomposition(D, seqb)
True

The vertex separation of a 𝑁 × 𝑁 grid is 𝑁 :

sage: from sage.graphs.graph_decompositions import vertex_separation as VS


sage: G = graphs.Grid2dGraph(4,4)
sage: vs, seq = VS.vertex_separation_BAB(G); vs
4
sage: vs == VS.width_of_path_decomposition(G, seq)
True

The vertex separation of a 𝑁 × 𝑀 grid with 𝑁 < 𝑀 is 𝑁 :

sage: from sage.graphs.graph_decompositions import vertex_separation as VS


sage: G = graphs.Grid2dGraph(3,5)
sage: vs, seq = VS.vertex_separation_BAB(G); vs
3
sage: vs == VS.width_of_path_decomposition(G, seq)
True

The vertex separation of circuit of order 𝑁 ≥ 2 is 1:

sage: from sage.graphs.graph_decompositions import vertex_separation as VS


sage: D = digraphs.Circuit(10)
sage: vs, seq = VS.vertex_separation_BAB(D); vs
1
sage: vs == VS.width_of_path_decomposition(D, seq)
True

The vertex separation of cycle of order 𝑁 ≥ 3 is 2:

sage: from sage.graphs.graph_decompositions import vertex_separation as VS


sage: G = graphs.CycleGraph(10)
sage: vs, seq = VS.vertex_separation_BAB(G); vs
2

The vertex separation of MycielskiGraph(5) is 10:

sage: from sage.graphs.graph_decompositions import vertex_separation as VS


sage: G = graphs.MycielskiGraph(5)
sage: vs, seq = VS.vertex_separation_BAB(G); vs
10

Searching for any solution with width less or equal to cut_off:

5.19. Vertex separation 739


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.graph_decompositions import vertex_separation as VS


sage: G = graphs.MycielskiGraph(5)
sage: vs, seq = VS.vertex_separation_BAB(G, cut_off=11); vs
11
sage: vs, seq = VS.vertex_separation_BAB(G, cut_off=10); vs
10
sage: vs, seq = VS.vertex_separation_BAB(G, cut_off=9); vs
10

Testing for the existence of a solution with width strictly less than upper_bound:

sage: from sage.graphs.graph_decompositions import vertex_separation as VS


sage: G = graphs.MycielskiGraph(5)
sage: vs, seq = VS.vertex_separation_BAB(G, upper_bound=11); vs
10
sage: vs, seq = VS.vertex_separation_BAB(G, upper_bound=10); vs
-1
sage: vs, seq = VS.vertex_separation_BAB(G, cut_off=11, upper_bound=10); vs
-1

Changing the parameters of the prefix storage:

sage: from sage.graphs.graph_decompositions import vertex_separation as VS


sage: G = graphs.MycielskiGraph(5)
sage: vs, seq = VS.vertex_separation_BAB(G, max_prefix_length=0); vs
10
sage: vs, seq = VS.vertex_separation_BAB(G, max_prefix_number=5); vs
10
sage: vs, seq = VS.vertex_separation_BAB(G, max_prefix_number=0); vs
10

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:

740 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.graph_decompositions import vertex_separation


sage: G = digraphs.DeBruijn(2,3)
sage: vs, L = vertex_separation.vertex_separation_MILP(G); vs
2
sage: vs == vertex_separation.width_of_path_decomposition(G, L)
True
sage: vse, Le = vertex_separation.vertex_separation(G); vse
2

The vertex separation of a circuit is 1:

sage: from sage.graphs.graph_decompositions import vertex_separation


sage: G = digraphs.Circuit(6)
sage: vs, L = vertex_separation.vertex_separation_MILP(G); vs
1

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: from sage.graphs.graph_decompositions.vertex_separation import vertex_


˓→separation_exp

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

𝑣𝑠𝐿 (𝐺) = max |𝑁 + (𝐿[: 𝑖]) ∖ 𝐿[: 𝑖]|


0≤𝑖<|𝑉 |−1

𝑝𝑤𝐿 (𝐺) = max |𝑁 (𝐿[: 𝑖]) ∖ 𝐿[: 𝑖]|


0≤𝑖<|𝑉 |−1

INPUT:
• G – a Graph or a DiGraph
• L – a linear ordering of the vertices of G

5.19. Vertex separation 741


Sage Reference Manual: Graph Theory, Release 8.4

EXAMPLES:
Path decomposition of a cycle:

sage: from sage.graphs.graph_decompositions import vertex_separation


sage: G = graphs.CycleGraph(6)
sage: L = [u for u in G.vertices()]
sage: vertex_separation.width_of_path_decomposition(G, L)
2

Directed path decomposition of a circuit:

sage: from sage.graphs.graph_decompositions import vertex_separation


sage: G = digraphs.Circuit(6)
sage: L = [u for u in G.vertices()]
sage: vertex_separation.width_of_path_decomposition(G, L)
1

5.20 Rank Decompositions of graphs

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

742 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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:

5.20. Rank Decompositions of graphs 743


Sage Reference Manual: Graph Theory, Release 8.4

• 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: from sage.graphs.graph_decompositions.rankwidth import rank_decomposition


sage: g = graphs.PetersenGraph()
sage: rank_decomposition(g)
(3, Graph on 19 vertices)

On more than 32 vertices:

sage: g = graphs.RandomGNP(40, .5)


sage: rank_decomposition(g)
Traceback (most recent call last):
...
RuntimeError: the rank decomposition cannot be computed on graphs of >= 32
˓→vertices

The empty graph:

sage: g = Graph()
sage: rank_decomposition(g)
(0, Graph on 0 vertices)

5.21 Bandwidth of undirected graphs

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:

𝑘 × 𝑑𝐺 (𝑣𝑖 , 𝑣𝑗 ) = 𝑘 × 𝑑𝐺 (𝑣𝑖 , 𝑣𝑠0 ) + 𝑘 × 𝑑𝐺 (𝑣𝑠0 , 𝑣𝑠1 ) + ... + 𝑘 × 𝑑𝐺 (𝑣𝑠𝑖−1 , 𝑣𝑠𝑖 ) + 𝑘 × 𝑑𝐺 (𝑣𝑠𝑖 , 𝑣𝑗 )


≥ |𝑣𝑖 − 𝑣𝑠0 | + |𝑣𝑠0 − 𝑣𝑠1 | + ... + |𝑣𝑠𝑖−1 − 𝑣𝑠𝑖 | + |𝑣𝑠𝑖 − 𝑣𝑗 |
≥ |𝑣𝑖 − 𝑣𝑗 |

5.21.2 Satisfiability of a partial assignment

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 ?

744 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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.

5.21.3 Solving the matching problem

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).

5.21.4 The algorithm

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.5 This module contains the following methods

bandwidth() Compute the bandwidth of an undirected graph


bandwidth_heuristics() Uses Boost heuristics to approximate the bandwidth of the input graph

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 𝑏𝑤(𝐺).

5.21. Bandwidth of undirected graphs 745


Sage Reference Manual: Graph Theory, Release 8.4

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 𝑤 ∈ 𝑉 (𝐺)∖𝑆}|

746 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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 𝐺

5.22.1 Exponential algorithm for cutwidth

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.

5.22. Cutwidth 747


Sage Reference Manual: Graph Theory, Release 8.4

5.22.2 MILP formulation for the cutwidth

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

• David Coudert (2015-06): Initial version

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

748 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

• algorithm – (default: "exponential") Specify the algorithm to use among


– exponential – Use an exponential time and space algorithm based on dynamic programming.
This algorithm only works on graphs with strictly 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.
• cut_off – (default: 0) This parameter is used 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.
• solver – (default: None) Specify a Linear Program (LP) solver to be used. If set to None,
the default one is used. This parameter is used only when algorithm='MILP'. For more in-
formation on LP solvers and which default solver is used, see the method solve of the class
MixedIntegerLinearProgram.
• verbose (boolean) – whether to display information on the computations.
OUTPUT:
A pair (cost, ordering) representing the optimal ordering of the vertices and its cost.
EXAMPLES:
Cutwidth of a Complete Graph:

sage: from sage.graphs.graph_decompositions.cutwidth import cutwidth


sage: G = graphs.CompleteGraph(5)
sage: cw,L = cutwidth(G); cw
6
sage: K = graphs.CompleteGraph(6)
sage: cw,L = cutwidth(K); cw
9
sage: cw,L = cutwidth(K+K); cw
9

The cutwidth of a 𝑝 × 𝑞 Grid Graph with 𝑝 ≤ 𝑞 is 𝑝 + 1:

sage: from sage.graphs.graph_decompositions.cutwidth import cutwidth


sage: G = graphs.Grid2dGraph(3,3)
sage: cw,L = cutwidth(G); cw
4
sage: G = graphs.Grid2dGraph(3,5)
sage: cw,L = cutwidth(G); cw
4

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.

5.22. Cutwidth 749


Sage Reference Manual: Graph Theory, Release 8.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 pair (cost, ordering) representing the optimal ordering of the vertices and its cost.
EXAMPLES:
Cutwidth of a Cycle graph:

sage: from sage.graphs.graph_decompositions import cutwidth


sage: G = graphs.CycleGraph(5)
sage: cw, L = cutwidth.cutwidth_MILP(G); cw
2
sage: cw == cutwidth.width_of_cut_decomposition(G, L)
True
sage: cwe, Le = cutwidth.cutwidth_dyn(G); cwe
2

Cutwidth of a Complete graph:

sage: from sage.graphs.graph_decompositions import cutwidth


sage: G = graphs.CompleteGraph(4)
sage: cw, L = cutwidth.cutwidth_MILP(G); cw
4
sage: cw == cutwidth.width_of_cut_decomposition(G, L)
True

Cutwidth of a Path graph:

sage: from sage.graphs.graph_decompositions import cutwidth


sage: G = graphs.PathGraph(3)
sage: cw, L = cutwidth.cutwidth_MILP(G); cw
1
sage: cw == cutwidth.width_of_cut_decomposition(G, L)
True

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.

750 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: from sage.graphs.graph_decompositions import cutwidth


sage: G = graphs.CycleGraph(6)
sage: L = G.vertices()
sage: cutwidth.width_of_cut_decomposition(G, L)
2

Cut decomposition of a Path graph:

sage: from sage.graphs.graph_decompositions import cutwidth


sage: P = graphs.PathGraph(6)
sage: cutwidth.width_of_cut_decomposition(P, [0, 1, 2, 3, 4, 5])
1
sage: cutwidth.width_of_cut_decomposition(P, [5, 0, 1, 2, 3, 4])
2
sage: cutwidth.width_of_cut_decomposition(P, [0, 2, 4, 1, 3, 5])
5

5.23 Products of graphs

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)

5.23.1 Cartesian product of graphs – the recognition problem

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

5.23. Products of graphs 751


Sage Reference Manual: Graph Theory, Release 8.4

• ℎ = ℎ′ 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.

752 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

1st criterion : As a corollary, we know that:


1. If two vertices 𝑢, 𝑣 have a unique common neighbor 𝑥, then 𝑢𝑥 and 𝑥𝑣 have the same color.
2. If two vertices 𝑢, 𝑣 have more that two common neighbors 𝑥1 , ..., 𝑥𝑘 then all edges between the 𝑥𝑖
and the vertices of 𝑢, 𝑣 have the same color. This is also a consequence of the first remark.
2nd criterion : if two edges 𝑢𝑣 and 𝑢′ 𝑣 ′ of the product graph 𝐺𝐻 are such that 𝑑(𝑢, 𝑢′ ) + 𝑑(𝑣, 𝑣 ′ ) ̸=
𝑑(𝑢, 𝑣 ′ ) + 𝑑(𝑣, 𝑢′ ) then the two edges 𝑢𝑣 and 𝑢′ 𝑣 ′ necessarily have the same color.
This is a consequence of the fact that for any two vertices 𝑢, 𝑣 of 𝐺𝐻 (where 𝑢 = (𝑢𝐺 , 𝑢𝐻 )
and 𝑣 = (𝑣𝐺 , 𝑣𝐻 )), we have 𝑑(𝑢, 𝑣) = 𝑑𝐺 (𝑢𝐺 , 𝑣𝐺 ) + 𝑑𝐻 (𝑢𝐻 , 𝑣𝐻 ). Indeed, a shortest path
from 𝑢 to 𝑣 in 𝐺𝐻 contains the information of a shortest path from 𝑢𝐺 to 𝑣𝐺 in 𝐺, and a
shortest path from 𝑢𝐻 to 𝑣𝐻 in 𝐻.

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. Products of graphs 753


Sage Reference Manual: Graph Theory, Release 8.4

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: from sage.graphs.graph_decompositions.graph_products import is_cartesian_


˓→product

sage: g = graphs.PetersenGraph()
sage: is_cartesian_product(g)
False

A 2d grid is the product of paths:

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

Forgetting the graph’s labels, then finding them back:

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:

754 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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

5.24 Convexity properties of graphs

This class gathers the algorithms related to convexity in a graph. It implements the following methods:

ConvexityProperties. Returns the convex hull of a set of vertices


hull()
ConvexityProperties. Computes the hull number of a graph and a corresponding generating set.
hull_number()

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:

5.24. Convexity properties of graphs 755


Sage Reference Manual: Graph Theory, Release 8.4

• 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:

sage: from sage.graphs.convexity_properties import ConvexityProperties


sage: g = graphs.PetersenGraph()
sage: CP = ConvexityProperties(g)
sage: CP.hull([1,3])
[1, 2, 3]
sage: CP.hull_number()
3

hull(vertices)
Returns the convex hull of a set of vertices.
INPUT:
• vertices – A list of vertices.
EXAMPLES:

sage: from sage.graphs.convexity_properties import ConvexityProperties


sage: g = graphs.PetersenGraph()
sage: CP = ConvexityProperties(g)
sage: CP.hull([1,3])
[1, 2, 3]

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.

756 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: from sage.graphs.convexity_properties import ConvexityProperties


sage: g = graphs.PetersenGraph()
sage: CP = ConvexityProperties(g)
sage: CP.hull_number()
3
sage: generating_set = CP.hull_number(value_only = False)
sage: CP.hull(generating_set)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

REFERENCE:

5.25 Weakly chordal graphs

This module deals with everything related to weakly chordal graphs. It currently contains the following functions:

is_long_hole_free() Tests whether g contains an induced cycle of length at least 5.


is_long_antihole_free() Tests whether g contains an induced anticycle of length at least 5.
is_weakly_chordal() Tests whether g is weakly chordal.

5.25. Weakly chordal graphs 757


Sage Reference Manual: Graph Theory, Release 8.4

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

The complement of a cycle is an antihole:

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:

758 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

• 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

The following graph contains a hole, which we want to display:

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:

5.25. Weakly chordal graphs 759


Sage Reference Manual: Graph Theory, Release 8.4

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

5.26 Distances/shortest paths between all pairs of vertices

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.

5.26.1 The module’s main function

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.

760 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

• 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.

Warning: The function all_pairs_shortest_path_BFS has no reason to be called by the


user, even though he would be writing his code in Cython and look for efficiency. This module contains
wrappers for this function that feed it with the good parameters. As the function is inlined, using those
wrappers actually saves time as it should avoid testing the parameters again and again in the main
function’s body.

AUTHOR:
• Nathann Cohen (2011)
• David Coudert (2014) – 2sweep, multi-sweep and iFUB for diameter computation
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 𝐺.

5.26. Distances/shortest paths between all pairs of vertices 761


Sage Reference Manual: Graph Theory, Release 8.4

– 'multi-sweep' – Computes a lower bound on the diameter of an unweighted undirected graph


using several iterations of the 2sweep algorithms [CGH+13]. Roughly, it first uses 2sweep to
identify two vertices 𝑢 and 𝑣 that are far apart. Then it selects a vertex 𝑤 that is at same distance from
𝑢 and 𝑣. This vertex 𝑤 will serve as the new source for another iteration of the 2sweep algorithm
that may improve the current lower bound on the diameter. This process is repeated as long as the
lower bound on the diameter is improved.
– 'iFUB' – The iFUB (iterative Fringe Upper Bound) algorithm, proposed in [CGI+10], computes
the exact value of the diameter of an unweighted undirected graph. It is based on the following
observation:
The diameter of the graph is equal to the maximum eccentricity of a vertex. Let 𝑣 be any
vertex, and let 𝑉 be partitionned into 𝐴 ∪ 𝐵 where:

𝑑(𝑣, 𝑎) <= 𝑖, ∀𝑎 ∈ 𝐴
𝑑(𝑣, 𝑏) >= 𝑖, ∀𝑏 ∈ 𝐵

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:

sage: from sage.graphs.distances_all_pairs import diameter


sage: G = graphs.PetersenGraph()
sage: diameter(G, algorithm='iFUB')
2
sage: G = Graph( { 0 : [], 1 : [], 2 : [1] } )
sage: diameter(G, algorithm='iFUB')
+Infinity

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

Comparison of exact algorithms:

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!")

Comparison of lower bound algorithms:

762 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

sage: lb2 = diameter(G, algorithm='2sweep')


sage: lbm = diameter(G, algorithm='multi-sweep')
sage: if not (lb2<=lbm and lbm<=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)

5.26. Distances/shortest paths between all pairs of vertices 763


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


4: {0: 4, 1: 0, 2: 3, 3: 4, 4: None, 5: 0, 6: 9, 7: 9, 8: 3, 9: 4},
5: {0: 5, 1: 0, 2: 7, 3: 8, 4: 0, 5: None, 6: 8, 7: 5, 8: 5, 9: 7},
6: {0: 1, 1: 6, 2: 1, 3: 8, 4: 9, 5: 8, 6: None, 7: 9, 8: 6, 9: 6},
7: {0: 5, 1: 2, 2: 7, 3: 2, 4: 9, 5: 7, 6: 9, 7: None, 8: 5, 9: 7},
8: {0: 5, 1: 6, 2: 3, 3: 8, 4: 3, 5: 8, 6: 8, 7: 5, 8: None, 9: 6},
9: {0: 4, 1: 6, 2: 7, 3: 4, 4: 9, 5: 7, 6: 9, 7: 9, 8: 6, 9: None}})

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()
{}

A Graph of order 2 without edge:

sage: g = Graph()
sage: g.add_vertices([1,2])
sage: g.distances_distribution()
{+Infinity: 1}

The Petersen Graph:

sage: g = graphs.PetersenGraph()
sage: g.distances_distribution()
{1: 1/3, 2: 2/3}

A graph with multiple disconnected components:

sage: g = graphs.PetersenGraph()
sage: g.add_edge('good','wine')
sage: g.distances_distribution()
{1: 8/33, 2: 5/11, +Infinity: 10/33}

The de Bruijn digraph dB(2,3):

764 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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: from sage.graphs.distances_all_pairs import eccentricity


sage: g = graphs.PetersenGraph()
sage: eccentricity(g)
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2]

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.

5.26. Distances/shortest paths between all pairs of vertices 765


Sage Reference Manual: Graph Theory, Release 8.4

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}}

Checking the distances are correct

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

Checking a random path is valid

sage: u,v = g.random_vertex(), g.random_vertex()


sage: p = [v]
sage: while p[0] is not None:
....: p.insert(0,path[u][p[0]])
sage: len(p) == dist[u][v] + 2
True

Distances for all pairs of vertices in a diamond:

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:

766 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

• 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: from sage.graphs.distances_all_pairs import shortest_path_all_pairs


sage: g = graphs.PetersenGraph()
sage: shortest_path_all_pairs(g)
{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},
4: {0: 4, 1: 0, 2: 3, 3: 4, 4: None, 5: 0, 6: 9, 7: 9, 8: 3, 9: 4},
5: {0: 5, 1: 0, 2: 7, 3: 8, 4: 0, 5: None, 6: 8, 7: 5, 8: 5, 9: 7},
6: {0: 1, 1: 6, 2: 1, 3: 8, 4: 9, 5: 8, 6: None, 7: 9, 8: 6, 9: 6},
7: {0: 5, 1: 2, 2: 7, 3: 2, 4: 9, 5: 7, 6: 9, 7: None, 8: 5, 9: 7},
8: {0: 5, 1: 6, 2: 3, 3: 8, 4: 3, 5: 8, 6: 8, 7: 5, 8: None, 9: 6},
9: {0: 4, 1: 6, 2: 7, 3: 4, 4: 9, 5: 7, 6: 9, 7: 9, 8: 6, 9: None}}

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 𝑣.
∑︀

• Let Ω be a set of 𝑛(𝑛−1)


2 paths in 𝐺 such that Ω contains exactly one shortest 𝑢 − 𝑣 path for each set
{𝑢, 𝑣} of vertices
∑︀ in 𝐺. Besides, ∀𝑒 ∈ 𝐸(𝐺), let Ω(𝑒) denote the paths from Ω containing 𝑒. We then have
𝑊 (𝐺) = 𝑒∈𝐸(𝐺) |Ω(𝑒)|.

5.26. Distances/shortest paths between all pairs of vertices 767


Sage Reference Manual: Graph Theory, Release 8.4

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

5.27 LaTeX options for graphs

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

768 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

5.27.1 LaTeX Versions of Graphs

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

5.27. LaTeX options for graphs 769


Sage Reference Manual: Graph Theory, Release 8.4

• 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)

770 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


\definecolor{cfv2}{rgb}{1.0,1.0,1.0}
\definecolor{clv2}{rgb}{1.0,0.0,0.0}
\definecolor{cv3}{rgb}{0.0,0.502,0.0}
\definecolor{cfv3}{rgb}{1.0,1.0,1.0}
\definecolor{clv3}{rgb}{1.0,0.0,0.0}
\definecolor{cv4}{rgb}{0.0,0.502,0.0}
\definecolor{cfv4}{rgb}{1.0,1.0,1.0}
\definecolor{clv4}{rgb}{1.0,0.0,0.0}
\definecolor{cv5}{rgb}{0.0,0.502,0.0}
\definecolor{cfv5}{rgb}{1.0,1.0,1.0}
\definecolor{clv5}{rgb}{1.0,0.0,0.0}
\definecolor{cv6}{rgb}{0.0,0.502,0.0}
\definecolor{cfv6}{rgb}{1.0,1.0,1.0}
\definecolor{clv6}{rgb}{1.0,0.0,0.0}
\definecolor{cv7}{rgb}{0.0,0.502,0.0}
\definecolor{cfv7}{rgb}{1.0,1.0,1.0}
\definecolor{clv7}{rgb}{1.0,0.0,0.0}
\definecolor{cv8}{rgb}{0.0,0.502,0.0}
\definecolor{cfv8}{rgb}{1.0,1.0,1.0}
\definecolor{clv8}{rgb}{1.0,0.0,0.0}
\definecolor{cv9}{rgb}{0.0,0.502,0.0}
\definecolor{cfv9}{rgb}{1.0,1.0,1.0}
\definecolor{clv9}{rgb}{1.0,0.0,0.0}
\definecolor{cv10}{rgb}{0.0,0.502,0.0}
\definecolor{cfv10}{rgb}{1.0,1.0,1.0}
\definecolor{clv10}{rgb}{1.0,0.0,0.0}
\definecolor{cv11}{rgb}{0.0,0.502,0.0}
\definecolor{cfv11}{rgb}{1.0,1.0,1.0}
\definecolor{clv11}{rgb}{1.0,0.0,0.0}
\definecolor{cv12}{rgb}{0.0,0.502,0.0}
\definecolor{cfv12}{rgb}{1.0,1.0,1.0}
\definecolor{clv12}{rgb}{1.0,0.0,0.0}
\definecolor{cv13}{rgb}{0.0,0.502,0.0}
\definecolor{cfv13}{rgb}{1.0,1.0,1.0}
\definecolor{clv13}{rgb}{1.0,0.0,0.0}
\definecolor{cv0v1}{rgb}{0.0,0.502,0.0}
\definecolor{cv0v5}{rgb}{0.0,0.502,0.0}
\definecolor{cv0v13}{rgb}{0.0,0.502,0.0}
\definecolor{cv1v2}{rgb}{0.0,0.502,0.0}
\definecolor{cv1v10}{rgb}{0.0,0.502,0.0}
\definecolor{cv2v3}{rgb}{0.0,0.502,0.0}
\definecolor{cv2v7}{rgb}{0.0,0.502,0.0}
\definecolor{cv3v4}{rgb}{0.0,0.502,0.0}
\definecolor{cv3v12}{rgb}{0.0,0.502,0.0}
\definecolor{cv4v5}{rgb}{0.0,0.502,0.0}
\definecolor{cv4v9}{rgb}{0.0,0.502,0.0}
\definecolor{cv5v6}{rgb}{0.0,0.502,0.0}
\definecolor{cv6v7}{rgb}{0.0,0.502,0.0}
\definecolor{cv6v11}{rgb}{0.0,0.502,0.0}
\definecolor{cv7v8}{rgb}{0.0,0.502,0.0}
\definecolor{cv8v9}{rgb}{0.0,0.502,0.0}
\definecolor{cv8v13}{rgb}{0.0,0.502,0.0}
\definecolor{cv9v10}{rgb}{0.0,0.502,0.0}
\definecolor{cv10v11}{rgb}{0.0,0.502,0.0}
\definecolor{cv11v12}{rgb}{0.0,0.502,0.0}
\definecolor{cv12v13}{rgb}{0.0,0.502,0.0}
%
(continues on next page)

5.27. LaTeX options for graphs 771


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


\Vertex[style={minimum size=0.2cm,draw=cv0,fill=cfv0,text=clv0,shape=circle},
˓→LabelOut=false,L=\hbox{$0$},x=2.5cm,y=5.0cm]{v0}

\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.

772 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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}

This example illustrates using the optional dot2tex module:

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 {})

sage: latex(g) # optional - dot2tex graphviz


\begin{tikzpicture}[>=latex,line join=bevel,]
...
\end{tikzpicture}

5.27.2 GraphLatex class and functions

class sage.graphs.graph_latex.GraphLatex(graph, **options)


Bases: sage.structure.sage_object.SageObject
A class to hold, manipulate and employ options for converting a graph to LaTeX.
This class serves two purposes. First it holds the values of various options designed to work with the
tkz-graph LaTeX package for rendering graphs. As such, a graph that uses this class will hold a refer-
ence to it. Second, this class contains the code to convert a graph into the corresponding LaTeX constructs,
returning a string.

5.27. LaTeX options for graphs 773


Sage Reference Manual: Graph Theory, Release 8.4

EXAMPLES:

sage: from sage.graphs.graph_latex import GraphLatex


sage: opts = GraphLatex(graphs.PetersenGraph())
sage: opts
LaTeX options for Petersen graph: {}
sage: g = graphs.PetersenGraph()
sage: opts = g.latex_options()
sage: g == loads(dumps(g))
True

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);

\draw [black,->] (node_2) ..controls (...bp,...bp) and (...bp,...bp) ..


˓→(node_1);

\draw [black,->] (node_0) ..controls (...bp,...bp) and (...bp,...bp) ..


˓→(node_1);

\draw [black,->] (node_2) ..controls (...bp,...bp) and (...bp,...bp) ..


˓→(node_3);

%
\end{tikzpicture}

We make sure trac ticket #13624 is fixed:

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}

Check that trac ticket #25120 is fixed:

774 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: from sage.graphs.graph_latex import check_tkz_graph


sage: check_tkz_graph() # random - depends on TeX installation
sage: g = graphs.CompleteGraph(2)
sage: opts = g.latex_options()
(continues on next page)

5.27. LaTeX options for graphs 775


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: print(opts.latex())
\begin{tikzpicture}
\definecolor{cv0}{rgb}{0.0,0.0,0.0}
\definecolor{cfv0}{rgb}{1.0,1.0,1.0}
\definecolor{clv0}{rgb}{0.0,0.0,0.0}
\definecolor{cv1}{rgb}{0.0,0.0,0.0}
\definecolor{cfv1}{rgb}{1.0,1.0,1.0}
\definecolor{clv1}{rgb}{0.0,0.0,0.0}
\definecolor{cv0v1}{rgb}{0.0,0.0,0.0}
%
\Vertex[style={minimum size=1.0cm,draw=cv0,fill=cfv0,text=clv0,shape=circle},
˓→LabelOut=false,L=\hbox{$0$},x=2.5cm,y=5.0cm]{v0}

\Vertex[style={minimum size=1.0cm,draw=cv1,fill=cfv1,text=clv1,shape=circle},
˓→LabelOut=false,L=\hbox{$1$},x=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

776 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

• 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

5.27. LaTeX options for graphs 777


Sage Reference Manual: Graph Theory, Release 8.4

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

778 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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.

See sage.graphs.generic_graph.GenericGraph.layout_graphviz() for installation


instructions for graphviz and dot2tex. Further more, pgf >= 2.00 should be available inside La-
TeX’s tree for LaTeX compilation (e.g. when using view). In case your LaTeX distribution does not
provide it, here are short instructions:
• download pgf from http://sourceforge.net/projects/pgf/

5.27. LaTeX options for graphs 779


Sage Reference Manual: Graph Theory, Release 8.4

• unpack it in /usr/share/texmf/tex/generic (depends on your system)


• clean out remaining pgf files from older version
• run texhash
set_options(**kwds)
Set several LaTeX options for a graph all at once.
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. Errors are raised in the set_option() method.
EXAMPLES:

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.

sage: from sage.graphs.graph_latex import check_tkz_graph


sage: check_tkz_graph() # random - depends on TeX installation
sage: g = graphs.CompleteGraph(3)
sage: opts = g.latex_options()
sage: g.set_latex_options(tkz_style='Art')
sage: print(opts.tkz_picture())
\begin{tikzpicture}
\GraphInit[vstyle=Art]
%
\Vertex[L=\hbox{$0$},x=2.5cm,y=5.0cm]{v0}
\Vertex[L=\hbox{$1$},x=0.0cm,y=0.0cm]{v1}
\Vertex[L=\hbox{$2$},x=5.0cm,y=0.0cm]{v2}
%
\Edge[](v0)(v1)
\Edge[](v0)(v2)
\Edge[](v1)(v2)
%
\end{tikzpicture}

780 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

Setting the style to “Custom” results in various configurable aspects set to the defaults, so the string is
more involved.

sage: from sage.graphs.graph_latex import check_tkz_graph


sage: check_tkz_graph() # random - depends on TeX installation
sage: g = graphs.CompleteGraph(3)
sage: opts = g.latex_options()
sage: g.set_latex_options(tkz_style='Custom')
sage: print(opts.tkz_picture())
\begin{tikzpicture}
\definecolor{cv0}{rgb}{0.0,0.0,0.0}
\definecolor{cfv0}{rgb}{1.0,1.0,1.0}
\definecolor{clv0}{rgb}{0.0,0.0,0.0}
\definecolor{cv1}{rgb}{0.0,0.0,0.0}
\definecolor{cfv1}{rgb}{1.0,1.0,1.0}
\definecolor{clv1}{rgb}{0.0,0.0,0.0}
\definecolor{cv2}{rgb}{0.0,0.0,0.0}
\definecolor{cfv2}{rgb}{1.0,1.0,1.0}
\definecolor{clv2}{rgb}{0.0,0.0,0.0}
\definecolor{cv0v1}{rgb}{0.0,0.0,0.0}
\definecolor{cv0v2}{rgb}{0.0,0.0,0.0}
\definecolor{cv1v2}{rgb}{0.0,0.0,0.0}
%
\Vertex[style={minimum size=1.0cm,draw=cv0,fill=cfv0,text=clv0,shape=circle},
˓→LabelOut=false,L=\hbox{$0$},x=2.5cm,y=5.0cm]{v0}

\Vertex[style={minimum size=1.0cm,draw=cv1,fill=cfv1,text=clv1,shape=circle},
˓→LabelOut=false,L=\hbox{$1$},x=0.0cm,y=0.0cm]{v1}

\Vertex[style={minimum size=1.0cm,draw=cv2,fill=cfv2,text=clv2,shape=circle},
˓→LabelOut=false,L=\hbox{$2$},x=5.0cm,y=0.0cm]{v2}

%
\Edge[lw=0.1cm,style={color=cv0v1,},](v0)(v1)
\Edge[lw=0.1cm,style={color=cv0v2,},](v0)(v2)
\Edge[lw=0.1cm,style={color=cv1v2,},](v1)(v2)
%
\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().

5.27. LaTeX options for graphs 781


Sage Reference Manual: Graph Theory, Release 8.4

EXAMPLES:

sage: sage.graphs.graph_latex.setup_latex_preamble()

5.28 Graph editor

sage.graphs.graph_editor.graph_editor(graph=None, graph_name=None, re-


place_input=True, **layout_options)
Opens a graph editor in the Sage notebook.
INPUT:
• graph - a Graph instance (default: graphs.CompleteGraph(2)); the graph to edit
• graph_name - a string (default: None); the variable name to use for the updated instance; by default,
this function attempts to determine the name automatically
• replace_input - a boolean (default: True); whether to replace the text in the input cell with the updated
graph data when “Save” is clicked; if this is False, the data is still evaluated as if it had been entered in the
cell
EXAMPLES:

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: from sage.graphs.graph_editor import graph_to_js


sage: G = graphs.CompleteGraph(4)
sage: graph_to_js(G)
'num_vertices=4;edges=[[0,1],[0,2],[0,3],[1,2],[1,3],[2,3]];pos=[[0.5,0.0],[0.0,0.
˓→5],[0.5,1.0],[1.0,0.5]];'

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]];'

5.29 Lists of graphs

AUTHORS:
• Robert L. Miller (2007-02-10): initial version

782 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

• Emily A. Kirkman (2007-02-13): added show functions (to_graphics_array and show_graphs)


sage.graphs.graph_list.from_graph6(data)
Returns a list of Sage Graphs, given a list of graph6 data.
INPUT:
• data - can be a string, a list of strings, or a file stream.
EXAMPLES:

sage: 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: filename = tmp_filename()


sage: with open(filename, 'w') as fobj:
....: _ = fobj.write('\n'.join(l))
sage: with open(filename) as fobj:
....: graphs_list.from_whatever(fobj)
[Graph on 15 vertices, Looped multi-graph on 17 vertices]

sage.graphs.graph_list.show_graphs(graph_list, **kwds)
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.

5.29. Lists of graphs 783


Sage Reference Manual: Graph Theory, Release 8.4

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))

Check that length is = 20:

sage: len(glist)
14

Show the graphs in a graphics array:

sage: graphs_list.show_graphs(glist)

Here’s an example where more than one graphics array is used:

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_graph6(graphs, file=None, output_list=False)


Converts a list of Sage graphs to a single string of graph6 graphs. If file is specified, then the string will be
written quietly to the file. If output_list is True, then a list of strings will be returned, one string per graph.
INPUT:
• graphs - a Python list of Sage Graphs

784 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

• file - (optional) a file stream to write to (must be in ‘w’ mode)


• output_list - False - output is a string True - output is a list of strings (ignored if file gets specified)
EXAMPLES:

sage: l = [graphs.DodecahedralGraph(), graphs.PetersenGraph()]


sage: graphs_list.to_graph6(l)
'ShCHGD@?K?_@?@?C_GGG@??cG?G?GK_?C\nIheA@GUAo\n'

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

sage.graphs.graph_list.to_sparse6(graphs, file=None, output_list=False)


Converts a list of Sage graphs to a single string of sparse6 graphs. If file is specified, then the string will be
written quietly to the file. If output_list is True, then a list of strings will be returned, one string per graph.
INPUT:
• list - a Python list of Sage Graphs
• file - (optional) a file stream to write to (must be in ‘w’ mode)
• output_list - False - output is a string True - output is a list of strings (ignored if file gets specified)
EXAMPLES:

sage: l = [graphs.DodecahedralGraph(), graphs.PetersenGraph()]


sage: graphs_list.to_sparse6(l)
':S_`abcaDe`Fg_HijhKfLdMkNcOjP_BQ\n:I`ES@obGkqegW~\n'

5.29. Lists of graphs 785


Sage Reference Manual: Graph Theory, Release 8.4

5.30 Functions for reading/building graphs/digraphs.

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.

from_adjacency_matrix() Fill G with the data of an adjacency matrix.


from_dict_of_dicts() Fill G with the data of a dictionary of dictionaries.
from_dict_of_lists() Fill G with the data of a dictionary of lists.
from_dig6() Fill G with the data of a dig6 string.
from_graph6() Fill G with the data of a graph6 string.
from_incidence_matrix() Fill G with the data of an incidence matrix.
Fill G with the data of an oriented incidence matrix.
from_oriented_incidence_matrix()
Fill G with the data of a Seidel adjacency matrix.
from_seidel_adjacency_matrix()
from_sparse6() Fill G with the data of a sparse6 string.

5.30.1 Functions

sage.graphs.graph_input.from_adjacency_matrix(G, M, loops=False, multiedges=False,


weighted=False)
Fill G with the data of an adjacency matrix.
INPUT:
• G – a Graph or DiGraph.
• M – an adjacency matrix
• loops, multiedges, weighted (booleans) – whether to consider the graph as having loops, multiple
edges, or weights. Set to False by default.
EXAMPLES:

sage: from sage.graphs.graph_input import from_adjacency_matrix


sage: g = Graph()
sage: from_adjacency_matrix(g, graphs.PetersenGraph().adjacency_matrix())
sage: g.is_isomorphic(graphs.PetersenGraph())
True

sage.graphs.graph_input.from_dict_of_dicts(G, M, loops=False, multi-


edges=False, weighted=False, con-
vert_empty_dict_labels_to_None=False)
Fill G with the data of a dictionary of dictionaries.
INPUT:
• G – a graph
• M – a dictionary of dictionaries.
• loops, multiedges, weighted (booleans) – whether to consider the graph as having loops, multiple
edges, or weights. Set to False by default.

786 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

• convert_empty_dict_labels_to_None (boolean) – whether to adjust for empty dicts instead of


None in NetworkX default edge labels.
EXAMPLES:

sage: from sage.graphs.graph_input import from_dict_of_dicts


sage: g = Graph()
sage: from_dict_of_dicts(g, graphs.PetersenGraph().to_dictionary(edge_
˓→labels=True))

sage: g.is_isomorphic(graphs.PetersenGraph())
True

sage.graphs.graph_input.from_dict_of_lists(G, D, loops=False, multiedges=False,


weighted=False)
Fill G with the data of a dictionary of lists.
INPUT:
• G – a Graph or DiGraph.
• D – a dictionary of lists.
• loops, multiedges, weighted (booleans) – whether to consider the graph as having loops, multiple
edges, or weights. Set to False by default.
EXAMPLES:

sage: from sage.graphs.graph_input import from_dict_of_lists


sage: g = Graph()
sage: from_dict_of_lists(g, graphs.PetersenGraph().to_dictionary())
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: from sage.graphs.graph_input import from_dig6


sage: g = DiGraph()
sage: from_dig6(g, digraphs.Circuit(10).dig6_string())
sage: g.is_isomorphic(digraphs.Circuit(10))
True

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:

5.30. Functions for reading/building graphs/digraphs. 787


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.graph_input import from_graph6


sage: g = Graph()
sage: from_graph6(g, 'IheA@GUAo')
sage: g.is_isomorphic(graphs.PetersenGraph())
True

sage.graphs.graph_input.from_incidence_matrix(G, M, loops=False, multiedges=False,


weighted=False)
Fill G with the data of an incidence matrix.
INPUT:
• G – a graph
• 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: from sage.graphs.graph_input import from_incidence_matrix


sage: g = Graph()
sage: from_incidence_matrix(g, graphs.PetersenGraph().incidence_matrix())
sage: g.is_isomorphic(graphs.PetersenGraph())
True

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: from sage.graphs.graph_input import from_oriented_incidence_matrix


sage: g = DiGraph()
sage: from_oriented_incidence_matrix(g, digraphs.Circuit(10).incidence_matrix())
sage: g.is_isomorphic(digraphs.Circuit(10))
True

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:

788 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.graph_input import from_seidel_adjacency_matrix


sage: g = Graph()
sage: from_seidel_adjacency_matrix(g, graphs.PetersenGraph().seidel_adjacency_
˓→matrix())

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:

sage: from sage.graphs.graph_input import from_sparse6


sage: g = Graph()
sage: from_sparse6(g, ':I`ES@obGkqegW~')
sage: g.is_isomorphic(graphs.PetersenGraph())
True

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 𝑎,𝑏,𝑐,𝑑∈𝑉 (𝐺)

(note that ℎ𝑦𝑝(𝑎, 𝑏, 𝑐, 𝑑) = 0 whenever two elements among 𝑎, 𝑏, 𝑐, 𝑑 are equal)


Some known results :
• Trees and cliques are 0-hyperbolic
• 𝑛 × 𝑛 grids are 𝑛 − 1-hyperbolic
• Cycles are approximately 𝑛/4-hyperbolic
• Chordal graphs are ≤ 1-hyperbolic
Besides, the hyperbolicity of a graph is the maximum over all its biconnected components.
Algorithms and complexity :

5.31. Hyperbolicity 789


Sage Reference Manual: Graph Theory, Release 8.4

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

𝑆2 + 𝑆3 =𝑑𝑖𝑠𝑡(𝑎, 𝑐) + 𝑑𝑖𝑠𝑡(𝑏, 𝑑) + 𝑑𝑖𝑠𝑡(𝑎, 𝑑) + 𝑑𝑖𝑠𝑡(𝑏, 𝑐)


=[𝑑𝑖𝑠𝑡(𝑎, 𝑐) + 𝑑𝑖𝑠𝑡(𝑏, 𝑐)] + [𝑑𝑖𝑠𝑡(𝑎, 𝑑) + 𝑑𝑖𝑠𝑡(𝑏, 𝑑)]
≥𝑑𝑖𝑠𝑡(𝑎, 𝑏) + 𝑑𝑖𝑠𝑡(𝑎, 𝑏)
≥2𝑑𝑖𝑠𝑡(𝑎, 𝑏)

Now, since 𝑆1 is the largest sum, we have

ℎ𝑦𝑝(𝑎, 𝑏, 𝑐, 𝑑) =𝑆1 − max{𝑆2 , 𝑆3 }


𝑆2 + 𝑆3
≤𝑆1 −
2
≤𝑆1 − 𝑑𝑖𝑠𝑡(𝑎, 𝑏)
=𝑑𝑖𝑠𝑡(𝑐, 𝑑)

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

𝑑𝑖𝑠𝑡(𝑤, 𝑎) + 𝑑𝑖𝑠𝑡(𝑎, 𝑏) > 𝑑𝑖𝑠𝑡(𝑤, 𝑏) and 𝑑𝑖𝑠𝑡(𝑤, 𝑏) + 𝑑𝑖𝑠𝑡(𝑎, 𝑏) > 𝑑𝑖𝑠𝑡(𝑤, 𝑎)

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

This module contains the following functions


At Python level :

790 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

hyperbolicity() Return the hyperbolicity of the graph or an approximation of this value.


Return the hyperbolicity distribution of the graph or a sampling of it.
hyperbolicity_distribution()

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

sage.graphs.hyperbolicity.hyperbolicity(G, algorithm=’BCCM’, approxima-


tion_factor=None, additive_gap=None, ver-
bose=False)
Returns the hyperbolicity of the graph or an approximation of this value.
The hyperbolicity of a graph has been defined by Gromov [Gromov87] as follows: Let 𝑎, 𝑏, 𝑐, 𝑑 be vertices of
the graph, let 𝑆1 = 𝑑𝑖𝑠𝑡(𝑎, 𝑏) + 𝑑𝑖𝑠𝑡(𝑏, 𝑐), 𝑆2 = 𝑑𝑖𝑠𝑡(𝑎, 𝑐) + 𝑑𝑖𝑠𝑡(𝑏, 𝑑), and 𝑆3 = 𝑑𝑖𝑠𝑡(𝑎, 𝑑) + 𝑑𝑖𝑠𝑡(𝑏, 𝑐), and
let 𝑀1 and 𝑀2 be the two largest values among 𝑆1 , 𝑆2 , and 𝑆3 . We have ℎ𝑦𝑝(𝑎, 𝑏, 𝑐, 𝑑) = |𝑀1 − 𝑀2 |, and the
hyperbolicity of the graph is the maximum over all possible 4-tuples (𝑎, 𝑏, 𝑐, 𝑑) divided by 2. The worst case
time complexity is in 𝑂(𝑛4 ).
See the documentation of sage.graphs.hyperbolicity for more information.
INPUT:
• G – a connected Graph
• algorithm – (default: 'BCCM') specifies the algorithm to use among:
– 'basic' is an exhaustive algorithm considering all possible 4-tuples and so have time complexity
in 𝑂(𝑛4 ).
– 'CCL' is an exact algorithm proposed in [CCL15]. It considers the 4-tuples in an ordering allowing
to cut the search space as soon as a new lower bound is found (see the module’s documentation). This
algorithm can be turned into a approximation algorithm.
– 'CCL+FA' or 'CCL+' uses the notion of far-apart pairs as proposed in [Soto11] to significantly
reduce the overall computation time of the 'CCL' algorithm.
– 'BCCM' is an exact algorithm proposed in [BCCM15]. It improves 'CCL+FA' by cutting several
4-tuples (for more information, see the module’s documentation).
– 'dom' is an approximation with additive constant four. It computes the hyperbolicity of the vertices
of a dominating set of the graph. This is sometimes slower than 'CCL' and sometimes faster. Try it to
know if it is interesting for you. The additive_gap and approximation_factor parameters
cannot be used in combination with this method and so are ignored.
• approximation_factor – (default: None) When the approximation factor is set to some value (larger
than 1.0), the function stop computations as soon as the ratio between the upper bound and the best found
solution is less than the approximation factor. When the approximation factor is 1.0, the problem is solved
optimally. This parameter is used only when the chosen algorithm is 'CCL', 'CCL+FA', or 'BCCM'.

5.31. Hyperbolicity 791


Sage Reference Manual: Graph Theory, Release 8.4

• 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:

sage: from sage.graphs.hyperbolicity import hyperbolicity


sage: G = graphs.GridGraph([3,3])
sage: hyperbolicity(G,algorithm='BCCM')
(2, [(0, 0), (0, 2), (2, 0), (2, 2)], 2)
sage: hyperbolicity(G,algorithm='CCL')
(2, [(0, 0), (0, 2), (2, 0), (2, 2)], 2)
sage: hyperbolicity(G,algorithm='basic')
(2, [(0, 0), (0, 2), (2, 0), (2, 2)], 2)

Hyperbolicity of a PetersenGraph:

sage: from sage.graphs.hyperbolicity import hyperbolicity


sage: G = graphs.PetersenGraph()
sage: hyperbolicity(G,algorithm='BCCM')
(1/2, [6, 7, 8, 9], 1/2)
sage: hyperbolicity(G,algorithm='CCL')
(1/2, [0, 1, 2, 3], 1/2)
sage: hyperbolicity(G,algorithm='CCL+')
(1/2, [0, 1, 2, 3], 1/2)
sage: hyperbolicity(G,algorithm='CCL+FA')
(1/2, [0, 1, 2, 3], 1/2)
sage: hyperbolicity(G,algorithm='basic')
(1/2, [0, 1, 2, 3], 1/2)
sage: hyperbolicity(G,algorithm='dom')
(0, [0, 2, 8, 9], 1)

Asking for an approximation in a grid graph:

sage: from sage.graphs.hyperbolicity import hyperbolicity


sage: G = graphs.GridGraph([2,10])
sage: hyperbolicity(G,algorithm='CCL', approximation_factor=1.5)
(1, [(0, 0), (0, 9), (1, 0), (1, 9)], 3/2)
sage: hyperbolicity(G,algorithm='CCL+', approximation_factor=1.5)
(1, [(0, 0), (0, 9), (1, 0), (1, 9)], 1)
sage: hyperbolicity(G,algorithm='CCL', approximation_factor=4)
(1, [(0, 0), (0, 9), (1, 0), (1, 9)], 4)
(continues on next page)

792 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: hyperbolicity(G,algorithm='CCL', additive_gap=2)
(1, [(0, 0), (0, 9), (1, 0), (1, 9)], 3)
sage: hyperbolicity(G,algorithm='dom')
(1, [(0, 1), (0, 9), (1, 0), (1, 8)], 5)

Asking for an approximation in a cycle graph:

sage: from sage.graphs.hyperbolicity import hyperbolicity


sage: G = graphs.CycleGraph(10)
sage: hyperbolicity(G,algorithm='CCL', approximation_factor=1.5)
(2, [0, 2, 5, 7], 5/2)
sage: hyperbolicity(G,algorithm='CCL+FA', approximation_factor=1.5)
(2, [0, 2, 5, 7], 5/2)
sage: hyperbolicity(G,algorithm='CCL+FA', additive_gap=1)
(2, [0, 2, 5, 7], 5/2)

Comparison of results:

sage: from sage.graphs.hyperbolicity import hyperbolicity


sage: for i in range(10): # long time
....: G = graphs.RandomBarabasiAlbert(100,2)
....: d1,_,_ = hyperbolicity(G,algorithm='basic')
....: d2,_,_ = hyperbolicity(G,algorithm='CCL')
....: d3,_,_ = hyperbolicity(G,algorithm='CCL+')
....: d4,_,_ = hyperbolicity(G,algorithm='CCL+FA')
....: d5,_,_ = hyperbolicity(G,algorithm='BCCM')
....: l3,_,u3 = hyperbolicity(G,approximation_factor=2)
....: if (not d1==d2==d3==d4==d5) or l3>d1 or u3<d1:
....: print("That's not good!")

sage: from sage.graphs.hyperbolicity import hyperbolicity


sage: import random
sage: random.seed()
sage: for i in range(10): # long time
....: n = random.randint(2, 20)
....: m = random.randint(0, n*(n-1) / 2)
....: G = graphs.RandomGNM(n, m)
....: for cc in G.connected_components_subgraphs():
....: d1,_,_ = hyperbolicity(cc, algorithm='basic')
....: d2,_,_ = hyperbolicity(cc, algorithm='CCL')
....: d3,_,_ = hyperbolicity(cc, algorithm='CCL+')
....: d4,_,_ = hyperbolicity(cc, algorithm='CCL+FA')
....: d5,_,_ = hyperbolicity(cc, algorithm='BCCM')
....: l3,_,u3 = hyperbolicity(cc, approximation_factor=2)
....: if (not d1==d2==d3==d4==d5) or l3>d1 or u3<d1:
....: print("Error in graph ", cc.edges())

The hyperbolicity of a graph is the maximum value over all its biconnected components:

sage: from sage.graphs.hyperbolicity import hyperbolicity


sage: G = graphs.PetersenGraph() * 2
sage: G.add_edge(0, 11)
sage: hyperbolicity(G)
(1/2, [6, 7, 8, 9], 1/2)

sage.graphs.hyperbolicity.hyperbolicity_distribution(G, algorithm=’sampling’, sam-


pling_size=1000000)

5.31. Hyperbolicity 793


Sage Reference Manual: Graph Theory, Release 8.4

Return the hyperbolicity distribution of the graph or a sampling of it.


The hyperbolicity of a graph has been defined by Gromov [Gromov87] as follows: Let 𝑎, 𝑏, 𝑐, 𝑑 be vertices of
the graph, let 𝑆1 = 𝑑𝑖𝑠𝑡(𝑎, 𝑏) + 𝑑𝑖𝑠𝑡(𝑏, 𝑐), 𝑆2 = 𝑑𝑖𝑠𝑡(𝑎, 𝑐) + 𝑑𝑖𝑠𝑡(𝑏, 𝑑), and 𝑆3 = 𝑑𝑖𝑠𝑡(𝑎, 𝑑) + 𝑑𝑖𝑠𝑡(𝑏, 𝑐), and
let 𝑀1 and 𝑀2 be the two largest values among 𝑆1 , 𝑆2 , and 𝑆3 . We have ℎ𝑦𝑝(𝑎, 𝑏, 𝑐, 𝑑) = |𝑀1 − 𝑀2 |, and the
hyperbolicity of the graph is the maximum over all possible 4-tuples (𝑎, 𝑏, 𝑐, 𝑑) divided by 2.
The computation of the hyperbolicity of each 4-tuple, and so the hyperbolicity distribution, takes time in 𝑂(𝑛4 ).
INPUT:
• G – a Graph.
• algorithm – (default: ‘sampling’) When algorithm is ‘sampling’, it returns the distribution of the hy-
perbolicity over a sample of sampling_size 4-tuples. When algorithm is ‘exact’, it computes the
distribution of the hyperbolicity over all 4-tuples. Be aware that the computation time can be HUGE.
• sampling_size – (default: 106 ) number of 4-tuples considered in the sampling. Used only when
algorithm == 'sampling'.
OUTPUT:
• hdict – A dictionary such that hdict[i] is the number of 4-tuples of hyperbolicity i.
EXAMPLES:
Exact hyperbolicity distribution of the Petersen Graph:

sage: from sage.graphs.hyperbolicity import hyperbolicity_distribution


sage: G = graphs.PetersenGraph()
sage: hyperbolicity_distribution(G,algorithm='exact')
{0: 3/7, 1/2: 4/7}

Exact hyperbolicity distribution of a 3 × 3 grid:

sage: from sage.graphs.hyperbolicity import hyperbolicity_distribution


sage: G = graphs.GridGraph([3,3])
sage: hyperbolicity_distribution(G,algorithm='exact')
{0: 11/18, 1: 8/21, 2: 1/126}

5.32 Tutte polynomial

This module implements a deletion-contraction algorithm for computing the Tutte polynomial as described in the
paper [Gordon10].

tutte_polynomial() Computes the Tutte polynomial of the input graph

Authors:
• Mike Hansen (06-2013), Implemented the algorithm.
• Jernej Azarija (06-2013), Tweaked the code, added documentation

794 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

5.32.1 Definition

Given a graph 𝐺, with 𝑛 vertices and 𝑚 edges and 𝑘(𝐺) connected components we define the Tutte polynomial of 𝐺
as
∑︁
(𝑥 − 1)𝑘(𝐻)−𝑐 (𝑦 − 1)𝑘(𝐻)−|𝐸(𝐻)|−𝑛
𝐻

where the sum ranges over all induced subgraphs 𝐻 of 𝐺.


REFERENCES:

5.32.2 Functions

class sage.graphs.tutte_polynomial.Ear(graph, end_points, interior, is_cycle)


Bases: object
An ear is a sequence of vertices
Here is the definition from [Gordon10]:
An ear in a graph is a path 𝑣1 − 𝑣2 − · · · − 𝑣𝑛 − 𝑣𝑛+1 where 𝑑(𝑣1 ) > 2, 𝑑(𝑣𝑛+1 ) > 2 and 𝑑(𝑣2 ) = 𝑑(𝑣3 ) =
· · · = 𝑑(𝑣𝑛 ) = 2.
A cycle is viewed as a special ear where 𝑣1 = 𝑣𝑛+1 and the restriction on the degree of this vertex is lifted.
INPUT:
static find_ear(g)
Finds the first ear in a graph.
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.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

5.32. Tutte polynomial 795


Sage Reference Manual: Graph Theory, Release 8.4

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: from sage.graphs.tutte_polynomial import VertexOrder


sage: A = VertexOrder([4,6,3,2,1,7])
sage: A.order
[4, 6, 3, 2, 1, 7]
sage: A.inverse_order
{1: 4, 2: 3, 3: 2, 4: 0, 6: 1, 7: 5}

796 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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)

5.32. Tutte polynomial 797


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


[(0, 0, 'c')]
sage: G.edges()
[(0, 0, 'c'), (0, 1, 'a'), (1, 2, 'b')]

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: from sage.graphs.tutte_polynomial import removed_multiedge


sage: G = Graph(multiedges=True)
sage: G.add_edges([(0,1,'a'),(0,1,'b')])
sage: G.edges()
[(0, 1, 'a'), (0, 1, 'b')]
sage: with removed_multiedge(G,(0,1)) as Y:
....: G.edges()
[]
sage: G.edges()
[(0, 1, 'a'), (0, 1, 'b')]

sage.graphs.tutte_polynomial.tutte_polynomial(G, edge_selector=None, cache=None)


Return the Tutte polynomial of the graph 𝐺.
INPUT:
• edge_selector (optional; method) this argument allows the user to specify his own heuristic for se-
lecting edges used in the deletion contraction recurrence
• cache – (optional; dict) a dictionary to cache the Tutte polynomials generated in the recursive process.
One will be created automatically if not provided.
EXAMPLES:
The Tutte polynomial of any tree of order 𝑛 is 𝑥𝑛−1 :

sage: all(T.tutte_polynomial() == x**9 for T in graphs.trees(10))


True

The Tutte polynomial of the Petersen graph is:

sage: P = graphs.PetersenGraph()
sage: P.tutte_polynomial()
x^9 + 6*x^8 + 21*x^7 + 56*x^6 + 12*x^5*y + y^6 + 114*x^5 + 70*x^4*y
+ 30*x^3*y^2 + 15*x^2*y^3 + 10*x*y^4 + 9*y^5 + 170*x^4 + 170*x^3*y
+ 105*x^2*y^2 + 65*x*y^3 + 35*y^4 + 180*x^3 + 240*x^2*y + 171*x*y^2
+ 75*y^3 + 120*x^2 + 168*x*y + 84*y^2 + 36*x + 36*y

The Tutte polynomial of 𝐺 evaluated at (1,1) is the number of spanning trees of 𝐺:

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)

798 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: R = PolynomialRing(ZZ, 'x')
sage: R((-1)^5*x*T(1-x,0)).factor()
(x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32)
sage: G.chromatic_polynomial().factor()
(x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32)

sage.graphs.tutte_polynomial.underlying_graph(G)
Given a graph 𝐺 with multi-edges, returns a graph where all the multi-edges are replaced with a single edge.
EXAMPLES:

sage: from sage.graphs.tutte_polynomial import underlying_graph


sage: G = Graph(multiedges=True)
sage: G.add_edges([(0,1,'a'),(0,1,'b')])
sage: G.edges()
[(0, 1, 'a'), (0, 1, 'b')]
sage: underlying_graph(G).edges()
[(0, 1, None)]

5.33 Partial cubes

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:

5.33.1 Recognition algorithm

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.

5.33. Partial cubes 799


Sage Reference Manual: Graph Theory, Release 8.4

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:

800 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

• G – a graph to perform the search on.


• start – vertex or list of vertices from which to start the traversal.
OUTPUT:
• a generator of triples (v,w,edgetype), where edgetype is True if the algorithm is progressing via
the edge vw, or False if the algorithm is backtracking via the edge wv.
EXAMPLES:

sage: H = digraphs.DeBruijn(3,2)
sage: t = list(sage.graphs.partial_cube.depth_first_traversal(H, '00'))
sage: len(t)
16

sage.graphs.partial_cube.is_partial_cube(G, certificate=False)
Test whether the given graph is a partial cube.
A partial cube is a graph that can be isometrically embedded into a hypercube, i.e., its vertices can be labelled
with (0,1)-vectors of some fixed length such that the distance between any two vertices in the graph equals the
Hamming distance of their labels.
Originally written by D. Eppstein for the PADS library (http://www.ics.uci.edu/~eppstein/PADS/), see also
[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

All prisms are partial cubes:

sage: g = graphs.CycleGraph(10).cartesian_product(graphs.CompleteGraph(2))
sage: g.is_partial_cube()
True

5.34 GenericGraph Cython functions

AUTHORS:
• Robert L. Miller (2007-02-13): initial version
• Robert W. Bradshaw (2007-03-31): fast spring layout algorithms
• Nathann Cohen : exhaustive search

5.34. GenericGraph Cython functions 801


Sage Reference Manual: Graph Theory, Release 8.4

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

˓→'

802 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: binary_string_from_dig6('???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_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:

sage: from sage.graphs.generic_graph_pyx import binary_string_from_graph6


sage: binary_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?', 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:

sage: from sage.graphs.generic_graph_pyx import binary_string_to_graph6


sage: binary_string_to_graph6('110111010110110010111000001100000001000000001')
'vUqwK@?G'

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.

5.34. GenericGraph Cython functions 803


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: from sage.graphs.generic_graph_pyx import find_hamiltonian as fh


sage: G=graphs.DodecahedralGraph()
sage: fh(G)
(True, [12, 11, 10, 9, 13, 14, 15, 5, 4, 3, 2, 6, 7, 8, 1, 0, 19, 18, 17, 16])
sage: fh(G,find_path=True)
(True, [10, 0, 19, 3, 4, 5, 15, 16, 17, 18, 11, 12, 13, 9, 8, 1, 2, 6, 7, 14])

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:

804 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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])

Finally, an example on a graph which does not have a Hamiltonian path:


sage: G=graphs.HyperStarGraph(5,2)
sage: fh(G,find_path=False)
(False, ['00110', '10100', '01100', '11000', '01010', '10010', '00011', '10001',
˓→'00101'])

sage: fh(G,find_path=True)
(False, ['01001', '10001', '00101', '10100', '00110', '10010', '01010', '11000',
˓→'01100'])

sage.graphs.generic_graph_pyx.int_to_binary_string(n)
A quick python int to binary string conversion.
INPUT:
• n (integer)
EXAMPLES:
sage: sage.graphs.generic_graph_pyx.int_to_binary_string(389)
'110000101'
sage: Integer(389).binary()
'110000101'
sage: sage.graphs.generic_graph_pyx.int_to_binary_string(2007)
'11111010111'

sage.graphs.generic_graph_pyx.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)

5.34. GenericGraph Cython functions 805


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


(63, '?????_@?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?')

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: from sage.graphs.generic_graph_pyx import small_integer_to_graph6


sage: small_integer_to_graph6(13)
'L'
sage: small_integer_to_graph6(136)
'~?AG'

sage.graphs.generic_graph_pyx.spring_layout_fast(G, iterations=50, dim=2,


vpos=None, rescale=True,
height=False, by_component=False,
**options)
Spring force model layout
This function primarily acts as a wrapper around run_spring, converting to and from raw c types.
This kind of speed cannot be achieved by naive Cythonification of the function alone, especially if we require a
function call (let alone an object creation) every time we want to add a pair of doubles.
INPUT:
• by_component – a boolean
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.

806 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: from sage.graphs.generic_graph_pyx import transitive_reduction_acyclic


sage: G = posets.BooleanLattice(4).hasse_diagram()
sage: G == transitive_reduction_acyclic(G.transitive_closure())
True

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. Orientations 807


Sage Reference Manual: Graph Theory, Release 8.4

Return an iterator over all strong orientations of a graph 𝐺


strong_orientations_iterator()
random_orientation() Return a random orientation of a graph 𝐺

5.35.1 Authors

• Kolja Knauer, Petru Valicov (2017-01-10) – initial version

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:

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()

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.

808 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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

A tree cannot be strongly oriented:

sage: g = graphs.RandomTree(100)
sage: len(list(g.strong_orientations_iterator()))
0

Neither can be a disconnected graph:

sage: g = graphs.CompleteGraph(6)
sage: g.add_vertex(7)
sage: len(list(g.strong_orientations_iterator()))
0

5.36 Connectivity related functions

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:

is_connected() Test whether the (di)graph is connected.


connected_components() Return the list of connected components
Return the number of connected components.
connected_components_number()
Return a list of connected components as graph objects.
connected_components_subgraphs()
Return a list of the vertices connected to vertex.
connected_component_containing_vertex()
Return the sizes of the connected components as a list.
connected_components_sizes()
Compute the blocks and cut vertices of the graph.
blocks_and_cut_vertices()
blocks_and_cuts_tree() Compute the blocks-and-cuts tree of the graph.
is_cut_edge() Return True if the input edge is a cut-edge or a bridge.
is_cut_vertex() Return True if the input vertex is a cut-vertex.
edge_connectivity() Return the edge connectivity of the graph.
vertex_connectivity() Return the vertex connectivity of the graph.

For DiGraph:

5.36. Connectivity related functions 809


Sage Reference Manual: Graph Theory, Release 8.4

is_strongly_connected() Returns whether the current DiGraph is strongly connected.


Returns the digraph of the strongly connected components
strongly_connected_components_digraph()
Returns the strongly connected components as a list of subgraphs.
strongly_connected_components_subgraphs()
Returns the strongly connected component containing a given vertex.
strongly_connected_component_containing_vertex()
Return the strong articulation points of this digraph.
strong_articulation_points()

For undirected graphs:

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

810 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

EXAMPLES:
Example from the Wikipedia article SPQR_tree:

sage: from sage.graphs.connectivity import TriconnectivitySPQR


sage: from sage.graphs.connectivity import spqr_tree_to_graph
sage: G = Graph([(1, 2), (1, 4), (1, 8), (1, 12), (3, 4), (2, 3),
....: (2, 13), (3, 13), (4, 5), (4, 7), (5, 6), (5, 8), (5, 7), (6, 7),
....: (8, 11), (8, 9), (8, 12), (9, 10), (9, 11), (9, 12), (10, 12)])
sage: tric = TriconnectivitySPQR(G)
sage: T = tric.get_spqr_tree()
sage: G.is_isomorphic(spqr_tree_to_graph(T))
True

An example from [Hopcroft1973]:

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')]

Polygon: [(3, 4, None), (3, 1, 'newVEdge0'), (4, 1, 'newVEdge1')]


Bond: [(1, 4, None), (4, 1, 'newVEdge1'), (4, 1, 'newVEdge2')]
Polygon: [(6, 7, None), (5, 6, None), (7, 5, 'newVEdge3')]
Bond: [(7, 5, 'newVEdge3'), (5, 7, 'newVEdge4'), (5, 7, None)]
Polygon: [(5, 7, 'newVEdge4'), (4, 7, None), (5, 4, 'newVEdge5')]
Bond: [(4, 5, None), (5, 4, 'newVEdge5'), (5, 4, 'newVEdge6')]
Polygon: [(5, 4, 'newVEdge6'), (4, 1, 'newVEdge2'), (5, 8, None), (8, 1,
˓→'newVEdge8')]

Bond: [(1, 8, None), (8, 1, 'newVEdge8'), (8, 1, 'newVEdge9')]


Triconnected: [(8, 9, None), (9, 12, None), (9, 11, None), (8, 11, None), (10, 11,
˓→ None), (9, 10, None), (10, 12, None), (8, 12, 'newVEdge10')]

Bond: [(8, 12, 'newVEdge10'), (12, 8, 'newVEdge11'), (8, 12, None)]


Polygon: [(8, 1, 'newVEdge9'), (12, 8, 'newVEdge11'), (1, 12, None)]

An example from [Gut2001]:

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

An example with multi-edges and accessing the triconnected components:

sage: G = Graph([(1, 2), (1, 5), (1, 5), (2, 3), (2, 3), (3, 4), (4, 5)],
˓→multiedges=True)

sage: tric = TriconnectivitySPQR(G)


sage: tric.print_triconnected_components()
Bond: [(1, 5, None), (1, 5, None), (1, 5, 'newVEdge0')]
Bond: [(2, 3, None), (2, 3, None), (2, 3, 'newVEdge1')]
Polygon: [(4, 5, None), (1, 5, 'newVEdge0'), (3, 4, None), (2, 3, 'newVEdge1'),
˓→(1, 2, None)]

5.36. Connectivity related functions 811


Sage Reference Manual: Graph Theory, Release 8.4

An example of a triconnected graph:

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

An example of a directed graph with multi-edges:

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)]

Edge labels are preserved by the construction:

sage: G = Graph([(0, 1, '01'), (0, 4, '04'), (1, 2, '12'), (1, 5, '15'),


....: (2, 3, '23'), (2, 6, '26'), (3, 7, '37'), (4, 5, '45'),
....: (5, 6, '56'), (6, 7, 67)])
sage: T = TriconnectivitySPQR(G).get_spqr_tree()
sage: H = spqr_tree_to_graph(T)
sage: set(G.edges()) == set(H.edges())
True

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:

812 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

sage: from sage.graphs.connectivity import TriconnectivitySPQR


sage: G = Graph(2)
sage: for i in range(3):
....: G.add_clique([0, 1, G.add_vertex(), G.add_vertex()])
sage: tric = TriconnectivitySPQR(G)
sage: Tree = tric.get_spqr_tree()
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: 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

sage: G = Graph([(0, 1)], multiedges=True)


sage: tric = TriconnectivitySPQR(G)
sage: Tree = tric.get_spqr_tree()
sage: Tree.vertices()
[('Q', Multi-graph on 2 vertices)]
sage: G.add_edge(0, 1)
sage: Tree = TriconnectivitySPQR(G).get_spqr_tree()
sage: Tree.vertices()
[('P', Multi-graph on 2 vertices)]

5.36. Connectivity related functions 813


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: from sage.graphs.connectivity import TriconnectivitySPQR


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: tric.get_triconnected_components()
[('Polygon', [(4, 5, None), (0, 4, None), (1, 5, None), (1, 0, 'newVEdge1')]),
('Polygon', [(6, 7, None), (0, 6, None), (1, 7, None), (1, 0, 'newVEdge3')]),
('Bond', [(1, 0, 'newVEdge1'), (1, 0, 'newVEdge3'), (1, 0, 'newVEdge4')]),
('Polygon', [(1, 3, None), (1, 0, 'newVEdge4'), (2, 3, None), (0, 2, None)])]

print_triconnected_components()
Print the type and list of edges of each component.
EXAMPLES:
An example from [Hopcroft1973]:

sage: from sage.graphs.connectivity import TriconnectivitySPQR


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')]

Polygon: [(3, 4, None), (3, 1, 'newVEdge0'), (4, 1, 'newVEdge1')]


Bond: [(1, 4, None), (4, 1, 'newVEdge1'), (4, 1, 'newVEdge2')]
Polygon: [(6, 7, None), (5, 6, None), (7, 5, 'newVEdge3')]
Bond: [(7, 5, 'newVEdge3'), (5, 7, 'newVEdge4'), (5, 7, None)]
Polygon: [(5, 7, 'newVEdge4'), (4, 7, None), (5, 4, 'newVEdge5')]
Bond: [(4, 5, None), (5, 4, 'newVEdge5'), (5, 4, 'newVEdge6')]
Polygon: [(5, 4, 'newVEdge6'), (4, 1, 'newVEdge2'), (5, 8, None), (8, 1,
˓→'newVEdge8')]

Bond: [(1, 8, None), (8, 1, 'newVEdge8'), (8, 1, 'newVEdge9')]


Triconnected: [(8, 9, None), (9, 12, None), (9, 11, None), (8, 11, None), (10,
˓→ 11, None), (9, 10, None), (10, 12, None), (8, 12, 'newVEdge10')]

Bond: [(8, 12, 'newVEdge10'), (12, 8, 'newVEdge11'), (8, 12, None)]


Polygon: [(8, 1, 'newVEdge9'), (12, 8, 'newVEdge11'), (1, 12, None)]

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:

814 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

• algorithm – The algorithm to use in computing the blocks and cut vertices of G. The following al-
gorithms are supported:

– "Tarjan_Boost" (default) – Tarjan’s algorithm (Boost implementation).


– "Tarjan_Sage" – Tarjan’s algorithm (Sage implementation).

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: from sage.graphs.connectivity import blocks_and_cut_vertices


sage: rings = graphs.CycleGraph(10)
sage: rings.merge_vertices([0, 5])
sage: blocks_and_cut_vertices(rings)
([[0, 1, 4, 2, 3], [0, 6, 9, 7, 8]], [0])
sage: rings.blocks_and_cut_vertices()
([[0, 1, 4, 2, 3], [0, 6, 9, 7, 8]], [0])
sage: blocks_and_cut_vertices(rings, algorithm="Tarjan_Sage")
([[0, 1, 2, 3, 4], [0, 6, 7, 8, 9]], [0])

The Petersen graph is biconnected, hence has no cut vertices:

sage: blocks_and_cut_vertices(graphs.PetersenGraph())
([[0, 1, 4, 5, 2, 6, 3, 7, 8, 9]], [])

Decomposing paths to pairs:

sage: g = graphs.PathGraph(4) + graphs.PathGraph(5)


sage: blocks_and_cut_vertices(g)
([[2, 3], [1, 2], [0, 1], [7, 8], [6, 7], [5, 6], [4, 5]], [1, 2, 5, 6, 7])

A disconnected graph:

sage: g = Graph({1:{2:28, 3:10}, 2:{1:10, 3:16}, 4:{}, 5:{6:3, 7:10, 8:4}})


sage: blocks_and_cut_vertices(g)
([[1, 2, 3], [5, 6], [5, 7], [5, 8], [4]], [5])

A directed graph with Boost’s algorithm (trac ticket #25994):

5.36. Connectivity related functions 815


Sage Reference Manual: Graph Theory, Release 8.4

sage: rings = graphs.CycleGraph(10)


sage: rings.merge_vertices([0, 5])
sage: rings = rings.to_directed()
sage: blocks_and_cut_vertices(rings, algorithm="Tarjan_Boost")
([[0, 1, 4, 2, 3], [0, 6, 9, 7, 8]], [0])

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: from sage.graphs.connectivity import blocks_and_cuts_tree


sage: T = blocks_and_cuts_tree(graphs.KrackhardtKiteGraph()); T
Graph on 5 vertices
sage: T.is_isomorphic(graphs.PathGraph(5))
True
sage: from sage.graphs.connectivity import blocks_and_cuts_tree
sage: T = graphs.KrackhardtKiteGraph().blocks_and_cuts_tree(); T
Graph on 5 vertices

The distance between two leaves is even:

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

The tree of a biconnected graph has a single vertex, of type 𝐵:

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:

816 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

• labels – (default: True) if False, each bridge is a tuple (𝑢, 𝑣) of vertices


EXAMPLES:

sage: from sage.graphs.connectivity import bridges


sage: from sage.graphs.connectivity import is_connected
sage: g = 2*graphs.PetersenGraph()
sage: g.add_edge(1,10)
sage: is_connected(g)
True
sage: bridges(g)
[(1, 10, None)]
sage: g.bridges()
[(1, 10, None)]

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: from sage.graphs.connectivity import cleave


sage: G = Graph(2)
sage: for _ in range(3):
....: G.add_clique([0, 1, G.add_vertex(), G.add_vertex()])
sage: S1,C1,f1 = cleave(G, cut_vertices=[0, 1])
sage: [g.order() for g in S1]
[4, 4, 4]
(continues on next page)

5.36. Connectivity related functions 817


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: C1.order(), C1.size()
(2, 4)
sage: f1.vertices(), f1.edges()
([0, 1], [])

If virtual_edges == False and there is an edge between cut vertices:

sage: G.subgraph([0, 1]).complement() == Graph([[0, 1], []])


True
sage: S2,C2,f2 = cleave(G, cut_vertices=[0, 1], virtual_edges = False)
sage: (S1 == S2, C1 == C2, f1 == f2)
(True, True, True)

If cut vertices doesn’t have edge between them:

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:

sage: G.subgraph([0, 1]).complement() == Graph([[0, 1], []])


False
sage: S2,C2,f2 = cleave(G, cut_vertices=[0, 1], virtual_edges = False)
sage: [g.order() for g in S2]
[4, 4, 4]
sage: C2.order(), C2.size()
(2, 0)
sage: f2.vertices(), f2.edges()
([0, 1], [])
sage: (S1 == S2, C1 == C2, f1 == f2)
(False, False, False)

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.

818 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

• v – the vertex to search for.


• sort – boolean (default True) whether to sort vertices inside the component
EXAMPLES:

sage: from sage.graphs.connectivity import connected_component_containing_vertex


sage: G = Graph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )
sage: connected_component_containing_vertex(G,0)
[0, 1, 2, 3]
sage: G.connected_component_containing_vertex(0)
[0, 1, 2, 3]
sage: D = DiGraph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )
sage: connected_component_containing_vertex(D,0)
[0, 1, 2, 3]

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: from sage.graphs.connectivity import connected_components


sage: G = Graph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )
sage: connected_components(G)
[[0, 1, 2, 3], [4, 5, 6]]
sage: G.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: connected_components(D)
[[0, 1, 2, 3], [4, 5, 6]]

sage.graphs.connectivity.connected_components_number
Return the number of connected components.
INPUT:
• G (generic_graph) – the input graph.
EXAMPLES:

sage: from sage.graphs.connectivity import connected_components_number


sage: G = Graph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )
sage: connected_components_number(G)
2
sage: G.connected_components_number()
2
sage: D = DiGraph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )
sage: connected_components_number(D)
2

sage.graphs.connectivity.connected_components_sizes
Return the sizes of the connected components as a list.

5.36. Connectivity related functions 819


Sage Reference Manual: Graph Theory, Release 8.4

The list is sorted from largest to lower values.


EXAMPLES:

sage: from sage.graphs.connectivity import connected_components_sizes


sage: for x in graphs(3): print(connected_components_sizes(x))
[1, 1, 1]
[2, 1]
[3]
[3]
sage: for x in graphs(3): print(x.connected_components_sizes())
[1, 1, 1]
[2, 1]
[3]
[3]

sage.graphs.connectivity.connected_components_subgraphs
Return a list of connected components as graph objects.
EXAMPLES:

sage: from sage.graphs.connectivity import connected_components_subgraphs


sage: G = Graph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )
sage: L = connected_components_subgraphs(G)
sage: graphs_list.show_graphs(L)
sage: D = DiGraph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )
sage: L = connected_components_subgraphs(D)
sage: graphs_list.show_graphs(L)
sage: L = D.connected_components_subgraphs()
sage: graphs_list.show_graphs(L)

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)

820 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

– 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:

sage: from sage.graphs.connectivity import edge_connectivity


sage: g = graphs.PappusGraph()
sage: edge_connectivity(g)
3
sage: g.edge_connectivity()
3

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)

(continues on next page)

5.36. Connectivity related functions 821


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


sage: l == minimum
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

Boost interface also works with directed graphs

sage: edge_connectivity(digraphs.Circuit(10), implementation = "boost", vertices


˓→= True)

[1, [(0, 1)], [{0}, {1, 2, 3, 4, 5, 6, 7, 8, 9}]]

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:

822 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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.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: from sage.graphs.connectivity import is_cut_edge


sage: G = graphs.CompleteGraph(4)
sage: is_cut_edge(G,0,2)
False
sage: G.is_cut_edge(0,2)
False

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 = Graph([[0,1],[0,2],[1,1]], loops = True)


sage: is_cut_edge(G,(1,1))
(continues on next page)

5.36. Connectivity related functions 823


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


False

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: from sage.graphs.connectivity import is_cut_vertex


sage: G = graphs.LollipopGraph(4,2)
sage: is_cut_vertex(G,0)
False
sage: is_cut_vertex(G,3)
True
sage: G.is_cut_vertex(3)
True

Comparing the weak and strong connectivity of a digraph:

sage: from sage.graphs.connectivity import is_strongly_connected


sage: D = digraphs.Circuit(6)
sage: is_strongly_connected(D)
True
sage: is_cut_vertex(D,2)
True
sage: is_cut_vertex(D, 2, weak=True)
False

Giving a vertex that is not in the graph:

824 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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: from sage.graphs.connectivity import is_strongly_connected


sage: g = digraphs.Circuit(5)
sage: is_strongly_connected(g)
True
sage: g.is_strongly_connected()
True

But a transitive triangle is not:

sage: g = DiGraph({ 0 : [1,2], 1 : [2]})


sage: is_strongly_connected(g)
False

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:

– "Hopcroft_Tarjan" (default) – Use the algorithm proposed by Hopcroft and Tar-


jan in [Hopcroft1973] and later corrected by Gutwenger and Mutzel in [Gut2001]. See
TriconnectivitySPQR.
– "cleave" – Using method cleave().

5.36. Connectivity related functions 825


Sage Reference Manual: Graph Theory, Release 8.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 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)

826 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


True

sage: G = Graph('LlCG{O@?GBoMw?')
sage: T = spqr_tree(G, algorithm="Hopcroft_Tarjan")
sage: G.is_isomorphic(spqr_tree_to_graph(T))
True
sage: T2 = spqr_tree(G, algorithm='cleave')
sage: G.is_isomorphic(spqr_tree_to_graph(T2))
True

sage: G = Graph([(0, 1)], multiedges=True)


sage: T = spqr_tree(G, algorithm='cleave')
sage: T.vertices()
[('Q', Multi-graph on 2 vertices)]
sage: G.is_isomorphic(spqr_tree_to_graph(T))
True
sage: T = spqr_tree(G, algorithm='Hopcroft_Tarjan')
sage: T.vertices()
[('Q', Multi-graph on 2 vertices)]
sage: G.add_edge(0, 1)
sage: spqr_tree(G, algorithm='cleave').vertices()
[('P', Multi-graph on 2 vertices)]

sage: from collections import Counter


sage: G = graphs.PetersenGraph()
sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan")
sage: Counter(u[0] for u in T)
Counter({'R': 1})
sage: T = G.spqr_tree(algorithm="cleave")
sage: Counter(u[0] for u in T)
Counter({'R': 1})
sage: for u,v in G.edges(labels=False):
....: G.add_path([u, G.add_vertex(), G.add_vertex(), v])
sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan")
sage: Counter(u[0] for u in T)
Counter({'P': 15, 'S': 15, 'R': 1})
sage: T = G.spqr_tree(algorithm="cleave")
sage: Counter(u[0] for u in T)
Counter({'P': 15, 'S': 15, 'R': 1})
sage: for u,v in G.edges(labels=False):
....: G.add_path([u, G.add_vertex(), G.add_vertex(), v])
sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan")
sage: Counter(u[0] for u in T)
Counter({'S': 75, 'P': 60, 'R': 1})
sage: T = G.spqr_tree(algorithm="cleave") # long time
sage: Counter(u[0] for u in T) # long time
Counter({'S': 75, 'P': 60, 'R': 1})

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

5.36. Connectivity related functions 827


Sage Reference Manual: Graph Theory, Release 8.4

EXAMPLES:
Wikipedia article SPQR_tree reference paper example:

sage: from sage.graphs.connectivity import spqr_tree


sage: from sage.graphs.connectivity import spqr_tree_to_graph
sage: G = Graph([(1, 2), (1, 4), (1, 8), (1, 12), (3, 4), (2, 3),
....: (2, 13), (3, 13), (4, 5), (4, 7), (5, 6), (5, 8), (5, 7), (6, 7),
....: (8, 11), (8, 9), (8, 12), (9, 10), (9, 11), (9, 12), (10, 12)])
sage: T = spqr_tree(G)
sage: H = spqr_tree_to_graph(T)
sage: H.is_isomorphic(G)
True

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: from sage.graphs.connectivity import strong_articulation_points


sage: D = digraphs.Complete(4)
sage: D.add_clique([3, 4, 5, 6])
sage: strong_articulation_points(D)
[3]
sage: D.strong_articulation_points()
[3]

Two cliques connected by some arcs:

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)
[]

828 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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: from sage.graphs.connectivity import strongly_connected_component_


˓→containing_vertex

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

sage: from sage.graphs.connectivity import strongly_connected_components_digraph


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 components:

sage: g = digraphs.ButterflyGraph(2)
sage: scc_digraph = strongly_connected_components_digraph(g)
sage: g.is_directed_acyclic()
True
(continues on next page)

5.36. Connectivity related functions 829


Sage Reference Manual: Graph Theory, Release 8.4

(continued from previous page)


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:

sage: g = DiGraph({0:{1:"01", 2: "02", 3: "03"}, 1: {2: "12"}, 2:{1: "21", 3: "23


˓→"}})

sage: scc_digraph = strongly_connected_components_digraph(g)


sage: scc_digraph.vertices(key=sorted)
[{0}, {1, 2}, {3}]
sage: scc_digraph.edges()
[({0}, {1, 2}, None), ({0}, {3}, None), ({1, 2}, {3}, None)]

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: g = DiGraph({0:{1:"0-12", 2: "0-12", 3: "0-3"}, 1: {2: "1-2", 3: "1-3"}, 2:


˓→{1: "2-1", 3: "2-3"}})

sage: scc_digraph = strongly_connected_components_digraph(g, keep_labels = True)


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')]

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: 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]

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

830 Chapter 5. Libraries of algorithms


Sage Reference Manual: Graph Theory, Release 8.4

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:

sage: from sage.graphs.connectivity import vertex_connectivity


sage: g=graphs.PappusGraph()
sage: vertex_connectivity(g)
3
sage: g.vertex_connectivity()
3

In a grid, the vertex connectivity is equal to the minimum degree, in which case one of the two sets is of
cardinality 1:

sage: g = graphs.GridGraph([ 3,3 ])


sage: [value, cut, [ setA, setB ]] = vertex_connectivity(g, sets=True)
sage: len(setA) == 1 or len(setB) == 1
True

A vertex cut in a tree is any internal vertex:

sage: tree = graphs.RandomTree(15)


sage: val, [cut_vertex] = vertex_connectivity(tree, value_only=False)
sage: tree.degree(cut_vertex) > 1
True

When value_only = True, this function is optimized for small connectivity values and does not need to
build a linear program.

5.36. Connectivity related functions 831


Sage Reference Manual: Graph Theory, Release 8.4

It is the case for connected graphs which are not connected:

sage: g = 2 * graphs.PetersenGraph()
sage: vertex_connectivity(g)
0

Or if they are just 1-connected:

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

A complete graph on 10 vertices is 9-connected:

sage: g = graphs.CompleteGraph(10)
sage: vertex_connectivity(g)
9

A complete digraph on 10 vertices is 9-connected:

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

832 Chapter 5. Libraries of algorithms


CHAPTER

SIX

INDICES AND TABLES

• Index
• Module Index
• Search Page

833
Sage Reference Manual: Graph Theory, Release 8.4

834 Chapter 6. Indices and Tables


BIBLIOGRAPHY

[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

[CIA] CIA Factbook 09 https://www.cia.gov/library/publications/the-world-factbook/


[buckygen] G. Brinkmann, J. Goedgebeur and B.D. McKay, Generation of Fullerenes, Journal of Chemical Informa-
tion and Modeling, 52(11):2910-2918, 2012.
[benzene] G. Brinkmann, G. Caporossi and P. Hansen, A Constructive Enumeration of Fusenes and Benzenoids,
Journal of Algorithms, 45:155-166, 2002.
[plantri] G. Brinkmann and B.D. McKay, Fast generation of planar graphs, MATCH-Communications in Mathemati-
cal and in Computer Chemistry, 58(2):323-357, 2007.
[RPK80] S. M. Reddy, D. K. Pradhan, and J. Kuhl. Directed graphs with minimal diameter and maximal connectivity,
School Eng., Oakland Univ., Rochester MI, Tech. Rep., July 1980.
[RPK83] S. Reddy, P. Raghavan, and J. Kuhl. A Class of Graphs for Processor Interconnection. IEEE International
Conference on Parallel Processing, pages 154-157, Los Alamitos, Ca., USA, August 1983.
[II83] M. Imase and M. Itoh. A design for directed graphs with minimum diameter, IEEE Trans. Comput., vol. C-32,
pp. 782-784, 1983.
[Kautz68] W. H. Kautz. Bounds on directed (d, k) graphs. Theory of cellular logic networks and machines, AFCRL-
68-0668, SRI Project 7258, Final Rep., pp. 20-28, 1968.
[BvL84] A. Brouwer, J. van Lint, Strongly regular graphs and partial geometries, Enumeration and design, (Waterloo,
Ont., 1982) (1984): 85-122. http://oai.cwi.nl/oai/asset/1817/1817A.pdf
[JK03] L. K. Jørgensen, M. Klin, M., Switching of edges in strongly regular graphs. I. A family of partial difference
sets on 100 vertices, Electronic Journal of Combinatorics 10(1), 2003.
[GS70] J.-M. Goethals and J. J. Seidel, Strongly regular graphs derived from combinatorial designs, Can. J. Math. 22
(1970) 597-614. doi:10.4153/CJM-1970-067-9
[Co06] K. Coolsaet, The uniqueness of the strongly regular graph srg(105,32,4,12), Bull. Belg. Math. Soc. 12(2006),
707-718. http://projecteuclid.org/euclid.bbms/1136902608
[BvE92] A. Brouwer and C. Van Eijl, On the p-Rank of the Adjacency Matrices of Strongly Regular Graphs Journal
of Algebraic Combinatorics (1992), vol.1, n.4, pp329-346, doi:10.1023/A%3A1022438616684
[BrouwerPolarities82] A. Brouwer, Polarities of G. Higman’s symmetric design and a strongly regular graph on 176
vertices, Aequationes mathematicae 25, no. 1 (1982): 77-82.
[IS06] Y.J. Ionin, S. Shrikhande, Combinatorics of symmetric designs. Cambridge University Press, 2006.
[KPRWZ10] M. H. Klin, C. Pech, S. Reichard, A. Woldar, M. Zvi-Av, Examples of computer experimentation in
algebraic combinatorics, ARS MATHEMATICA CONTEMPORANEA 3 (2010) 237–258 http://amc-journal.eu/
index.php/amc/article/viewFile/119/118
[COCO] I. A. Faradjev and M. H. Klin, Computer package for computations with coherent configurations, Proc.
ISSAC-91, ACM Press, Bonn, 1991, pages 219–223; code, by I.A.Faradjev (with contributions by A.E.Brouwer,
D.V.Pasechnik) https://github.com/dimpase/coco
[GS75] J.M. Goethals, and J. J. Seidel, The regular two-graph on 276 vertices, Discrete Mathematics 12, no. 2 (1975):
143-158. doi:10.1016/0012-365X(75)90029-1
[HT96] W. H. Haemers and V. D. Tonchev, Spreads in strongly regular graphs, Designs, Codes and Cryptography 8
(1996) 145-157.
[MR85] R. Mathon and A. Rosa, A new strongly regular graph, Journal of Combinatorial Theory, Series A 38, no. 1
(1985): 84-86. doi:10.1016/0097-3165(85)90025-1
[BI84] Eiichi Bannai, Tatsuro Ito, Algebraic Combinatorics I: Association Schemes, Benjamin/Cummings, 1984
[Pa92] D. V. Pasechnik, Skew-symmetric association schemes with two classes and strongly regular graphs of type
𝐿2𝑛−1 (4𝑛 − 1), Acta Applicandaie Math. 29(1992), 129-138

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

844 Python Module Index


INDEX

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

all_arcs() (sage.graphs.base.c_graph.CGraph method), 549


all_arcs() (sage.graphs.base.sparse_graph.SparseGraph method), 576
all_cycles_iterator() (sage.graphs.digraph.DiGraph method), 304
all_graph_colorings() (in module sage.graphs.graph_coloring), 645
all_max_clique (in module sage.graphs.cliquer), 654
all_paths() (sage.graphs.generic_graph.GenericGraph method), 13
all_paths_iterator() (sage.graphs.digraph.DiGraph method), 306
all_simple_cycles() (sage.graphs.digraph.DiGraph method), 308
all_simple_paths() (sage.graphs.digraph.DiGraph method), 310
allow_loops() (sage.graphs.bipartite_graph.BipartiteGraph method), 341
allow_loops() (sage.graphs.generic_graph.GenericGraph method), 14
allow_multiple_edges() (sage.graphs.generic_graph.GenericGraph method), 15
allows_loops() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 604
allows_loops() (sage.graphs.generic_graph.GenericGraph method), 16
allows_multiple_edges() (sage.graphs.generic_graph.GenericGraph method), 17
am() (sage.graphs.generic_graph.GenericGraph method), 17
antisymmetric() (sage.graphs.generic_graph.GenericGraph method), 19
apex_vertices() (sage.graphs.graph.Graph method), 219
apparently_feasible_parameters() (in module sage.graphs.strongly_regular_db), 518
append_child() (sage.graphs.schnyder.TreeNode method), 694
arc_label() (sage.graphs.base.sparse_graph.SparseGraph method), 576
automorphism_group() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 627
automorphism_group() (sage.graphs.generic_graph.GenericGraph method), 19
average_degree() (sage.graphs.generic_graph.GenericGraph method), 21
average_distance() (sage.graphs.generic_graph.GenericGraph method), 22
AztecDiamondGraph() (sage.graphs.graph_generators.GraphGenerators static method), 358

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

blocks() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 628


blocks_and_cut_vertices (in module sage.graphs.connectivity), 814
blocks_and_cut_vertices() (in module sage.graphs.base.boost_graph), 616
blocks_and_cut_vertices() (sage.graphs.generic_graph.GenericGraph method), 23
blocks_and_cuts_tree (in module sage.graphs.connectivity), 816
blocks_and_cuts_tree() (sage.graphs.generic_graph.GenericGraph method), 24
boruvka() (in module sage.graphs.spanning_tree), 671
bounded_outdegree_orientation() (sage.graphs.graph.Graph method), 221
breadth_first_level_search() (in module sage.graphs.partial_cube), 800
breadth_first_search() (sage.graphs.base.c_graph.CGraphBackend method), 560
breadth_first_search() (sage.graphs.generic_graph.GenericGraph method), 25
bridges (in module sage.graphs.connectivity), 816
bridges() (sage.graphs.graph.Graph method), 222
BrinkmannGraph() (sage.graphs.graph_generators.GraphGenerators static method), 364
BrouwerHaemersGraph() (sage.graphs.graph_generators.GraphGenerators static method), 365
BubbleSortGraph() (sage.graphs.graph_generators.GraphGenerators static method), 365
BuckyBall() (sage.graphs.graph_generators.GraphGenerators static method), 366
BullGraph() (sage.graphs.graph_generators.GraphGenerators static method), 367
ButterflyGraph() (sage.graphs.digraph_generators.DiGraphGenerators method), 489
ButterflyGraph() (sage.graphs.graph_generators.GraphGenerators static method), 368

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

check_aut_edge() (in module sage.graphs.graph_generators), 485


check_tkz_graph() (in module sage.graphs.graph_latex), 781
check_vertex() (sage.graphs.base.c_graph.CGraph method), 550
ChessboardGraphGenerator() (sage.graphs.graph_generators.GraphGenerators static method), 370
chromatic_index() (sage.graphs.graph.Graph method), 223
chromatic_number() (in module sage.graphs.graph_coloring), 647
chromatic_number() (sage.graphs.graph.Graph method), 224
chromatic_polynomial() (sage.graphs.graph.Graph method), 225
chromatic_quasisymmetric_function() (sage.graphs.graph.Graph method), 226
chromatic_symmetric_function() (sage.graphs.graph.Graph method), 227
ChvatalGraph() (sage.graphs.graph_generators.GraphGenerators static method), 371
Circuit() (sage.graphs.digraph_generators.DiGraphGenerators method), 490
Circulant() (sage.graphs.digraph_generators.DiGraphGenerators method), 490
CirculantGraph() (sage.graphs.graph_generators.GraphGenerators static method), 372
CircularLadderGraph() (sage.graphs.graph_generators.GraphGenerators static method), 373
classes() (sage.graphs.isgci.GraphClasses method), 541
ClawGraph() (sage.graphs.graph_generators.GraphGenerators static method), 374
clear() (sage.graphs.generic_graph.GenericGraph method), 34
cleave (in module sage.graphs.connectivity), 817
cleave() (sage.graphs.graph.Graph method), 228
ClebschGraph() (sage.graphs.graph_generators.GraphGenerators static method), 374
clique_complex() (sage.graphs.graph.Graph method), 229
clique_maximum() (sage.graphs.graph.Graph method), 230
clique_number (in module sage.graphs.cliquer), 654
clique_number() (sage.graphs.graph.Graph method), 230
clique_polynomial() (sage.graphs.graph.Graph method), 231
cliques_containing_vertex() (sage.graphs.graph.Graph method), 232
cliques_get_clique_bipartite() (sage.graphs.graph.Graph method), 232
cliques_get_max_clique_graph() (sage.graphs.graph.Graph method), 233
cliques_maximal() (sage.graphs.graph.Graph method), 233
cliques_maximum() (sage.graphs.graph.Graph method), 234
cliques_number_of() (sage.graphs.graph.Graph method), 235
cliques_vertex_clique_number() (sage.graphs.graph.Graph method), 235
cluster_transitivity() (sage.graphs.generic_graph.GenericGraph method), 35
cluster_triangles() (sage.graphs.generic_graph.GenericGraph method), 35
clustering_average() (sage.graphs.generic_graph.GenericGraph method), 35
clustering_coeff() (in module sage.graphs.base.boost_graph), 616
clustering_coeff() (sage.graphs.generic_graph.GenericGraph method), 36
coarsest_equitable_refinement() (sage.graphs.generic_graph.GenericGraph method), 36
coloring() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 629
coloring() (sage.graphs.graph.Graph method), 236
complement() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 629
complement() (sage.graphs.base.dense_graph.DenseGraph method), 587
complement() (sage.graphs.bipartite_graph.BipartiteGraph method), 342
complement() (sage.graphs.generic_graph.GenericGraph method), 37
Complete() (sage.graphs.digraph_generators.DiGraphGenerators method), 490
complete_poly (in module sage.graphs.matchpoly), 683
CompleteBipartiteGraph() (sage.graphs.graph_generators.GraphGenerators static method), 374
CompleteGraph() (sage.graphs.graph_generators.GraphGenerators static method), 376
CompleteMultipartiteGraph() (sage.graphs.graph_generators.GraphGenerators static method), 377

848 Index
Sage Reference Manual: Graph Theory, Release 8.4

CompleteUniform() (sage.graphs.hypergraph_generators.HypergraphGenerators method), 623


compute_depth_of_self_and_children() (sage.graphs.schnyder.TreeNode method), 694
compute_number_of_descendants() (sage.graphs.schnyder.TreeNode method), 694
connected_component_containing_vertex (in module sage.graphs.connectivity), 818
connected_component_containing_vertex() (sage.graphs.generic_graph.GenericGraph method), 38
connected_components (in module sage.graphs.connectivity), 819
connected_components() (sage.graphs.generic_graph.GenericGraph method), 38
connected_components_number (in module sage.graphs.connectivity), 819
connected_components_number() (sage.graphs.generic_graph.GenericGraph method), 39
connected_components_sizes (in module sage.graphs.connectivity), 819
connected_components_sizes() (sage.graphs.generic_graph.GenericGraph method), 39
connected_components_subgraphs (in module sage.graphs.connectivity), 820
connected_components_subgraphs() (sage.graphs.generic_graph.GenericGraph method), 39
connected_subgraph_iterator (in module sage.graphs.base.static_dense_graph), 594
connected_subgraph_iterator() (sage.graphs.generic_graph.GenericGraph method), 39
contract_edge() (sage.graphs.generic_graph.GenericGraph method), 40
contract_edges() (sage.graphs.generic_graph.GenericGraph method), 41
contracted_edge() (in module sage.graphs.tutte_polynomial), 796
convexity_properties() (sage.graphs.graph.Graph method), 237
ConvexityProperties (class in sage.graphs.convexity_properties), 755
copy() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 630
copy() (sage.graphs.generic_graph.GenericGraph method), 42
cores() (sage.graphs.graph.Graph method), 239
cospectral_graphs() (sage.graphs.graph_generators.GraphGenerators method), 471
CossidentePenttilaGraph() (sage.graphs.graph_generators.GraphGenerators static method), 377
CoxeterGraph() (sage.graphs.graph_generators.GraphGenerators static method), 378
crossing_number() (sage.graphs.generic_graph.GenericGraph method), 44
CubeGraph() (sage.graphs.graph_generators.GraphGenerators static method), 378
current_allocation() (sage.graphs.base.c_graph.CGraph method), 551
cutwidth() (in module sage.graphs.graph_decompositions.cutwidth), 748
cutwidth_dyn() (in module sage.graphs.graph_decompositions.cutwidth), 750
cutwidth_MILP() (in module sage.graphs.graph_decompositions.cutwidth), 749
cycle_basis() (sage.graphs.generic_graph.GenericGraph method), 44
CycleGraph() (sage.graphs.graph_generators.GraphGenerators static method), 379

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

DegreeSequence() (sage.graphs.graph_generators.GraphGenerators static method), 380


DegreeSequenceBipartite() (sage.graphs.graph_generators.GraphGenerators static method), 380
DegreeSequenceConfigurationModel() (sage.graphs.graph_generators.GraphGenerators static method), 381
DegreeSequenceExpected() (sage.graphs.graph_generators.GraphGenerators static method), 382
DegreeSequenceTree() (sage.graphs.graph_generators.GraphGenerators static method), 382
degseq_to_data() (in module sage.graphs.graph_database), 511
DejterGraph() (sage.graphs.graph_generators.GraphGenerators static method), 382
del_all_arcs() (sage.graphs.base.c_graph.CGraph method), 552
del_all_arcs() (sage.graphs.base.dense_graph.DenseGraph method), 587
del_all_arcs() (sage.graphs.base.sparse_graph.SparseGraph method), 577
del_arc_label() (sage.graphs.base.sparse_graph.SparseGraph method), 577
del_edge() (sage.graphs.base.dense_graph.DenseGraphBackend method), 590
del_edge() (sage.graphs.base.graph_backends.GenericGraphBackend method), 610
del_edge() (sage.graphs.base.sparse_graph.SparseGraphBackend method), 582
del_vertex() (sage.graphs.base.c_graph.CGraph method), 552
del_vertex() (sage.graphs.base.c_graph.CGraphBackend method), 562
del_vertex() (sage.graphs.base.graph_backends.GenericGraphBackend method), 610
del_vertex() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 604
del_vertex() (sage.graphs.base.static_sparse_backend.StaticSparseCGraph method), 607
del_vertices() (sage.graphs.base.c_graph.CGraphBackend method), 562
del_vertices() (sage.graphs.base.graph_backends.GenericGraphBackend method), 610
delete_edge() (sage.graphs.generic_graph.GenericGraph method), 48
delete_edges() (sage.graphs.generic_graph.GenericGraph method), 49
delete_multiedge() (sage.graphs.generic_graph.GenericGraph method), 49
delete_vertex() (sage.graphs.bipartite_graph.BipartiteGraph method), 342
delete_vertex() (sage.graphs.generic_graph.GenericGraph method), 50
delete_vertices() (sage.graphs.bipartite_graph.BipartiteGraph method), 343
delete_vertices() (sage.graphs.generic_graph.GenericGraph method), 50
DenseGraph (class in sage.graphs.base.dense_graph), 586
DenseGraphBackend (class in sage.graphs.base.dense_graph), 589
density() (sage.graphs.generic_graph.GenericGraph method), 51
depth_first_search() (sage.graphs.base.c_graph.CGraphBackend method), 563
depth_first_search() (sage.graphs.generic_graph.GenericGraph method), 51
depth_first_traversal() (in module sage.graphs.partial_cube), 800
DesarguesGraph() (sage.graphs.graph_generators.GraphGenerators static method), 383
description() (sage.graphs.isgci.GraphClass method), 540
diameter (in module sage.graphs.distances_all_pairs), 761
diameter() (sage.graphs.generic_graph.GenericGraph method), 52
DiamondGraph() (sage.graphs.graph_generators.GraphGenerators static method), 383
dig6_string() (sage.graphs.digraph.DiGraph method), 311
DiGraph (class in sage.graphs.digraph), 300
DiGraphGenerators (class in sage.graphs.digraph_generators), 487
DipoleGraph() (sage.graphs.graph_generators.GraphGenerators static method), 383
disjoint_routed_paths() (sage.graphs.generic_graph.GenericGraph method), 53
disjoint_union() (sage.graphs.generic_graph.GenericGraph method), 54
disjunctive_product() (sage.graphs.generic_graph.GenericGraph method), 54
distance() (sage.graphs.generic_graph.GenericGraph method), 55
distance_all_pairs() (sage.graphs.generic_graph.GenericGraph method), 55
distance_graph() (sage.graphs.generic_graph.GenericGraph method), 57
distance_matrix() (sage.graphs.generic_graph.GenericGraph method), 58

850 Index
Sage Reference Manual: Graph Theory, Release 8.4

distances_all_pairs (in module sage.graphs.distances_all_pairs), 763


distances_and_predecessors_all_pairs (in module sage.graphs.distances_all_pairs), 763
distances_distribution (in module sage.graphs.distances_all_pairs), 764
distances_distribution() (sage.graphs.generic_graph.GenericGraph method), 59
DodecahedralGraph() (sage.graphs.graph_generators.GraphGenerators static method), 383
dominating_set() (sage.graphs.generic_graph.GenericGraph method), 60
dominator_tree (in module sage.graphs.base.boost_graph), 617
dominator_tree() (sage.graphs.generic_graph.GenericGraph method), 61
DorogovtsevGoltsevMendesGraph() (sage.graphs.graph_generators.GraphGenerators static method), 384
dot2tex_picture() (sage.graphs.graph_latex.GraphLatex method), 774
DoubleStarSnark() (sage.graphs.graph_generators.GraphGenerators static method), 384
dual() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 631
DurerGraph() (sage.graphs.graph_generators.GraphGenerators static method), 384
DyckGraph() (sage.graphs.graph_generators.GraphGenerators static method), 385

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

genus() (sage.graphs.genus.simple_connected_genus_backtracker method), 687


get_class() (sage.graphs.isgci.GraphClasses method), 541
get_edge_label() (sage.graphs.base.dense_graph.DenseGraphBackend method), 591
get_edge_label() (sage.graphs.base.graph_backends.GenericGraphBackend method), 611
get_edge_label() (sage.graphs.base.sparse_graph.SparseGraphBackend method), 582
get_edge_label() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 605
get_embedding() (sage.graphs.generic_graph.GenericGraph method), 85
get_embedding() (sage.graphs.genus.simple_connected_genus_backtracker method), 688
get_graphs_list() (sage.graphs.graph_database.GraphQuery method), 508
get_option() (sage.graphs.graph_latex.GraphLatex method), 775
get_pos() (sage.graphs.generic_graph.GenericGraph method), 85
get_spqr_tree() (sage.graphs.connectivity.TriconnectivitySPQR method), 812
get_triconnected_components() (sage.graphs.connectivity.TriconnectivitySPQR method), 813
get_vertex() (sage.graphs.generic_graph.GenericGraph method), 85
get_vertices() (sage.graphs.generic_graph.GenericGraph method), 86
girth() (sage.graphs.generic_graph.GenericGraph method), 86
GoethalsSeidelGraph() (sage.graphs.graph_generators.GraphGenerators static method), 396
GoldnerHararyGraph() (sage.graphs.graph_generators.GraphGenerators static method), 396
gomory_hu_tree() (sage.graphs.graph.Graph method), 243
GossetGraph() (sage.graphs.graph_generators.GraphGenerators static method), 397
Graph (class in sage.graphs.graph), 212
graph6_string() (sage.graphs.graph.Graph method), 244
graph6_to_plot() (in module sage.graphs.graph_database), 511
graph_db_info() (in module sage.graphs.graph_database), 511
graph_editor() (in module sage.graphs.graph_editor), 782
graph_isom_equivalent_non_edge_labeled_graph() (in module sage.graphs.generic_graph), 202
graph_to_js() (in module sage.graphs.graph_editor), 782
GraphClass (class in sage.graphs.isgci), 539
GraphClasses (class in sage.graphs.isgci), 540
GraphDatabase (class in sage.graphs.graph_database), 501
GraphGenerators (class in sage.graphs.graph_generators), 353
GraphLatex (class in sage.graphs.graph_latex), 773
GraphPlot (class in sage.graphs.graph_plot), 701
graphplot() (sage.graphs.generic_graph.GenericGraph method), 86
GraphQuery (class in sage.graphs.graph_database), 507
graphviz_string() (sage.graphs.generic_graph.GenericGraph method), 87
graphviz_to_file_named() (sage.graphs.generic_graph.GenericGraph method), 92
GrayGraph() (sage.graphs.graph_generators.GraphGenerators static method), 397
greedy_is_comparability (in module sage.graphs.comparability), 663
greedy_is_comparability_with_certificate (in module sage.graphs.comparability), 664
Grid2dGraph() (sage.graphs.graph_generators.GraphGenerators static method), 398
GridGraph() (sage.graphs.graph_generators.GraphGenerators static method), 398
GrotzschGraph() (sage.graphs.graph_generators.GraphGenerators static method), 398
ground_set() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 632
grundy_coloring() (in module sage.graphs.graph_coloring), 649

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

hamiltonian_path() (sage.graphs.generic_graph.GenericGraph method), 94


HammingGraph() (sage.graphs.graph_generators.GraphGenerators static method), 400
HanoiTowerGraph() (sage.graphs.graph_generators.GraphGenerators static method), 401
HararyGraph() (sage.graphs.graph_generators.GraphGenerators static method), 403
HarborthGraph() (sage.graphs.graph_generators.GraphGenerators static method), 403
HarriesGraph() (sage.graphs.graph_generators.GraphGenerators static method), 404
HarriesWongGraph() (sage.graphs.graph_generators.GraphGenerators static method), 404
has_arc() (sage.graphs.base.c_graph.CGraph method), 554
has_arc() (sage.graphs.base.dense_graph.DenseGraph method), 587
has_arc() (sage.graphs.base.sparse_graph.SparseGraph method), 578
has_arc() (sage.graphs.base.static_sparse_backend.StaticSparseCGraph method), 607
has_arc_label() (sage.graphs.base.sparse_graph.SparseGraph method), 578
has_edge() (sage.graphs.base.dense_graph.DenseGraphBackend method), 591
has_edge() (sage.graphs.base.graph_backends.GenericGraphBackend method), 611
has_edge() (sage.graphs.base.sparse_graph.SparseGraphBackend method), 582
has_edge() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 605
has_edge() (sage.graphs.generic_graph.GenericGraph method), 95
has_homomorphism_to() (sage.graphs.graph.Graph method), 244
has_loops() (sage.graphs.generic_graph.GenericGraph method), 95
has_multiple_edges() (sage.graphs.generic_graph.GenericGraph method), 96
has_perfect_matching() (sage.graphs.graph.Graph method), 245
has_vertex() (sage.graphs.base.c_graph.CGraph method), 554
has_vertex() (sage.graphs.base.c_graph.CGraphBackend method), 564
has_vertex() (sage.graphs.base.graph_backends.GenericGraphBackend method), 611
has_vertex() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 605
has_vertex() (sage.graphs.base.static_sparse_backend.StaticSparseCGraph method), 607
has_vertex() (sage.graphs.generic_graph.GenericGraph method), 97
have_tkz_graph() (in module sage.graphs.graph_latex), 781
HeawoodGraph() (sage.graphs.graph_generators.GraphGenerators static method), 405
HerschelGraph() (sage.graphs.graph_generators.GraphGenerators static method), 405
HexahedralGraph() (sage.graphs.graph_generators.GraphGenerators static method), 406
HigmanSimsGraph() (sage.graphs.graph_generators.GraphGenerators static method), 407
HoffmanGraph() (sage.graphs.graph_generators.GraphGenerators static method), 408
HoffmanSingletonGraph() (sage.graphs.graph_generators.GraphGenerators static method), 408
HoltGraph() (sage.graphs.graph_generators.GraphGenerators static method), 408
HortonGraph() (sage.graphs.graph_generators.GraphGenerators static method), 409
HouseGraph() (sage.graphs.graph_generators.GraphGenerators static method), 409
HouseXGraph() (sage.graphs.graph_generators.GraphGenerators static method), 410
hull() (sage.graphs.convexity_properties.ConvexityProperties method), 756
hull_number() (sage.graphs.convexity_properties.ConvexityProperties method), 756
hyperbolicity() (in module sage.graphs.hyperbolicity), 791
hyperbolicity_distribution() (in module sage.graphs.hyperbolicity), 793
HypergraphGenerators (class in sage.graphs.hypergraph_generators), 623
HyperStarGraph() (sage.graphs.graph_generators.GraphGenerators static method), 410

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

immediate_dominators() (sage.graphs.digraph.DiGraph method), 315


in_degree() (sage.graphs.base.c_graph.CGraphBackend method), 564
in_degree() (sage.graphs.base.graph_backends.GenericGraphBackend method), 611
in_degree() (sage.graphs.base.sparse_graph.SparseGraph method), 578
in_degree() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 605
in_degree() (sage.graphs.base.static_sparse_backend.StaticSparseCGraph method), 608
in_degree() (sage.graphs.digraph.DiGraph method), 317
in_degree_iterator() (sage.graphs.digraph.DiGraph method), 317
in_degree_sequence() (sage.graphs.digraph.DiGraph method), 317
in_neighbors() (sage.graphs.base.c_graph.CGraph method), 555
in_neighbors() (sage.graphs.base.dense_graph.DenseGraph method), 588
in_neighbors() (sage.graphs.base.sparse_graph.SparseGraph method), 579
in_neighbors() (sage.graphs.base.static_sparse_backend.StaticSparseCGraph method), 608
incidence_graph() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 632
incidence_matrix() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 632
incidence_matrix() (sage.graphs.generic_graph.GenericGraph method), 99
IncidenceStructure (class in sage.combinat.designs.incidence_structures), 626
inclusion_digraph() (sage.graphs.isgci.GraphClasses method), 541
inclusions() (sage.graphs.isgci.GraphClasses method), 541
incoming_edge_iterator() (sage.graphs.digraph.DiGraph method), 318
incoming_edges() (sage.graphs.digraph.DiGraph method), 318
incomparable() (sage.graphs.linearextensions.LinearExtensions method), 691
independent_set() (sage.graphs.graph.Graph method), 246
independent_set_of_representatives() (sage.graphs.graph.Graph method), 247
IndependentSets (class in sage.graphs.independent_sets), 659
induced_substructure() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 633
int_to_binary_string() (in module sage.graphs.generic_graph_pyx), 805
interactive_query() (sage.graphs.graph_database.GraphDatabase method), 504
intersection_graph() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 633
IntersectionGraph() (sage.graphs.graph_generators.GraphGenerators static method), 411
IntervalGraph() (sage.graphs.graph_generators.GraphGenerators static method), 411
IoninKharaghani765Graph() (sage.graphs.graph_generators.GraphGenerators static method), 412
is_affine_polar() (in module sage.graphs.strongly_regular_db), 523
is_aperiodic() (sage.graphs.digraph.DiGraph method), 318
is_apex() (sage.graphs.graph.Graph method), 249
is_arc_transitive() (sage.graphs.graph.Graph method), 250
is_asteroidal_triple_free (in module sage.graphs.asteroidal_triples), 658
is_asteroidal_triple_free() (sage.graphs.graph.Graph method), 250
is_biconnected() (sage.graphs.graph.Graph method), 251
is_bipartite() (sage.graphs.generic_graph.GenericGraph method), 100
is_block_graph() (sage.graphs.graph.Graph method), 251
is_cactus() (sage.graphs.graph.Graph method), 252
is_cartesian_product (in module sage.graphs.graph_decompositions.graph_products), 754
is_cartesian_product() (sage.graphs.graph.Graph method), 252
is_cayley() (sage.graphs.generic_graph.GenericGraph method), 101
is_chordal() (sage.graphs.generic_graph.GenericGraph method), 102
is_circulant() (sage.graphs.generic_graph.GenericGraph method), 104
is_circular_planar() (sage.graphs.generic_graph.GenericGraph method), 104
is_circumscribable() (sage.graphs.graph.Graph method), 253
is_clique() (sage.graphs.generic_graph.GenericGraph method), 106

Index 855
Sage Reference Manual: Graph Theory, Release 8.4

is_cograph() (sage.graphs.graph.Graph method), 254


is_comparability (in module sage.graphs.comparability), 664
is_comparability_MILP (in module sage.graphs.comparability), 665
is_complete_multipartite() (in module sage.graphs.strongly_regular_db), 524
is_connected (in module sage.graphs.connectivity), 822
is_connected() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 634
is_connected() (sage.graphs.base.c_graph.CGraphBackend method), 565
is_connected() (sage.graphs.generic_graph.GenericGraph method), 107
is_cossidente_penttila() (in module sage.graphs.strongly_regular_db), 524
is_cut_edge (in module sage.graphs.connectivity), 823
is_cut_edge() (sage.graphs.generic_graph.GenericGraph method), 107
is_cut_vertex (in module sage.graphs.connectivity), 824
is_cut_vertex() (sage.graphs.generic_graph.GenericGraph method), 108
is_cycle() (sage.graphs.generic_graph.GenericGraph method), 109
is_directed() (sage.graphs.digraph.DiGraph method), 318
is_directed() (sage.graphs.graph.Graph method), 255
is_directed_acyclic() (sage.graphs.base.c_graph.CGraphBackend method), 565
is_directed_acyclic() (sage.graphs.digraph.DiGraph method), 319
is_distance_regular (in module sage.graphs.distances_all_pairs), 766
is_distance_regular() (sage.graphs.graph.Graph method), 255
is_drawn_free_of_edge_crossings() (sage.graphs.generic_graph.GenericGraph method), 110
is_edge_transitive() (sage.graphs.graph.Graph method), 255
is_equitable() (sage.graphs.generic_graph.GenericGraph method), 110
is_eulerian() (sage.graphs.generic_graph.GenericGraph method), 111
is_even_hole_free() (sage.graphs.graph.Graph method), 256
is_forest() (sage.graphs.graph.Graph method), 257
is_gallai_tree() (sage.graphs.generic_graph.GenericGraph method), 112
is_generalized_quadrangle() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 634
is_goethals_seidel() (in module sage.graphs.strongly_regular_db), 524
is_GQqmqp() (in module sage.graphs.strongly_regular_db), 520
is_haemers() (in module sage.graphs.strongly_regular_db), 525
is_half_transitive() (sage.graphs.graph.Graph method), 257
is_hamiltonian() (sage.graphs.generic_graph.GenericGraph method), 112
is_immutable() (sage.graphs.generic_graph.GenericGraph method), 113
is_independent_set() (sage.graphs.generic_graph.GenericGraph method), 113
is_inscribable() (sage.graphs.graph.Graph method), 258
is_interval() (sage.graphs.generic_graph.GenericGraph method), 113
is_isomorphic() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 634
is_isomorphic() (sage.graphs.generic_graph.GenericGraph method), 114
is_johnson() (in module sage.graphs.strongly_regular_db), 525
is_line_graph() (in module sage.graphs.line_graph), 668
is_line_graph() (sage.graphs.graph.Graph method), 259
is_long_antihole_free (in module sage.graphs.weakly_chordal), 758
is_long_antihole_free() (sage.graphs.graph.Graph method), 260
is_long_hole_free (in module sage.graphs.weakly_chordal), 758
is_long_hole_free() (sage.graphs.graph.Graph method), 260
is_mathon_PC_srg() (in module sage.graphs.strongly_regular_db), 526
is_muzychuk_S6() (in module sage.graphs.strongly_regular_db), 526
is_NO_F2() (in module sage.graphs.strongly_regular_db), 521
is_NO_F3() (in module sage.graphs.strongly_regular_db), 521

856 Index
Sage Reference Manual: Graph Theory, Release 8.4

is_NOodd() (in module sage.graphs.strongly_regular_db), 522


is_NOperp_F5() (in module sage.graphs.strongly_regular_db), 522
is_nowhere0_twoweight() (in module sage.graphs.strongly_regular_db), 526
is_NU() (in module sage.graphs.strongly_regular_db), 522
is_odd_hole_free() (sage.graphs.graph.Graph method), 261
is_orthogonal_array_block_graph() (in module sage.graphs.strongly_regular_db), 527
is_orthogonal_polar() (in module sage.graphs.strongly_regular_db), 527
is_overfull() (sage.graphs.graph.Graph method), 262
is_paley() (in module sage.graphs.strongly_regular_db), 528
is_partial_cube() (in module sage.graphs.partial_cube), 801
is_partial_cube() (sage.graphs.graph.Graph method), 263
is_perfect() (sage.graphs.graph.Graph method), 264
is_permutation (in module sage.graphs.comparability), 665
is_planar() (in module sage.graphs.planarity), 696
is_planar() (sage.graphs.generic_graph.GenericGraph method), 116
is_polhill() (in module sage.graphs.strongly_regular_db), 528
is_polyhedral() (sage.graphs.graph.Graph method), 265
is_prime() (sage.graphs.graph.Graph method), 265
is_regular() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 635
is_regular() (sage.graphs.generic_graph.GenericGraph method), 118
is_resolvable() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 635
is_RSHCD() (in module sage.graphs.strongly_regular_db), 523
is_self_complementary() (sage.graphs.generic_graph.GenericGraph method), 118
is_semi_symmetric() (sage.graphs.graph.Graph method), 266
is_simple() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 636
is_split() (sage.graphs.graph.Graph method), 266
is_steiner() (in module sage.graphs.strongly_regular_db), 529
is_strongly_connected (in module sage.graphs.connectivity), 825
is_strongly_connected() (sage.graphs.base.c_graph.CGraphBackend method), 566
is_strongly_connected() (sage.graphs.digraph.DiGraph method), 320
is_strongly_regular (in module sage.graphs.base.static_dense_graph), 595
is_strongly_regular() (sage.graphs.graph.Graph method), 267
is_subgraph() (sage.graphs.generic_graph.GenericGraph method), 119
is_switch_OA_srg() (in module sage.graphs.strongly_regular_db), 529
is_switch_skewhad() (in module sage.graphs.strongly_regular_db), 529
is_t_design() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 637
is_taylor_twograph_srg() (in module sage.graphs.strongly_regular_db), 530
is_tournament() (sage.graphs.digraph.DiGraph method), 320
is_transitive (in module sage.graphs.comparability), 666
is_transitive() (sage.graphs.digraph.DiGraph method), 321
is_transitively_reduced() (sage.graphs.generic_graph.GenericGraph method), 120
is_tree() (sage.graphs.graph.Graph method), 268
is_triangle_free() (sage.graphs.graph.Graph method), 269
is_twograph_descendant_of_srg() (in module sage.graphs.strongly_regular_db), 530
is_uniform() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 638
is_unitary_dual_polar() (in module sage.graphs.strongly_regular_db), 531
is_unitary_polar() (in module sage.graphs.strongly_regular_db), 531
is_valid_ordering (in module sage.graphs.graph_decompositions.vertex_separation), 733
is_vertex_transitive() (sage.graphs.generic_graph.GenericGraph method), 120
is_weakly_chordal (in module sage.graphs.weakly_chordal), 759

Index 857
Sage Reference Manual: Graph Theory, Release 8.4

is_weakly_chordal() (sage.graphs.graph.Graph method), 270


isomorphic_substructures_iterator() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 639
iterator_edges() (sage.graphs.base.dense_graph.DenseGraphBackend method), 592
iterator_edges() (sage.graphs.base.graph_backends.GenericGraphBackend method), 611
iterator_edges() (sage.graphs.base.sparse_graph.SparseGraphBackend method), 583
iterator_edges() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 605
iterator_in_edges() (sage.graphs.base.dense_graph.DenseGraphBackend method), 592
iterator_in_edges() (sage.graphs.base.graph_backends.GenericGraphBackend method), 611
iterator_in_edges() (sage.graphs.base.sparse_graph.SparseGraphBackend method), 583
iterator_in_edges() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 605
iterator_in_nbrs() (sage.graphs.base.c_graph.CGraphBackend method), 567
iterator_in_nbrs() (sage.graphs.base.graph_backends.GenericGraphBackend method), 612
iterator_in_nbrs() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 606
iterator_nbrs() (sage.graphs.base.c_graph.CGraphBackend method), 567
iterator_nbrs() (sage.graphs.base.graph_backends.GenericGraphBackend method), 612
iterator_nbrs() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 606
iterator_out_edges() (sage.graphs.base.dense_graph.DenseGraphBackend method), 592
iterator_out_edges() (sage.graphs.base.graph_backends.GenericGraphBackend method), 612
iterator_out_edges() (sage.graphs.base.sparse_graph.SparseGraphBackend method), 583
iterator_out_edges() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 606
iterator_out_nbrs() (sage.graphs.base.c_graph.CGraphBackend method), 567
iterator_out_nbrs() (sage.graphs.base.graph_backends.GenericGraphBackend method), 612
iterator_out_nbrs() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 606
iterator_verts() (sage.graphs.base.c_graph.CGraphBackend method), 568
iterator_verts() (sage.graphs.base.graph_backends.GenericGraphBackend method), 612
iterator_verts() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 606

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

matching() (sage.graphs.graph.Graph method), 273


matching_polynomial (in module sage.graphs.matchpoly), 684
matching_polynomial() (sage.graphs.bipartite_graph.BipartiteGraph method), 345
matching_polynomial() (sage.graphs.graph.Graph method), 274
MathonPseudocyclicMergingGraph() (sage.graphs.graph_generators.GraphGenerators static method), 421
MathonPseudocyclicStronglyRegularGraph() (sage.graphs.graph_generators.GraphGenerators static method), 421
MathonStronglyRegularGraph() (sage.graphs.graph_generators.GraphGenerators static method), 422
max_clique (in module sage.graphs.cliquer), 654
max_cut() (sage.graphs.generic_graph.GenericGraph method), 137
MaximizeDegree (class in sage.graphs.tutte_polynomial), 796
maximum_average_degree() (sage.graphs.graph.Graph method), 278
McGeeGraph() (sage.graphs.graph_generators.GraphGenerators static method), 423
McLaughlinGraph() (sage.graphs.graph_generators.GraphGenerators static method), 423
MeredithGraph() (sage.graphs.graph_generators.GraphGenerators static method), 423
merge_vertices() (sage.graphs.generic_graph.GenericGraph method), 138
min_spanning_tree() (in module sage.graphs.base.boost_graph), 620
min_spanning_tree() (sage.graphs.generic_graph.GenericGraph method), 138
minimal_schnyder_wood() (in module sage.graphs.schnyder), 695
MinimizeDegree (class in sage.graphs.tutte_polynomial), 796
MinimizeSingleDegree (class in sage.graphs.tutte_polynomial), 796
minimum_outdegree_orientation() (sage.graphs.graph.Graph method), 279
minor() (sage.graphs.graph.Graph method), 279
mkgraph (in module sage.graphs.graph_decompositions.rankwidth), 743
modular_decomposition() (sage.graphs.graph.Graph method), 280
MoebiusKantorGraph() (sage.graphs.graph_generators.GraphGenerators static method), 424
MoserSpindle() (sage.graphs.graph_generators.GraphGenerators static method), 424
move() (sage.graphs.linearextensions.LinearExtensions method), 691
multicommodity_flow() (sage.graphs.generic_graph.GenericGraph method), 140
multiple_edges() (sage.graphs.base.dense_graph.DenseGraphBackend method), 592
multiple_edges() (sage.graphs.base.graph_backends.GenericGraphBackend method), 612
multiple_edges() (sage.graphs.base.sparse_graph.SparseGraphBackend method), 584
multiple_edges() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 607
multiple_edges() (sage.graphs.generic_graph.GenericGraph method), 141
multiway_cut() (sage.graphs.generic_graph.GenericGraph method), 142
mutate() (sage.graphs.base.graph_backends.NetworkXDiGraphDeprecated method), 613
mutate() (sage.graphs.base.graph_backends.NetworkXGraphDeprecated method), 614
MuzychukS6Graph() (sage.graphs.graph_generators.GraphGenerators static method), 425
MycielskiGraph() (sage.graphs.graph_generators.GraphGenerators static method), 426
MycielskiStep() (sage.graphs.graph_generators.GraphGenerators static method), 426

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

neighbors_in() (sage.graphs.digraph.DiGraph method), 323


neighbors_out() (sage.graphs.digraph.DiGraph method), 324
networkx_graph() (sage.graphs.generic_graph.GenericGraph method), 144
NetworkXDiGraphDeprecated (class in sage.graphs.base.graph_backends), 613
NetworkXGraphDeprecated (class in sage.graphs.base.graph_backends), 614
new_P() (in module sage.graphs.pq_trees), 682
new_Q() (in module sage.graphs.pq_trees), 682
next() (sage.graphs.base.c_graph.Search_iterator method), 572
next() (sage.graphs.generic_graph_pyx.SubgraphSearch method), 802
next() (sage.graphs.trees.TreeIterator method), 683
NKStarGraph() (sage.graphs.graph_generators.GraphGenerators static method), 427
NonisotropicOrthogonalPolarGraph() (sage.graphs.graph_generators.GraphGenerators static method), 428
NonisotropicUnitaryPolarGraph() (sage.graphs.graph_generators.GraphGenerators static method), 429
Nowhere0WordsTwoWeightCodeGraph() (sage.graphs.graph_generators.GraphGenerators static method), 429
nowhere_zero_flow() (sage.graphs.generic_graph.GenericGraph method), 145
NStarGraph() (sage.graphs.graph_generators.GraphGenerators static method), 427
num_blocks() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 640
num_edges() (sage.graphs.base.c_graph.CGraphBackend method), 569
num_edges() (sage.graphs.base.graph_backends.GenericGraphBackend method), 613
num_edges() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 607
num_edges() (sage.graphs.generic_graph.GenericGraph method), 146
num_faces() (sage.graphs.generic_graph.GenericGraph method), 146
num_points() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 640
num_verts() (sage.graphs.base.c_graph.CGraphBackend method), 569
num_verts() (sage.graphs.base.graph_backends.GenericGraphBackend method), 613
num_verts() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 607
num_verts() (sage.graphs.generic_graph.GenericGraph method), 146
number_of() (sage.graphs.graph_database.GraphQuery method), 508
number_of_children() (sage.graphs.pq_trees.PQ method), 679
number_of_loops() (sage.graphs.generic_graph.GenericGraph method), 146
number_of_n_colorings() (in module sage.graphs.graph_coloring), 651
numbers_of_colorings() (in module sage.graphs.graph_coloring), 652

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

out_degree_iterator() (sage.graphs.digraph.DiGraph method), 324


out_degree_sequence() (sage.graphs.digraph.DiGraph method), 325
out_neighbors() (sage.graphs.base.c_graph.CGraph method), 555
out_neighbors() (sage.graphs.base.dense_graph.DenseGraph method), 588
out_neighbors() (sage.graphs.base.sparse_graph.SparseGraph method), 579
out_neighbors() (sage.graphs.base.static_sparse_backend.StaticSparseCGraph method), 608
outgoing_edge_iterator() (sage.graphs.digraph.DiGraph method), 325
outgoing_edges() (sage.graphs.digraph.DiGraph method), 325

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

random() (sage.graphs.graph_coloring.Test method), 643


random_all_graph_colorings() (sage.graphs.graph_coloring.Test method), 644
random_edge() (sage.graphs.generic_graph.GenericGraph method), 156
random_edge_iterator() (sage.graphs.generic_graph.GenericGraph method), 156
random_orientation() (in module sage.graphs.orientations), 808
random_orientation() (sage.graphs.graph.Graph method), 285
random_spanning_tree (in module sage.graphs.spanning_tree), 675
random_spanning_tree() (sage.graphs.graph.Graph method), 285
random_subgraph() (sage.graphs.generic_graph.GenericGraph method), 156
random_vertex() (sage.graphs.generic_graph.GenericGraph method), 157
random_vertex_iterator() (sage.graphs.generic_graph.GenericGraph method), 157
RandomBarabasiAlbert() (sage.graphs.graph_generators.GraphGenerators static method), 438
RandomBicubicPlanar() (sage.graphs.graph_generators.GraphGenerators static method), 439
RandomBipartite() (sage.graphs.graph_generators.GraphGenerators static method), 440
RandomBlockGraph() (sage.graphs.graph_generators.GraphGenerators static method), 440
RandomBoundedToleranceGraph() (sage.graphs.graph_generators.GraphGenerators static method), 442
RandomDirectedGN() (sage.graphs.digraph_generators.DiGraphGenerators method), 494
RandomDirectedGNC() (sage.graphs.digraph_generators.DiGraphGenerators method), 494
RandomDirectedGNM() (sage.graphs.digraph_generators.DiGraphGenerators method), 495
RandomDirectedGNP() (sage.graphs.digraph_generators.DiGraphGenerators method), 495
RandomDirectedGNR() (sage.graphs.digraph_generators.DiGraphGenerators method), 496
RandomGNM() (sage.graphs.graph_generators.GraphGenerators static method), 442
RandomGNP() (in module sage.graphs.graph_generators_pyx), 499
RandomGNP() (sage.graphs.graph_generators.GraphGenerators static method), 443
RandomHolmeKim() (sage.graphs.graph_generators.GraphGenerators static method), 444
RandomIntervalGraph() (sage.graphs.graph_generators.GraphGenerators static method), 444
RandomLobster() (sage.graphs.graph_generators.GraphGenerators static method), 445
RandomNewmanWattsStrogatz() (sage.graphs.graph_generators.GraphGenerators static method), 445
RandomRegular() (sage.graphs.graph_generators.GraphGenerators static method), 446
RandomRegularBipartite() (sage.graphs.graph_generators.GraphGenerators static method), 446
RandomSemiComplete() (sage.graphs.digraph_generators.DiGraphGenerators method), 496
RandomShell() (sage.graphs.graph_generators.GraphGenerators static method), 446
RandomToleranceGraph() (sage.graphs.graph_generators.GraphGenerators static method), 447
RandomTournament() (sage.graphs.digraph_generators.DiGraphGenerators method), 497
RandomTree() (sage.graphs.graph_generators.GraphGenerators static method), 447
RandomTreePowerlaw() (sage.graphs.graph_generators.GraphGenerators static method), 448
RandomTriangulation() (sage.graphs.graph_generators.GraphGenerators static method), 448
rank() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 640
rank_decomposition (in module sage.graphs.graph_decompositions.rankwidth), 743
rank_decomposition() (sage.graphs.graph.Graph method), 286
realloc() (sage.graphs.base.c_graph.CGraph method), 556
realloc() (sage.graphs.base.dense_graph.DenseGraph method), 588
realloc() (sage.graphs.base.sparse_graph.SparseGraph method), 580
reduced_adjacency_matrix() (sage.graphs.bipartite_graph.BipartiteGraph method), 346
relabel() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 641
relabel() (sage.graphs.base.c_graph.CGraphBackend method), 570
relabel() (sage.graphs.base.graph_backends.GenericGraphBackend method), 613
relabel() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 607
relabel() (sage.graphs.generic_graph.GenericGraph method), 157
remove_loops() (sage.graphs.generic_graph.GenericGraph method), 160

Index 863
Sage Reference Manual: Graph Theory, Release 8.4

remove_multiple_edges() (sage.graphs.generic_graph.GenericGraph method), 160


removed_edge() (in module sage.graphs.tutte_polynomial), 797
removed_from() (sage.graphs.tutte_polynomial.Ear method), 795
removed_loops() (in module sage.graphs.tutte_polynomial), 797
removed_multiedge() (in module sage.graphs.tutte_polynomial), 798
reorder_sets() (in module sage.graphs.pq_trees), 682
reverse() (sage.graphs.digraph.DiGraph method), 326
reverse() (sage.graphs.pq_trees.PQ method), 679
reverse_edge() (sage.graphs.digraph.DiGraph method), 326
reverse_edges() (sage.graphs.digraph.DiGraph method), 329
right() (sage.graphs.linearextensions.LinearExtensions method), 692
RingedTree() (sage.graphs.graph_generators.GraphGenerators static method), 449
RobertsonGraph() (sage.graphs.graph_generators.GraphGenerators static method), 449
RookGraph() (sage.graphs.graph_generators.GraphGenerators static method), 450
root_graph() (in module sage.graphs.line_graph), 671
round_robin() (in module sage.graphs.graph_coloring), 652

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

sage.graphs.graph_editor (module), 782


sage.graphs.graph_generators (module), 349
sage.graphs.graph_generators_pyx (module), 499
sage.graphs.graph_input (module), 786
sage.graphs.graph_latex (module), 768
sage.graphs.graph_list (module), 782
sage.graphs.graph_plot (module), 696
sage.graphs.graph_plot_js (module), 727
sage.graphs.hyperbolicity (module), 789
sage.graphs.hypergraph_generators (module), 623
sage.graphs.independent_sets (module), 658
sage.graphs.isgci (module), 534
sage.graphs.line_graph (module), 667
sage.graphs.linearextensions (module), 690
sage.graphs.lovasz_theta (module), 689
sage.graphs.matchpoly (module), 683
sage.graphs.orientations (module), 807
sage.graphs.partial_cube (module), 799
sage.graphs.planarity (module), 696
sage.graphs.pq_trees (module), 676
sage.graphs.schnyder (module), 693
sage.graphs.spanning_tree (module), 671
sage.graphs.strongly_regular_db (module), 512
sage.graphs.trees (module), 682
sage.graphs.tutte_polynomial (module), 794
sage.graphs.weakly_chordal (module), 757
save_afile() (sage.graphs.bipartite_graph.BipartiteGraph method), 347
SchlaefliGraph() (sage.graphs.graph_generators.GraphGenerators static method), 450
Search_iterator (class in sage.graphs.base.c_graph), 571
seidel_adjacency_matrix() (sage.graphs.graph.Graph method), 286
seidel_switching() (sage.graphs.graph.Graph method), 287
set_contiguous() (in module sage.graphs.pq_trees), 682
set_contiguous() (sage.graphs.pq_trees.P method), 678
set_contiguous() (sage.graphs.pq_trees.Q method), 681
set_edge_label() (sage.graphs.base.dense_graph.DenseGraphBackend method), 593
set_edge_label() (sage.graphs.base.graph_backends.GenericGraphBackend method), 613
set_edge_label() (sage.graphs.base.sparse_graph.SparseGraphBackend method), 584
set_edge_label() (sage.graphs.generic_graph.GenericGraph method), 161
set_edges() (sage.graphs.graph_plot.GraphPlot method), 718
set_embedding() (sage.graphs.generic_graph.GenericGraph method), 162
set_latex_options() (sage.graphs.generic_graph.GenericGraph method), 162
set_option() (sage.graphs.graph_latex.GraphLatex method), 776
set_options() (sage.graphs.graph_latex.GraphLatex method), 780
set_planar_positions() (sage.graphs.generic_graph.GenericGraph method), 163
set_pos() (sage.graphs.generic_graph.GenericGraph method), 163
set_pos() (sage.graphs.graph_plot.GraphPlot method), 723
set_vertex() (sage.graphs.generic_graph.GenericGraph method), 163
set_vertices() (sage.graphs.generic_graph.GenericGraph method), 163
set_vertices() (sage.graphs.graph_plot.GraphPlot method), 724
setup_latex_preamble() (in module sage.graphs.graph_latex), 781

Index 865
Sage Reference Manual: Graph Theory, Release 8.4

shortest_path() (sage.graphs.base.c_graph.CGraphBackend method), 570


shortest_path() (sage.graphs.generic_graph.GenericGraph method), 164
shortest_path_all_pairs (in module sage.graphs.distances_all_pairs), 767
shortest_path_all_pairs() (sage.graphs.generic_graph.GenericGraph method), 165
shortest_path_all_vertices() (sage.graphs.base.c_graph.CGraphBackend method), 570
shortest_path_length() (sage.graphs.generic_graph.GenericGraph method), 169
shortest_path_lengths() (sage.graphs.generic_graph.GenericGraph method), 170
shortest_paths() (in module sage.graphs.base.boost_graph), 621
shortest_paths() (sage.graphs.generic_graph.GenericGraph method), 172
show() (sage.graphs.generic_graph.GenericGraph method), 174
show() (sage.graphs.graph_database.GraphQuery method), 509
show() (sage.graphs.graph_plot.GraphPlot method), 724
show3d() (sage.graphs.generic_graph.GenericGraph method), 174
show_all() (sage.graphs.isgci.GraphClasses method), 542
show_graphs() (in module sage.graphs.graph_list), 783
ShrikhandeGraph() (sage.graphs.graph_generators.GraphGenerators static method), 451
SierpinskiGasketGraph() (sage.graphs.graph_generators.GraphGenerators static method), 452
simple_connected_genus_backtracker (class in sage.graphs.genus), 686
simple_connected_graph_genus() (in module sage.graphs.genus), 688
simplify() (sage.graphs.pq_trees.PQ method), 680
SimsGewirtzGraph() (sage.graphs.graph_generators.GraphGenerators static method), 454
sinks() (sage.graphs.digraph.DiGraph method), 330
size() (sage.graphs.generic_graph.GenericGraph method), 175
small_integer_to_graph6() (in module sage.graphs.generic_graph_pyx), 806
smallgraphs() (sage.graphs.isgci.GraphClasses method), 542
sources() (sage.graphs.digraph.DiGraph method), 330
SousselierGraph() (sage.graphs.graph_generators.GraphGenerators static method), 454
spanning_trees() (sage.graphs.graph.Graph method), 287
spanning_trees_count() (sage.graphs.generic_graph.GenericGraph method), 175
sparse6_string() (sage.graphs.graph.Graph method), 288
SparseGraph (class in sage.graphs.base.sparse_graph), 575
SparseGraphBackend (class in sage.graphs.base.sparse_graph), 580
spectral_radius (in module sage.graphs.base.static_sparse_graph), 599
spectral_radius() (sage.graphs.generic_graph.GenericGraph method), 176
spectrum() (sage.graphs.generic_graph.GenericGraph method), 178
spqr_tree (in module sage.graphs.connectivity), 825
spqr_tree() (sage.graphs.graph.Graph method), 288
spqr_tree_to_graph (in module sage.graphs.connectivity), 827
spring_layout_fast() (in module sage.graphs.generic_graph_pyx), 806
spring_layout_fast_split() (in module sage.graphs.generic_graph_pyx), 807
SquaredSkewHadamardMatrixGraph() (sage.graphs.graph_generators.GraphGenerators static method), 455
SRG_100_44_18_20() (in module sage.graphs.strongly_regular_db), 512
SRG_100_45_20_20() (in module sage.graphs.strongly_regular_db), 512
SRG_105_32_4_12() (in module sage.graphs.strongly_regular_db), 513
SRG_120_63_30_36() (in module sage.graphs.strongly_regular_db), 513
SRG_120_77_52_44() (in module sage.graphs.strongly_regular_db), 513
SRG_126_25_8_4() (in module sage.graphs.strongly_regular_db), 513
SRG_126_50_13_24() (in module sage.graphs.strongly_regular_db), 513
SRG_1288_792_476_504() (in module sage.graphs.strongly_regular_db), 514
SRG_144_39_6_12() (in module sage.graphs.strongly_regular_db), 514

866 Index
Sage Reference Manual: Graph Theory, Release 8.4

SRG_175_72_20_36() (in module sage.graphs.strongly_regular_db), 514


SRG_176_105_68_54() (in module sage.graphs.strongly_regular_db), 514
SRG_176_49_12_14() (in module sage.graphs.strongly_regular_db), 515
SRG_176_90_38_54() (in module sage.graphs.strongly_regular_db), 515
SRG_196_91_42_42() (in module sage.graphs.strongly_regular_db), 515
SRG_210_99_48_45() (in module sage.graphs.strongly_regular_db), 515
SRG_220_84_38_28() (in module sage.graphs.strongly_regular_db), 516
SRG_243_110_37_60() (in module sage.graphs.strongly_regular_db), 516
SRG_253_140_87_65() (in module sage.graphs.strongly_regular_db), 516
SRG_276_140_58_84() (in module sage.graphs.strongly_regular_db), 516
SRG_280_117_44_52() (in module sage.graphs.strongly_regular_db), 517
SRG_280_135_70_60() (in module sage.graphs.strongly_regular_db), 517
SRG_416_100_36_20() (in module sage.graphs.strongly_regular_db), 517
SRG_560_208_72_80() (in module sage.graphs.strongly_regular_db), 517
SRG_630_85_20_10() (in module sage.graphs.strongly_regular_db), 518
SRG_from_RSHCD() (in module sage.graphs.strongly_regular_db), 518
StarGraph() (sage.graphs.graph_generators.GraphGenerators static method), 455
StaticSparseBackend (class in sage.graphs.base.static_sparse_backend), 602
StaticSparseCGraph (class in sage.graphs.base.static_sparse_backend), 607
steiner_tree() (sage.graphs.generic_graph.GenericGraph method), 178
strong_articulation_points (in module sage.graphs.connectivity), 828
strong_articulation_points() (sage.graphs.digraph.DiGraph method), 331
strong_orientation() (sage.graphs.graph.Graph method), 290
strong_orientations_iterator() (in module sage.graphs.orientations), 808
strong_orientations_iterator() (sage.graphs.graph.Graph method), 291
strong_product() (sage.graphs.generic_graph.GenericGraph method), 180
strongly_connected_component_containing_vertex (in module sage.graphs.connectivity), 829
strongly_connected_component_containing_vertex() (sage.graphs.base.c_graph.CGraphBackend method), 571
strongly_connected_component_containing_vertex() (sage.graphs.digraph.DiGraph method), 331
strongly_connected_components() (sage.graphs.digraph.DiGraph method), 332
strongly_connected_components_digraph (in module sage.graphs.base.static_sparse_graph), 601
strongly_connected_components_digraph (in module sage.graphs.connectivity), 829
strongly_connected_components_digraph() (sage.graphs.digraph.DiGraph method), 332
strongly_connected_components_subgraphs (in module sage.graphs.connectivity), 830
strongly_connected_components_subgraphs() (sage.graphs.digraph.DiGraph method), 333
strongly_regular_from_two_intersection_set() (in module sage.graphs.strongly_regular_db), 532
strongly_regular_from_two_weight_code() (in module sage.graphs.strongly_regular_db), 532
strongly_regular_graph() (in module sage.graphs.strongly_regular_db), 533
strongly_regular_graph() (sage.graphs.graph_generators.GraphGenerators static method), 480
subdivide_edge() (sage.graphs.generic_graph.GenericGraph method), 180
subdivide_edges() (sage.graphs.generic_graph.GenericGraph method), 181
subgraph() (sage.graphs.generic_graph.GenericGraph method), 182
subgraph_search() (sage.graphs.generic_graph.GenericGraph method), 184
subgraph_search_count() (sage.graphs.generic_graph.GenericGraph method), 186
subgraph_search_iterator() (sage.graphs.generic_graph.GenericGraph method), 187
subgraphs_to_query() (in module sage.graphs.graph_database), 511
SubgraphSearch (class in sage.graphs.generic_graph_pyx), 802
SuzukiGraph() (sage.graphs.graph_generators.GraphGenerators static method), 456
switch() (sage.graphs.linearextensions.LinearExtensions method), 692
SwitchedSquaredSkewHadamardMatrixGraph() (sage.graphs.graph_generators.GraphGenerators static method), 456

Index 867
Sage Reference Manual: Graph Theory, Release 8.4

SylvesterGraph() (sage.graphs.graph_generators.GraphGenerators static method), 457


SymplecticDualPolarGraph() (sage.graphs.graph_generators.GraphGenerators static method), 457
SymplecticPolarGraph() (sage.graphs.graph_generators.GraphGenerators static method), 457
szeged_index() (sage.graphs.generic_graph.GenericGraph method), 188
SzekeresSnarkGraph() (sage.graphs.graph_generators.GraphGenerators static method), 458

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

TriconnectivitySPQR (class in sage.graphs.connectivity), 810


TruncatedIcosidodecahedralGraph() (sage.graphs.graph_generators.GraphGenerators static method), 463
TruncatedTetrahedralGraph() (sage.graphs.graph_generators.GraphGenerators static method), 463
TuranGraph() (sage.graphs.graph_generators.GraphGenerators static method), 464
Tutte12Cage() (sage.graphs.graph_generators.GraphGenerators static method), 464
tutte_polynomial() (in module sage.graphs.tutte_polynomial), 798
tutte_polynomial() (sage.graphs.graph.Graph method), 294
TutteCoxeterGraph() (sage.graphs.graph_generators.GraphGenerators static method), 464
TutteGraph() (sage.graphs.graph_generators.GraphGenerators static method), 465
two_factor_petersen() (sage.graphs.graph.Graph method), 295
twograph() (sage.graphs.graph.Graph method), 296

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

WellsGraph() (sage.graphs.graph_generators.GraphGenerators static method), 468


WheelGraph() (sage.graphs.graph_generators.GraphGenerators static method), 468
width_of_cut_decomposition() (in module sage.graphs.graph_decompositions.cutwidth), 750
width_of_path_decomposition (in module sage.graphs.graph_decompositions.vertex_separation), 741
wiener_index (in module sage.graphs.distances_all_pairs), 767
wiener_index() (sage.graphs.generic_graph.GenericGraph method), 201
WienerArayaGraph() (sage.graphs.graph_generators.GraphGenerators static method), 469
WindmillGraph() (sage.graphs.graph_generators.GraphGenerators static method), 469
WorldMap() (sage.graphs.graph_generators.GraphGenerators static method), 470
write_to_eps() (sage.graphs.graph.Graph method), 297

870 Index

You might also like